File manager - Edit - /home/opticamezl/www/newok/builder-source.tar
Back
config/customizer.json 0000644 00000006647 15174511643 0011134 0 ustar 00 { "sources": { "filters": { "before": { "label": "Before", "description": "Add text before the content field." }, "after": { "label": "After", "description": "Add text after the content field." }, "search": { "label": "Search", "description": "Select a predefined search pattern or enter a custom string or regular expression to search for. The regular expression has to be enclosed between slashes. For example `my-string` or `/ab+c/`.", "type": "data-list", "options": { "URL Protocol": "/https?:\\/\\//", "Hyphen and Underscore": "/[\\-_]/" } }, "replace": { "label": "Replace", "description": "Enter the replacement string which may contain references. If left empty, the search matches will be removed." }, "limit": { "label": "Content Length", "description": "Limit the content length to a number of characters. All HTML elements will be stripped.", "type": "number", "attrs": { "placeholder": "No limit." } }, "preserve": { "type": "checkbox", "text": "Preserve words" }, "date": { "label": "Date Format", "description": "Select a predefined date format or enter a custom format.", "type": "data-list", "default": "", "options": { "Aug 6, 1999 (M j, Y)": "M j, Y", "August 06, 1999 (F d, Y)": "F d, Y", "08/06/1999 (m/d/Y)": "m/d/Y", "08.06.1999 (m.d.Y)": "m.d.Y", "6 Aug, 1999 (j M, Y)": "j M, Y", "Tuesday, Aug 06 (l, M d)": "l, M d", "15:00 (G:i)": "G:i", "3:00 pm (g:i A)": "g:i a" }, "attrs": { "placeholder": "Default" } } }, "directives": { "slice": { "fields": { "_grid": { "description": "Set the starting point and limit the number of items.", "type": "grid", "width": "1-2", "fields": { "offset": { "label": "Start", "type": "number", "default": 0, "modifier": 1, "attrs": { "min": 1, "required": true } }, "limit": { "label": "Quantity", "type": "limit", "attrs": { "placeholder": "No limit", "min": 0 } } } } } } } } } config/builder.json 0000644 00000007517 15174511643 0010353 0 ustar 00 { "source": { "type": "fields", "fields": { "_source": { "label": "Dynamic Content", "type": "source-select", "description": "Select a content source to make its fields available for mapping. Choose between sources of the current page or query a custom source." }, "_sourceArgs": { "type": "source-query-args" }, "_sourceField": { "label": "Multiple Items Source", "type": "source-field-select", "description": "By default, fields of related sources with single items are available for mapping. Select a related source which has multiple items to map its fields.", "show": "yootheme.builder.helpers.Source.showMultipleSelectField(this.builder.path(this.node))" }, "_sourceFieldArgs": { "type": "source-field-args" }, "_sourceFieldDirectives": { "type": "source-field-directives" }, "_sourceCondition": { "type": "fields", "fields": { "_sourceConditionProp": { "label": "Dynamic Condition", "prop": "_condition", "type": "source-prop-select", "description": "Set a condition to display the element or its item depending on the content of a field." }, "_sourceConditionArgs": { "type": "source-prop-filters", "prop": "_condition", "fields": { "_grid": { "type": "grid", "width": "1-2", "fields": { "condition": { "label": "Condition", "type": "select", "default": "!!", "options": { "Is empty": "!", "Is not empty": "!!", "Is equal to": "=", "Is not equal to": "!=", "Contains": "~=", "Does not contain": "!~=", "Less than": "<", "Greater than": ">", "Starts with": "^=", "Does not start with": "!^=", "Ends with": "$=", "Does not end with": "!$=", "Matches a RegExp": "regex" }, "enable": "!show_empty" }, "condition_value": { "label": "Value", "enable": "!show_empty && $match(condition, '=|<|>|regex')" } } }, "show_empty": { "type": "checkbox", "text": "Show element only if dynamic content is empty" } } } }, "show": "yootheme.builder.helpers.Source.getSourceField(this.builder.path(this.node))" } } } } src/Source.php 0000644 00000004746 15174511643 0007326 0 ustar 00 <?php namespace YOOtheme\Builder; use YOOtheme\Event; use YOOtheme\GraphQL\Executor\ExecutionResult; use YOOtheme\GraphQL\GraphQL; use YOOtheme\GraphQL\SchemaBuilder; use YOOtheme\GraphQL\Type\Schema; use YOOtheme\GraphQL\Utils\AST; use YOOtheme\GraphQL\Utils\Introspection; class Source extends SchemaBuilder { /** * @var Schema|null */ protected $schema; /** * Gets the schema. * * @return Schema */ public function getSchema() { return $this->schema ?: ($this->schema = $this->buildSchema()); } /** * Sets the schema. * * @param Schema $schema * * @return Schema */ public function setSchema(Schema $schema) { return $this->schema = $schema; } /** * Executes a query on schema. * * @param mixed $source * @param mixed $value * @param mixed $context * @param array|null $variables * @param string|null $operation * @param callable $fieldResolver * @param array $validationRules * * @return ExecutionResult */ public function query( $source, $value = null, $context = null, $variables = null, $operation = null, $fieldResolver = null, $validationRules = null ) { if (is_array($source)) { $source = AST::fromArray($source); } return GraphQL::executeQuery( $this->getSchema(), $source, $value, $context, $variables, $operation, $fieldResolver, $validationRules, ); } /** * Executes an introspection on schema. * * @param array $options * * @return ExecutionResult */ public function queryIntrospection(array $options = []) { $metadata = [ 'type' => $this->getType('Object'), 'resolve' => fn($type) => Event::emit( 'source.type.metadata|filter', $type->config['metadata'] ?? null, $type, ), ]; $options += [ '__Type' => compact('metadata'), '__Field' => compact('metadata'), '__Directive' => compact('metadata'), '__InputValue' => compact('metadata'), ]; return GraphQL::executeQuery( $this->getSchema(), Introspection::getIntrospectionQuery($options), ); } } src/Source/Type/RequestType.php 0000644 00000006607 15174511643 0012537 0 ustar 00 <?php namespace YOOtheme\Builder\Source\Type; use function YOOtheme\trans; use YOOtheme\Http\Request; class RequestType { /** * @return array */ public static function config() { return [ 'fields' => [ 'url' => [ 'type' => 'String', 'metadata' => [ 'label' => trans('URL'), ], 'extensions' => [ 'call' => __CLASS__ . '::resolveUrl', ], ], 'method' => [ 'type' => 'String', 'metadata' => [ 'label' => trans('Method'), ], 'extensions' => [ 'call' => __CLASS__ . '::resolveMethod', ], ], 'scheme' => [ 'type' => 'String', 'metadata' => [ 'label' => trans('Scheme'), ], 'extensions' => [ 'call' => __CLASS__ . '::resolveScheme', ], ], 'host' => [ 'type' => 'String', 'metadata' => [ 'label' => trans('Host'), ], 'extensions' => [ 'call' => __CLASS__ . '::resolveHost', ], ], 'port' => [ 'type' => 'String', 'metadata' => [ 'label' => trans('Port'), ], 'extensions' => [ 'call' => __CLASS__ . '::resolvePort', ], ], 'path' => [ 'type' => 'String', 'metadata' => [ 'label' => trans('Path'), ], 'extensions' => [ 'call' => __CLASS__ . '::resolvePath', ], ], 'query' => [ 'type' => 'String', 'metadata' => [ 'label' => trans('Query'), ], 'extensions' => [ 'call' => __CLASS__ . '::resolveQuery', ], ], ], 'metadata' => [ 'type' => true, 'label' => trans('Request'), ], ]; } public static function resolveUrl(Request $request) { return (string) $request->getUri(); } public static function resolveMethod(Request $request) { return $request->getMethod(); } public static function resolveScheme(Request $request) { return $request->getUri()->getScheme(); } public static function resolveHost(Request $request) { return $request->getUri()->getHost(); } public static function resolvePort(Request $request) { return $request->getUri()->getPort(); } public static function resolvePath(Request $request) { return $request->getUri()->getPath(); } public static function resolveQuery(Request $request) { return $request->getUri()->getQuery(); } } src/Source/Type/SiteType.php 0000644 00000006502 15174511643 0012005 0 ustar 00 <?php namespace YOOtheme\Builder\Source\Type; use YOOtheme\Config; use YOOtheme\Http\Request; use function YOOtheme\app; use function YOOtheme\trans; class SiteType { /** * @return array */ public static function config() { return [ 'fields' => [ 'title' => [ 'type' => 'String', 'metadata' => [ 'label' => trans('Site Title'), 'filters' => ['limit', 'preserve'], ], ], 'page_title' => [ 'type' => 'String', 'metadata' => [ 'label' => trans('Page Title'), 'filters' => ['limit', 'preserve'], ], ], 'page_locale' => [ 'type' => 'String', 'metadata' => [ 'label' => trans('Page Locale'), ], 'extensions' => [ 'call' => __CLASS__ . '::resolvePageLocale', ], ], 'page_url' => [ 'type' => 'String', 'args' => [ 'query' => [ 'type' => 'Boolean', ], ], 'metadata' => [ 'label' => trans('Page URL'), 'arguments' => [ 'query' => [ 'label' => trans('Query String'), 'type' => 'checkbox', 'text' => trans('Include query string'), 'default' => false, ], ], ], 'extensions' => [ 'call' => __CLASS__ . '::resolvePageUrl', ], ], 'is_guest' => [ 'type' => 'Int', 'metadata' => [ 'label' => trans('Guest User'), 'condition' => true, ], ], 'user' => [ 'type' => 'User', 'metadata' => [ 'label' => trans('Current User'), ], ], 'request' => [ 'type' => 'Request', 'metadata' => [ 'label' => trans('Request'), ], 'extensions' => [ 'call' => __CLASS__ . '::resolveRequest', ], ], ], 'metadata' => [ 'type' => true, 'label' => trans('Site'), ], ]; } public static function resolveRequest() { return app(Request::class); } public static function resolvePageUrl($obj, array $args) { $uri = static::resolveRequest()->getUri(); return $uri->getPath() . ($args['query'] ? "?{$uri->getQuery()}" : ''); } public static function resolvePageLocale() { return app(Config::class)('locale.code'); } } src/Source/Listener/LoadBuilderConfig.php 0000644 00000002016 15174511643 0014413 0 ustar 00 <?php namespace YOOtheme\Builder\Source\Listener; use YOOtheme\Builder\BuilderConfig; use YOOtheme\Builder\Source; use YOOtheme\Config; use YOOtheme\GraphQL\SchemaPrinter; class LoadBuilderConfig { public Config $config; public Source $source; public function __construct(Config $config, Source $source) { $this->config = $config; $this->source = $source; } /** * @param BuilderConfig $config */ public function handle($config): void { $dir = $this->config->get('image.cacheDir'); $file = "{$dir}/schema-{$this->config->get('source.id')}.gql"; $result = $this->source->queryIntrospection()->toArray(); $content = SchemaPrinter::doPrint($this->source->getSchema()); // update schema cache if (isset($result['data'])) { file_put_contents($file, $content); } elseif (is_file($file)) { unlink($file); } $config->merge(['schema' => $result['data']['__schema'] ?? $result]); } } src/Source/Listener/OrderSourceMetadata.php 0000644 00000000600 15174511643 0014771 0 ustar 00 <?php namespace YOOtheme\Builder\Source\Listener; class OrderSourceMetadata { public static function handle($metadata) { if (!empty($metadata['fields'])) { uasort( $metadata['fields'], fn($fieldA, $fieldB) => ($fieldA['@order'] ?? 0) - ($fieldB['@order'] ?? 0), ); } return $metadata; } } src/Source/Listener/LoadSourceSchema.php 0000644 00000002630 15174511643 0014262 0 ustar 00 <?php namespace YOOtheme\Builder\Source\Listener; use YOOtheme\Builder\Source; use YOOtheme\Config; use YOOtheme\Event; use YOOtheme\File; use YOOtheme\GraphQL\Error\Error; use YOOtheme\Http\Request; class LoadSourceSchema { public Config $config; public Request $request; public function __construct(Config $config, Request $request) { $this->config = $config; $this->request = $request; } /** * @param Source $source * @return bool|null */ public function handle($source): ?bool { $dir = $this->config->get('image.cacheDir'); $name = "schema-{$this->config->get('source.id')}"; $file = "{$dir}/{$name}.gql"; try { if ( $this->config->get('app.isSite') && !$this->request->getAttribute('customizer') && is_file($file) && filectime($file) > filectime(__FILE__) ) { // load schema from cache $hash = hash('crc32b', $file); $source->setSchema($source->loadSchema($file, "{$dir}/schema-{$hash}.php")); // stop event return false; } // delete invalid schema cache } catch (Error $e) { Event::emit('source.error', [$e]); File::rename($file, "{$dir}/{$name}.error.gql"); } return null; } } src/Source/Listener/LogSourceError.php 0000644 00000002307 15174511643 0014016 0 ustar 00 <?php namespace YOOtheme\Builder\Source\Listener; use YOOtheme\Config; use YOOtheme\GraphQL\Error\DebugFlag; use YOOtheme\GraphQL\Error\FormattedError; use YOOtheme\Metadata; class LogSourceError { public Config $config; public Metadata $metadata; public function __construct(Config $config, Metadata $metadata) { $this->config = $config; $this->metadata = $metadata; } public function handle($errors): void { if ($this->config->get('app.debug') || $this->config->get('app.isCustomizer')) { $this->metadata->set( 'script:graphql-errors', join( "\n", array_map( fn($error) => sprintf( 'console.warn(%s);', json_encode( FormattedError::createFromException( $error, DebugFlag::INCLUDE_DEBUG_MESSAGE, ), ), ), $errors, ), ), ); } } } src/Source/Query/Node.php 0000644 00000004217 15174511643 0011311 0 ustar 00 <?php namespace YOOtheme\Builder\Source\Query; class Node implements \JsonSerializable { /** * @var string */ public $kind; /** * @var ?string */ public $name; /** * @var ?string */ public $alias; /** * @var array */ public $children = []; /** * @var array */ public $arguments = []; /** * @var array */ public $directives = []; /** * Constructor. */ public function __construct($kind, $name, array $options = []) { $this->kind = $kind; $this->name = $name; foreach ($options as $key => $value) { $this->$key = $value; } } public function get($name) { foreach ($this->children as $child) { if ($child->name === $name) { return $child; } } return null; } public function query($name = null) { static::assertNode($this, 'Document'); return $this->children[] = new self('Query', $name); } public function field($name, array $arguments = []) { static::assertNode($this, 'Field', 'Query'); return $this->children[] = new self('Field', $name, ['arguments' => $arguments]); } public function directive($name, array $arguments = []) { static::assertNode($this, 'Field'); return $this->directives[] = new self('Directive', $name, ['arguments' => $arguments]); } public function toAST() { return AST::build($this); } public function toHash() { return hash('crc32b', json_encode($this)); } #[\ReturnTypeWillChange] public function jsonSerialize() { return array_values( array_filter([$this->kind, $this->name, $this->arguments, $this->directives]), ); } public static function document() { return new self('Document', null); } protected static function assertNode(self $node, ...$kind) { if (!in_array($node->kind, $kind, true)) { throw new \Exception('Node must be a ' . join(', ', $kind)); } } } src/Source/Query/AST.php 0000644 00000007225 15174511643 0011055 0 ustar 00 <?php namespace YOOtheme\Builder\Source\Query; class AST { public static function build(Node $node) { $build = [static::class, $node->kind]; return $build($node); } public static function field(Node $node) { $result = [ 'kind' => 'Field', 'name' => static::name($node->name), 'arguments' => static::arguments($node->arguments), 'directives' => array_map([static::class, 'directive'], $node->directives), ]; if ($node->alias) { $result['alias'] = static::name($node->alias); } if ($node->children) { $result['selectionSet'] = static::selections($node->children); } return $result; } public static function query(Node $node) { $result = [ 'kind' => 'OperationDefinition', 'operation' => 'query', 'selectionSet' => static::selections($node->children), 'variableDefinitions' => [], ]; if ($node->name) { $result['name'] = static::name($node->name); } return $result; } public static function document(Node $node) { return [ 'kind' => 'Document', 'definitions' => array_map([static::class, 'build'], $node->children), ]; } public static function directive(Node $node) { return [ 'kind' => 'Directive', 'name' => static::name($node->name), 'arguments' => static::arguments($node->arguments), ]; } public static function name($name) { return [ 'kind' => 'Name', 'value' => $name, ]; } public static function value($value) { switch (gettype($value)) { case 'NULL': return ['kind' => 'NullValue']; case 'string': return ['kind' => 'StringValue', 'value' => $value]; case 'boolean': return ['kind' => 'BooleanValue', 'value' => $value]; case 'integer': return ['kind' => 'IntValue', 'value' => strval($value)]; case 'double': return ['kind' => 'FloatValue', 'value' => strval($value)]; case 'array': return [ 'kind' => 'ListValue', 'values' => array_map([static::class, 'value'], $value), ]; case 'object': $fields = []; foreach (get_object_vars($value) as $key => $val) { $fields[] = static::objectField($key, $val); } return [ 'kind' => 'ObjectValue', 'fields' => $fields, ]; } } public static function objectField($name, $value) { return [ 'kind' => 'ObjectField', 'name' => static::name($name), 'value' => static::value($value), ]; } public static function arguments(array $arguments) { $result = []; foreach ($arguments as $name => $value) { $result[] = [ 'kind' => 'Argument', 'name' => static::name($name), 'value' => static::value($value), ]; } return $result; } public static function selections(array $selections) { $result = [ 'kind' => 'SelectionSet', 'selections' => [], ]; foreach ($selections as $selection) { $result['selections'][] = static::build($selection); } return $result; } } src/Source/SourceQuery.php 0000644 00000004651 15174511643 0011607 0 ustar 00 <?php namespace YOOtheme\Builder\Source; use YOOtheme\Builder\Source\Query\Node; class SourceQuery { public const PARENT = '#parent'; /** * @var Node */ public $document; /** * Constructor. */ public function __construct(?Node $document = null) { $this->document = $document ?? Node::document(); } /** * Creates a source query. * * @param object $node * * @return Node */ public function create($node) { return $this->querySource($node->source, $this->document->query()); } /** * Query source definition. * * @param object $source * @param Node $node * * @return Node */ public function querySource($source, Node $node) { $field = $node; // add query selection if ($source->query->name !== self::PARENT) { $field = $this->queryField($source->query, $field); } // add field selection if (isset($source->query->field)) { $field = $this->queryField($source->query->field, $field); } // add source properties foreach ((array) ($source->props ?? []) as $prop) { if (!str_starts_with($prop->name, '#')) { $this->queryField($prop, $field); } } return $field; } /** * Create nested field nodes. * * @param object $field * @param Node $node * * @return Node */ public function queryField($field, Node $node) { $parts = explode('.', $field->name); $name = array_pop($parts); $arguments = (array) ($field->arguments ?? []); $directives = (array) ($field->directives ?? []); foreach ($parts as $part) { $node = is_null($_node = $node->get($part)) ? $node->field($part) : $_node; } // check if field already exists $nodeExists = $node->get($name); // create node for field $node = $node->field($name, $arguments); // add directives foreach ($directives as $directive) { $node->directive($directive->name, (array) ($directive->arguments ?? [])); } // add alias if ($nodeExists && $nodeExists->toHash() !== ($hash = $node->toHash())) { $node->alias = "{$name}_{$hash}"; $field->name .= "_{$hash}"; } return $node; } } src/Source/SourceFilter.php 0000644 00000011167 15174511643 0011727 0 ustar 00 <?php namespace YOOtheme\Builder\Source; use YOOtheme\Arr; use YOOtheme\Str; trait SourceFilter { /** * @var array */ public $filters; /** * Constructor. * * @param array $filters */ public function __construct(array $filters = []) { $this->filters = array_merge( [ 'date' => [$this, 'applyDate'], 'limit' => [$this, 'applyLimit'], 'search' => [$this, 'applySearch'], 'before' => [$this, 'applyBefore'], 'after' => [$this, 'applyAfter'], 'condition' => [$this, 'applyCondition'], ], $filters, ); } /** * Adds a filter. * * @param string $name * @param callable $filter * @param int $offset */ public function addFilter($name, callable $filter, $offset = null) { Arr::splice($this->filters, $offset, 0, [$name => $filter]); } /** * Apply "before" filter. * * @param mixed $value * @param mixed $before * * @return string */ public function applyBefore($value, $before) { return $value != '' ? $before . $value : $value; } /** * Apply "after" filter. * * @param mixed $value * @param mixed $after * * @return string */ public function applyAfter($value, $after) { return $value != '' ? $value . $after : $value; } /** * Apply "limit" filter. * * @param mixed $value * @param mixed $limit * @param array $filters * * @return string */ public function applyLimit($value, $limit, array $filters) { if ($limit) { $value = preg_replace('/\s*<br[^<]*?\/?>\s*/', ' ', $value); $value = Str::limit( strip_tags($value), intval($limit), '…', !($filters['preserve'] ?? false), ); } return $value; } /** * Apply "date" filter. * * @param mixed $value * @param mixed $format * * @return false|string */ public function applyDate($value, $format) { if (!$value) { return $value; } if (is_string($value) && !is_numeric($value)) { $value = strtotime($value); } return date($format ?: 'd/m/Y', intval($value) ?: time()); } /** * Apply "search" filter. * * @param mixed $value * @param mixed $search * @param array $filters * * @return false|string */ public function applySearch($value, $search, array $filters) { $replace = $filters['replace'] ?? ''; if ($search && $search[0] === '/') { return @preg_replace($search, $replace, $value); } return str_replace($search, $replace, $value); } /** * Apply "condition" filter. * * @param mixed $value * @param mixed $operator * @param array $filters * * @return bool */ public function applyCondition($value, $operator, array $filters) { $propertyValue = html_entity_decode($value); $conditionValue = $filters['condition_value'] ?? ''; if ($operator === '!') { return empty($propertyValue); } if ($operator === '!!') { return !empty($propertyValue); } if ($operator === '=') { return $propertyValue == $conditionValue; } if ($operator === '!=') { return $propertyValue != $conditionValue; } if ($operator === '<') { return $propertyValue < $conditionValue; } if ($operator === '>') { return $propertyValue > $conditionValue; } if ($operator === '~=') { return str_contains($propertyValue, $conditionValue); } if ($operator === '!~=') { return !str_contains($propertyValue, $conditionValue); } if ($operator === '^=') { return str_starts_with($propertyValue, $conditionValue); } if ($operator === '!^=') { return !str_starts_with($propertyValue, $conditionValue); } if ($operator === '$=') { return str_ends_with($propertyValue, $conditionValue); } if ($operator === '!$=') { return !str_ends_with($propertyValue, $conditionValue); } if ($operator === 'regex') { return @preg_match($conditionValue, $propertyValue) > 0; } return !!$propertyValue; } } src/Source/SourceTransform.php 0000644 00000015527 15174511643 0012461 0 ustar 00 <?php namespace YOOtheme\Builder\Source; use YOOtheme\Arr; use YOOtheme\Builder\Source; use YOOtheme\Config; use YOOtheme\Event; use function YOOtheme\app; class SourceTransform { use SourceFilter; /** * Transform callback "preload". * * @param object $node * @param array $params * * @return void */ public function preload($node, array &$params) { if ($params['context'] !== 'render') { return; } if (empty($node->source->query->name)) { return; } if ($node->source->query->name === SourceQuery::PARENT) { if (!empty($params['source'])) { $params['source']->source->children[] = $node; } if (!empty($node->source->query->field->name)) { $params['source'] = $node; } } else { $params['source'] = $node; } } /** * Transform callback "prerender". * * @param object $node * @param array $params * * @return bool|void */ public function prerender($node, array &$params) { if (isset($node->source->data)) { $params['data'] = $node->source->data; } if (empty($node->source->query->name)) { return; } if ($node->source->query->name === SourceQuery::PARENT) { // Ignore if no field is mapped if (empty($node->source->props) && empty($node->source->children)) { return; } return $this->resolveSource($node, $params); } if ($result = $this->querySource($node, $params)) { $params['data'] = $result['data'] ?? null; return $this->resolveSource($node, $params); } } /** * Create source query. * * @param object $node * * @return ?Query\Node */ public function createQuery($node) { $query = new SourceQuery(); $parent = $query->create($node); $props = !empty($node->source->props); // extend source query foreach ($node->source->children ?? [] as $child) { $props = $this->createChildQuery($query, $parent, $child) || $props; } return $props ? $query->document : null; } /** * Add child queries * * @param SourceQuery $query * @param Query\Node $parent * @param object $node * * @return bool */ protected function createChildQuery($query, $parent, $node) { $p = $query->querySource($node->source, $parent); $props = !empty($node->source->props); foreach ($node->source->children ?? [] as $child) { $props = $this->createChildQuery($query, $p, $child) || $props; } return $props; } /** * Query source data. * * @param object $node * @param array $params * * @return array|void */ public function querySource($node, array $params) { if (!($query = $this->createQuery($node))) { return; } // execute query without validation rules $result = app(Source::class)->query( $query->toAST(), $params, new \ArrayObject(), null, null, null, app(Config::class)->get('app.debug') ? null : [], ); if (!empty($result->errors)) { Event::emit('source.error', $result->errors, $node); } return $result->toArray(); } /** * Map source properties. * * @param object $node * @param array $params * * @return ?object */ public function mapSource($node, array $params) { foreach ($node->source->props ?? [] as $name => $prop) { $value = trim($this->toString(Arr::get($params, "data.{$prop->name}"))); $filters = (array) ($prop->filters ?? []); // apply value filters foreach (array_intersect_key($this->filters, $filters) as $key => $filter) { $value = $filter($value, $filters[$key], $filters, $params); } // check condition value if ($name === '_condition' && $value === false) { return null; } // set filtered value $node->props[$name] = $value; } return $node; } /** * Repeat node for each source item. * * @param object $node * @param array $params * * @return array */ public function repeatSource($node, array $params) { $nodes = []; // clone and map node for each item foreach ($params['data'] as $index => $data) { $data = (array) $data; $data['#index'] = $index; $data['#first'] = $index === 0; $data['#last'] = $index === array_key_last($params['data']); if ($clone = $this->mapSource($this->cloneNode($node), ['data' => $data] + $params)) { $clone->source = (object) ['data' => $data]; $nodes[] = $clone; } } // insert cloned nodes after current node array_splice($params['parent']->children, $params['i'] + 1, 0, $nodes); return $nodes; } /** * Resolve source data. * * @param object $node * @param array $params * * @return bool */ public function resolveSource($node, array &$params) { $name = 'data'; // add query name if ($node->source->query->name !== SourceQuery::PARENT) { $name .= ".{$node->source->query->name}"; } // add field name if (isset($node->source->query->field)) { $name .= ".{$node->source->query->field->name}"; } // get source data $params['data'] = Arr::get($params, $name); if (!empty($node->source->props->_condition->filters->show_empty)) { return !$params['data']; } if ($params['data'] && is_array($params['data'])) { if (!array_is_list($params['data'])) { return (bool) $this->mapSource($node, $params); } $this->repeatSource($node, $params); } return false; } /** * Clone node recursively. * * @param object $node * * @return object */ protected function cloneNode($node) { $clone = clone $node; // recursively clone children if (isset($node->children)) { $clone->children = array_map(fn($child) => $this->cloneNode($child), $node->children); } return $clone; } protected function toString($value) { if (is_scalar($value) || is_callable([$value, '__toString'])) { return (string) $value; } return ''; } } src/Source/OptimizeTransform.php 0000644 00000000546 15174511643 0013014 0 ustar 00 <?php namespace YOOtheme\Builder\Source; class OptimizeTransform { /** * Transform callback. * * @param object $node * @param array $params */ public function __invoke($node, array $params) { if (empty($node->source->query) && isset($node->source->props)) { unset($node->source); } } } updates.php 0000644 00000000334 15174511643 0006731 0 ustar 00 <?php namespace YOOtheme; return [ '3.0.0-beta.1.2' => function ($node) { if (isset($node->source->query->name) && empty($node->source->query->name)) { unset($node->source); } }, ]; bootstrap.php 0000644 00000003305 15174511643 0007302 0 ustar 00 <?php namespace YOOtheme\Builder\Source; use YOOtheme\Application; use YOOtheme\Builder; use YOOtheme\Builder\BuilderConfig; use YOOtheme\Builder\Source; use YOOtheme\Builder\UpdateTransform; use YOOtheme\Event; use YOOtheme\GraphQL\Directive\SliceDirective; use YOOtheme\GraphQL\Plugin\ContainerPlugin; use YOOtheme\GraphQL\Type\ObjectScalarType; return [ 'events' => [ 'source.init' => [Listener\LoadSourceSchema::class => ['@handle', 50]], 'source.error' => [Listener\LogSourceError::class => '@handle'], 'source.type.metadata' => [Listener\OrderSourceMetadata::class => 'handle'], BuilderConfig::class => [Listener\LoadBuilderConfig::class => '@handle'], ], 'config' => [ BuilderConfig::class => __DIR__ . '/config/customizer.json', ], 'extend' => [ Builder::class => function (Builder $builder, $app) { $source = $app(SourceTransform::class); $builder->addTransform('preload', [$source, 'preload']); $builder->addTransform('prerender', [$source, 'prerender'], 2); // Before Placeholder Transform $builder->addTransform('presave', new OptimizeTransform()); }, UpdateTransform::class => function (UpdateTransform $update) { $update->addGlobals(require __DIR__ . '/updates.php'); }, ], 'services' => [ Source::class => function (SliceDirective $slice, ObjectScalarType $objectType) { $source = new Source([new ContainerPlugin(Application::getInstance())]); $source->setType($objectType); $source->setDirective($slice); Event::emit('source.init', $source); return $source; }, ], ];
| ver. 1.4 |
Github
|
.
| PHP 8.3.23 | Generation time: 0 |
proxy
|
phpinfo
|
Settings