Вход Регистрация
Файл: vendor/laravel/framework/src/Illuminate/View/Component.php
Строк: 439
<?php

namespace IlluminateView;

use 
Closure;
use 
IlluminateContainerContainer;
use 
IlluminateContractsSupportHtmlable;
use 
IlluminateContractsViewView as ViewContract;
use 
ReflectionClass;
use 
ReflectionMethod;
use 
ReflectionProperty;

abstract class 
Component
{
    
/**
     * The properties / methods that should not be exposed to the component.
     *
     * @var array
     */
    
protected $except = [];

    
/**
     * The component alias name.
     *
     * @var string
     */
    
public $componentName;

    
/**
     * The component attributes.
     *
     * @var IlluminateViewComponentAttributeBag
     */
    
public $attributes;

    
/**
     * The view factory instance, if any.
     *
     * @var IlluminateContractsViewFactory|null
     */
    
protected static $factory;

    
/**
     * The component resolver callback.
     *
     * @var (Closure(string, array): Component)|null
     */
    
protected static $componentsResolver;

    
/**
     * The cache of blade view names, keyed by contents.
     *
     * @var array<string, string>
     */
    
protected static $bladeViewCache = [];

    
/**
     * The cache of public property names, keyed by class.
     *
     * @var array
     */
    
protected static $propertyCache = [];

    
/**
     * The cache of public method names, keyed by class.
     *
     * @var array
     */
    
protected static $methodCache = [];

    
/**
     * The cache of constructor parameters, keyed by class.
     *
     * @var array<class-string, array<int, string>>
     */
    
protected static $constructorParametersCache = [];

    
/**
     * Get the view / view contents that represent the component.
     *
     * @return IlluminateContractsViewView|IlluminateContractsSupportHtmlable|Closure|string
     */
    
abstract public function render();

    
/**
     * Resolve the component instance with the given data.
     *
     * @param  array  $data
     * @return static
     */
    
public static function resolve($data)
    {
        if (static::
$componentsResolver) {
            return 
call_user_func(static::$componentsResolver, static::class, $data);
        }

        
$parameters = static::extractConstructorParameters();

        
$dataKeys array_keys($data);

        if (empty(
array_diff($parameters$dataKeys))) {
            return new static(...
array_intersect_key($dataarray_flip($parameters)));
        }

        return 
Container::getInstance()->make(static::class, $data);
    }

    
/**
     * Extract the constructor parameters for the component.
     *
     * @return array
     */
    
protected static function extractConstructorParameters()
    {
        if (! isset(static::
$constructorParametersCache[static::class])) {
            
$class = new ReflectionClass(static::class);

            
$constructor $class->getConstructor();

            static::
$constructorParametersCache[static::class] = $constructor
                
collect($constructor->getParameters())->map->getName()->all()
                : [];
        }

        return static::
$constructorParametersCache[static::class];
    }

    
/**
     * Resolve the Blade view or view file that should be used when rendering the component.
     *
     * @return IlluminateContractsViewView|IlluminateContractsSupportHtmlable|Closure|string
     */
    
public function resolveView()
    {
        
$view $this->render();

        if (
$view instanceof ViewContract) {
            return 
$view;
        }

        if (
$view instanceof Htmlable) {
            return 
$view;
        }

        
$resolver = function ($view) {
            if (
$view instanceof ViewContract) {
                return 
$view;
            }

            return 
$this->extractBladeViewFromString($view);
        };

        return 
$view instanceof Closure ? function (array $data = []) use ($view$resolver) {
            return 
$resolver($view($data));
        }
        : 
$resolver($view);
    }

    
/**
     * Create a Blade view with the raw component string content.
     *
     * @param  string  $contents
     * @return string
     */
    
protected function extractBladeViewFromString($contents)
    {
        
$key sprintf('%s::%s', static::class, $contents);

        if (isset(static::
$bladeViewCache[$key])) {
            return static::
$bladeViewCache[$key];
        }

        if (
strlen($contents) <= PHP_MAXPATHLEN && $this->factory()->exists($contents)) {
            return static::
$bladeViewCache[$key] = $contents;
        }

        return static::
$bladeViewCache[$key] = $this->createBladeViewFromString($this->factory(), $contents);
    }

    
/**
     * Create a Blade view with the raw component string content.
     *
     * @param  IlluminateContractsViewFactory  $factory
     * @param  string  $contents
     * @return string
     */
    
protected function createBladeViewFromString($factory$contents)
    {
        
$factory->addNamespace(
            
'__components',
            
$directory Container::getInstance()['config']->get('view.compiled')
        );

        if (! 
is_file($viewFile $directory.'/'.hash('xxh128'$contents).'.blade.php')) {
            if (! 
is_dir($directory)) {
                
mkdir($directory0755true);
            }

            
file_put_contents($viewFile$contents);
        }

        return 
'__components::'.basename($viewFile'.blade.php');
    }

    
/**
     * Get the data that should be supplied to the view.
     *
     * @author Freek Van der Herten
     * @author Brent Roose
     *
     * @return array
     */
    
public function data()
    {
        
$this->attributes $this->attributes ?: $this->newAttributeBag();

        return 
array_merge($this->extractPublicProperties(), $this->extractPublicMethods());
    }

    
/**
     * Extract the public properties for the component.
     *
     * @return array
     */
    
protected function extractPublicProperties()
    {
        
$class get_class($this);

        if (! isset(static::
$propertyCache[$class])) {
            
$reflection = new ReflectionClass($this);

            static::
$propertyCache[$class] = collect($reflection->getProperties(ReflectionProperty::IS_PUBLIC))
                ->
reject(function (ReflectionProperty $property) {
                    return 
$property->isStatic();
                })
                ->
reject(function (ReflectionProperty $property) {
                    return 
$this->shouldIgnore($property->getName());
                })
                ->
map(function (ReflectionProperty $property) {
                    return 
$property->getName();
                })->
all();
        }

        
$values = [];

        foreach (static::
$propertyCache[$class] as $property) {
            
$values[$property] = $this->{$property};
        }

        return 
$values;
    }

    
/**
     * Extract the public methods for the component.
     *
     * @return array
     */
    
protected function extractPublicMethods()
    {
        
$class get_class($this);

        if (! isset(static::
$methodCache[$class])) {
            
$reflection = new ReflectionClass($this);

            static::
$methodCache[$class] = collect($reflection->getMethods(ReflectionMethod::IS_PUBLIC))
                ->
reject(function (ReflectionMethod $method) {
                    return 
$this->shouldIgnore($method->getName());
                })
                ->
map(function (ReflectionMethod $method) {
                    return 
$method->getName();
                });
        }

        
$values = [];

        foreach (static::
$methodCache[$class] as $method) {
            
$values[$method] = $this->createVariableFromMethod(new ReflectionMethod($this$method));
        }

        return 
$values;
    }

    
/**
     * Create a callable variable from the given method.
     *
     * @param  ReflectionMethod  $method
     * @return mixed
     */
    
protected function createVariableFromMethod(ReflectionMethod $method)
    {
        return 
$method->getNumberOfParameters() === 0
                        
$this->createInvokableVariable($method->getName())
                        : 
Closure::fromCallable([$this$method->getName()]);
    }

    
/**
     * Create an invokable, toStringable variable for the given component method.
     *
     * @param  string  $method
     * @return IlluminateViewInvokableComponentVariable
     */
    
protected function createInvokableVariable(string $method)
    {
        return new 
InvokableComponentVariable(function () use ($method) {
            return 
$this->{$method}();
        });
    }

    
/**
     * Determine if the given property / method should be ignored.
     *
     * @param  string  $name
     * @return bool
     */
    
protected function shouldIgnore($name)
    {
        return 
str_starts_with($name'__') ||
               
in_array($name$this->ignoredMethods());
    }

    
/**
     * Get the methods that should be ignored.
     *
     * @return array
     */
    
protected function ignoredMethods()
    {
        return 
array_merge([
            
'data',
            
'render',
            
'resolve',
            
'resolveView',
            
'shouldRender',
            
'view',
            
'withName',
            
'withAttributes',
            
'flushCache',
            
'forgetFactory',
            
'forgetComponentsResolver',
            
'resolveComponentsUsing',
        ], 
$this->except);
    }

    
/**
     * Set the component alias name.
     *
     * @param  string  $name
     * @return $this
     */
    
public function withName($name)
    {
        
$this->componentName $name;

        return 
$this;
    }

    
/**
     * Set the extra attributes that the component should make available.
     *
     * @param  array  $attributes
     * @return $this
     */
    
public function withAttributes(array $attributes)
    {
        
$this->attributes $this->attributes ?: $this->newAttributeBag();

        
$this->attributes->setAttributes($attributes);

        return 
$this;
    }

    
/**
     * Get a new attribute bag instance.
     *
     * @param  array  $attributes
     * @return IlluminateViewComponentAttributeBag
     */
    
protected function newAttributeBag(array $attributes = [])
    {
        return new 
ComponentAttributeBag($attributes);
    }

    
/**
     * Determine if the component should be rendered.
     *
     * @return bool
     */
    
public function shouldRender()
    {
        return 
true;
    }

    
/**
     * Get the evaluated view contents for the given view.
     *
     * @param  string|null  $view
     * @param  IlluminateContractsSupportArrayable|array  $data
     * @param  array  $mergeData
     * @return IlluminateContractsViewView
     */
    
public function view($view$data = [], $mergeData = [])
    {
        return 
$this->factory()->make($view$data$mergeData);
    }

    
/**
     * Get the view factory instance.
     *
     * @return IlluminateContractsViewFactory
     */
    
protected function factory()
    {
        if (
is_null(static::$factory)) {
            static::
$factory Container::getInstance()->make('view');
        }

        return static::
$factory;
    }

    
/**
     * Flush the component's cached state.
     *
     * @return void
     */
    
public static function flushCache()
    {
        static::
$bladeViewCache = [];
        static::
$constructorParametersCache = [];
        static::
$methodCache = [];
        static::
$propertyCache = [];
    }

    
/**
     * Forget the component's factory instance.
     *
     * @return void
     */
    
public static function forgetFactory()
    {
        static::
$factory null;
    }

    
/**
     * Forget the component's resolver callback.
     *
     * @return void
     *
     * @internal
     */
    
public static function forgetComponentsResolver()
    {
        static::
$componentsResolver null;
    }

    
/**
     * Set the callback that should be used to resolve components within views.
     *
     * @param  Closure(string $component, array $data): Component  $resolver
     * @return void
     *
     * @internal
     */
    
public static function resolveComponentsUsing($resolver)
    {
        static::
$componentsResolver $resolver;
    }
}
Онлайн: 0
Реклама