Passed
Push — master ( 4bccec...259a7c )
by David
01:44
created

ThemeRegistry::getSubThemes()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 2
nop 0
dl 0
loc 18
rs 9.2
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($theme->getPath().'/index.twig', []);
97
    }
98
99
    private function subThemeToBlock(SubTheme $subTheme) : ThemeDescriptorInterface
100
    {
101
        $context = [];
102
        foreach ($subTheme->getAssignations() as $zone => $blocks) {
103
            foreach ($blocks as $blockName) {
104
                foreach ($this->blockRegistry->getBlocks($blockName) as $block) {
105
                    // FIXME: here we should insert a CONDITIONAL block that displays only when the correct language is set.
106
                    $context[$zone][] = $block->getContent();
107
                }
108
            }
109
        }
110
        return new SubThemeDescriptor($this->getThemeNoCache($subTheme->getParent()), $context);
111
    }
112
113
    /**
114
     * Loads all subthemes and returns them, indexed by name.
115
     *
116
     * @return SubTheme[]
117
     * @throws \TheCodingMachine\CMS\StaticRegistry\Registry\DuplicateSubThemeException
118
     */
119
    private function getSubThemes(): array
120
    {
121
        if ($this->subThemes === null)
122
        {
123
            $fileList = new Finder();
124
125
            $fileList->files()->in($this->subThemeDirectory)->name('/\.yml|\.yaml/')->sortByName();
126
127
            foreach ($fileList as $splFileInfo) {
128
                $subTheme = SubTheme::fromFile($splFileInfo->getRealPath());
129
                $themeName = $subTheme->getName();
130
                if (isset($this->subThemes[$themeName])) {
131
                    throw new DuplicateSubThemeException(sprintf('The sub-theme "%s" has been found twice.', $themeName));
132
                }
133
                $this->subThemes[$themeName] = $subTheme;
134
            }
135
        }
136
        return $this->subThemes;
137
    }
138
}
139