Issues (2882)

src/View/ThemeManifest.php (1 issue)

Severity
1
<?php
2
3
namespace SilverStripe\View;
4
5
use Psr\SimpleCache\CacheInterface;
6
use SilverStripe\Core\Cache\CacheFactory;
7
use SilverStripe\Core\Manifest\ManifestFileFinder;
8
use SilverStripe\Core\Manifest\ModuleLoader;
9
10
/**
11
 * A class which builds a manifest of all themes (which is really just a directory called "templates")
12
 */
13
class ThemeManifest implements ThemeList
14
{
15
16
    const TEMPLATES_DIR = 'templates';
17
18
    /**
19
     * Base path
20
     *
21
     * @var string
22
     */
23
    protected $base;
24
25
    /**
26
     * Path to application code
27
     *
28
     * @var string
29
     */
30
    protected $project;
31
32
    /**
33
     * Cache
34
     *
35
     * @var CacheInterface
36
     */
37
    protected $cache;
38
39
    /**
40
     * Cache key
41
     *
42
     * @var string
43
     */
44
    protected $cacheKey;
45
46
    /**
47
     * List of theme root directories
48
     *
49
     * @var string[]
50
     */
51
    protected $themes = null;
52
53
    /**
54
     * @var CacheFactory
55
     */
56
    protected $cacheFactory= null;
57
58
    /**
59
     * Constructs a new template manifest. The manifest is not actually built
60
     * or loaded from cache until needed.
61
     *
62
     * @param string $base The base path.
63
     * @param string $project Path to application code
64
     * @param CacheFactory $cacheFactory Cache factory to generate backend cache with
65
     */
66
    public function __construct($base, $project = null, CacheFactory $cacheFactory = null)
67
    {
68
        $this->base = $base;
69
        $this->project = $project;
70
        $this->cacheFactory = $cacheFactory;
71
    }
72
73
    /**
74
     * @param bool $includeTests Include tests in the manifest
75
     * @param bool $forceRegen Force the manifest to be regenerated.
76
     */
77
    public function init($includeTests = false, $forceRegen = false)
78
    {
79
        // build cache from factory
80
        if ($this->cacheFactory) {
81
            $this->cache = $this->cacheFactory->create(
82
                CacheInterface::class . '.thememanifest',
83
                [ 'namespace' => 'thememanifest' . ($includeTests ? '_tests' : '') ]
84
            );
85
        }
86
        $this->cacheKey = $this->getCacheKey($includeTests);
87
        if (!$forceRegen && $this->cache && ($data = $this->cache->get($this->cacheKey))) {
88
            $this->themes = $data;
89
        } else {
90
            $this->regenerate($includeTests);
91
        }
92
    }
93
94
    /**
95
     * @return string
96
     */
97
    public function getBase()
98
    {
99
        return $this->base;
100
    }
101
102
    /**
103
     * Generate a unique cache key to avoid manifest cache collisions.
104
     * We compartmentalise based on the base path, the given project, and whether
105
     * or not we intend to include tests.
106
     *
107
     * @param bool $includeTests
108
     * @return string
109
     */
110
    public function getCacheKey($includeTests = false)
111
    {
112
        return sha1(sprintf(
113
            "manifest-%s-%s-%u",
114
            $this->base,
115
            $this->project,
116
            $includeTests
117
        ));
118
    }
119
120
    /**
121
     * @return string[]
122
     */
123
    public function getThemes()
124
    {
125
        return $this->themes;
126
    }
127
128
    /**
129
     * Regenerates the manifest by scanning the base path.
130
     *
131
     * @param bool $includeTests
132
     */
133
    public function regenerate($includeTests = false)
134
    {
135
        $finder = new ManifestFileFinder();
136
        $finder->setOptions(array(
137
            'include_themes' => false,
138
            'ignore_dirs' => array('node_modules', THEMES_DIR),
139
            'ignore_tests'  => !$includeTests,
140
            'dir_callback'  => array($this, 'handleDirectory')
141
        ));
142
143
        $this->themes = [];
144
145
        $modules = ModuleLoader::inst()->getManifest()->getModules();
146
        foreach ($modules as $module) {
147
            $finder->find($module->getPath());
148
        }
149
150
        if ($this->cache) {
151
            $this->cache->set($this->cacheKey, $this->themes);
152
        }
153
    }
154
155
    /**
156
     * Add a directory to the manifest
157
     *
158
     * @param string $basename
159
     * @param string $pathname
160
     * @param int $depth
161
     */
162
    public function handleDirectory($basename, $pathname, $depth)
0 ignored issues
show
The parameter $depth is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

162
    public function handleDirectory($basename, $pathname, /** @scrutinizer ignore-unused */ $depth)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
163
    {
164
        if ($basename !== self::TEMPLATES_DIR) {
165
            return;
166
        }
167
        $dir = trim(substr(dirname($pathname), strlen($this->base)), '/\\');
168
        $this->themes[] = "/" . $dir;
169
    }
170
171
    /**
172
     * Sets the project
173
     *
174
     * @param string $project
175
     * @return $this
176
     */
177
    public function setProject($project)
178
    {
179
        $this->project = $project;
180
181
        return $this;
182
    }
183
}
184