Cake "ignores" inserting associated data


#1

I found an issue in my application where when a user registers, it doesn’t insert the firstname and lastname into the associated table.
This was “intended” behaviour (more like: I forgot to implement this) back then so I started to fix it.

Fast forward two days and I can’t get it to work.
This is what I want:

  1. Create a new user entity (for the username, email, password and creation date) for the Users (named users in the db) table
  2. Add data to the associated UsersDetails (named users_details in the db) table
  3. Save it all
  4. Check whether it went right (to show success message or error message as needed)

This is the code I have currently written for that:

$user = $this->Users->newEntity([
  'username' => $this->request->getData('username'),
  'email' => $this->request->getData('email'),
  'password' => $this->request->getData('password'),
  'created' => date("Y-m-d H:i:s"),
  'users_details' => [
    'firstname' => '',
    'lastname' => ''
  ]
]);

if($this->Users->save($user)) {
...

The user is inserted into the Users table but Cake seems to “ignore” the fact that I added stuff to the UsersDetails table as well (so it doesn’t add a new entry to it).

This us my User entity file:

class User extends Entity {
    use UserTrait;

    protected $_accessible = [
        'username' => true,
        'email' => true,
        'password' => true,
        'created' => true,
        'articles' => true,
        'roles' => true,
        'users_details' => true
    ];

    protected $_hidden = [
        'password'
    ];
}

The UsersTable has an association to the UsersDetails table:

$this->hasOne('UsersDetails', [
    'foreignKey' => 'id',
    'joinType' => 'INNER'
]);

How can I make it work?

UPDATE: changed the belongsTo to hasOne


#2

rename users_details to users_detail as its belongsTo

https://book.cakephp.org/3.0/en/orm/saving-data.html#saving-belongsto-associations

When saving belongsTo associations, the ORM expects a single nested entity named with the singular

when in doubt how your post structure should looks like you can always get record first and take a peek

$user = $this->Users->findById(1)->contain(['UsersDetails'])->first();
dd($user);

#3

Doing this results in the error:

The UsersDetails association is not defined on Users.

Last time I encountered this issue I forgot to load the model (which I did this time).


#4

sounds like wrong namespace / filename / letter casing


#5
<?php
namespace Kikioboeru\Kikioboeru\Model\Table;

class UsersDetailsTable extends Table {
...

Loaded in the controller with:

$this->loadModel('Kikioboeru/Kikioboeru.UsersDetails');

#6

you are loading UsersDetails and trying to use Users table?


#7

I also have the Users Table loaded.
Like I said in the OP, I want to create a new user entity for the username, password and email and have associated data inserted into the UsersDetails table (the firstname and lastname of the user)


#8

So I have some progress.
$this->Users has no associations at all (even though specified in the UsersTable).

dd($this->Users);

results in:

Table {#239 
  +"registryAlias": "Users"
  +"table": "users"
  +"alias": "Users"
  +"entityClass": "Cake\ORM\Entity"
  +"associations": []
  +"behaviors": []
  +"defaultConnection": "default"
  +"connectionName": "default"
}

however, TableRegistry::get('Kikioboeru/Kikioboeru.Users') does have associations:

$usersTable = TableRegistry::get('Kikioboeru/Kikioboeru.Users');
dd($usersTable);

results in:

UsersTable {#272 
  +"registryAlias": "Kikioboeru/Kikioboeru.Users"
  +"table": "users"
  +"alias": "Users"
  +"entityClass": "Kikioboeru\Kikioboeru\Model\Entity\User"
  +"associations": array:3 [
    0 => "articles"
    1 => "roles"
    2 => "usersdetails"
  ]
  +"behaviors": array:1 [
    0 => "Timestamp"
  ]
  +"defaultConnection": "default"
  +"connectionName": "default"
}

Is this a bug in CakePHP or?

For those wondering, this is my initialize method:

public function initialize() {
      parent::initialize();

      $this->loadModel('Kikioboeru/Kikioboeru.Users');
      $this->loadModel('Kikioboeru/Kikioboeru.UsersDetails');
      $this->loadModel('Kikioboeru/Kikioboeru.ResetTokens');
      $this->loadModel('Kikioboeru/Kikioboeru.AuthTokens');
}

#9

Using the TableRegistry (instead of $this->Users) as shown above does make the issue go away.
Could somebody explain me why, even though I loaded the model it uses a completely different model instead?
It seems to have used some build-in model(?) instead of the one I specified in my controller.


#10

whats in parent::initialize() ? maybe you already have loaded Users table before loading your plugin Users table version


#11

Can you can use setProperty (or propertyName in array) to the relation to try force the association to be saved?


#12

How about

$userData =[
    'username' => $this->request->getData('username'),
    'email' => $this->request->getData('email'),
    'password' => $this->request->getData('password'),
    'created' => date("Y-m-d H:i:s"),
    'users_details' => [
        'firstname' => '',
        'lastname' => ''
    ]
];

$user = $this->Users->newEntity($userData, [‘associated’ => ‘UserDetails’]);
pr($user);


#13

There is one note of $this->loadModel('Users'); in the plugin’s AppController!
Unfortunately, I’ll have to try this out tomorrow when I have access to my workstation again.
Will report back!


#14

Jepp, this seemed to be the issue…

I have updated the “rules” of the project to prevent these issues down the road.