Passed
Push — master ( 2d425f...eb03d1 )
by Jan
04:57 queued 10s
created

LogDataTable::configure()   D

Complexity

Conditions 16
Paths 1

Size

Total Lines 157
Code Lines 102

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 0 Features 0
Metric Value
cc 16
eloc 102
c 6
b 0
f 0
nc 1
nop 2
dl 0
loc 157
rs 4.4532

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
4
 *
5
 * Copyright (C) 2019 - 2020 Jan Böhmer (https://github.com/jbtronics)
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Affero General Public License as published
9
 * by the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License
18
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19
 */
20
21
declare(strict_types=1);
22
23
/**
24
 * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
25
 *
26
 * Copyright (C) 2019 - 2020 Jan Böhmer (https://github.com/jbtronics)
27
 *
28
 * This program is free software; you can redistribute it and/or
29
 * modify it under the terms of the GNU General Public License
30
 * as published by the Free Software Foundation; either version 2
31
 * of the License, or (at your option) any later version.
32
 *
33
 * This program is distributed in the hope that it will be useful,
34
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36
 * GNU General Public License for more details.
37
 *
38
 * You should have received a copy of the GNU General Public License
39
 * along with this program; if not, write to the Free Software
40
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
41
 */
42
43
namespace App\DataTables;
44
45
use App\DataTables\Column\IconLinkColumn;
46
use App\DataTables\Column\LocaleDateTimeColumn;
47
use App\DataTables\Column\LogEntryExtraColumn;
48
use App\DataTables\Column\LogEntryTargetColumn;
49
use App\DataTables\Column\RevertLogColumn;
50
use App\Entity\Base\AbstractDBElement;
51
use App\Entity\Contracts\TimeTravelInterface;
52
use App\Entity\LogSystem\AbstractLogEntry;
53
use App\Entity\LogSystem\CollectionElementDeleted;
54
use App\Entity\LogSystem\ElementCreatedLogEntry;
55
use App\Entity\LogSystem\ElementDeletedLogEntry;
56
use App\Entity\LogSystem\ElementEditedLogEntry;
57
use App\Entity\UserSystem\Group;
58
use App\Entity\UserSystem\User;
59
use App\Exceptions\EntityNotSupportedException;
60
use App\Services\ElementTypeNameGenerator;
61
use App\Services\EntityURLGenerator;
62
use Doctrine\ORM\EntityManagerInterface;
63
use Doctrine\ORM\QueryBuilder;
64
use Omines\DataTablesBundle\Adapter\Doctrine\ORMAdapter;
65
use Omines\DataTablesBundle\Column\TextColumn;
66
use Omines\DataTablesBundle\DataTable;
67
use Omines\DataTablesBundle\DataTableTypeInterface;
68
use Psr\Log\LogLevel;
69
use Symfony\Component\OptionsResolver\OptionsResolver;
70
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
71
use Symfony\Component\Security\Core\Security;
72
use Symfony\Contracts\Translation\TranslatorInterface;
73
use Symfony\Flex\Options;
74
75
class LogDataTable implements DataTableTypeInterface
76
{
77
    protected $elementTypeNameGenerator;
78
    protected $translator;
79
    protected $urlGenerator;
80
    protected $entityURLGenerator;
81
    protected $logRepo;
82
    protected $security;
83
84
    public function __construct(ElementTypeNameGenerator $elementTypeNameGenerator, TranslatorInterface $translator,
85
        UrlGeneratorInterface $urlGenerator, EntityURLGenerator $entityURLGenerator, EntityManagerInterface $entityManager, Security $security)
86
    {
87
        $this->elementTypeNameGenerator = $elementTypeNameGenerator;
88
        $this->translator = $translator;
89
        $this->urlGenerator = $urlGenerator;
90
        $this->entityURLGenerator = $entityURLGenerator;
91
        $this->logRepo = $entityManager->getRepository(AbstractLogEntry::class);
92
        $this->security = $security;
93
    }
94
95
    public function configureOptions(OptionsResolver $optionsResolver)
96
    {
97
        $optionsResolver->setDefaults([
98
                                          'mode' => 'system_log',
99
                                          'filter_elements' => [],
100
                                      ]);
101
102
        $optionsResolver->setAllowedValues('mode', ['system_log', 'element_history', 'last_activity']);
103
    }
104
105
    public function configure(DataTable $dataTable, array $options): void
106
    {
107
        $resolver = new OptionsResolver();
108
        $this->configureOptions($resolver);
109
        $options = $resolver->resolve($options);
110
111
112
        $dataTable->add('symbol', TextColumn::class, [
113
            'label' => '',
114
            'render' => function ($value, AbstractLogEntry $context) {
115
                switch ($context->getLevelString()) {
116
                    case LogLevel::DEBUG:
117
                        $symbol = 'fa-bug';
118
119
                        break;
120
                    case LogLevel::INFO:
121
                        $symbol = 'fa-info';
122
123
                        break;
124
                    case LogLevel::NOTICE:
125
                        $symbol = 'fa-flag';
126
127
                        break;
128
                    case LogLevel::WARNING:
129
                        $symbol = 'fa-exclamation-circle';
130
131
                        break;
132
                    case LogLevel::ERROR:
133
                        $symbol = 'fa-exclamation-triangle';
134
135
                        break;
136
                    case LogLevel::CRITICAL:
137
                        $symbol = 'fa-bolt';
138
139
                        break;
140
                    case LogLevel::ALERT:
141
                        $symbol = 'fa-radiation';
142
143
                        break;
144
                    case LogLevel::EMERGENCY:
145
                        $symbol = 'fa-skull-crossbones';
146
147
                        break;
148
                    default:
149
                        $symbol = 'fa-question-circle';
150
151
                        break;
152
                }
153
154
                return sprintf(
155
                    '<i class="fas fa-fw %s" title="%s"></i>',
156
                    $symbol,
157
                    $context->getLevelString()
158
                );
159
            },
160
        ]);
161
162
        $dataTable->add('id', TextColumn::class, [
163
            'label' => $this->translator->trans('log.id'),
164
            'visible' => false,
165
        ]);
166
167
        $dataTable->add('timestamp', LocaleDateTimeColumn::class, [
168
            'label' => $this->translator->trans('log.timestamp'),
169
            'timeFormat' => 'medium',
170
        ]);
171
172
        $dataTable->add('type', TextColumn::class, [
173
            'label' => $this->translator->trans('log.type'),
174
            'propertyPath' => 'type',
175
            'render' => function (string $value, AbstractLogEntry $context) {
0 ignored issues
show
Unused Code introduced by
The parameter $context is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

175
            'render' => function (string $value, /** @scrutinizer ignore-unused */ AbstractLogEntry $context) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
176
                return $this->translator->trans('log.type.'.$value);
177
            },
178
        ]);
179
180
        $dataTable->add('level', TextColumn::class, [
181
            'label' => $this->translator->trans('log.level'),
182
            'visible' => $options['mode'] === 'system_log',
183
            'propertyPath' => 'levelString',
184
            'render' => function (string $value, AbstractLogEntry $context) {
0 ignored issues
show
Unused Code introduced by
The parameter $context is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

184
            'render' => function (string $value, /** @scrutinizer ignore-unused */ AbstractLogEntry $context) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
185
                return $value;
186
            },
187
        ]);
188
189
        $dataTable->add('user', TextColumn::class, [
190
            'label' => $this->translator->trans('log.user'),
191
            'render' => function ($value, AbstractLogEntry $context) {
192
                $user = $context->getUser();
193
194
                return sprintf(
195
                    '<a href="%s">%s</a>',
196
                    $this->urlGenerator->generate('user_info', ['id' => $user->getID()]),
197
                    $user->getFullName(true)
198
                );
199
            },
200
        ]);
201
202
        $dataTable->add('target_type', TextColumn::class, [
203
            'label' => $this->translator->trans('log.target_type'),
204
            'visible' => false,
205
            'render' => function ($value, AbstractLogEntry $context) {
206
                $class = $context->getTargetClass();
207
                if (null !== $class) {
208
                    return $this->elementTypeNameGenerator->getLocalizedTypeLabel($class);
209
                }
210
211
                return '';
212
            },
213
        ]);
214
215
        $dataTable->add('target', LogEntryTargetColumn::class, [
216
            'label' => $this->translator->trans('log.target'),
217
        ]);
218
219
        $dataTable->add('extra', LogEntryExtraColumn::class, [
220
            'label' => $this->translator->trans('log.extra'),
221
        ]);
222
223
        $dataTable->add('timeTravel', IconLinkColumn::class,[
224
            'label' => '',
225
            'icon' => 'fas fa-fw fa-eye',
226
            'href' => function ($value, AbstractLogEntry $context) {
227
                if (
228
                    ($context instanceof TimeTravelInterface
229
                        && $context->hasOldDataInformations())
230
                    || $context instanceof CollectionElementDeleted
231
                ) {
232
                    try {
233
                        $target = $this->logRepo->getTargetElement($context);
234
                        if($target !== null) {
235
                            $str = $this->entityURLGenerator->timeTravelURL($target, $context->getTimestamp());
236
                            return $str;
237
                        }
238
                    } catch (EntityNotSupportedException $exception) {
239
                        return null;
240
                    }
241
                }
242
                return null;
243
            },
244
            'disabled' => function ($value, AbstractLogEntry $context) {
245
                return
246
                    !$this->security->isGranted('@tools.timetravel')
247
                    || !$this->security->isGranted('show_history', $context->getTargetClass());
248
            }
249
250
        ]);
251
252
        $dataTable->add('actionRevert', RevertLogColumn::class, [
253
            'label' => ''
254
        ]);
255
256
        $dataTable->addOrderBy('timestamp', DataTable::SORT_DESCENDING);
257
258
        $dataTable->createAdapter(ORMAdapter::class, [
259
            'entity' => AbstractLogEntry::class,
260
            'query' => function (QueryBuilder $builder) use ($options): void {
261
                $this->getQuery($builder, $options);
262
            },
263
        ]);
264
    }
265
266
    protected function getQuery(QueryBuilder $builder, array $options): void
267
    {
268
        $builder->distinct()->select('log')
269
            ->addSelect('user')
270
            ->from(AbstractLogEntry::class, 'log')
271
            ->leftJoin('log.user', 'user');
272
273
        if ($options['mode'] === 'last_activity') {
274
            $builder->where('log INSTANCE OF ' . ElementCreatedLogEntry::class)
275
                ->orWhere('log INSTANCE OF ' . ElementDeletedLogEntry::class)
276
                ->orWhere('log INSTANCE OF ' . ElementEditedLogEntry::class)
277
                ->orWhere('log INSTANCE OF ' . CollectionElementDeleted::class)
278
                ->andWhere('log.target_type NOT IN (:disallowed)');;
279
280
            $builder->setParameter('disallowed', [
281
                AbstractLogEntry::targetTypeClassToID(User::class),
282
                AbstractLogEntry::targetTypeClassToID(Group::class),
283
            ]);
284
        }
285
286
        if (!empty($options['filter_elements'])) {
287
            foreach ($options['filter_elements'] as $element) {
288
                /** @var AbstractDBElement $element */
289
290
                $target_type = AbstractLogEntry::targetTypeClassToID(get_class($element));
291
                $target_id = $element->getID();
292
                $builder->orWhere("log.target_type = $target_type AND log.target_id = $target_id");
293
            }
294
        }
295
    }
296
}
297