Completed
Pull Request — master (#162)
by
unknown
03:18
created

PerformanceEventAdmin   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 417
Duplicated Lines 18.47 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 83.51%

Importance

Changes 0
Metric Value
dl 77
loc 417
ccs 157
cts 188
cp 0.8351
rs 8.3999
c 0
b 0
f 0
wmc 46
lcom 1
cbo 10

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A configureRoutes() 0 7 1
B configureFormFields() 0 81 3
A configureListFields() 13 13 1
A configureDatagridFilters() 0 7 1
B preUpdate() 0 19 5
A postUpdate() 0 14 4
A getEm() 0 7 2
A enableTicketsForSale() 0 14 1
A inspectPriceCategories() 0 14 3
B getRows() 11 16 5
B getPlaces() 11 19 6
B getSeat() 41 44 6
B inspectSeatMoreThanOnePrice() 0 22 4
A inspectSeatWithoutPrice() 0 22 3

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like PerformanceEventAdmin often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PerformanceEventAdmin, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace AppBundle\Admin;
4
5
use AppBundle\Entity\PerformanceEvent;
6
use AppBundle\Entity\PriceCategory;
7
use AppBundle\Entity\RowsForSale;
8
use AppBundle\Entity\Seat;
9
use AppBundle\Entity\Ticket;
10
use AppBundle\Entity\Venue;
11
use AppBundle\Entity\VenueSector;
12
use AppBundle\Services\Ticket\GenerateSetHandler;
13
use Doctrine\ORM\EntityManager;
14
use Sonata\AdminBundle\Admin\Admin;
15
use Sonata\AdminBundle\Datagrid\ListMapper;
16
use Sonata\AdminBundle\Exception\ModelManagerException;
17
use Sonata\AdminBundle\Form\FormMapper;
18
use Sonata\AdminBundle\Route\RouteCollection;
19
use Symfony\Component\Form\Extension\Core\Type\TextType;
20
use Sonata\AdminBundle\Datagrid\DatagridMapper;
21
22
/**
23
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
24
 */
25
class PerformanceEventAdmin extends Admin
26
{
27
    protected $baseRouteName = 'AppBundle\Entity\PerformanceEvent';
28
    protected $baseRoutePattern = 'PerformanceEvent';
29
    protected $datagridValues = [
30
        '_sort_order' => 'DESC',
31
        '_sort_by'    => 'dateTime',
32
    ];
33
    protected $seatPrice = [];
34
35
    /** @var GenerateSetHandler */
36
    protected $ticketGenerateSet;
37
38
    /**
39
     * PerformanceEventAdmin constructor.
40
     * @param string $code
41
     * @param string $class
42
     * @param string $baseControllerName
43
     * @param GenerateSetHandler $ticketGenerateSet
44
     */
45 31
    public function __construct($code, $class, $baseControllerName, GenerateSetHandler $ticketGenerateSet)
46
    {
47 31
        parent::__construct($code, $class, $baseControllerName);
48 31
        $this->ticketGenerateSet = $ticketGenerateSet;
49 31
    }
50
51
    /**
52
     * @var EntityManager
53
     */
54
    protected $em;
55
56
    /**
57
     * @param RouteCollection $collection
58
     */
59 2
    protected function configureRoutes(RouteCollection $collection)
60
    {
61
        $collection
62 2
            ->add('getVenue')
63 2
            ->add('deletePriceCategories')
64
        ;
65 2
    }
66
67
    /**
68
     * @param FormMapper $formMapper
69
     *
70
     * @return void
71
     */
72 1
    protected function configureFormFields(FormMapper $formMapper)
73
    {
74 1
        $queryRowsForSale = $this->getEm()->getRepository(RowsForSale::class)
75 1
            ->findVenueSectorsByPerformanceEventQueryBuilder($this->getSubject());
76
77
        $formMapper
78 1
            ->with('PerformanceEvents')
79 1
            ->add('performance', 'sonata_type_model')
80 1
            ->add(
81 1
                'dateTime',
82 1
                'sonata_type_datetime_picker',
83
                [
84 1
                    'dp_side_by_side'       => true,
85
                    'dp_use_current'        => false,
86
                    'dp_use_seconds'        => false,
87
                    'format' => "dd/MM/yyyy HH:mm",
88
                ]
89
            )
90 1
            ->add('venue')
91 1
            ->end()
92 1
            ->with('PriceCategory')
93 1
            ->add('priceCategories', 'sonata_type_collection', [
94 1
                'by_reference' => true,
95
                'required' => false,
96
                'cascade_validation' => true,
97
                'type_options'       => [
98
                    'delete' => true,
99
                ],
100
                'label' => false,
101
            ], [
102 1
                'inline'  => 'table',
103 1
                'edit' => 'inline',
104 1
                'sortable' => 'position',
105
                'link_parameters'       => [
106 1
                    'performanceEvent_id' => $this->getSubject()->getId(),
107
                ],
108
            ])
109 1
            ->end()
110 1
            ->with('EnableSale')
111 1
            ->add('seriesDate', 'sonata_type_datetime_picker', [
112 1
                'dp_side_by_side'       => true,
113
                'dp_use_current'        => true,
114
                'dp_use_seconds'        => false,
115
                'format' => "dd/MM/yyyy HH:mm",
116
                'required' => true,
117
            ])
118 1
            ->add('rowsForSale', 'sonata_type_model', [
119 1
                'class' => RowsForSale::class,
120
                'required' => false,
121
                'multiple' => true,
122 1
                'query' => $queryRowsForSale,
123
            ])
124
        ;
125 1
        if ($this->getSubject()->isEnableSale() !== true) {
126
            $formMapper
127 1
                ->add('seriesNumber', null, [
128 1
                    'required' => true,
129
                ])
130 1
                ->add('sale', 'checkbox', [
131 1
                    'required' => false,
132
                    'label' => 'Enable Sale',
133
                ])
134 1
                ->end()
135
            ;
136
        }
137 1
        if ($this->getSubject()->isEnableSale()) {
138
            $formMapper
139
                ->add('seriesNumber', null, [
140
                    'required' => true,
141
                    'attr' => ['class' => 'hidden'],
142
                    'label' => false,
143
                ])
144
                ->add('enableSale', TextType::class, [
145
                    'required' => false,
146
                    'attr' => ['class' => 'hidden'],
147
                    'label' => false,
148
                ])
149
                ->end()
150
            ;
151
        }
152 1
    }
153
154
    /**
155
     * @param ListMapper $listMapper
156
     *
157
     * @return void
158
     */
159 2 View Code Duplication
    protected function configureListFields(ListMapper $listMapper)
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...
160
    {
161
        $listMapper
162 2
            ->add('performance')
163 2
            ->add('dateTime')
164 2
            ->add('venue')
165 2
            ->add('_action', 'actions', [
166 2
                'actions' => [
167
                    'edit' => [],
168
                    'delete' => [],
169
                ],
170
            ]);
171 2
    }
172
173
    /**
174
     * @param DatagridMapper $datagridMapper
175
     *
176
     * @return void
177
     */
178 2
    protected function configureDatagridFilters(DatagridMapper $datagridMapper)
179
    {
180
        $datagridMapper
181 2
            ->add('performance')
182 2
            ->add('venue')
183
        ;
184 2
    }
185
186 1
    public function preUpdate($object)
187
    {
188 1
        $this->seatPrice = [];
189 1
        if (!self::inspectPriceCategories($object)) {
190
            return null;
191
        }
192 1
        if ($object->isEnableSale() === null) {
193 1
            $object->setEnableSale(false);
194 1
            $this->getEm()->persist($object);
195
        }
196 1
        if (($object->isEnableSale() === false) && ($object->isSale() === true)) {
197
            /** @var Ticket[] $tickets */
198
            $tickets = $this->ticketGenerateSet->handle($object);
199
            $this->getEm()->getRepository(Ticket::class)->batchSave($tickets);
200
            $object->setEnableSale(true);
201
            $this->getEm()->persist($object);
202
        }
203 1
        return true;
204
    }
205
206 1
    public function postUpdate($object)
207
    {
208 1
        $this->seatPrice = [];
209 1
        if (!self::inspectPriceCategories($object)) {
210
            return null;
211
        }
212 1
        if (!self::inspectSeatWithoutPrice($object->getVenue())) {
213
            return null;
214
        }
215 1
        if ($object->isEnableSale()) {
216
            self::enableTicketsForSale($object);
217
        }
218 1
        return true;
219
    }
220
221 4
    public function getEm()
222
    {
223 4
        if (!$this->em) {
224 4
            $this->em = $this->getConfigurationPool()->getContainer()->get('Doctrine')->getManager();
225
        }
226 4
        return $this->em;
227
    }
228
229
    /**
230
     * Change Status in Ticket
231
     * form STATUS_OFFLINE to STATUS_FREE if Ticket is in RowsForSale
232
     * and vice versa
233
     *
234
     * @param PerformanceEvent $performanceEvent
235
     * @return int
236
     */
237 1
    public function enableTicketsForSale(PerformanceEvent $performanceEvent)
238
    {
239 1
        $count = $this->getEm()->getRepository(Ticket::class)->enableTicketsForSale($performanceEvent);
240
            $this
241 1
                ->getConfigurationPool()
242 1
                ->getContainer()
243 1
                ->get('session')
244 1
                ->getFlashBag()
245 1
                ->add(
246 1
                    'success',
247 1
                    "До продажу вiдкрито $count квиткiв!"
248
                );
249 1
        return $count;
250
    }
251
252
    /**
253
     * Inspect PriceCategory. Search errors
254
     *
255
     * @param PerformanceEvent $performanceEvent
256
     * @return bool
257
     */
258 1
    public function inspectPriceCategories(PerformanceEvent $performanceEvent)
259
    {
260 1
        $categories = $this->getEm()->getRepository('AppBundle:PriceCategory')
261 1
            ->findBy(['performanceEvent' => $performanceEvent]);
262 1
        $venue = $performanceEvent->getVenue();
263
        /** @var PriceCategory $category*/
264 1
        foreach ($categories as $category) {
265 1
            self::getRows($venue, $category->getRows(), $category->getVenueSector(), $category->getPlaces());
266
        }
267 1
        if (!$categories) {
268
            return false;
269
        }
270 1
        return true;
271
    }
272
273
    /**
274
     * Parse string rows in PriceCategory
275
     *
276
     * @param Venue $venue
277
     * @param $strRows
278
     * @param VenueSector $venueSector
279
     * @param $strPlaces
280
     * @return bool|null
281
     */
282 2
    public function getRows(Venue $venue, $strRows, VenueSector $venueSector, $strPlaces = null)
283
    {
284 2
        $dataRows = explode(',', $strRows);
285 2 View Code Duplication
        foreach ($dataRows as $rows) {
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...
286 2
            if (substr_count($rows, '-') === 1) {
287 2
                list($begin, $end) = explode('-', $rows);
288 2
                for ($row = $begin; $row <= $end; $row++) {
289 2
                    self::getPlaces($venue, $row, $venueSector, $strPlaces);
290
                }
291
            }
292 2
            if (substr_count($rows, '-') === 0) {
293 1
                self::getPlaces($venue, $rows, $venueSector, $strPlaces);
294
            }
295
        }
296 2
        return true;
297
    }
298
299
    /**
300
     * Parse string places in PriceCategory
301
     *
302
     * @param Venue $venue
303
     * @param $row
304
     * @param VenueSector $venueSector
305
     * @param $strPlaces
306
     */
307 2
    public function getPlaces(Venue $venue, $row, VenueSector $venueSector, $strPlaces = null)
308
    {
309 2
        if ($strPlaces === null) {
310 2
            self::getSeat($venue, $row, $venueSector);
311 2
            return;
312
        }
313 1
        $dataPlaces = explode(',', $strPlaces);
314 1 View Code Duplication
        foreach ($dataPlaces as $places) {
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...
315 1
            if (substr_count($places, '-') === 1) {
316 1
                list($begin, $end) = explode('-', $places);
317 1
                for ($place = $begin; $place <= $end; $place++) {
318 1
                    self::getSeat($venue, $row, $venueSector, $place);
319
                }
320
            }
321 1
            if (substr_count($places, '-') === 0) {
322 1
                self::getSeat($venue, $row, $venueSector, $places);
323
            }
324
        }
325 1
    }
326
327
    /**
328
     * Research existing Seat with row-place - $row-$place
329
     *
330
     * @param Venue $venue
331
     * @param $row
332
     * @param VenueSector $venueSector
333
     * @param null $place
334
     * @throws ModelManagerException
335
     */
336 2
    public function getSeat(Venue $venue, $row, VenueSector $venueSector, $place = null)
337
    {
338 2 View Code Duplication
        if ($place === null) {
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...
339 2
            $seat = $this->getEm()->getRepository('AppBundle:Seat')->findBy([
340 2
                'row' => $row,
341 2
                'venueSector' => $venueSector,
342
            ]);
343 2
            if (!$seat) {
344
                $this
345 1
                    ->getConfigurationPool()
346 1
                    ->getContainer()
347 1
                    ->get('session')
348 1
                    ->getFlashBag()
349 1
                    ->add(
350 1
                        'error',
351 1
                        "Помилка. В залi $venue немає $row ряда в секторі $venueSector!"
352
                    );
353 1
                throw new ModelManagerException('Error row!');
354
            }
355 2
            foreach ($seat as $placeAllInRow) {
356 2
                self::inspectSeatMoreThanOnePrice($row, $placeAllInRow->getPlace(), $venueSector);
357
            }
358
        }
359 2 View Code Duplication
        if ($place !== null) {
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...
360 1
            $seat = $this->getEm()->getRepository('AppBundle:Seat')->findOneBy([
361 1
                'row' => $row,
362 1
                'place' => $place,
363 1
                'venueSector' => $venueSector,
364
            ]);
365 1
            if (!$seat) {
366
                $this
367 1
                    ->getConfigurationPool()
368 1
                    ->getContainer()
369 1
                    ->get('session')
370 1
                    ->getFlashBag()
371 1
                    ->add(
372 1
                        'error',
373 1
                        "Помилка. В залi $venue немає $row - $place в секторі $venueSector!"
374
                    );
375 1
                throw new ModelManagerException('Error row-place!');
376
            }
377 1
            self::inspectSeatMoreThanOnePrice($row, $place, $venueSector);
378
        }
379 2
    }
380
381
    /**
382
     * Search Seat with more than one price
383
     *
384
     * @param $row
385
     * @param $place
386
     * @param VenueSector $venueSector
387
     * @throws ModelManagerException
388
     */
389 2
    public function inspectSeatMoreThanOnePrice($row, $place, VenueSector $venueSector)
390
    {
391 2
        $seats = $this->seatPrice;
392 2
        foreach ($this->seatPrice as $sector => $key) {
393 2
            if ($sector === $venueSector->getId()) {
394 2
                if ($key === $row.'-'.$place) {
395
                    $this
396
                        ->getConfigurationPool()
397
                        ->getContainer()
398
                        ->get('session')
399
                        ->getFlashBag()
400
                        ->add(
401
                            'error',
402
                            "Помилка. $row - $place в секторі $venueSector вже має цiну!"
403
                        );
404
                    throw new ModelManagerException('Error Seat with more than one price!');
405
                }
406
            }
407
        }
408 2
        $seats[$venueSector->getId()][] = $row.'-'.$place;
409 2
        $this->seatPrice = $seats;
410 2
    }
411
412
    /**
413
     * Search Seat without price
414
     *
415
     * @param Venue $venue
416
     * @return bool
417
     * @throws ModelManagerException
418
     */
419 2
    public function inspectSeatWithoutPrice(Venue $venue)
420
    {
421 2
        foreach ($this->seatPrice as $sector => $key) {
422 1
            $venueSector = $this->getEm()->getRepository(VenueSector::class)->find($sector);
423 1
            $seat = $this->getEm()->getRepository(Seat::class)->findBy(['venueSector' => $venueSector]);
424 1
            if (count($seat) != count($key)) {
425
                $this
426
                    ->getConfigurationPool()
427
                    ->getContainer()
428
                    ->get('session')
429
                    ->getFlashBag()
430
                    ->add(
431
                        'error',
432
                        "Помилка. В залі 
433
                        $venue в секторі 
434
                        $venueSector ціна проставлена не на всі місця!"
435
                    );
436
                throw new ModelManagerException('In the hall not all places have price!');
437
            }
438
        }
439 2
        return true;
440
    }
441
}
442