Passed
Push — master ( 857ad5...ffca44 )
by WEBEWEB
03:44
created

AbstractController::getDataTablesManager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 2
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
/*
4
 * This file is part of the jquery-datatables-bundle package.
5
 *
6
 * (c) 2018 WEBEWEB
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace WBW\Bundle\JQuery\DataTablesBundle\Controller;
13
14
use Doctrine\ORM\EntityNotFoundException;
15
use Symfony\Component\HttpFoundation\JsonResponse;
16
use Symfony\Component\HttpFoundation\Request;
17
use Symfony\Component\HttpFoundation\Response;
18
use Throwable;
19
use WBW\Bundle\BootstrapBundle\Controller\AbstractController as BaseController;
20
use WBW\Bundle\JQuery\DataTablesBundle\Api\DataTablesColumnInterface;
21
use WBW\Bundle\JQuery\DataTablesBundle\Api\DataTablesWrapperInterface;
22
use WBW\Bundle\JQuery\DataTablesBundle\Event\DataTablesEvent;
23
use WBW\Bundle\JQuery\DataTablesBundle\Exception\BadDataTablesColumnException;
24
use WBW\Bundle\JQuery\DataTablesBundle\Exception\BadDataTablesCSVExporterException;
25
use WBW\Bundle\JQuery\DataTablesBundle\Exception\BadDataTablesEditorException;
26
use WBW\Bundle\JQuery\DataTablesBundle\Exception\BadDataTablesRepositoryException;
27
use WBW\Bundle\JQuery\DataTablesBundle\Exception\UnregisteredDataTablesProviderException;
28
use WBW\Bundle\JQuery\DataTablesBundle\Factory\DataTablesFactory;
29
use WBW\Bundle\JQuery\DataTablesBundle\Helper\DataTablesExportHelper;
30
use WBW\Bundle\JQuery\DataTablesBundle\Manager\DataTablesManagerTrait;
31
use WBW\Bundle\JQuery\DataTablesBundle\Provider\DataTablesCSVExporterInterface;
32
use WBW\Bundle\JQuery\DataTablesBundle\Provider\DataTablesEditorInterface;
33
use WBW\Bundle\JQuery\DataTablesBundle\Provider\DataTablesProviderInterface;
34
use WBW\Bundle\JQuery\DataTablesBundle\Provider\DataTablesRouterInterface;
35
use WBW\Bundle\JQuery\DataTablesBundle\Repository\DataTablesRepositoryInterface;
36
use WBW\Bundle\JQuery\DataTablesBundle\WBWJQueryDataTablesBundle;
37
use WBW\Library\Database\Helper\PaginateHelper;
38
use WBW\Library\Symfony\Response\SimpleJsonResponseData;
39
use WBW\Library\Symfony\Response\SimpleJsonResponseDataInterface;
40
41
/**
42
 * Abstract controller.
43
 *
44
 * @author webeweb <https://github.com/webeweb>
45
 * @package WBW\Bundle\JQuery\DataTablesBundle\Controller
46
 * @abstract
47
 */
48
abstract class AbstractController extends BaseController {
49
50
    use DataTablesManagerTrait {
51
        setDataTablesManager as public;
52
    }
53
54
    /**
55
     * Build a response.
56
     *
57
     * @param Request $request The request.
58
     * @param string $name The provider name.
59
     * @param SimpleJsonResponseDataInterface $output The output.
60
     * @return Response Returns the response.
61
     * @throws Throwable Throws an exception if an error occurs.
62
     */
63
    protected function buildDataTablesResponse(Request $request, string $name, SimpleJsonResponseDataInterface $output): Response {
64
65
        if (true === $request->isXmlHttpRequest()) {
66
            return new JsonResponse($output);
67
        }
68
69
        switch ($output->getStatus()) {
70
71
            case 200:
72
                $this->notifySuccess($output->getNotify());
0 ignored issues
show
Bug introduced by
It seems like $output->getNotify() can also be of type null; however, parameter $content of WBW\Bundle\BootstrapBund...roller::notifySuccess() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

72
                $this->notifySuccess(/** @scrutinizer ignore-type */ $output->getNotify());
Loading history...
73
                break;
74
75
            case 404:
76
                $this->notifyDanger($output->getNotify());
0 ignored issues
show
Bug introduced by
It seems like $output->getNotify() can also be of type null; however, parameter $content of WBW\Bundle\BootstrapBund...troller::notifyDanger() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

76
                $this->notifyDanger(/** @scrutinizer ignore-type */ $output->getNotify());
Loading history...
77
                break;
78
79
            case 500:
80
                $this->notifyWarning($output->getNotify());
0 ignored issues
show
Bug introduced by
It seems like $output->getNotify() can also be of type null; however, parameter $content of WBW\Bundle\BootstrapBund...roller::notifyWarning() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

80
                $this->notifyWarning(/** @scrutinizer ignore-type */ $output->getNotify());
Loading history...
81
                break;
82
        }
83
84
        return $this->redirectToRoute("wbw_jquery_datatables_index", ["name" => $name]);
85
    }
86
87
    /**
88
     * Dispatch an event.
89
     *
90
     * @param string $eventName The event name.
91
     * @param array $entities The entities.
92
     * @param DataTablesProviderInterface|null $provider The provider.
93
     * @return DataTablesEvent|null Returns the event in case of success, null otherwise.
94
     * @throws Throwable Throws an exception if an error occurs.
95
     */
96
    protected function dispatchDataTablesEvent(string $eventName, array $entities, ?DataTablesProviderInterface $provider = null): ?DataTablesEvent {
97
        return $this->dispatchEvent($eventName, new DataTablesEvent($eventName, $entities, $provider));
98
    }
99
100
    /**
101
     * Export callback.
102
     *
103
     * @param DataTablesProviderInterface $dtProvider The provider.
104
     * @param DataTablesRepositoryInterface $repository The repository.
105
     * @param DataTablesCSVExporterInterface $dtExporter The exporter.
106
     * @param bool $windows Windows ?
107
     * @return void
108
     * @throws Throwable Throws an exception if an error occurs.
109
     */
110
    protected function exportDataTablesCallback(DataTablesProviderInterface $dtProvider, DataTablesRepositoryInterface $repository, DataTablesCSVExporterInterface $dtExporter, bool $windows): void {
111
112
        $stream = fopen("php://output", "w+");
113
        fputcsv($stream, DataTablesExportHelper::convert($dtExporter->exportColumns(), $windows), ";");
114
115
        // Paginates.
116
        $total = $repository->dataTablesCountExported($dtProvider);
117
        $pages = PaginateHelper::getPagesCount($total, DataTablesRepositoryInterface::REPOSITORY_LIMIT);
118
119
        $em = $this->getEntityManager();
120
121
        for ($i = 0; $i < $pages; ++$i) {
122
123
            // Get the offset and limit.
124
            [$offset, $limit] = PaginateHelper::getPageOffsetAndLimit($i, DataTablesRepositoryInterface::REPOSITORY_LIMIT, $total);
125
126
            // Get the export query with offset and limit.
127
            $result = $repository->dataTablesExportAll($dtProvider)
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Query::iterate() has been deprecated. ( Ignorable by Annotation )

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

127
            $result = /** @scrutinizer ignore-deprecated */ $repository->dataTablesExportAll($dtProvider)
Loading history...
128
                ->setFirstResult($offset)
129
                ->setMaxResults($limit)
130
                ->getQuery()
131
                ->iterate();
132
133
            while (false !== ($row = $result->next())) {
134
135
                $this->dispatchDataTablesEvent(DataTablesEvent::PRE_EXPORT, [$row[0]], $dtProvider);
136
137
                fputcsv($stream, DataTablesExportHelper::convert($dtExporter->exportRow($row[0]), $windows), ";");
138
139
                $this->dispatchDataTablesEvent(DataTablesEvent::POST_EXPORT, [$row[0]], $dtProvider);
140
            }
141
142
            $em->clear(); // Detach the entity to avoid memory consumption.
143
        }
144
145
        fclose($stream);
146
    }
147
148
    /**
149
     * Get a CSV exporter.
150
     *
151
     * @param DataTablesProviderInterface $dtProvider The provider.
152
     * @return DataTablesCSVExporterInterface Returns the CSV exporter.
153
     * @throws BadDataTablesCSVExporterException Throws a bad CSV exporter exception.
154
     */
155
    protected function getDataTablesCSVExporter(DataTablesProviderInterface $dtProvider): DataTablesCSVExporterInterface {
156
157
        $context = [
158
            "_controller" => get_class($this),
159
            "_provider"   => get_class($dtProvider),
160
        ];
161
162
        $this->logInfo(sprintf('DataTables controller search for a CSV exporter with name "%s"', $dtProvider->getName()), $context);
163
164
        $dtExporter = $dtProvider->getCSVExporter();
165
        if (false === ($dtExporter instanceof DataTablesCSVExporterInterface)) {
166
            throw new BadDataTablesCSVExporterException($dtExporter);
167
        }
168
169
        $context["_exporter"] = get_class($dtExporter);
170
171
        $this->logInfo(sprintf('DataTables controller found a CSV exporter with name "%s"', $dtProvider->getName()), $context);
172
173
        return $dtExporter;
174
    }
175
176
    /**
177
     * Get a column.
178
     *
179
     * @param DataTablesProviderInterface $dtProvider The provider.
180
     * @param string $data The data.
181
     * @return DataTablesColumnInterface Returns the column.
182
     * @throws BadDataTablesColumnException Throws a bad column exception.
183
     */
184
    protected function getDataTablesColumn(DataTablesProviderInterface $dtProvider, string $data): DataTablesColumnInterface {
185
186
        $dtWrapper = $this->getDataTablesWrapper($dtProvider);
187
188
        $context = [
189
            "_controller" => get_class($this),
190
            "_provider"   => get_class($dtProvider),
191
            "_wrapper"    => get_class($dtWrapper),
192
        ];
193
194
        $this->logInfo(sprintf('DataTables controller search for a column with name "%s"', $data), $context);
195
196
        $dtColumn = $dtWrapper->getColumn($data);
197
        if (null === $dtColumn) {
198
            throw new BadDataTablesColumnException($data);
199
        }
200
201
        $context["_column"] = get_class($dtColumn);
202
203
        $this->logInfo(sprintf('DataTables controller found a column with name "%s"', $data), $context);
204
205
        return $dtColumn;
206
    }
207
208
    /**
209
     * Get an editor.
210
     *
211
     * @param DataTablesProviderInterface $dtProvider The provider.
212
     * @return DataTablesEditorInterface Returns the editor.
213
     * @throws BadDataTablesEditorException Throws a bad editor exception.
214
     */
215
    protected function getDataTablesEditor(DataTablesProviderInterface $dtProvider): DataTablesEditorInterface {
216
217
        $context = [
218
            "_controller" => get_class($this),
219
            "_provider"   => get_class($dtProvider),
220
        ];
221
222
        $this->logInfo(sprintf('DataTables controller search for an editor with name "%s"', $dtProvider->getName()), $context);
223
224
        $dtEditor = $dtProvider->getEditor();
225
        if (false === ($dtEditor instanceof DataTablesEditorInterface)) {
226
            throw new BadDataTablesEditorException($dtEditor);
227
        }
228
229
        $context["_editor"] = get_class($dtEditor);
230
231
        $this->logInfo(sprintf('DataTables controller found an editor with name "%s"', $dtProvider->getName()), $context);
232
233
        return $dtEditor;
234
    }
235
236
    /**
237
     * Get an entity by id.
238
     *
239
     * @param DataTablesProviderInterface $dtProvider The provider.
240
     * @param string $id The entity id.
241
     * @return object Returns the entity.
242
     * @throws BadDataTablesRepositoryException Throws a bad repository exception.
243
     * @throws EntityNotFoundException Throws an Entity not found exception.
244
     */
245
    protected function getDataTablesEntityById(DataTablesProviderInterface $dtProvider, string $id) {
246
247
        $repository = $this->getDataTablesRepository($dtProvider);
248
249
        $context = [
250
            "_controller" => get_class($this),
251
            "_provider"   => get_class($dtProvider),
252
            "_repository" => get_class($repository),
253
        ];
254
255
        $this->logInfo(sprintf("DataTables controller search for an entity with id [%s]", $id), $context);
256
257
        $entity = $repository->find($id);
0 ignored issues
show
Bug introduced by
The method find() does not exist on WBW\Bundle\JQuery\DataTa...blesRepositoryInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to WBW\Bundle\JQuery\DataTa...blesRepositoryInterface. ( Ignorable by Annotation )

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

257
        /** @scrutinizer ignore-call */ 
258
        $entity = $repository->find($id);
Loading history...
258
        if (null === $entity) {
259
            throw EntityNotFoundException::fromClassNameAndIdentifier($dtProvider->getEntity(), [$id]);
260
        }
261
262
        $context["_entity"] = get_class($entity);
263
264
        $this->logInfo(sprintf("DataTables controller found an entity with id [%s]", $id), $context);
265
266
        return $entity;
267
    }
268
269
    /**
270
     * Get the provider.
271
     *
272
     * @param string $name The provider name.
273
     * @return DataTablesProviderInterface Returns the provider.
274
     * @throws UnregisteredDataTablesProviderException Throws an unregistered provider exception.
275
     */
276
    protected function getDataTablesProvider(string $name): DataTablesProviderInterface {
277
278
        $dtManager = $this->getDataTablesManager();
279
280
        $context = [
281
            "_controller" => get_class($this),
282
            "_manager"    => get_class($dtManager),
0 ignored issues
show
Bug introduced by
It seems like $dtManager can also be of type null; however, parameter $object of get_class() does only seem to accept object, maybe add an additional type check? ( Ignorable by Annotation )

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

282
            "_manager"    => get_class(/** @scrutinizer ignore-type */ $dtManager),
Loading history...
283
        ];
284
285
        $this->logInfo(sprintf('DataTables controller search for a provider with name "%s"', $name), $context);
286
287
        $dtProvider = $dtManager->getProvider($name);
288
289
        $context["_provider"] = get_class($dtProvider);
290
291
        $this->logInfo(sprintf('DataTables controller found a provider with name "%s"', $name), $context);
292
293
        return $dtProvider;
294
    }
295
296
    /**
297
     * Get a repository.
298
     *
299
     * @param DataTablesProviderInterface $dtProvider The provider.
300
     * @return DataTablesRepositoryInterface Returns the repository.
301
     * @throws Throwable Throws an exception if an error occurs.
302
     * @throws BadDataTablesRepositoryException Throws a bad repository exception.
303
     */
304
    protected function getDataTablesRepository(DataTablesProviderInterface $dtProvider): DataTablesRepositoryInterface {
305
306
        $em = $this->getEntityManager();
307
308
        $context = [
309
            "_controller" => get_class($this),
310
            "_provider"   => get_class($dtProvider),
311
            "_entity"     => $dtProvider->getEntity(),
312
        ];
313
314
        $this->logInfo(sprintf('DataTables controller search for a repository with name "%s"', $dtProvider->getName()), $context);
315
316
        $repository = $em->getRepository($dtProvider->getEntity());
317
        if (false === ($repository instanceof DataTablesRepositoryInterface)) {
318
            throw new BadDataTablesRepositoryException($repository);
319
        }
320
321
        $context["_repository"] = get_class($repository);
322
323
        $this->logInfo(sprintf('DataTables controller found a repository with name "%s"', $dtProvider->getName()), $context);
324
325
        /** @var DataTablesRepositoryInterface $repository */
326
        return $repository;
327
    }
328
329
    /**
330
     * Get a URL.
331
     *
332
     * @param DataTablesProviderInterface $dtProvider The provider.
333
     * @return string Returns the URL.
334
     * @throws Throwable Throws an exception if an error occurs.
335
     */
336
    protected function getDataTablesUrl(DataTablesProviderInterface $dtProvider): string {
337
338
        $context = [
339
            "_controller" => get_class($this),
340
            "_provider"   => get_class($dtProvider),
341
        ];
342
343
        $this->logInfo(sprintf('DataTables controller search for an URL with name "%s"', $dtProvider->getName()), $context);
344
345
        if (true === ($dtProvider instanceof DataTablesRouterInterface)) {
346
            $url = $dtProvider->getUrl();
347
        } else {
348
            $url = $this->getRouter()->generate("wbw_jquery_datatables_index", ["name" => $dtProvider->getName()]);
349
        }
350
351
        $context["_url"] = $url;
352
353
        $this->logInfo(sprintf('DataTables controller found for an URL with name "%s"', $dtProvider->getName()), $context);
354
355
        return $url;
356
    }
357
358
    /**
359
     * Get a wrapper.
360
     *
361
     * @param DataTablesProviderInterface $dtProvider The provider.
362
     * @return DataTablesWrapperInterface Returns the wrapper.
363
     * @throws Throwable Throws an exception if an error occurs.
364
     */
365
    protected function getDataTablesWrapper(DataTablesProviderInterface $dtProvider): DataTablesWrapperInterface {
366
367
        $dtWrapper = DataTablesFactory::newWrapper($this->getDataTablesUrl($dtProvider), $dtProvider, $this->getKernelEventListener()->getUser());
368
369
        $context = [
370
            "_controller" => get_class($this),
371
            "_provider"   => get_class($dtProvider),
372
            "_wrapper"    => get_class($dtWrapper),
373
        ];
374
375
        foreach ($dtProvider->getColumns() as $dtColumn) {
376
377
            $this->logInfo(sprintf('DataTables controller add a column "%s" with the provider "%s"', $dtColumn->getData(), $dtProvider->getName()), $context);
378
379
            $dtWrapper->addColumn($dtColumn);
380
        }
381
382
        if (null !== $dtProvider->getOptions()) {
383
            $dtWrapper->setOptions($dtProvider->getOptions());
384
        }
385
386
        return $dtWrapper;
387
    }
388
389
    /**
390
     * Handle an exception.
391
     *
392
     * @param Throwable $ex The exception.
393
     * @param string $notificationBaseId The notification base id.
394
     * @return SimpleJsonResponseDataInterface Returns the action response.
395
     */
396
    protected function handleDataTablesException(Throwable $ex, string $notificationBaseId): SimpleJsonResponseDataInterface {
397
398
        $this->logInfo($ex->getMessage());
399
400
        if (true === ($ex instanceof EntityNotFoundException)) {
401
            return $this->prepareActionResponse(404, $notificationBaseId . ".danger");
402
        }
403
404
        return $this->prepareActionResponse(500, $notificationBaseId . ".warning");
405
    }
406
407
    /**
408
     * Log an info.
409
     *
410
     * @param string $message The message.
411
     * @param array $context The context.
412
     * @return AbstractController Returns this controller.
413
     * @throws Throwable Throws an exception if an error occurs.
414
     */
415
    protected function logInfo(string $message, array $context = []): AbstractController {
416
        $this->getLogger()->info($message, $context);
417
        return $this;
418
    }
419
420
    /**
421
     * Prepare an action response.
422
     *
423
     * @param int $status The status.
424
     * @param string $notificationId The notification id.
425
     * @return SimpleJsonResponseDataInterface Returns the action response.
426
     * @throws Throwable Throws an exception if an error occurs.
427
     */
428
    protected function prepareActionResponse(int $status, string $notificationId): SimpleJsonResponseDataInterface {
429
430
        $notify = $this->getTranslator()->trans($notificationId, [], WBWJQueryDataTablesBundle::getTranslationDomain());
431
432
        $response = new SimpleJsonResponseData();
433
        $response->setStatus($status);
434
        $response->setNotify($notify);
435
436
        return $response;
437
    }
438
}
439