TrackingProcessor::getIdentifyPrevVisitsCount()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 14

Duplication

Lines 19
Ratio 100 %
Metric Value
dl 19
loc 19
rs 9.4285
cc 2
eloc 14
nc 2
nop 0
1
<?php
2
3
namespace Oro\Bundle\TrackingBundle\Processor;
4
5
use Doctrine\Common\Persistence\ManagerRegistry;
6
use Doctrine\ORM\EntityManager;
7
use Doctrine\Common\Util\ClassUtils;
8
9
use Psr\Log\LoggerAwareInterface;
10
use Psr\Log\LoggerAwareTrait;
11
use Psr\Log\NullLogger;
12
13
use Oro\Bundle\EntityExtendBundle\Tools\ExtendHelper;
14
15
use Oro\Bundle\TrackingBundle\Entity\TrackingEventDictionary;
16
use Oro\Bundle\TrackingBundle\Entity\TrackingEvent;
17
use Oro\Bundle\TrackingBundle\Entity\TrackingVisit;
18
use Oro\Bundle\TrackingBundle\Entity\TrackingVisitEvent;
19
use Oro\Bundle\TrackingBundle\Migration\Extension\IdentifierEventExtension;
20
use Oro\Bundle\TrackingBundle\Migration\Extension\VisitEventAssociationExtension;
21
use Oro\Bundle\TrackingBundle\Provider\TrackingEventIdentificationProvider;
22
23
/**
24
 * Class TrackingProcessor
25
 * @package Oro\Bundle\TrackingBundle\Processor
26
 *
27
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
28
 */
29
class TrackingProcessor implements LoggerAwareInterface
30
{
31
    use LoggerAwareTrait;
32
33
    const TRACKING_EVENT_ENTITY       = 'OroTrackingBundle:TrackingEvent';
34
    const TRACKING_VISIT_ENTITY       = 'OroTrackingBundle:TrackingVisit';
35
    const TRACKING_VISIT_EVENT_ENTITY = 'OroTrackingBundle:TrackingVisitEvent';
36
37
    /** Batch size for tracking events */
38
    const BATCH_SIZE = 100;
39
40
    /** Max retries to identify tracking visit */
41
    const MAX_RETRIES = 5;
42
43
    /** @var ManagerRegistry */
44
    protected $doctrine;
45
46
    /** @var array */
47
    protected $collectedVisits = [];
48
49
    /** @var array */
50
    protected $eventDictionary = [];
51
52
    /** @var TrackingEventIdentificationProvider */
53
    protected $trackingIdentification;
54
55
    /** @var int */
56
    protected $processedBatches = 0;
57
58
    /** @var array */
59
    protected $skipList = [];
60
61
    /** @var DeviceDetectorFactory */
62
    protected $deviceDetector;
63
64
    /** @var \DateTime start time */
65
    protected $startTime = null;
66
67
    /** @var \DateInterval|bool */
68
    protected $maxExecTimeout = false;
69
70
    /** Default max execution time (in minutes) */
71
    protected $maxExecTime = 5;
72
73
    /**
74
     * @param ManagerRegistry                     $doctrine
75
     * @param TrackingEventIdentificationProvider $trackingIdentification
76
     */
77
    public function __construct(ManagerRegistry $doctrine, TrackingEventIdentificationProvider $trackingIdentification)
78
    {
79
        $this->doctrine               = $doctrine;
80
        $this->trackingIdentification = $trackingIdentification;
81
        $this->deviceDetector         = new DeviceDetectorFactory();
82
83
        $this->startTime      = $this->getCurrentUtcDateTime();
84
        $this->maxExecTimeout = $this->maxExecTime > 0
85
            ? new \DateInterval('PT' . $this->maxExecTime . 'M')
86
            : false;
87
    }
88
89
    /**
90
     * @param integer $minutes
91
     */
92
    public function setMaxExecutionTime($minutes = null)
93
    {
94
        if ($minutes !== null) {
95
            $this->maxExecTime    = $minutes;
96
            $this->maxExecTimeout = $minutes > 0 ? new \DateInterval('PT' . $minutes . 'M') : false;
97
        }
98
    }
99
100
    /**
101
     * Process tracking data
102
     */
103
    public function process()
104
    {
105
        /** To avoid memory leaks, we turn off doctrine logger */
106
        $this->getEntityManager()->getConnection()->getConfiguration()->setSQLLogger(null);
107
108
        if ($this->logger === null) {
109
            $this->logger = new NullLogger();
110
        }
111
112
        $this->logger->info('Check new visits...');
113
        $totalEvents = $this->getEventsCount();
114
        if ($totalEvents > 0) {
115
            $totalBatches = number_format(ceil($totalEvents / $this->getBatchSize()));
116
            $this->logger->info(
117
                sprintf(
118
                    '<info>Total visits to be processed - %s (%s batches).</info>',
119
                    number_format($totalEvents),
120
                    $totalBatches
121
                )
122
            );
123
            while ($this->processVisits()) {
124
                $this->logBatch(++$this->processedBatches, $totalBatches);
125
                if ($this->checkMaxExecutionTime()) {
126
                    return;
127
                }
128
            }
129
        }
130
131
        $this->logger->info('Recheck previous visit identifiers...');
132
        $totalEvents = $this->getIdentifyPrevVisitsCount();
133 View Code Duplication
        if ($totalEvents > 0) {
134
            $totalBatches           = number_format(ceil($totalEvents / $this->getBatchSize()));
135
            $this->processedBatches = 0;
136
            $this->logger->info(
137
                sprintf(
138
                    '<info>Total previous visit identifiers to be processed - %s (%s batches).</info>',
139
                    number_format($totalEvents),
140
                    $totalBatches
141
                )
142
            );
143
            while ($this->identifyPrevVisits()) {
144
                $this->logBatch(++$this->processedBatches, $totalBatches);
145
                if ($this->checkMaxExecutionTime()) {
146
                    return;
147
                }
148
            }
149
        }
150
151
        $this->logger->info('Recheck previous visit events...');
152
        $totalEvents = $this->getIdentifyPrevVisitEventsCount();
153 View Code Duplication
        if ($totalEvents > 0) {
154
            $totalBatches           = number_format(ceil($totalEvents / $this->getBatchSize()));
155
            $this->processedBatches = 0;
156
            $this->logger->info(
157
                sprintf(
158
                    '<info>Total previous visit events to be processed - %s (%s batches).</info>',
159
                    number_format($totalEvents),
160
                    $totalBatches
161
                )
162
            );
163
            $this->skipList = [];
164
            while ($this->identifyPrevVisitEvents()) {
165
                $this->logBatch(++$this->processedBatches, $totalBatches);
166
                if ($this->checkMaxExecutionTime()) {
167
                    return;
168
                }
169
            }
170
        }
171
172
        $this->logger->info('<info>Done</info>');
173
    }
174
175
    /**
176
     * @param integer $processed
177
     * @param string  $total
178
     */
179
    protected function logBatch($processed, $total)
180
    {
181
        $this->logger->info(
182
            sprintf(
183
                'Batch #%s of %s processed at <info>%s</info>.',
184
                number_format($processed),
185
                $total,
186
                date('Y-m-d H:i:s')
187
            )
188
        );
189
    }
190
191
    /**
192
     * Checks of process max execution time
193
     *
194
     * @return bool
195
     */
196
    protected function checkMaxExecutionTime()
197
    {
198
        if ($this->maxExecTimeout !== false) {
199
            $date = $this->getCurrentUtcDateTime();
200
            if ($date->sub($this->maxExecTimeout) >= $this->startTime) {
201
                $this->logger->info('<comment>Exit because allocated time frame elapsed.</comment>');
202
203
                return true;
204
            }
205
        }
206
207
        return false;
208
    }
209
210
    /**
211
     * Returns count of web events to be processed.
212
     *
213
     * @return integer
214
     */
215
    protected function getEventsCount()
216
    {
217
        $em           = $this->getEntityManager();
218
        $queryBuilder = $em
219
            ->getRepository(self::TRACKING_EVENT_ENTITY)
220
            ->createQueryBuilder('entity')
221
            ->select('COUNT (entity.id)')
222
            ->where('entity.parsed = false');
223
224
        return $queryBuilder->getQuery()->getSingleScalarResult();
225
    }
226
227
    /**
228
     * Returns count of not identified web visits to be processed.
229
     *
230
     * @return integer
231
     */
232 View Code Duplication
    protected function getIdentifyPrevVisitsCount()
233
    {
234
        $em           = $this->getEntityManager();
235
        $queryBuilder = $em
236
            ->getRepository(self::TRACKING_VISIT_ENTITY)
237
            ->createQueryBuilder('entity');
238
        $queryBuilder
239
            ->select('COUNT (entity.id)')
240
            ->where('entity.identifierDetected = false')
241
            ->andWhere('entity.parsedUID > 0')
242
            ->andWhere('entity.parsingCount < :maxRetries')
243
            ->setParameter('maxRetries', $this->getMaxRetriesCount());
244
245
        if (count($this->skipList)) {
246
            $queryBuilder->andWhere('entity.id not in(' . implode(',', $this->skipList) . ')');
247
        }
248
249
        return $queryBuilder->getQuery()->getSingleScalarResult();
250
    }
251
252
    /**
253
     * Returns count of tracking visit events to be processed.
254
     *
255
     * @return integer
256
     */
257 View Code Duplication
    protected function getIdentifyPrevVisitEventsCount()
258
    {
259
        $em           = $this->getEntityManager();
260
        $queryBuilder = $em
261
            ->getRepository(self::TRACKING_VISIT_EVENT_ENTITY)
262
            ->createQueryBuilder('entity');
263
        $queryBuilder
264
            ->select('COUNT (entity.id)')
265
            ->andWhere('entity.parsingCount < :maxRetries')
266
            ->setParameter('maxRetries', $this->getMaxRetriesCount());
267
268
        if (count($this->skipList)) {
269
            $queryBuilder->andWhere('entity.id not in(' . implode(',', $this->skipList) . ')');
270
        }
271
272
        return $queryBuilder->getQuery()->getSingleScalarResult();
273
    }
274
275
    /**
276
     * Process previous visit events
277
     *
278
     * @return bool
279
     */
280
    protected function identifyPrevVisitEvents()
281
    {
282
        $em           = $this->getEntityManager();
283
        $queryBuilder = $em
284
            ->getRepository(self::TRACKING_VISIT_EVENT_ENTITY)
285
            ->createQueryBuilder('entity');
286
        $queryBuilder
287
            ->select('entity')
288
            ->andWhere('entity.parsingCount < :maxRetries')
289
            ->setParameter('maxRetries', $this->getMaxRetriesCount())
290
            ->setMaxResults($this->getBatchSize());
291
292
        if (count($this->skipList)) {
293
            $queryBuilder->andWhere('entity.id not in(' . implode(',', $this->skipList) . ')');
294
        }
295
296
        /** @var TrackingVisitEvent[] $entities */
297
        $entities = $queryBuilder->getQuery()->getResult();
298
        if ($entities) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $entities of type Oro\Bundle\TrackingBundl...ty\TrackingVisitEvent[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
299
            foreach ($entities as $visitEvent) {
300
                $visitEvent->setParsingCount($visitEvent->getParsingCount() + 1);
301
                $this->skipList[] = $visitEvent->getId();
302
                $targets          = $this->trackingIdentification->processEvent($visitEvent);
303
                if (!empty($targets)) {
304
                    foreach ($targets as $target) {
305
                        $visitEvent->addAssociationTarget($target);
306
                    }
307
                }
308
309
                $em->persist($visitEvent);
310
            }
311
312
            $em->flush();
313
            $em->clear();
314
315
            return true;
316
        }
317
318
        return false;
319
    }
320
321
    /**
322
     *  Identify previous visits in case than we haven't data to identify visit previously
323
     */
324
    protected function identifyPrevVisits()
325
    {
326
        $em           = $this->getEntityManager();
327
        $queryBuilder = $em
328
            ->getRepository(self::TRACKING_VISIT_ENTITY)
329
            ->createQueryBuilder('entity');
330
        $queryBuilder
331
            ->select('entity')
332
            ->where('entity.identifierDetected = false')
333
            ->andWhere('entity.parsedUID > 0')
334
            ->andWhere('entity.parsingCount < :maxRetries')
335
            ->orderBy('entity.firstActionTime', 'ASC')
336
            ->setParameter('maxRetries', $this->getMaxRetriesCount())
337
            ->setMaxResults($this->getBatchSize());
338
339
        if (count($this->skipList)) {
340
            $queryBuilder->andWhere('entity.id not in(' . implode(',', $this->skipList) . ')');
341
        }
342
343
        $entities = $queryBuilder->getQuery()->getResult();
344
        if ($entities) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $entities of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
345
            /** @var TrackingVisit $visit */
346
            foreach ($entities as $visit) {
347
                $idObj = $this->trackingIdentification->identify($visit);
348
                if ($idObj && $idObj['targetObject']) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $idObj of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
349
                    $visit->setIdentifierTarget($idObj['targetObject']);
350
                    $visit->setIdentifierDetected(true);
351
352
                    $this->logger->info('-- <comment>parsed UID "' . $idObj['parsedUID'] . '"</comment>');
353
                } else {
354
                    $visit->setParsingCount($visit->getParsingCount() + 1);
355
                    $this->skipList[] = $visit->getId();
356
                }
357
358
                $em->persist($visit);
359
                $this->collectedVisits[] = $visit;
360
            }
361
362
            $em->flush();
363
364
            $this->updateVisits($this->collectedVisits);
365
366
            $this->collectedVisits = [];
367
            $em->clear();
368
369
            return true;
370
        }
371
372
        return false;
373
    }
374
375
    /**
376
     * Identify previous visits
377
     *
378
     * @param array $entities
379
     */
380
    protected function updateVisits($entities)
381
    {
382
        /** @var TrackingVisit $visit */
383
        foreach ($entities as $visit) {
384
            $this->logger->info(
385
                sprintf(
386
                    'Process visit id: %s, visitorUid: %s',
387
                    $visit->getId(),
388
                    $visit->getVisitorUid()
389
                )
390
            );
391
392
            $identifier = $visit->getIdentifierTarget();
393
            if ($identifier) {
394
                // update tracking event identifiers
395
                $associationName = ExtendHelper::buildAssociationName(
396
                    ClassUtils::getClass($identifier),
397
                    VisitEventAssociationExtension::ASSOCIATION_KIND
398
                );
399
400
                $qb = $this->getEntityManager()
401
                    ->createQueryBuilder();
402
403
                $subSelect = $qb->select('entity.id')
404
                    ->from(self::TRACKING_VISIT_ENTITY, 'entity')
405
                    ->where('entity.visitorUid = :visitorUid')
406
                    ->andWhere('entity.firstActionTime < :maxDate')
407
                    ->andWhere('entity.identifierDetected = false')
408
                    ->andWhere('entity.parsedUID = 0')
409
                    ->andWhere('entity.trackingWebsite  = :website')
410
                    ->setParameter('visitorUid', $visit->getVisitorUid())
411
                    ->setParameter('maxDate', $visit->getFirstActionTime())
412
                    ->setParameter('website', $visit->getTrackingWebsite())
413
                    ->getQuery()
414
                    ->getArrayResult();
415
                if (!empty($subSelect)) {
416
                    array_walk(
417
                        $subSelect,
418
                        function (&$value) {
419
                            $value = $value['id'];
420
                        }
421
                    );
422
423
                    $this->getEntityManager()->createQueryBuilder()
424
                        ->update(self::TRACKING_VISIT_EVENT_ENTITY, 'event')
425
                        ->set('event.' . $associationName, ':identifier')
426
                        ->where('event.visit in(' . implode(',', $subSelect) . ')')
427
                        ->setParameter('identifier', $identifier)
428
                        ->getQuery()
429
                        ->execute();
430
                }
431
432
                $associationName = ExtendHelper::buildAssociationName(
433
                    ClassUtils::getClass($identifier),
434
                    IdentifierEventExtension::ASSOCIATION_KIND
435
                );
436
437
                $this->getEntityManager()
438
                    ->createQueryBuilder()
439
                    ->update(self::TRACKING_VISIT_ENTITY, 'entity')
440
                    ->set('entity.' . $associationName, ':identifier')
441
                    ->set('entity.identifierDetected', ':detected')
442
                    ->where('entity.visitorUid = :visitorUid')
443
                    ->andWhere('entity.firstActionTime < :maxDate')
444
                    ->andWhere('entity.identifierDetected = false')
445
                    ->andWhere('entity.parsedUID = 0')
446
                    ->andWhere('entity.trackingWebsite  = :website')
447
                    ->setParameter('visitorUid', $visit->getVisitorUid())
448
                    ->setParameter('maxDate', $visit->getFirstActionTime())
449
                    ->setParameter('website', $visit->getTrackingWebsite())
450
                    ->setParameter('identifier', $identifier)
451
                    ->setParameter('detected', true)
452
                    ->getQuery()
453
                    ->execute();
454
            }
455
        }
456
457
        $this->deviceDetector->clearInstances();
458
    }
459
460
    /**
461
     * Collect new tracking visits with tracking visit events
462
     */
463
    protected function processVisits()
464
    {
465
        $queryBuilder = $this->getEntityManager()
466
            ->getRepository(self::TRACKING_EVENT_ENTITY)
467
            ->createQueryBuilder('entity')
468
            ->where('entity.parsed = false')
469
            ->orderBy('entity.id', 'ASC')
470
            ->setMaxResults($this->getBatchSize());
471
472
        $entities = $queryBuilder->getQuery()->getResult();
473
474
        if ($entities) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $entities of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
475
            $this->processTrackingVisits($entities);
476
477
            return true;
478
        }
479
480
        return false;
481
    }
482
483
    /**
484
     * @param array|TrackingEvent[] $entities
485
     */
486
    protected function processTrackingVisits($entities)
487
    {
488
        $em = $this->getEntityManager();
489
490
        /** @var  TrackingEvent $event */
491
        foreach ($entities as $event) {
492
            $this->logger->info('Processing event - ' . $event->getId());
493
494
            $trackingVisitEvent = new TrackingVisitEvent();
495
            $trackingVisitEvent->setParsingCount(0);
496
            $trackingVisitEvent->setEvent($this->getEventType($event));
497
498
            $eventData   = $event->getEventData();
499
            $decodedData = json_decode($eventData->getData(), true);
500
501
            $trackingVisit = $this->getTrackingVisit($event, $decodedData);
502
            $trackingVisitEvent->setVisit($trackingVisit);
503
            $trackingVisitEvent->setWebEvent($event);
504
            $trackingVisitEvent->setWebsite($event->getWebsite());
505
506
            $targets = $this->trackingIdentification->processEvent($trackingVisitEvent);
507
            if (!empty($targets)) {
508
                foreach ($targets as $target) {
509
                    $trackingVisitEvent->addAssociationTarget($target);
510
                }
511
            }
512
513
            $event->setParsed(true);
514
515
            $em->persist($event);
516
            $em->persist($trackingVisitEvent);
517
            $em->persist($trackingVisit);
518
        }
519
520
        $em->flush();
521
522
        $this->updateVisits($this->collectedVisits);
523
524
        $this->collectedVisits = [];
525
        $this->eventDictionary = [];
526
        $em->clear();
527
528
        $this->logger->info(
529
            sprintf(
530
                '<comment>Memory usage (currently) %dMB/ (max) %dMB</comment>',
531
                round(memory_get_usage(true) / 1024 / 1024),
532
                memory_get_peak_usage(true) / 1024 / 1024
533
            )
534
        );
535
    }
536
537
    /**
538
     * @param TrackingEvent $trackingEvent
539
     * @param array         $decodedData
540
     *
541
     * @return TrackingVisit
542
     */
543
    protected function getTrackingVisit(TrackingEvent $trackingEvent, $decodedData)
544
    {
545
        $visitorUid     = $decodedData['_id'];
546
        $userIdentifier = $trackingEvent->getUserIdentifier();
547
548
        $hash = md5($visitorUid . $userIdentifier);
549
550
        // try to find existing visit
551
        if (!empty($this->collectedVisits) && array_key_exists($hash, $this->collectedVisits)) {
552
            $visit = $this->collectedVisits[$hash];
553
        } else {
554
            $visit = $this->doctrine->getRepository(self::TRACKING_VISIT_ENTITY)->findOneBy(
555
                [
556
                    'visitorUid'      => $visitorUid,
557
                    'userIdentifier'  => $trackingEvent->getUserIdentifier(),
558
                    'trackingWebsite' => $trackingEvent->getWebsite()
559
                ]
560
            );
561
        }
562
563
        if (!$visit) {
564
            $visit = new TrackingVisit();
565
            $visit->setParsedUID(0);
566
            $visit->setParsingCount(0);
567
            $visit->setUserIdentifier($trackingEvent->getUserIdentifier());
568
            $visit->setVisitorUid($visitorUid);
569
            $visit->setFirstActionTime($trackingEvent->getCreatedAt());
570
            $visit->setLastActionTime($trackingEvent->getCreatedAt());
571
            $visit->setTrackingWebsite($trackingEvent->getWebsite());
572
            $visit->setIdentifierDetected(false);
573
574
            if (!empty($decodedData['cip'])) {
575
                $visit->setIp($decodedData['cip']);
576
            }
577
578
            if (!empty($decodedData['ua'])) {
579
                $this->processUserAgentString($visit, $decodedData['ua']);
580
            }
581
582
            $this->identifyTrackingVisit($visit);
583
584
            $this->collectedVisits[$hash] = $visit;
585
        } else {
586
            if ($visit->getFirstActionTime() > $trackingEvent->getCreatedAt()) {
587
                $visit->setFirstActionTime($trackingEvent->getCreatedAt());
588
            }
589
            if ($visit->getLastActionTime() < $trackingEvent->getCreatedAt()) {
590
                $visit->setLastActionTime($trackingEvent->getCreatedAt());
591
            }
592
        }
593
594
        return $visit;
595
    }
596
597
    /**
598
     * @param TrackingVisit $visit
599
     * @param string        $ua
600
     *
601
     * @SuppressWarnings(PHPMD.NPathComplexity)
602
     * because of ternary operators which in current case is clear enough to replace it with 'if' statement.
603
     */
604
    protected function processUserAgentString(TrackingVisit $visit, $ua)
605
    {
606
        $device = $this->deviceDetector->getInstance($ua);
607
        $os     = $device->getOs();
608
        if (is_array($os)) {
609
            $visit->setOs(isset($os['name']) ? $os['name'] : null);
610
            $visit->setOsVersion(isset($os['version']) ? $os['version'] : null);
611
        }
612
613
        $client = $device->getClient();
614
        if (is_array($client)) {
615
            $visit->setClient(isset($client['name']) ? $client['name'] : null);
616
            $visit->setClientType(isset($client['type']) ? $client['type'] : null);
617
            $visit->setClientVersion(isset($client['version']) ? $client['version'] : null);
618
        }
619
620
        $visit->setDesktop($device->isDesktop());
621
        $visit->setMobile($device->isMobile());
622
        $visit->setBot($device->isBot());
623
    }
624
625
    /**
626
     * Get Event dictionary for given tracking event
627
     *
628
     * @param TrackingEvent $event
629
     * @return TrackingEventDictionary
630
     */
631
    protected function getEventType(TrackingEvent $event)
632
    {
633
        $eventWebsite = $event->getWebsite();
634
        if ($eventWebsite
635
            && isset(
636
                $this->eventDictionary[$eventWebsite->getId()],
637
                $this->eventDictionary[$eventWebsite->getId()][$event->getName()]
638
            )
639
        ) {
640
            $eventType = $this->eventDictionary[$eventWebsite->getId()][$event->getName()];
641
        } else {
642
            $eventType = $this->getEntityManager()
643
                ->getRepository('OroTrackingBundle:TrackingEventDictionary')
644
                ->findOneBy(
645
                    [
646
                        'name'    => $event->getName(),
647
                        'website' => $eventWebsite
648
                    ]
649
                );
650
        }
651
652
        if (!$eventType) {
653
            $eventType = new TrackingEventDictionary();
654
            $eventType->setName($event->getName());
655
            $eventType->setWebsite($eventWebsite);
656
657
            $this->getEntityManager()->persist($eventType);
658
659
            $this->eventDictionary[$eventWebsite ? $eventWebsite->getId() : null][$event->getName()] = $eventType;
660
        }
661
662
        return $eventType;
663
    }
664
665
    /**
666
     * @param TrackingVisit $visit
667
     */
668
    protected function identifyTrackingVisit(TrackingVisit $visit)
669
    {
670
        /**
671
         * try to identify visit
672
         */
673
        $idObj = $this->trackingIdentification->identify($visit);
674
        if ($idObj) {
675
            /**
676
             * if identification was successful we should:
677
             *  - assign visit to target
678
             *  - assign all previous visits to same identified object(s).
679
             */
680
            $this->logger->info('-- <comment>parsed UID "' . $idObj['parsedUID'] . '"</comment>');
681
            if ($idObj['parsedUID'] !== null) {
682
                $visit->setParsedUID($idObj['parsedUID']);
683
                if ($idObj['targetObject']) {
684
                    $visit->setIdentifierTarget($idObj['targetObject']);
685
                    $visit->setIdentifierDetected(true);
686
                }
687
            }
688
        }
689
    }
690
691
    /**
692
     * Returns default entity manager
693
     *
694
     * @return EntityManager
695
     */
696 View Code Duplication
    protected function getEntityManager()
697
    {
698
        /** @var EntityManager $em */
699
        $em = $this->doctrine->getManager();
700
        if (!$em->isOpen()) {
701
            $this->doctrine->resetManager();
702
            $em = $this->doctrine->getManager();
703
        }
704
705
        return $em;
706
    }
707
708
    /**
709
     * Get max retries to identify tracking visit
710
     *
711
     * @return int
712
     */
713
    protected function getMaxRetriesCount()
714
    {
715
        return self::MAX_RETRIES;
716
    }
717
718
    /**
719
     * Get batch size for tracking events
720
     *
721
     * @return int
722
     */
723
    protected function getBatchSize()
724
    {
725
        return self::BATCH_SIZE;
726
    }
727
728
    /**
729
     * Gets a DateTime object that is set to the current date and time in UTC.
730
     *
731
     * @return \DateTime
732
     */
733
    protected function getCurrentUtcDateTime()
734
    {
735
        return new \DateTime('now', new \DateTimeZone('UTC'));
736
    }
737
}
738