Completed
Push — 1.x ( c183a4...05b51a )
by Alexander
8s
created

CachingTransformer   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 115
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 14
Bugs 3 Features 3
Metric Value
wmc 19
c 14
b 3
f 3
lcom 1
cbo 2
dl 0
loc 115
ccs 0
cts 62
cp 0
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
C transform() 0 50 14
A processTransformers() 0 16 4
1
<?php
2
/*
3
 * Go! AOP framework
4
 *
5
 * @copyright Copyright 2012, Lisachenko Alexander <[email protected]>
6
 *
7
 * This source file is subject to the license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
11
namespace Go\Instrument\Transformer;
12
13
use Go\Core\AspectKernel;
14
use Go\Instrument\ClassLoading\CachePathManager;
15
16
/**
17
 * Caching transformer that is able to take the transformed source from a cache
18
 */
19
class CachingTransformer extends BaseSourceTransformer
20
{
21
    /**
22
     * Mask of permission bits for cache files.
23
     * By default, permissions are affected by the umask system setting
24
     *
25
     * @var integer|null
26
     */
27
    protected $cacheFileMode;
28
29
    /**
30
     * @var array|callable|SourceTransformer[]
31
     */
32
    protected $transformers = [];
33
34
    /**
35
     * @var CachePathManager|null
36
     */
37
    protected $cacheManager;
38
39
    /**
40
     * Class constructor
41
     *
42
     * @param AspectKernel $kernel Instance of aspect kernel
43
     * @param array|callable $transformers Source transformers or callable that should return transformers
44
     * @param CachePathManager $cacheManager Cache manager
45
     */
46
    public function __construct(AspectKernel $kernel, $transformers, CachePathManager $cacheManager)
47
    {
48
        parent::__construct($kernel);
49
        $this->cacheManager  = $cacheManager;
50
        $this->cacheFileMode = $this->options['cacheFileMode'];
51
        $this->transformers  = $transformers;
52
    }
53
54
    /**
55
     * This method may transform the supplied source and return a new replacement for it
56
     *
57
     * @param StreamMetaData $metadata Metadata for source
58
     * @return bool Return false if transformation should be stopped
59
     */
60
    public function transform(StreamMetaData $metadata)
61
    {
62
        // Do not create a cache
63
        if (!$this->cacheManager->getCacheDir()) {
64
            return $this->processTransformers($metadata);
65
        }
66
67
        $originalUri  = $metadata->uri;
68
        $wasProcessed = false;
69
        $cacheUri     = $this->cacheManager->getCachePathForResource($originalUri);
70
        // Guard to disable overwriting of original files
71
        if ($cacheUri === $originalUri) {
72
            return false;
73
        }
74
75
        $lastModified  = filemtime($originalUri);
76
        $cacheState    = $this->cacheManager->queryCacheState($originalUri);
77
        $cacheModified = $cacheState ? $cacheState['filemtime'] : 0;
78
79
        if ($cacheModified < $lastModified
80
            || (isset($cacheState['cacheUri']) && $cacheState['cacheUri'] !== $cacheUri)
81
            || !$this->container->isFresh($cacheModified)
82
        ) {
83
            $wasProcessed = $this->processTransformers($metadata);
84
            if ($wasProcessed) {
85
                $parentCacheDir = dirname($cacheUri);
86
                if (!is_dir($parentCacheDir)) {
87
                    mkdir($parentCacheDir, $this->cacheFileMode, true);
88
                }
89
                file_put_contents($cacheUri, $metadata->source, LOCK_EX);
90
                // For cache files we don't want executable bits by default
91
                chmod($cacheUri, $this->cacheFileMode & (~0111));
92
            }
93
            $this->cacheManager->setCacheState($originalUri, array(
94
                'filemtime' => isset($_SERVER['REQUEST_TIME']) ? $_SERVER['REQUEST_TIME'] : time(),
95
                'cacheUri'  => $wasProcessed ? $cacheUri : null
96
            ));
97
98
            return $wasProcessed;
99
        }
100
101
        if ($cacheState) {
102
            $wasProcessed = isset($cacheState['cacheUri']);
103
        }
104
        if ($wasProcessed) {
105
            $metadata->source = file_get_contents($cacheUri);
106
        }
107
108
        return $wasProcessed;
109
    }
110
111
    /**
112
     * Iterates over transformers
113
     *
114
     * @param StreamMetaData $metadata Metadata for source code
115
     * @return bool False, if transformation should be stopped
116
     */
117
    private function processTransformers(StreamMetaData $metadata)
118
    {
119
        if (is_callable($this->transformers)) {
120
            $delayedTransformers = $this->transformers;
121
            $this->transformers  = $delayedTransformers();
122
        }
123
        foreach ($this->transformers as $transformer) {
124
            $isTransformed = $transformer->transform($metadata);
125
            // transformer reported about termination, next transformers will be skipped
126
            if ($isTransformed === false) {
127
                return false;
128
            }
129
        }
130
131
        return true;
132
    }
133
}
134