LoadLeadsData   C
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 286
Duplicated Lines 12.24 %

Coupling/Cohesion

Components 1
Dependencies 22

Importance

Changes 0
Metric Value
wmc 20
lcom 1
cbo 22
dl 35
loc 286
rs 5.7894
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A setContainer() 0 6 1
A load() 0 6 1
B initSupportingEntities() 0 24 2
B loadLeads() 28 32 5
A loadSalesFlows() 0 55 4
A getRandomBoolean() 0 4 1
A setSecurityContext() 7 7 1
A createLead() 0 67 2
A transit() 0 11 2
A getOrder() 0 4 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace Oro\Bundle\ReportCRMBundle\Tests\Functional\DataFixtures;
4
5
use Doctrine\Common\Collections\Collection;
6
use Doctrine\Common\DataFixtures\AbstractFixture;
7
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
8
use Doctrine\Common\Persistence\ObjectManager;
9
use Doctrine\ORM\EntityManager;
10
11
use Oro\Bundle\CurrencyBundle\Entity\MultiCurrency;
12
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
13
use Symfony\Component\DependencyInjection\ContainerInterface;
14
15
use Oro\Bundle\AddressBundle\Entity\Country;
16
use Oro\Bundle\AddressBundle\Entity\Region;
17
use Oro\Bundle\EntityConfigBundle\Config\ConfigManager;
18
use Oro\Bundle\EntityExtendBundle\Entity\AbstractEnumValue;
19
use Oro\Bundle\EntityExtendBundle\Tools\ExtendHelper;
20
use Oro\Bundle\OrganizationBundle\Entity\Organization;
21
use Oro\Bundle\SecurityBundle\Authentication\Token\UsernamePasswordOrganizationToken;
22
use Oro\Bundle\UserBundle\Entity\User;
23
use Oro\Bundle\WorkflowBundle\Entity\WorkflowItem;
24
use Oro\Bundle\WorkflowBundle\Model\WorkflowManager;
25
use Oro\Bundle\ChannelBundle\Builder\BuilderFactory;
26
use Oro\Bundle\ChannelBundle\Entity\Channel;
27
use Oro\Bundle\SalesBundle\Entity\Lead;
28
use Oro\Bundle\SalesBundle\Entity\LeadPhone;
29
use Oro\Bundle\SalesBundle\Entity\LeadEmail;
30
use Oro\Bundle\SalesBundle\Entity\LeadAddress;
31
use Oro\Bundle\SalesBundle\Entity\Opportunity;
32
use Oro\Bundle\SalesBundle\Migrations\Data\ORM\DefaultChannelData;
33
34
class LoadLeadsData extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface
35
{
36
    const FLUSH_MAX = 50;
37
38
    /** @var ContainerInterface */
39
    protected $container;
40
41
    /** @var User[] */
42
    protected $users;
43
44
    /** @var Country[] */
45
    protected $countries;
46
47
    /** @var WorkflowManager */
48
    protected $workflowManager;
49
50
    /** @var  EntityManager */
51
    protected $em;
52
53
    /** @var Organization */
54
    protected $organization;
55
56
    /** @var BuilderFactory */
57
    protected $channelBuilderFactory;
58
59
    /** @var Channel */
60
    protected $channel;
61
62
    /** @var AbstractEnumValue[] */
63
    protected $sources;
64
65
66
    /**
67
     * {@inheritDoc}
68
     */
69
    public function setContainer(ContainerInterface $container = null)
70
    {
71
        $this->container             = $container;
72
        $this->workflowManager       = $container->get('oro_workflow.manager');
0 ignored issues
show
Bug introduced by
It seems like $container is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
73
        $this->channelBuilderFactory = $container->get('oro_channel.builder.factory');
74
    }
75
76
    /**
77
     * {@inheritDoc}
78
     */
79
    public function load(ObjectManager $manager)
80
    {
81
        $this->organization = $manager->getRepository('OroOrganizationBundle:Organization')->getFirst();
82
        $this->initSupportingEntities($manager);
83
        $this->loadLeads($manager);
84
    }
85
86
    protected function initSupportingEntities(ObjectManager $manager = null)
87
    {
88
        if ($manager) {
89
            $this->em = $manager;
90
        }
91
92
        $this->users     = $this->em->getRepository('OroUserBundle:User')->findAll();
93
        $this->countries = $this->em->getRepository('OroAddressBundle:Country')->findAll();
94
95
        $className     = ExtendHelper::buildEnumValueClassName('lead_source');
96
        $enumRepo      = $manager->getRepository($className);
0 ignored issues
show
Bug introduced by
It seems like $manager is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
97
        $this->sources = $enumRepo->findAll();
98
99
        $this->channel = $this
100
            ->channelBuilderFactory
101
            ->createBuilder()
102
            ->setChannelType(DefaultChannelData::B2B_CHANNEL_TYPE)
103
            ->setStatus(Channel::STATUS_ACTIVE)
104
            ->setEntities()
105
            ->getChannel();
106
107
        $manager->persist($this->channel);
108
        $manager->flush($this->channel);
109
    }
110
111
    public function loadLeads(ObjectManager $manager)
112
    {
113
        $handle = fopen(__DIR__ . DIRECTORY_SEPARATOR . 'dictionaries' . DIRECTORY_SEPARATOR . "leads.csv", "r");
114 View Code Duplication
        if ($handle) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
115
            $headers = [];
116
            if (($data = fgetcsv($handle, 1000, ",")) !== false) {
117
                //read headers
118
                $headers = $data;
119
            }
120
            $randomUser = count($this->users) - 1;
121
            $i          = 0;
122
            while (($data = fgetcsv($handle, 1000, ",")) !== false) {
123
                $user = $this->users[mt_rand(0, $randomUser)];
124
                $this->setSecurityContext($user);
125
126
                $data = array_combine($headers, array_values($data));
127
128
                $lead = $this->createLead($manager, $data, $user);
129
                $this->em->persist($lead);
130
131
                $this->loadSalesFlows($lead);
132
133
                $i++;
134
                if ($i % self::FLUSH_MAX == 0) {
135
                    $this->em->flush();
136
                }
137
            }
138
139
            $this->em->flush();
140
            fclose($handle);
141
        }
142
    }
143
144
    /**
145
     * @param Lead $lead
146
     */
147
    protected function loadSalesFlows(Lead $lead)
148
    {
149
        $leadWorkflowItem = $this->workflowManager->startWorkflow(
150
            'b2b_flow_lead',
151
            $lead,
152
            'qualify',
153
            [
154
                'opportunity_name' => $lead->getName(),
155
                'company_name' => $lead->getCompanyName(),
156
            ]
157
        );
158
        //@TODO change test according to CRM-6344
159
        if ($this->getRandomBoolean()) {
160
            /** @var Opportunity $opportunity */
161
            $opportunity   = $leadWorkflowItem->getResult()->get('opportunity');
162
            $budgetAmount = MultiCurrency::create(mt_rand(10, 10000), 'USD');
163
            $closeRevenue = MultiCurrency::create(mt_rand(10, 10000), 'USD');
164
            $salesFlowItem = $this->workflowManager->startWorkflow(
165
                'opportunity_flow',
166
                $opportunity,
167
                '__start__',
168
                [
169
                    'budget_amount'     => $budgetAmount,
170
                    'customer_need'     => mt_rand(10, 10000),
171
                    'proposed_solution' => mt_rand(10, 10000),
172
                    'probability'       => round(mt_rand(50, 85) / 100.00, 2)
173
                ]
174
            );
175
176
            if ($this->getRandomBoolean()) {
177
                if ($this->getRandomBoolean()) {
178
                    $this->transit(
179
                        $this->workflowManager,
180
                        $salesFlowItem,
181
                        'close_won',
182
                        [
183
                            'close_revenue' => $closeRevenue,
184
                            'close_date'    => new \DateTime('now'),
185
                        ]
186
                    );
187
                } else {
188
                    $this->transit(
189
                        $this->workflowManager,
190
                        $salesFlowItem,
191
                        'close_lost',
192
                        [
193
                            'close_reason_name' => 'cancelled',
194
                            'close_revenue'     => $closeRevenue,
195
                            'close_date'        => new \DateTime('now'),
196
                        ]
197
                    );
198
                }
199
            }
200
        }
201
    }
202
203
    /**
204
     * @return bool
205
     */
206
    protected function getRandomBoolean()
207
    {
208
        return (bool)mt_rand(0, 1);
209
    }
210
211
    /**
212
     * @param User $user
213
     */
214 View Code Duplication
    protected function setSecurityContext($user)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
215
    {
216
        $securityContext = $this->container->get('security.context');
217
        $token           = new UsernamePasswordOrganizationToken($user, $user->getUsername(
218
        ), 'main', $this->organization);
219
        $securityContext->setToken($token);
220
    }
221
222
    /**
223
     * @param ObjectManager $manager
224
     * @param  array $data
225
     * @param User $user
226
     *
227
     * @return Lead
228
     */
229
    protected function createLead(ObjectManager $manager, array $data, $user)
230
    {
231
        $lead = new Lead();
232
        
233
        $className = ExtendHelper::buildEnumValueClassName(Lead::INTERNAL_STATUS_CODE);
234
        $defaultStatus = $manager->getRepository($className)->find(ExtendHelper::buildEnumValueId('new'));
235
        
236
        $lead->setStatus($defaultStatus);
237
        $lead->setName($data['Company']);
238
        $lead->setFirstName($data['GivenName']);
239
        $lead->setLastName($data['Surname']);
240
241
        $leadEmail = new LeadEmail($data['EmailAddress']);
242
        $leadEmail->setPrimary(true);
243
        $lead->addEmail($leadEmail);
244
245
        $leadPhone = new LeadPhone($data['TelephoneNumber']);
246
        $leadPhone->setPrimary(true);
247
        $lead->addPhone($leadPhone);
248
249
        $lead->setCompanyName($data['Company']);
250
        $lead->setOwner($user);
251
        $lead->setDataChannel($this->channel);
252
        /** @var LeadAddress $address */
253
        $address = new LeadAddress();
254
        $address->setLabel('Primary Address');
255
        $address->setCity($data['City']);
256
        $address->setStreet($data['StreetAddress']);
257
        $address->setPostalCode($data['ZipCode']);
258
        $address->setFirstName($data['GivenName']);
259
        $address->setLastName($data['Surname']);
260
261
        $isoCode = $data['Country'];
262
        $country = array_filter(
263
            $this->countries,
264
            function (Country $a) use ($isoCode) {
265
                return $a->getIso2Code() == $isoCode;
266
            }
267
        );
268
269
        $country = array_values($country);
270
        /** @var Country $country */
271
        $country = $country[0];
272
273
        $idRegion = $data['State'];
274
        /** @var Collection $regions */
275
        $regions = $country->getRegions();
276
277
        $region = $regions->filter(
278
            function (Region $a) use ($idRegion) {
279
                return $a->getCode() == $idRegion;
280
            }
281
        );
282
283
        $address->setCountry($country);
284
        if (!$region->isEmpty()) {
285
            $address->setRegion($region->first());
286
        }
287
288
        $lead->addAddress($address);
289
290
        $countSources = count($this->sources) - 1;
291
        $source       = $this->sources[mt_rand(0, $countSources)];
292
        $lead->setSource($source);
293
294
        return $lead;
295
    }
296
297
    /**
298
     * @param WorkflowManager $workflowManager
299
     * @param WorkflowItem    $workflowItem
300
     * @param string          $transition
301
     * @param array           $data
302
     */
303
    protected function transit($workflowManager, $workflowItem, $transition, array $data)
304
    {
305
        foreach ($data as $key => $value) {
306
            $workflowItem->getData()->set($key, $value);
307
        }
308
309
        $workflow = $workflowManager->getWorkflow($workflowItem);
310
311
        $workflow->transit($workflowItem, $transition);
312
        $workflowItem->setUpdated();
313
    }
314
315
    public function getOrder()
316
    {
317
        return 300;
318
    }
319
}
320