Completed
Push — master ( a18731...e2e070 )
by
unknown
99:54 queued 47:45
created

persistEventDictionaries()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 27
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 27
rs 8.8571
c 1
b 0
f 0
cc 3
eloc 19
nc 3
nop 2
1
<?php
2
3
namespace OroCRM\Bundle\DemoDataBundle\Migrations\Data\Demo\ORM;
4
5
use Doctrine\Common\DataFixtures\AbstractFixture;
6
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
7
use Doctrine\Common\Persistence\ObjectManager;
8
9
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
10
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
11
12
use Oro\Bundle\OrganizationBundle\Entity\Organization;
13
use Oro\Bundle\TrackingBundle\Entity\TrackingEvent;
14
use Oro\Bundle\TrackingBundle\Entity\TrackingEventDictionary;
15
use Oro\Bundle\TrackingBundle\Entity\TrackingVisit;
16
use Oro\Bundle\TrackingBundle\Entity\TrackingVisitEvent;
17
use Oro\Bundle\TrackingBundle\Entity\TrackingWebsite;
18
19
use OroCRM\Bundle\MagentoBundle\Entity\Customer;
20
use OroCRM\Bundle\MagentoBundle\Provider\ChannelType;
21
use OroCRM\Bundle\MagentoBundle\Provider\TrackingCustomerIdentification as TCI;
22
23
class LoadTrackingWebsiteData extends AbstractFixture implements
24
    ContainerAwareInterface,
25
    DependentFixtureInterface
26
{
27
    use ContainerAwareTrait;
28
29
    /**
30
     * Number of TrackingVisits to generate per customer
31
     *
32
     * @var int
33
     */
34
    const VISITS_PER_CUSTOMER = 10;
35
36
    /**
37
     * Number of events per visit
38
     * Total events would be customers x VISITS_PER_CUSTOMER x EVENTS_PER_VISIT
39
     *
40
     * @var int
41
     */
42
    const EVENTS_PER_VISIT = 20;
43
44
    /**
45
     * The time window that events are generated in days
46
     *
47
     * @var int
48
     */
49
    const EVENTS_PERIOD = 75;
50
51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function getDependencies()
55
    {
56
        return [
57
            'OroCRM\Bundle\DemoDataBundle\Migrations\Data\Demo\ORM\LoadMagentoData'
58
        ];
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64
    public function load(ObjectManager $om)
65
    {
66
        $organization = $this->getReference('default_organization');
67
        $customers = $om->getRepository('OroCRMMagentoBundle:Customer')->findAll();
68
69
        $websites = $this->persistTrackingWebsites($om, $organization);
70
        $eventDictionary = $this->persistEventDictionaries($om, $websites);
71
72
        foreach ($customers as $customer) {
73
            $website = $websites[$customer->getDataChannel()->getId()];
74
            $websiteEvents = $eventDictionary[$website->getIdentifier()];
75
76
            for ($i = 0; $i < static::VISITS_PER_CUSTOMER; $i++) {
77
                $visit = $this->persistTrackingVisit($om, $website, $customer);
78
79
                for ($j = 0; $j < static::EVENTS_PER_VISIT; $j++) {
80
                    $this->persistTrackingVisitEvent($om, $visit, $websiteEvents);
0 ignored issues
show
Documentation introduced by
$websiteEvents is of type object<Oro\Bundle\Tracki...rackingEventDictionary>, but the function expects a array<integer,object<Oro...ackingEventDictionary>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
81
                }
82
            }
83
        }
84
85
        $om->flush();
86
    }
87
88
    /**
89
     * @param ObjectManager $om
90
     * @param Organization $organization
91
     * @return TrackingWebsite[]
92
     */
93
    protected function persistTrackingWebsites(ObjectManager $om, Organization $organization)
94
    {
95
        $channels = $om->getRepository('OroCRMChannelBundle:Channel')->findBy([
96
            'channelType' => ChannelType::TYPE
97
        ]);
98
99
        $websites = [];
100
        foreach ($channels as $channel) {
101
            $website = new TrackingWebsite();
102
            $website->setName($channel->getName())
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Oro\Bundle\TrackingBundle\Entity\TrackingWebsite as the method setChannel() does only exist in the following sub-classes of Oro\Bundle\TrackingBundle\Entity\TrackingWebsite: OroCRM\Bundle\MagentoBun...ity\TestTrackingWebsite. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
103
                ->setIdentifier(uniqid())
104
                ->setUrl('http://magento.domain')
105
                ->setChannel($channel)
106
                ->setOrganization($organization);
107
108
            $om->persist($website);
109
            $websites[$channel->getId()] = $website;
110
        }
111
112
        return $websites;
113
    }
114
115
    /**
116
     * @param ObjectManager $om
117
     * @param array $websites
118
     *
119
     * @return TrackingEventDictionary[]
120
     */
121
    protected function persistEventDictionaries(ObjectManager $om, array $websites)
122
    {
123
        $events = [
124
            TCI::EVENT_REGISTRATION_FINISHED,
125
            TCI::EVENT_CART_ITEM_ADDED,
126
            TCI::EVENT_CHECKOUT_STARTED,
127
            TCI::EVENT_ORDER_PLACE_SUCCESS,
128
            TCI::EVENT_ORDER_PLACED,
129
            TCI::EVENT_CUSTOMER_LOGIN,
130
            TCI::EVENT_CUSTOMER_LOGOUT,
131
            TCI::EVENT_VISIT,
132
        ];
133
134
        $dictionaries = [];
135
        foreach ($websites as $website) {
136
            foreach ($events as $eventName) {
137
                $event = new TrackingEventDictionary();
138
                $event->setName($eventName);
139
                $event->setWebsite($website);
140
141
                $om->persist($event);
142
                $dictionaries[$website->getIdentifier()][] = $event;
143
            }
144
        }
145
146
        return $dictionaries;
147
    }
148
149
    /**
150
     * @param ObjectManager $om
151
     * @param TrackingWebsite $website
152
     * @param Customer $customer
153
     *
154
     * @return TrackingVisit
155
     */
156
    protected function persistTrackingVisit(
157
        ObjectManager $om,
158
        TrackingWebsite $website,
159
        Customer $customer
160
    ) {
161
        $randomDays = mt_rand(0, static::EVENTS_PERIOD - 1);
162
        $start = new \DateTime(sprintf('-%s day', $randomDays));
163
164
        $end = new \DateTime();
165
        $end->setTimestamp(mt_rand($start->getTimestamp(), time()));
166
167
        $visit = new TrackingVisit();
168
        $visit->setTrackingWebsite($website)
169
            ->setVisitorUid(uniqid())
170
            ->setUserIdentifier('id=' . $customer->getOriginId())
171
            ->setIdentifierTarget($customer)
172
            ->setFirstActionTime($start)
173
            ->setLastActionTime($end);
174
175
        $om->persist($visit);
176
177
        return $visit;
178
    }
179
180
    /**
181
     * @param ObjectManager $om
182
     * @param TrackingVisit $visit
183
     * @param TrackingEventDictionary[] $eventDictionary
184
     */
185
    protected function persistTrackingVisitEvent(ObjectManager $om, TrackingVisit $visit, array $eventDictionary)
186
    {
187
        $event = $eventDictionary[array_rand($eventDictionary)];
188
189
        $eventTimestamp = mt_rand(
190
            $visit->getFirstActionTime()->getTimestamp(),
191
            $visit->getLastActionTime()->getTimestamp()
192
        );
193
194
        $eventDate = new \DateTime();
195
        $eventDate->setTimestamp($eventTimestamp);
196
197
        $trackingEvent = new TrackingEvent();
198
        $trackingEvent->setWebsite($visit->getTrackingWebsite())
199
            ->setName($event->getName())
200
            ->setValue(1)
201
            ->setUserIdentifier($visit->getUserIdentifier())
202
            ->setUrl('http://magento.domain')
203
            ->setTitle('Magento Store')
204
            ->setLoggedAt($eventDate)
205
        ;
206
207
        $om->persist($trackingEvent);
208
209
        $visitEvent = new TrackingVisitEvent();
210
        $visitEvent->setVisit($visit)
211
            ->setEvent($event)
212
            ->setWebEvent($trackingEvent)
213
            ->setWebsite($visit->getTrackingWebsite())
214
            ->addAssociationTarget($visit->getIdentifierTarget())
0 ignored issues
show
Bug introduced by
It seems like $visit->getIdentifierTarget() targeting Oro\Bundle\TrackingBundl...::getIdentifierTarget() can also be of type null; however, Oro\Bundle\TrackingBundl...:addAssociationTarget() does only seem to accept object, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
215
        ;
216
217
        $om->persist($visitEvent);
218
    }
219
}
220