Completed
Pull Request — master (#5)
by David
02:51
created

ThemeRegistry::getThemePath()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 1
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
4
namespace TheCodingMachine\CMS\StaticRegistry\Registry;
5
6
7
use Psr\Container\ContainerInterface;
8
use Psr\SimpleCache\CacheInterface;
9
use Symfony\Component\Finder\Finder;
10
use TheCodingMachine\CMS\StaticRegistry\Loaders\SubTheme;
11
use TheCodingMachine\CMS\StaticRegistry\Loaders\Theme;
12
use TheCodingMachine\CMS\Theme\SubThemeDescriptor;
13
use TheCodingMachine\CMS\Theme\ThemeDescriptorInterface;
14
use TheCodingMachine\CMS\Theme\TwigThemeDescriptor;
15
16
/**
17
 * The theme registry can fetch Theme objects from the "theme" directory or from the container.
18
 */
19
class ThemeRegistry
20
{
21
    /**
22
     * @var string
23
     */
24
    private $themeDirectory;
25
    /**
26
     * @var string
27
     */
28
    private $subThemeDirectory;
29
    /**
30
     * @var ContainerInterface
31
     */
32
    private $container;
33
    /**
34
     * @var CacheInterface
35
     */
36
    private $cache;
37
    /**
38
     * @var SubTheme[]
39
     */
40
    private $subThemes;
41
    /**
42
     * @var BlockRegistry
43
     */
44
    private $blockRegistry;
45
46
    public function __construct(string $themeDirectory, string $subThemeDirectory, ContainerInterface $container, CacheInterface $cache, BlockRegistry $blockRegistry)
47
    {
48
        $this->themeDirectory = rtrim($themeDirectory, '/\\').'/';
49
        $this->subThemeDirectory = rtrim($subThemeDirectory, '/\\').'/';
50
        $this->container = $container;
51
        $this->cache = $cache;
52
        $this->blockRegistry = $blockRegistry;
53
    }
54
55
    public function getThemeDescriptor(string $themeName): ThemeDescriptorInterface
56
    {
57
        $key = 'theme.'.$themeName;
58
        $theme = $this->cache->get($key);
59
        if ($theme === null) {
60
            $theme = $this->getThemeNoCache($themeName);
61
            $this->cache->set($key, $theme);
62
        }
63
        return $theme;
64
    }
65
66
    private function getThemeNoCache(string $themeName): ThemeDescriptorInterface
67
    {
68
        $dir = $this->themeDirectory.$themeName;
69
        if ($this->container->has($themeName)) {
70
            $entry = $this->container->get($themeName);
71
            if ($entry instanceof Theme) {
72
                return $this->themeToBlock($entry);
73
            }
74
            if ($entry instanceof SubTheme) {
75
                return $this->subThemeToBlock($entry);
76
            }
77
            if ($entry instanceof ThemeDescriptorInterface) {
78
                return $entry;
79
            }
80
        }
81
82
        if (Theme::existsInDirectory($dir)) {
83
            return $this->themeToBlock(Theme::fromDirectory($dir));
84
        }
85
86
        $subThemes = $this->getSubThemes();
87
        if (isset($subThemes[$themeName])) {
88
            return $this->subThemeToBlock($subThemes[$themeName]);
89
        } else {
90
            throw ThemeNotFoundException::couldNotLoadTheme($themeName, $dir);
91
        }
92
    }
93
94
    private function themeToBlock(Theme $theme) : ThemeDescriptorInterface
95
    {
96
        return new TwigThemeDescriptor('index.twig', [
97
            'theme' => $theme->getName()
98
        ]);
99
    }
100
101
    private function subThemeToBlock(SubTheme $subTheme) : ThemeDescriptorInterface
102
    {
103
        $context = [];
104
        foreach ($subTheme->getAssignations() as $zone => $blocks) {
105
            foreach ($blocks as $blockName) {
106
                foreach ($this->blockRegistry->getBlocks($blockName) as $block) {
107
                    $context[$zone][] = $block->toCmsBlock($this->getThemePath($subTheme));
108
                }
109
            }
110
        }
111
        return new SubThemeDescriptor($this->getThemeDescriptor($subTheme->getParent()), $context);
112
    }
113
114
    private function getThemePath(SubTheme $subTheme): string
115
    {
116
        $subThemes = $this->getSubThemes();
117
        while (true) {
118
            $parentName = $subTheme->getParent();
119
            if (!isset($subThemes[$parentName])) {
120
                break;
121
            }
122
            $subTheme = $subThemes[$parentName];
123
        }
124
        return $parentName;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $parentName does not seem to be defined for all execution paths leading up to this point.
Loading history...
125
    }
126
127
    /**
128
     * Loads all subthemes and returns them, indexed by name.
129
     *
130
     * @return SubTheme[]
131
     * @throws \TheCodingMachine\CMS\StaticRegistry\Registry\DuplicateSubThemeException
132
     */
133
    private function getSubThemes(): array
134
    {
135
        if ($this->subThemes === null)
136
        {
137
            $this->subThemes = [];
138
            $fileList = new Finder();
139
140
            $fileList->files()->in($this->subThemeDirectory)->name('/\.yml|\.yaml/')->sortByName();
141
142
            foreach ($fileList as $splFileInfo) {
143
                $subTheme = SubTheme::fromFile($splFileInfo->getRealPath());
144
                $themeName = $subTheme->getName();
145
                if (isset($this->subThemes[$themeName])) {
146
                    throw new DuplicateSubThemeException(sprintf('The sub-theme "%s" has been found twice.', $themeName));
147
                }
148
                $this->subThemes[$themeName] = $subTheme;
149
            }
150
        }
151
        return $this->subThemes;
152
    }
153
}
154