Skip to content

Commit

Permalink
Symfony 5 support (#134)
Browse files Browse the repository at this point in the history
* Symfony 5.0 support

* Replace Pagerfanta with Paginator

* Fixed tests

* PHPStan fixes

* PHP 7.4 support

* Fixed Doctrine deprecation

* Code cleanup and typehint fixes
  • Loading branch information
DamienHarper authored Dec 2, 2019
1 parent 4c08a2c commit 19d2d96
Show file tree
Hide file tree
Showing 13 changed files with 207 additions and 108 deletions.
6 changes: 4 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ php:
- 7.1
- 7.2
- 7.3
- 7.4snapshot

env:
- DB=mysql
Expand All @@ -29,8 +30,8 @@ install:
- COMPOSER_MEMORY_LIMIT=-1 composer update $COMPOSER_FLAGS --prefer-dist

before_script:
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
- chmod +x ./cc-test-reporter
- if [ $(phpenv version-name) = "7.3" ]; then curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter; fi
- if [ $(phpenv version-name) = "7.3" ]; then chmod +x ./cc-test-reporter; fi
- if [ $(phpenv version-name) = "7.3" ]; then ./cc-test-reporter before-build; fi
- phpenv config-rm xdebug.ini
- pecl install pcov
Expand All @@ -39,6 +40,7 @@ script:
- if [ $(phpenv version-name) = "7.1" ]; then ./vendor/bin/phpunit -c tests/travis/$DB.travis.xml --disable-coverage; fi
- if [ $(phpenv version-name) = "7.2" ]; then ./vendor/bin/phpunit -c tests/travis/$DB.travis.xml --disable-coverage; fi
- if [ $(phpenv version-name) = "7.3" ]; then php -d pcov.enabled=1 ./vendor/bin/phpunit -c tests/travis/$DB.travis.xml --coverage-clover clover.xml; fi
- if [ $(phpenv version-name) = "7.4" ]; then ./vendor/bin/phpunit -c tests/travis/$DB.travis.xml --disable-coverage; fi

after_script:
- if [ $(phpenv version-name) = "7.3" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT; fi
Expand Down
25 changes: 12 additions & 13 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@
"php": ">=7.1",
"doctrine/orm": "^2.7",
"doctrine/doctrine-bundle": "^1.9|^2.0",
"symfony/event-dispatcher": "^3.4 || ^4.0",
"symfony/security-bundle": "^3.4 || ^4.0",
"pagerfanta/pagerfanta": "^2.1",
"white-october/pagerfanta-bundle": "^1.2",
"symfony/event-dispatcher": "^3.4|^4.0|^5.0",
"symfony/security-bundle": "^3.4|^4.0|^5.0",
"symfony/translation": "^3.4|^4.0|^5.0",
"doctrine/annotations": "^1.8",
"symfony/lock": "^3.4 || ^4.0"
"symfony/lock": "^3.4|^4.0|^5.0"
},
"autoload": {
"psr-4": {
Expand All @@ -32,17 +31,17 @@
}
},
"require-dev": {
"phpunit/phpunit": "^7.0 || ^8.0",
"phpunit/phpunit": "^7.0|^8.0",
"doctrine/doctrine-migrations-bundle": "^1.3|^2.0",
"matthiasnoback/symfony-dependency-injection-test": "^3.1 || ^4.0",
"matthiasnoback/symfony-dependency-injection-test": "^3.1|^4.0",
"gedmo/doctrine-extensions": "^2.4",
"symfony/var-dumper": "^4.2",
"stof/doctrine-extensions-bundle": "^1.3",
"phpstan/phpstan": "^0.11.2",
"phpstan/phpstan-doctrine": "^0.11.1",
"phpstan/phpstan-symfony": "^0.11.1",
"symfony/var-dumper": "^4.2|^5.0",
"twig/extensions": "^1.5",
"friendsofphp/php-cs-fixer": "^2.15"
"friendsofphp/php-cs-fixer": "^2.15",
"phpstan/phpstan-doctrine": "^0.11",
"phpstan/phpstan-strict-rules": "^0.11",
"phpstan/phpstan-symfony": "^0.11",
"phpstan/phpstan-shim": "^0.11"
},
"conflict": {
"twig/twig": "<1.40|<2.9"
Expand Down
11 changes: 8 additions & 3 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ parameters:

ignoreErrors:
# false positives
- '~Class Symfony\\Component\\Security\\Core\\Role\\SwitchUserRole not found~'
- '~Class Symfony\\Component\\EventDispatcher\\Event not found~'
- '~Cannot cast array\<string\>\|string\|null to int~'
- '~Method Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface\:\:dispatch\(\) invoked with 2 parameters\, 1 required~'
- '~Parameter \#1 \$event of method Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface\:\:dispatch\(\) expects object\, string given~'
- '~Parameter \#1 \$name of method Symfony\\Component\\Console\\Command\\Command\:\:setName\(\) expects string, string\|null given~'
- '~Parameter \#1 \$tableName of method Doctrine\\DBAL\\Schema\\Schema\:\:(has|get)Table\(\) expects string, string\|null given~'
- '~Parameter \#1 \$(first|max)Results? of method Doctrine\\DBAL\\Query\\QueryBuilder\:\:set(First|Max)Results?\(\) expects int, null given~'
- '~Parameter \#1 \$event of method Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface\:\:dispatch\(\) expects object, string given~'
- '~Parameter \#2 \$eventName of method Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface\:\:dispatch\(\) expects string\|null, DH\\DoctrineAuditBundle\\Event\\LifecycleEvent given~'
- '~Cannot call method fetchColumn\(\) on Doctrine\\DBAL\\Driver\\Statement\|int~'
- '~Possibly invalid array key type object\|string~'
- '~Cannot call method fetchAll\(\) on Doctrine\\DBAL\\Driver\\Statement\|int~'
- '~Call to an undefined method Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface\:\:getRoles\(\)~'
- '~Call to method getSource\(\) on an unknown class Symfony\\Component\\Security\\Core\\Role\\SwitchUserRole~'
3 changes: 2 additions & 1 deletion src/DoctrineAuditBundle/AuditConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ public function __construct(
$this->dispatcher = $dispatcher;

$r = new ReflectionMethod($this->dispatcher, 'dispatch');
$this->is_pre43_dispatcher = 2 === \count($r->getParameters());
$p = $r->getParameters();
$this->is_pre43_dispatcher = 2 === \count($p) && 'event' !== $p[0]->name;

$this->enabled = $config['enabled'];
$this->tablePrefix = $config['table_prefix'];
Expand Down
11 changes: 10 additions & 1 deletion src/DoctrineAuditBundle/Controller/AuditController.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public function showTransactionAction(string $hash): Response
* @param string $entity
* @param int|string $id
*
* @throws InvalidArgumentException
*
* @return Response
*/
public function showEntityHistoryAction(Request $request, string $entity, $id = null): Response
Expand All @@ -76,7 +78,14 @@ public function showEntityHistoryAction(Request $request, string $entity, $id =
return $this->render('@DHDoctrineAudit/Audit/entity_history.html.twig', [
'id' => $id,
'entity' => $entity,
'entries' => $entries,
'paginator' => $entries,
]);
}

public static function getSubscribedServices(): array
{
return array_merge(parent::getSubscribedServices(), [
'dh_doctrine_audit.reader' => AuditReader::class,
]);
}
}
2 changes: 1 addition & 1 deletion src/DoctrineAuditBundle/Helper/DoctrineHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace DH\DoctrineAuditBundle\Helper;

use Doctrine\ORM\Proxy\Proxy;
use Doctrine\Common\Persistence\Proxy;

class DoctrineHelper
{
Expand Down
110 changes: 45 additions & 65 deletions src/DoctrineAuditBundle/Reader/AuditReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
use Doctrine\DBAL\Statement;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata as ORMMetadata;
use Pagerfanta\Adapter\DoctrineDbalSingleTableAdapter;
use Pagerfanta\Pagerfanta;
use PDO;
use Symfony\Component\Security\Core\Security as CoreSecurity;

Expand Down Expand Up @@ -120,7 +118,7 @@ public function getEntities(): array
/**
* Returns an array of audited entries/operations.
*
* @param object|string $entity
* @param string $entity
* @param null|int|string $id
* @param null|int $page
* @param null|int $pageSize
Expand All @@ -132,7 +130,7 @@ public function getEntities(): array
*
* @return array
*/
public function getAudits($entity, $id = null, ?int $page = null, ?int $pageSize = null, ?string $transactionHash = null, bool $strict = true): array
public function getAudits(string $entity, $id = null, ?int $page = null, ?int $pageSize = null, ?string $transactionHash = null, bool $strict = true): array
{
$this->checkAuditable($entity);
$this->checkRoles($entity, Security::VIEW_SCOPE);
Expand Down Expand Up @@ -179,67 +177,55 @@ public function getAuditsByTransactionHash(string $transactionHash): array
/**
* Returns an array of audited entries/operations.
*
* @param object|string $entity
* @param string $entity
* @param null|int|string $id
* @param int $page
* @param int $pageSize
*
* @throws AccessDeniedException
* @throws InvalidArgumentException
*
* @return Pagerfanta
* @return array
*/
public function getAuditsPager($entity, $id = null, int $page = 1, int $pageSize = self::PAGE_SIZE): Pagerfanta
public function getAuditsPager(string $entity, $id = null, int $page = 1, int $pageSize = self::PAGE_SIZE): array
{
$queryBuilder = $this->getAuditsQueryBuilder($entity, $id);

$adapter = new DoctrineDbalSingleTableAdapter($queryBuilder, 'at.id');

$pagerfanta = new Pagerfanta($adapter);
$pagerfanta
->setMaxPerPage($pageSize)
->setCurrentPage($page)
;

return $pagerfanta;
}

/**
* Returns the amount of audited entries/operations.
*
* @param object|string $entity
* @param null|int|string $id
*
* @throws AccessDeniedException
* @throws InvalidArgumentException
*
* @return int
*/
public function getAuditsCount($entity, $id = null): int
{
$queryBuilder = $this->getAuditsQueryBuilder($entity, $id);
$currentPage = $page < 1 ? 1 : $page;
$firstResult = ($currentPage - 1) * $pageSize;

$result = $queryBuilder
->resetQueryPart('select')
->resetQueryPart('orderBy')
->select('COUNT(id)')
->execute()
->fetchColumn(0)
$queryBuilder
->setFirstResult($firstResult)
->setMaxResults($pageSize)
;

return false === $result ? 0 : $result;
$paginator = new Paginator($queryBuilder);
$numResults = $paginator->count();
$hasPreviousPage = $currentPage > 1;
$hasNextPage = ($currentPage * $pageSize) < $numResults;

return [
'results' => $paginator->getIterator(),
'currentPage' => $currentPage,
'hasPreviousPage' => $hasPreviousPage,
'hasNextPage' => $hasNextPage,
'previousPage' => $hasPreviousPage ? $currentPage - 1 : null,
'nextPage' => $hasNextPage ? $currentPage + 1 : null,
'numPages' => (int) ceil($numResults / $pageSize),
'haveToPaginate' => $numResults > $pageSize,
];
}

/**
* @param object|string $entity
* @param string $id
* @param string $entity
* @param string $id
*
* @throws AccessDeniedException
* @throws InvalidArgumentException
*
* @return mixed[]
*/
public function getAudit($entity, $id): array
public function getAudit(string $entity, $id): array
{
$this->checkAuditable($entity);
$this->checkRoles($entity, Security::VIEW_SCOPE);
Expand Down Expand Up @@ -269,34 +255,30 @@ public function getAudit($entity, $id): array
/**
* Returns the table name of $entity.
*
* @param object|string $entity
* @param string $entity
*
* @return string
*/
public function getEntityTableName($entity): string
public function getEntityTableName(string $entity): string
{
$entityName = \is_string($entity) ? $entity : \get_class($entity);

return $this->entityManager->getClassMetadata($entityName)->getTableName();
return $this->entityManager->getClassMetadata($entity)->getTableName();
}

/**
* Returns the audit table name for $entity.
*
* @param object|string $entity
* @param string $entity
*
* @return string
*/
public function getEntityAuditTableName($entity): string
public function getEntityAuditTableName(string $entity): string
{
$entityName = \is_string($entity) ? $entity : \get_class($entity);

$schema = '';
if ($this->entityManager->getClassMetadata($entityName)->getSchemaName()) {
$schema = $this->entityManager->getClassMetadata($entityName)->getSchemaName().'.';
if ($this->entityManager->getClassMetadata($entity)->getSchemaName()) {
$schema = $this->entityManager->getClassMetadata($entity)->getSchemaName().'.';
}

return sprintf('%s%s%s%s', $schema, $this->configuration->getTablePrefix(), $this->getEntityTableName($entityName), $this->configuration->getTableSuffix());
return sprintf('%s%s%s%s', $schema, $this->configuration->getTablePrefix(), $this->getEntityTableName($entity), $this->configuration->getTableSuffix());
}

/**
Expand Down Expand Up @@ -352,7 +334,7 @@ private function filterByObjectId(QueryBuilder $queryBuilder, $id): QueryBuilder
/**
* Returns an array of audited entries/operations.
*
* @param object|string $entity
* @param string $entity
* @param null|int|string $id
* @param null|int $page
* @param null|int $pageSize
Expand All @@ -364,10 +346,8 @@ private function filterByObjectId(QueryBuilder $queryBuilder, $id): QueryBuilder
*
* @return QueryBuilder
*/
private function getAuditsQueryBuilder($entity, $id = null, ?int $page = null, ?int $pageSize = null, ?string $transactionHash = null, bool $strict = true): QueryBuilder
private function getAuditsQueryBuilder(string $entity, $id = null, ?int $page = null, ?int $pageSize = null, ?string $transactionHash = null, bool $strict = true): QueryBuilder
{
$entityName = \is_string($entity) ? $entity : \get_class($entity);

$this->checkAuditable($entity);
$this->checkRoles($entity, Security::VIEW_SCOPE);

Expand All @@ -390,11 +370,11 @@ private function getAuditsQueryBuilder($entity, $id = null, ?int $page = null, ?
->addOrderBy('id', 'DESC')
;

$metadata = $this->entityManager->getClassMetadata($entityName);
$metadata = $this->entityManager->getClassMetadata($entity);
if ($strict && $metadata instanceof ORMMetadata && ORMMetadata::INHERITANCE_TYPE_SINGLE_TABLE === $metadata->inheritanceType) {
$queryBuilder
->andWhere('discriminator = :discriminator')
->setParameter('discriminator', \is_object($entity) ? \get_class($entity) : $entity)
->setParameter('discriminator', $entity)
;
}

Expand All @@ -415,11 +395,11 @@ private function getAuditsQueryBuilder($entity, $id = null, ?int $page = null, ?
/**
* Throws an InvalidArgumentException if given entity is not auditable.
*
* @param object|string $entity
* @param string $entity
*
* @throws InvalidArgumentException
*/
private function checkAuditable($entity): void
private function checkAuditable(string $entity): void
{
if (!$this->configuration->isAuditable($entity)) {
throw new InvalidArgumentException('Entity '.$entity.' is not auditable.');
Expand All @@ -429,12 +409,12 @@ private function checkAuditable($entity): void
/**
* Throws an AccessDeniedException if user not is granted to access audits for the given entity.
*
* @param object|string $entity
* @param string $scope
* @param string $entity
* @param string $scope
*
* @throws AccessDeniedException
*/
private function checkRoles($entity, string $scope): void
private function checkRoles(string $entity, string $scope): void
{
$userProvider = $this->configuration->getUserProvider();
$user = null === $userProvider ? null : $userProvider->getUser();
Expand Down
Loading

0 comments on commit 19d2d96

Please sign in to comment.