From 74a2689174a4785b877277b5237c8bd6de1af8c3 Mon Sep 17 00:00:00 2001 From: Marco Wansinck Date: Thu, 24 May 2018 12:34:32 +0200 Subject: [PATCH 1/9] Added missing dev requirements to composer.json --- composer.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/composer.json b/composer.json index 47f05e07..0cb093ce 100644 --- a/composer.json +++ b/composer.json @@ -25,6 +25,14 @@ "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" + }, "autoload": { "psr-4": { "Sg\\DatatablesBundle\\": "" } } From 2a407e3ce23d1225fb4e5a9e13dee0d98ea75ff6 Mon Sep 17 00:00:00 2001 From: Marco Wansinck Date: Thu, 24 May 2018 12:36:40 +0200 Subject: [PATCH 2/9] Pass the container to the Factory so datatables and columns can be a service (optional) --- Datatable/AbstractDatatable.php | 4 ++++ Datatable/Column/AbstractColumn.php | 14 ++++++++++++++ Datatable/Column/ColumnBuilder.php | 5 ++++- Datatable/Column/EditableTrait.php | 5 ++++- Datatable/Column/FilterableTrait.php | 5 ++++- Datatable/DatatableFactory.php | 10 ++++++++++ Datatable/Factory.php | 10 ++++++++-- Resources/config/services.yml | 2 ++ 8 files changed, 50 insertions(+), 5 deletions(-) diff --git a/Datatable/AbstractDatatable.php b/Datatable/AbstractDatatable.php index 7b0c9e71..eaa7591b 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; @@ -149,6 +150,7 @@ abstract class AbstractDatatable implements DatatableInterface /** * AbstractDatatable constructor. * + * @param ContainerInterface $container * @param AuthorizationCheckerInterface $authorizationChecker * @param TokenStorageInterface $securityToken * @param TranslatorInterface $translator @@ -159,6 +161,7 @@ abstract class AbstractDatatable implements DatatableInterface * @throws Exception */ public function __construct( + ContainerInterface $container, AuthorizationCheckerInterface $authorizationChecker, TokenStorageInterface $securityToken, TranslatorInterface $translator, @@ -178,6 +181,7 @@ public function __construct( $metadata = $em->getClassMetadata($this->getEntity()); $this->columnBuilder = new ColumnBuilder($metadata, $twig, $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 7da35c1c..ce609ebd 100644 --- a/Datatable/Column/AbstractColumn.php +++ b/Datatable/Column/AbstractColumn.php @@ -15,6 +15,8 @@ use Sg\DatatablesBundle\Datatable\AddIfTrait; use Sg\DatatablesBundle\Datatable\Editable\EditableInterface; +use Symfony\Component\DependencyInjection\ContainerAwareTrait; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Doctrine\DBAL\Types\Type as DoctrineType; use Doctrine\ORM\Mapping\ClassMetadataInfo; @@ -28,6 +30,8 @@ */ abstract class AbstractColumn implements ColumnInterface { + use ContainerAwareTrait; + /** * Use the OptionsResolver. */ @@ -295,6 +299,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/ColumnBuilder.php b/Datatable/Column/ColumnBuilder.php index 44b7a191..c25959e4 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 Twig_Environment; use Exception; @@ -26,6 +27,8 @@ */ class ColumnBuilder { + use ContainerAwareTrait; + /** * The class metadata. * @@ -124,7 +127,7 @@ public function __construct(ClassMetadata $metadata, Twig_Environment $twig, $da */ 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..53e505ea 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 @@ -23,6 +24,8 @@ */ trait EditableTrait { + use ContainerAwareTrait; + /** * An EditableInterface instance. * Default: null @@ -68,7 +71,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..966a3f4d 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 @@ -23,6 +24,8 @@ */ trait FilterableTrait { + use ContainerAwareTrait; + /** * A FilterInterface instance for individual filtering. * Default: See the column type. @@ -67,7 +70,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/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'] ] From 8fbf8ad7885e004caf47a5e0bc27b59bda509609 Mon Sep 17 00:00:00 2001 From: Marco Wansinck Date: Fri, 25 May 2018 21:11:44 +0200 Subject: [PATCH 3/9] Added missing composer dev dependency --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 0cb093ce..99815534 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,6 @@ "php": ">=5.5.9", "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" }, @@ -31,7 +30,8 @@ "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" + "twig/twig": "^1.0|^2.0", + "symfony/options-resolver": "^4.0" }, "autoload": { "psr-4": { "Sg\\DatatablesBundle\\": "" } From 28fefd04fc874182d23f9d01b4c4bb4540e1fce7 Mon Sep 17 00:00:00 2001 From: Marco Wansinck Date: Fri, 25 May 2018 21:12:46 +0200 Subject: [PATCH 4/9] Added missing throws --- Datatable/OptionsTrait.php | 1 + 1 file changed, 1 insertion(+) 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) { From 6caf48d06055971fe84eb04df89080fd17b49eff Mon Sep 17 00:00:00 2001 From: Marco Wansinck Date: Tue, 29 May 2018 10:36:01 +0200 Subject: [PATCH 5/9] Removed ContainerAwareTrait (conflicts) --- Datatable/Column/AbstractColumn.php | 9 +++++---- Datatable/Column/Column.php | 3 +++ Datatable/Column/EditableTrait.php | 2 -- Datatable/Column/FilterableTrait.php | 2 -- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Datatable/Column/AbstractColumn.php b/Datatable/Column/AbstractColumn.php index ce609ebd..74879176 100644 --- a/Datatable/Column/AbstractColumn.php +++ b/Datatable/Column/AbstractColumn.php @@ -14,8 +14,6 @@ use Sg\DatatablesBundle\Datatable\OptionsTrait; use Sg\DatatablesBundle\Datatable\AddIfTrait; use Sg\DatatablesBundle\Datatable\Editable\EditableInterface; - -use Symfony\Component\DependencyInjection\ContainerAwareTrait; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Doctrine\DBAL\Types\Type as DoctrineType; @@ -30,8 +28,6 @@ */ abstract class AbstractColumn implements ColumnInterface { - use ContainerAwareTrait; - /** * Use the OptionsResolver. */ @@ -75,6 +71,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 diff --git a/Datatable/Column/Column.php b/Datatable/Column/Column.php index 3a535fa5..b7e131b4 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/EditableTrait.php b/Datatable/Column/EditableTrait.php index 53e505ea..c479b948 100644 --- a/Datatable/Column/EditableTrait.php +++ b/Datatable/Column/EditableTrait.php @@ -24,8 +24,6 @@ */ trait EditableTrait { - use ContainerAwareTrait; - /** * An EditableInterface instance. * Default: null diff --git a/Datatable/Column/FilterableTrait.php b/Datatable/Column/FilterableTrait.php index 966a3f4d..14a30fd2 100644 --- a/Datatable/Column/FilterableTrait.php +++ b/Datatable/Column/FilterableTrait.php @@ -24,8 +24,6 @@ */ trait FilterableTrait { - use ContainerAwareTrait; - /** * A FilterInterface instance for individual filtering. * Default: See the column type. From fc28fe39bcd631552c30d9e8f1757d2b8f7e4dd0 Mon Sep 17 00:00:00 2001 From: Marco Wansinck Date: Tue, 29 May 2018 10:37:03 +0200 Subject: [PATCH 6/9] Added more_entropy to uniqid --- Datatable/AbstractDatatable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Datatable/AbstractDatatable.php b/Datatable/AbstractDatatable.php index eaa7591b..e58a1834 100644 --- a/Datatable/AbstractDatatable.php +++ b/Datatable/AbstractDatatable.php @@ -170,7 +170,7 @@ public function __construct( Twig_Environment $twig ) { $this->validateName(); - $this->uniqueName = uniqid($this->getName().'-'); + $this->uniqueName = uniqid($this->getName().'-', true); $this->authorizationChecker = $authorizationChecker; $this->securityToken = $securityToken; From c1c639e2350957ce15f39a2091cf44dd9fd96af8 Mon Sep 17 00:00:00 2001 From: Marco Wansinck Date: Tue, 29 May 2018 15:12:24 +0200 Subject: [PATCH 7/9] Reverted: Added more_entropy to uniqid (again) --- Datatable/AbstractDatatable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Datatable/AbstractDatatable.php b/Datatable/AbstractDatatable.php index e58a1834..1e37610a 100644 --- a/Datatable/AbstractDatatable.php +++ b/Datatable/AbstractDatatable.php @@ -170,7 +170,7 @@ public function __construct( Twig_Environment $twig ) { $this->validateName(); - $this->uniqueName = uniqid($this->getName().'-', true); + $this->uniqueName = uniqid($this->getName().'-', false); $this->authorizationChecker = $authorizationChecker; $this->securityToken = $securityToken; From df158a18376e3c9ed01ec822b0c2521f256f29a7 Mon Sep 17 00:00:00 2001 From: Marco Wansinck Date: Thu, 31 May 2018 15:13:42 +0200 Subject: [PATCH 8/9] Disables the alert when datatable fails to get data --- Resources/views/datatable/datatable_js.html.twig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Resources/views/datatable/datatable_js.html.twig b/Resources/views/datatable/datatable_js.html.twig index 0857e5fe..06368802 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' %} From 5904b8d6abbbc50d48a2d1ffc5e40ce5976ab77b Mon Sep 17 00:00:00 2001 From: darylholling Date: Thu, 11 Jul 2019 14:10:10 +0200 Subject: [PATCH 9/9] Further improvement of pull request 736, now also prefix table name alias uses in joins. --- Response/DatatableQueryBuilder.php | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) 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; }