Saving associated data with hasOne association not working


#1

The problem: I want to create a company and its associated user using single form for company create

I have baked the scaffold and using CakePHP convention.

my association setup:-
CompaniesTable class

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

            $this->setTable('companies');
            $this->setDisplayField('name');
            $this->setPrimaryKey('id');

            $this->hasMany('Users', [
                'foreignKey' => 'company_id'
            ]);
        }

UsersTable

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

    $this->setTable('users');
    $this->setDisplayField('id');
    $this->setPrimaryKey('id');

    $this->addBehavior('Timestamp');

    $this->belongsTo('Companies', [
        'foreignKey' => 'company_id',
        'joinType' => 'INNER'
    ]);
    $this->belongsToMany('Roles', [
        'foreignKey' => 'user_id',
        'targetForeignKey' => 'role_id',
        'joinTable' => 'roles_users'
    ]);
}

I have used following code in my add.ctp to generate fields for user

<?=$this->Form->control('users.0.user_name');?>
<?=$this->Form->control('users.0.password');?> </div

code of add method in the controller

public function add()
{
$this->viewBuilder()->setLayout(false);
$company = $this->Companies->newEntity();
if ($this->request->is(‘post’)) {
$company = $this->Companies->patchEntity($company, $this->request->getData());

        if ($this->Companies->save($company)) {
            $this->Flash->success(__('The company has been saved.'));

            return $this->redirect(['action' => 'index']);
        }
        $this->Flash->error(__('The company could not be saved. Please, try again.'));
    }
    $this->set(compact('company'));
    $this->set('_serialize', ['company']);
}

my request data

[
‘name’ => ‘x’,
‘print_name’ => ‘x’,
‘address_line1’ => ‘x’,
‘address_line2’ => ‘x’,
‘city’ => ‘x’,
‘state’ => ‘x’,
‘country’ => ‘x’,
‘pincode’ => ‘x’,
‘current_financial_year’ => ‘x’,
‘organization_start_date’ => [
‘year’ => ‘2021’,
‘month’ => ‘03’,
‘day’ => ‘04’
],
‘currency_name’ => ‘x’,
‘currency_symbol’ => ‘x’,
‘currency_subname’ => ‘x’,
‘symbol_of_partition’ => ‘x’,
‘symbol_to_print’ => ‘xx’,
‘multi_currency_management’ => ‘0’,
‘has_pan’ => ‘0’,
‘has_gst’ => ‘0’,
‘has_tds’ => ‘0’,
‘has_tcs’ => ‘0’,
‘pan_number’ => ‘’,
‘gst_number’ => ‘’,
‘tds_number’ => ‘’,
‘tcs_number’ => ‘’,
‘pan_date’ => [
‘year’ => ‘2017’,
‘month’ => ‘12’,
‘day’ => ‘02’
],
‘gst_date’ => [
‘year’ => ‘2017’,
‘month’ => ‘12’,
‘day’ => ‘02’
],
‘tds_date’ => [
‘year’ => ‘2017’,
‘month’ => ‘12’,
‘day’ => ‘02’
],
‘tcs_date’ => [
‘year’ => ‘2017’,
‘month’ => ‘12’,
‘day’ => ‘02’
],
‘users’ => [
(int) 0 => [
‘user_name’ => ‘james’,
‘password’ => ‘password’
]
]
]

Thanks in advance for your help


#2

And what is the effect? Some error? or only new company without user? nothing?
Code of your form /template may also help.
Also debug in controller your entity after patch (and if you don’t guess by your self, paste it here)
debug($company);
Check for errors,dirty and isNew flags.
You can try to add [‘contain’=>‘Users’] to newEntinty and/or patchEntity and/or save. I remember that it can help if your associations aren’t saved.


#3

Only new company created without user


#4

I have changed my add method and it is working now. The only problem is that user entity accepts an empty string( i.e. user is not validated).

my code is

 public function add()
    {
        $this->viewBuilder()->setLayout(false);
       $company = $this->Companies->newEntity();

        if ($this->request->is('post')) {
            $company = $this->Companies->patchEntity( $company,$this->request->getData());
        
            $user = $this->Companies->users->newEntity();

            $userinfo = $this->request->getData('user');
           
            $user->email = $userinfo['email'];
            $user->user_name = $userinfo['user_name'];
            $user->password = $userinfo['password'];
            $company->users = [$user];
           
            if ($this->Companies->save($company)) {
              
                $this->Flash->success(__('The company has been saved.'));

                return $this->redirect(['controller'=>'Users','action' => 'login']);
            }
            $this->Flash->error(__('The company could not be saved. Please, try again.'));
        }
        $this->set(compact('company'));
        $this->set('_serialize', ['company']);
    }

#5

You can add validation in Table class https://book.cakephp.org/3.0/en/orm/validation.html#creating-a-default-validation-set

also it is possible to add company and user from one form, withoun manual re-write, but you must experiment by your self. I recomend to debug your variables after patchEntity and also after save. In most cases when saving goes ok you got new ID in your entities.

and adding [‘contain’=> …] is still actual (of course if want to avoid manual re-write)

ps. and check size of first letter and plural ending in users/companies/etc.


#6

thanks, I will experiment.


#7

your error lies in structure of data you are passing

<?=$this->Form->control('users.0.user_name');?>
<?=$this->Form->control('users.0.password');?>

when you are using hasOne it should be singular - https://book.cakephp.org/3.0/en/orm/saving-data.html#saving-hasone-associations so

<?= $this->Form->control('user.user_name') ?>
<?= $this->Form->control('user.password') ?>

if you have trouble remembering how to set your fields in form you can always fill database with fake data and get it to see how its constructed


#8

Try to check your allowed/accessible field list at
Entity/company & Entity user.

Entity/Company
’users’ => true

Entity/Users
company => true