1: <?php
2: /**
3: * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4: * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
5: *
6: * Licensed under The MIT License
7: * For full copyright and license information, please see the LICENSE.txt
8: * Redistributions of files must retain the above copyright notice.
9: *
10: * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
11: * @link https://cakephp.org CakePHP(tm) Project
12: * @since 3.0.0
13: * @license https://opensource.org/licenses/mit-license.php MIT License
14: */
15: namespace Cake\ORM;
16:
17: use Cake\Datasource\RulesChecker as BaseRulesChecker;
18: use Cake\ORM\Rule\ExistsIn;
19: use Cake\ORM\Rule\IsUnique;
20: use Cake\ORM\Rule\ValidCount;
21:
22: /**
23: * ORM flavoured rules checker.
24: *
25: * Adds ORM related features to the RulesChecker class.
26: *
27: * @see \Cake\Datasource\RulesChecker
28: */
29: class RulesChecker extends BaseRulesChecker
30: {
31: /**
32: * Returns a callable that can be used as a rule for checking the uniqueness of a value
33: * in the table.
34: *
35: * ### Example:
36: *
37: * ```
38: * $rules->add($rules->isUnique(['email'], 'The email should be unique'));
39: * ```
40: *
41: * @param string[] $fields The list of fields to check for uniqueness.
42: * @param string|array|null $message The error message to show in case the rule does not pass. Can
43: * also be an array of options. When an array, the 'message' key can be used to provide a message.
44: * @return callable
45: */
46: public function isUnique(array $fields, $message = null)
47: {
48: $options = [];
49: if (is_array($message)) {
50: $options = $message + ['message' => null];
51: $message = $options['message'];
52: unset($options['message']);
53: }
54: if (!$message) {
55: if ($this->_useI18n) {
56: $message = __d('cake', 'This value is already in use');
57: } else {
58: $message = 'This value is already in use';
59: }
60: }
61:
62: $errorField = current($fields);
63:
64: return $this->_addError(new IsUnique($fields, $options), '_isUnique', compact('errorField', 'message'));
65: }
66:
67: /**
68: * Returns a callable that can be used as a rule for checking that the values
69: * extracted from the entity to check exist as the primary key in another table.
70: *
71: * This is useful for enforcing foreign key integrity checks.
72: *
73: * ### Example:
74: *
75: * ```
76: * $rules->add($rules->existsIn('author_id', 'Authors', 'Invalid Author'));
77: *
78: * $rules->add($rules->existsIn('site_id', new SitesTable(), 'Invalid Site'));
79: * ```
80: *
81: * Available $options are error 'message' and 'allowNullableNulls' flag.
82: * 'message' sets a custom error message.
83: * Set 'allowNullableNulls' to true to accept composite foreign keys where one or more nullable columns are null.
84: *
85: * @param string|string[] $field The field or list of fields to check for existence by
86: * primary key lookup in the other table.
87: * @param object|string $table The table name where the fields existence will be checked.
88: * @param string|array|null $message The error message to show in case the rule does not pass. Can
89: * also be an array of options. When an array, the 'message' key can be used to provide a message.
90: * @return callable
91: */
92: public function existsIn($field, $table, $message = null)
93: {
94: $options = [];
95: if (is_array($message)) {
96: $options = $message + ['message' => null];
97: $message = $options['message'];
98: unset($options['message']);
99: }
100:
101: if (!$message) {
102: if ($this->_useI18n) {
103: $message = __d('cake', 'This value does not exist');
104: } else {
105: $message = 'This value does not exist';
106: }
107: }
108:
109: $errorField = is_string($field) ? $field : current($field);
110:
111: return $this->_addError(new ExistsIn($field, $table, $options), '_existsIn', compact('errorField', 'message'));
112: }
113:
114: /**
115: * Validates the count of associated records.
116: *
117: * @param string $field The field to check the count on.
118: * @param int $count The expected count.
119: * @param string $operator The operator for the count comparison.
120: * @param string|null $message The error message to show in case the rule does not pass.
121: * @return callable
122: */
123: public function validCount($field, $count = 0, $operator = '>', $message = null)
124: {
125: if (!$message) {
126: if ($this->_useI18n) {
127: $message = __d('cake', 'The count does not match {0}{1}', [$operator, $count]);
128: } else {
129: $message = sprintf('The count does not match %s%d', $operator, $count);
130: }
131: }
132:
133: $errorField = $field;
134:
135: return $this->_addError(
136: new ValidCount($field),
137: '_validCount',
138: compact('count', 'operator', 'errorField', 'message')
139: );
140: }
141: }
142: