template = Schema::load(is_string($template) ? $template : 'graphql'); $this->rootSchemaPath = $this->template->getPath(); } /** * Set schema root path. * * @param string $path * * @return SchemaSourceProvider */ public function setRootPath(string $path): self { $this->rootSchemaPath = $path; return $this; } /** * Stitch together schema documents and return the result as a string. * * @return string */ public function getSchemaString(): string { // root types $schema = ' type Query { dummy: Boolean } type Mutation { dummy: Boolean } '; // schema $schema .= collect($this->getGraphMap())->implode('schema', ''); return $schema; } public function findGraph($fieldName, $findOrFail = false) { if (!isset($this->getFieldGraphMap()[$fieldName])) { if ($findOrFail) { throw new Error("Could not find graph of field '{$fieldName}'."); } return null; } $name = $this->getFieldGraphMap()[$fieldName]; if (isset($this->graphMap[$name])) { // if available, use already instantiated graph objects in memory return $this->graphMap[$name]['graph']; } return Graph::loadCached($this->template, $name); } public function getFieldGraphMap() { if (!is_null($this->fieldGraphMap)) { return $this->fieldGraphMap; } // restore from cache $cacheable = true; if ($cacheable) { $map = Cache::get($this->fieldGraphMapCacheKey, false); if ($map && ($map = @unserialize(@base64_decode($map))) && is_array($map)) { $this->fieldGraphMap = $map; return $this->fieldGraphMap; } } // rebuild mapping $this->fieldGraphMap = []; foreach ($this->getGraphMap() as $key => $element) { if (empty(trim($element['schema']))) { continue; } // parse the AST to collect fields mapping $ast = Parser::parse($element['schema'], ['noLocation' => true]); $fields = collect($ast->definitions) ->filter(function ($node) { // we only consider the root types since their fields are unique return $node->name->value == 'Query' || $node->name->value == 'Mutation'; }) ->flatMap(function ($node) { // collect field names return collect($node->fields)->map(function ($field) { return $field->name->value; }); }); // map as [$field_name => $graph_filename] $this->fieldGraphMap = array_merge($this->fieldGraphMap, array_fill_keys($fields->toArray(), $key)); } // cache mapping if ($cacheable) { Cache::put($this->fieldGraphMapCacheKey, base64_encode(serialize($this->fieldGraphMap)), 10); } return $this->fieldGraphMap; } public function getGraphMap() { if (!is_null($this->graphMap)) { return $this->graphMap; } $this->graphMap = []; $component_re = '/{%\s*component\s+["|\'](.*)["|\']\s*%}/m'; $component_str = [$this, 'getComponentSchemaString']; foreach ($this->template->listGraphs() as $graph) { /* @var $graph \GermanAirlinesVa\Graphql\Classes\Graph */ $markup = $graph->markup; $schema = preg_replace_callback( $component_re, function (array $matches) use ($graph, $component_str) { $matched_alias = $matches[1]; foreach ($graph->settings['components'] as $component => $properties) { // find component by alias [$name, $alias] = strpos($component, ' ') ? explode(' ', $component) : [$component, $component]; if ($alias == $matched_alias) { // resolve component schema return $component_str($name, $alias); } } // if not found, remove return ''; }, $markup ); $this->graphMap[$graph->getFileName()] = [ 'graph' => $graph, 'schema' => $schema, ]; } return $this->graphMap; } public function getComponentSchemaString($componentName, $alias) { $manager = ComponentManager::instance(); $componentObj = $manager->makeComponent($componentName); if ($partial = ComponentPartial::load($componentObj, 'schema.graphqls')) { $content = $partial->getContent(); $content = str_replace('__SELF__', $alias, $content); return $content; } else { return "# {$componentName} does not provide a default schema definition"; } } public function clearCache() { Cache::forget($this->fieldGraphMapCacheKey); } }