Skip to content

Commit

Permalink
refs stwe#976: fixed Datatable name validation
Browse files Browse the repository at this point in the history
- added test for invalid name validation
- changed thrown exception from `\Exception` to more specific
`\LogicException`
- updated documentation
  • Loading branch information
Eloar committed Dec 17, 2021
1 parent cac7033 commit 7bf44a1
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 6 deletions.
11 changes: 6 additions & 5 deletions Datatable/AbstractDatatable.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
namespace Sg\DatatablesBundle\Datatable;

use Doctrine\ORM\EntityManagerInterface;
use Exception;
use LogicException;
use Sg\DatatablesBundle\Datatable\Column\ColumnBuilder;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessor;
Expand Down Expand Up @@ -147,7 +147,7 @@ abstract class AbstractDatatable implements DatatableInterface
protected static $uniqueCounter = [];

/**
* @throws Exception
* @throws LogicException
*/
public function __construct(
AuthorizationCheckerInterface $authorizationChecker,
Expand Down Expand Up @@ -313,12 +313,13 @@ public function getUniqueName()
/**
* Checks the name only contains letters, numbers, underscores or dashes.
*
* @throws Exception
* @throws LogicException
*/
private function validateName()
{
if (1 !== preg_match(self::NAME_REGEX, $this->getName())) {
throw new Exception('AbstractDatatable::validateName(): The result of the getName method can only contain letters, numbers, underscore and dashes.');
$name = $this->getName();
if (1 !== preg_match(self::NAME_REGEX, $name)) {
throw new LogicException(sprintf('AbstractDatatable::validateName(): "%s" is invalid Datatable Name. Name can only contain letters, numbers, underscore and dashes.', $name));
}
}
}
2 changes: 1 addition & 1 deletion Datatable/DatatableInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
*/
interface DatatableInterface
{
const NAME_REGEX = '/[a-zA-Z0-9\-\_]+/';
const NAME_REGEX = '/^[a-zA-Z0-9\-\_]+$/';

/**
* Builds the datatable.
Expand Down
5 changes: 5 additions & 0 deletions Resources/doc/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,11 @@ class PostDatatable extends AbstractDatatable
}
```

**Important:**
When declaring datatable "by hand" as extending `AbstractDatatable` class watch out for datatable name as returned from
`getName()` method. Valid datatable name may contains only letters ([a-zA-Z]), digits (0-9), dashes (-) and underscores
(_). Putting any other character in name will cause `\LogicException` to be thrown.

### Step 2: (Optional) Registering your Datatable as a Service

``` yaml
Expand Down
46 changes: 46 additions & 0 deletions Tests/DatatableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
namespace Sg\DatatablesBundle\Tests;

use Doctrine\ORM\EntityManager;
use ReflectionClass;
use Sg\DatatablesBundle\Datatable\AbstractDatatable;
use Sg\DatatablesBundle\Tests\Datatables\PostDatatable;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
Expand Down Expand Up @@ -64,6 +66,50 @@ public function testCreate()
$table->buildDatatable();
}

public function testInvalidName()
{
/** @noinspection PhpUndefinedMethodInspection */
$authorizationChecker = $this->createMock(AuthorizationCheckerInterface::class);
/** @noinspection PhpUndefinedMethodInspection */
$securityToken = $this->createMock(TokenStorageInterface::class);
/** @noinspection PhpUndefinedMethodInspection */
$translator = $this->createMock(TranslatorInterface::class);
/** @noinspection PhpUndefinedMethodInspection */
$router = $this->createMock(RouterInterface::class);
/** @noinspection PhpUndefinedMethodInspection */
$twig = $this->createMock(Environment::class);

/** @noinspection PhpUndefinedMethodInspection */
$em = $this->getMockBuilder(EntityManager::class)
->disableOriginalConstructor()
->setMethods(
['getClassMetadata']
)
->getMock()
;

// @noinspection PhpUndefinedMethodInspection
$em->expects(static::any())
->method('getClassMetadata')
->willReturn($this->getClassMetadataMock())
;

$mock = $this->getMockBuilder(AbstractDatatable::class)
->disableOriginalConstructor()
->setMethods(['getName'])
->getMockForAbstractClass()
;
$mock->expects(static::any())
->method('getName')
->willReturn('invalid.name')
;

$refledtionClass = new ReflectionClass(AbstractDatatable::class);
$constructor = $refledtionClass->getConstructor();
$this->expectException(\LogicException::class);
$constructor->invoke($mock, $authorizationChecker, $securityToken, $translator, $router, $em, $twig);
}

public function getClassMetadataMock()
{
/** @noinspection PhpUndefinedMethodInspection */
Expand Down

0 comments on commit 7bf44a1

Please sign in to comment.