How to make field enum migration yii2 - yii

I make field ENUM and the result is error when I use yii migrate/up on CMD windows.
public function up()
{
$tableOptions = null;
if ($this->db->driverName === 'mysql') {
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
}
$this->createTable('{{%user_social_media}}', [
'social_media' => $this->ENUM('facebook', 'google', 'twitter', 'github'),
'id' => $this->primaryKey(),
'username' => $this->string(),
'user_id' => $this->integer(11),
'created_at' => $this->integer(11),
'updated_at' => $this->integer(11),
], $tableOptions);
}

There is no enum() method at the moment since not every DB is supporting ENUM fields. You can do it manually though:
'social_media' => "ENUM('facebook', 'google', 'twitter', 'github')",
Note:
This solution is for Mysql only
For related Postgresql content visit here

Actually the best way of working this and keeping your migrations clean would be by using some tool/helper like the one provided by the yii2mod team https://github.com/yii2mod/yii2-enum
this way you can build the enum functionality on code, works like a charm.
i.e. an enum for genderType
<?php
namespace common\models\enums;
use yii2mod\enum\helpers\BaseEnum;
/**
* Class GenderType
*
* #package yii2mod\settings\models\enumerables
*/
class GenderType extends BaseEnum
{
// add as many genders as you need
const MALE_TYPE = 'MALE';
const FEMALE_TYPE = 'FEMALE';
public static $list = [
self::MALE_TYPE => 'Male',
self::FEMALE_TYPE => 'Female',
];
}
Use the following methods to access your Enum:
createByName() - Creates a new type instance using the name of a
value.
getValueByName() - Returns the constant key by value(label)
createByValue() - Creates a new type instance using the value.
listData() - Returns the associative array with constants values and
labels
getLabel()- Returns the constant label by key
getConstantsByName() - Returns the list of constants (by name) for
this type.
getConstantsByValue() - Returns the list of constants (by
value) for this type.
isValidName() - Checks if a name is valid for
this type. isValidValue() - Checks if a value is valid for this type.

Related

PDO's fetch method passes wrong parameter to constructor class (in Yii)

Model class MyModel has following behavior
public function behaviors() {
return [
'CTimestampBehavior' => [
'class' => 'zii.behaviors.CTimestampBehavior',
'createAttribute' => null,
'updateAttribute' => 'update_time',
'setUpdateOnCreate' => true
]
];
}
In code, in controller I write something like
$model = new MyModel();
$dataReader = Yii::app()->db->createCommand()
->selectDistinct('some fields')
->from('MyModel')
->leftJoin('some table')
->where('some criteria')
->query();
while ($item = $dataReader->readObject('MyMode', $model->getAttributes())) {
**//!!! HERE item array is with model attributes, which are empty**
$items[] = $item;
}
disaster, it's not working, items is array, each of element holding empty list of attributes, like no data fetched from db
If I write
$dataReader = Yii::app()->db->createCommand()
->selectDistinct('some fields')
->from('MyModel')
->leftJoin('some table')
->where('some criteria')
->query();
while ($item = $dataReader->readObject('MyModel', MyModel::model()->getAttributes())) {
//!!! HERE item array is with model attributes, which hold correct data, taken from db
$items[] = $item;
}
it's working
If I get rid off CTimestamp behavior, both cases work.
If I debug first case, I realize that, after pdo fetchobject is done, it calls constructor with scenario="current_timestamp()". Question is why? And where I missstepped?
If you read readObject() documentation you will find that second argument is not list of fields, but list of constructor arguments. CActiveRecord has only one constructor argument - $scenario. $dataReader->readObject('MyMode', $model->getAttributes()) essentially assigns random value as scenario, since it will get first value from $model->getAttributes(). In your case you probably need:
$item = $dataReader->readObject('MyModel', []);

Phalcon: save reference to new record in one transaction

Im trying to save a reference to a new object in a single transaction as shown here in the documentation under 'implicit transactions':
I am creating two new objects of the same class, one is then referencing the other. From the documentation, the save should be performed on TreeNodeA when TreeNodeB is saved and the ID will be passed to TreeNodeB->parent_tree_node_id
This doesnt seem to be working, and it still being passed as an object as Im getting the error on the save function:
Object of class TreeNodes could not be converted to string
I've tried writing a saveTreeParentNodeId function in the model and also setting it using the alias, but neither seem to work.
$treeNode = new TreeNodes();
$treeNode->setConnectionService(Registry::setConnection(MyModel::MAIN_DB));
$parentNode = $treeNode->findFirst();
$treeNodeA = new TreeNodes();
$treeNodeA->tree_id = $parentNode->tree_id;
$treeNodeA->tree_parent_node_id = $parentNode;
$treeNodeA->tree_level_id = 2;
$treeNodeA->node_desc = "Test Node A";
$treeNodeB = new TreeNodes();
$treeNodeB->tree_id = $parentNode->tree_id;
$treeNodeB->tree_parent_node_id = $treeNodeA;
$treeNodeB->tree_level_id = 3;
$treeNodeB->tree_desc = "Test Node B";
$treeNodeB->save();
The model:
class TreeNodes extends MyModel
{
public $node_id;
public $tree_id;
public $tree_parent_node_id;
public $tree_level_id;
public $node_desc;
public function getSource()
{
return "TreeNodes";
}
public function setTreeParentNodeId(TreeNodes $parentNode){
$this->tree_parent_node_id = $parentNode->node_id;
}
public function initialize()
{
parent::initialize();
$this->belongsTo(
'tree_id',
'Organisations',
'TreeID',
array(
'alias' => 'organisation',
'reusable' => true
)
);
$this->hasOne(
'tree_id',
'TreeType',
'tree_id',
array(
'alias' => 'type',
'reusable' => true
)
);
$this->hasOne(
'tree_parent_node_id',
'TreeNodes',
'node_id',
array(
'alias' => 'parentNode'
)
);
}
}
Update
By updating the model to use belongsTo, Phalcon recognises the parentNode.
$this->belongsTo(
'tree_parent_node_id',
'TreeNodes',
'node_id',
array(
'alias' => 'parentNode'
)
);
This enables $treeNodeA to save implicitly when $treeNodeB is saved.
$treeNodeA->parentNode = $parentNode;
Unfortunately, $treeNodeB with a reference to $treeNodeA as the parentNode is NOT saved. No error message is returned either, just 'true'.
In the documentation example you linked, they assign the $robotPart object to $robot->robotPart. robotPart refers to the linked RobotPart object and not to the ID ( to which you are trying to assign your object )
$treeNodeB = new TreeNodes();
$treeNodeB->tree_id = $parentNode->tree_id;
// $treeNodeB->tree_parent_node_id = $treeNodeA;
$treeNodeB->parentNode = $treeNodeA;
$treeNodeB->save();
You should use parentNode here because this is the name you gave to your relationship via hasOne.
I haven't tested this myself, but by following the documentation's logic, this should push you in the right direction.
Alter you model relationships so you have both sides of the relation
// let Phalcon know that "tree_parent_node_id" is a reference to "node_id"
$this->hasOne(
'tree_parent_node_id', // your column
'TreeNodes', // referenced table
'node_id', // referenced table column
array(
'alias' => 'parentNode',
'foreignKey' => true
)
);
// let Phalcon know that "node_id" is being referenced as a FK in "TreeNodes"
$this->belongsTo(
'node_id', // PK
'TreeNodes', // referenced table
'tree_parent_node_id', // referenced table column
array('foreignKey' => ['message' => 'FK constraint error between node_id and tree_parent_node_id'])
);

SilverStripe duplicate entries even with unique index

I'm trying to prevent duplicate records when adding customer records in my CRM with the following index:
private static $indexes = array(
'IndexFirstSurName' => array(
'type' => 'unique',
'value' => '"FirstName","Surname"'
)
);
Note that I extended Customer from Member where FirstName and Surname came from:
class Customer extends Member
But SilverStripe is still allowing duplicate entries of FirstName and Surname combination? Has anyone experienced the same problem?
The Man, in my experience a validate() is still needed even when using indexing:
public function validate() {
$result = parent::validate();
if(Member::get()->filter(array('FirstName' => $this->FirstName, 'Surname' => $this->Surname))->first()) {
$result->error('First and Surname must be unique for each member.');
}
return $result;
}
Alternately for a more robust breakout:
public function validate() {
$result = parent::validate();
if($member = Member::get()->filter(array('FirstName' => $this->FirstName, 'Surname' => $this->Surname))->first()) {
if($member->FirstName == $this->FirstName){
$result->error('Your Surname is fine, please change your First Name.');
}
if($member->Surname == $this->Surname){
$result->error('Your First Name is fine, please change your Surname.');
}
}
return $result;
}
note that I extended Customer from Member were FirstName and Surname came from
I wonder if SilverStripe is attempting to set indexes on the non-existent fields Customer.FirstName and Customer.Surname. Maybe try qualifying the columns by prepending the table that is actually having the indexes added to it like this:
private static $indexes = array(
'IndexFirstSurName' => array(
'type' => 'unique',
'value' => '"Member"."FirstName","Member"."Surname"'
)
);
You might also consider decorating Member instead of subclassing it. That way you wouldn't need to qualify the query fragments in this way.
The way to extend Member on SilverStripe is by extending DataExtension. As theruss is saying, you are trying to create a unique index on the table Customer, where you prabably do not have the fields FirstName and Surname.
Try this instead
class Customer extends DataExtension
{
private static $indexes = array(
'IndexFirstSurName' => array(
'type' => 'unique',
'value' => '"FirstName","Surname"'
)
);
}
And then let SilverStripe know about your extension in config.yml
Member:
extensions:
- Customer
Now run /dev/build?flush and you should see your index being created.
Check here for more information about extensions.

SugarCRM - Add leads with auto-incremented ID

I use the SOAP API to add new leads to SugarCRM. Additionally, I use a plugin to assign an auto-incremented lead ID whenever a new lead is created (http://www.sugarforge.org/projects/autoincrement/).
Now, the plugin works fine, if I create a new lead via frontend. But, if I use the SOAP API, the function from the module, which assigns the auto-increment ID to the lead, does not trigger.
I create the lead via
$module = 'Leads';
$params = array(
'session' => $session,
'module_name' => $module,
'name_value_list' => array(
array('name' => 'id', 'value' => ''),
//array('name' => 'int_lead_id_c', 'value' => ''),
array('name' => 'first_name', 'value' => $_POST["first_name"]),
array('name' => 'last_name', 'value' => $_POST["last_name"]),
array('name' => 'phone_home', 'value' => $_POST["phone"]),
array('name' => 'email1', 'value' => $_POST["email"]),
array('name' => 'assigned_user_id', 'value' => '1'),
)
);
//Create the Lead record
$lead_result = $soapclient->call('set_entry', $params);
The function in the module is this one:
class SugarFieldAutoincrement extends SugarFieldBase {
/**
* Override the SugarFieldBase::save() function to implement the logic to get the next autoincrement value
* and format the saved value based on the attributes defined for the field.
*
* #param SugarBean bean - the bean performing the save
* #param array params - an array of paramester relevant to the save, most likely will be $_REQUEST
* #param string field - the name of the field
*/
public function save(&$bean, $params, $field, $properties, $prefix = '') {
}
}
How can I make sure, that this function is also triggered, when adding leads via SOAP API?
Thanks a lot for your help! :-)
David
You would need to set the field type to 'autoincrement' and the dbType to 'int' in the vardef record for the field.
If I'm not mistaken, the Database has a UUID() trigger on insert for most tables, so you should be able to completely remove the id field.
If you want to trigger the function before saving, you can use beforeSave logic hook.

Yii -CExistValidator for external key

In a simple project with Yii I have a model:
Checkins.php
* The followings are the available columns in table 'checkins':
* #property integer $id
* #property integer $user_id
* #property integer $item_id
* #property double $lat
* #property double $long
The two values $user_id and $item_id belong to other two tables:
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'user' => array(self::BELONGS_TO, 'Users', 'user_id'),
'item' => array(self::BELONGS_TO, 'Items', 'item_id'),
);
}
I defined some validator:
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('user_id, item_id, lat, long', 'required'),
array('item_id', 'exist', 'on'=>'create', 'attributeName'=>'id', 'className'=>'Items'),
array('user_id, item_id', 'numerical', 'integerOnly'=>true),
array('lat, long', 'numerical'),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, user_id, item_id, lat, long', 'safe', 'on'=>'search'),
);
}
When in the actionCreate the method save() execute all the validators are working but not the one designed to check the presence of the external key in the model Items
array('item_id', 'exist', 'on'=>'create', 'attributeName'=>'id', 'className'=>'Items'),
And in case I try to save a Checkins that has a value in item_id without having the same id in the Items I don's any validation error.
Is this the right approach?
Thanks
I think it is most likely because you don't set the model's scenario to 'create' before saving (I'm just guessing that, because you don't attach the $checkin->save() code in the controller's actionCreate.). The other validation worked most likely because they aren't set to a specific scenario (i.e. they will work in all validation.).
For example if there is no Item with id 5, the code below
$checkin = new Checkin();
$checkin->text = 'test';
$checkin->item_id = 5;
if (!$checkin->validate()){
print_r($checkin->errors);
}
will work normally since the Checkin's scenario is not set to 'create' (the default is 'insert'). But I tried the code below
$checkin = new Checkin();
$checkin->scenario = 'create';
//or you can set it in the instantiation
//$checkin = new Checkin('create');
$checkin->text = 'test';
$checkin->item_id = 5;
if (!$checkin->validate()){
print_r($checkin->errors);
}
This will result a validation error.
Can you paste your model saving code?