Skip to content

Commit

Permalink
Merge pull request #15955 from cakephp/cascadedelete-null
Browse files Browse the repository at this point in the history
Allow association binding key to be null during cascadeDelete
  • Loading branch information
markstory committed Sep 29, 2021
2 parents a39b833 + d88be55 commit ffa65ce
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 2 deletions.
6 changes: 5 additions & 1 deletion src/ORM/Association/DependentDeleteHelper.php
Expand Up @@ -45,7 +45,11 @@ public function cascadeDelete(Association $association, EntityInterface $entity,
/** @psalm-suppress InvalidArgument */
$foreignKey = array_map([$association, 'aliasField'], (array)$association->getForeignKey());
$bindingKey = (array)$association->getBindingKey();
$conditions = array_combine($foreignKey, $entity->extract($bindingKey));
$bindingValue = $entity->extract($bindingKey);
if (in_array(null, $bindingValue, true)) {
return true;
}
$conditions = array_combine($foreignKey, $bindingValue);

if ($association->getCascadeCallbacks()) {
foreach ($association->find()->where($conditions)->all()->toList() as $related) {
Expand Down
41 changes: 41 additions & 0 deletions tests/Fixture/NullableAuthorsFixture.php
@@ -0,0 +1,41 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @since 4.2.10
* @license https://opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Test\Fixture;

use Cake\TestSuite\Fixture\TestFixture;

class NullableAuthorsFixture extends TestFixture
{
/**
* fields property
*
* @var array
*/
public $fields = [
'id' => ['type' => 'integer'],
'author_id' => ['type' => 'integer', 'null' => true],
'_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]],
];

/**
* records property
*
* @var array
*/
public $records = [
['author_id' => 3],
['author_id' => null],
];
}
33 changes: 32 additions & 1 deletion tests/TestCase/ORM/Association/HasOneTest.php
Expand Up @@ -33,7 +33,7 @@ class HasOneTest extends TestCase
*
* @var array
*/
protected $fixtures = ['core.Users', 'core.Profiles'];
protected $fixtures = ['core.Articles', 'core.Authors', 'core.NullableAuthors', 'core.Users', 'core.Profiles'];

/**
* @var bool
Expand Down Expand Up @@ -354,6 +354,37 @@ public function testCascadeDelete()
$this->assertSame(0, $query->count(), 'Matching record was deleted.');
}

/**
* Tests cascading deletes on entities with null binding and foreign key.
*/
public function testCascadeDeleteNullBindingNullForeign(): void
{
$Articles = $this->getTableLocator()->get('Articles');
$Authors = $this->getTableLocator()->get('NullableAuthors');

$config = [
'dependent' => true,
'sourceTable' => $Authors,
'targetTable' => $Articles,
'bindingKey' => 'author_id',
'foreignKey' => 'author_id',
'cascadeCallbacks' => false,
];
$association = $Authors->hasOne('Articles', $config);

// create article with null foreign key
$entity = new Entity(['author_id' => null, 'title' => 'this has no author', 'body' => 'I am abandoned', 'published' => 'N']);
$Articles->save($entity);

// get author with null binding key
$entity = $Authors->get(2, ['contain' => 'Articles']);
$this->assertNull($entity->article);
$this->assertTrue($association->cascadeDelete($entity));

$query = $Articles->query();
$this->assertSame(4, $query->count(), 'No articles should be deleted');
}

/**
* Test cascading delete with has one.
*
Expand Down

0 comments on commit ffa65ce

Please sign in to comment.