Completed
Pull Request — 8.x-3.x (#442)
by Sebastian
02:16
created

SchemaPluginBase::getRootFields()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 1
nop 0
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Drupal\graphql\Plugin\GraphQL\Schemas;
4
5
use Drupal\Component\Plugin\PluginBase;
6
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
7
use Drupal\graphql\GraphQL\Schema\Schema;
8
use Drupal\graphql\Plugin\GraphQL\PluggableSchemaBuilder;
9
use Drupal\graphql\Plugin\GraphQL\PluggableSchemaPluginInterface;
10
use Drupal\graphql\Plugin\GraphQL\TypeSystemPluginInterface;
11
use Drupal\graphql\Plugin\GraphQL\TypeSystemPluginManagerAggregator;
12
use Symfony\Component\DependencyInjection\ContainerInterface;
13
use Youshido\GraphQL\Schema\InternalSchemaMutationObject;
14
use Youshido\GraphQL\Schema\InternalSchemaQueryObject;
15
16
abstract class SchemaPluginBase extends PluginBase implements PluggableSchemaPluginInterface, ContainerFactoryPluginInterface {
17
18
  /**
19
   * The schema builder object.
20
   *
21
   * @var \Drupal\graphql\Plugin\GraphQL\PluggableSchemaBuilderInterface
22
   */
23
  protected $schemaBuilder;
24
25
  /**
26
   * {@inheritdoc}
27
   */
28
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
29
    return new static(
30
      $configuration,
31
      $plugin_id,
32
      $plugin_definition,
33
      $container->get('graphql.plugin_manager_aggregator')
34
    );
35
  }
36
37
  /**
38
   * SchemaPluginBase constructor.
39
   *
40
   * @param array $configuration
41
   *   The plugin configuration array.
42
   * @param string $pluginId
43
   *   The plugin id.
44
   * @param array $pluginDefinition
45
   *   The plugin definition array.
46
   * @param \Drupal\graphql\Plugin\GraphQL\TypeSystemPluginManagerAggregator $pluginManagers
47
   *   Type system plugin manager aggregator service.
48
   */
49
  public function __construct($configuration, $pluginId, $pluginDefinition, TypeSystemPluginManagerAggregator $pluginManagers) {
50
    parent::__construct($configuration, $pluginId, $pluginDefinition);
51
    $this->schemaBuilder = new PluggableSchemaBuilder($pluginManagers);
52
  }
53
54
  /**
55
   * {@inheritdoc}
56
   */
57
  public function getSchemaBuilder() {
58
    return $this->schemaBuilder;
59
  }
60
61
  /**
62
   * {@inheritdoc}
63
   */
64
  public function getSchema() {
65
    $mutation = new InternalSchemaMutationObject(['name' => 'RootMutation']);
66
    $mutation->addFields($this->extractDefinitions(($this->getMutations())));
67
68
    $query = new InternalSchemaQueryObject(['name' => 'RootQuery']);
69
    $query->addFields($this->extractDefinitions($this->getRootFields()));
70
71
    $types = $this->extractDefinitions($this->getTypes());
72
73
    return new Schema($this, [
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Drupal\graph...n, 'types' => $types)); (Drupal\graphql\GraphQL\Schema\Schema) is incompatible with the return type declared by the interface Drupal\graphql\Plugin\Gr...ginInterface::getSchema of type Youshido\GraphQL\Schema\AbstractSchema.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
74
      'query' => $query,
75
      'mutation' => $mutation,
76
      'types' => $types,
77
    ]);
78
  }
79
80
  /**
81
   * Extract type or field definitions from plugins.
82
   *
83
   * @param array $plugins
84
   *   The list of plugins to extract the type or field definitions from.
85
   *
86
   * @return array
87
   *   The list of extracted type or field definitions.
88
   */
89
  protected function extractDefinitions(array $plugins) {
90
    return array_map(function (TypeSystemPluginInterface $plugin) {
91
      return $plugin->getDefinition($this->schemaBuilder);
92
    }, $plugins);
93
  }
94
95
  /**
96
   * Retrieve all mutations.
97
   *
98
   * @return \Drupal\graphql\Plugin\GraphQL\TypeSystemPluginInterface[]
99
   *   The list of mutation plugins.
100
   */
101
  protected function getMutations() {
102
    return $this->schemaBuilder->find(function() {
103
      return TRUE;
104
    }, [GRAPHQL_MUTATION_PLUGIN]);
105
  }
106
107
  /**
108
   * Retrieve all fields that are not associated with a specific type.
109
   *
110
   * @return \Drupal\graphql\Plugin\GraphQL\TypeSystemPluginInterface[]
111
   *   The list root field plugins.
112
   */
113
  protected function getRootFields() {
114
    // Retrieve the list of fields that are not attached to any type or are
115
    // explicitly attached to the artificial "Root" type.
116
    return $this->schemaBuilder->find(function($definition) {
117
      return empty($definition['parents']) || in_array('Root', $definition['parents']);
118
    }, [GRAPHQL_FIELD_PLUGIN]);
119
  }
120
121
  /**
122
   * Retrieve all types to be registered explicitly.
123
   *
124
   * @return \Drupal\graphql\Plugin\GraphQL\TypeSystemPluginInterface[]
125
   *   The list of types to be registered explicitly.
126
   */
127
  protected function getTypes() {
128
    return $this->schemaBuilder->find(function() {
129
      return TRUE;
130
    }, [
131
      GRAPHQL_UNION_TYPE_PLUGIN,
132
      GRAPHQL_TYPE_PLUGIN,
133
      GRAPHQL_INPUT_TYPE_PLUGIN,
134
    ]);
135
  }
136
137
}
138