Completed
Branch 2.0.x (e30486)
by Andrew
02:20
created

CFSTemplateManager   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 116
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 3
Bugs 0 Features 1
Metric Value
wmc 14
c 3
b 0
f 1
lcom 1
cbo 5
dl 0
loc 116
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 2
A getPath() 0 13 2
A isCompileRequired() 0 8 3
A requireSourceFileContent() 0 8 2
A writeFile() 0 5 1
A ensureWriteableDirectory() 0 12 4
1
<?php
2
/**
3
 * @author     Andrew Coulton <[email protected]>
4
 * @copyright  2015 inGenerator Ltd
5
 * @license    http://kohanaframework.org/license
6
 */
7
8
namespace Ingenerator\KohanaView\TemplateManager;
9
10
use Ingenerator\KohanaView\Exception\TemplateCacheException;
11
use Ingenerator\KohanaView\Exception\TemplateNotFoundException;
12
use Ingenerator\KohanaView\TemplateCompiler;
13
use Ingenerator\KohanaView\TemplateManager;
14
15
/**
16
 * Manages compilation of templates from view files located within the cascading file system. This allows extension
17
 * modules or applications to provide their own templates that are used in place of defaults provided by other modules.
18
 *
19
 * Templates will be dynamically compiled and cached to disk:
20
 *  * If the recompile_always option is TRUE, then once for every execution
21
 *  * If the recompile_always option is FALSE, then only if the compiled template does not yet exist
22
 *
23
 * @package Ingenerator\KohanaView\TemplateManager
24
 */
25
class CFSTemplateManager implements TemplateManager
26
{
27
    /**
28
     * @var string
29
     */
30
    protected $cache_dir;
31
32
    /**
33
     * @var CFSWrapper
34
     */
35
    protected $cascading_files;
36
37
    /**
38
     * @var array
39
     */
40
    protected $compiled_paths = [];
41
42
    /**
43
     * @var TemplateCompiler
44
     */
45
    protected $compiler;
46
47
    /**
48
     * @var boolean
49
     */
50
    protected $recompile_always;
51
52
    /**
53
     * Valid options:
54
     * * cache_dir => the path where compiled templates will be cached
55
     * * recompile_always => whether to recompile each template on every execution,
56
     *
57
     * @param TemplateCompiler $compiler
58
     * @param array            $options
59
     * @param CFSWrapper       $cascading_files
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cascading_files not be null|CFSWrapper?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
60
     */
61
    public function __construct(TemplateCompiler $compiler, array $options, CFSWrapper $cascading_files = NULL)
62
    {
63
        $this->cascading_files  = $cascading_files ?: new CFSWrapper;
64
        $this->compiler         = $compiler;
65
        $this->cache_dir        = rtrim($options['cache_dir'], '/');
66
        $this->recompile_always = \Arr::get($options, 'recompile_always', FALSE);
67
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72
    public function getPath($template_name)
73
    {
74
        $compiled_path = $this->cache_dir.'/'.$template_name.'.php';
75
76
        if ($this->isCompileRequired($compiled_path)) {
77
            $source   = $this->requireSourceFileContent($template_name);
78
            $compiled = $this->compiler->compile($source);
79
            $this->writeFile($compiled_path, $compiled);
80
            $this->compiled_paths[$compiled_path] = TRUE;
81
        }
82
83
        return $compiled_path;
84
    }
85
86
    /**
87
     * @param string $compiled_path
88
     *
89
     * @return bool
90
     */
91
    protected function isCompileRequired($compiled_path)
92
    {
93
        if ($this->recompile_always AND ! isset($this->compiled_paths[$compiled_path])) {
1 ignored issue
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
94
            return TRUE;
95
        }
96
97
        return ! file_exists($compiled_path);
98
    }
99
100
    /**
101
     * @param string $template_name
102
     *
103
     * @return string
104
     */
105
    protected function requireSourceFileContent($template_name)
106
    {
107
        if ( ! $source_file = $this->cascading_files->find_file('views', $template_name)) {
108
            throw TemplateNotFoundException::forSourcePath('views/'.$template_name);
109
        }
110
111
        return file_get_contents($source_file);
112
    }
113
114
    /**
115
     * @param string $compiled_path
116
     * @param string $compiled
117
     */
118
    protected function writeFile($compiled_path, $compiled)
119
    {
120
        $this->ensureWriteableDirectory(dirname($compiled_path));
121
        file_put_contents($compiled_path, $compiled);
122
    }
123
124
    /**
125
     * @param string $path
126
     */
127
    protected function ensureWriteableDirectory($path)
128
    {
129
        if (is_dir($path)) {
130
            if ( ! is_writeable($path)) {
131
                throw TemplateCacheException::pathNotWriteable($path);
132
            }
133
        } else {
134
            if ( ! mkdir($path, 0777, TRUE)) {
135
                throw TemplateCacheException::cannotCreateDirectory($path);
136
            }
137
        }
138
    }
139
140
}
141