Completed
Pull Request — master (#41)
by Vladimir
02:32
created

Website   C

Complexity

Total Complexity 34

Size/Duplication

Total Lines 423
Duplicated Lines 4.73 %

Coupling/Cohesion

Components 1
Dependencies 19

Importance

Changes 0
Metric Value
dl 20
loc 423
rs 6.325
c 0
b 0
f 0
wmc 34
lcom 1
cbo 19

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
B build() 0 85 2
B watch() 0 47 4
A getConfiguration() 0 4 1
A setConfiguration() 0 19 4
A isConfLess() 0 4 1
A setConfLess() 0 4 1
A isSafeMode() 0 4 1
A setSafeMode() 0 4 1
A isNoClean() 0 4 1
A setNoClean() 0 4 1
A createFolderStructure() 0 13 2
C creationWatcher() 10 40 7
C modificationWatcher() 10 38 7

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/**
4
 * @copyright 2017 Vladimir Jimenez
5
 * @license   https://github.com/allejo/stakx/blob/master/LICENSE.md MIT
6
 */
7
8
namespace allejo\stakx\Object;
9
10
use allejo\stakx\Compiler;
11
use allejo\stakx\Core\StakxLogger;
12
use allejo\stakx\Manager\AssetManager;
13
use allejo\stakx\Manager\CollectionManager;
14
use allejo\stakx\Manager\DataManager;
15
use allejo\stakx\Manager\MenuManager;
16
use allejo\stakx\Manager\PageManager;
17
use allejo\stakx\Manager\ThemeManager;
18
use allejo\stakx\Manager\TwigManager;
19
use allejo\stakx\System\FileExplorer;
20
use allejo\stakx\System\Filesystem;
21
use allejo\stakx\System\Folder;
22
use JasonLewis\ResourceWatcher\Event;
23
use JasonLewis\ResourceWatcher\Resource\FileResource;
24
use JasonLewis\ResourceWatcher\Tracker;
25
use JasonLewis\ResourceWatcher\Watcher;
26
use Symfony\Component\Console\Output\OutputInterface;
27
28
class Website
29
{
30
    /**
31
     * The location of where the compiled website will be written to.
32
     *
33
     * @var Folder
34
     */
35
    private $outputDirectory;
36
37
    /**
38
     * The main configuration to be used to build the specified website.
39
     *
40
     * @var Configuration
41
     */
42
    private $configuration;
43
44
    /**
45
     * When set to true, the Stakx website will be built without a configuration file.
46
     *
47
     * @var bool
48
     */
49
    private $confLess;
50
51
    /**
52
     * When set to true, Twig templates will not have access to filters or functions which provide access to the
53
     * filesystem.
54
     *
55
     * @var bool
56
     */
57
    private $safeMode;
58
59
    /**
60
     * When set to true, Stakx will not clean the _site folder after a rebuild.
61
     *
62
     * @var bool
63
     */
64
    private $noClean;
65
66
    /**
67
     * @var StakxLogger
68
     */
69
    private $output;
70
71
    /**
72
     * @var AssetManager
73
     */
74
    private $am;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $am. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
75
76
    /**
77
     * @var CollectionManager
78
     */
79
    private $cm;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $cm. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
80
81
    /**
82
     * @var DataManager
83
     */
84
    private $dm;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $dm. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
85
86
    /**
87
     * @var Filesystem
88
     */
89
    private $fs;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $fs. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
90
91
    /** @var MenuManager */
92
    private $mm;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $mm. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
93
94
    /**
95
     * @var PageManager
96
     */
97
    private $pm;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $pm. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
98
99
    /**
100
     * @var ThemeManager
101
     */
102
    private $tm;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $tm. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
103
104
    /** @var Compiler */
105
    private $compiler;
106
107
    /**
108
     * Website constructor.
109
     *
110
     * @param OutputInterface $output
111
     */
112
    public function __construct(OutputInterface $output)
113
    {
114
        $this->output = new StakxLogger($output);
115
        $this->cm = new CollectionManager();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
116
        $this->dm = new DataManager();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
117
        $this->mm = new MenuManager();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
118
        $this->pm = new PageManager();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
119
        $this->fs = new Filesystem();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
120
    }
121
122
    /**
123
     * Compile the website.
124
     *
125
     * @param bool $tracking Whether or not to keep track of files as they're compiled to save time in 'watch'
126
     */
127
    public function build($tracking = false)
128
    {
129
        // Configure the environment
130
        $this->createFolderStructure(!$this->noClean);
131
132
        // Our output directory
133
        $this->outputDirectory = new Folder($this->getConfiguration()->getTargetFolder());
134
        $this->outputDirectory->setTargetDirectory($this->getConfiguration()->getBaseUrl());
135
136
        // Parse DataItems
137
        $this->dm->setLogger($this->output);
138
        $this->dm->enableTracking($tracking);
139
        $this->dm->parseDataItems($this->getConfiguration()->getDataFolders());
140
        $this->dm->parseDataSets($this->getConfiguration()->getDataSets());
141
142
        // Prepare Collections
143
        $this->cm->setLogger($this->output);
144
        $this->cm->enableTracking($tracking);
145
        $this->cm->parseCollections($this->getConfiguration()->getCollectionsFolders());
146
147
        // Handle PageViews
148
        $this->pm->setLogger($this->output);
149
        $this->pm->enableTracking($tracking);
150
        $this->pm->setCollections($this->cm->getCollections());
151
        $this->pm->parsePageViews($this->getConfiguration()->getPageViewFolders());
152
153
        // Handle the site's menu
154
        $this->mm->setLogger($this->output);
155
        $this->mm->buildFromPageViews($this->pm->getStaticPageViews());
156
157
        // Configure our Twig environment
158
        $twigEnv = new TwigManager();
159
        $twigEnv->configureTwig($this->getConfiguration(), array(
160
            'safe'    => $this->safeMode,
161
            'globals' => array(
162
                array('name' => 'site', 'value' => $this->getConfiguration()->getConfiguration()),
163
                array('name' => 'collections', 'value' => $this->cm->getJailedCollections()),
164
                array('name' => 'menu', 'value' => $this->mm->getSiteMenu()),
165
                array('name' => 'pages', 'value' => $this->pm->getJailedStaticPageViews()),
166
                array('name' => 'data', 'value' => $this->dm->getDataItems()),
167
            ),
168
        ));
169
170
        // Compile everything
171
        $this->compiler = new Compiler();
172
        $this->compiler->setLogger($this->output);
173
        $this->compiler->setRedirectTemplate($this->getConfiguration()->getRedirectTemplate());
174
        $this->compiler->setPageViews($this->pm->getPageViews(), $this->pm->getPageViewsFlattened());
175
        $this->compiler->setTargetFolder($this->outputDirectory);
176
        $this->compiler->compileAll();
177
178
        // At this point, we are looking at static files to copy over meaning we need to ignore all of the files that
179
        // make up the source of a stakx website
180
        $assetsToIgnore = array_merge(
181
            Configuration::$stakxSourceFiles,
182
            $this->getConfiguration()->getExcludes()
183
        );
184
185
        //
186
        // Theme Management
187
        //
188
        $theme = $this->configuration->getTheme();
189
190
        if (!is_null($theme))
191
        {
192
            $this->output->notice("Looking for '${theme}' theme...");
193
194
            $this->tm = new ThemeManager($theme);
195
            $this->tm->configureFinder($this->getConfiguration()->getIncludes(), $assetsToIgnore);
196
            $this->tm->setLogger($this->output);
197
            $this->tm->enableTracking($tracking);
198
            $this->tm->setFolder($this->outputDirectory);
199
            $this->tm->copyFiles();
200
        }
201
202
        //
203
        // Static file management
204
        //
205
        $this->am = new AssetManager();
206
        $this->am->configureFinder($this->getConfiguration()->getIncludes(), $assetsToIgnore);
207
        $this->am->setLogger($this->output);
208
        $this->am->setFolder($this->outputDirectory);
209
        $this->am->enableTracking($tracking);
210
        $this->am->copyFiles();
211
    }
212
213
    public function watch()
214
    {
215
        $this->output->writeln('Building website...');
216
        $this->build(true);
217
        $this->output->writeln(sprintf('Watching %s', getcwd()));
218
219
        $fileExplorer = FileExplorer::create(
220
            getcwd(),
221
            array_merge($this->getConfiguration()->getExcludes(), array(
222
                $this->getConfiguration()->getTargetFolder(),
223
            )),
224
            $this->getConfiguration()->getIncludes()
225
        );
226
        $tracker = new Tracker();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
227
        $watcher = new Watcher($tracker, $this->fs);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
228
        $listener = $watcher->watch(getcwd(), $fileExplorer->getExplorer());
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
229
        $targetPath = $this->getConfiguration()->getTargetFolder();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
230
231
        $this->output->writeln('Watch started successfully');
232
233
        $listener->onAnything(function (Event $event, FileResource $resouce, $path) use ($targetPath)
234
        {
235
            $filePath = $this->fs->getRelativePath($path);
236
237
            try
238
            {
239
                switch ($event->getCode())
240
                {
241
                    case Event::RESOURCE_CREATED:
242
                        $this->creationWatcher($filePath);
243
                        break;
244
245
                    case Event::RESOURCE_MODIFIED:
246
                        $this->modificationWatcher($filePath);
247
                        break;
248
                }
249
            }
250
            catch (\Exception $e)
251
            {
252
                $this->output->error(sprintf('Your website failed to build with the following error: %s',
253
                    $e->getMessage()
254
                ));
255
            }
256
        });
257
258
        $watcher->start();
259
    }
260
261
    /**
262
     * @return Configuration
263
     */
264
    public function getConfiguration()
265
    {
266
        return $this->configuration;
267
    }
268
269
    /**
270
     * @param string $configFile
271
     *
272
     * @throws \LogicException
273
     */
274
    public function setConfiguration($configFile)
275
    {
276
        if (!$this->fs->exists($configFile) && !$this->isConfLess())
277
        {
278
            $this->output->error('You are trying to build a website in a directory without a configuration file. Is this what you meant to do?');
279
            $this->output->error("To build a website without a configuration, use the '--no-conf' option");
280
281
            throw new \LogicException('Cannot build a website without a configuration when not in Configuration-less mode');
282
        }
283
284
        if ($this->isConfLess())
285
        {
286
            $configFile = '';
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $configFile. This often makes code more readable.
Loading history...
287
        }
288
289
        $this->configuration = new Configuration();
290
        $this->configuration->setLogger($this->output);
291
        $this->configuration->parseConfiguration($configFile);
292
    }
293
294
    /**
295
     * Get whether or not the website is being built in Configuration-less mode.
296
     *
297
     * @return bool True when being built with no configuration file
298
     */
299
    public function isConfLess()
300
    {
301
        return $this->confLess;
302
    }
303
304
    /**
305
     * Set whether or not the website should be built with a configuration.
306
     *
307
     * @param bool $status True when a website should be built without a configuration
308
     */
309
    public function setConfLess($status)
310
    {
311
        $this->confLess = $status;
312
    }
313
314
    /**
315
     * Get whether or not the website is being built in safe mode.
316
     *
317
     * Safe mode is defined as disabling file system access from Twig and disabling user Twig extensions
318
     *
319
     * @return bool True when the website is being built in safe mode
320
     */
321
    public function isSafeMode()
322
    {
323
        return $this->safeMode;
324
    }
325
326
    /**
327
     * Set whether a website should be built in safe mode.
328
     *
329
     * @param bool $bool True if a website should be built in safe mode
330
     */
331
    public function setSafeMode($bool)
332
    {
333
        $this->safeMode = $bool;
334
    }
335
336
    /**
337
     * @return bool
338
     */
339
    public function isNoClean()
340
    {
341
        return $this->noClean;
342
    }
343
344
    /**
345
     * @param bool $noClean
346
     */
347
    public function setNoClean($noClean)
348
    {
349
        $this->noClean = $noClean;
350
    }
351
352
    private function creationWatcher($filePath)
353
    {
354
        $this->output->writeln(sprintf('File creation detected: %s', $filePath));
355
356
        if ($this->pm->isHandled($filePath))
357
        {
358
            $this->pm->createNewItem($filePath);
359
            $this->pm->refreshItem($filePath);
360
        }
361
        elseif ($this->cm->isHandled($filePath))
362
        {
363
            $contentItem = $this->cm->createNewItem($filePath);
364
            TwigManager::getInstance()->addGlobal('collections', $this->cm->getCollections());
365
366
            $this->pm->trackNewContentItem($contentItem);
367
            $this->compiler->compileContentItem($contentItem);
0 ignored issues
show
Deprecated Code introduced by
The method allejo\stakx\Compiler::compileContentItem() has been deprecated.

This method has been deprecated.

Loading history...
368
            $this->compiler->compileSome(array(
369
                'namespace' => 'collections',
370
                'dependency' => $contentItem->getCollection()
371
            ));
372
        }
373 View Code Duplication
        elseif ($this->dm->isHandled($filePath))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
374
        {
375
            $change = $this->dm->createNewItem($filePath);
376
            TwigManager::getInstance()->addGlobal('data', $this->dm->getDataItems());
377
378
            $this->compiler->compileSome(array(
379
                'namespace' => 'data',
380
                'dependency' => $change
381
            ));
382
        }
383
        elseif (!is_null($this->tm) && $this->tm->isHandled($filePath))
384
        {
385
            $this->tm->createNewItem($filePath);
386
        }
387
        elseif ($this->am->isHandled($filePath))
388
        {
389
            $this->am->createNewItem($filePath);
390
        }
391
    }
392
393
    private function modificationWatcher($filePath)
394
    {
395
        $this->output->writeln(sprintf('File change detected: %s', $filePath));
396
397
        if ($this->pm->isTracked($filePath))
398
        {
399
            $this->pm->refreshItem($filePath);
400
        }
401
        elseif ($this->cm->isTracked($filePath))
402
        {
403
            $contentItem = &$this->cm->getContentItem($filePath);
404
            $contentItem->refreshFileContent();
405
406
            $this->compiler->compileContentItem($contentItem);
0 ignored issues
show
Deprecated Code introduced by
The method allejo\stakx\Compiler::compileContentItem() has been deprecated.

This method has been deprecated.

Loading history...
407
            $this->compiler->compileSome(array(
408
                'namespace' => 'collections',
409
                'dependency' => $contentItem->getCollection()
410
            ));
411
        }
412 View Code Duplication
        elseif ($this->dm->isTracked($filePath))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
413
        {
414
            $change = $this->dm->refreshItem($filePath);
415
            TwigManager::getInstance()->addGlobal('data', $this->dm->getDataItems());
416
417
            $this->compiler->compileSome(array(
418
                'namespace' => 'data',
419
                'dependency' => $change
420
            ));
421
        }
422
        elseif (!is_null($this->tm) && $this->tm->isTracked($filePath))
423
        {
424
            $this->tm->refreshItem($filePath);
425
        }
426
        elseif ($this->am->isTracked($filePath))
427
        {
428
            $this->am->refreshItem($filePath);
429
        }
430
    }
431
432
    /**
433
     * Prepare the Stakx environment by creating necessary cache folders.
434
     *
435
     * @param bool $cleanDirectory Clean the target directory
436
     */
437
    private function createFolderStructure($cleanDirectory)
438
    {
439
        $tarDir = $this->fs->absolutePath($this->configuration->getTargetFolder());
440
441
        if ($cleanDirectory)
442
        {
443
            $this->fs->remove($tarDir);
444
        }
445
446
        $this->fs->remove($this->fs->absolutePath('.stakx-cache'));
447
        $this->fs->mkdir($this->fs->absolutePath('.stakx-cache/twig'));
448
        $this->fs->mkdir($tarDir);
449
    }
450
}
451