Giter Site home page Giter Site logo

yii2-save-relations-behavior's People

Contributors

bookin avatar dd174 avatar execut avatar juban avatar k0r73z avatar leandrogehlen avatar malinink avatar sankam-nikolya avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yii2-save-relations-behavior's Issues

Delete relation on array field postgresql

I have array field with ids of 3 related items and hasMany relation. Then I delete one of them and
when I try to save the model it is deleted. I think the problem is in the method $model->unlink($relationName, $initialModels[$key], true). Since there is no via table and a parameter $delete is true it deletes the parent model.

Don't work with some relations

Migration

 $this->createTable('{{%project}}', [
            'id' => $this->primaryKey(),
            'name' => $this->string(32)->notNull(),
        ]);
 $this->createTable('{{%project_company}}', [
            'id' => $this->primaryKey(),
            'project_id' => $this->integer()->notNull(),
            'title' => $this->string(64)->notNull(),
            'desc' => $this->text()->notNull(),
        ]);

Model

use lhs\Yii2SaveRelationsBehavior\SaveRelationsBehavior;

class Project extends \yii\db\ActiveRecord
{
    public function behaviors()
    {
        return [
            'saveRelations' => [
                'class'     => SaveRelationsBehavior::className(),
                'relations' => [ 'company'],
            ],
        ];
    }

    public function transactions()
    {
        return [
            self::SCENARIO_DEFAULT => self::OP_ALL,
        ];
    }

    /**
     * @return ActiveQuery
     */
    public function getCompany()
    {
        return $this->hasOne(ProjectCompany::className(), ['project_id' => 'id']);
    }

   // other relations
}

This code don't work, because project_id don't set automatically

$project = Project::findOne(1);
$project->company = ['title' => 'new company']; 
$project->save();

Some issue with one-to-one relationship

Thank you for your useful extension. I would like to give you feedback to enhance your extension. Version is 1.3.1.

I have some issue with saving new models Dummy and DummyBrother if I try to save with validation. There will be an SQL error anyway. Saving Dummy and DummyMany models works fine.

2017-10-29 22:07:15 [127.0.0.1][-][-][warning][lhs\Yii2SaveRelationsBehavior\SaveRelationsBehavior::saveRelatedRecords] yii\db\Exception was thrown while saving related records during beforeValidate event: SQLSTATE[HY000]: General error: 1364 Field 'dummy_id' doesn't have a default value

I have to save Dummy model without validation. It works if I do only like that.

I would be grateful if this case would be considered in tests.

...
class Dummy extends \yii\db\ActiveRecord
{
    public function behaviors()
    {
        return [
            'saveRelations' => [
                'class'    => SaveRelationsBehavior::class,
                'relations' => ['dummyBrother', 'dummyManies']
            ],
        ];
    }

    public function transactions()
    {
        return [
            self::SCENARIO_DEFAULT => self::OP_ALL,
        ];
    }
...
CREATE TABLE dummy (
  id int(11) NOT NULL AUTO_INCREMENT,
  name varchar(50) NOT NULL,
  PRIMARY KEY (id)
)
ENGINE = INNODB
AUTO_INCREMENT = 1
CHARACTER SET utf8
COLLATE utf8_general_ci
ROW_FORMAT = DYNAMIC;

CREATE TABLE dummy_brother (
  dummy_id int(11) NOT NULL,
  name varchar(50) NOT NULL,
  PRIMARY KEY (dummy_id),
  UNIQUE INDEX UK_dummy_brother_dummy_id (dummy_id),
  CONSTRAINT FK_dummy_brother_dummy_id FOREIGN KEY (dummy_id)
  REFERENCES dummy (id) ON DELETE NO ACTION ON UPDATE RESTRICT
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci
ROW_FORMAT = DYNAMIC;

CREATE TABLE dummy_many (
  id int(11) NOT NULL AUTO_INCREMENT,
  dummy_id int(11) NOT NULL,
  name varchar(50) NOT NULL,
  PRIMARY KEY (id),
  CONSTRAINT FK_dummy_many_dummy_id FOREIGN KEY (dummy_id)
  REFERENCES dummy (id) ON DELETE NO ACTION ON UPDATE RESTRICT
)
ENGINE = INNODB
AUTO_INCREMENT = 1
CHARACTER SET utf8
COLLATE utf8_general_ci
ROW_FORMAT = DYNAMIC;

Enh: Аdjust access to save the relation

Is there such a functional?
For example, I need adjust access. So that only the admin could save relation tags

public function scenarios()
{
    $s = parent::scenarios();
    if(Yii::$app->user->can('admin')){
        $s[self::SCENARIO_DEFAULT][] = 'tags';
    }
    return $s;
}
var_dump($project->isAttributeSafe('tags')); //false

But relation tags save anyway when $project->save();

Only write, not rewrite

I have a relation (has many) model and when saved common model I would like SaveRelationsBehavior only write new record to db. Now SaveRelationsBehavior every time rewriting relations data. This my behavior in model:

public function behaviors() {
        return [
            [
                'class' => SaveRelationsBehavior::class,
                'relations' => [
                    'vacancies',
                    'resumes'
                ],
            ],
        ];
    }

So, how can I do to only writer SaveRelationsBehavior?

Using behavior for relations

Hi!

You can make the functionality, that can configure relations through behavior?

Before:

    public function getUser()
    {
        return $this->hasOne(User::class, ['user_id' => 'id']);
    } 

After:

...
    private User $user
...
    /**
     * @var User $user
     **/
    public function getUser()
    {
        return $this->user;
    }

...
    public function behaviors()
    {
        return [
            'saveRelations' => [
                'class'     => SaveRelationsBehavior::class,
                'relations' => [
                     'users' => [
                          'class' => User::class,
                          'relation' => 'has-one',
                          'link' => ['user_id' => 'id']
                     ],
                ],
            ],
        ];
    }  
...

Now we can call get User and we won't get AR in response.

Allow saving extra columns to junction table

Currently it the behavior code it is hard coded that the yii\db\BaseActiveRecord->link method is called without a possible third parameter.

The third parameter is used for passing additional columns data to be saved to the junction table in a many-to-many relationship through a junction table.
http://www.yiiframework.com/doc-2.0/yii-db-baseactiverecord.html#link()-detail

It would be nice if the behavior would allow to pass and save/update such additional columns in the junction table utilizing this native Yii2 method.

For example it could be made with declaring a callback in the behavior configuration that returns an array of the junction table column values for each ActiveRecord instance being saved,

An example:

/** @inheritdoc */
    public function behaviors()
    {
        return [
            'saveRelations' => [
                'class'     => SaveRelationsBehavior::class,
                'relations' => [
                    'photos'
                ],
                'junctionTableProperties' => [
                    'photos' => function (\yii\db\ActiveRecord $record) :array {
                        return [
                            'order' => $record->order
                        ];
                    }
                ]
            ]
        ];
    }

Nested model changes does not save if parent model not dirty.

I have three level of models:

model1 {
  id: id1,
  prop1: value1,
  nested1: [
    model2 {
      id: id2,
      prop2: value2,
      nested2: [
        model3 {
          id: id3,
          prop3: value3
        }
      ]
    }
  ]
}

I want to change only prop3 of model3, but can not do this, because parent model has no dirty attributes, so nested models does not saves:

564      if (count($relationModel->dirtyAttributes)) {
565         if ($relationModel->validate()) {
566             $relationModel->save();
567         } else {
568             $this->_addError($relationModel, $owner, $relationName, self::prettyRelationName($relationName));
569             throw new DbException('Related record ' . self::prettyRelationName($relationName) . ' could not be saved.');
570         }
571      }

https://github.com/la-haute-societe/yii2-save-relations-behavior/blob/master/src/SaveRelationsBehavior.php#L564

Load relations with Json Data

This JSON can't be loaded on $model->load(Yii::$app->request->post())... Just with : $model->attributes, but this doesn't load the relations
{ "id":"6", "idEscolaridade":"16", "descricao":"teste", "salario":5500.00, "Escolaridades":{ "id":"16", "descricao":"testando" } }

I'm using 'jaacoder/yii2-activated' to mapping the attributes, works for the parent model, but doesn't work for related models (ID column only)

Can't set virtual attribute for ActiveRecord

My ActiveRecord class has the attribute

class Profile extends ActiveRecord
{
   /**
     * @var bool
     */
    public $agree;

public function rules()
    {
        return [
         
            [['agree'], 'required', 'on' => 'insert'],
         
        ];
    }
}

But i have got an error "Failed to set unsafe attribute 'agree' in 'app\models\user\Profile'."

I found out we have to set scenario here if scenario provided by behavior

$relationModel->setAttributes($data);

Anyway it helps me to work/ Isn't it the right case?

Validation trouble

if i use input form like

<?= $form->field($user, 'profile[opf_id]')->dropDownList(Opf::getDropDown(), ['prompt' => ''])
                        ->label(Profile::instance()->getAttributeLabel('opf_id')); ?>

i didn't watch validation errors.

i found out that your method has to be like

 private function _addError($relationModel, $owner, $relationName, $prettyRelationName)
    {
        foreach ($relationModel->errors as $attribute=>$attributeErrors) {
            foreach ($attributeErrors as $error) {
                $owner->addError("{$relationName}[{$attribute}][]", "{$prettyRelationName}: {$error}");
            }
        }
    }

it helps to render any error for related inputs.
How is the right way to build form-field statement and validate input data in my case?

attributeBehavior for primarykey reset populated hasmany relations

i have a UniquIdBehavior for id (primary key)

this reset populated relations, after yiisoft/yii2#13618 pr merged:

public function __set($name, $value)
    {
        if ($this->hasAttribute($name)) {
            if (
                !empty($this->_relationsDependencies[$name])
                && (!array_key_exists($name, $this->_attributes) || $this->_attributes[$name] !== $value)
            ) {
                $this->resetDependentRelations($name);
            }
            $this->_attributes[$name] = $value;
        } else {
            parent::__set($name, $value);
        }
    }

feature request - work only existing models, or create new

Hi,

i have a scenario where i would like to work on huge form saved by this behavior. My only problem is i need to put the ids on the form for multi input if i would like to keep old records, and not always delete and create new ones.

what if somebody is overwriting id-s in hidden input than this behaviour will try to load it from db with that id. It could happen the user receives data which they should not see, and will linked to him.

i would suggest a small extra here, there could be a mode where it can only work with existing models, it checks was the model already in hasmany relation, if not then it will be created.

what do you think?

Fail when parent model has more than one PRIMARY KEY

Hello,

In short words:
If my model has more than one PK like 'id' and 'timestamp'.
Then your code is failing here:


    private function _prepareHasOneRelation(BaseActiveRecord $model, $relationName, ModelEvent $event)
    {
        Yii::debug("_prepareHasOneRelation for {$relationName}", __METHOD__);
        $relationModel = $model->{$relationName};
        $this->validateRelationModel(self::prettyRelationName($relationName), $relationName, $model->{$relationName});
        $relation = $model->getRelation($relationName);
        $p1 = $model->isPrimaryKey(array_keys($relation->link)); <<<<HERE only 'id' is passed to isPrimaryKey()
        $p2 = $relationModel::isPrimaryKey(array_values($relation->link));

        if ($relationModel->getIsNewRecord() && $p1 && !$p2) {
            // Save Has one relation new record
            if ($event->isValid && (count($model->dirtyAttributes) || $model->{$relationName}->isNewRecord)) {
                Yii::debug('Saving ' . self::prettyRelationName($relationName) . ' relation model', __METHOD__);
                if ($model->{$relationName}->save()) {
                    $this->_savedHasOneModels[] = $model->{$relationName};
                }
            }
        }
    }

But frankly speaking I'm not sure that bug on your side.
Thats why I've rised same question on YII2 project
And where I described my problem in all details.

If I where you, I would avoid usage of function BaseActiveRecord::isPrimaryKey()
And use your own implementaion instead.

1:1 connection - feature request

Hi,

do you see a solution where it could work with 1:1 connections as well?

i have a table: product (primary key product_id)
and product_coupon (primary key product_id)
and product_room (primary key product_id)

product_coupon, product_room are extending product base info.

what do you think?

How Save hasOne relation from InputForm

I have

class Project extends \yii\db\ActiveRecord
{
    use SaveRelationsTrait; // Optional

    public function behaviors()
    {
        return [
            'saveRelations' => [
                'class'     => SaveRelationsBehavior::className(),
                'relations' => ['videos', 'company']
            ],
        ];
    }

    /**
     * @return ActiveQuery
     */
    public function getCompany()
    {
        return $this->hasOne(Company::className(), ['id' => 'company_id']);
    }

    /**
     * @return ActiveQuery
     */
    public function getVideos()
    {
        return $this->hasMany(Videos::className(), ['project_id' => 'id']);
    }
}

and form

$form->field($project, 'company[name]')->textarea(); // value is it, but not saved
$form->field($project, 'videos[0][name]')->textarea(); // saved good!
$form->field($project, 'videos[1][name]')->textarea(); // saved good!

In ProjectController I see

$_POST[Project][company][name] = 'Company name';  // This value not saved
$_POST[Project][videos][0][name] = 'Video 1 name'; // // This value saved

    public function actionUpdate($id)
    {
        $model = Project::findOne($id);
        $request = Yii::$app->request;
        $load = $model->load($request->post());

        $model->save(); // relation video saved, relation company - not saved

}

Company name not saved in my controller.

updated values of the relations cannot be correctly accessed in the afterSave method of the master model

Hello!
I don't know exactly is this a bug or not but will try explain my problem.
Suppose we have Orders and OrderItems.

Orders:

class Order ... {

....

public function behaviors()
{
return [
.....
[
'class' => SaveRelationsBehavior::class,
'relations' => [
'orderItems'
]
],
.....
];
}

public function getOrderItems()
{
return $this->hasMany(OrderItem::class, ['order_id' => 'order_id']);
}

public function afterSave($insert, $changedAttributes)
{
var_dump(count($this->orderItems)); die();
retrun parent::afterSave($insert, $changedAttributes);
}

....

}

$order = new Order();
$order->orderItems = OrderItem[]; // simplified code
$order->save();

after that i see that afterSave method: count($this->orderItems) = 0.

but

$order = Order::findOne(1);
$order->orderItems = OrderItem[]; // simplified code
$order->save();

after that i see that afterSave: count($this->orderItems) > 0.

When i insert a new Order, before insert OrderItems i want to modify them. I can modify only when updating the Order, not when inserting.

Separation of validation and saving does unique validation not possible

When i save a model with "hasMany" relation it does validate each of relations from an array and then saving them with ->save(false). But i have the unique validation rule in relation model, which shouldn't let it save both of them in this example:

ParentModel [
    'property' => 'value',
    'relation' => [
        [
            'name' => 'ex1',
            'uniqueField' => 1,
        ],
        [
            'name' => 'ex2',
            'uniqueField' => 1,//shouldn't be saved
        ],
    ],
]

Logs:

  1. SELECT CASE WHEN EXISTS(SELECT * FROM relation WHERE uniqueField = 1) THEN 1 ELSE 0 END FROM DUAL; /* validation of ex1 */
  2. SELECT CASE WHEN EXISTS(SELECT * FROM relation WHERE uniqueField = 1) THEN 1 ELSE 0 END FROM DUAL; /* validation of ex2 */
  3. INSERT ... ex1
  4. INSERT ... ex2

Instead of SELECT /ex1/, INSERT /ex1/, SELECT /ex2/, addError

hasOne relation via() is not working as expected

it creates new linking all the time, if i am populating it from a POST.

becouse of this: (line 279)
$relationModel = null; if (!empty($fks)) { $relationModel = $modelClass::findOne($fks); }

it creates a new instance
than (line 664)
if ($this->_oldRelationValue[$relationName] !== $owner->{$relationName}) {
will be false all the time. it links again, whenever it was a existing relation or not.

i am using php7.1

Updating multiple records in nested related model

Scenario :

$scenarios[self::SCENARIO_SAVE_STEP_2] = ['company', 'address', 'vehicles', 'id'];

Behavior :

    public function behaviors() {
            return [
                'saveRelations' => [
                    'class'     => SaveRelationsBehavior::className(),
                    'relations' => [
                        'company' => ['scenario' => Company::SCENARIO_COMPANY],
                        'address' => ['scenario' => Address::SCENARIO_PROFILE_COMPANY],
                        'vehicles' => ['scenario' => Vehicle::SCENARIO_PROFILE_VEHICLE]
                      ]
                  ],
            ];
    }

example : In User Model,

    $user = User::findOne($this->id);
    $user->scenario = User::SCENARIO_SAVE_STEP_2;
    $user->load(Yii::$app->getRequest()->getBodyParams(), '');

Payloads,

    {
    id:1,
    name : "adam",
        company : {
            id : "2",
            userid : "1",
            name : "My Company",
            logo : {
                id : "1",
                url : "http://myimage.com/logo.png"
                }
        },
        address : {
            id : "1",
            userid : "1",
            name : "My Company",
        },
        vehicles : [
            { 

             id : 2,
             type : "two wheeler"
             licenseImages : [{
                id : "3",
                url : "http://myimage.com/license.png"
                }]

             },

            { 

             id : 3,
             type : "four wheeler"
             licenseImages : [{
                id : "4",
                url : "http://myimage.com/license.png"
                }]

             }

        ]
    }

This is working:

1. New record save for hasOne relation, when primary key is given blank.

2. New data for Nested relation hasMany, data is saving.

This is NOT working:

1. Existing record update for hasOne relation, when primary key is given.
2. Existing data for Nested relation hasMany, data is not saving, with primary key given in payload.
3. New data is not saving for hasMany relation when data is given in array (ref. vehicles in above example).
4. Existing data is not saving for hasMany relation when data is given in array (ref. vehicles in above example), with primary key i.e id.
5. New or Existing data for Nested relation hasMany, data is not saving, with primary key given in payload. (ref. vehicles->licenseImages in above example)

My system configuration :
Yii2 = Version 2.0.14
PHP = Version 7.1.20
Mysql Server = Version 5.7.23
Extenstion = Version ^1.5

Strange behavior saving newly created hasOne entity

I have a Profile Model. The model saved into database and has an ID. It has relation
public function getPerson()
{
return $this->hasOne(Person::className(), ['user_id' => 'user_id']);
}
Both user_id are primary key (One to One). But no person record exists.
Of course a have no

field($model, 'person[user_id]')->hiddenInput(); ?>

line in the view file

Then i save the Profile. It throws an constrait error.

if ($model->{$modelAttribute} !== $model->{$relationName}->{$relatedAttribute}) {
sets primary key of Profile model to null because $model->{$modelAttribute} !== $model->{$relationName}->{$relatedAttribute} where $model->{$relationName}->{$relatedAttribute} is null

It happens because Person model has not been saved because

if ($relationModel->getIsNewRecord() && $p1 && !$p2) {
Line return false because $p2 is primary key. And person model has been validated only. Why are so difficult conditions (i am not allowed to have both as pk)?

#29 has a similar issue. Possibly we don't unserstand how to manipulate hasOne relations..

Yii::debug("Setting foreign keys for {$relationName}", __METHOD__);
writes me "Setting foreign keys for person" but
$model->{$modelAttribute} = $model->{$relationName}->{$relatedAttribute};
sets Profile property to null in my case.

Sort related models

It will be great if related models will be sorted and user can swap the related models

Deep nesting relations saving

Wrong saving a nested relations with one main.

Models relations example.

Main has many Child, Child has one SubChild.

<?php
namespace api\models;

use lhs\Yii2SaveRelationsBehavior\SaveRelationsBehavior;
.....
class Main extends \yii\db\ActiveRecord
{

    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
			.....
            [
                'class' => SaveRelationsBehavior::className(),
                'relations' => [
                    'childs'
                ]
            ],
			.....
        ];
    }

    /**
     * @return array
     */
    public function transactions()
    {
        return [
            self::SCENARIO_DEFAULT => [
                self::OP_ALL
            ]
        ];
    }

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return '{{%main}}';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        .....
    }
	
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getChilds()
    {
        return $this->hasMany(Child::className(), ['child_id' => 'id']);
    }

    /**
     * @inheritdoc
     * @return \api\models\scopes\MainQuery the active query used by this AR class.
     */
    public static function find()
    {
        return new \api\models\scopes\MainQuery(get_called_class());
    }
}
<?php

namespace api\models;
.....
use lhs\Yii2SaveRelationsBehavior\SaveRelationsBehavior;

class Child extends \yii\db\ActiveRecord
{
    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
			......
            [
                'class' => SaveRelationsBehavior::className(),
                'relations' => [
                    'subChild'
                ]
            ],
			.....
        ];
    }

    /**
     * @return array
     */
    public function transactions()
    {
        return [
            self::SCENARIO_DEFAULT => [
                self::OP_ALL
            ]
        ];
    }

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return '{{%child}}';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
			....
        ];
    }

    public static function create(/** some params **/)
    {
        $iteration = new static();
        $iteration->subChild = SubChild::create(/** some params **/);

        return $child;
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getSubChild()
    {
        return $this->hasOne(SubChild::className(), ['sub_child_id' => 'id']);
    }

 
    public static function find()
    {
        return new \api\models\scopes\ChildQuery(get_called_class());
    }
}
<?php

namespace api\models;

class SubChild extends \yii\db\ActiveRecord
{

    /**
     * @return array
     */
    public function transactions()
    {
        return [
            self::SCENARIO_DEFAULT => [
                self::OP_ALL
            ]
        ];
    }

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return '{{%sub_child}}';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
			....
        ];
    }

    /**
     * @return static
     */
    public static function create(/**  some params **/)
    {
        $subChild = new static();

        return $subChild;
    }
}

Save Main model instance

$banner = new Main();
$banner->load($form->attributes,'');
$banner->child = Child::create(/** some params**/);

$banner->save();

Trouble

In this case relations must saves recursively, but in beforeValidate behavior method raises exception:

[lhs\Yii2SaveRelationsBehavior\SaveRelationsBehavior::saveRelatedRecords] yii\db\IntegrityException was thrown while saving related records during beforeValidate event: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`schema`.`sub_child`, CONSTRAINT `fk-sub_child-child` FOREIGN KEY (`child_id`) REFERENCES `child` (`id`) ON UPDATE CASCADE)
The SQL being executed was: INSERT INTO `sub_child` (`state`, `created_at`) VALUES ('skipped', UNIX_TIMESTAMP())
    in /dd_main/web/sites/chulakov/bander/api/vendor/la-haute-societe/yii2-save-relations-behavior/src/SaveRelationsBehavior.php:300
    in /dd_main/web/sites/chulakov/bander/api/vendor/la-haute-societe/yii2-save-relations-behavior/src/SaveRelationsBehavior.php:233
    in /dd_main/web/sites/chulakov/bander/api/vendor/la-haute-societe/yii2-save-relations-behavior/src/SaveRelationsBehavior.php:340
2017-11-06 12:33:16 [192.168.1.1][1][-][error][yii\db\Exception] exception 'yii\db\Exception' with message 'Failed to commit transaction: transaction was inactive.' in /dd_main/web/sites/chulakov/bander/api/vendor/yiisoft/yii2/db/Transaction.php:151
Stack trace:
#0 /dd_main/web/sites/chulakov/bander/api/vendor/yiisoft/yii2/db/ActiveRecord.php(486): yii\db\Transaction->commit()
#1 /dd_main/web/sites/chulakov/bander/api/vendor/yiisoft/yii2/db/BaseActiveRecord.php(646): yii\db\ActiveRecord->insert(true, NULL)
#2 /dd_main/web/sites/chulakov/bander/api/api/repositories/BannerRepository.php(17): yii\db\BaseActiveRecord->save()
#3 /dd_main/web/sites/chulakov/bander/api/api/services/BannerService.php(64): api\repositories\BannerRepository->save(Object(api\models\Banner))
#4 /dd_main/web/sites/chulakov/bander/api/api/controllers/BannerController.php(95): api\services\BannerService->upload(Object(api\forms\BanderUpload))
#5 [internal function]: api\controllers\BannerController->actionUpload()
#6 /dd_main/web/sites/chulakov/bander/api/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
#7 /dd_main/web/sites/chulakov/bander/api/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction->runWithParams(Array)
#8 /dd_main/web/sites/chulakov/bander/api/vendor/yiisoft/yii2/base/Module.php(528): yii\base\Controller->runAction('upload', Array)
#9 /dd_main/web/sites/chulakov/bander/api/vendor/yiisoft/yii2/web/Application.php(103): yii\base\Module->runAction('banner/upload', Array)
#10 /dd_main/web/sites/chulakov/bander/api/vendor/yiisoft/yii2/base/Application.php(386): yii\web\Application->handleRequest(Object(yii\web\Request))
#11 /dd_main/web/sites/chulakov/bander/api/api/web-test/index.php(18): yii\base\Application->run()
#12 {main}

Foreign key value not append to insert query. This error appears in saving with validation. If save the main instance without validation no errors raised.

No SaveRelationsTrait.php file

There is no SaveRelationsTrait.php file, when I install this extension throw composer.
"src" folder contains only SaveRelationsBehavior.php

Trying to set ID of parent model to null

Hello!

https://monosnap.com/file/BV4PyFdUKuOLvhoj6K3a06wNKcqpPS

I have a problem with saving parent model. When I specifying relation on line SaveRelationBehavior:253 behavior replace primary key of main model and set foreign key of related model.
foreach ($relation->link as $relatedAttribute => $modelAttribute) { if ($model->{$modelAttribute} !== $model->{$relationName}->{$relatedAttribute}) { $model->{$modelAttribute} = $model->{$relationName}->{$relatedAttribute}; } }

but I have related attribute value is NULL and it's breaking saving process;

I think, solution is check NOT EMPTY related attribute ($model->{$relationName}->{$relatedAttribute})

Error Unable to link models: the primary key of

You have an error from 384 to 386 lines.

$p1 = $model->isPrimaryKey(array_keys ($relation->link));
$p2 = $relationModel::isPrimaryKey(array_values($relation->link));
if ($relationModel->getIsNewRecord () & & $p1 && !$p2) {
...

What's the point? With such a relations

    public function getCompany()
    {
        return $this->hasOne(Company:: className (), ['id' = > 'company_id']);
    } 

if the parent class has properties primarykey (in your example on the main page Project ) the same as the relation class (in your example on the main page Company ) then your behavior will work.
But if in Project establish primaryKey as project_id the will error

Unable to link models: the primary key of ...

because relation class not save
as for me it is more correct to write the following code

$p1 = $model->isPrimaryKey(array_values($relation->link));
$p2 = $relationModel:: isPrimaryKey(array_keys($relation->link));
if ($relationModel->getIsNewRecord() && !$p1 & & $p2) {

почему так для relation
$this->hasOne(Company::className(), ['id' => 'company_id']);


array_keys($relation->link)='id'
array_values($relation->link)='company_id'

"private" replace with "protected".

Now some properties and methods are declared as "private". It does not allow to expand the behavior.

I suggest instead of "private" to use "protected".

usage question maybe a bug?

hi,

i just cannot find out how this is working. i did put it in my project, did set up as an document, but it is just not working. i did recognised some parts which could be buggy, but of course if it works for everyone else, than the problem will be with me.

if i add new line here :

protected function _setRelationForeignKeys($relationName)
{
/** @var BaseActiveRecord $owner /
$owner = $this->owner;
/
* @var ActiveQuery $relation */
$relation = $owner->getRelation($relationName);
if ($relation->multiple === false && !empty($owner->{$relationName})) {
Yii::debug("Setting foreign keys for {$relationName}", METHOD);
foreach ($relation->link as $relatedAttribute => $modelAttribute) {
if ($owner->{$modelAttribute} !== $owner->{$relationName}->{$relatedAttribute}) {
if ($owner->{$relationName}->isNewRecord) {
$owner->{$relationName}->{$relatedAttribute} = $owner->{$modelAttribute};
$owner->{$relationName}->save();
}
$owner->{$modelAttribute} = $owner->{$relationName}->{$relatedAttribute};
}
}
}
}

than it starts working for me as well. i just could not find out where will be set all the foreign keys.

the another one is:
_prepareHasOneRelation
in my mind this one is wrong:
$p1 = $model->isPrimaryKey(array_keys($relation->link));
$p2 = $relationModel::isPrimaryKey(array_values($relation->link));
the first one should be array_values, second array_keys. but maybe i don't understand the porpuse of the method.

my setup is really strait forward:

        'saveRelations' => [
            'class' => SaveRelationsBehavior::class,
            'relations' => [
                'personDetail',
                'personAddress',
                'personEmails',
                'personPhones',
                'personSocials',
                'user',
            ],
        ]

but it cannot handle new records, it deals perfect with existing ones. My db should be ok, gii can generate model properly.

Transaction object may not be defined

The transaction object may not be defined if an exception occurs in the _saveRelatedRecords method and no transactions are declared in the owner model.

hasOne relation not rollback when owner model is not valid and relation are inserted

The hasOne relationships are saved and inserted in beforeValidate and if owner model not inserted due to validation error hasOne inserted relations not rollback.

How to Test:

In model Project, name attribute is required and if you don't set name, $project->save() will be failed, but company record willl be inserted in database.

public function testSaveNewHasOneRelationShouldSucceed()
{
$project = new Project();
//$project->name = "Java";
$company = new Company();
$company->name = "Oracle";
$project->company = $company;
$this->assertTrue($company->isNewRecord, 'Company should be a new record');
$this->assertTrue($project->save(), 'Project could not be saved');
$this->assertNotNull($project->company_id, 'Company ID should be set');
$this->assertEquals($project->company_id, $company->id, 'Company ID is not the one expected');
}

hasMany relations with no pivot table are not saved correctly

For hasMany relations not using a junction table with via() method, records are not saved during the beforeValidate event if the foreign key is set as 'NOT NULL'.
These kind of record should be saved during the afterSave event of the owner model.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.