Issues (88)

src/Dependencies.php (6 issues)

Labels
Severity
1
<?php
2
3
namespace Drupal\qa;
4
5
use Drupal\Core\Extension\ModuleExtensionList;
6
use Drupal\Core\Extension\ThemeExtensionList;
7
use Grafizzi\Graph\Attribute;
0 ignored issues
show
The type Grafizzi\Graph\Attribute was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use Grafizzi\Graph\Cluster;
0 ignored issues
show
The type Grafizzi\Graph\Cluster was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use Grafizzi\Graph\Edge;
0 ignored issues
show
The type Grafizzi\Graph\Edge was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use Grafizzi\Graph\Graph;
0 ignored issues
show
The type Grafizzi\Graph\Graph was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use Grafizzi\Graph\Node;
0 ignored issues
show
The type Grafizzi\Graph\Node was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use Pimple\Container;
0 ignored issues
show
The type Pimple\Container was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
13
use Psr\Log\LoggerInterface;
14
15
/**
16
 * Class Dependencies supports building the dependency graph for extensions.
17
 */
18
class Dependencies {
19
  const SHAPE_THEME = 'octagon';
20
  const SHAPE_ENGINE = 'doubleoctagon';
21
22
  /**
23
   * The current drawing font.
24
   *
25
   * @var \Grafizzi\Graph\Attribute
26
   */
27
  protected $font;
28
29
  /**
30
   * A logger service.
31
   *
32
   * @var \Psr\Log\LoggerInterface
33
   */
34
  protected $logger;
35
36
  /**
37
   * The extension.list.module service.
38
   *
39
   * @var \Drupal\Core\Extension\ModuleExtensionList
40
   */
41
  protected $moduleExtensionList;
42
43
  /**
44
   * The container used by Grafizzi.
45
   *
46
   * @var \Pimple\Container
47
   */
48
  protected $pimple;
49
50
  /**
51
   * The extension.list.theme service.
52
   *
53
   * @var \Drupal\Core\Extension\ThemeExtensionList
54
   */
55
  protected $themeExtensionList;
56
57
  /**
58
   * Dependencies constructor.
59
   *
60
   * @param \Drupal\Core\Extension\ModuleExtensionList $moduleExtensionList
61
   *   The extension.list.module service.
62
   * @param \Drupal\Core\Extension\ThemeExtensionList $themeExtensionList
63
   *   The extension.list.theme service.
64
   * @param \Psr\Log\LoggerInterface $logger
65
   *   A logger service.
66
   */
67
  public function __construct(
68
    ModuleExtensionList $moduleExtensionList,
69
    ThemeExtensionList $themeExtensionList,
70
    LoggerInterface $logger
71
  ) {
72
    $this->logger = $logger;
73
    $this->moduleExtensionList = $moduleExtensionList;
74
    $this->themeExtensionList = $themeExtensionList;
75
    $this->pimple = new Container(['logger' => $logger]);
76
77
    $this->font = $this->attr("fontsize", 10);
78
  }
79
80
  /**
81
   * Clone of function _graphviz_create_filepath() from graphviz_filter.module.
82
   *
83
   * @param string $path
84
   *   The path were to create the graph.
85
   * @param string $filename
86
   *   The name of the graph file.
87
   *
88
   * @return string
89
   *   The complet graph path.
90
   */
91
  public function graphvizCreateFilepath($path, $filename) {
92
    if (!empty($path)) {
93
      return rtrim($path, '/') . "/${filename}";
94
    }
95
    return $filename;
96
  }
97
98
  /**
99
   * Facade for Grafizzi Attribute constructor.
100
   *
101
   * @param string $name
102
   *   The name of the Attribute to create.
103
   * @param string $value
104
   *   The value of the Attribute to create.
105
   *
106
   * @return \Grafizzi\Graph\Attribute
107
   *   The created Attribute.
108
   */
109
  public function attr(string $name, string $value) : Attribute {
110
    return new Attribute($this->pimple, $name, $value);
111
  }
112
113
  /**
114
   * Facade for Grafizzi Edge constructor.
115
   *
116
   * @param \Grafizzi\Graph\Node $from
117
   *   The edge origin (tail).
118
   * @param \Grafizzi\Graph\Node $to
119
   *   The edge destination (head).
120
   * @param array $attrs
121
   *   The attributes to add to the edge.
122
   *
123
   * @return \Grafizzi\Graph\Edge
124
   *   The created Edge.
125
   */
126
  public function edge(Node $from, Node $to, array $attrs) : Edge {
127
    return new Edge($this->pimple, $from, $to, $attrs);
128
  }
129
130
  /**
131
   * Facade for Grafizzi Node constructor.
132
   *
133
   * Strips the optional "namespace" (aka project or package) part of the name.
134
   *
135
   * @param string $name
136
   *   The name of the node to create.
137
   * @param \Grafizzi\Graph\Attribute[] $attrs
138
   *   The attributes to add to the node.
139
   *
140
   * @return \Grafizzi\Graph\Node
141
   *   The created Node.
142
   */
143
  public function node(string $name, array $attrs = []) : Node {
144
    // Strip the "namespace" part.
145
    $arName = explode(':', $name);
146
    $localName = array_pop($arName);
147
148
    $arLocal = explode(' ', $localName);
149
    $simpleName = current($arLocal);
150
    return new Node($this->pimple, $simpleName, $attrs);
151
  }
152
153
  /**
154
   * Facade for Grafizzi Cluster constructor.
155
   *
156
   * @param string $name
157
   *   The name of the cluster subgraph to create.
158
   * @param array $attrs
159
   *   The attributes to add to the subgraph.
160
   *
161
   * @return \Grafizzi\Graph\Cluster
162
   *   The created cluster subgraph.
163
   */
164
  public function cluster(string $name, array $attrs = []): Cluster {
165
    return new Cluster($this->pimple, urlencode($name), [
166
      $this->attr('label', $name),
167
    ] + $attrs);
168
  }
169
170
  /**
171
   * Initialize a Grafizzi graph.
172
   *
173
   * @return \Grafizzi\Graph\Graph
174
   *   The created Graph.
175
   */
176
  protected function initGraph() : Graph {
177
    $g = new Graph($this->pimple, "deps", [
178
      $this->attr("rankdir", "RL"),
179
    ]);
180
    $g->setDirected(TRUE);
181
    return $g;
182
  }
183
184
  /**
185
   * Build the modules dependency graph.
186
   *
187
   * @param \Grafizzi\Graph\Graph $g
188
   *   The Graph within which to draw.
189
   *
190
   * @return \Grafizzi\Graph\Graph
191
   *   The modified Graph.
192
   */
193
  public function buildModules(Graph $g) : Graph {
194
    $modules = $this->moduleExtensionList->reset()->getList();
195
    krsort($modules);
196
197
    $packages = [];
198
199
    foreach ($modules as $module => $detail) {
200
      if (!$detail->status) {
201
        continue;
202
      }
203
      $package = $detail->info['package'] ?? '';
204
      if (!empty($package)) {
205
        if (!isset($packages[$package])) {
206
          $packageCluster = $this->cluster($package);
207
          $packages[$package] = $packageCluster;
208
          $g->addChild($packageCluster);
209
        }
210
        else {
211
          /** @var \Grafizzi\Graph\Cluster $packageCluster */
212
          $packageCluster = $packages[$package];
213
        }
214
215
        $packageCluster->addChild($from = $this->node("${package}:${module}", [$this->font]));
216
      }
217
      else {
218
        $g->addChild($from = $this->node($module, [$this->font]));
219
      }
220
221
      $dependencies = $detail->info['dependencies'] ?? [];
222
      foreach ($dependencies as $depend) {
223
        $to = $this->node($depend, [$this->font]);
224
        $g->addChild(
225
          $this->edge($from, $to, [
226
            $this->font,
227
            $this->attr('color', 'lightgray'),
228
          ]));
229
      }
230
    }
231
    return $g;
232
  }
233
234
  /**
235
   * Build the themes dependency graph.
236
   *
237
   * @param \Grafizzi\Graph\Graph $g
238
   *   The Graph within which to draw.
239
   *
240
   * @return \Grafizzi\Graph\Graph
241
   *   The modified Graph.
242
   */
243
  protected function buildTheming(Graph $g) : Graph {
244
    $engineShape = $this->attr('shape', static::SHAPE_ENGINE);
245
    $themeShape = $this->attr('shape', static::SHAPE_THEME);
246
    $engineLine = $this->attr('style', 'dotted');
247
    $baseLine = $this->attr('style', 'dashed');
248
249
    $themeList = $this->themeExtensionList->getAllAvailableInfo();
250
    krsort($themeList);
251
252
    $engines = [];
253
    $themes = [];
254
255
    foreach ($themeList as $theme => $detail) {
256
      // Build theme engine links.
257
      $themes[$theme] = $from = $this->node($theme, [$this->font, $themeShape]);
258
      $g->addChild($from);
259
      if (!empty($detail['engine'])) {
260
        // D8 still theoretically supports multiple engines (e.g. nyan_cat).
261
        // XXX Name used to include the extension. Play it safe for now.
262
        $engine = basename($detail['engine']);
263
        $engineBase = basename($engine, '.engine');
264
        if (!isset($engines[$engineBase])) {
265
          $engines[$engineBase] = $engineNode = $this->node($engineBase, [
266
            $engineShape,
267
          ]);
268
          $g->addChild($engineCluster = $this->cluster($engineBase, [$this->font]));
269
          $engineCluster->addChild($engineNode);
270
        }
271
        $to = $engines[$engineBase];
272
        $g->addChild($this->edge($from, $to, [$this->font, $engineLine]));
273
      }
274
      else {
275
        $g->addChild($from);
276
      }
277
278
      // Build base theme links.
279
      $toName = $detail['base theme'] ?? '';
280
      if (!empty($toName)) {
281
        $to = $themes[$toName];
282
        if (empty($to)) {
283
          $to = $this->node($toName, [$this->font]);
284
          $g->addChild($to);
285
        }
286
        $g->addChild($this->edge($from, $to, [$this->font, $baseLine]));
287
      }
288
    }
289
290
    return $g;
291
  }
292
293
  /**
294
   * Build the complete dependency graph.
295
   *
296
   * @return \Grafizzi\Graph\Graph
297
   *   The created Graph object. Render it with Grafizzi\Graph\Graph::build().
298
   */
299
  public function build() : Graph {
300
    // @see https://wiki.php.net/rfc/pipe-operator
301
    $g = $this->initGraph();
302
    $g = $this->buildModules($g);
303
    $g = $this->buildTheming($g);
304
    return $g;
305
  }
306
307
}
308