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.3.0
13: * @license https://opensource.org/licenses/mit-license.php MIT License
14: */
15: namespace Cake\ORM;
16:
17: use ArrayObject;
18: use RuntimeException;
19:
20: /**
21: * OOP style Save Option Builder.
22: *
23: * This allows you to build options to save entities in a OOP style and helps
24: * you to avoid mistakes by validating the options as you build them.
25: *
26: * @see \Cake\Datasource\RulesChecker
27: */
28: class SaveOptionsBuilder extends ArrayObject
29: {
30: use AssociationsNormalizerTrait;
31:
32: /**
33: * Options
34: *
35: * @var array
36: */
37: protected $_options = [];
38:
39: /**
40: * Table object.
41: *
42: * @var \Cake\ORM\Table
43: */
44: protected $_table;
45:
46: /**
47: * Constructor.
48: *
49: * @param \Cake\ORM\Table $table A table instance.
50: * @param array $options Options to parse when instantiating.
51: */
52: public function __construct(Table $table, array $options = [])
53: {
54: $this->_table = $table;
55: $this->parseArrayOptions($options);
56:
57: parent::__construct();
58: }
59:
60: /**
61: * Takes an options array and populates the option object with the data.
62: *
63: * This can be used to turn an options array into the object.
64: *
65: * @throws \InvalidArgumentException If a given option key does not exist.
66: * @param array $array Options array.
67: * @return \Cake\ORM\SaveOptionsBuilder
68: */
69: public function parseArrayOptions($array)
70: {
71: foreach ($array as $key => $value) {
72: $this->{$key}($value);
73: }
74:
75: return $this;
76: }
77:
78: /**
79: * Set associated options.
80: *
81: * @param string|array $associated String or array of associations.
82: * @return \Cake\ORM\SaveOptionsBuilder
83: */
84: public function associated($associated)
85: {
86: $associated = $this->_normalizeAssociations($associated);
87: $this->_associated($this->_table, $associated);
88: $this->_options['associated'] = $associated;
89:
90: return $this;
91: }
92:
93: /**
94: * Checks that the associations exists recursively.
95: *
96: * @param \Cake\ORM\Table $table Table object.
97: * @param array $associations An associations array.
98: * @return void
99: */
100: protected function _associated(Table $table, array $associations)
101: {
102: foreach ($associations as $key => $associated) {
103: if (is_int($key)) {
104: $this->_checkAssociation($table, $associated);
105: continue;
106: }
107: $this->_checkAssociation($table, $key);
108: if (isset($associated['associated'])) {
109: $this->_associated($table->getAssociation($key)->getTarget(), $associated['associated']);
110: continue;
111: }
112: }
113: }
114:
115: /**
116: * Checks if an association exists.
117: *
118: * @throws \RuntimeException If no such association exists for the given table.
119: * @param \Cake\ORM\Table $table Table object.
120: * @param string $association Association name.
121: * @return void
122: */
123: protected function _checkAssociation(Table $table, $association)
124: {
125: if (!$table->associations()->has($association)) {
126: throw new RuntimeException(sprintf('Table `%s` is not associated with `%s`', get_class($table), $association));
127: }
128: }
129:
130: /**
131: * Set the guard option.
132: *
133: * @param bool $guard Guard the properties or not.
134: * @return \Cake\ORM\SaveOptionsBuilder
135: */
136: public function guard($guard)
137: {
138: $this->_options['guard'] = (bool)$guard;
139:
140: return $this;
141: }
142:
143: /**
144: * Set the validation rule set to use.
145: *
146: * @param string $validate Name of the validation rule set to use.
147: * @return \Cake\ORM\SaveOptionsBuilder
148: */
149: public function validate($validate)
150: {
151: $this->_table->getValidator($validate);
152: $this->_options['validate'] = $validate;
153:
154: return $this;
155: }
156:
157: /**
158: * Set check existing option.
159: *
160: * @param bool $checkExisting Guard the properties or not.
161: * @return \Cake\ORM\SaveOptionsBuilder
162: */
163: public function checkExisting($checkExisting)
164: {
165: $this->_options['checkExisting'] = (bool)$checkExisting;
166:
167: return $this;
168: }
169:
170: /**
171: * Option to check the rules.
172: *
173: * @param bool $checkRules Check the rules or not.
174: * @return \Cake\ORM\SaveOptionsBuilder
175: */
176: public function checkRules($checkRules)
177: {
178: $this->_options['checkRules'] = (bool)$checkRules;
179:
180: return $this;
181: }
182:
183: /**
184: * Sets the atomic option.
185: *
186: * @param bool $atomic Atomic or not.
187: * @return \Cake\ORM\SaveOptionsBuilder
188: */
189: public function atomic($atomic)
190: {
191: $this->_options['atomic'] = (bool)$atomic;
192:
193: return $this;
194: }
195:
196: /**
197: * @return array
198: */
199: public function toArray()
200: {
201: return $this->_options;
202: }
203:
204: /**
205: * Setting custom options.
206: *
207: * @param string $option Option key.
208: * @param mixed $value Option value.
209: * @return \Cake\ORM\SaveOptionsBuilder
210: */
211: public function set($option, $value)
212: {
213: if (method_exists($this, $option)) {
214: return $this->{$option}($value);
215: }
216: $this->_options[$option] = $value;
217:
218: return $this;
219: }
220: }
221: