Вход Регистрация
Файл: upload/core/vendor/twig/twig/src/Extension/AttributeExtension.php
Строк: 260
<?php

/*
 * This file is part of Twig.
 *
 * (c) Fabien Potencier
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace TwigExtension;

use 
TwigAttributeAsTwigFilter;
use 
TwigAttributeAsTwigFunction;
use 
TwigAttributeAsTwigTest;
use 
TwigEnvironment;
use 
TwigTwigFilter;
use 
TwigTwigFunction;
use 
TwigTwigTest;

/**
 * Define Twig filters, functions, and tests with PHP attributes.
 *
 * @author Jérôme Tamarelle <jerome@tamarelle.net>
 */
final class AttributeExtension extends AbstractExtension
{
    private array 
$filters;
    private array 
$functions;
    private array 
$tests;

    
/**
     * Use a runtime class using PHP attributes to define filters, functions, and tests.
     *
     * @param class-string $class
     */
    
public function __construct(private string $class)
    {
    }

    
/**
     * @return class-string
     */
    
public function getClass(): string
    
{
        return 
$this->class;
    }

    public function 
getFilters(): array
    {
        if (!isset(
$this->filters)) {
            
$this->initFromAttributes();
        }

        return 
$this->filters;
    }

    public function 
getFunctions(): array
    {
        if (!isset(
$this->functions)) {
            
$this->initFromAttributes();
        }

        return 
$this->functions;
    }

    public function 
getTests(): array
    {
        if (!isset(
$this->tests)) {
            
$this->initFromAttributes();
        }

        return 
$this->tests;
    }

    public function 
getLastModified(): int
    
{
        return 
max(
            
filemtime(__FILE__),
            
is_file($filename = (new ReflectionClass($this->getClass()))->getFileName()) ? filemtime($filename) : 0,
        );
    }

    private function 
initFromAttributes(): void
    
{
        
$filters $functions $tests = [];
        
$reflectionClass = new ReflectionClass($this->getClass());
        foreach (
$reflectionClass->getMethods() as $method) {
            foreach (
$method->getAttributes(AsTwigFilter::class) as $reflectionAttribute) {
                
/** @var AsTwigFilter $attribute */
                
$attribute $reflectionAttribute->newInstance();

                
$callable = new TwigFilter($attribute->name, [$reflectionClass->name$method->getName()], [
                    
'needs_context' => $attribute->needsContext ?? false,
                    
'needs_environment' => $attribute->needsEnvironment ?? $this->needsEnvironment($method),
                    
'needs_charset' => $attribute->needsCharset ?? false,
                    
'is_variadic' => $method->isVariadic(),
                    
'is_safe' => $attribute->isSafe,
                    
'is_safe_callback' => $attribute->isSafeCallback,
                    
'pre_escape' => $attribute->preEscape,
                    
'preserves_safety' => $attribute->preservesSafety,
                    
'deprecation_info' => $attribute->deprecationInfo,
                ]);

                if (
$callable->getMinimalNumberOfRequiredArguments() > $method->getNumberOfParameters()) {
                    throw new 
LogicException(sprintf('"%s::%s()" needs at least %d arguments to be used AsTwigFilter, but only %d defined.'$reflectionClass->getName(), $method->getName(), $callable->getMinimalNumberOfRequiredArguments(), $method->getNumberOfParameters()));
                }

                
$filters[$attribute->name] = $callable;
            }

            foreach (
$method->getAttributes(AsTwigFunction::class) as $reflectionAttribute) {
                
/** @var AsTwigFunction $attribute */
                
$attribute $reflectionAttribute->newInstance();

                
$callable = new TwigFunction($attribute->name, [$reflectionClass->name$method->getName()], [
                    
'needs_context' => $attribute->needsContext ?? false,
                    
'needs_environment' => $attribute->needsEnvironment ?? $this->needsEnvironment($method),
                    
'needs_charset' => $attribute->needsCharset ?? false,
                    
'is_variadic' => $method->isVariadic(),
                    
'is_safe' => $attribute->isSafe,
                    
'is_safe_callback' => $attribute->isSafeCallback,
                    
'deprecation_info' => $attribute->deprecationInfo,
                ]);

                if (
$callable->getMinimalNumberOfRequiredArguments() > $method->getNumberOfParameters()) {
                    throw new 
LogicException(sprintf('"%s::%s()" needs at least %d arguments to be used AsTwigFunction, but only %d defined.'$reflectionClass->getName(), $method->getName(), $callable->getMinimalNumberOfRequiredArguments(), $method->getNumberOfParameters()));
                }

                
$functions[$attribute->name] = $callable;
            }

            foreach (
$method->getAttributes(AsTwigTest::class) as $reflectionAttribute) {
                
/** @var AsTwigTest $attribute */
                
$attribute $reflectionAttribute->newInstance();

                
$callable = new TwigTest($attribute->name, [$reflectionClass->name$method->getName()], [
                    
'needs_context' => $attribute->needsContext ?? false,
                    
'needs_environment' => $attribute->needsEnvironment ?? $this->needsEnvironment($method),
                    
'needs_charset' => $attribute->needsCharset ?? false,
                    
'is_variadic' => $method->isVariadic(),
                    
'deprecation_info' => $attribute->deprecationInfo,
                ]);

                if (
$callable->getMinimalNumberOfRequiredArguments() > $method->getNumberOfParameters()) {
                    throw new 
LogicException(sprintf('"%s::%s()" needs at least %d arguments to be used AsTwigTest, but only %d defined.'$reflectionClass->getName(), $method->getName(), $callable->getMinimalNumberOfRequiredArguments(), $method->getNumberOfParameters()));
                }

                
$tests[$attribute->name] = $callable;
            }
        }

        
// Assign all at the end to avoid inconsistent state in case of exception
        
$this->filters array_values($filters);
        
$this->functions array_values($functions);
        
$this->tests array_values($tests);
    }

    
/**
     * Detect if the first argument of the method is the environment.
     */
    
private function needsEnvironment(ReflectionFunctionAbstract $function): bool
    
{
        if (!
$parameters $function->getParameters()) {
            return 
false;
        }

        return 
$parameters[0]->getType() instanceof ReflectionNamedType
            
&& Environment::class === $parameters[0]->getType()->getName()
            && !
$parameters[0]->isVariadic();
    }
}
Онлайн: 0
Реклама