From 81220f6a0a61428d2c8c37736f6e73dc8d416204 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 30 Jun 2018 10:58:56 +0200 Subject: [PATCH 01/22] Added compatibility with symfony 3 --- Datatables/DatatableManager.php | 9 +++++++-- composer.json | 6 +++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Datatables/DatatableManager.php b/Datatables/DatatableManager.php index b7edf4f..95556f7 100755 --- a/Datatables/DatatableManager.php +++ b/Datatables/DatatableManager.php @@ -50,19 +50,24 @@ protected function getClassName($className) { */ public function getDatatable($class) { + $symfony_version = \Symfony\Component\HttpKernel\Kernel::VERSION; + $request = $symfony_version >= 3 + ? $this->container->get('request_stack')->getCurrentRequest()->query->all() + : $this->container->get('request')->query->all(); + $class = $this->getClassName($class); $metadata = $this->doctrine->getManager()->getClassMetadata($class); $repository = $this->doctrine->getRepository($class); $datatable = new Datatable( - $this->container->get('request')->query->all(), + $request, $this->doctrine->getRepository($class), $this->doctrine->getManager()->getClassMetadata($class), $this->doctrine->getManager(), $this->container->get('lankit_datatables.serializer') ); - return $datatable->useDoctrinePaginator($this->useDoctrinePaginator); + return $datatable->useDoctrinePaginator($this->useDoctrinePaginator); } } diff --git a/composer.json b/composer.json index bb1ee71..b26b2f8 100755 --- a/composer.json +++ b/composer.json @@ -11,9 +11,9 @@ } ], "require": { - "symfony/framework-bundle": "~2.0", - "doctrine/orm": "~2.0", - "doctrine/doctrine-bundle": "~1.0" + "symfony/framework-bundle": "~2.0|~3.0", + "doctrine/orm": "~2.0|~2.4", + "doctrine/doctrine-bundle": "~1.0|~1.4" }, "suggest": { "jms/serializer-bundle": "Advanced JSON encoding capabilities, recommended." From 88c8f4315ae0bedaddeeae2f1d140d9da6894ab2 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 30 Jun 2018 11:32:23 +0200 Subject: [PATCH 02/22] Added changes. --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index b26b2f8..573a46b 100755 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { - "name": "lankit/datatables-bundle", + "name": "Tejadong/datatables-bundle", "description": "DataTables.js server-side processing for Doctrine Entities", - "keywords": ["LanKitDatatables","LanKit","DataTables"], + "keywords": ["TejadongDatatables","Tejadong","DataTables"], "type": "symfony-bundle", "license": "MIT", "authors": [ @@ -19,7 +19,7 @@ "jms/serializer-bundle": "Advanced JSON encoding capabilities, recommended." }, "autoload": { - "psr-0": { "LanKit\\DatatablesBundle": "" } + "psr-0": { "Tejadong\\DatatablesBundle": "" } }, "target-dir": "LanKit/DatatablesBundle" } From 2ec6c95f78f5cc0f805abc251e1189ba1fe5380a Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 30 Jun 2018 11:35:16 +0200 Subject: [PATCH 03/22] Added changes. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 573a46b..8df2da3 100755 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "Tejadong/datatables-bundle", + "name": "tejadong/datatables-bundle", "description": "DataTables.js server-side processing for Doctrine Entities", "keywords": ["TejadongDatatables","Tejadong","DataTables"], "type": "symfony-bundle", From 902935f85d91bfb738d5ea94012ae80b382177ea Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 30 Jun 2018 11:40:56 +0200 Subject: [PATCH 04/22] Fix error in composer.json --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 8df2da3..832bfb3 100755 --- a/composer.json +++ b/composer.json @@ -11,9 +11,9 @@ } ], "require": { - "symfony/framework-bundle": "~2.0|~3.0", - "doctrine/orm": "~2.0|~2.4", - "doctrine/doctrine-bundle": "~1.0|~1.4" + "symfony/framework-bundle": "~2.0||~3.0", + "doctrine/orm": "~2.0||~2.4", + "doctrine/doctrine-bundle": "~1.0||~1.4" }, "suggest": { "jms/serializer-bundle": "Advanced JSON encoding capabilities, recommended." From 5e21b80e277ba983a87bde0f898feef3b71d1e37 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 30 Jun 2018 11:47:25 +0200 Subject: [PATCH 05/22] Changing version in dependencies. --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 832bfb3..5de81e5 100755 --- a/composer.json +++ b/composer.json @@ -11,9 +11,9 @@ } ], "require": { - "symfony/framework-bundle": "~2.0||~3.0", - "doctrine/orm": "~2.0||~2.4", - "doctrine/doctrine-bundle": "~1.0||~1.4" + "symfony/framework-bundle": "~3.0", + "doctrine/orm": "~2.4", + "doctrine/doctrine-bundle": "~1.4" }, "suggest": { "jms/serializer-bundle": "Advanced JSON encoding capabilities, recommended." From 0b823a5b6261339edeec5765b5dee15660905b61 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 30 Jun 2018 12:01:20 +0200 Subject: [PATCH 06/22] Added require symfony/finder. --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 5de81e5..9071d58 100755 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ } ], "require": { + "symfony/finder ": "~2.0", "symfony/framework-bundle": "~3.0", "doctrine/orm": "~2.4", "doctrine/doctrine-bundle": "~1.4" From 93b7991dccef773cf1d0a90d30e96b1ce547fa7b Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 30 Jun 2018 12:07:40 +0200 Subject: [PATCH 07/22] Trying fixes --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index 9071d58..5de81e5 100755 --- a/composer.json +++ b/composer.json @@ -11,7 +11,6 @@ } ], "require": { - "symfony/finder ": "~2.0", "symfony/framework-bundle": "~3.0", "doctrine/orm": "~2.4", "doctrine/doctrine-bundle": "~1.4" From 4d50c399f8d7905a0eee43f6b45ad149c9a5aad0 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 30 Jun 2018 12:18:39 +0200 Subject: [PATCH 08/22] Trying fixes --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 5de81e5..832bfb3 100755 --- a/composer.json +++ b/composer.json @@ -11,9 +11,9 @@ } ], "require": { - "symfony/framework-bundle": "~3.0", - "doctrine/orm": "~2.4", - "doctrine/doctrine-bundle": "~1.4" + "symfony/framework-bundle": "~2.0||~3.0", + "doctrine/orm": "~2.0||~2.4", + "doctrine/doctrine-bundle": "~1.0||~1.4" }, "suggest": { "jms/serializer-bundle": "Advanced JSON encoding capabilities, recommended." From e7baa661fb73de01b97f754982a209ddd9740cea Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 30 Jun 2018 13:10:33 +0200 Subject: [PATCH 09/22] Changed all references called "Lankit" to "Tejadong". --- Datatables/Datatable.php | 2 +- Datatables/DatatableManager.php | 4 +-- DependencyInjection/Configuration.php | 4 +-- ...on.php => TejadongDatatablesExtension.php} | 8 ++--- LanKitDatatablesBundle.php | 14 -------- README.md | 6 ++-- Resources/config/services.xml | 4 +-- Resources/doc/index.md | 33 ++++++++++--------- TejadongDatatablesBundle.php | 14 ++++++++ composer.json | 8 +++-- 10 files changed, 51 insertions(+), 46 deletions(-) rename DependencyInjection/{LanKitDatatablesExtension.php => TejadongDatatablesExtension.php} (84%) mode change 100755 => 100644 delete mode 100755 LanKitDatatablesBundle.php create mode 100644 TejadongDatatablesBundle.php diff --git a/Datatables/Datatable.php b/Datatables/Datatable.php index a65fdf1..b8f16ae 100755 --- a/Datatables/Datatable.php +++ b/Datatables/Datatable.php @@ -22,7 +22,7 @@ * built off of, see: https://gist.github.com/1638094 */ -namespace LanKit\DatatablesBundle\Datatables; +namespace Tejadong\DatatablesBundle\Datatables; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Mapping\ClassMetadata; diff --git a/Datatables/DatatableManager.php b/Datatables/DatatableManager.php index 95556f7..d2e22cc 100755 --- a/Datatables/DatatableManager.php +++ b/Datatables/DatatableManager.php @@ -1,6 +1,6 @@ doctrine->getRepository($class), $this->doctrine->getManager()->getClassMetadata($class), $this->doctrine->getManager(), - $this->container->get('lankit_datatables.serializer') + $this->container->get('tejadong_datatables.serializer') ); return $datatable->useDoctrinePaginator($this->useDoctrinePaginator); } diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 443b3f2..313f4fa 100755 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -1,6 +1,6 @@ root('lankit_datatables'); + $rootNode = $treeBuilder->root('tejadong_datatables'); $rootNode ->children() diff --git a/DependencyInjection/LanKitDatatablesExtension.php b/DependencyInjection/TejadongDatatablesExtension.php old mode 100755 new mode 100644 similarity index 84% rename from DependencyInjection/LanKitDatatablesExtension.php rename to DependencyInjection/TejadongDatatablesExtension.php index 9c08ec3..636c8b7 --- a/DependencyInjection/LanKitDatatablesExtension.php +++ b/DependencyInjection/TejadongDatatablesExtension.php @@ -1,6 +1,6 @@ setAlias($this->getAlias() . '.' . $key, $service); } - $container->getDefinition('lankit_datatables') + $container->getDefinition('tejadong_datatables') ->replaceArgument(2, $config['datatable']['use_doctrine_paginator']); } @@ -38,6 +38,6 @@ public function load(array $configs, ContainerBuilder $container) */ public function getAlias() { - return 'lankit_datatables'; + return 'tejadong_datatables'; } } diff --git a/LanKitDatatablesBundle.php b/LanKitDatatablesBundle.php deleted file mode 100755 index 48579ef..0000000 --- a/LanKitDatatablesBundle.php +++ /dev/null @@ -1,14 +0,0 @@ - - LanKit\DatatablesBundle\Datatables\DatatableManager + Tejadong\DatatablesBundle\Datatables\DatatableManager - + diff --git a/Resources/doc/index.md b/Resources/doc/index.md index 1077e2a..78aef11 100755 --- a/Resources/doc/index.md +++ b/Resources/doc/index.md @@ -1,5 +1,6 @@ -Getting Started With LanKitDatatablesBundle +Getting Started With TejadongDatatablesBundle =========================================== +*¡¡Attention!!, This bundle is a copy adapted to add compatibility with Symfony 3, the real repository belongs to [LanKit/DatatablesBundle](https://github.com/LanKit/DatatablesBundle).* * [Prerequisites](#prerequisites) * [Installation](#installation) @@ -46,21 +47,21 @@ serializer service in your config file... ```yml // app/config.yml -lankit_datatables: +tejadong_datatables: services: serializer: some_other_serializer # Defaults to jms_serializer.serializer ``` ## Installation -### Step 1: Download LanKitDatatablesBundle using composer +### Step 1: Download TejadongDatatablesBundle using composer -Add LanKitDatatablesBundle to your composer.json: +Add TejadongDatatablesBundle to your composer.json: ```js { "require": { - "lankit/datatables-bundle": "*" + "tejadong/datatables-bundle": "*" } } ``` @@ -68,7 +69,7 @@ Add LanKitDatatablesBundle to your composer.json: Use composer to download the bundle using the following command: ``` bash -$ php composer.phar update lankit/datatables-bundle +$ php composer.phar update tejadong/datatables-bundle ``` ### Step 2: Enable the bundle @@ -83,7 +84,7 @@ public function registerBundles() { $bundles = array( // ... - new LanKit\DatatablesBundle\LanKitDatatablesBundle(), + new Tejadong\DatatablesBundle\TejadongDatatablesBundle(), ); } ``` @@ -96,7 +97,7 @@ To respond to a DataTables.js request from a controller, you can do the followin public function getDatatableAction() { - $datatable = $this->get('lankit_datatables')->getDatatable('AcmeDemoBundle:Customer'); + $datatable = $this->get('tejadong_datatables')->getDatatable('AcmeDemoBundle:Customer'); return $datatable->getSearchResults(); } @@ -108,12 +109,12 @@ By default an entity association is inner joined. This can be changed as a defau can be set on a per columm basis: ``` php -use LanKit\DatatablesBundle\Datatables\DataTable; +use Tejadong\DatatablesBundle\Datatables\DataTable; ... public function getDatatableAction() { - $datatable = $this->get('lankit_datatables')->getDatatable('AcmeDemoBundle:Customer'); + $datatable = $this->get('tejadong_datatables')->getDatatable('AcmeDemoBundle:Customer'); // The default type for all joins is inner. Change it to left if desired. $datatable->setDefaultJoinType(Datatable::JOIN_LEFT); @@ -132,12 +133,12 @@ If you need a different format for the response, you can specify the result type constants `Datatable::RESULT_ARRAY` and `Datatable::RESULT_JSON`: ``` php -use LanKit\DatatablesBundle\Datatables\DataTable; +use Tejadong\DatatablesBundle\Datatables\DataTable; ... public function getDatatableAction() { - $datatable = $this->get('lankit_datatables')->getDatatable('AcmeDemoBundle:Customer'); + $datatable = $this->get('tejadong_datatables')->getDatatable('AcmeDemoBundle:Customer'); // Get the results as an array $datatableArray = $datatable->getSearchResults(Datatable::RESULT_ARRAY); @@ -156,7 +157,7 @@ is passed the QueryBuilder instance as an argument. public function getDatatableAction() { - $datatable = $this->get('lankit_datatables')->getDatatable('AcmeDemoBundle:Customer'); + $datatable = $this->get('tejadong_datatables')->getDatatable('AcmeDemoBundle:Customer'); // Add the $datatable variable, or other needed variables, to the callback scope $datatable->addWhereBuilderCallback(function($qb) use ($datatable) { @@ -187,7 +188,7 @@ then you can toggle it with the `hideFilteredCount` method. public function getDatatableAction() { - $datatable = $this->get('lankit_datatables') + $datatable = $this->get('tejadong_datatables') ->getDatatable('AcmeDemoBundle:Customer') ->addWhereBuilderCallback(function($qb) use ($datatable) { // ... @@ -245,7 +246,7 @@ You can toggle and modify these properties with the methods `setDtRowClass`, `us public function getDatatableAction() { - $datatable = $this->get('lankit_datatables') + $datatable = $this->get('tejadong_datatables') ->getDatatable('AcmeDemoBundle:Customer') ->setDtRowClass('special-class') // Add whatever class(es) you want. Separate classes with a space. ->useDtRowId(true); @@ -266,7 +267,7 @@ MS SQL. You may receive an error like... To get around this you can disable the use of the Paginator by doing the following... ```yml -lankit_datatables: +tejadong_datatables: datatable: use_doctrine_paginator: false ``` diff --git a/TejadongDatatablesBundle.php b/TejadongDatatablesBundle.php new file mode 100644 index 0000000..822f36a --- /dev/null +++ b/TejadongDatatablesBundle.php @@ -0,0 +1,14 @@ + Date: Sat, 30 Jun 2018 14:03:33 +0200 Subject: [PATCH 10/22] Fix error in TejadongDatatablesBundle.php --- TejadongDatatablesBundle.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TejadongDatatablesBundle.php b/TejadongDatatablesBundle.php index 822f36a..5f6c1b3 100644 --- a/TejadongDatatablesBundle.php +++ b/TejadongDatatablesBundle.php @@ -9,6 +9,6 @@ class TejadongDatatablesBundle extends Bundle { public function getContainerExtension() { - return new TejadongDatatablesBundle(); + return new TejadongDatatablesExtension(); } } From 09ee2555fce597c0f890588cce830000480996d7 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 30 Jun 2018 14:18:32 +0200 Subject: [PATCH 11/22] Updated the help. --- Resources/doc/index.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/Resources/doc/index.md b/Resources/doc/index.md index 78aef11..f04083b 100755 --- a/Resources/doc/index.md +++ b/Resources/doc/index.md @@ -56,20 +56,11 @@ tejadong_datatables: ### Step 1: Download TejadongDatatablesBundle using composer -Add TejadongDatatablesBundle to your composer.json: - -```js -{ - "require": { - "tejadong/datatables-bundle": "*" - } -} -``` Use composer to download the bundle using the following command: ``` bash -$ php composer.phar update tejadong/datatables-bundle +$ php composer require tejadong/datatables-bundle ``` ### Step 2: Enable the bundle From 310e13fe04fc0879badbf4949ec5e4ba6225103c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Secaduras=20Cano?= Date: Mon, 25 Feb 2019 13:06:33 +0100 Subject: [PATCH 12/22] Arreglado al relacionar dos columnas con la misma entidad. Default join ahora es LEFT_JOIN. --- Datatables/Datatable.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Datatables/Datatable.php b/Datatables/Datatable.php index b8f16ae..a8c64c9 100755 --- a/Datatables/Datatable.php +++ b/Datatables/Datatable.php @@ -202,7 +202,7 @@ public function __construct(array $request, EntityRepository $repository, ClassM $this->metadata = $metadata; $this->serializer = $serializer; $this->tableName = Container::camelize($metadata->getTableName()); - $this->defaultJoinType = self::JOIN_INNER; + $this->defaultJoinType = self::JOIN_LEFT; $this->defaultResultType = self::RESULT_RESPONSE; $this->setParameters(); $this->qb = $em->createQueryBuilder(); @@ -318,6 +318,8 @@ protected function setRelatedEntityColumnInfo(array &$association, array $fields Container::camelize($metadata->getTableName()), $entityName ); + $joinName .= '_' . $entityName; + // The join required to get to the entity in question if (!isset($this->assignedJoins[$joinName])) { $this->assignedJoins[$joinName]['joinOn'] = $joinOn; From b347ffc167f49bc4a63880c17f7b7e9bae5de227 Mon Sep 17 00:00:00 2001 From: TEJADA Date: Fri, 27 Sep 2019 11:34:18 +0200 Subject: [PATCH 13/22] =?UTF-8?q?A=C3=B1adido=20el=20directorio=20/.idea?= =?UTF-8?q?=20al=20.gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 380e437..a737644 100755 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ composer.lock .*.sw[a-z] *.un~ Session.vim +/.idea From 349f2d81c8eaa942edcb301d7eb665d23622376a Mon Sep 17 00:00:00 2001 From: TEJADA Date: Fri, 27 Sep 2019 11:34:39 +0200 Subject: [PATCH 14/22] =?UTF-8?q?A=C3=B1adida=20funci=C3=B3n=20para=20las?= =?UTF-8?q?=20columnas=20personalizadas=20de=20Iv=C3=A1n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Datatables/Datatable.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Datatables/Datatable.php b/Datatables/Datatable.php index a8c64c9..d9fa160 100755 --- a/Datatables/Datatable.php +++ b/Datatables/Datatable.php @@ -797,4 +797,25 @@ public function getQueryBuilder() { return $this->qb; } + + public function setCustom($response, $nombre, $clase, $funcion, $parameters = []){ + + $data = json_decode($response->getContent(), true); + + foreach($data['aaData'] as $key => $registro){ + + $parametros = []; + + if(count($parameters) == 0) + $parametros = array($registro['id']); + else{ + $parametros = array_merge(array($registro['id']), $parameters); + } + + $data['aaData'][$key][$nombre] = call_user_func_array( array( $clase, $funcion), $parametros ); + } + + return $response->setContent(json_encode($data)); + + } } From 02a4a9370c5ef3bd22395ff4944113924bc33f1c Mon Sep 17 00:00:00 2001 From: TEJADA Date: Fri, 27 Sep 2019 12:27:09 +0200 Subject: [PATCH 15/22] =?UTF-8?q?Aplicados=20m=C3=A1s=20cambios=20sobre=20?= =?UTF-8?q?columnas=20custom=20de=20Iv=C3=A1n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Datatables/Datatable.php | 86 +++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/Datatables/Datatable.php b/Datatables/Datatable.php index d9fa160..b83ae57 100755 --- a/Datatables/Datatable.php +++ b/Datatables/Datatable.php @@ -201,7 +201,7 @@ public function __construct(array $request, EntityRepository $repository, ClassM $this->repository = $repository; $this->metadata = $metadata; $this->serializer = $serializer; - $this->tableName = Container::camelize($metadata->getTableName()); + $this->tableName = Container::camelize(explode('\\', $metadata->getName())[count(explode('\\', $metadata->getName()))-1]); $this->defaultJoinType = self::JOIN_LEFT; $this->defaultResultType = self::RESULT_RESPONSE; $this->setParameters(); @@ -296,31 +296,32 @@ public function setParameters() protected function setRelatedEntityColumnInfo(array &$association, array $fields) { $mdataName = implode('.', $fields); $lastField = Container::camelize(array_pop($fields)); - $joinName = $this->tableName; - $entityName = ''; + $joinName = $this->tableName; + $entityName = ''; $columnName = ''; // loop through the related entities, checking the associations as we go $metadata = $this->metadata; + while ($field = array_shift($fields)) { $columnName .= empty($columnName) ? $field : ".$field"; $entityName = lcfirst(Container::camelize($field)); + if ($metadata->hasAssociation($entityName)) { $joinOn = "$joinName.$entityName"; - if ($metadata->isCollectionValuedAssociation($entityName)) { + + if ($metadata->isCollectionValuedAssociation($entityName)) $association['containsCollections'] = true; - } - $metadata = $this->em->getClassMetadata( - $metadata->getAssociationTargetClass($entityName) - ); + + $metadata = $this->em->getClassMetadata($metadata->getAssociationTargetClass($entityName)); + $joinName .= '_' . $this->getJoinName( $metadata, - Container::camelize($metadata->getTableName()), + Container::camelize(explode('\\', $metadata->getName())[count(explode('\\', $metadata->getName()))-1]), $entityName ); - $joinName .= '_' . $entityName; - - // The join required to get to the entity in question + + // The join required to get to the entity in question if (!isset($this->assignedJoins[$joinName])) { $this->assignedJoins[$joinName]['joinOn'] = $joinOn; $this->assignedJoins[$joinName]['mdataColumn'] = $columnName; @@ -329,7 +330,7 @@ protected function setRelatedEntityColumnInfo(array &$association, array $fields } else { throw new Exception( - "Association '$entityName' not found ($mdataName)", + "Relación '$entityName' no encontrada ($mdataName)", '404' ); } @@ -338,7 +339,7 @@ protected function setRelatedEntityColumnInfo(array &$association, array $fields // Check the last field on the last related entity of the dotted notation if (!$metadata->hasField(lcfirst($lastField))) { throw new Exception( - "Field '$lastField' on association '$entityName' not found ($mdataName)", + "Propiedad '$lastField' en la relación '$entityName' no encontrada ($mdataName)", '404' ); } @@ -358,15 +359,14 @@ protected function setSingleFieldColumnInfo(array &$association, $fieldName) { $fieldName = Container::camelize($fieldName); if (!$this->metadata->hasField(lcfirst($fieldName))) { - throw new Exception( - "Field '$fieldName' not found.)", - '404' - ); - } - - $association['fieldName'] = $fieldName; - $association['entityName'] = $this->tableName; - $association['fullName'] = $this->tableName . '.' . lcfirst($fieldName); + $association['fieldName'] = $fieldName; + $association['entityName'] = null; + $association['fullName'] = lcfirst($fieldName); + }else{ + $association['fieldName'] = $fieldName; + $association['entityName'] = $this->tableName; + $association['fullName'] = $this->tableName . '.' . lcfirst($fieldName); + } } /** @@ -382,7 +382,7 @@ protected function getJoinName(ClassMetadata $metadata, $tableName, $entityName) // If it is self-referencing then we must avoid collisions if ($metadata->getName() == $this->metadata->getName()) { - $joinName .= "_$entityName"; + $joinName = "$entityName"; } return $joinName; @@ -551,10 +551,15 @@ public function setSelect(QueryBuilder $qb) // Combine all columns to pull foreach ($this->associations as $column) { $parts = explode('.', $column['fullName']); - $columns[$parts[0]][] = $parts[1]; - } - // Partial column results on entities require that we include the identifier as part of the selection + if(count($parts) > 1){ + $columns[$parts[0]][] = $parts[1]; + }else{ + $columns['Custom'][] = $parts[0]; + } + } + + // Partial column results on entities require that we include the identifier as part of the selection foreach ($this->identifiers as $joinName => $identifiers) { if (!in_array($identifiers[0], $columns[$joinName])) { array_unshift($columns[$joinName], $identifiers[0]); @@ -567,7 +572,8 @@ public function setSelect(QueryBuilder $qb) } foreach ($columns as $columnName => $fields) { - $partials[] = 'partial ' . $columnName . '.{' . implode(',', $fields) . '}'; + if($columnName != 'Custom') + $partials[] = 'partial ' . $columnName . '.{' . implode(',', $fields) . '}'; } $qb->select(implode(',', $partials)); @@ -800,22 +806,22 @@ public function getQueryBuilder() public function setCustom($response, $nombre, $clase, $funcion, $parameters = []){ - $data = json_decode($response->getContent(), true); + $data = json_decode($response->getContent(), true); - foreach($data['aaData'] as $key => $registro){ + foreach($data['aaData'] as $key => $registro){ - $parametros = []; + $parametros = []; - if(count($parameters) == 0) - $parametros = array($registro['id']); - else{ - $parametros = array_merge(array($registro['id']), $parameters); - } + if(count($parameters) == 0) + $parametros = array($registro['id']); + else{ + $parametros = array_merge(array($registro['id']), $parameters); + } - $data['aaData'][$key][$nombre] = call_user_func_array( array( $clase, $funcion), $parametros ); - } + $data['aaData'][$key][$nombre] = call_user_func_array( array( $clase, $funcion), $parametros ); + } - return $response->setContent(json_encode($data)); + return $response->setContent(json_encode($data)); - } + } } From 3040cc73b144c2923142d8e5624025a09f474776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Tejada?= Date: Mon, 20 Jan 2020 12:34:23 +0100 Subject: [PATCH 16/22] =?UTF-8?q?Fix:=20hacia=20comprobaci=C3=B3n=20de=20u?= =?UTF-8?q?na=20funci=C3=B3n=20sin=20antes=20comprobar=20si=20el=20valor?= =?UTF-8?q?=20de=20$rowRef=20era=20nulo=20o=20no.=20Al=20ser=20las=20relac?= =?UTF-8?q?iones=20inner=20join=20por=20defecto,=20cuando=20se=20quer?= =?UTF-8?q?=C3=ADa=20usar=20left=20join=20y=20la=20tabla=20de=20la=20parte?= =?UTF-8?q?=20left=20no=20ten=C3=ADa=20datos=20ocasionaba=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Datatables/Datatable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Datatables/Datatable.php b/Datatables/Datatable.php index b83ae57..31fafe8 100755 --- a/Datatables/Datatable.php +++ b/Datatables/Datatable.php @@ -638,7 +638,7 @@ public function executeSearch() while ($field = array_shift($fields)) { $rowRef = &$rowRef[$field]; // We ran into a collection based entity. Combine, merge, and continue on... - if (!empty($fields) && !$this->isAssocArray($rowRef)) { + if (!empty($fields) && $rowRef !== null && !$this->isAssocArray($rowRef)) { $children = array(); while ($childItem = array_shift($rowRef)) { $children = array_merge_recursive($children, $childItem); From 8d0a20197c7332e44ce5ef85f17ca8c087b27d68 Mon Sep 17 00:00:00 2001 From: JT Date: Thu, 19 Mar 2020 12:23:18 +0100 Subject: [PATCH 17/22] Arreglado al relacionar dos columnas con la misma entidad --- Datatables/Datatable.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Datatables/Datatable.php b/Datatables/Datatable.php index 31fafe8..9af06a4 100755 --- a/Datatables/Datatable.php +++ b/Datatables/Datatable.php @@ -321,6 +321,8 @@ protected function setRelatedEntityColumnInfo(array &$association, array $fields $entityName ); + $joinName .= '_' . $entityName; + // The join required to get to the entity in question if (!isset($this->assignedJoins[$joinName])) { $this->assignedJoins[$joinName]['joinOn'] = $joinOn; From 9bdbfaea8414a99d5b0f9035b409de5d044d9a52 Mon Sep 17 00:00:00 2001 From: Jesus Date: Sat, 3 Oct 2020 21:36:18 +0200 Subject: [PATCH 18/22] =?UTF-8?q?-=20A=C3=B1adida=20compatibilidad=20en=20?= =?UTF-8?q?las=20b=C3=BAsquedas=20con=20el=20formato=20de=20fecha=20d/m/Y?= =?UTF-8?q?=20H:i:s.=20-=20Actualizada=20la=20documentaci=C3=B3n.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Datatables/Datatable.php | 29 +++++++++++++++++++++++++++++ Resources/doc/index.md | 13 +++++++++++++ composer.json | 3 ++- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Datatables/Datatable.php b/Datatables/Datatable.php index 9af06a4..bfcab3f 100755 --- a/Datatables/Datatable.php +++ b/Datatables/Datatable.php @@ -484,6 +484,18 @@ public function setWhere(QueryBuilder $qb) for ($i=0 ; $i < count($this->parameters); $i++) { if (isset($this->request['bSearchable_'.$i]) && $this->request['bSearchable_'.$i] == "true") { $qbParam = "sSearch_global_{$this->associations[$i]['entityName']}_{$this->associations[$i]['fieldName']}"; + $fieldType = $this->metadata->getTypeOfField(lcfirst($this->associations[$i]['fieldName'])); + + if ($fieldType === 'datetime' || $fieldType === 'date') { + $orExpr->add( + $qb->expr()->like( + "DATE_FORMAT(".$this->associations[$i]['fullName'].", '%d/%m/%Y %H:%i:%s')", + ":$qbParam" + ) + ); + $qb->setParameter($qbParam, "%" . $this->request['sSearch_'.$i] . "%"); + } + $orExpr->add($qb->expr()->like( $this->associations[$i]['fullName'], ":$qbParam" @@ -496,9 +508,22 @@ public function setWhere(QueryBuilder $qb) // Individual column filtering $andExpr = $qb->expr()->andX(); + $orExpr = $qb->expr()->orX(); for ($i=0 ; $i < count($this->parameters); $i++) { if (isset($this->request['bSearchable_'.$i]) && $this->request['bSearchable_'.$i] == "true" && $this->request['sSearch_'.$i] != '') { $qbParam = "sSearch_single_{$this->associations[$i]['entityName']}_{$this->associations[$i]['fieldName']}"; + $fieldType = $this->metadata->getTypeOfField(lcfirst($this->associations[$i]['fieldName'])); + + if ($fieldType === 'datetime' || $fieldType === 'date') { + $orExpr->add( + $qb->expr()->like( + "DATE_FORMAT(".$this->associations[$i]['fullName'].", '%d/%m/%Y %H:%i:%s')", + ":$qbParam" + ) + ); + $qb->setParameter($qbParam, "%" . $this->request['sSearch_'.$i] . "%"); + } + $andExpr->add($qb->expr()->like( $this->associations[$i]['fullName'], ":$qbParam" @@ -510,6 +535,10 @@ public function setWhere(QueryBuilder $qb) $qb->andWhere($andExpr); } + if ($orExpr->count() > 0) { + $qb->orWhere($orExpr); + } + if (!empty($this->callbacks['WhereBuilder'])) { foreach ($this->callbacks['WhereBuilder'] as $callback) { $callback($qb); diff --git a/Resources/doc/index.md b/Resources/doc/index.md index f04083b..e3d634e 100755 --- a/Resources/doc/index.md +++ b/Resources/doc/index.md @@ -80,6 +80,19 @@ public function registerBundles() } ``` +### Step 3: Add the config format + + +Add settings to support date filtering d/m/Y H:i:s : + +```yml +doctrine: + orm: + dql: + datetime_functions: + date_format: DoctrineExtensions\Query\Mysql\DateFormat +``` + ## Usage To respond to a DataTables.js request from a controller, you can do the following: diff --git a/composer.json b/composer.json index 230e441..288073e 100755 --- a/composer.json +++ b/composer.json @@ -17,7 +17,8 @@ "require": { "symfony/framework-bundle": "~2.0||~3.0", "doctrine/orm": "~2.0||~2.4", - "doctrine/doctrine-bundle": "~1.0||~1.4" + "doctrine/doctrine-bundle": "~1.0||~1.4", + "beberlei/doctrineextensions": "^1.2" }, "suggest": { "jms/serializer-bundle": "Advanced JSON encoding capabilities, recommended." From 1560436522821f4cd21f3912712d4919627a8a3b Mon Sep 17 00:00:00 2001 From: Jesus Date: Sat, 3 Oct 2020 21:46:07 +0200 Subject: [PATCH 19/22] Fix version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 288073e..e2fe9e4 100755 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "symfony/framework-bundle": "~2.0||~3.0", "doctrine/orm": "~2.0||~2.4", "doctrine/doctrine-bundle": "~1.0||~1.4", - "beberlei/doctrineextensions": "^1.2" + "beberlei/doctrineextensions": "^1.1" }, "suggest": { "jms/serializer-bundle": "Advanced JSON encoding capabilities, recommended." From 5e7d1fdb63fcc0c4ac58019d0b203e74718c541d Mon Sep 17 00:00:00 2001 From: tejadong Date: Thu, 8 Oct 2020 19:23:00 +0200 Subject: [PATCH 20/22] =?UTF-8?q?Fix:=20quitada=20la=20comprobaci=C3=B3n?= =?UTF-8?q?=20del=20tipo=20e=20incluida=20siempre=20la=20comprobaci=C3=B3n?= =?UTF-8?q?=20del=20campo=20de=20fecha=20en=20un=20or?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Datatables/Datatable.php | 42 +++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/Datatables/Datatable.php b/Datatables/Datatable.php index bfcab3f..77b97c1 100755 --- a/Datatables/Datatable.php +++ b/Datatables/Datatable.php @@ -19,7 +19,7 @@ * { "mData": "customer.location.address" } * * Felix-Antoine Paradis is the author of the original implementation this is - * built off of, see: https://gist.github.com/1638094 + * built off of, see: https://gist.github.com/1638094 */ namespace Tejadong\DatatablesBundle\Datatables; @@ -484,17 +484,14 @@ public function setWhere(QueryBuilder $qb) for ($i=0 ; $i < count($this->parameters); $i++) { if (isset($this->request['bSearchable_'.$i]) && $this->request['bSearchable_'.$i] == "true") { $qbParam = "sSearch_global_{$this->associations[$i]['entityName']}_{$this->associations[$i]['fieldName']}"; - $fieldType = $this->metadata->getTypeOfField(lcfirst($this->associations[$i]['fieldName'])); - - if ($fieldType === 'datetime' || $fieldType === 'date') { - $orExpr->add( - $qb->expr()->like( - "DATE_FORMAT(".$this->associations[$i]['fullName'].", '%d/%m/%Y %H:%i:%s')", - ":$qbParam" - ) - ); - $qb->setParameter($qbParam, "%" . $this->request['sSearch_'.$i] . "%"); - } + + $orExpr->add( + $qb->expr()->like( + "DATE_FORMAT(".$this->associations[$i]['fullName'].", '%d/%m/%Y %H:%i:%s')", + ":$qbParam" + ) + ); + $qb->setParameter($qbParam, "%" . $this->request['sSearch_'.$i] . "%"); $orExpr->add($qb->expr()->like( $this->associations[$i]['fullName'], @@ -512,17 +509,14 @@ public function setWhere(QueryBuilder $qb) for ($i=0 ; $i < count($this->parameters); $i++) { if (isset($this->request['bSearchable_'.$i]) && $this->request['bSearchable_'.$i] == "true" && $this->request['sSearch_'.$i] != '') { $qbParam = "sSearch_single_{$this->associations[$i]['entityName']}_{$this->associations[$i]['fieldName']}"; - $fieldType = $this->metadata->getTypeOfField(lcfirst($this->associations[$i]['fieldName'])); - if ($fieldType === 'datetime' || $fieldType === 'date') { - $orExpr->add( - $qb->expr()->like( - "DATE_FORMAT(".$this->associations[$i]['fullName'].", '%d/%m/%Y %H:%i:%s')", - ":$qbParam" - ) - ); - $qb->setParameter($qbParam, "%" . $this->request['sSearch_'.$i] . "%"); - } + $orExpr->add( + $qb->expr()->like( + "DATE_FORMAT(".$this->associations[$i]['fullName'].", '%d/%m/%Y %H:%i:%s')", + ":$qbParam" + ) + ); + $qb->setParameter($qbParam, "%" . $this->request['sSearch_'.$i] . "%"); $andExpr->add($qb->expr()->like( $this->associations[$i]['fullName'], @@ -615,7 +609,7 @@ public function setSelect(QueryBuilder $qb) * Method to execute after constructing this object. Configures the object before * executing getSearchResults() */ - public function makeSearch() + public function makeSearch() { $this->setSelect($this->qb); $this->setAssociations($this->qb); @@ -785,7 +779,7 @@ public function getCountAllResults() return (int) $qb->getQuery()->getSingleScalarResult(); } - + /** * @return int Total query results after searches/filtering */ From 03c45b000f66a2462d66301e9df2ec2969615320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Tejada?= Date: Mon, 25 Apr 2022 09:53:51 +0200 Subject: [PATCH 21/22] Fix: modificado el filtrado de fechas y horas porque no funcionaba correctamente --- Datatables/Datatable.php | 108 ++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 48 deletions(-) diff --git a/Datatables/Datatable.php b/Datatables/Datatable.php index 77b97c1..054061d 100755 --- a/Datatables/Datatable.php +++ b/Datatables/Datatable.php @@ -296,8 +296,8 @@ public function setParameters() protected function setRelatedEntityColumnInfo(array &$association, array $fields) { $mdataName = implode('.', $fields); $lastField = Container::camelize(array_pop($fields)); - $joinName = $this->tableName; - $entityName = ''; + $joinName = $this->tableName; + $entityName = ''; $columnName = ''; // loop through the related entities, checking the associations as we go @@ -484,17 +484,25 @@ public function setWhere(QueryBuilder $qb) for ($i=0 ; $i < count($this->parameters); $i++) { if (isset($this->request['bSearchable_'.$i]) && $this->request['bSearchable_'.$i] == "true") { $qbParam = "sSearch_global_{$this->associations[$i]['entityName']}_{$this->associations[$i]['fieldName']}"; - - $orExpr->add( - $qb->expr()->like( - "DATE_FORMAT(".$this->associations[$i]['fullName'].", '%d/%m/%Y %H:%i:%s')", - ":$qbParam" - ) - ); - $qb->setParameter($qbParam, "%" . $this->request['sSearch_'.$i] . "%"); + $fieldType = $this->metadata->getTypeOfField(lcfirst($this->associations[$i]['fieldName'])); + + switch ($fieldType) { + case "datetime": + $fieldName = "DATE_FORMAT(".$this->associations[$i]['fullName'].", '%d/%m/%Y %H:%i:%s')"; + break; + case "time": + $fieldName = "DATE_FORMAT(".$this->associations[$i]['fullName'].", '%H:%i:%s')"; + break; + case "date": + $fieldName = "DATE_FORMAT(".$this->associations[$i]['fullName'].", '%d/%m/%Y')"; + break; + default: + $fieldName = $this->associations[$i]['fullName']; + break; + } $orExpr->add($qb->expr()->like( - $this->associations[$i]['fullName'], + $fieldName, ":$qbParam" )); $qb->setParameter($qbParam, "%" . $this->request['sSearch'] . "%"); @@ -505,34 +513,38 @@ public function setWhere(QueryBuilder $qb) // Individual column filtering $andExpr = $qb->expr()->andX(); - $orExpr = $qb->expr()->orX(); for ($i=0 ; $i < count($this->parameters); $i++) { if (isset($this->request['bSearchable_'.$i]) && $this->request['bSearchable_'.$i] == "true" && $this->request['sSearch_'.$i] != '') { $qbParam = "sSearch_single_{$this->associations[$i]['entityName']}_{$this->associations[$i]['fieldName']}"; - - $orExpr->add( - $qb->expr()->like( - "DATE_FORMAT(".$this->associations[$i]['fullName'].", '%d/%m/%Y %H:%i:%s')", - ":$qbParam" - ) - ); - $qb->setParameter($qbParam, "%" . $this->request['sSearch_'.$i] . "%"); + $fieldType = $this->metadata->getTypeOfField(lcfirst($this->associations[$i]['fieldName'])); + + switch ($fieldType) { + case "datetime": + $fieldName = "DATE_FORMAT(".$this->associations[$i]['fullName'].", '%d/%m/%Y %H:%i:%s')"; + break; + case "time": + $fieldName = "DATE_FORMAT(".$this->associations[$i]['fullName'].", '%H:%i:%s')"; + break; + case "date": + $fieldName = "DATE_FORMAT(".$this->associations[$i]['fullName'].", '%d/%m/%Y')"; + break; + default: + $fieldName = $this->associations[$i]['fullName']; + break; + } $andExpr->add($qb->expr()->like( - $this->associations[$i]['fullName'], - ":$qbParam" - )); + $fieldName, + ":$qbParam") + ); $qb->setParameter($qbParam, "%" . $this->request['sSearch_'.$i] . "%"); } } + if ($andExpr->count() > 0) { $qb->andWhere($andExpr); } - if ($orExpr->count() > 0) { - $qb->orWhere($orExpr); - } - if (!empty($this->callbacks['WhereBuilder'])) { foreach ($this->callbacks['WhereBuilder'] as $callback) { $callback($qb); @@ -577,14 +589,14 @@ public function setSelect(QueryBuilder $qb) foreach ($this->associations as $column) { $parts = explode('.', $column['fullName']); - if(count($parts) > 1){ - $columns[$parts[0]][] = $parts[1]; - }else{ - $columns['Custom'][] = $parts[0]; - } - } + if(count($parts) > 1){ + $columns[$parts[0]][] = $parts[1]; + }else{ + $columns['Custom'][] = $parts[0]; + } + } - // Partial column results on entities require that we include the identifier as part of the selection + // Partial column results on entities require that we include the identifier as part of the selection foreach ($this->identifiers as $joinName => $identifiers) { if (!in_array($identifiers[0], $columns[$joinName])) { array_unshift($columns[$joinName], $identifiers[0]); @@ -597,8 +609,8 @@ public function setSelect(QueryBuilder $qb) } foreach ($columns as $columnName => $fields) { - if($columnName != 'Custom') - $partials[] = 'partial ' . $columnName . '.{' . implode(',', $fields) . '}'; + if($columnName != 'Custom') + $partials[] = 'partial ' . $columnName . '.{' . implode(',', $fields) . '}'; } $qb->select(implode(',', $partials)); @@ -831,22 +843,22 @@ public function getQueryBuilder() public function setCustom($response, $nombre, $clase, $funcion, $parameters = []){ - $data = json_decode($response->getContent(), true); + $data = json_decode($response->getContent(), true); - foreach($data['aaData'] as $key => $registro){ + foreach($data['aaData'] as $key => $registro){ - $parametros = []; + $parametros = []; - if(count($parameters) == 0) - $parametros = array($registro['id']); - else{ - $parametros = array_merge(array($registro['id']), $parameters); - } + if(count($parameters) == 0) + $parametros = array($registro['id']); + else{ + $parametros = array_merge(array($registro['id']), $parameters); + } - $data['aaData'][$key][$nombre] = call_user_func_array( array( $clase, $funcion), $parametros ); - } + $data['aaData'][$key][$nombre] = call_user_func_array( array( $clase, $funcion), $parametros ); + } - return $response->setContent(json_encode($data)); + return $response->setContent(json_encode($data)); - } + } } From 202306200ec819b12500d121f7fa469af2107887 Mon Sep 17 00:00:00 2001 From: tejada Date: Mon, 23 Jun 2025 13:51:38 +0200 Subject: [PATCH 22/22] Arreglada vulnerabilidad XSS. --- Datatables/Datatable.php | 52 +++++++++++++++++++++++++++++++++++++++- composer.json | 3 ++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/Datatables/Datatable.php b/Datatables/Datatable.php index 054061d..86576e6 100755 --- a/Datatables/Datatable.php +++ b/Datatables/Datatable.php @@ -30,10 +30,11 @@ use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Tools\Pagination\Paginator; - use Symfony\Component\DependencyInjection\Container; use Symfony\Component\Config\Definition\Exception\Exception; use Symfony\Component\HttpFoundation\Response; +use HTMLPurifier; +use HTMLPurifier_Config; class Datatable { @@ -194,6 +195,8 @@ class Datatable */ protected $datatable; + protected $htmlPurifier; + public function __construct(array $request, EntityRepository $repository, ClassMetadata $metadata, EntityManager $em, $serializer) { $this->em = $em; @@ -213,6 +216,8 @@ public function __construct(array $request, EntityRepository $repository, ClassM $identifiers = $this->metadata->getIdentifierFieldNames(); $this->rootEntityIdentifier = array_shift($identifiers); + + $this->htmlPurifierInit(); } /** @@ -684,6 +689,10 @@ public function executeSearch() } } } + + // Iterate and sanitize + $item = $this->purifyRecursive($item); + $output['aaData'][] = $item; } @@ -861,4 +870,45 @@ public function setCustom($response, $nombre, $clase, $funcion, $parameters = [] return $response->setContent(json_encode($data)); } + + private function htmlPurifierInit() + { + $config = HTMLPurifier_Config::createDefault(); + + // Permitir todos los elementos y atributos válidos HTML5, para no limitar nada + $config->set('HTML.Allowed', null); // No restringir etiquetas ni atributos + + // Permitir completamente el CSS, para evitar que modifique estilos + $config->set('CSS.AllowedProperties', null); + + // No transformar ni corregir el HTML + $config->set('HTML.Doctype', 'HTML 4.01 Transitional'); // un doctype flexible + $config->set('HTML.Trusted', false); // seguridad contra XSS + $config->set('Core.EscapeNonASCIICharacters', false); + $config->set('Core.ConvertDocumentToFragment', true); + + // Evitar auto-corrección de etiquetas + $config->set('HTML.DefinitionID', 'custom-def'); + $config->set('HTML.DefinitionRev', 1); + $config->set('AutoFormat.AutoParagraph', false); + $config->set('AutoFormat.RemoveEmpty', false); + + // Deshabilitar filtro CSS agresivo + $config->set('CSS.Trusted', false); + $config->set('CSS.AllowImportant', true); + + $this->htmlPurifier = new HTMLPurifier($config); + } + + protected function purifyRecursive($data) + { + foreach ($data as $key => $value) { + if (is_string($value)) { + $data[$key] = $this->htmlPurifier->purify($value); + } elseif (is_array($value)) { + $data[$key] = $this->purifyRecursive($value); + } + } + return $data; + } } diff --git a/composer.json b/composer.json index e2fe9e4..eef464a 100755 --- a/composer.json +++ b/composer.json @@ -18,7 +18,8 @@ "symfony/framework-bundle": "~2.0||~3.0", "doctrine/orm": "~2.0||~2.4", "doctrine/doctrine-bundle": "~1.0||~1.4", - "beberlei/doctrineextensions": "^1.1" + "beberlei/doctrineextensions": "^1.1", + "ezyang/htmlpurifier": "^4.18" }, "suggest": { "jms/serializer-bundle": "Advanced JSON encoding capabilities, recommended."