~xibo-maintainers/xibo/tempel

« back to all changes in this revision

Viewing changes to lib/Entity/Campaign.php

  • Committer: Dan Garner
  • Date: 2015-08-11 09:29:02 UTC
  • mto: This revision was merged to the branch mainline in revision 453.
  • Revision ID: git-v1:a86fb4369b7395c13367577d23b14c0ab4528c1a
Transitions fixes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
namespace Xibo\Entity;
24
24
 
25
25
use Respect\Validation\Validator as v;
26
 
use Xibo\Exception\InvalidArgumentException;
27
 
use Xibo\Exception\NotFoundException;
28
 
use Xibo\Exception\XiboException;
29
26
use Xibo\Factory\DisplayFactory;
30
27
use Xibo\Factory\LayoutFactory;
31
28
use Xibo\Factory\PermissionFactory;
32
29
use Xibo\Factory\ScheduleFactory;
33
 
use Xibo\Factory\TagFactory;
34
 
use Xibo\Service\LogServiceInterface;
35
 
use Xibo\Storage\StorageServiceInterface;
 
30
use Xibo\Helper\Log;
 
31
use Xibo\Storage\PDOConnect;
36
32
 
37
33
/**
38
34
 * Class Campaign
74
70
     */
75
71
    public $numberLayouts;
76
72
 
77
 
    /**
78
 
     * @SWG\Property(description="The total duration of the campaign (sum of layout's durations)")
79
 
     * @var int
80
 
     */
81
 
    public $totalDuration;
82
 
 
83
 
    public $tags = [];
84
 
 
85
 
    /**
86
 
     * @var Layout[]
87
 
     */
88
73
    private $layouts = [];
89
 
 
90
 
    /**
91
 
     * @var Permission[]
92
 
     */
93
74
    private $permissions = [];
94
 
 
95
 
    /**
96
 
     * @var Schedule[]
97
 
     */
98
75
    private $events = [];
99
 
    
100
 
    // Private
101
 
    private $unassignTags = [];
102
 
 
103
 
    /** @var bool Have the Layout assignments changed? */
104
 
    private $layoutAssignmentsChanged = false;
105
 
 
106
 
    /**
107
 
     * @var PermissionFactory
108
 
     */
109
 
    private $permissionFactory;
110
 
 
111
 
    /**
112
 
     * @var LayoutFactory
113
 
     */
114
 
    private $layoutFactory;
115
 
    
116
 
    /**
117
 
     * @var TagFactory
118
 
     */
119
 
    private $tagFactory;
120
 
 
121
 
    /**
122
 
     * @var ScheduleFactory
123
 
     */
124
 
    private $scheduleFactory;
125
 
 
126
 
    /**
127
 
     * @var DisplayFactory
128
 
     */
129
 
    private $displayFactory;
130
 
 
131
 
    /**
132
 
     * Entity constructor.
133
 
     * @param StorageServiceInterface $store
134
 
     * @param LogServiceInterface $log
135
 
     * @param PermissionFactory $permissionFactory
136
 
     * @param ScheduleFactory $scheduleFactory
137
 
     * @param DisplayFactory $displayFactory
138
 
     * @param TagFactory $tagFactory
139
 
     */
140
 
    public function __construct($store, $log, $permissionFactory, $scheduleFactory, $displayFactory, $tagFactory)
141
 
    {
142
 
        $this->setCommonDependencies($store, $log);
143
 
        $this->permissionFactory = $permissionFactory;
144
 
        $this->scheduleFactory = $scheduleFactory;
145
 
        $this->displayFactory = $displayFactory;
146
 
        $this->tagFactory = $tagFactory;
147
 
    }
148
 
 
149
 
    /**
150
 
     * Set Child Object Depencendies
151
 
     *  must be set before calling Load with all objects
152
 
     * @param LayoutFactory $layoutFactory
153
 
     * @return $this
154
 
     */
155
 
    public function setChildObjectDependencies($layoutFactory)
156
 
    {
157
 
        $this->layoutFactory = $layoutFactory;
158
 
        return $this;
159
 
    }
160
 
 
161
 
    /**
162
 
     * @return string
163
 
     */
 
76
 
164
77
    public function __toString()
165
78
    {
166
79
        return sprintf('CampaignId %d, Campaign %s, LayoutSpecific %d', $this->campaignId, $this->campaign, $this->isLayoutSpecific);
184
97
        return $this->ownerId;
185
98
    }
186
99
 
187
 
    /**
188
 
     * Sets the Owner
189
 
     * @param int $ownerId
190
 
     */
191
 
    public function setOwner($ownerId)
192
 
    {
193
 
        $this->ownerId = $ownerId;
194
 
    }
195
 
 
196
 
    /**
197
 
     * @param array $options
198
 
     * @throws \Xibo\Exception\NotFoundException
199
 
     */
200
 
    public function load($options = [])
201
 
    {
202
 
        $options = array_merge([
203
 
            'loadPermissions' => true,
204
 
            'loadLayouts' => true,
205
 
            'loadTags' => true,
206
 
            'loadEvents' => true
207
 
        ], $options);
208
 
        
 
100
    public function load()
 
101
    {
209
102
        // If we are already loaded, then don't do it again
210
103
        if ($this->campaignId == null || $this->loaded)
211
104
            return;
212
105
 
213
 
        if ($this->layoutFactory == null)
214
 
            throw new \RuntimeException('Cannot load campaign with all objects without first calling setChildObjectDependencies');
215
 
 
216
106
        // Permissions
217
 
        if ($options['loadPermissions'])
218
 
            $this->permissions = $this->permissionFactory->getByObjectId('Campaign', $this->campaignId);
 
107
        $this->permissions = PermissionFactory::getByObjectId('Campaign', $this->campaignId);
219
108
 
220
109
        // Layouts
221
 
        if ($options['loadLayouts'])
222
 
            $this->layouts = $this->layoutFactory->getByCampaignId($this->campaignId, false);
223
 
            
224
 
        // Load all tags
225
 
        if ($options['loadTags'])
226
 
            $this->tags = $this->tagFactory->loadByCampaignId($this->campaignId);
 
110
        $this->layouts = LayoutFactory::getByCampaignId($this->campaignId);
227
111
 
228
112
        // Events
229
 
        if ($options['loadEvents'])
230
 
            $this->events = $this->scheduleFactory->getByCampaignId($this->campaignId);
 
113
        $this->events = ScheduleFactory::getByCampaignId($this->campaignId);
231
114
 
232
115
        $this->loaded = true;
233
116
    }
234
117
 
235
 
    /**
236
 
     * @throws InvalidArgumentException
237
 
     */
238
118
    public function validate()
239
119
    {
240
 
        if (!v::stringType()->notEmpty()->validate($this->campaign))
241
 
            throw new InvalidArgumentException(__('Name cannot be empty'), 'name');
242
 
    }
243
 
    
244
 
    
245
 
    /**
246
 
     * Does the campaign have the provided tag?
247
 
     * @param $searchTag
248
 
     * @return bool
249
 
     * @throws NotFoundException
250
 
     */
251
 
    public function hasTag($searchTag)
252
 
    {
253
 
        $this->load();
254
 
 
255
 
        foreach ($this->tags as $tag) {
256
 
            /* @var Tag $tag */
257
 
            if ($tag->tag == $searchTag)
258
 
                return true;
259
 
        }
260
 
 
261
 
        return false;
262
 
    }
263
 
 
264
 
    /**
265
 
     * Assign Tag
266
 
     * @param Tag $tag
267
 
     * @return $this
268
 
     */
269
 
    public function assignTag($tag)
270
 
    {
271
 
        $this->load();
272
 
 
273
 
        if (!in_array($tag, $this->tags))
274
 
            $this->tags[] = $tag;
275
 
 
276
 
        return $this;
277
 
    }
278
 
 
279
 
    /**
280
 
     * Unassign tag
281
 
     * @param Tag $tag
282
 
     * @return $this
283
 
     */
284
 
    public function unassignTag($tag)
285
 
    {
286
 
        $this->tags = array_udiff($this->tags, [$tag], function($a, $b) {
287
 
            /* @var Tag $a */
288
 
            /* @var Tag $b */
289
 
            return $a->tagId - $b->tagId;
290
 
        });
291
 
 
292
 
        return $this;
293
 
    }
294
 
 
295
 
    /**
296
 
     * @param array[Tag] $tags
297
 
     */
298
 
    public function replaceTags($tags = [])
299
 
    {
300
 
        if (!is_array($this->tags) || count($this->tags) <= 0)
301
 
            $this->tags = $this->tagFactory->loadByCampaignId($this->campaignId);
302
 
 
303
 
        $this->unassignTags = array_udiff($this->tags, $tags, function($a, $b) {
304
 
            /* @var Tag $a */
305
 
            /* @var Tag $b */
306
 
            return $a->tagId - $b->tagId;
307
 
        });
308
 
 
309
 
        $this->getLog()->debug('Tags to be removed: %s', json_encode($this->unassignTags));
310
 
 
311
 
        // Replace the arrays
312
 
        $this->tags = $tags;
313
 
 
314
 
        $this->getLog()->debug('Tags remaining: %s', json_encode($this->tags));
315
 
    }
316
 
 
317
 
    /**
318
 
     * Save this Campaign
319
 
     * @param array $options
320
 
     * @throws InvalidArgumentException
321
 
     */
322
 
    public function save($options = [])
323
 
    {
324
 
        $options = array_merge([
325
 
            'validate' => true,
326
 
            'notify' => true,
327
 
            'collectNow' => true,
328
 
            'saveTags' => true
329
 
        ], $options);
330
 
 
331
 
        $this->getLog()->debug('Saving ' . $this);
332
 
 
333
 
        if ($options['validate'])
 
120
        if (!v::string()->notEmpty()->validate($this->campaign))
 
121
            throw new \InvalidArgumentException(__('Name cannot be empty'));
 
122
    }
 
123
 
 
124
    public function save($validate = true)
 
125
    {
 
126
        Log::debug('Saving %s', $this);
 
127
 
 
128
        if ($validate)
334
129
            $this->validate();
335
130
 
336
131
        if ($this->campaignId == null || $this->campaignId == 0) {
339
134
        }
340
135
        else
341
136
            $this->update();
342
 
        
343
 
            
344
 
        // Save the tags
345
 
        if (is_array($this->tags)) {
346
 
            foreach ($this->tags as $tag) {
347
 
                /* @var Tag $tag */
348
 
 
349
 
                $this->getLog()->debug('Assigning tag ' . $tag->tag);
350
 
 
351
 
                $tag->assignCampaign($this->campaignId);
352
 
                $tag->save();
353
 
            }
354
 
        }
355
 
 
356
 
        // Remove unwanted ones
357
 
        if (is_array($this->unassignTags)) {
358
 
            foreach ($this->unassignTags as $tag) {
359
 
                /* @var Tag $tag */
360
 
                $this->getLog()->debug('Unassigning tag ' . $tag->tag);
361
 
 
362
 
                $tag->unassignCampaign($this->campaignId);
363
 
                $tag->save();
364
 
            }
365
 
        }
366
137
 
367
138
        if ($this->loaded) {
368
139
            // Manage assignments
370
141
        }
371
142
 
372
143
        // Notify anyone interested of the changes
373
 
        $this->notify($options);
 
144
        $this->notify();
374
145
    }
375
146
 
376
 
    /**
377
 
     * Delete Campaign
378
 
     * @throws NotFoundException
379
 
     */
380
147
    public function delete()
381
148
    {
382
149
        $this->load();
390
157
            /* @var Permission $permission */
391
158
            $permission->delete();
392
159
        }
393
 
        
394
 
        // Unassign all Tags
395
 
        foreach ($this->tags as $tag) {
396
 
            /* @var Tag $tag */
397
 
            $tag->unassignCampaign($this->campaignId);
398
 
            $tag->save();
399
 
        }
400
 
 
401
 
        // Notify anyone interested of the changes
402
 
        // we do this before we delete from the DB (otherwise notify won't find anything)
403
 
        $this->notify();
404
160
 
405
161
        // Delete all events
406
162
        foreach ($this->events as $event) {
407
163
            /* @var Schedule $event */
408
 
            $event->setDisplayFactory($this->displayFactory);
409
164
            $event->delete();
410
165
        }
411
166
 
412
167
        // Delete the Actual Campaign
413
 
        $this->getStore()->update('DELETE FROM `campaign` WHERE CampaignID = :campaignId', ['campaignId' => $this->campaignId]);
 
168
        PDOConnect::update('DELETE FROM `campaign` WHERE CampaignID = :campaignId', ['campaignId' => $this->campaignId]);
414
169
    }
415
170
 
416
171
    /**
417
172
     * Assign Layout
418
173
     * @param Layout $layout
419
 
     * @throws NotFoundException
420
174
     */
421
175
    public function assignLayout($layout)
422
176
    {
423
177
        $this->load();
424
178
 
425
 
        $layout->displayOrder = ($layout->displayOrder == null || $layout->displayOrder == 0) ? count($this->layouts) + 1 : $layout->displayOrder;
426
 
 
427
 
        $found = false;
428
 
        foreach ($this->layouts as $existingLayout) {
429
 
            if ($existingLayout->getId() === $layout->getId() && $existingLayout->displayOrder === $layout->displayOrder) {
430
 
                $found = true;
431
 
                break;
432
 
            }
433
 
        }
434
 
 
435
 
        if (!$found) {
436
 
            $this->getLog()->debug('Layout assignment doesnt exist, adding it. ' . $layout . ', display order ' . $layout->displayOrder);
437
 
            $this->layoutAssignmentsChanged = true;
 
179
        if (!in_array($layout, $this->layouts))
438
180
            $this->layouts[] = $layout;
439
 
        }
440
181
    }
441
182
 
442
183
    /**
445
186
     */
446
187
    public function unassignLayout($layout)
447
188
    {
448
 
        $this->load();
449
 
 
450
 
        $countBefore = count($this->layouts);
451
 
        $this->getLog()->debug('Unassigning Layout, count before assign = ' . $countBefore);
452
 
 
453
 
        $found = false;
454
 
        $existingKey = null;
455
 
        foreach ($this->layouts as $key => $existing) {
456
 
            /** @var Layout $existing */
457
 
            $this->getLog()->debug('Comparing existing [' . $existing->layoutId . ', ' . $existing->displayOrder . '] with unassign [' . $layout->layoutId . ', ' . $layout->displayOrder . '].');
458
 
 
459
 
            if ($layout->displayOrder == null) {
460
 
                if ($existing->getId() == $layout->getId()) {
461
 
                    $found = true;
462
 
                    $existingKey = $key;
463
 
                    break;
464
 
                }
465
 
            } else {
466
 
                if ($existing->getId() == $layout->getId() && $existing->displayOrder == $layout->displayOrder) {
467
 
                    $found = true;
468
 
                    $existingKey = $key;
469
 
                    break;
470
 
                }
471
 
            }
472
 
        }
473
 
 
474
 
        if ($found) {
475
 
            $this->getLog()->debug('Removing item at key ' . $existingKey);
476
 
            unset($this->layouts[$existingKey]);
477
 
        }
478
 
 
479
 
        $countAfter = count($this->layouts);
480
 
        $this->getLog()->debug('Count after unassign ' . $countAfter);
481
 
 
482
 
        if ($countBefore !== $countAfter)
483
 
            $this->layoutAssignmentsChanged = true;
484
 
    }
485
 
 
486
 
    /**
487
 
     * Is the provided layout already assigned to this campaign
488
 
     * @param Layout $checkLayout
489
 
     * @return bool
490
 
     * @throws XiboException
491
 
     */
492
 
    public function isLayoutAssigned($checkLayout)
493
 
    {
494
 
        $assigned = false;
495
 
 
496
 
        $this->load();
497
 
 
498
 
        foreach ($this->layouts as $layout) {
499
 
            if ($layout->layoutId === $checkLayout->layoutId) {
500
 
                $assigned = true;
501
 
                break;
502
 
            }
503
 
        }
504
 
 
505
 
        return $assigned;
 
189
        Log::debug('Unassigning Layout %s from Campaign %s', $layout, $this);
 
190
 
 
191
        $this->load();
 
192
 
 
193
        $this->layouts = array_udiff($this->layouts, [$layout], function ($a, $b) {
 
194
            /**
 
195
             * @var Layout $a
 
196
             * @var Layout $b
 
197
             */
 
198
            return $a->getId() - $b->getId();
 
199
        });
506
200
    }
507
201
 
508
202
    private function add()
509
203
    {
510
 
        $this->campaignId = $this->getStore()->insert('INSERT INTO `campaign` (Campaign, IsLayoutSpecific, UserId) VALUES (:campaign, :isLayoutSpecific, :userId)', array(
 
204
        $this->campaignId = PDOConnect::insert('INSERT INTO `campaign` (Campaign, IsLayoutSpecific, UserId) VALUES (:campaign, :isLayoutSpecific, :userId)', array(
511
205
            'campaign' => $this->campaign,
512
206
            'isLayoutSpecific' => $this->isLayoutSpecific,
513
207
            'userId' => $this->ownerId
516
210
 
517
211
    private function update()
518
212
    {
519
 
        $this->getStore()->update('UPDATE `campaign` SET campaign = :campaign, userId = :userId WHERE CampaignID = :campaignId', [
 
213
        PDOConnect::update('UPDATE `campaign` SET campaign = :campaign WHERE CampaignID = :campaignId', [
520
214
            'campaignId' => $this->campaignId,
521
 
            'campaign' => $this->campaign,
522
 
            'userId' => $this->ownerId
 
215
            'campaign' => $this->campaign
523
216
        ]);
524
217
    }
525
218
 
528
221
     */
529
222
    private function manageAssignments()
530
223
    {
531
 
        if ($this->layoutAssignmentsChanged) {
532
 
            $this->getLog()->debug('Managing Assignments on ' . $this);
533
 
            $this->unlinkLayouts();
534
 
            $this->linkLayouts();
535
 
        } else {
536
 
            $this->getLog()->debug('Assignments have not changed on ' . $this);
537
 
        }
 
224
        Log::debug('Managing Assignments on %s', $this);
 
225
        $this->linkLayouts();
 
226
        $this->unlinkLayouts();
538
227
    }
539
228
 
540
229
    /**
542
231
     */
543
232
    private function linkLayouts()
544
233
    {
545
 
        // Don't do anything if we don't have any layouts
546
 
        if (count($this->layouts) <= 0)
547
 
            return;
548
 
 
549
 
        // Sort the layouts by their display order
550
 
        usort($this->layouts, function($a, $b) {
551
 
            /** @var Layout $a */
552
 
            /** @var Layout $b */
553
 
            if ($a->displayOrder === null)
554
 
                return 1;
555
 
 
556
 
            if ($a->displayOrder === $b->displayOrder)
557
 
                return 0;
558
 
 
559
 
            return ($a->displayOrder < $b->displayOrder) ? -1 : 1;
560
 
        });
561
 
 
562
 
        // Update the layouts, in order to have display order 1 to n
 
234
        // TODO: Make this more efficient by storing the prepared SQL statement
 
235
        $sql = 'INSERT INTO `lkcampaignlayout` (CampaignID, LayoutID, DisplayOrder) VALUES (:campaignId, :layoutId, :displayOrder) ON DUPLICATE KEY UPDATE layoutId = :layoutId2';
 
236
 
563
237
        $i = 0;
564
 
        $sql = 'INSERT INTO `lkcampaignlayout` (CampaignID, LayoutID, DisplayOrder) VALUES ';
565
 
        $params = [];
566
 
 
567
238
        foreach ($this->layouts as $layout) {
568
239
            $i++;
569
 
            $layout->displayOrder = $i;
570
240
 
571
 
            $sql .= '(:campaignId_' . $i . ', :layoutId_' . $i . ', :displayOrder_' . $i . '),';
572
 
            $params['campaignId_' . $i] = $this->campaignId;
573
 
            $params['layoutId_' . $i] = $layout->layoutId;
574
 
            $params['displayOrder_' . $i] = $layout->displayOrder;
 
241
            PDOConnect::insert($sql, array(
 
242
                'campaignId' => $this->campaignId,
 
243
                'displayOrder' => $i,
 
244
                'layoutId' => $layout->layoutId,
 
245
                'layoutId2' => $layout->layoutId
 
246
            ));
575
247
        }
576
 
 
577
 
        $sql = rtrim($sql, ',');
578
 
 
579
 
        $this->getStore()->update($sql, $params);
580
248
    }
581
249
 
582
250
    /**
584
252
     */
585
253
    private function unlinkLayouts()
586
254
    {
587
 
        // Delete all the links
588
 
        $this->getStore()->update('DELETE FROM `lkcampaignlayout` WHERE campaignId = :campaignId', ['campaignId' => $this->campaignId]);
 
255
        // Unlink any layouts that are NOT in the collection
 
256
        $params = ['campaignId' => $this->campaignId];
 
257
 
 
258
        $sql = 'DELETE FROM `lkcampaignlayout` WHERE campaignId = :campaignId AND layoutId NOT IN (0';
 
259
 
 
260
        $i = 0;
 
261
        foreach ($this->layouts as $layout) {
 
262
            $i++;
 
263
            $sql .= ',:layoutId' . $i;
 
264
            $params['layoutId' . $i] = $layout->layoutId;
 
265
        }
 
266
 
 
267
        $sql .= ')';
 
268
 
 
269
        PDOConnect::update($sql, $params);
589
270
    }
590
271
 
591
272
    /**
592
273
     * Notify displays of this campaign change
593
 
     * @param array $options
594
274
     */
595
 
    private function notify($options = [])
 
275
    private function notify()
596
276
    {
597
 
        $options = array_merge([
598
 
            'notify' => true,
599
 
            'collectNow' => true,
600
 
        ], $options);
601
 
 
602
 
        // Do we notify?
603
 
        if ($options['notify']) {
604
 
            $this->getLog()->debug('CampaignId ' . $this->campaignId . ' wants to notify.');
605
 
 
606
 
            $notify = $this->displayFactory->getDisplayNotifyService();
607
 
 
608
 
            // Should we collect immediately
609
 
            if ($options['collectNow'])
610
 
                $notify->collectNow();
611
 
 
612
 
            // Notify
613
 
            $notify->notifyByCampaignId($this->campaignId);
 
277
        Log::debug('Checking for Displays to refresh on Campaign %d', $this->campaignId);
 
278
 
 
279
        foreach (DisplayFactory::getByActiveCampaignId($this->campaignId) as $display) {
 
280
            /* @var \Xibo\Entity\Display $display */
 
281
            $display->setMediaIncomplete();
 
282
            $display->save(false);
614
283
        }
615
284
    }
616
 
}
 
285
}
 
 
b'\\ No newline at end of file'