【问题标题】:In CakePHP 3, how can I create a new Entity with BelongsToMany records including join data?在 CakePHP 3 中,如何创建一个包含 BelongsToMany 记录的新实体,包括连接数据?
【发布时间】:2016-09-13 19:48:49
【问题描述】:

用经典的 BelongsToMany 示例的说法,我正在尝试创建一个具有关联课程记录的新学生,以及每个学生课程的 final_grade 数据。 (课程记录本身已经存在。)当我尝试创建学生时,我发送courses[0][_joinData][course_id]courses[0][_joinData][final_grade],但是当它尝试保存新的 CoursesStudents 记录时,验证抱怨它没有student_id 字段。我无法传递它,因为它还不存在!

我可以通过将数据发送为courses[_ids] 将新学生记录与现有课程相关联,这样可以正确地为连接表的新记录选择course_id 的新配置课程的id。但我还没有找到一种方法来包含非默认连接数据。

(我的真实模型是 AccessGroups 和 Markets,但关系是相同的。我希望能够在创建时将新 AccessGroup 与特定 access_level 的现有 Market 相关联,而无需生成AccessGroupsMarkets 事后记录。)

编辑

代码:

按照@burzum 的建议,我正在添加我的代码以及我从 CakePHP 得到的响应:

// in a controller
$accessGroupsTable = TableRegistry::get('AccessGroups');

$data = [
    'name' => 'Test for Access Group with Market Join Data',
    'access_group_type_id' => '1',
    'project_id' => '49',
    'markets' => [
        0 => [
            'id' => '46',
            '_joinData' => [
                'market_id' => '46',
                'access_level' => '2',
            ]
        ],
        1 => [
            'id' => '47',
            '_joinData' => [
                'market_id' => '47',
                'access_level' => '2',
            ]
        ]
    ],
];

$newAccessGroup = $accessGroupsTable->newEntity($data);
debug(["newAccessGroup", $newAccessGroup], false); // debug!
$saved = $accessGroupsTable->save($newAccessGroup);
debug(["saved", $saved], false); // debug!

回应:

/src/Controller/AccessGroupsController.php (line 161)
########## DEBUG ##########
[
    (int) 0 => 'newAccessGroup',
    (int) 1 => object(App\Model\Entity\AccessGroup) {

        'name' => 'Test for Access Group with Market Join Data',
        'access_group_type_id' => (int) 1,
        'project_id' => (int) 49,
        'markets' => [
            (int) 0 => object(App\Model\Entity\Market) {

                'id' => (int) 46,
                'project_id' => (int) 49,
                'name' => 'United States - Flammmo',
                'created' => object(Cake\I18n\Time) {

                    'time' => '2016-05-13T18:42:11+00:00',
                    'timezone' => 'UTC',
                    'fixedNowTime' => false

                },
                'modified' => object(Cake\I18n\Time) {

                    'time' => '2016-05-13T18:42:11+00:00',
                    'timezone' => 'UTC',
                    'fixedNowTime' => false

                },
                'deleted' => null,
                '_joinData' => object(App\Model\Entity\AccessGroupsMarket) {

                    'market_id' => (int) 46,
                    'access_level' => (int) 2,
                    '[new]' => true,
                    '[accessible]' => [
                        'market_id' => true,
                        'access_group_id' => true,
                        'access_level' => true
                    ],
                    '[dirty]' => [
                        'market_id' => true,
                        'access_level' => true
                    ],
                    '[original]' => [],
                    '[virtual]' => [],
                    '[errors]' => [
                        'access_group_id' => [
                            '_required' => 'This field is required'
                        ]
                    ],
                    '[invalid]' => [],
                    '[repository]' => 'AccessGroupsMarkets'

                },
                '[new]' => false,
                '[accessible]' => [
                    '*' => true
                ],
                '[dirty]' => [
                    '_joinData' => true
                ],
                '[original]' => [
                    '_joinData' => [
                        'market_id' => '46',
                        'access_level' => '2'
                    ]
                ],
                '[virtual]' => [
                    (int) 0 => 'flag_url'
                ],
                '[errors]' => [],
                '[invalid]' => [],
                '[repository]' => 'Markets'

            },
            (int) 1 => object(App\Model\Entity\Market) {

                'id' => (int) 47,
                'project_id' => (int) 49,
                'name' => 'Indonesia - Flammmo',
                'created' => object(Cake\I18n\Time) {

                    'time' => '2016-06-24T16:24:57+00:00',
                    'timezone' => 'UTC',
                    'fixedNowTime' => false

                },
                'modified' => object(Cake\I18n\Time) {

                    'time' => '2016-06-24T16:24:57+00:00',
                    'timezone' => 'UTC',
                    'fixedNowTime' => false

                },
                'deleted' => null,
                '_joinData' => object(App\Model\Entity\AccessGroupsMarket) {

                    'market_id' => (int) 47,
                    'access_level' => (int) 2,
                    '[new]' => true,
                    '[accessible]' => [
                        'market_id' => true,
                        'access_group_id' => true,
                        'access_level' => true
                    ],
                    '[dirty]' => [
                        'market_id' => true,
                        'access_level' => true
                    ],
                    '[original]' => [],
                    '[virtual]' => [],
                    '[errors]' => [
                        'access_group_id' => [
                            '_required' => 'This field is required'
                        ]
                    ],
                    '[invalid]' => [],
                    '[repository]' => 'AccessGroupsMarkets'

                },
                '[new]' => false,
                '[accessible]' => [
                    '*' => true
                ],
                '[dirty]' => [
                    '_joinData' => true
                ],
                '[original]' => [
                    '_joinData' => [
                        'market_id' => '47',
                        'access_level' => '2'
                    ]
                ],
                '[virtual]' => [
                    (int) 0 => 'flag_url'
                ],
                '[errors]' => [],
                '[invalid]' => [],
                '[repository]' => 'Markets'

            }
        ],
        '[new]' => true,
        '[accessible]' => [
            'project_id' => true,
            'access_group_type_id' => true,
            'name' => true,
            'slug' => true,
            'features' => true,
            'assets' => true,
            'markets' => true,
            'child_groups' => true,
            'users' => true
        ],
        '[dirty]' => [
            'name' => true,
            'access_group_type_id' => true,
            'project_id' => true,
            'markets' => true
        ],
        '[original]' => [],
        '[virtual]' => [],
        '[errors]' => [],
        '[invalid]' => [],
        '[repository]' => 'AccessGroups'

    }
]
###########################
/src/Controller/AccessGroupsController.php (line 177)
########## DEBUG ##########
[
    (int) 0 => 'saved',
    (int) 1 => false
]
###########################

注意两个市场的 _joinData access_group_id 上的验证错误

工作代码不是我想要的

$accessGroupsTable = TableRegistry::get('AccessGroups');

$data2 = [
    'name' => 'Test for Access Group with Market IDs',
    'access_group_type_id' => '1',
    'project_id' => '49',
    'markets' => [
        '_ids' => [ 46, 47 ],
    ],
];

$newAccessGroup = $accessGroupsTable->newEntity($data2);
$saved = $accessGroupsTable->save($newAccessGroup);

此代码成功创建了新的 AccessGroup 以及关联的新 AccessGroupsMarkets 记录,但使用的是 access_level 的默认值,而不是我希望能够指定的值。

@systematical 询问有关表设置的问题。它们是从 migration 生成的,然后是 cake/bake'd(参见 Table associations

【问题讨论】:

  • 如果您不显示实际代码,您很可能得不到任何帮助。如果没有代码可以提供任何建议,所有文本都是无用的。
  • @burzum 所说的,除了代码之外,数据库模式的 sn-p 也不会受到伤害。你有没有用蛋糕/烘焙来做这些东西并遵循蛋糕惯例?它通常很擅长处理这些东西。
  • 感谢您的反馈。我希望我的编辑将有助于确定在初始创建父实体时添加连接表数据的方法。

标签: php cakephp join cakephp-3.0


【解决方案1】:

问题(由 IRC #cakephp 上的@npm 指出)是我正在对连接表模型中的外键进行验证:

// in AccessGroupsMarketsTable::validationDefault
$validator
    ->requirePresence('access_group_id', 'create')
    ->notEmpty('access_group_id')
    ->add('access_group_id', 'valid', ['rule' => 'numeric']);

$validator
    ->requirePresence('market_id', 'create')
    ->notEmpty('market_id')
    ->add('market_id', 'valid', ['rule' => 'numeric']);

这是对 buildRules 中 $rules 的补充:

$rules->add($rules->existsIn(['access_group_id'], 'AccessGroups'));
$rules->add($rules->existsIn(['market_id'], 'Markets'));

@npm 建议我删除对这些外键的验证(保留$rules)。他的建议奏效了。我现在可以保存新的 AccessGroups 实体及其相关的 AccessGroupsMarkets 记录及其关联的 access_level 信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-15
    • 2019-12-15
    相关资源
    最近更新 更多