ソースを参照

Fix up validateUnique for null values

mscherer 2 年 前
コミット
8e201d7622

+ 19 - 5
src/Model/Table/Table.php

@@ -63,17 +63,31 @@ class Table extends ShimTable {
 	 * the same site_id. Scoping will only be used if the scoping field is present in
 	 * the data to be validated.
 	 *
-	 * @override To allow multiple scoped values
+	 * @override To allow multiple scoped fields with NULL values.
 	 *
 	 * @param mixed $value The value of column to be checked for uniqueness
 	 * @param array<string, mixed> $options The options array, optionally containing the 'scope' key
-	 * @param array $context The validation context as provided by the validation routine
+	 * @param array|null $context The validation context as provided by the validation routine
 	 * @return bool true if the value is unique
 	 */
-	public function validateUniqueExt($value, array $options, array $context = []) {
-		$context += $options;
+	public function validateUniqueExt($value, array $options, ?array $context = null) {
+		$data = $context['data'] ?? null;
+		if ($data) {
+			foreach ($data as $field => $value) {
+				if (empty($options['scope']) || !in_array($field, $options['scope'], true)) {
+					continue;
+				}
+
+				if ($value === '') {
+					$value = null;
+				}
+
+				$data[$field] = $value;
+			}
+			$context['data'] = $data;
+		}
 
-		return parent::validateUnique($value, $context);
+		return parent::validateUnique($value, $options, $context);
 	}
 
 	/**

+ 16 - 16
tests/TestCase/Model/Behavior/ConfirmableBehaviorTest.php

@@ -31,16 +31,16 @@ class ConfirmableBehaviorTest extends TestCase {
 	 * @return void
 	 */
 	public function testBasicValidation() {
-		$this->Articles = $this->getTableLocator()->get('SluggedArticles');
-		$this->Articles->addBehavior('Tools.Confirmable');
+		$Articles = $this->getTableLocator()->get('SluggedArticles');
+		$Articles->addBehavior('Tools.Confirmable');
 
-		$animal = $this->Articles->newEmptyEntity();
+		$animal = $Articles->newEmptyEntity();
 
 		$data = [
 			'name' => 'FooBar',
 			'confirm' => '0',
 		];
-		$animal = $this->Articles->patchEntity($animal, $data);
+		$animal = $Articles->patchEntity($animal, $data);
 		$this->assertNotEmpty($animal->getErrors());
 		$this->assertSame(['confirm' => ['notBlank' => __d('tools', 'Please confirm the checkbox')]], $animal->getErrors());
 
@@ -48,7 +48,7 @@ class ConfirmableBehaviorTest extends TestCase {
 			'name' => 'FooBar',
 			'confirm' => '1',
 		];
-		$animal = $this->Articles->patchEntity($animal, $data);
+		$animal = $Articles->patchEntity($animal, $data);
 		$this->assertEmpty($animal->getErrors());
 	}
 
@@ -56,9 +56,9 @@ class ConfirmableBehaviorTest extends TestCase {
 	 * @return void
 	 */
 	public function testValidationThatHasBeenModifiedBefore() {
-		$this->Articles = $this->getTableLocator()->get('SluggedArticles');
+		$Articles = $this->getTableLocator()->get('SluggedArticles');
 		/*
-		$this->Articles->validator()->add('confirm', 'notBlank', [
+		$Articles->validator()->add('confirm', 'notBlank', [
 				'rule' => function ($value, $context) {
 					return !empty($value);
 				},
@@ -67,18 +67,18 @@ class ConfirmableBehaviorTest extends TestCase {
 				'allowEmpty' => false,
 				'last' => true,
 			]);
-		$this->Articles->validator()->remove('confirm');
+		$Articles->validator()->remove('confirm');
 		*/
 
-		$this->Articles->addBehavior('Tools.Confirmable');
+		$Articles->addBehavior('Tools.Confirmable');
 
-		$animal = $this->Articles->newEmptyEntity();
+		$animal = $Articles->newEmptyEntity();
 
 		$data = [
 			'name' => 'FooBar',
 			'confirm' => '0',
 		];
-		$animal = $this->Articles->patchEntity($animal, $data);
+		$animal = $Articles->patchEntity($animal, $data);
 		$this->assertNotEmpty($animal->getErrors());
 
 		$this->assertSame(['confirm' => ['notBlank' => __d('tools', 'Please confirm the checkbox')]], $animal->getErrors());
@@ -87,7 +87,7 @@ class ConfirmableBehaviorTest extends TestCase {
 			'name' => 'FooBar',
 			'confirm' => '1',
 		];
-		$animal = $this->Articles->patchEntity($animal, $data);
+		$animal = $Articles->patchEntity($animal, $data);
 		$this->assertEmpty($animal->getErrors());
 	}
 
@@ -95,14 +95,14 @@ class ConfirmableBehaviorTest extends TestCase {
 	 * @return void
 	 */
 	public function testValidationFieldMissing() {
-		$this->Articles = $this->getTableLocator()->get('SluggedArticles');
-		$this->Articles->addBehavior('Tools.Confirmable');
+		$Articles = $this->getTableLocator()->get('SluggedArticles');
+		$Articles->addBehavior('Tools.Confirmable');
 
-		$animal = $this->Articles->newEmptyEntity();
+		$animal = $Articles->newEmptyEntity();
 		$data = [
 			'name' => 'FooBar',
 		];
-		$animal = $this->Articles->patchEntity($animal, $data);
+		$animal = $Articles->patchEntity($animal, $data);
 		$this->assertSame(['confirm' => ['_required' => 'This field is required']], $animal->getErrors());
 	}
 

+ 3 - 3
tests/TestCase/Model/Table/TableTest.php

@@ -67,9 +67,9 @@ class TableTest extends TestCase {
 	 * @return void
 	 */
 	public function testTimestamp() {
-		$this->Roles = $this->getTableLocator()->get('Roles');
-		$entity = $this->Roles->newEntity(['name' => 'Foo', 'alias' => 'foo']);
-		$result = $this->Roles->save($entity);
+		$Roles = $this->getTableLocator()->get('Roles');
+		$entity = $Roles->newEntity(['name' => 'Foo', 'alias' => 'foo']);
+		$result = $Roles->save($entity);
 		$this->assertTrue(!empty($result['created']));
 		$this->assertTrue(!empty($result['modified']));
 	}