cakephp icon indicating copy to clipboard operation
cakephp copied to clipboard

Utility\Hash error when trying to Table::save() a recursive association

Open celsowm opened this issue 3 years ago • 4 comments

Description

Using three tables (a,b and c):

image

sql here: https://gist.github.com/celsowm/68af8c0b7cb6e463d5aa10d28afec216

and Tables generated by bake where:

  • a hasMany b
  • b hasMany c
  • c belongsTo b and a

I tried this code:

$aTable = $this->getTableLocator()->get('A');
$bTable = $this->getTableLocator()->get('B');
$cTable = $this->getTableLocator()->get('C');
		
$a = $aTable->newEntity([
		'value' => 'my_a'
]);
$b = $bTable->newEntity([
		'value' => 'my_b'
]);
$c = $cTable->newEntity([
		'value' => 'my_c'
]);
		
$a->b = [$b];
$b->c = [$c];
$c->a = $a;
		
$aTable->save($a);

And got this error:

Warning: Uncaught Error in exception handling during call to Error::__toString() in C:\wamp64\www\cake_teste\vendor\cakephp\cakephp\src\Utility\Hash.php on line 660

The complete stack error (using xdebug) is available here: https://gist.github.com/celsowm/6e36a048f579a9ad07048556d67ca14b

So, I would like to know if there a way to handle with a situation similar to that, because I have a real model with some tables in a situation like that but I preferred create some dummy tables to simplify my point.

image

Thanks in advance.

CakePHP Version

4.4.4

PHP Version

8.1

celsowm avatar Aug 28 '22 13:08 celsowm

This is the same issue as https://github.com/cakephp/cakephp/issues/16588

LordSimal avatar Aug 28 '22 15:08 LordSimal

This is the same issue as #16588

Any suggestion for a quick fix? (In my case)

celsowm avatar Aug 28 '22 15:08 celsowm

The main problem here is the fact, that $a references itself via $a->b[0]->c[0]->a and therefore we run into an infinite loop trying to check for errors in all deep associations. (see the second error message in your xdebug log gist)

You can try the quick fix from the linked issue above - so edit the vendor/cakephp/cakephp/src/Datasource/EntityTrait.php and replace the public function hasErrors(bool $includeNested = true): bool with what is mentioned inside the linked issue.


But here is another way of thinking about your problem:

Why do you need the connection from C => A? Can't you get the the associated A record from C via C->B->A?

LordSimal avatar Aug 28 '22 15:08 LordSimal

Why do you need the connection from C => A? Can't you get the the associated A record from C via C->B->A?

This A,B,C situation is just a simplified version of the second model in the second image on the first post. In the real situation I need to save a processo_administrativo (lawsuit) with all the others entities in just one transaction and, one of them, has a similar behavior of C, its the documento_rascunho (draft) table

celsowm avatar Aug 28 '22 16:08 celsowm

The issue with hasErrors/getErrors has been fixed in #17333

markstory avatar Oct 08 '23 02:10 markstory