Completed
Push — master ( 28be56...359087 )
by Serhii
13:20
created

PerformanceEventAdmin   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 385
Duplicated Lines 20 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 77
loc 385
ccs 19
cts 19
cp 1
rs 8.3673
c 0
b 0
f 0
wmc 45
lcom 1
cbo 7

13 Methods

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

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