23
23
namespace Xibo\Entity;
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;
31
use Xibo\Storage\PDOConnect;
75
71
public $numberLayouts;
78
* @SWG\Property(description="The total duration of the campaign (sum of layout's durations)")
81
public $totalDuration;
88
73
private $layouts = [];
93
74
private $permissions = [];
98
75
private $events = [];
101
private $unassignTags = [];
103
/** @var bool Have the Layout assignments changed? */
104
private $layoutAssignmentsChanged = false;
107
* @var PermissionFactory
109
private $permissionFactory;
114
private $layoutFactory;
122
* @var ScheduleFactory
124
private $scheduleFactory;
127
* @var DisplayFactory
129
private $displayFactory;
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
140
public function __construct($store, $log, $permissionFactory, $scheduleFactory, $displayFactory, $tagFactory)
142
$this->setCommonDependencies($store, $log);
143
$this->permissionFactory = $permissionFactory;
144
$this->scheduleFactory = $scheduleFactory;
145
$this->displayFactory = $displayFactory;
146
$this->tagFactory = $tagFactory;
150
* Set Child Object Depencendies
151
* must be set before calling Load with all objects
152
* @param LayoutFactory $layoutFactory
155
public function setChildObjectDependencies($layoutFactory)
157
$this->layoutFactory = $layoutFactory;
164
77
public function __toString()
166
79
return sprintf('CampaignId %d, Campaign %s, LayoutSpecific %d', $this->campaignId, $this->campaign, $this->isLayoutSpecific);
184
97
return $this->ownerId;
189
* @param int $ownerId
191
public function setOwner($ownerId)
193
$this->ownerId = $ownerId;
197
* @param array $options
198
* @throws \Xibo\Exception\NotFoundException
200
public function load($options = [])
202
$options = array_merge([
203
'loadPermissions' => true,
204
'loadLayouts' => true,
100
public function load()
209
102
// If we are already loaded, then don't do it again
210
103
if ($this->campaignId == null || $this->loaded)
213
if ($this->layoutFactory == null)
214
throw new \RuntimeException('Cannot load campaign with all objects without first calling setChildObjectDependencies');
217
if ($options['loadPermissions'])
218
$this->permissions = $this->permissionFactory->getByObjectId('Campaign', $this->campaignId);
107
$this->permissions = PermissionFactory::getByObjectId('Campaign', $this->campaignId);
221
if ($options['loadLayouts'])
222
$this->layouts = $this->layoutFactory->getByCampaignId($this->campaignId, false);
225
if ($options['loadTags'])
226
$this->tags = $this->tagFactory->loadByCampaignId($this->campaignId);
110
$this->layouts = LayoutFactory::getByCampaignId($this->campaignId);
229
if ($options['loadEvents'])
230
$this->events = $this->scheduleFactory->getByCampaignId($this->campaignId);
113
$this->events = ScheduleFactory::getByCampaignId($this->campaignId);
232
115
$this->loaded = true;
236
* @throws InvalidArgumentException
238
118
public function validate()
240
if (!v::stringType()->notEmpty()->validate($this->campaign))
241
throw new InvalidArgumentException(__('Name cannot be empty'), 'name');
246
* Does the campaign have the provided tag?
249
* @throws NotFoundException
251
public function hasTag($searchTag)
255
foreach ($this->tags as $tag) {
257
if ($tag->tag == $searchTag)
269
public function assignTag($tag)
273
if (!in_array($tag, $this->tags))
274
$this->tags[] = $tag;
284
public function unassignTag($tag)
286
$this->tags = array_udiff($this->tags, [$tag], function($a, $b) {
289
return $a->tagId - $b->tagId;
296
* @param array[Tag] $tags
298
public function replaceTags($tags = [])
300
if (!is_array($this->tags) || count($this->tags) <= 0)
301
$this->tags = $this->tagFactory->loadByCampaignId($this->campaignId);
303
$this->unassignTags = array_udiff($this->tags, $tags, function($a, $b) {
306
return $a->tagId - $b->tagId;
309
$this->getLog()->debug('Tags to be removed: %s', json_encode($this->unassignTags));
311
// Replace the arrays
314
$this->getLog()->debug('Tags remaining: %s', json_encode($this->tags));
319
* @param array $options
320
* @throws InvalidArgumentException
322
public function save($options = [])
324
$options = array_merge([
327
'collectNow' => true,
331
$this->getLog()->debug('Saving ' . $this);
333
if ($options['validate'])
120
if (!v::string()->notEmpty()->validate($this->campaign))
121
throw new \InvalidArgumentException(__('Name cannot be empty'));
124
public function save($validate = true)
126
Log::debug('Saving %s', $this);
334
129
$this->validate();
336
131
if ($this->campaignId == null || $this->campaignId == 0) {
390
157
/* @var Permission $permission */
391
158
$permission->delete();
395
foreach ($this->tags as $tag) {
397
$tag->unassignCampaign($this->campaignId);
401
// Notify anyone interested of the changes
402
// we do this before we delete from the DB (otherwise notify won't find anything)
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();
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]);
418
173
* @param Layout $layout
419
* @throws NotFoundException
421
175
public function assignLayout($layout)
425
$layout->displayOrder = ($layout->displayOrder == null || $layout->displayOrder == 0) ? count($this->layouts) + 1 : $layout->displayOrder;
428
foreach ($this->layouts as $existingLayout) {
429
if ($existingLayout->getId() === $layout->getId() && $existingLayout->displayOrder === $layout->displayOrder) {
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;
446
187
public function unassignLayout($layout)
450
$countBefore = count($this->layouts);
451
$this->getLog()->debug('Unassigning Layout, count before assign = ' . $countBefore);
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 . '].');
459
if ($layout->displayOrder == null) {
460
if ($existing->getId() == $layout->getId()) {
466
if ($existing->getId() == $layout->getId() && $existing->displayOrder == $layout->displayOrder) {
475
$this->getLog()->debug('Removing item at key ' . $existingKey);
476
unset($this->layouts[$existingKey]);
479
$countAfter = count($this->layouts);
480
$this->getLog()->debug('Count after unassign ' . $countAfter);
482
if ($countBefore !== $countAfter)
483
$this->layoutAssignmentsChanged = true;
487
* Is the provided layout already assigned to this campaign
488
* @param Layout $checkLayout
490
* @throws XiboException
492
public function isLayoutAssigned($checkLayout)
498
foreach ($this->layouts as $layout) {
499
if ($layout->layoutId === $checkLayout->layoutId) {
189
Log::debug('Unassigning Layout %s from Campaign %s', $layout, $this);
193
$this->layouts = array_udiff($this->layouts, [$layout], function ($a, $b) {
198
return $a->getId() - $b->getId();
508
202
private function add()
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
517
211
private function update()
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
543
232
private function linkLayouts()
545
// Don't do anything if we don't have any layouts
546
if (count($this->layouts) <= 0)
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)
556
if ($a->displayOrder === $b->displayOrder)
559
return ($a->displayOrder < $b->displayOrder) ? -1 : 1;
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';
564
$sql = 'INSERT INTO `lkcampaignlayout` (CampaignID, LayoutID, DisplayOrder) VALUES ';
567
238
foreach ($this->layouts as $layout) {
569
$layout->displayOrder = $i;
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
577
$sql = rtrim($sql, ',');
579
$this->getStore()->update($sql, $params);
585
253
private function unlinkLayouts()
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];
258
$sql = 'DELETE FROM `lkcampaignlayout` WHERE campaignId = :campaignId AND layoutId NOT IN (0';
261
foreach ($this->layouts as $layout) {
263
$sql .= ',:layoutId' . $i;
264
$params['layoutId' . $i] = $layout->layoutId;
269
PDOConnect::update($sql, $params);
592
273
* Notify displays of this campaign change
593
* @param array $options
595
private function notify($options = [])
275
private function notify()
597
$options = array_merge([
599
'collectNow' => true,
603
if ($options['notify']) {
604
$this->getLog()->debug('CampaignId ' . $this->campaignId . ' wants to notify.');
606
$notify = $this->displayFactory->getDisplayNotifyService();
608
// Should we collect immediately
609
if ($options['collectNow'])
610
$notify->collectNow();
613
$notify->notifyByCampaignId($this->campaignId);
277
Log::debug('Checking for Displays to refresh on Campaign %d', $this->campaignId);
279
foreach (DisplayFactory::getByActiveCampaignId($this->campaignId) as $display) {
280
/* @var \Xibo\Entity\Display $display */
281
$display->setMediaIncomplete();
282
$display->save(false);
b'\\ No newline at end of file'