Completed
Push — master ( efe256...811ea7 )
by Alexander
11s
created

CachingTransformer::transform()   C

Complexity

Conditions 13
Paths 19

Size

Total Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 15.6406

Importance

Changes 0
Metric Value
dl 0
loc 46
ccs 21
cts 28
cp 0.75
rs 6.6166
c 0
b 0
f 0
cc 13
nc 19
nop 1
crap 15.6406

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types = 1);
3
/*
4
 * Go! AOP framework
5
 *
6
 * @copyright Copyright 2012, Lisachenko Alexander <[email protected]>
7
 *
8
 * This source file is subject to the license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Go\Instrument\Transformer;
13
14
use Go\Core\AspectKernel;
15
use Go\Instrument\ClassLoading\CachePathManager;
16
17
/**
18
 * Caching transformer that is able to take the transformed source from a cache
19
 */
20
class CachingTransformer extends BaseSourceTransformer
21
{
22
    /**
23
     * Mask of permission bits for cache files.
24
     * By default, permissions are affected by the umask system setting
25
     *
26
     * @var integer|null
27
     */
28
    protected $cacheFileMode;
29
30
    /**
31
     * @var array|callable|SourceTransformer[]
32
     */
33
    protected $transformers = [];
34
35
    /**
36
     * Cache manager
37
     */
38
    protected $cacheManager;
39
40
    /**
41
     * Class constructor
42
     *
43
     * @param array|callable $transformers Source transformers or callable that should return transformers
44
     */
45 1
    public function __construct(AspectKernel $kernel, $transformers, CachePathManager $cacheManager)
46
    {
47 1
        parent::__construct($kernel);
48 1
        $this->cacheManager  = $cacheManager;
49 1
        $this->cacheFileMode = $this->options['cacheFileMode'];
50 1
        $this->transformers  = $transformers;
51 1
    }
52
53
    /**
54
     * This method may transform the supplied source and return a new replacement for it
55
     *
56
     * @return string See RESULT_XXX constants in the interface
57
     */
58 1
    public function transform(StreamMetaData $metadata): string
59
    {
60 1
        $originalUri      = $metadata->uri;
61 1
        $processingResult = self::RESULT_ABSTAIN;
62 1
        $cacheUri         = $this->cacheManager->getCachePathForResource($originalUri);
63
        // Guard to disable overwriting of original files
64 1
        if ($cacheUri === $originalUri) {
65
            return self::RESULT_ABORTED;
66
        }
67
68 1
        $lastModified  = filemtime($originalUri);
69 1
        $cacheState    = $this->cacheManager->queryCacheState($originalUri);
70 1
        $cacheModified = $cacheState ? $cacheState['filemtime'] : 0;
71
72 1
        if ($cacheModified < $lastModified
73
            || (isset($cacheState['cacheUri']) && $cacheState['cacheUri'] !== $cacheUri)
74 1
            || !$this->container->isFresh($cacheModified)
75
        ) {
76 1
            $processingResult = $this->processTransformers($metadata);
77 1
            if ($processingResult === self::RESULT_TRANSFORMED) {
78 1
                $parentCacheDir = dirname($cacheUri);
79 1
                if (!is_dir($parentCacheDir)) {
80 1
                    mkdir($parentCacheDir, $this->cacheFileMode, true);
81
                }
82 1
                file_put_contents($cacheUri, $metadata->source, LOCK_EX);
83
                // For cache files we don't want executable bits by default
84 1
                chmod($cacheUri, $this->cacheFileMode & (~0111));
85
            }
86 1
            $this->cacheManager->setCacheState($originalUri, [
87 1
                'filemtime' => $_SERVER['REQUEST_TIME'] ?? time(),
88 1
                'cacheUri'  => ($processingResult === self::RESULT_TRANSFORMED) ? $cacheUri : null
89
            ]);
90
91 1
            return $processingResult;
92
        }
93
94
        if ($cacheState) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $cacheState of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
95
            $processingResult = isset($cacheState['cacheUri']) ? self::RESULT_TRANSFORMED : self::RESULT_ABORTED;
96
        }
97
        if ($processingResult === self::RESULT_TRANSFORMED) {
98
            // Just replace all tokens in the stream
99
            $metadata->tokenStream = token_get_all(file_get_contents($cacheUri));
100
        }
101
102
        return $processingResult;
103
    }
104
105
    /**
106
     * Iterates over transformers
107
     *
108
     * @return string See RESULT_XXX constants in the interface
109
     */
110 1
    private function processTransformers(StreamMetaData $metadata): string
111
    {
112 1
        $overallResult = self::RESULT_ABSTAIN;
113 1
        if (is_callable($this->transformers)) {
114 1
            $delayedTransformers = $this->transformers;
115 1
            $this->transformers  = $delayedTransformers();
116
        }
117 1
        foreach ($this->transformers as $transformer) {
118 1
            $transformationResult = $transformer->transform($metadata);
119 1
            if ($overallResult === self::RESULT_ABSTAIN && $transformationResult === self::RESULT_TRANSFORMED) {
120 1
                $overallResult = self::RESULT_TRANSFORMED;
121
            }
122
            // transformer reported about termination, next transformers will be skipped
123 1
            if ($transformationResult === self::RESULT_ABORTED) {
124
                $overallResult = self::RESULT_ABORTED;
125 1
                break;
126
            }
127
        }
128
129 1
        return $overallResult;
130
    }
131
}
132