|
|
@@ -16,6 +16,7 @@ namespace Cake\ORM\Rule;
|
|
|
|
|
|
use Cake\Datasource\EntityInterface;
|
|
|
use Cake\ORM\Association;
|
|
|
+use RuntimeException;
|
|
|
|
|
|
/**
|
|
|
* Checks that the value provided in a field exists as the primary key of another
|
|
|
@@ -57,22 +58,34 @@ class ExistsIn
|
|
|
* @param \Cake\Datasource\EntityInterface $entity The entity from where to extract the fields
|
|
|
* @param array $options Options passed to the check,
|
|
|
* where the `repository` key is required.
|
|
|
+ * @throws \RuntimeException When the rule refers to an undefined association.
|
|
|
* @return bool
|
|
|
*/
|
|
|
public function __invoke(EntityInterface $entity, array $options)
|
|
|
{
|
|
|
if (is_string($this->_repository)) {
|
|
|
- $this->_repository = $options['repository']->association($this->_repository);
|
|
|
- }
|
|
|
-
|
|
|
- $source = !empty($options['repository']) ? $options['repository'] : $this->_repository;
|
|
|
+ $alias = $this->_repository;
|
|
|
+ $this->_repository = $options['repository']->association($alias);
|
|
|
|
|
|
- $source = $source instanceof Association ? $source->source() : $source;
|
|
|
- $target = $this->_repository;
|
|
|
+ if (empty($this->_repository)) {
|
|
|
+ throw new RuntimeException(sprintf(
|
|
|
+ "ExistsIn rule for '%s' is invalid. The '%s' association is not defined.",
|
|
|
+ implode(', ', $this->_fields),
|
|
|
+ $alias
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ $source = $target = $this->_repository;
|
|
|
+ if (!empty($options['repository'])) {
|
|
|
+ $source = $options['repository'];
|
|
|
+ }
|
|
|
+ if ($source instanceof Association) {
|
|
|
+ $source = $source->source();
|
|
|
+ }
|
|
|
if ($target instanceof Association) {
|
|
|
$bindingKey = (array)$target->bindingKey();
|
|
|
- $target = $this->_repository->target();
|
|
|
+ $target = $target->target();
|
|
|
} else {
|
|
|
$bindingKey = (array)$target->primaryKey();
|
|
|
}
|
|
|
@@ -85,25 +98,37 @@ class ExistsIn
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- $nulls = 0;
|
|
|
- $schema = $source->schema();
|
|
|
- foreach ($this->_fields as $field) {
|
|
|
- if ($schema->column($field) && $schema->isNullable($field) && $entity->get($field) === null) {
|
|
|
- $nulls++;
|
|
|
- }
|
|
|
- }
|
|
|
- if ($nulls === count($this->_fields)) {
|
|
|
+ if ($this->_fieldsAreNull($entity, $source)) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
$primary = array_map(
|
|
|
- [$this->_repository, 'aliasField'],
|
|
|
+ [$target, 'aliasField'],
|
|
|
$bindingKey
|
|
|
);
|
|
|
$conditions = array_combine(
|
|
|
$primary,
|
|
|
$entity->extract($this->_fields)
|
|
|
);
|
|
|
- return $this->_repository->exists($conditions);
|
|
|
+ return $target->exists($conditions);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Check whether or not the entity fields are nullable and null.
|
|
|
+ *
|
|
|
+ * @param \Cake\ORM\EntityInterface $entity The entity to check.
|
|
|
+ * @param \Cake\ORM\Table $source The table to use schema from.
|
|
|
+ * @return bool
|
|
|
+ */
|
|
|
+ protected function _fieldsAreNull($entity, $source)
|
|
|
+ {
|
|
|
+ $nulls = 0;
|
|
|
+ $schema = $source->schema();
|
|
|
+ foreach ($this->_fields as $field) {
|
|
|
+ if ($schema->column($field) && $schema->isNullable($field) && $entity->get($field) === null) {
|
|
|
+ $nulls++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $nulls === count($this->_fields);
|
|
|
}
|
|
|
}
|