Skip to content

Commit e559a97

Browse files
committed
Allow multiple project namespaces
1 parent 0810667 commit e559a97

File tree

13 files changed

+64
-63
lines changed

13 files changed

+64
-63
lines changed

config/cakephp3.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
return [
44
'Project' => [
5-
'namespace' => 'Cake',
5+
'namespaces' => 'Cake',
66
'sourceDirs' => ['src', 'config'],
77
'excludePatterns' => [
88
'Cake\Collection\CollectionTrait',

config/cakephp4.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
return [
44
'Project' => [
5-
'namespace' => 'Cake',
5+
'namespaces' => 'Cake',
66
'sourceDirs' => ['src', 'config'],
77
'excludePatterns' => [
88
'Cake\Collection\CollectionTrait',

config/chronos.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// Chronos API docs
44
return [
55
'Project' => [
6-
'namespace' => 'Cake\Chronos',
6+
'namespaces' => 'Cake\Chronos',
77
'sourceDirs' => ['src'],
88
'excludePatterns' => [
99
'Cake\Chronos\Traits',

config/elastic.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// Elastic Search API docs
44
return [
55
'Project' => [
6-
'namespace' => 'Cake\ElasticSearch',
6+
'namespaces' => 'Cake\ElasticSearch',
77
'sourceDirs' => ['src'],
88
'excludePatterns' => [],
99
'repo' => 'https://github.com/cakephp/elastic-search',

config/queue.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// Queue API docs
44
return [
55
'Project' => [
6-
'namespace' => 'Cake\Queue',
6+
'namespaces' => 'Cake\Queue',
77
'sourceDirs' => ['src'],
88
'excludePatterns' => [],
99
'repo' => 'https://github.com/cakephp/queue',

src/Generator.php

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,12 @@ public function generate(Project $project): void
5454
{
5555
$this->log(sprintf('Generating project into `%s`', $this->outputDir), 'info');
5656

57-
$namespaces = [];
58-
if (!$project->globalNamespace->isEmpty()) {
59-
$namespaces[] = $project->globalNamespace;
60-
}
61-
$namespaces[] = $project->rootNamespace;
62-
$this->twig->addGlobal('namespaces', $namespaces);
57+
$this->twig->addGlobal('namespaces', $project->namespaces);
6358

6459
$this->renderOverview();
65-
$this->renderSearch($namespaces);
60+
$this->renderSearch($project->namespaces);
6661

67-
foreach ($namespaces as $namespace) {
68-
$this->renderNamespace($namespace);
69-
}
62+
array_walk($project->namespaces, fn ($namespace) => $this->renderNamespace($namespace));
7063
}
7164

7265
/**
@@ -90,7 +83,7 @@ public function renderNamespace(ProjectNamespace $ns): void
9083
$renderer = function (ProjectNamespace $ns) use (&$renderer): void {
9184
$this->renderTemplate(
9285
'pages/namespace.twig',
93-
sprintf('namespace-%s.html', str_replace('\\', '.', $ns->name ?? $ns->displayName)),
86+
sprintf('namespace-%s.html', str_replace('\\', '.', $ns->qualifiedName ?? $ns->name)),
9487
['namespace' => $ns, 'contextName' => $ns->name]
9588
);
9689

src/Project.php

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ class Project
3232

3333
use LogTrait;
3434

35-
public ProjectNamespace $globalNamespace;
36-
37-
public ProjectNamespace $rootNamespace;
35+
/**
36+
* @var array<string, \Cake\ApiDocs\ProjectNamespace>
37+
*/
38+
public array $namespaces;
3839

3940
protected Loader $loader;
4041

@@ -54,8 +55,9 @@ public function __construct(string $projectPath, array $config)
5455
{
5556
$this->setConfig($config);
5657

57-
$this->globalNamespace = new ProjectNamespace(null, 'Global');
58-
$this->rootNamespace = new ProjectNamespace($this->_config['namespace'], $this->_config['namespace']);
58+
foreach ((array)$this->_config['namespaces'] as $namespace) {
59+
$this->namespaces[$namespace] = new ProjectNamespace($namespace);
60+
}
5961

6062
$this->loader = new Loader($projectPath);
6163
$this->classLoader = $this->createClassLoader($projectPath);
@@ -69,10 +71,11 @@ public function __construct(string $projectPath, array $config)
6971
$this->cache[$node->qualifiedName()] = $node;
7072
}
7173

72-
$namespace = $this->findNamespace($node->context->namespace);
74+
$namespace = $this->getNamespace($node->context->namespace);
7375
$namespace->addNode($node);
7476
}
7577
}
78+
ksort($this->namespaces);
7679

7780
$this->mergeInherited();
7881
}
@@ -131,8 +134,7 @@ protected function mergeInherited(): void
131134
}
132135
};
133136

134-
$namespaceMerger($this->globalNamespace);
135-
$namespaceMerger($this->rootNamespace);
137+
array_walk($this->namespaces, fn ($namespace) => $namespaceMerger($namespace));
136138
}
137139

138140
/**
@@ -188,42 +190,44 @@ protected function createClassLoader(string $projectPath): ?ClassLoader
188190
/**
189191
* Finds or creates project namespace.
190192
*
191-
* @param string|null $name Namespace name
193+
* @param string|null $qualifiedName Qualified name
192194
* @return self|null
193195
*/
194-
protected function findNamespace(?string $name): ProjectNamespace
196+
protected function getNamespace(?string $qualifiedName): ProjectNamespace
195197
{
196-
if ($name === null) {
197-
return $this->globalNamespace;
198+
if ($qualifiedName === null) {
199+
return $this->namespaces[''] ??= new ProjectNamespace(null);
200+
}
201+
202+
$namespace = null;
203+
foreach ($this->namespaces as $root) {
204+
if (str_starts_with($qualifiedName, $root->qualifiedName)) {
205+
$namespace = $root;
206+
break;
207+
}
198208
}
199209

200-
if (!str_starts_with($name, $this->rootNamespace->name)) {
201-
throw new RuntimeException(sprintf(
202-
'Namespace `%s` is not a child of the project namespace `%s`.',
203-
$name,
204-
$this->rootNamespace->name
205-
));
210+
if ($namespace === null) {
211+
throw new RuntimeException(sprintf('Namespace `%s` is part of the project namespaces.', $qualifiedName));
206212
}
207213

208-
$remainder = substr($name, strlen($this->rootNamespace->name) + 1);
209-
if (!$remainder) {
210-
return $this->rootNamespace;
214+
if ($namespace->qualifiedName === $qualifiedName) {
215+
return $namespace;
211216
}
212217

213-
$ns = $this->rootNamespace;
214-
$parts = preg_split('/\\\\/', $remainder);
215-
foreach ($parts as $part) {
216-
if (isset($ns->children[$part])) {
217-
$ns = $ns->children[$part];
218+
$names = explode('\\', substr($qualifiedName, strlen($namespace->qualifiedName) + 1));
219+
foreach ($names as $name) {
220+
if (isset($namespace->children[$name])) {
221+
$namespace = $namespace->children[$name];
218222
continue;
219223
}
220224

221-
$ns->children[$part] = new ProjectNamespace($ns->name . '\\' . $part, $part);
222-
ksort($ns->children);
225+
$child = $namespace->children[$name] = new ProjectNamespace($namespace->qualifiedName . '\\' . $name);
226+
ksort($namespace->children);
223227

224-
$ns = $ns->children[$part];
228+
$namespace = $child;
225229
}
226230

227-
return $ns;
231+
return $namespace;
228232
}
229233
}

src/ProjectNamespace.php

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@
2727

2828
class ProjectNamespace
2929
{
30-
public ?string $name;
30+
public string $name;
3131

32-
public ?string $displayName;
32+
public ?string $qualifiedName;
3333

3434
/**
3535
* @var array<string, self>
@@ -62,13 +62,17 @@ class ProjectNamespace
6262
public array $traits = [];
6363

6464
/**
65-
* @param string|null $name Qualified namespace name
66-
* @param string $displayName Display name
65+
* @param string|null $qualifiedName Qualified name
6766
*/
68-
public function __construct(?string $name, string $displayName)
67+
public function __construct(?string $qualifiedName)
6968
{
70-
$this->name = $name;
71-
$this->displayName = $displayName;
69+
if (!$qualifiedName) {
70+
$this->name = $qualifiedName ?: 'Global';
71+
} else {
72+
$lastSlash = strrpos($qualifiedName, '\\');
73+
$this->name = substr($qualifiedName, $lastSlash + 1);
74+
}
75+
$this->qualifiedName = $qualifiedName;
7276
}
7377

7478
/**

src/Twig/Extension/ReflectionExtension.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ public function __construct(Project $project)
4545
public function getFilters()
4646
{
4747
return [
48-
new TwigFilter('url', function (string $name, string $type) {
48+
new TwigFilter('classlike_to_url', function (string $name, string $type) {
4949
return sprintf('%s-%s.html', $type, preg_replace('[\\\\]', '.', $name));
5050
}),
51-
new TwigFilter('namespace_url', function (?string $name) {
51+
new TwigFilter('namespace_to_url', function (?string $name) {
5252
return sprintf('namespace-%s.html', preg_replace('[\\\\]', '.', $name ?: 'Global'));
5353
}),
5454
new TwigFilter('type', function (?TypeNode $type) {

templates/page.twig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@
5454
<h3 class="nav-title">Namespaces</h3>
5555
<ul class="nav-list">
5656
{% macro listNamespace(namespace, topLevel, context) %}
57-
{% set isActive = context['contextName'] is defined and inNamespace(namespace.name, context['contextName']) %}
57+
{% set isActive = context['contextName'] is defined and inNamespace(namespace.qualifiedName, context['contextName']) %}
5858
<li class="{{ isActive ? 'active' : '' }}">
59-
<a href="{{ namespace.name|namespace_url }}">{{ namespace.displayName }}</a>
59+
<a href="{{ namespace.qualifiedName|namespace_to_url }}">{{ namespace.name }}</a>
6060
{% if (topLevel or isActive) and namespace.children %}
6161
<ul>
6262
{% for child in namespace.children %}

0 commit comments

Comments
 (0)