1 | <?php |
||||||
2 | namespace SoftDelete\Model\Table; |
||||||
3 | |||||||
4 | use Cake\ORM\RulesChecker; |
||||||
5 | use Cake\Datasource\EntityInterface; |
||||||
6 | use Cake\Utility\Hash; |
||||||
7 | use SoftDelete\Error\MissingColumnException; |
||||||
8 | use SoftDelete\ORM\Query; |
||||||
9 | |||||||
10 | trait SoftDeleteTrait |
||||||
11 | { |
||||||
12 | |||||||
13 | /** |
||||||
14 | * @var boolean |
||||||
15 | */ |
||||||
16 | protected $_findWithDeleted; |
||||||
17 | |||||||
18 | /** |
||||||
19 | * Get the configured deletion field |
||||||
20 | * |
||||||
21 | * @return string |
||||||
22 | * @throws \SoftDelete\Error\MissingFieldException |
||||||
23 | */ |
||||||
24 | public function ensureSoftDeleteFieldExists() |
||||||
25 | { |
||||||
26 | $callable = [$this, 'getSoftDeleteField']; |
||||||
27 | if (!is_callable($callable)) { |
||||||
28 | throw new \BadMethodCallException(); |
||||||
29 | } |
||||||
30 | |||||||
31 | $field = call_user_func($callable); |
||||||
32 | |||||||
33 | if ($this->getSchema()->getColumn($field) === null) { |
||||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||||
34 | throw new MissingColumnException( |
||||||
35 | __('Configured field `{0}` is missing from the table `{1}`.', |
||||||
36 | $field, |
||||||
37 | $this->getAlias() |
||||||
0 ignored issues
–
show
It seems like
getAlias() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
38 | ) |
||||||
39 | ); |
||||||
40 | } |
||||||
41 | |||||||
42 | return $field; |
||||||
43 | } |
||||||
44 | |||||||
45 | public function query() |
||||||
46 | { |
||||||
47 | return new Query($this->getConnection(), $this); |
||||||
0 ignored issues
–
show
It seems like
getConnection() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() $this of type SoftDelete\Model\Table\SoftDeleteTrait is incompatible with the type Cake\ORM\Table expected by parameter $table of SoftDelete\ORM\Query::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
48 | } |
||||||
49 | |||||||
50 | /** |
||||||
51 | * Perform the delete operation. |
||||||
52 | * |
||||||
53 | * Will soft delete the entity provided. Will remove rows from any |
||||||
54 | * dependent associations, and clear out join tables for BelongsToMany associations. |
||||||
55 | * |
||||||
56 | * @param \Cake\DataSource\EntityInterface $entity The entity to soft delete. |
||||||
57 | * @param \ArrayObject $options The options for the delete. |
||||||
58 | * @throws \InvalidArgumentException if there are no primary key values of the |
||||||
59 | * passed entity |
||||||
60 | * @return bool success |
||||||
61 | */ |
||||||
62 | protected function _processDelete($entity, $options) |
||||||
63 | { |
||||||
64 | if ($entity->isNew()) { |
||||||
65 | return false; |
||||||
66 | } |
||||||
67 | |||||||
68 | $primaryKey = (array)$this->getPrimaryKey(); |
||||||
0 ignored issues
–
show
It seems like
getPrimaryKey() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
69 | if (!$entity->has($primaryKey)) { |
||||||
70 | $msg = 'Deleting requires all primary key values.'; |
||||||
71 | throw new \InvalidArgumentException($msg); |
||||||
72 | } |
||||||
73 | |||||||
74 | if ($options['checkRules'] && !$this->checkRules($entity, RulesChecker::DELETE, $options)) { |
||||||
0 ignored issues
–
show
It seems like
checkRules() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
75 | return false; |
||||||
76 | } |
||||||
77 | |||||||
78 | $event = $this->dispatchEvent('Model.beforeDelete', [ |
||||||
0 ignored issues
–
show
It seems like
dispatchEvent() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
79 | 'entity' => $entity, |
||||||
80 | 'options' => $options |
||||||
81 | ]); |
||||||
82 | |||||||
83 | if ($event->isStopped()) { |
||||||
84 | return $event->result; |
||||||
85 | } |
||||||
86 | |||||||
87 | $this->_associations->cascadeDelete( |
||||||
88 | $entity, |
||||||
89 | ['_primary' => false] + $options->getArrayCopy() |
||||||
90 | ); |
||||||
91 | |||||||
92 | $query = $this->query(); |
||||||
93 | $conditions = (array)$entity->extract($primaryKey); |
||||||
94 | $statement = $query->update() |
||||||
95 | ->set([$this->ensureSoftDeleteFieldExists() => $this->getSoftDeleteValue()]) |
||||||
0 ignored issues
–
show
It seems like
getSoftDeleteValue() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
96 | ->where($conditions) |
||||||
97 | ->execute(); |
||||||
98 | |||||||
99 | $success = $statement->rowCount() > 0; |
||||||
100 | if (!$success) { |
||||||
101 | return $success; |
||||||
102 | } |
||||||
103 | |||||||
104 | $this->dispatchEvent('Model.afterDelete', [ |
||||||
105 | 'entity' => $entity, |
||||||
106 | 'options' => $options |
||||||
107 | ]); |
||||||
108 | |||||||
109 | return $success; |
||||||
110 | } |
||||||
111 | |||||||
112 | /** |
||||||
113 | * Soft deletes all records matching `$conditions`. |
||||||
114 | * @return int number of affected rows. |
||||||
115 | */ |
||||||
116 | public function deleteAll($conditions) |
||||||
117 | { |
||||||
118 | $query = $this->query() |
||||||
119 | ->update() |
||||||
120 | ->set([$this->ensureSoftDeleteFieldExists() => $this->getSoftDeleteValue()]) |
||||||
121 | ->where($conditions); |
||||||
122 | $statement = $query->execute(); |
||||||
123 | $statement->closeCursor(); |
||||||
124 | return $statement->rowCount(); |
||||||
125 | } |
||||||
126 | |||||||
127 | /** |
||||||
128 | * Hard deletes the given $entity. |
||||||
129 | * @return bool true in case of success, false otherwise. |
||||||
130 | */ |
||||||
131 | public function hardDelete(EntityInterface $entity) |
||||||
132 | { |
||||||
133 | if (!$this->delete($entity)) { |
||||||
0 ignored issues
–
show
The method
delete() does not exist on SoftDelete\Model\Table\SoftDeleteTrait . Did you maybe mean deleteAll() ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||
134 | return false; |
||||||
135 | } |
||||||
136 | $primaryKey = (array)$this->getPrimaryKey(); |
||||||
137 | $query = $this->query(); |
||||||
138 | $conditions = (array)$entity->extract($primaryKey); |
||||||
139 | $statement = $query->delete() |
||||||
140 | ->where($conditions) |
||||||
141 | ->execute(); |
||||||
142 | |||||||
143 | $success = $statement->rowCount() > 0; |
||||||
144 | if (!$success) { |
||||||
145 | return $success; |
||||||
146 | } |
||||||
147 | |||||||
148 | return $success; |
||||||
149 | } |
||||||
150 | |||||||
151 | /** |
||||||
152 | * Hard deletes all records that were soft deleted before a given date. |
||||||
153 | * @param $conditions |
||||||
154 | * @return int number of affected rows. |
||||||
155 | */ |
||||||
156 | public function hardDeleteAll($conditions) |
||||||
157 | { |
||||||
158 | $conditions = Hash::merge($conditions, ['NOT' => [$this->getActiveExpression()]]); |
||||||
159 | |||||||
160 | $query = $this->query() |
||||||
161 | ->delete() |
||||||
162 | ->where($conditions); |
||||||
163 | $statement = $query->execute(); |
||||||
164 | $statement->closeCursor(); |
||||||
165 | return $statement->rowCount(); |
||||||
166 | } |
||||||
167 | |||||||
168 | /** |
||||||
169 | * Restore a soft deleted entity into an active state. |
||||||
170 | * @param EntityInterface $entity Entity to be restored. |
||||||
171 | * @return bool true in case of success, false otherwise. |
||||||
172 | */ |
||||||
173 | public function restore(EntityInterface $entity) |
||||||
174 | { |
||||||
175 | $softDeleteField = $this->ensureSoftDeleteFieldExists(); |
||||||
176 | $entity->$softDeleteField = $this->getRestoreValue(); |
||||||
0 ignored issues
–
show
It seems like
getRestoreValue() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
177 | return $this->save($entity); |
||||||
0 ignored issues
–
show
It seems like
save() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
178 | } |
||||||
179 | |||||||
180 | /** |
||||||
181 | * @param bool $enable |
||||||
182 | */ |
||||||
183 | public function enableFindWithDeleted($enable = true) |
||||||
184 | { |
||||||
185 | $this->_findWithDeleted = (bool)$enable; |
||||||
186 | } |
||||||
187 | |||||||
188 | /** |
||||||
189 | * @return bool |
||||||
190 | */ |
||||||
191 | public function findWithDeleted() |
||||||
192 | { |
||||||
193 | return $this->_findWithDeleted; |
||||||
194 | } |
||||||
195 | |||||||
196 | /** |
||||||
197 | * @return array|string |
||||||
198 | */ |
||||||
199 | public function getActiveExpression() |
||||||
200 | { |
||||||
201 | $aliasedField = $this->aliasField($this->ensureSoftDeleteFieldExists()); |
||||||
0 ignored issues
–
show
It seems like
aliasField() must be provided by classes using this trait. How about adding it as abstract method to this trait?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
202 | $activeValue = $this->getRestoreValue(); |
||||||
203 | |||||||
204 | if ($activeValue === null) { |
||||||
205 | return $aliasedField . ' IS NULL'; |
||||||
206 | } |
||||||
207 | |||||||
208 | return [$aliasedField => $activeValue]; |
||||||
209 | } |
||||||
210 | } |
||||||
211 |