cakephp / orm

[READ-ONLY] A flexible, lightweight and powerful Object-Relational Mapper for PHP, implemented using the DataMapper pattern. This repo is a split of the main code that can be found in https://github.com/cakephp/cakephp

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Aliases X propertyName problems

gildonei opened this issue · comments

Hi,
I guess that Cake isn't preserving table alias when creating some associations like in the case below.

I have the following Table objects

PessoasTable

class PessoasTable extends AppTable
{
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setAlias('Pessoa');
        $this->setEntityClass('Pessoa');
        $this->setTable('pessoas');
        $this->setPrimaryKey('id');
        $this->setDisplayField('ds_nome');

        $this->addAssociations([
            'hasOne' => [
                'Usuarios' => [
                    'className' => 'Usuarios',
                    'propertyName' => 'Usuario',
                    'foreignKey' => 'id',
                    'joinType' => 'LEFT',
                    'dependent' => true,
                ],
                'Pessoafisicas' => [
                    'className' => 'Pessoafisicas',
                    'propertyName' => 'Pessoafisica',
                    'foreignKey' => 'id',
                    'joinType' => 'LEFT',
                    'dependent' => true,
                ],
                ...

UsuariosTable

class UsuariosTable extends AppTable
{
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setAlias('Usuario');
        $this->setEntityClass('Usuario');
        $this->setTable('usuarios');
        $this->setPrimaryKey('id');
        $this->setDisplayField('ds_login');

        $this->addAssociations([
            'belongsTo' => [
                'Pessoas' => [
                    'className' => 'Pessoas',
                    'propertyName' => 'Pessoa',
                    'foreignKey' => 'id',
                    'joinType' => 'INNER',
                ]
            ],
        ]);
    }
...

PessoafisicasTable

class PessoafisicasTable extends AppTable
{
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->setAlias('Pessoafisica');
        $this->setEntityClass('Pessoafisica');
        $this->setTable('pessoafisicas');
        $this->setDisplayField('nr_cpf');
        $this->setPrimaryKey('id');

        $this->addAssociations([
            'belongsTo' => [
                'Pessoas' => [
                    'className' => 'Pessoas',
                    'propertyName' => 'Pessoa',
                    'foreignKey' => 'id',
                    'joinType' => 'INNER',
                ],
            ]
        ]);
    }
    ...

In UsuariosController the following find is producing the SQL query bellow

$usuario = $this->Usuarios->get($id, [
            'fields' => ['id', 'ds_login'],
            'contain' => [
                'Pessoas' => [
                    'fields' => ['id', 'ds_nome'],
                    'Pessoafisicas'
                ],
            ]);

SQL output

SELECT 
  Usuario.id AS `Usuario__id`, 
  Usuario.ds_login AS `Usuario__ds_login`, 
  Pessoas.id AS `Pessoas__id`, 
  Pessoas.ds_nome AS `Pessoas__ds_nome` 
FROM 
  usuarios Usuario 
  INNER JOIN pessoas Pessoas ON Pessoas.id = (Usuario.id) 
  LEFT JOIN pessoafisicas Pessoafisicas ON Pessoa.id = (Pessoafisicas.id) 
WHERE 
  Usuario.id = 4 
LIMIT 
  1

Error Note that CakePHP isn't respecting my table Alias name in Pessoas and neither in Pessoafisicas but in ON condition thru Pessoa and Pessoafisica it is.

I think it is not documented coreectly, but the alis for each table does is set by the association name, for example, when you created the hasOne association.

The alias is the key name in the array, and you set it as Usuarios, instead of Usuario, for example.
Since the alias is overridden when creating the association, it is generally not recommended to call setAlias() yourself and it will just cause confusion.

So why UsuariosTable is being aliased on result SQL?

It depends on the table you query, but the associations alias will always take precedence, and can lead to this kind of problems. Just use the association aliasing and not the setAlias() function

It does not make sense, according to your comment above, all my query should be in singular like it happen to Usuario not plural because I adopted the same name rule for Pessoas e Pessoafisicas.

Debugging code, I guess in \Cake\ORM\Association -> _joinCondition -> $tAlias = $this->_name should be $this->getTarget()->getAlias() just like $sAlias = $this->getSource()->getAlias();

@gildonei did my explanation help fixing your problem?

Not yet, I am still debuggin to find where the ORM get the table name to mount associations to create joins. I think it is using _name intead of _alias just like it is happening in _joinCondition

I give up! Cound't find a solution! I will remove setAlias from tables. If possible I would like to ask ORM team to perform some tests with this case. I am sure that something odd happening, like I mentioned in \Cake\ORM\Association -> _joinCondition (method).

In all honesty, having setAlias() as a method in the table was a big mistake in my original design, it causes this kind of confusions. Try to avoid it in the future and use the aliasing provided by the association classes.