Issues (36)

src/GraphQL/Schema.php (3 issues)

1
<?php declare(strict_types=1);
2
3
/*
4
 * This file is part of Biurad opensource projects.
5
 *
6
 * @copyright 2019 Biurad Group (https://biurad.com/)
7
 * @license   https://opensource.org/licenses/BSD-3-Clause License
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace Flange\GraphQL;
14
15
use GraphQL\Language\AST\DocumentNode;
16
use GraphQL\Language\Parser;
17
use GraphQL\Language\Source;
18
use GraphQL\Type\Schema as TypeSchema;
19
use GraphQL\Utils\AST;
20
use GraphQL\Utils\BuildSchema;
21
22
/**
23
 * Definitions of GraphQL schemas.
24
 *
25
 * @author Divine Niiquaye Ibok <[email protected]>
26
 */
27
class Schema implements \Countable
28
{
29
    private const CACHE_PREFIX = '.cache.php';
30
31
    private array $schemas;
32
    private int $count = 0;
33
34
    public function __construct(array $schemas = [], private $cacheDir = null)
35
    {
36
        foreach ($schemas as $name => $schema) {
37
            if ($schema instanceof TypeSchema) {
38
                $this->schemas[$name] = $schema;
39
                ++$this->count;
40
41
                continue;
42
            }
43
44
            $this->set($name, $schema);
45
        }
46
    }
47
48
    /**
49
     * {@inheritdoc}
50
     */
51
    public function count(): int
52
    {
53
        return $this->count;
54
    }
55
56
    public function set(string $name, string|TypeSchema|\Closure $schema): void
57
    {
58
        ++$this->count;
59
60
        if (null !== $cache = $this->cacheDir) {
61
            if (\file_exists($cache = ($cache.$name.self::CACHE_PREFIX))) {
62
                $this->schemas[$name] = AST::fromArray(require $cache);
63
64
                return;
65
            }
66
        }
67
68
        $this->schemas[$name] = $schema = $this->resolveSchema($schema instanceof \Closure ? $schema() : $schema, $cache);
0 ignored issues
show
The assignment to $schema is dead and can be removed.
Loading history...
69
    }
70
71
    public function get(string $name): ?TypeSchema
72
    {
73
        return $this->schemas[$name] ?? null;
74
    }
75
76
    private function resolveSchema($schema, ?string $cache): TypeSchema
77
    {
78
        if ($schema instanceof TypeSchema) {
79
            return $schema;
80
        }
81
82
        if ($schema instanceof DocumentNode) {
83
            $schema = Parser::parse($schema);
84
        } elseif (\is_string($schema)) {
85
            if (!\is_file($schema)) {
86
                throw new \InvalidArgumentException(\sprintf('Schema file "%s" does not exist.', $schema));
87
            }
88
89
            if ('php' === \pathinfo($schema, \PATHINFO_EXTENSION)) {
90
                return require $schema;
91
            }
92
93
            $schema = Parser::parse(new Source(\file_get_contents($schema), \pathinfo($schema, \PATHINFO_BASENAME)));
0 ignored issues
show
It seems like pathinfo($schema, PATHINFO_BASENAME) can also be of type array; however, parameter $name of GraphQL\Language\Source::__construct() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

93
            $schema = Parser::parse(new Source(\file_get_contents($schema), /** @scrutinizer ignore-type */ \pathinfo($schema, \PATHINFO_BASENAME)));
Loading history...
94
        }
95
96
        if (null !== $cache) {
97
            if (!\is_dir($directory = \dirname($cache))) {
98
                @\mkdir($directory, 0775, true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

98
                /** @scrutinizer ignore-unhandled */ @\mkdir($directory, 0775, true);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
99
            }
100
101
            \file_put_contents($cache, "<?php\nreturn ".\var_export(AST::toArray($schema), true).";\n");
102
        }
103
104
        return (new BuildSchema($schema))->buildSchema();
105
    }
106
}
107