1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Telefonica\Traits; |
4
|
|
|
|
5
|
|
|
use InvalidArgumentException; |
6
|
|
|
use Illuminate\Database\Eloquent\Model; |
7
|
|
|
use Illuminate\Database\Eloquent\Builder; |
8
|
|
|
use Illuminate\Database\Eloquent\Collection; |
9
|
|
|
use Illuminate\Database\Eloquent\Relations\MorphToMany; |
10
|
|
|
use Casa\Models\Calendar\Task; |
11
|
|
|
|
12
|
|
|
trait HasTask |
13
|
|
|
{ |
14
|
|
|
protected $queuedTask = []; |
15
|
|
|
|
16
|
|
|
public static function getTaskClassName(): string |
17
|
|
|
{ |
18
|
|
|
return Task::class; |
19
|
|
|
} |
20
|
|
|
|
21
|
|
View Code Duplication |
public static function bootHasTask() |
|
|
|
|
22
|
|
|
{ |
23
|
|
|
static::created( |
24
|
|
|
function (Model $taskableModel) { |
25
|
|
|
if (count($taskableModel->queuedTask) > 0) { |
26
|
|
|
$taskableModel->attachTask($taskableModel->queuedTask); |
27
|
|
|
|
28
|
|
|
$taskableModel->queuedTask = []; |
29
|
|
|
} |
30
|
|
|
} |
31
|
|
|
); |
32
|
|
|
|
33
|
|
|
static::deleted( |
34
|
|
|
function (Model $deletedModel) { |
35
|
|
|
$tasks = $deletedModel->tasks()->get(); |
36
|
|
|
|
37
|
|
|
$deletedModel->detachTask($tasks); |
38
|
|
|
} |
39
|
|
|
); |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
public function tasks(): MorphToMany |
43
|
|
|
{ |
44
|
|
|
return $this |
|
|
|
|
45
|
|
|
->morphToMany(self::getTaskClassName(), 'taskable') |
46
|
|
|
->ordered(); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @param string $locale |
51
|
|
|
*/ |
52
|
|
View Code Duplication |
public function tasksTranslated($locale = null): MorphToMany |
|
|
|
|
53
|
|
|
{ |
54
|
|
|
$locale = ! is_null($locale) ? $locale : app()->getLocale(); |
55
|
|
|
|
56
|
|
|
return $this |
|
|
|
|
57
|
|
|
->morphToMany(self::getTaskClassName(), 'taskable') |
58
|
|
|
->select('*') |
59
|
|
|
->selectRaw("JSON_UNQUOTE(JSON_EXTRACT(name, '$.\"{$locale}\"')) as name_translated") |
60
|
|
|
->selectRaw("JSON_UNQUOTE(JSON_EXTRACT(slug, '$.\"{$locale}\"')) as slug_translated") |
61
|
|
|
->ordered(); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* @param string|array|\ArrayAccess|\\App\Models\Task $tasks |
66
|
|
|
*/ |
67
|
|
|
public function setTaskAttribute($tasks) |
68
|
|
|
{ |
69
|
|
|
if (! $this->exists) { |
|
|
|
|
70
|
|
|
$this->queuedTask = $tasks; |
71
|
|
|
|
72
|
|
|
return; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
$this->attachTask($tasks); |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @param \Illuminate\Database\Eloquent\Builder $query |
80
|
|
|
* @param array|\ArrayAccess|\\App\Models\Task $tasks |
81
|
|
|
* |
82
|
|
|
* @return \Illuminate\Database\Eloquent\Builder |
83
|
|
|
*/ |
84
|
|
View Code Duplication |
public function scopeWithAllTask(Builder $query, $tasks, string $type = null): Builder |
|
|
|
|
85
|
|
|
{ |
86
|
|
|
$tasks = static::convertToTask($tasks, $type); |
87
|
|
|
|
88
|
|
|
collect($tasks)->each( |
89
|
|
|
function ($task) use ($query) { |
90
|
|
|
$query->whereHas( |
91
|
|
|
'tasks', function (Builder $query) use ($task) { |
92
|
|
|
$query->where('tasks.id', $task ? $task->id : 0); |
93
|
|
|
} |
94
|
|
|
); |
95
|
|
|
} |
96
|
|
|
); |
97
|
|
|
|
98
|
|
|
return $query; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* @param \Illuminate\Database\Eloquent\Builder $query |
103
|
|
|
* @param array|\ArrayAccess|\\App\Models\Task $tasks |
104
|
|
|
* |
105
|
|
|
* @return \Illuminate\Database\Eloquent\Builder |
106
|
|
|
*/ |
107
|
|
View Code Duplication |
public function scopeWithAnyTask(Builder $query, $tasks, string $type = null): Builder |
|
|
|
|
108
|
|
|
{ |
109
|
|
|
$tasks = static::convertToTask($tasks, $type); |
110
|
|
|
|
111
|
|
|
return $query->whereHas( |
112
|
|
|
'tasks', function (Builder $query) use ($tasks) { |
113
|
|
|
$taskIds = collect($tasks)->pluck('id'); |
114
|
|
|
|
115
|
|
|
$query->whereIn('tasks.id', $taskIds); |
116
|
|
|
} |
117
|
|
|
); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
View Code Duplication |
public function scopeWithAllTaskOfAnyType(Builder $query, $tasks): Builder |
|
|
|
|
121
|
|
|
{ |
122
|
|
|
$tasks = static::convertToTaskOfAnyType($tasks); |
123
|
|
|
|
124
|
|
|
collect($tasks)->each( |
125
|
|
|
function ($task) use ($query) { |
126
|
|
|
$query->whereHas( |
127
|
|
|
'tasks', function (Builder $query) use ($task) { |
128
|
|
|
$query->where('tasks.id', $task ? $task->id : 0); |
129
|
|
|
} |
130
|
|
|
); |
131
|
|
|
} |
132
|
|
|
); |
133
|
|
|
|
134
|
|
|
return $query; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
View Code Duplication |
public function scopeWithAnyTaskOfAnyType(Builder $query, $tasks): Builder |
|
|
|
|
138
|
|
|
{ |
139
|
|
|
$tasks = static::convertToTaskOfAnyType($tasks); |
140
|
|
|
|
141
|
|
|
return $query->whereHas( |
142
|
|
|
'tasks', function (Builder $query) use ($tasks) { |
143
|
|
|
$taskIds = collect($tasks)->pluck('id'); |
144
|
|
|
|
145
|
|
|
$query->whereIn('tasks.id', $taskIds); |
146
|
|
|
} |
147
|
|
|
); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
public function tasksWithType(string $type = null): Collection |
151
|
|
|
{ |
152
|
|
|
return $this->tasks->filter( |
|
|
|
|
153
|
|
|
function (Task $task) use ($type) { |
154
|
|
|
return $task->type === $type; |
155
|
|
|
} |
156
|
|
|
); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* @param array|\ArrayAccess|\\App\Models\Task $tasks |
161
|
|
|
* |
162
|
|
|
* @return $this |
163
|
|
|
*/ |
164
|
|
View Code Duplication |
public function attachTask($tasks) |
|
|
|
|
165
|
|
|
{ |
166
|
|
|
$className = static::getTaskClassName(); |
167
|
|
|
|
168
|
|
|
$tasks = collect($className::findOrCreate($tasks)); |
169
|
|
|
|
170
|
|
|
$this->tasks()->syncWithoutDetaching($tasks->pluck('id')->toArray()); |
171
|
|
|
|
172
|
|
|
return $this; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* @param array|\ArrayAccess $tasks |
177
|
|
|
* |
178
|
|
|
* @return $this |
179
|
|
|
*/ |
180
|
|
|
public function detachTask($tasks) |
181
|
|
|
{ |
182
|
|
|
$tasks = static::convertToTask($tasks); |
183
|
|
|
|
184
|
|
|
collect($tasks) |
185
|
|
|
->filter() |
186
|
|
|
->each( |
187
|
|
|
function (Task $task) { |
188
|
|
|
$this->tasks()->detach($task); |
189
|
|
|
} |
190
|
|
|
); |
191
|
|
|
|
192
|
|
|
return $this; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* @param array|\ArrayAccess $tasks |
197
|
|
|
* |
198
|
|
|
* @return $this |
199
|
|
|
*/ |
200
|
|
View Code Duplication |
public function syncTask($tasks) |
|
|
|
|
201
|
|
|
{ |
202
|
|
|
$className = static::getTaskClassName(); |
203
|
|
|
|
204
|
|
|
$tasks = collect($className::findOrCreate($tasks)); |
205
|
|
|
|
206
|
|
|
$this->tasks()->sync($tasks->pluck('id')->toArray()); |
207
|
|
|
|
208
|
|
|
return $this; |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* @param array|\ArrayAccess $tasks |
213
|
|
|
* @param string|null $type |
214
|
|
|
* |
215
|
|
|
* @return $this |
216
|
|
|
*/ |
217
|
|
View Code Duplication |
public function syncTaskWithType($tasks, string $type = null) |
|
|
|
|
218
|
|
|
{ |
219
|
|
|
$className = static::getTaskClassName(); |
220
|
|
|
|
221
|
|
|
$tasks = collect($className::findOrCreate($tasks, $type)); |
222
|
|
|
|
223
|
|
|
$this->syncTaskIds($tasks->pluck('id')->toArray(), $type); |
224
|
|
|
|
225
|
|
|
return $this; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
View Code Duplication |
protected static function convertToTask($values, $type = null, $locale = null) |
|
|
|
|
229
|
|
|
{ |
230
|
|
|
return collect($values)->map( |
231
|
|
|
function ($value) use ($type, $locale) { |
232
|
|
|
if ($value instanceof Task) { |
|
|
|
|
233
|
|
|
if (isset($type) && $value->type != $type) { |
234
|
|
|
throw new InvalidArgumentException("Type was set to {$type} but task is of type {$value->type}"); |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
return $value; |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
$className = static::getTaskClassName(); |
241
|
|
|
|
242
|
|
|
return $className::findFromString($value, $type, $locale); |
243
|
|
|
} |
244
|
|
|
); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
View Code Duplication |
protected static function convertToTaskOfAnyType($values, $locale = null) |
|
|
|
|
248
|
|
|
{ |
249
|
|
|
return collect($values)->map( |
250
|
|
|
function ($value) use ($locale) { |
251
|
|
|
if ($value instanceof Task) { |
|
|
|
|
252
|
|
|
return $value; |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
$className = static::getTaskClassName(); |
256
|
|
|
|
257
|
|
|
return $className::findFromStringOfAnyType($value, $locale); |
258
|
|
|
} |
259
|
|
|
); |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* Use in place of eloquent's sync() method so that the task type may be optionally specified. |
264
|
|
|
* |
265
|
|
|
* @param $ids |
266
|
|
|
* @param string|null $type |
267
|
|
|
* @param bool $detaching |
268
|
|
|
*/ |
269
|
|
View Code Duplication |
protected function syncTaskIds($ids, string $type = null, $detaching = true) |
|
|
|
|
270
|
|
|
{ |
271
|
|
|
$isUpdated = false; |
272
|
|
|
|
273
|
|
|
// Get a list of task_ids for all current tasks |
274
|
|
|
$current = $this->tasks() |
275
|
|
|
->newPivotStatement() |
276
|
|
|
->where('taskable_id', $this->getKey()) |
|
|
|
|
277
|
|
|
->where('taskable_type', $this->getMorphClass()) |
|
|
|
|
278
|
|
|
->when( |
279
|
|
|
$type !== null, function ($query) use ($type) { |
280
|
|
|
$taskModel = $this->tasks()->getRelated(); |
281
|
|
|
|
282
|
|
|
return $query->join( |
283
|
|
|
$taskModel->getTable(), |
284
|
|
|
'taskables.task_id', |
285
|
|
|
'=', |
286
|
|
|
$taskModel->getTable().'.'.$taskModel->getKeyName() |
287
|
|
|
) |
288
|
|
|
->where('tasks.type', $type); |
289
|
|
|
} |
290
|
|
|
) |
291
|
|
|
->pluck('task_id') |
292
|
|
|
->all(); |
293
|
|
|
|
294
|
|
|
// Compare to the list of ids given to find the tasks to remove |
295
|
|
|
$detach = array_diff($current, $ids); |
296
|
|
|
if ($detaching && count($detach) > 0) { |
297
|
|
|
$this->tasks()->detach($detach); |
298
|
|
|
$isUpdated = true; |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
// Attach any new ids |
302
|
|
|
$attach = array_diff($ids, $current); |
303
|
|
|
if (count($attach) > 0) { |
304
|
|
|
collect($attach)->each( |
305
|
|
|
function ($id) { |
306
|
|
|
$this->tasks()->attach($id, []); |
307
|
|
|
} |
308
|
|
|
); |
309
|
|
|
$isUpdated = true; |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
// Once we have finished attaching or detaching the records, we will see if we |
313
|
|
|
// have done any attaching or detaching, and if we have we will touch these |
314
|
|
|
// relationships if they are configured to touch on any database updates. |
315
|
|
|
if ($isUpdated) { |
316
|
|
|
$this->tasks()->touchIfTouching(); |
317
|
|
|
} |
318
|
|
|
} |
319
|
|
|
} |
320
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.