diff --git a/Datatable/AbstractDatatable.php b/Datatable/AbstractDatatable.php index 51e9390e..a002208a 100644 --- a/Datatable/AbstractDatatable.php +++ b/Datatable/AbstractDatatable.php @@ -13,6 +13,7 @@ use Sg\DatatablesBundle\Datatable\Column\ColumnBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Translation\TranslatorInterface; @@ -158,6 +159,7 @@ abstract class AbstractDatatable implements DatatableInterface /** * AbstractDatatable constructor. * + * @param ContainerInterface $container * @param AuthorizationCheckerInterface $authorizationChecker * @param TokenStorageInterface $securityToken * @param TranslatorInterface $translator @@ -168,6 +170,7 @@ abstract class AbstractDatatable implements DatatableInterface * @throws Exception */ public function __construct( + ContainerInterface $container, AuthorizationCheckerInterface $authorizationChecker, TokenStorageInterface $securityToken, TranslatorInterface $translator, @@ -192,6 +195,7 @@ public function __construct( $metadata = $em->getClassMetadata($this->getEntity()); $this->columnBuilder = new ColumnBuilder($metadata, $twig, $router, $this->getName(), $em); + $this->columnBuilder->setContainer($container); $this->ajax = new Ajax(); $this->options = new Options(); diff --git a/Datatable/Column/AbstractColumn.php b/Datatable/Column/AbstractColumn.php index 00497fb4..c827a8f9 100644 --- a/Datatable/Column/AbstractColumn.php +++ b/Datatable/Column/AbstractColumn.php @@ -14,7 +14,7 @@ use Sg\DatatablesBundle\Datatable\OptionsTrait; use Sg\DatatablesBundle\Datatable\AddIfTrait; use Sg\DatatablesBundle\Datatable\Editable\EditableInterface; - +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Routing\RouterInterface; use Doctrine\DBAL\Types\Type as DoctrineType; @@ -72,6 +72,11 @@ abstract class AbstractColumn implements ColumnInterface // pre-assigned with a value (true or false). //-------------------------------------------------------------------------------------------------- + /** + * @var ContainerInterface + */ + protected $container; + /** * Change the cell type created for the column - either TD cells or TH cells. * DataTables default: td @@ -312,6 +317,16 @@ abstract class AbstractColumn implements ColumnInterface //------------------------------------------------- /** + * AbstractColumn constructor. + * @param ContainerInterface $container + */ + public function __construct(ContainerInterface $container) + { + $this->container = $container; + } + + + /** * Config options. * * @param OptionsResolver $resolver diff --git a/Datatable/Column/Column.php b/Datatable/Column/Column.php index 25b45a3a..7be08126 100644 --- a/Datatable/Column/Column.php +++ b/Datatable/Column/Column.php @@ -15,6 +15,7 @@ use Sg\DatatablesBundle\Datatable\Filter\TextFilter; use Sg\DatatablesBundle\Datatable\Editable\EditableInterface; +use Symfony\Component\DependencyInjection\ContainerAwareTrait; use Symfony\Component\OptionsResolver\OptionsResolver; /** @@ -24,6 +25,8 @@ */ class Column extends AbstractColumn { + use ContainerAwareTrait; + /** * The Column is editable. */ diff --git a/Datatable/Column/ColumnBuilder.php b/Datatable/Column/ColumnBuilder.php index 1c218aea..cef13680 100644 --- a/Datatable/Column/ColumnBuilder.php +++ b/Datatable/Column/ColumnBuilder.php @@ -16,6 +16,7 @@ use Doctrine\Common\Persistence\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\MappingException; use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\DependencyInjection\ContainerAwareTrait; use Symfony\Component\Routing\RouterInterface; use Twig_Environment; use Exception; @@ -27,6 +28,8 @@ */ class ColumnBuilder { + use ContainerAwareTrait; + /** * The class metadata. * @@ -134,7 +137,7 @@ public function __construct(ClassMetadata $metadata, Twig_Environment $twig, Rou */ public function add($dql, $class, array $options = array()) { - $column = Factory::create($class, ColumnInterface::class); + $column = Factory::create($this->container, $class, ColumnInterface::class); $column->initOptions(); $this->handleDqlProperties($dql, $options, $column); diff --git a/Datatable/Column/EditableTrait.php b/Datatable/Column/EditableTrait.php index 9538a16b..c479b948 100644 --- a/Datatable/Column/EditableTrait.php +++ b/Datatable/Column/EditableTrait.php @@ -15,6 +15,7 @@ use Sg\DatatablesBundle\Datatable\Factory; use Exception; +use Symfony\Component\DependencyInjection\ContainerAwareTrait; /** * Class EditableTrait @@ -68,7 +69,7 @@ public function setEditable($editableClassAndOptions) throw new Exception('EditableTrait::setEditable(): Set an options array.'); } - $newEditable = Factory::create($editableClassAndOptions[0], EditableInterface::class); + $newEditable = Factory::create($this->container, $editableClassAndOptions[0], EditableInterface::class); $this->editable = $newEditable->set($editableClassAndOptions[1]); } else { $this->editable = $editableClassAndOptions; diff --git a/Datatable/Column/FilterableTrait.php b/Datatable/Column/FilterableTrait.php index 4ee03e68..14a30fd2 100644 --- a/Datatable/Column/FilterableTrait.php +++ b/Datatable/Column/FilterableTrait.php @@ -15,6 +15,7 @@ use Sg\DatatablesBundle\Datatable\Factory; use Exception; +use Symfony\Component\DependencyInjection\ContainerAwareTrait; /** * Class FilterableTrait @@ -67,7 +68,7 @@ public function setFilter(array $filterClassAndOptions) throw new Exception('AbstractColumn::setFilter(): Set an options array.'); } - $newFilter = Factory::create($filterClassAndOptions[0], FilterInterface::class); + $newFilter = Factory::create($this->container, $filterClassAndOptions[0], FilterInterface::class); $this->filter = $newFilter->set($filterClassAndOptions[1]); return $this; diff --git a/Datatable/DatatableFactory.php b/Datatable/DatatableFactory.php index fb011db9..184770e8 100644 --- a/Datatable/DatatableFactory.php +++ b/Datatable/DatatableFactory.php @@ -11,6 +11,7 @@ namespace Sg\DatatablesBundle\Datatable; +use Symfony\Component\DependencyInjection\ContainerAwareTrait; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Translation\TranslatorInterface; @@ -26,6 +27,8 @@ */ class DatatableFactory { + use ContainerAwareTrait; + /** * The AuthorizationChecker service. * @@ -122,6 +125,13 @@ public function create($class) } if (in_array(DatatableInterface::class, class_implements($class))) { + if ($this->container->has($class)) { + /** @var DatatableInterface $datatable */ + $datatable = $this->container->get($class); + + return $datatable; + } + return new $class( $this->authorizationChecker, $this->securityToken, diff --git a/Datatable/Factory.php b/Datatable/Factory.php index 1661bcba..55e12054 100644 --- a/Datatable/Factory.php +++ b/Datatable/Factory.php @@ -12,6 +12,7 @@ namespace Sg\DatatablesBundle\Datatable; use Exception; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Class Factory @@ -23,13 +24,14 @@ class Factory /** * Create. * + * @param ContainerInterface $container * @param mixed $class * @param mixed $interface * * @return mixed * @throws Exception */ - public static function create($class, $interface) + public static function create(ContainerInterface $container, $class, $interface) { if (empty($class) || !is_string($class) && !$class instanceof $interface) { throw new Exception("Factory::create(): String or $interface expected."); @@ -40,7 +42,11 @@ public static function create($class, $interface) } if (is_string($class) && class_exists($class)) { - $instance = new $class(); + if ($container->has($class)) { + $instance = $container->get($class); + } else { + $instance = new $class($container); + } if (!$instance instanceof $interface) { throw new Exception("Factory::create(): String or $interface expected."); diff --git a/Datatable/OptionsTrait.php b/Datatable/OptionsTrait.php index 8e32b171..5d78306e 100644 --- a/Datatable/OptionsTrait.php +++ b/Datatable/OptionsTrait.php @@ -47,6 +47,7 @@ trait OptionsTrait * @param bool $resolve * * @return $this + * @throws Exception */ public function initOptions($resolve = false) { diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 594ca6ea..9d081eb6 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -32,3 +32,5 @@ services: - '@router' - '@doctrine.orm.entity_manager' - '@twig' + calls: + - [ setContainer, ['@service_container'] ] diff --git a/Resources/views/datatable/datatable_js.html.twig b/Resources/views/datatable/datatable_js.html.twig index bfb98dcc..f2f66c14 100644 --- a/Resources/views/datatable/datatable_js.html.twig +++ b/Resources/views/datatable/datatable_js.html.twig @@ -66,6 +66,9 @@ $.extend(defaults, columns); $.extend(defaults, initialSearch); + // Disables the alert when datatable fails to get data + $.fn.dataTable.ext.errMode = 'none'; + if (!$.fn.dataTable.isDataTable(selector)) { $(selector) {% include '@SgDatatables/datatable/events.html.twig' %} diff --git a/Response/DatatableQueryBuilder.php b/Response/DatatableQueryBuilder.php index 4b800783..2b326587 100644 --- a/Response/DatatableQueryBuilder.php +++ b/Response/DatatableQueryBuilder.php @@ -12,6 +12,7 @@ namespace Sg\DatatablesBundle\Response; use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Platforms\Keywords\KeywordList; use Sg\DatatablesBundle\Datatable\Column\ColumnInterface; use Sg\DatatablesBundle\Datatable\Filter\AbstractFilter; use Sg\DatatablesBundle\Datatable\Filter\FilterInterface; @@ -187,6 +188,11 @@ class DatatableQueryBuilder */ private $useCountResultCacheArgs = [false]; + /** + * @var KeywordList + */ + private $reservedKeywordsList; + //------------------------------------------------- // Ctor. && Init column arrays //------------------------------------------------- @@ -204,6 +210,7 @@ public function __construct(array $requestParams, DatatableInterface $datatable) $this->requestParams = $requestParams; $this->em = $datatable->getEntityManager(); + $this->reservedKeywordsList = $this->em->getConnection()->getDatabasePlatform()->getReservedKeywordsList(); $this->entityName = $datatable->getEntity(); $this->metadata = $this->getMetadata($this->entityName); @@ -263,6 +270,14 @@ private function initColumnArrays() $currentPart = array_shift($parts); $currentAlias = ($previousPart === $this->entityShortName ? '' : $previousPart.'_').$currentPart; + try { + $isReservedKeyword = $this->reservedKeywordsList->isKeyword($currentAlias); + } catch (DBALException $exception) { + $isReservedKeyword = false; + } + + $currentAlias = $isReservedKeyword ? "_{$currentAlias}" : $currentAlias; + if (!array_key_exists($previousAlias.'.'.$currentPart, $this->joins)) { $this->addJoin($previousAlias.'.'.$currentPart, $currentAlias, $this->accessor->getValue($column, 'joinType')); } @@ -727,6 +742,14 @@ private function addSearchOrderColumn($column, $columnTableName, $data) */ private function addJoin($columnTableName, $alias, $type) { + try { + $isReservedKeyword = $this->reservedKeywordsList->isKeyword($alias); + } catch (DBALException $exception) { + $isReservedKeyword = false; + } + + $alias = $isReservedKeyword ? "_{$alias}" : $alias; + $this->joins[$columnTableName] = array( 'alias' => $alias, 'type' => $type, @@ -765,9 +788,9 @@ private function getMetadata($entityName) private function getEntityShortName(ClassMetadata $metadata, EntityManagerInterface $entityManager) { $entityShortName = strtolower($metadata->getReflectionClass()->getShortName()); + try { - $reservedKeywordsList = $entityManager->getConnection()->getDatabasePlatform()->getReservedKeywordsList(); - $isReservedKeyword = $reservedKeywordsList->isKeyword($entityShortName); + $isReservedKeyword = $this->reservedKeywordsList->isKeyword($entityShortName); } catch (DBALException $exception) { $isReservedKeyword = false; } diff --git a/composer.json b/composer.json index ba09f919..52848dcb 100644 --- a/composer.json +++ b/composer.json @@ -21,10 +21,18 @@ "php": ">=7.1", "symfony/framework-bundle": "^3.0|^4.0", "doctrine/orm": "^2.5", - "symfony/options-resolver": "^3.0|^4.0", "symfony/property-access": "^3.0|^4.0", "friendsofsymfony/jsrouting-bundle": "^1.6|^2.0" }, + "require-dev": { + "symfony/security-bundle": "^3.0|^4.0", + "symfony/translation": "^3.0|^4.0", + "sensio/framework-extra-bundle": "^3.0|^4.0|^5.0", + "sensio/generator-bundle": "^3.0", + "phpspec/prophecy": "^1.7", + "twig/twig": "^1.0|^2.0", + "symfony/options-resolver": "^4.0" + }, "autoload": { "psr-4": { "Sg\\DatatablesBundle\\": "" } }