Completed
Push — master ( e25006...247fc7 )
by WEBEWEB
01:30
created

handleDataTablesException()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.8333
c 0
b 0
f 0
cc 2
nc 2
nop 2
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 Doctrine\ORM\EntityRepository;
16
use Exception;
17
use Symfony\Component\EventDispatcher\Event;
18
use Symfony\Component\HttpFoundation\JsonResponse;
19
use Symfony\Component\HttpFoundation\Request;
20
use Symfony\Component\HttpFoundation\Response;
21
use Symfony\Component\Serializer\Encoder\JsonEncoder;
22
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
23
use Symfony\Component\Serializer\Serializer;
24
use WBW\Bundle\BootstrapBundle\Controller\AbstractController;
25
use WBW\Bundle\JQuery\DataTablesBundle\API\DataTablesColumnInterface;
26
use WBW\Bundle\JQuery\DataTablesBundle\API\DataTablesWrapperInterface;
27
use WBW\Bundle\JQuery\DataTablesBundle\Event\DataTablesEvent;
28
use WBW\Bundle\JQuery\DataTablesBundle\Event\DataTablesEvents;
29
use WBW\Bundle\JQuery\DataTablesBundle\Exception\BadDataTablesColumnException;
30
use WBW\Bundle\JQuery\DataTablesBundle\Exception\BadDataTablesCSVExporterException;
31
use WBW\Bundle\JQuery\DataTablesBundle\Exception\BadDataTablesEditorException;
32
use WBW\Bundle\JQuery\DataTablesBundle\Exception\BadDataTablesRepositoryException;
33
use WBW\Bundle\JQuery\DataTablesBundle\Exception\UnregisteredDataTablesProviderException;
34
use WBW\Bundle\JQuery\DataTablesBundle\Factory\DataTablesFactory;
35
use WBW\Bundle\JQuery\DataTablesBundle\Manager\DataTablesManager;
36
use WBW\Bundle\JQuery\DataTablesBundle\Provider\DataTablesCSVExporterInterface;
37
use WBW\Bundle\JQuery\DataTablesBundle\Provider\DataTablesEditorInterface;
38
use WBW\Bundle\JQuery\DataTablesBundle\Provider\DataTablesProviderInterface;
39
use WBW\Bundle\JQuery\DataTablesBundle\Repository\DataTablesRepositoryInterface;
40
use WBW\Library\Core\Database\PaginateHelper;
41
use WBW\Library\Core\Model\Response\ActionResponse;
42
43
/**
44
 * Abstract jQuery DataTables controller.
45
 *
46
 * @author webeweb <https://github.com/webeweb/>
47
 * @package WBW\Bundle\JQuery\DataTablesBundle\Controller
48
 * @abstract
49
 */
50
abstract class AbstractDataTablesController extends AbstractController {
51
52
    /**
53
     * Build a response.
54
     *
55
     * @param Request $request The request.
56
     * @param string $name The provider name.
57
     * @param ActionResponse $output The output.
58
     * @return Response Returns the response.
59
     */
60
    protected function buildDataTablesResponse(Request $request, $name, ActionResponse $output) {
61
62
        // Determines if the request is an XML HTTP request.
63
        if (true === $request->isXmlHttpRequest()) {
64
65
            // Return the response.
66
            return new JsonResponse($output);
67
        }
68
69
        // Notify the user.
70
        switch ($output->getStatus()) {
71
72
            case 200:
73
                $this->notifySuccess($output->getNotify());
74
                break;
75
76
            case 404:
77
                $this->notifyDanger($output->getNotify());
78
                break;
79
80
            case 500:
81
                $this->notifyWarning($output->getNotify());
82
                break;
83
        }
84
85
        // Return the response.
86
        return $this->redirectToRoute("jquery_datatables_index", ["name" => $name]);
87
    }
88
89
    /**
90
     * Dispatch an event.
91
     *
92
     * @param string $eventName The event name.
93
     * @param array $entities The entities.
94
     * @return Event Returns the event in case of succes, null otherwise.
95
     */
96
    protected function dispatchDataTablesEvent($eventName, array $entities) {
97
98
        // Get and check the event dispatcher.
99
        $eventDispatcher = $this->getEventDispatcher();
100
        if (null !== $eventDispatcher && false === $eventDispatcher->hasListeners($eventName)) {
101
            return null;
102
        }
103
104
        // Log a debug trace.
105
        $this->getLogger()->debug(sprintf("DataTables controller dispatch a DataTables event with name \"%s\"", $eventName));
106
107
        // Dispatch the event.
108
        return $eventDispatcher->dispatch($eventName, new DataTablesEvent($eventName, $entities));
109
    }
110
111
    /**
112
     * Export callback.
113
     *
114
     * @param DataTablesProviderInterface $dtProvider The provider.
115
     * @param DataTablesRepositoryInterface $repository The repository.
116
     * @param DataTablesCSVExporterInterface $dtExporter The exporter.
117
     * @return void
118
     */
119
    protected function exportCallback(DataTablesProviderInterface $dtProvider, DataTablesRepositoryInterface $repository, DataTablesCSVExporterInterface $dtExporter) {
120
121
        // Get the entities manager.
122
        $em = $this->getDoctrine()->getManager();
123
124
        // Open the file.
125
        $stream = fopen("php://output", "w+");
126
127
        // Export the columns.
128
        fputcsv($stream, $dtExporter->exportColumns(), ";");
129
130
        // Paginates.
131
        $total = $repository->dataTablesCountExported($dtProvider);
132
        $pages = PaginateHelper::getPagesCount($total, DataTablesRepositoryInterface::REPOSITORY_LIMIT);
133
134
        // Handle each page.
135
        for ($i = 0; $i < $pages; ++$i) {
136
137
            // Get the offset and limit.
138
            list($offset, $limit) = PaginateHelper::getPageOffsetAndLimit($i, DataTablesRepositoryInterface::REPOSITORY_LIMIT, $total);
139
140
            // Get the export query with offset and limit.
141
            $result = $repository->dataTablesExportAll($dtProvider)
142
                ->setFirstResult($offset)
143
                ->setMaxResults($limit)
144
                ->getQuery()
145
                ->iterate();
146
147
            // Handle each entity.
148
            while (false !== ($row = $result->next())) {
149
150
                // Dispatch an event.
151
                $this->dispatchDataTablesEvent(DataTablesEvents::DATATABLES_PRE_EXPORT, [$row[0]]);
152
153
                // Export the entity.
154
                fputcsv($stream, $dtExporter->exportRow($row[0]), ";");
155
156
                // Detach the entity to avoid memory consumption.
157
                $em->detach($row[0]);
158
159
                // Dispatch an event.
160
                $this->dispatchDataTablesEvent(DataTablesEvents::DATATABLES_PRE_EXPORT, [$row[0]]);
161
            }
162
        }
163
164
        // Close the file.
165
        fclose($stream);
166
    }
167
168
    /**
169
     * Get a column.
170
     *
171
     * @param DataTablesProviderInterface $dtProvider The provider.
172
     * @param string $data The data.
173
     * @return DataTablesColumnInterface Returns the column.
174
     * @throws BadDataTablesColumnException Throws a bad column exception.
175
     */
176
    protected function getDataTablesColumn(DataTablesProviderInterface $dtProvider, $data) {
177
178
        // Get the column.
179
        $dtColumn = $this->getDataTablesWrapper($dtProvider)->getColumn($data);
180
181
        // Log a debug trace.
182
        $this->getLogger()->debug(sprintf("DataTables controller search for a column with name \"%s\"", $data));
183
184
        // Check the column.
185
        if (null === $dtColumn) {
186
            throw new BadDataTablesColumnException($data);
187
        }
188
189
        // Log a debug trace.
190
        $this->getLogger()->debug(sprintf("DataTables controller found a column with name \"%s\"", $data));
191
192
        // Return the column.
193
        return $dtColumn;
194
    }
195
196
    /**
197
     * Get a CSV exporter.
198
     *
199
     * @param DataTablesProviderInterface $dtProvider The provider.
200
     * @return DataTablesCSVExporterInterface Returns the CSV exporter.
201
     * @throws UnregisteredDataTablesProviderException Throws an unregistered provider exception.
202
     * @throws BadDataTablesCSVExporterException Throws a bad CSV exporter exception.
203
     */
204
    protected function getDataTablesCSVExporter(DataTablesProviderInterface $dtProvider) {
205
206
        // Get the provider.
207
        $dtExporter = $dtProvider->getCSVExporter();
208
209
        // Log a debug trace.
210
        $this->getLogger()->debug(sprintf("DataTables controller search for a CSV exporter with name \"%s\"", $dtProvider->getName()));
211
212
        // Check the CSV exporter.
213
        if (false === ($dtExporter instanceOf DataTablesCSVExporterInterface)) {
214
            throw new BadDataTablesCSVExporterException($dtExporter);
215
        }
216
217
        // Log a debug trace.
218
        $this->getLogger()->debug(sprintf("DataTables controller found a CSV exporter with name \"%s\"", $dtProvider->getName()));
219
220
        // Return the exporter.
221
        return $dtExporter;
222
    }
223
224
    /**
225
     * Get an editor.
226
     *
227
     * @param DataTablesProviderInterface $dtProvider The provider.
228
     * @return DataTablesEditorInterface Returns the editor.
229
     * @throws UnregisteredDataTablesProviderException Throws an unregistered provider exception.
230
     * @throws BadDataTablesEditorException Throws a bad editor exception.
231
     */
232
    protected function getDataTablesEditor(DataTablesProviderInterface $dtProvider) {
233
234
        // Get the editor.
235
        $dtEditor = $dtProvider->getEditor();
236
237
        // Log a debug trace.
238
        $this->getLogger()->debug(sprintf("DataTables controller search for an editor with name \"%s\"", $dtProvider->getName()));
239
240
        // Check the CSV exporter.
241
        if (false === ($dtEditor instanceOf DataTablesEditorInterface)) {
242
            throw new BadDataTablesEditorException($dtEditor);
243
        }
244
245
        // Log a debug trace.
246
        $this->getLogger()->debug(sprintf("DataTables controller found an editor with name \"%s\"", $dtProvider->getName()));
247
248
        // Return the exporter.
249
        return $dtEditor;
250
    }
251
252
    /**
253
     * Get an entity by id.
254
     *
255
     * @param DataTablesProviderInterface $dtProvider The provider.
256
     * @param int $id The entity id.
257
     * @return object Returns the entity.
258
     * @throws BadDataTablesRepositoryException Throws a bad repository exception.
259
     * @throws EntityNotFoundException Throws an Entity not found exception.
260
     */
261
    protected function getDataTablesEntityById(DataTablesProviderInterface $dtProvider, $id) {
262
263
        // Get the repository.
264
        $repository = $this->getDataTablesRepository($dtProvider);
265
266
        // Log a debug trace.
267
        $this->getLogger()->debug(sprintf("DataTables controller search for an entity [%s]", $id));
268
269
        // Find and check the entity.
270
        $entity = $repository->find($id);
271
        if (null === $entity) {
272
            throw EntityNotFoundException::fromClassNameAndIdentifier($dtProvider->getEntity(), [$id]);
273
        }
274
275
        // Log a debug trace.
276
        $this->getLogger()->debug(sprintf("DataTables controller found an entity [%s]", $id));
277
278
        // Return the entity.
279
        return $entity;
280
    }
281
282
    /**
283
     * Get the manager.
284
     *
285
     * @return DataTablesManager Returns the manager.
286
     */
287
    protected function getDataTablesManager() {
288
        return $this->get(DataTablesManager::SERVICE_NAME);
289
    }
290
291
    /**
292
     * Get the provider.
293
     *
294
     * @param string $name The provider name.
295
     * @return DataTablesProviderInterface Returns the provider.
296
     * @throws UnregisteredDataTablesProviderException Throws an unregistered provider exception.
297
     */
298
    protected function getDataTablesProvider($name) {
299
300
        // Log a debug trace.
301
        $this->getLogger()->debug(sprintf("DataTables controller search for a provider with name \"%s\"", $name));
302
303
        // Get the provider.
304
        $dtProvider = $this->getDataTablesManager()->getProvider($name);
305
306
        // Log a debug trace.
307
        $this->getLogger()->debug(sprintf("DataTables controller found a provider with name \"%s\"", $name));
308
309
        // Return the provider.
310
        return $dtProvider;
311
    }
312
313
    /**
314
     * Get a repository.
315
     *
316
     * @param DataTablesProviderInterface $dtProvider The provider.
317
     * @return EntityRepository Returns the repository.
318
     * @throws BadDataTablesRepositoryException Throws a bad repository exception.
319
     */
320
    protected function getDataTablesRepository(DataTablesProviderInterface $dtProvider) {
321
322
        // Log a debug trace.
323
        $this->getLogger()->debug(sprintf("DataTables controller search for a repository with name \"%s\"", $dtProvider->getName()));
324
325
        // Get the entities manager.
326
        $em = $this->getDoctrine()->getManager();
327
328
        // Get and check the entities repository.
329
        $repository = $em->getRepository($dtProvider->getEntity());
330
        if (false === ($repository instanceOf DataTablesRepositoryInterface)) {
331
            throw new BadDataTablesRepositoryException($repository);
332
        }
333
334
        // Return the repository.
335
        return $repository;
336
    }
337
338
    /**
339
     * Get a serializer.
340
     *
341
     * @return Serializer Returns the serializer.
342
     */
343
    protected function getDataTablesSerializer() {
344
        return new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
345
    }
346
347
    /**
348
     * Get a wrapper.
349
     *
350
     * @param DataTablesProviderInterface $dtProvider The provider.
351
     * @return DataTablesWrapperInterface Returns the wrapper.
352
     */
353
    protected function getDataTablesWrapper(DataTablesProviderInterface $dtProvider) {
354
355
        // Initialize the URL.
356
        $url = $this->getRouter()->generate("jquery_datatables_index", ["name" => $dtProvider->getName()]);
357
358
        // Initialize the wrapper.
359
        $dtWrapper = DataTablesFactory::newWrapper($url, $dtProvider);
360
361
        // Handle each column.
362
        foreach ($dtProvider->getColumns() as $dtColumn) {
363
364
            // Log a debug trace.
365
            $this->getLogger()->debug(sprintf("DataTables provider add a column \"%s\"", $dtColumn->getData()));
366
367
            // Add the column.
368
            $dtWrapper->addColumn($dtColumn);
369
        }
370
371
        // Set the options.
372
        if (null !== $dtProvider->getOptions()) {
373
            $dtWrapper->setOptions($dtProvider->getOptions());
374
        }
375
376
        // Return the wrapper.
377
        return $dtWrapper;
378
    }
379
380
    /**
381
     * Get the notification.
382
     *
383
     * @param string $id The notification id.
384
     * @return string Returns the notification.
385
     */
386
    protected function getNotification($id) {
387
        return $this->getTranslator()->trans($id, [], "JQueryDataTablesBundle");
388
    }
389
390
    /**
391
     * Handle a DataTables exception.
392
     *
393
     * @param Exception $ex The exception.
394
     * @param string $notificationBaseId The notification base id.
395
     * @return ActionResponse Returns the action response.
396
     */
397
    protected function handleDataTablesException(Exception $ex, $notificationBaseId) {
398
399
        // Log a debug trace.
400
        $this->getLogger()->debug($ex->getMessage());
401
402
        // Check the exception.
403
        if (true === ($ex instanceof EntityNotFoundException)) {
404
            return $this->prepareActionResponse(404, $notificationBaseId . ".danger");
405
        }
406
407
        // Return a default action response.
408
        return $this->prepareActionResponse(500, $notificationBaseId . ".warning");
409
    }
410
411
    /**
412
     * Prepare an action response.
413
     *
414
     * @param int $status The status.
415
     * @param string $notify The notify.
416
     * @return ActionResponse Returns the action response.
417
     */
418
    protected function prepareActionResponse($status, $notify) {
419
420
        // Initialize the action response.
421
        $response = new ActionResponse();
422
        $response->setStatus($status);
423
        $response->setNotify($this->getNotification($notify));
424
425
        // Return the action response.
426
        return $response;
427
    }
428
429
}
430