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: /**
33: * Returns a callable that can be used as a rule for checking the uniqueness of a value
34: * in the table.
35: *
36: * ### Example:
37: *
38: * ```
39: * $rules->add($rules->isUnique(['email'], 'The email should be unique'));
40: * ```
41: *
42: * @param array $fields The list of fields to check for uniqueness.
43: * @param string|array|null $message The error message to show in case the rule does not pass. Can
44: * also be an array of options. When an array, the 'message' key can be used to provide a message.
45: * @return callable
46: */
47: public function isUnique(array $fields, $message = null)
48: {
49: $options = [];
50: if (is_array($message)) {
51: $options = $message + ['message' => null];
52: $message = $options['message'];
53: unset($options['message']);
54: }
55: if (!$message) {
56: if ($this->_useI18n) {
57: $message = __d('cake', 'This value is already in use');
58: } else {
59: $message = 'This value is already in use';
60: }
61: }
62:
63: $errorField = current($fields);
64:
65: return $this->_addError(new IsUnique($fields, $options), '_isUnique', compact('errorField', 'message'));
66: }
67:
68: /**
69: * Returns a callable that can be used as a rule for checking that the values
70: * extracted from the entity to check exist as the primary key in another table.
71: *
72: * This is useful for enforcing foreign key integrity checks.
73: *
74: * ### Example:
75: *
76: * ```
77: * $rules->add($rules->existsIn('author_id', 'Authors', 'Invalid Author'));
78: *
79: * $rules->add($rules->existsIn('site_id', new SitesTable(), 'Invalid Site'));
80: * ```
81: *
82: * Available $options are error 'message' and 'allowNullableNulls' flag.
83: * 'message' sets a custom error message.
84: * Set 'allowNullableNulls' to true to accept composite foreign keys where one or more nullable columns are null.
85: *
86: * @param string|array $field The field or list of fields to check for existence by
87: * primary key lookup in the other table.
88: * @param object|string $table The table name where the fields existence will be checked.
89: * @param string|array|null $message The error message to show in case the rule does not pass. Can
90: * also be an array of options. When an array, the 'message' key can be used to provide a message.
91: * @return callable
92: */
93: public function existsIn($field, $table, $message = null)
94: {
95: $options = [];
96: if (is_array($message)) {
97: $options = $message + ['message' => null];
98: $message = $options['message'];
99: unset($options['message']);
100: }
101:
102: if (!$message) {
103: if ($this->_useI18n) {
104: $message = __d('cake', 'This value does not exist');
105: } else {
106: $message = 'This value does not exist';
107: }
108: }
109:
110: $errorField = is_string($field) ? $field : current($field);
111:
112: return $this->_addError(new ExistsIn($field, $table, $options), '_existsIn', compact('errorField', 'message'));
113: }
114:
115: /**
116: * Validates the count of associated records.
117: *
118: * @param string $field The field to check the count on.
119: * @param int $count The expected count.
120: * @param string $operator The operator for the count comparison.
121: * @param string|null $message The error message to show in case the rule does not pass.
122: * @return callable
123: */
124: public function validCount($field, $count = 0, $operator = '>', $message = null)
125: {
126: if (!$message) {
127: if ($this->_useI18n) {
128: $message = __d('cake', 'The count does not match {0}{1}', [$operator, $count]);
129: } else {
130: $message = sprintf('The count does not match %s%d', $operator, $count);
131: }
132: }
133:
134: $errorField = $field;
135:
136: return $this->_addError(
137: new ValidCount($field),
138: '_validCount',
139: compact('count', 'operator', 'errorField', 'message')
140: );
141: }
142: }
143: