CakePHP 3.x - 跨多个表保存关联数据

CakePHP 3.x - Saving associated data across multiple tables

我在尝试将数据保存在关联的 table 中时遇到问题(目前,当我保存它时,它只保存在初始 table 中,而不是其他的)。

所以我的第一个 table(用户):

-id
-username
-password
-email

第二 table(艺术家):

-name
-cp_id (foreign key)
-user_id (foreign key)
-genre

第三个table(联系人):

-cp_firstname
-cp_lastname
-cp_email
-cp_phoneno

关系:

A User hasOne Artist. An Artist belongsTo a User. (1-1) 
An Artist belongsTo Contactperson. A Contactperson hasMany Artists (1 to many)

user_id in Artists references id in Users
cp_id in Artists references id in Contactpersons

在我的用户控制器中:

public function artistregister()
    {
        $user = $this->Users->newEntity();
        if($this->request->is('post')){
          $data = $this->request->data;
          $data['role_id'] = "2"; //role_id 2 makes the user register as role = artist
          $user = $this->Users->patchEntity($user, $data);
          $save = $this->Users->save($user);
          if ($save) {
            $user_id = $save->id;
            $data['user_id'] = $user_id;
            $ContactPersonsController = new ContactPersonsController();
            $ContactPersonsController->artistregister($data);
            $ArtistController = new ArtistsController();
            $ArtistController->artistregister($data);
            $this->Flash->success(__('Registration completed'));
            return $this->redirect(['action' => 'login']);
          } else {
            $this->Flash->error(__('Registration failed. Please try again.'));
          }
        }
        $artists = $this->Users->Artists->find('all');
        $persons = $this->Users->Artists->ContactPersons->find('all')->toArray();
        $this->set(compact('user', 'artists', 'roles', 'contactpersons','persons'));
          $this->set('_serialize', ['user']);
    }

然后在Contactpersons控制器中,同样的功能:

public function artistregister($data)
    {
    if ($this->Contactpersons)
        $contactperson = $this->Contactpersons->newEntity();
        $contactperson = $this->Contactpersons->patchEntity($contactperson, $data);
        if ($this->Contactpersons->save($contactperson)) {
            $this->Flash->error(__('Contact person details could not be saved. Please try again.'));
        }
        $this->set(compact('contactpersons'));
        $this->set('_serialize', ['contactperson']);
    }

还有ArtistsController,同样的功能:

public function artistregister($data)
    {
        $artist = $this->Artists->newEntity();
    $user = $this->request->session()->read('Auth.User');
    $data['user_id'] = $user['id'];
    $contactperson = $this->request->session()->read('Auth.Contactpersons') //I put in Auth.Contactpersons as a placeholder, but I'm not really sure what to put there.
    $data['cp_id'] = $contactperson['id'];
        $artist = $this->Artists->patchEntity($artist, $data);
        if ($this->Artists->save($artist)) {
            $this->Flash->error(__('Artist profile details could not be saved. Please try again.'));
        }
        $contactpersons = $this->Artists->Contactpersons->find('list', ['limit' => 200]);
        $this->set(compact('artist', 'contactpersons'));
        $this->set('_serialize', ['artist']);
    }

哦,好的,这里是 Artistregister.ctp 文件:

<div class="container" style="margin-top: 70px;">
    <?= $this->Flash->render('auth') ?>
    <?php $this->Form->templates([
        'inputContainer' => '<div class="form-group">{{content}}</div>',
        'inputContainerError' => '<div class="error" style="color:red;">{{content}}{{error}}</div>'
    ]);?>
    <div class="col-sm-2">
    </div>
    <div class="col-sm-8">
        <div class="container col-sm-12" style="border-radius: 10px; border: 1px solid;" >
            <?= $this->Form->create($user, ['role'=>'form']) ?>
            <header><?= __('Artist Registration') ?></header>
            <legend><?= __('User Account Details') ?></legend>
            <div class="col-sm-6">
                <?= $this->Form->input('username', ['class'=>'form-control',
                'placeholder'=>'Please enter a username.']);?>
            </div>
            <div class="col-sm-6">
                <?= $this->Form->input('email', ['class'=>'form-control', 'type'=>'email',
                'placeholder'=>'Please enter an email address.']);?>
            </div>
            <div class="col-sm-6">
                <?= $this->Form->input('password', ['class'=>'form-control', 'type'=>'password',
              'placeholder'=>'Please enter a password.']);?>
            </div>
            <div class="col-sm-6">
                <?= $this->Form->input('confirm_password', array('type'=>'password',
                    'label'=>'Confirm Password', 'value'=>'', 'autocomplete'=>'off','class'=>'form-control',
                  'placeholder'=>'Please re-enter your password.'))?>
            </div>
            <legend><?= __('Artist Profile Details') ?></legend>
            <div class="col-sm-12">
                <?= $this->Form->input('name', ['class'=>'form-control', 'label'=>'Artist Name',
              'placeholder'=>'Please enter your artist name.']);?>
            </div>
            <div class="col-sm-12">
                <?= $this->Form->input('genre', ['class'=>'form-control', 'type'=>'textarea', 'label'=>'Genres',
              'placeholder'=>'Please enter a description of the genres you play.']);?>
            </div>
            <legend><?= __('Contact Person Details') ?></legend>
            <div class="col-sm-6">
                <?= $this->Form->input('cp_firstname', ['class'=>'form-control', 'label'=>'First Name',
              'placeholder'=>'Please enter the first name of your contact.']);?>
            </div>
            <div class="col-sm-6">
                <?= $this->Form->input('cp_lastname', ['class'=>'form-control', 'label'=>'Last Name',
              'placeholder'=>'Please enter the last name of your contact.']);?>
            </div>
            <div class="col-sm-6">
                <?= $this->Form->input('cp_phoneno', ['class'=>'form-control','type'=>'tel', 'label'=>'Phone Number',
              'placeholder'=>'Please enter the phone number of your contact.']);?>
            </div>
            <div class="col-sm-6">
                <?= $this->Form->input('cp_email', ['class'=>'form-control','type'=>'email', 'label'=>'Email', 
              'placeholder'=>'Please enter the email of your contact.']);?>
            </div>
            <legend></legend>
            <div class="col-sm-12" >
                <?= $this->Form->button('<strong>'.__('Register').'</strong>',
                    ['class'=>'btn btn-primary', 'style'=>'width:100%;']); ?>
            </div>
            <div class="col-sm-12" align="center" style="margin-bottom: 20px;">
                <?= $this->Html->link(__("Already have an account? Log in"), ['action'=>'logout'])?>
            </div>
            <?= $this->Form->end() ?>
        </div>
    </div>
    <div class="col-sm-2">
    </div>
</div>

因此,当我转到艺术家注册页面,填写字段并单击提交时,所有与用户 table 相关的数据都已提交,但联系人和艺术家 table 仍为空白。目前我得到的错误是:

Call to undefined method App\Controller\ContactpersonsController::artistregister()

引用的行是:

$ContactPersonsController->artistregister($data);

在用户控制器中。

同时,如果我交换被调用函数的顺序(即在 ContactpersonsController 之前调用 ArtistsController),我会收到此错误:

syntax error, unexpected '$data' (T_VARIABLE)

引用的行是:

$data['cp_id'] = $contactperson['id'];

这一行是在 ArtistsController 函数中找到的。

我很确定我得到这个错误是因为不存在联系人,因此它找不到一个 id 来作为 cp_id - 这就是为什么在 UsersController 函数中,我首先调用了 ContactpersonsController 来在 Contactpersons table.

中建立一些数据

为每个添加模型:

联系人:

class ContactpersonsTable extends Table
{

    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->table('contactpersons');
        $this->displayField('id');
        $this->primaryKey('id');
    }

    public function validationDefault(Validator $validator)
    {
        $validator
            ->integer('id')
            ->allowEmpty('id', 'create');

        $validator
            ->requirePresence('cp_firstname', 'create')
            ->notEmpty('cp_firstname');

        $validator
            ->requirePresence('cp_lastname', 'create')
            ->notEmpty('cp_lastname');

        $validator
            ->requirePresence('cp_email', 'create')
            ->notEmpty('cp_email');

        $validator
            ->integer('cp_phoneno')
            ->requirePresence('cp_phoneno', 'create')
            ->notEmpty('cp_phoneno');

        return $validator;
    }
}

艺术家:

class ArtistsTable extends Table
{

    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->table('artists');
        $this->displayField('name');
        $this->primaryKey('id');

        $this->addBehavior('Timestamp');

        $this->belongsTo('Contactpersons', [
            'foreignKey' => 'cp_id',
            'joinType' => 'INNER'
        ]);
        $this->belongsTo('Users', [
            'foreignKey' => 'user_id',
            'joinType' => 'INNER'
        ]);
        $this->hasMany('Bookings', [
            'foreignKey' => 'artist_id'
        ]);
    }

    public function validationDefault(Validator $validator)
    {
        $validator
            ->integer('id')
            ->allowEmpty('id', 'create');

        $validator
            ->requirePresence('name', 'create')
            ->notEmpty('name');

        $validator
            ->allowEmpty('genre');

        return $validator;
    }

    public function buildRules(RulesChecker $rules)
    {
        $rules->add($rules->existsIn(['cp_id'], 'Contactpersons'));
        $rules->add($rules->existsIn(['user_id'], 'Users'));

        return $rules;
    }
}

用户:

class UsersTable extends Table
{
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->table('users');
        $this->displayField('id');
        $this->primaryKey('id');

        $this->addBehavior('Timestamp');

        $this->belongsTo('Roles', [
            'foreignKey' => 'role_id',
            'joinType' => 'INNER'
        ]);

        $this->hasOne('Artists', [
                'foreignKey' => 'user_id'
        ]);

            $this->hasOne('Engineers', [
                'foreignKey' => 'user_id'
        ]);
    }

    public function validationDefault(Validator $validator)
    {
        $validator
            ->integer('id')
            ->allowEmpty('id', 'create');

        $validator
            ->requirePresence('username', 'create')
            ->notEmpty('username');

        $validator
            ->requirePresence('password', 'create')
            ->notEmpty('password');

        $validator
            ->email('email')
            ->requirePresence('email', 'create')
            ->notEmpty('email');

        return $validator;
    }

    public function buildRules(RulesChecker $rules)
    {
        $rules->add($rules->isUnique(['username']));
        $rules->add($rules->isUnique(['email']));
        $rules->add($rules->existsIn(['role_id'], 'Roles'));

        return $rules;
    }
}

将html更改为:

<div class="container" style="margin-top: 70px;">
    <?= $this->Flash->render('auth') ?>
    <?php $this->Form->templates([
        'inputContainer' => '<div class="form-group">{{content}}</div>',
        'inputContainerError' => '<div class="error" style="color:red;">{{content}}{{error}}</div>'
    ]);?>
    <div class="col-sm-2">
    </div>
    <div class="col-sm-8">
        <div class="container col-sm-12" style="border-radius: 10px; border: 1px solid;" >
            <?= $this->Form->create($user, ['role'=>'form']) ?>
            <header><?= __('Artist Registration') ?></header>
            <legend><?= __('User Account Details') ?></legend>
            <div class="col-sm-6">
                <?= $this->Form->input('username', ['class'=>'form-control',
                'placeholder'=>'Please enter a username.']);?>
            </div>
            <div class="col-sm-6">
                <?= $this->Form->input('email', ['class'=>'form-control', 'type'=>'email',
                'placeholder'=>'Please enter an email address.']);?>
            </div>
            <div class="col-sm-6">
                <?= $this->Form->input('password', ['class'=>'form-control', 'type'=>'password',
              'placeholder'=>'Please enter a password.']);?>
            </div>
            <div class="col-sm-6">
                <?= $this->Form->input('confirm_password', array('type'=>'password',
                    'label'=>'Confirm Password', 'value'=>'', 'autocomplete'=>'off','class'=>'form-control',
                  'placeholder'=>'Please re-enter your password.'))?>
            </div>
            <legend><?= __('Artist Profile Details') ?></legend>
            <div class="col-sm-12">
                <?= $this->Form->input('artist.name', ['class'=>'form-control', 'label'=>'Artist Name',
              'placeholder'=>'Please enter your artist name.']);?>
            </div>
            <div class="col-sm-12">
                <?= $this->Form->input('artist.genre', ['class'=>'form-control', 'type'=>'textarea', 'label'=>'Genres',
              'placeholder'=>'Please enter a description of the genres you play.']);?>
            </div>
            <legend><?= __('Contact Person Details') ?></legend>
            <div class="col-sm-6">
                <?= $this->Form->input('contactperson.cp_firstname', ['class'=>'form-control', 'label'=>'First Name',
              'placeholder'=>'Please enter the first name of your contact.']);?>
            </div>
            <div class="col-sm-6">
                <?= $this->Form->input('contactperson.cp_lastname', ['class'=>'form-control', 'label'=>'Last Name',
              'placeholder'=>'Please enter the last name of your contact.']);?>
            </div>
            <div class="col-sm-6">
                <?= $this->Form->input('contactperson.cp_phoneno', ['class'=>'form-control','type'=>'tel', 'label'=>'Phone Number',
              'placeholder'=>'Please enter the phone number of your contact.']);?>
            </div>
            <div class="col-sm-6">
                <?= $this->Form->input('contactperson.cp_email', ['class'=>'form-control','type'=>'email', 'label'=>'Email', 
              'placeholder'=>'Please enter the email of your contact.']);?>
            </div>
            <legend></legend>
            <div class="col-sm-12" >
                <?= $this->Form->button('<strong>'.__('Register').'</strong>',
                    ['class'=>'btn btn-primary', 'style'=>'width:100%;']); ?>
            </div>
            <div class="col-sm-12" align="center" style="margin-bottom: 20px;">
                <?= $this->Html->link(__("Already have an account? Log in"), ['action'=>'logout'])?>
            </div>
            <?= $this->Form->end() ?>
        </div>
    </div>
    <div class="col-sm-2">
    </div>
</div>

将 UsersController 更改为:

public function artistregister()
{
    $user = $this->Users->newEntity();
    if($this->request->is('post')){
        $data = $this->request->data;
        $data['role_id'] = "2"; //role_id 2 makes the user register as role = artist
        $user = $this->Users->patchEntity($user, $data, ['associated' => ['ContactPersons', 'Artists']]);
        $save = $this->Users->save($user);
        if ($save) {
            $this->Flash->success(__('Registration completed'));
            return $this->redirect(['action' => 'login']);
        } else {
            $this->Flash->error(__('Registration failed. Please try again.'));
        }
    }
    $artists = $this->Users->Artists->find('all');
    $persons = $this->Users->Artists->ContactPersons->find('all')->toArray();
    $this->set(compact('user', 'artists', 'roles', 'contactpersons','persons'));
    $this->set('_serialize', ['user']);
}

得到答案 - 在 CakePHP Cookbook 的帮助下,根据@Derek 提供的内容稍作修改。

public function artistregister()
    {
        $user = $this->Users->newEntity($this->request->data(),[
          'associated'=>[
            'Artists' => ['associated' => ['Contactpersons']]
          ]
        ]);
        if($this->request->is('post')){
          $data = $this->request->data;
          $data['role_id'] = "2";
          $user = $this->Users->patchEntity($user, $data, [
            'associated'=>[
              'Artists' => ['associated' => ['Contactpersons']]
            ]
          ]);
          $save = $this->Users->save($user);
          $user_id = $save->id;
          $data['user_id'] = $user_id;
          $this->Flash->success(__('Registration completed'));
          return $this->redirect(['action' => 'login']);
        } else {
          $this->Flash->error(__('Registration failed. Please try again.'));
        }
        $this->set(compact('user', 'artists', 'roles', 'contactpersons'));
          $this->set('_serialize', ['user']);
    }