diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4cc5eed..897b1c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,18 +14,12 @@ jobs: fail-fast: false matrix: php-version: - - '7.4' - - '8.0' - '8.1' + - '8.2' + - '8.3' symfony-version: - - '4.4.*' - '5.4.*' - '6.3.*' - exclude: - - php-version: '7.4' - symfony-version: '6.3.*' - - php-version: '8.0' - symfony-version: '6.3.*' coverage: [ 'none' ] steps: - name: "Checkout" @@ -53,9 +47,9 @@ jobs: fail-fast: false matrix: php-version: - - '7.4' - - '8.0' - '8.1' + - '8.2' + - '8.3' steps: - name: "Checkout" uses: "actions/checkout@v2" diff --git a/Annotation/Sandbox.php b/Annotation/Sandbox.php index f32d66f..8c3c68a 100644 --- a/Annotation/Sandbox.php +++ b/Annotation/Sandbox.php @@ -3,6 +3,8 @@ namespace Intaro\TwigSandboxBundle\Annotation; /** + * @deprecated left only for automatic conversion of annotations to attributes + * * @Annotation * @Target({"METHOD", "PROPERTY"}) */ diff --git a/Attribute/Sandbox.php b/Attribute/Sandbox.php new file mode 100644 index 0000000..262454b --- /dev/null +++ b/Attribute/Sandbox.php @@ -0,0 +1,16 @@ + $options */ - public function __construct(LoaderInterface $loader, DumperInterface $dumper, SecurityPolicy $policy = null, array $options = []) + public function __construct(LoaderInterface $loader, DumperInterface $dumper, ?SecurityPolicy $policy = null, array $options = []) { $this->loader = $loader; $this->policy = $policy; @@ -65,7 +65,7 @@ public function addExtensions(?array $extensions = null): void * * @param array $params */ - public function getSandboxEnvironment(array $params = [], SecurityPolicy $securityPolicy = null): TwigAdapter + public function getSandboxEnvironment(array $params = [], ?SecurityPolicy $securityPolicy = null): TwigAdapter { $loader = new ArrayLoader(); $twig = new Environment($loader, $params); @@ -162,10 +162,7 @@ public function getPolicyRules(): SecurityPolicyRules return $this->rules; } - /** - * @param string $cacheDir - */ - public function warmUp(/*string */ $cacheDir/*, ?string $buildDir = null*/)/*: array*/ + public function warmUp(string $cacheDir/* , ?string $buildDir = null */)/* : array */ { $currentDir = $this->options['cache_dir']; diff --git a/Builder/TwigAdapter.php b/Builder/TwigAdapter.php index f1d3241..8c55fa5 100644 --- a/Builder/TwigAdapter.php +++ b/Builder/TwigAdapter.php @@ -18,10 +18,8 @@ public function __construct(Environment $twigEnvironment) /** * @param mixed[] $args - * - * @return mixed */ - public function __call(string $method, array $args) + public function __call(string $method, array $args): mixed { if (method_exists($this, $method)) { return $this->$method(...$args); diff --git a/CacheWarmer/TwigSandboxCacheWarmer.php b/CacheWarmer/TwigSandboxCacheWarmer.php index 3bd3869..c01a18d 100644 --- a/CacheWarmer/TwigSandboxCacheWarmer.php +++ b/CacheWarmer/TwigSandboxCacheWarmer.php @@ -14,10 +14,7 @@ public function __construct(EnvironmentBuilder $builder) $this->environmentBuilder = $builder; } - /** - * @param string $cacheDir - */ - public function warmUp(/*string */ $cacheDir/*, ?string $buildDir = null*/)/*: array*/ + public function warmUp(string $cacheDir/* , ?string $buildDir = null */)/* : array */ { return $this->environmentBuilder->warmUp($cacheDir); } diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index ef07516..acd7a67 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -12,19 +12,8 @@ */ class Configuration implements ConfigurationInterface { - /** - * {@inheritDoc} - */ public function getConfigTreeBuilder(): TreeBuilder { - $treeBuilder = new TreeBuilder('intaro_twig_sandbox'); - if (\method_exists($treeBuilder, 'getRootNode')) { - $rootNode = $treeBuilder->getRootNode(); - } else { - // BC layer for symfony/config 4.1 and older - $rootNode = $treeBuilder->root('intaro_twig_sandbox'); - } - - return $treeBuilder; + return new TreeBuilder('intaro_twig_sandbox'); } } diff --git a/Loader/AnnotationClassLoader.php b/Loader/AnnotationClassLoader.php index 22ed583..6d2d0fe 100644 --- a/Loader/AnnotationClassLoader.php +++ b/Loader/AnnotationClassLoader.php @@ -2,7 +2,7 @@ namespace Intaro\TwigSandboxBundle\Loader; -use Doctrine\Common\Annotations\Reader; +use Intaro\TwigSandboxBundle\Attribute\Sandbox; use Intaro\TwigSandboxBundle\SecurityPolicy\SecurityPolicyRules; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\Config\Loader\LoaderResolverInterface; @@ -10,79 +10,50 @@ class AnnotationClassLoader implements LoaderInterface { - protected Reader $reader; - protected string $annotationClass = 'Intaro\\TwigSandboxBundle\\Annotation\\Sandbox'; - - public function __construct(Reader $reader) - { - $this->reader = $reader; - } - /** - * Sets the annotation class to read properties from. - * - * @param string $class A fully-qualified class name + * @param string $resource A class name */ - public function setAnnotationClass(string $class): void + public function load(mixed $resource, ?string $type = null): SecurityPolicyRules { - $this->annotationClass = $class; - } - - /** - * Loads from annotations from a class. - * - * @param string $class A class name - * @param string $type The resource type - * - * @return SecurityPolicyRules A Rules instance - * - * @throws \InvalidArgumentException When annotations can't be parsed - */ - public function load($class, $type = null): SecurityPolicyRules - { - if (!class_exists($class)) { - throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class)); + if (!class_exists($resource)) { + throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $resource)); } - $class = new \ReflectionClass($class); + $class = new \ReflectionClass($resource); if ($class->isAbstract()) { - throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class)); + throw new \InvalidArgumentException(sprintf('Attributes from the class "%s" cannot be read as it is abstract.', $resource)); } $rules = new SecurityPolicyRules(); $rules->addResource(new FileResource((string) $class->getFileName())); foreach ($class->getMethods() as $method) { - foreach ($this->reader->getMethodAnnotations($method) as $annot) { - if ($annot instanceof $this->annotationClass) { - $methodName = $method->getName(); - $rules->addMethod($class->getName(), $methodName); - } + if (!count($method->getAttributes(Sandbox::class, \ReflectionAttribute::IS_INSTANCEOF))) { + continue; } + + $rules->addMethod($class->getName(), $method->getName()); } foreach ($class->getProperties() as $property) { - foreach ($this->reader->getPropertyAnnotations($property) as $annot) { - if ($annot instanceof $this->annotationClass) { - $rules->addProperty($class->getName(), $property->getName()); - } + if (!count($property->getAttributes(Sandbox::class, \ReflectionAttribute::IS_INSTANCEOF))) { + continue; } + + $rules->addProperty($class->getName(), $property->getName()); } return $rules; } - /** - * @param ?string $type - */ - public function supports($resource, $type = null): bool + public function supports(mixed $resource, ?string $type = null): bool { - return is_string($resource) && preg_match('/^(?:\\\\?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)+$/', $resource) && (!$type || 'annotation' === $type); + return + is_string($resource) + && preg_match('/^(?:\\\\?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)+$/', $resource) + && (!$type || in_array($type, ['annotation', 'attribute'], true)); } - /** - * {@inheritdoc} - */ public function setResolver(LoaderResolverInterface $resolver): void { } diff --git a/Loader/AnnotationDirectoryLoader.php b/Loader/AnnotationDirectoryLoader.php index 2ef9497..dfa6a4c 100644 --- a/Loader/AnnotationDirectoryLoader.php +++ b/Loader/AnnotationDirectoryLoader.php @@ -8,34 +8,28 @@ class AnnotationDirectoryLoader extends AnnotationFileLoader { /** - * Loads from annotations from a directory. - * - * @param string $path A directory path - * @param ?string $type The resource type - * - * @return SecurityPolicyRules A Rules instance - * - * @throws \InvalidArgumentException When annotations can't be parsed + * @param string $resource A directory path */ - public function load($path, $type = null): SecurityPolicyRules + public function load(mixed $resource, ?string $type = null): SecurityPolicyRules { - $dir = $this->locator->locate($path); + $dir = $this->locator->locate($resource); $rules = new SecurityPolicyRules(); $rules->addResource(new DirectoryResource($dir, '/\.php$/')); $files = iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), \RecursiveIteratorIterator::LEAVES_ONLY)); - usort($files, function (\SplFileInfo $a, \SplFileInfo $b) { - return (string) $a > (string) $b ? 1 : -1; - }); + usort( + $files, + static fn (\SplFileInfo $a, \SplFileInfo $b) => (string) $a > (string) $b ? 1 : -1 + ); foreach ($files as $file) { - if (!$file->isFile() || '.php' !== substr($file->getFilename(), -4)) { + if (!$file->isFile() || !str_ends_with($file->getFilename(), '.php')) { continue; } if ($class = $this->findClass($file)) { - $refl = new \ReflectionClass($class); - if ($refl->isAbstract()) { + $r = new \ReflectionClass($class); + if ($r->isAbstract()) { continue; } @@ -46,17 +40,17 @@ public function load($path, $type = null): SecurityPolicyRules return $rules; } - /** - * @param ?string $type - */ - public function supports($resource, $type = null): bool + public function supports(mixed $resource, ?string $type = null): bool { try { $path = $this->locator->locate($resource); - } catch (\Exception $e) { + } catch (\Exception) { return false; } - return is_string($resource) && is_dir($path) && (!$type || 'annotation' === $type); + return + is_string($resource) + && is_dir($path) + && (!$type || in_array($type, ['annotation', 'attribute'], true)); } } diff --git a/Loader/AnnotationFileLoader.php b/Loader/AnnotationFileLoader.php index 58d8936..1bec371 100644 --- a/Loader/AnnotationFileLoader.php +++ b/Loader/AnnotationFileLoader.php @@ -11,13 +11,7 @@ class AnnotationFileLoader extends FileLoader { protected AnnotationClassLoader $loader; - /** - * Constructor. - * - * @param FileLocator $locator A FileLocator instance - * @param AnnotationClassLoader $loader An AnnotationClassLoader instance - */ - public function __construct(FileLocator $locator, AnnotationClassLoader $loader, string $env = null) + public function __construct(FileLocator $locator, AnnotationClassLoader $loader, ?string $env = null) { if (!function_exists('token_get_all')) { throw new \RuntimeException('The Tokenizer extension is required for the routing annotation loaders.'); @@ -29,18 +23,11 @@ public function __construct(FileLocator $locator, AnnotationClassLoader $loader, } /** - * Loads from annotations from a file. - * - * @param string $file A PHP file path - * @param ?string $type The resource type - * - * @return SecurityPolicyRules A Rules instance - * - * @throws \InvalidArgumentException When annotations can't be parsed + * @param string $resource A PHP file path */ - public function load($file, $type = null): SecurityPolicyRules + public function load(mixed $resource, ?string $type = null): SecurityPolicyRules { - $path = $this->locator->locate($file); + $path = $this->locator->locate($resource); $rules = new SecurityPolicyRules(); if ($class = $this->findClass($path)) { @@ -51,22 +38,20 @@ public function load($file, $type = null): SecurityPolicyRules return $rules; } - /** - * @param ?string $type - */ - public function supports($resource, $type = null): bool + public function supports(mixed $resource, ?string $type = null): bool { - return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'annotation' === $type); + return + is_string($resource) + && 'php' === pathinfo($resource, PATHINFO_EXTENSION) + && (!$type || in_array($type, ['annotation', 'attribute'], true)); } /** * Returns the full class name for the first class in the file. * - * @param string $file A PHP file path - * - * @return class-string|false Full class name if found, false otherwise + * @return class-string|false */ - protected function findClass(string $file) + protected function findClass(string $file): string|false { $class = false; $namespace = false; @@ -117,7 +102,9 @@ protected function findClass(string $file) if (\T_DOUBLE_COLON === $tokens[$j][0] || \T_NEW === $tokens[$j][0]) { $skipClassToken = true; break; - } elseif (!\in_array($tokens[$j][0], [\T_WHITESPACE, \T_DOC_COMMENT, \T_COMMENT])) { + } + + if (!\in_array($tokens[$j][0], [\T_WHITESPACE, \T_DOC_COMMENT, \T_COMMENT])) { break; } } diff --git a/README.md b/README.md index e38d2c3..8cb97ae 100644 --- a/README.md +++ b/README.md @@ -2,49 +2,31 @@ ![CI](https://github.com/intaro/twig-sandbox-bundle/workflows/CI/badge.svg?branch=master) -There is [Twig](https://twig.symfony.com)-extension [Sandbox](https://twig.symfony.com/doc/2.x/api.html#sandbox-extension) which can be used to evaluate untrusted code and where access to unsafe attributes and methods is prohibited. This bundle allows to configure security policy for sandbox. +There is [Twig](https://twig.symfony.com)-extension [Sandbox](https://twig.symfony.com/doc/2.x/api.html#sandbox-extension) which can be used to evaluate untrusted code and where access to unsafe properties and methods is prohibited. This bundle allows to configure security policy for sandbox. ## Installation -TwigSandboxBundle requires Symfony 4.4 or higher. +TwigSandboxBundle requires Symfony 5.4 or higher. -Require the bundle in your `composer.json` file: +Install the bundle: -```json -{ - "require": { - "intaro/twig-sandbox-bundle": "^2.0" - } -} ``` - -Register the bundle in `AppKernel`: - -```php -// app/AppKernel.php - -public function registerBundles() -{ - $bundles = [ - //... - - new Intaro\TwigSandboxBundle\IntaroTwigSandboxBundle(), - ]; - - //... -} +$ composer require intaro/twig-sandbox-bundle ``` -Install the bundle: +Register the bundle in `config/bundles.php`: -``` -$ composer require intaro/twig-sandbox-bundle +```php +return [ + // ... + Intaro\TwigSandboxBundle\IntaroTwigSandboxBundle::class => ['all' => true], +]; ``` ## Usage -Define allowed properties and methods for your entities using annotation `@Sandbox`. -Optionally you can add `type` option for annotation. +Define allowed properties and methods for your entities using attribute `#[Sandbox]`. +Optionally you can add `type` option for attribute (for example `#[Sandbox(type: 'int')]`). This option defines type of value that property stores or method returns. In your application you can use annotation reader to extract value of `type` option and use this value @@ -59,97 +41,54 @@ namespace Acme\DemoBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Intaro\TwigSandboxBundle\Annotation\Sandbox; -/** - * @ORM\Table() - * @ORM\Entity - */ + #[ORM\Table] + #[ORM\Entity] class Product { - /** - * @var integer - * - * @ORM\Column(name="id", type="integer") - * @ORM\Id - * @ORM\GeneratedValue(strategy="AUTO") - */ - private $id; + #[ORM\Column(name: 'id', type: 'integer')] + #[ORM\Id] + #[ORM\GeneratedValue(strategy: "AUTO")] + private ?int $id = null; - /** - * @var string $name - * - * @Sandbox(type="string") - * @ORM\Column(name="name", type="string", length=255) - */ - private $name; - - /** - * @var integer $quantity - * - * @ORM\Column(name="quantity", type="integer", nullable=true) - */ - private $quantity; - - - /** - * Get id - * - * @Sandbox(type="int") - * @return integer - */ - public function getId() + #[ORM\Column(name: 'name', type: 'string', length: 255)] + #[Sandbox(type: 'string')] + private string $name = ''; + + #[ORM\Column(name: 'quantity', type: 'integer', nullable: true)] + private ?int $quantity = null; + + + #[Sandbox(type: 'int')] + public function getId(): ?int { return $this->id; } - /** - * Set name - * - * @param string $name - * @return Product - */ - public function setName($name) + public function setName(string $name): self { $this->name = $name; return $this; } - /** - * Get name - * - * @Sandbox - * @return string - */ - public function getName() + #[Sandbox] + public function getName(): string { return $this->name; } - /** - * Set quantity - * - * @param boolean $quantity - * @return Product - */ - public function setQuantity($quantity) + public function setQuantity(?int $quantity): self { $this->quantity = $quantity; return $this; } - /** - * Get quantity - * - * @return int - */ - public function getQuantity() + public function getQuantity(): ?int { return $this->quantity; } - } - ``` And use sandbox environment. @@ -174,20 +113,16 @@ class Example { $product->setName('Product 1'); $product->setQuantity(5); - //success render + // successful render $html1 = $twig->render( 'Product {{ product.name }}', - [ - 'product' => $product, - ] + ['product' => $product] ); - //render with exception + // render with the exception on access to the quantity method $html2 = $twig->render( 'Product {{ product.name }} in the quantity {{ product.quantity }}', - [ - 'product' => $product, - ] + ['product' => $product] ); } @@ -198,7 +133,7 @@ class Example { You can validate entity fields which contain twig templates with TwigSandbox validator. ```php -//in Entity/Page.php +// in Entity/Page.php use Intaro\TwigSandboxBundle\Validator\Constraints\TwigSandbox; @@ -220,7 +155,7 @@ class Page ### Methods and properties -You can define allowed methods and properties of entities with annotation `Intaro\TwigSandboxBundle\Annotation\Sandbox`. Example above. +You can define allowed methods and properties of entities with attribute `Intaro\TwigSandboxBundle\Attribute\Sandbox`. Example above. ### Tags @@ -353,7 +288,7 @@ $twig = $this->get(EnvironmentBuilder::class)->getSandboxEnvironment([ ]); ``` -Also you might want to add extensions to your twig environment. Example how to add: +Also, you might want to add extensions to your twig environment. Example how to add: ```php // Acme/DemoBundle/AcmeDemoBundle.php */ - private array $methods; - /** @var array */ - private array $properties; - /** @var ResourceInterface[] */ - private array $resources; - /** * @param array $methods * @param array $properties * @param ResourceInterface[] $resources */ - public function __construct(array $methods = [], array $properties = [], array $resources = []) - { - $this->methods = $methods; - $this->properties = $properties; - $this->resources = $resources; + public function __construct( + private array $methods = [], + private array $properties = [], + private array $resources = [], + ) { } /** @@ -76,11 +69,6 @@ public function getResources(): array return array_unique($this->resources); } - /** - * Adds a resource for this rules. - * - * @param ResourceInterface $resource A resource instance - */ public function addResource(ResourceInterface $resource): void { $this->resources[] = $resource; diff --git a/Validator/Constraints/TwigSandbox.php b/Validator/Constraints/TwigSandbox.php index f6f3904..75c6d5f 100644 --- a/Validator/Constraints/TwigSandbox.php +++ b/Validator/Constraints/TwigSandbox.php @@ -2,10 +2,12 @@ namespace Intaro\TwigSandboxBundle\Validator\Constraints; +use Symfony\Component\Validator\Constraint; + /** * @Annotation */ -class TwigSandbox extends \Symfony\Component\Validator\Constraint +class TwigSandbox extends Constraint { public string $message = 'This value is not a valid Twig template. The parsing error is: {{ syntax_error }}'; public string $criticalErrorMessage = 'Critical error occurred while rendering the template. Please check the correctness of template syntax.'; diff --git a/Validator/Constraints/TwigSandboxValidator.php b/Validator/Constraints/TwigSandboxValidator.php index 6adb6b7..42b0899 100644 --- a/Validator/Constraints/TwigSandboxValidator.php +++ b/Validator/Constraints/TwigSandboxValidator.php @@ -9,11 +9,9 @@ class TwigSandboxValidator extends ConstraintValidator { - private EnvironmentBuilder $builder; - - public function __construct(EnvironmentBuilder $builder) - { - $this->builder = $builder; + public function __construct( + private readonly EnvironmentBuilder $builder, + ) { } public function getTwig(): TwigAdapter @@ -22,10 +20,9 @@ public function getTwig(): TwigAdapter } /** - * @param mixed $value * @param TwigSandbox $constraint */ - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$value) { return; @@ -40,19 +37,15 @@ public function validate($value, Constraint $constraint): void $this->context->addViolation($constraint->message, [ '{{ syntax_error }}' => $message, - ]); + ]); } catch (\Twig\Error\SyntaxError $e) { $message = mb_strlen($e->getMessage()) > 150 ? mb_substr($e->getMessage(), 0, 150) . '…' : $e->getMessage(); $this->context->addViolation($constraint->message, [ '{{ syntax_error }}' => $message, - ]); - } catch (\Error $e) { - goto ex_r; - } catch (\Exception $e) { - ex_r: - - $this->context->addViolation($constraint->criticalErrorMessage); + ]); + } catch (\Error|\Exception) { + $this->context->addViolation($constraint->criticalErrorMessage); } } } diff --git a/composer.json b/composer.json index b999565..485abd8 100644 --- a/composer.json +++ b/composer.json @@ -15,11 +15,11 @@ } ], "require": { - "doctrine/annotations": "^1.13", - "php": "^7.4 || ^8.0", + "doctrine/annotations": "^1.13|^2.0", + "php": "^8.1", "psr/cache": "~1.0|~2.0", - "symfony/framework-bundle": "^4.4|^5.0|^6.0", - "symfony/validator": "^4.4|^5.0|^6.0", + "symfony/framework-bundle": "^5.0|^6.0", + "symfony/validator": "^5.0|^6.0", "twig/twig": "^2.14 | ^3.0" }, "autoload": { @@ -28,28 +28,28 @@ } }, "require-dev": { - "nyholm/symfony-bundle-test": "^2.0", + "nyholm/symfony-bundle-test": "^3.0", "phpstan/phpstan": "^1.0", "phpstan/phpstan-symfony": "^1.0", - "phpunit/phpunit": "^8.5", - "symfony/phpunit-bridge": "^5.0", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/http-kernel": "^4.4|^5.0|^6.0", - "symfony/http-foundation": "^4.4|^5.0|^6.0", - "symfony/yaml": "^4.4|^5.0|^6.0", + "phpunit/phpunit": "^8.5|^9.5", + "symfony/phpunit-bridge": "^5.0|^6.0", + "symfony/config": "^5.0|^6.0", + "symfony/dependency-injection": "^5.0|^6.0", + "symfony/event-dispatcher": "^5.0|^6.0", + "symfony/error-handler": "^5.0|^6.0", + "symfony/http-kernel": "^5.0|^6.0", + "symfony/http-foundation": "^5.0|^6.0", + "symfony/yaml": "^5.0|^6.0", "symfony/deprecation-contracts": "^1.1|^2.0", "symfony/event-dispatcher-contracts": "^1.1|^2.0", - "symfony/routing": "^4.4|^5.0|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/routing": "^5.0|^6.0", + "symfony/finder": "^5.0|^6.0", + "symfony/filesystem": "^5.0|^6.0", "symfony/translation-contracts": "^1.1|^2.0", - "symfony/var-exporter": "^4.4|^5.0|^6.0", - "symfony/var-dumper": "^4.4|^5.0|^6.0", + "symfony/var-exporter": "^5.0|^6.0", + "symfony/var-dumper": "^5.0|^6.0", "psr/log": "~1.0", - "friendsofphp/php-cs-fixer": "3.4" + "friendsofphp/php-cs-fixer": "^3" }, "autoload-dev": { "psr-4": { diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 625a23c..b068363 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,10 +1,6 @@ parameters: ignoreErrors: - - - message: "#^Call to an undefined method Symfony\\\\Component\\\\Config\\\\Definition\\\\Builder\\\\TreeBuilder::root\\(\\)\\.$#" - count: 1 - path: DependencyInjection/Configuration.php - message: "#Dead catch - .+? is never thrown in the try block#" - count: 2 + count: 1 path: Validator/Constraints/TwigSandboxValidator.php diff --git a/tests/BundleInitializationTest.php b/tests/BundleInitializationTest.php index b4ddcf7..cb05b2c 100644 --- a/tests/BundleInitializationTest.php +++ b/tests/BundleInitializationTest.php @@ -39,7 +39,7 @@ public function testInitBundle(): void $container = property_exists(__CLASS__, 'container') ? self::$container : self::getContainer(); $this->assertTrue($container->has(EnvironmentBuilder::class)); - $this->assertTrue($container->has(\Intaro\TwigSandboxBundle\Builder\EnvironmentBuilder::class)); + $this->assertTrue($container->has(EnvironmentBuilder::class)); $service = $container->get(EnvironmentBuilder::class); $this->assertInstanceOf(EnvironmentBuilder::class, $service); } diff --git a/tests/SimpleTest.php b/tests/SimpleTest.php index 1cb6a68..af57318 100644 --- a/tests/SimpleTest.php +++ b/tests/SimpleTest.php @@ -3,12 +3,16 @@ namespace Intaro\TwigSandboxBundle\Tests; use Intaro\TwigSandboxBundle\Builder\EnvironmentBuilder; +use Intaro\TwigSandboxBundle\Dumper\PhpDumper; use Intaro\TwigSandboxBundle\Loader\AnnotationClassLoader; use Intaro\TwigSandboxBundle\Loader\AnnotationDirectoryLoader; use Intaro\TwigSandboxBundle\Loader\AnnotationFileLoader; use Intaro\TwigSandboxBundle\Tests\fixtures\Entity\Product; use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; +use Symfony\Component\Config\Loader\DelegatingLoader; +use Symfony\Component\Config\Loader\LoaderResolver; +use Twig\Sandbox\SecurityPolicy; class SimpleTest extends TestCase { @@ -37,23 +41,22 @@ public function testRender(): void private function createTwigEnv() { - $annotationClassLoader = new AnnotationClassLoader(new \Doctrine\Common\Annotations\AnnotationReader()); + $annotationClassLoader = new AnnotationClassLoader(); $annotationDirectoryLoader = new AnnotationDirectoryLoader(new FileLocator(), $annotationClassLoader); $annotationFileLoader = new AnnotationFileLoader(new FileLocator(), $annotationClassLoader); - $loaderResolver = new \Symfony\Component\Config\Loader\LoaderResolver([ - $annotationDirectoryLoader, - $annotationFileLoader, - $annotationClassLoader, - ] - ); + $loaderResolver = new LoaderResolver([ + $annotationDirectoryLoader, + $annotationFileLoader, + $annotationClassLoader, + ]); - $loader = new \Symfony\Component\Config\Loader\DelegatingLoader($loaderResolver); - $securityPolicy = new \Twig\Sandbox\SecurityPolicy([], ['escape']); + $loader = new DelegatingLoader($loaderResolver); + $securityPolicy = new SecurityPolicy([], ['escape']); $builder = new EnvironmentBuilder( $loader, - new \Intaro\TwigSandboxBundle\Dumper\PhpDumper(), + new PhpDumper(), $securityPolicy, [ 'cache_dir' => __DIR__, diff --git a/tests/fixtures/Entity/Product.php b/tests/fixtures/Entity/Product.php index 303ad83..264c0d5 100644 --- a/tests/fixtures/Entity/Product.php +++ b/tests/fixtures/Entity/Product.php @@ -2,7 +2,7 @@ namespace Intaro\TwigSandboxBundle\Tests\fixtures\Entity; -use Intaro\TwigSandboxBundle\Annotation\Sandbox; +use Intaro\TwigSandboxBundle\Attribute\Sandbox; class Product { @@ -13,10 +13,9 @@ class Product /** * Get id * - * @Sandbox(type="int") - * * @return int */ + #[Sandbox(type: 'int')] public function getId() { return $this->id; @@ -39,10 +38,9 @@ public function setName($name) /** * Get name * - * @Sandbox - * * @return string */ + #[Sandbox] public function getName() { return $this->name;