I'm creating migration in Yii2, and would like to set initial value for primary key column (for example id = 100) for only one table, but by default it set to 1. Is it possible to change initial value of primary key?
Thanks in advance.
class m190723_083518_create_all_tables extends Migration
{
/**
* {#inheritdoc}
*/
public function safeUp()
{
$this->createTable('table', [
'id' => $this->primaryKey(),
....
]);
}
.....
}
You can achieve this using $options argument in createTable() method:
public function safeUp()
{
$this->createTable('table', [
'id' => $this->primaryKey(),
// ...
], 'ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=100');
}
Related
I.E. If i update address_line1 then its giving error for mobile number allocated.
While update it should not match with it self.
Even if i change mobile number it should check with other user.
public function rules()
{
return [
[['mobile_number','address_line1','address_line2','city','state','country','pincode' ],'required'],
['mobile_number','mobile_number_allocation_validate'],
];
}
public function mobile_number_allocation_validate($attribute){
// add custom validation
$result = User::find()
->where('`mobile_number` = "'.$this->$attribute.'" AND
`status` = "A" ')->all();
if(!empty($result)){
$this->addError($attribute,'Mobile number is allocated to other vehicle');
}
}
Thanks in Advance
Change your condition as :-- Override beforeSave() of User ActiveRecord
/**
* BeforeSave() check if User ActiveRecord is created with same calculator param
* if created then return false with model error
*
*/
public function beforeSave($insert){
$model = self::find()->where('`mobile_number` = "'.$this->$attribute.'" AND
`status` = "A" ')->all();
if($model !== null && $model->id !== $this->id){
$this->addError('mobile_number' , 'Mobile number is allocated to other vehicle');
return false;
}
return parent::beforeSave($insert);
}
You should be able to use the unique validator for this, by simply adding a filter condition like this
public function rules()
{
return [
[['mobile_number','address_line1','address_line2','city','state','country','pincode' ],'required'],
['mobile_number','unique', 'filter' => ['status' => 'A']],
];
}
I'm using yii2-advanced. I've several table :
tb_user:(iduser(PK),username),
tb_profile:(id,iduser(FK)),
tb_status:(id,iduser(FK))
My question is how can i insert iduser(PK) from tb_user to iduser(FK) on tb_profile and tb_status after i push the signup button.
For a while i think i must to do some modification of bevahiours() function on User model and i found some error, or adding trigger syntax on the table ? (i think this is not a good ways).
Is there anyone who can help me, how to solve my problem ?
this is the User model before the modification :
<?php
namespace common\models;
use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class User extends ActiveRecord implements IdentityInterface
{
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
/**
* #inheritdoc
*/
public static function tableName()
{
return '{{%user}}';
}
/**
* #inheritdoc
*/
public function behaviors()
{
return [
'timestamp' => [
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => 'created_at',
ActiveRecord::EVENT_BEFORE_UPDATE => 'updated_at',
],
'value' => function () {return date('Y-m-d h:m:s');},
],
];
}
/**
* #inheritdoc
*/
public function rules()
{
return [
['status', 'default', 'value' => self::STATUS_ACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
];
}
/**
* #inheritdoc
*/
public static function findIdentity($id)
{
return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
}
/**
* #inheritdoc
*/
public function getId()
{
return $this->getPrimaryKey();
}
}
?>
The Controller :
public function actionSignup()
{
$model = new SignupForm();
if ($model->load(Yii::$app->request->post())) {
if ($user = $model->signup()) {
if (Yii::$app->getUser()->login($user)) {
return $this->goHome();
}
}
}
return $this->render('signup', [
'model' => $model,
]);
}
I had similar situation in one of my project where i had 2 tables like user,user_image where user_id was foreign key to add the path.
For those kind of situation you can use either of following approach
1.Insert record in both table on click of signup button. You will have to write update action accordingly.
$user = new User();
$user->name = "John"
$user->email = "John#gmail.com"
//Add if any other fields in table
$user->save(); //save the record
$user_image = new UserImage();
$user_image->user_id = $user->id;
$user_image->image = "image path"
//Add any other images here
$user_image->save();//save the record
2.You can also call create action of UserImage and do the same. If you use this approach than you might also need to use any other unique column to find the id of that user and use it to insert new record,for example in my table email is unique column so i can write following code in UserImage and get the id
$user = User::findOne(['email' => 'john#gmail.com']);//this will return whole row
$user_image->user_id = $user->id;
$user_image->image = "image path"
//Add any other images here
$user_image->save();//save the record
And that way you can use the code as per it suits your need
Thank you
In controller i have:
public function actionGetItems()
{
$model = new \app\models\WarehouseItems;
$items = $model->find()->with(['user'])->asArray()->all();
return $items;
}
In WarehouseItem model i have standard (created by gii) relation declaration:
public function getUser()
{
return $this->hasOne('\dektrium\user\models\User', ['user_id' => 'user_id']);
}
How can i control which column data do i get from "user" relation? I currently get all columns which is not good as that data is being sent to Angular in JSON format.
Right now i have to loop trough $items and filer out all columns i dont want to send.
You should simply modify the relation query like this :
$items = \app\models\WarehouseItems::find()->with([
'user' => function ($query) {
$query->select('id, col1, col2');
}
])->asArray()->all();
Read more : http://www.yiiframework.com/doc-2.0/yii-db-activequerytrait.html#with()-detail
Your code should go this way.
public function actionGetItems()
{
$items = \app\models\WarehouseItems::find()
->joinWith([
/*
*You need to use alias and then must select index key from parent table
*and foreign key from child table else your query will give an error as
*undefined index **relation_key**
*/
'user as u' => function($query){
$query->select(['u.user_id', 'u.col1', 'u.col2']);
}
])
->asArray()
->all();
return $items;
}
Inside WarehouseItem model
/**
* #return ActiveQuery
*/
public function getUser()
{
$query = User::find()
->select(['id', 'col1', 'col2'])
->where([
'id' => $this->user_id,
]);
/**
* Default hasOne, setup multiple for hasMany
* $query->multiple = true;
*/
return $query;
}
I created src/Model/Behavior/ModernTreeBehavior.php:
<?php
namespace Cake\ORM\Behavior;
use Cake\Datasource\EntityInterface;
use Cake\Datasource\Exception\RecordNotFoundException;
use Cake\Event\Event;
use Cake\ORM\Behavior;
use Cake\ORM\Entity;
use Cake\ORM\Query;
use InvalidArgumentException;
use RuntimeException;
class ModernTreeBehavior extends Behavior
{
/**
* Cached copy of the first column in a table's primary key.
*
* #var string
*/
protected $_primaryKey;
/**
* Default config
*
* These are merged with user-provided configuration when the behavior is used.
*
* #var array
*/
protected $_defaultConfig = [
'implementedFinders' => [
'children' => 'findChildren',
'treeList' => 'findTreeList'
],
'implementedMethods' => [
'childCount' => 'childCount',
'getLevel' => 'getLevel'
],
'parent' => 'parent_id',
'path' => 'path',
'scope' => null,
'level' => null
];
public function getLevel($entity)
{
$primaryKey = $this->_getPrimaryKey();
$id = $entity;
if ($entity instanceof EntityInterface) {
$id = $entity->get($primaryKey);
}
$config = $this->config();
$entity = $this->_table->find('all')
->select([$config['path']])
->where([$primaryKey => $id])
->first();
if ($entity === null) {
return false;
}
return substr_count($entity[$config['path']], '-') + 1;
}
/**
* Returns a single string value representing the primary key of the attached table
*
* #return string
*/
protected function _getPrimaryKey()
{
if (!$this->_primaryKey) {
$this->_primaryKey = (array)$this->_table->primaryKey();
$this->_primaryKey = $this->_primaryKey[0];
}
return $this->_primaryKey;
}
}
I used $this->addBehavior('ModernTree'); in CommentTables.php
and I got error Fatal error: Cannot redeclare class Cake\ORM\Behavior\ModernTreeBehavior in .../src/Model/Behavior/ModernTreeBehavior.php on line 0
But if I paste /src/Model/Behavior/ModernTreeBehavior.php into built-in file TreeBehavior.php and load TreeBehavior.php, everything so goods.
Can you tell me the reason?
The namespace declaration of your class is wrong, it should be:
namespace App\Model\Behavior;
I get the above error when I try and logout by hitting the route /logout. The table that is referenced in the screenshot is mdbids. It stores all of my IDs (strings, 16 characters in length).
When a user is created their MDBID (id) is stored in the mdbids table.
routes.php
<?php
Route::get('login', ['as' => 'login', 'uses' => 'SessionsController#create']);
Route::get('logout', ['as' => 'logout', 'uses' => 'SessionsController#destroy']);
SessionsController.php
<?php
use MDB\Forms\LoginForm;
class SessionsController extends \BaseController {
protected $loginForm;
function __construct(LoginForm $loginForm)
{
$this->loginForm = $loginForm;
}
public function create()
{
if(Auth::check()) return Redirect::to("/users");
return View::make('sessions.create');
}
public function store()
{
$this->loginForm->validate($input = Input::only('email','password'));
if (Auth::attempt($input)) {
Notification::success('You signed in successfully!');
return Redirect::intended('/');
}
Notification::error('The form contains some errors');
return Redirect::to('login')->withInput()->withFlashMessage("The form contains some errors");
}
public function destroy()
{
Auth::logout();
return Redirect::home();
}
}
The following is taken from my User.php (model) file. It isn't the whole file as it is fairly big, but this is the only part where IDs are mentioned.
User.php (model)
<?php
public function save(array $options = array())
{
$this->mdbid = $this->mdbid ?: str_random(16);
$this->key = $this->key ?: str_random(11);
Mdbid::create([
'mdbid' => $this->mdbid,
'table_number' => 7,
'table_name' => 'users',
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
]);
parent::save($options);
}
I don't know where to start to look. Any help is greatly appreciated.
Your issue is that the logout is actually causing save() to run, and therefor you are causing Mdbid::create to run with an already added key (presumably when you logged in, or somewhere else in your User model?).
Solution #1:
You could add a logout() function to the User model that you have. Something similar to
function logout()
{
$this->mdbid = null;
return Auth::logout()
}
This will stop two of the same keys being added to the logout function.
Solution #2
If what you are trying to accomplish is adding a row upon a successful login, then you should not be using the User::save() function, rather, you should be listening for the auth.login event.
Inside app/start/global.php, add the following code:
Event::listen('auth.login', function($user)
{
$user->mdbid = $user->mdbid ?: str_random(16);
$user->key = $user->key ?: str_random(11);
Mdbid::create([
'mdbid' => $user->mdbid,
'table_number' => 7,
'table_name' => 'users',
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
]);
});
This will ensure only one row gets added to Mdbid per successful login, instead of adding a new row (with the same id) each time the User model is updated.
Solution #3 (a.k.a. what was really wanted)
Each table has mdbid as a primary key. Each primary key needs to be added to the Mdbid table each time a new row is inserted.
The way that this should be done is with an Observer. The first part is adding a new Observer class that will be used for all of the models we want to add the mdbid into:
class MdbidObserver
{
/**
* Observe new rows being added into the database
*/
public function creating($model)
{
// note that $model could be any model
$model->mdbid = $model->mdbid ?: str_random(16);
$model->key = $model->key ?: str_random(11);
Mdbid::create([
'mdbid' => $model->mdbid,
'table_number' => 7,
'table_name' => 'users',
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
]);
}
}
The second part is adding the Observer to all the models that we want the mdbid added to (inside app/start/global.php):
User::observe(new MdbidObserver);
Artist::observe(new MdbidObserver);
Album::observe(new MdbidObserver);
To stop any issues with mdbid not actually being random already being used, you might want to add a loop just before $model->mdbid. Something similar to:
$isUnique = false;
while (!$isUnique)
{
$unqiueId = str_random(16);
$row = Mdbid::where('mdbid', $uniqueId);
if (is_object($row))
$isUnique = true;
}
$model->mdbid = $uniqueId;