Completed
Push — master ( 91676c...354384 )
by Alexander
02:23
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 Closure;
15
use Go\Core\AspectKernel;
16
use Go\Instrument\ClassLoading\CachePathManager;
17
use function dirname;
18
19
/**
20
 * Caching transformer that is able to take the transformed source from a cache
21
 */
22
class CachingTransformer extends BaseSourceTransformer
23
{
24
    /**
25
     * Mask of permission bits for cache files.
26
     * By default, permissions are affected by the umask system setting
27
     *
28
     * @var integer|null
29
     */
30
    protected $cacheFileMode;
31
32
    /**
33
     * @var array|Closure|SourceTransformer[]
34
     */
35
    protected $transformers = [];
36
37
    /**
38
     * Cache manager
39
     */
40
    protected $cacheManager;
41
42
    /**
43
     * Class constructor
44
     *
45
     * @param array|callable $transformers Source transformers or callable that should return transformers
46
     */
47 1
    public function __construct(AspectKernel $kernel, $transformers, CachePathManager $cacheManager)
48
    {
49 1
        parent::__construct($kernel);
50 1
        $this->cacheManager  = $cacheManager;
51 1
        $this->cacheFileMode = $this->options['cacheFileMode'];
52 1
        $this->transformers  = $transformers;
0 ignored issues
show
Documentation Bug introduced by
It seems like $transformers of type callable is incompatible with the declared type array|object<Closure> of property $transformers.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
53 1
    }
54
55
    /**
56
     * This method may transform the supplied source and return a new replacement for it
57
     *
58
     * @return string See RESULT_XXX constants in the interface
59
     */
60 1
    public function transform(StreamMetaData $metadata): string
61
    {
62 1
        $originalUri      = $metadata->uri;
63 1
        $processingResult = self::RESULT_ABSTAIN;
64 1
        $cacheUri         = $this->cacheManager->getCachePathForResource($originalUri);
65
        // Guard to disable overwriting of original files
66 1
        if ($cacheUri === $originalUri) {
67
            return self::RESULT_ABORTED;
68
        }
69
70 1
        $lastModified  = filemtime($originalUri);
71 1
        $cacheState    = $this->cacheManager->queryCacheState($originalUri);
72 1
        $cacheModified = $cacheState ? $cacheState['filemtime'] : 0;
73
74 1
        if ($cacheModified < $lastModified
75
            || (isset($cacheState['cacheUri']) && $cacheState['cacheUri'] !== $cacheUri)
76 1
            || !$this->container->isFresh($cacheModified)
77
        ) {
78 1
            $processingResult = $this->processTransformers($metadata);
79 1
            if ($processingResult === self::RESULT_TRANSFORMED) {
80 1
                $parentCacheDir = dirname($cacheUri);
81 1
                if (!is_dir($parentCacheDir)) {
82 1
                    mkdir($parentCacheDir, $this->cacheFileMode, true);
83
                }
84 1
                file_put_contents($cacheUri, $metadata->source, LOCK_EX);
85
                // For cache files we don't want executable bits by default
86 1
                chmod($cacheUri, $this->cacheFileMode & (~0111));
87
            }
88 1
            $this->cacheManager->setCacheState($originalUri, [
89 1
                'filemtime' => $_SERVER['REQUEST_TIME'] ?? time(),
90 1
                'cacheUri'  => ($processingResult === self::RESULT_TRANSFORMED) ? $cacheUri : null
91
            ]);
92
93 1
            return $processingResult;
94
        }
95
96
        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...
97
            $processingResult = isset($cacheState['cacheUri']) ? self::RESULT_TRANSFORMED : self::RESULT_ABORTED;
98
        }
99
        if ($processingResult === self::RESULT_TRANSFORMED) {
100
            // Just replace all tokens in the stream
101
            $metadata->tokenStream = token_get_all(file_get_contents($cacheUri));
102
        }
103
104
        return $processingResult;
105
    }
106
107
    /**
108
     * Iterates over transformers
109
     *
110
     * @return string See RESULT_XXX constants in the interface
111
     */
112 1
    private function processTransformers(StreamMetaData $metadata): string
113
    {
114 1
        $overallResult = self::RESULT_ABSTAIN;
115 1
        if ($this->transformers instanceof Closure) {
116 1
            $delayedTransformers = $this->transformers;
117 1
            $this->transformers  = $delayedTransformers();
118
        }
119 1
        foreach ($this->transformers as $transformer) {
120 1
            $transformationResult = $transformer->transform($metadata);
121 1
            if ($overallResult === self::RESULT_ABSTAIN && $transformationResult === self::RESULT_TRANSFORMED) {
122 1
                $overallResult = self::RESULT_TRANSFORMED;
123
            }
124
            // transformer reported about termination, next transformers will be skipped
125 1
            if ($transformationResult === self::RESULT_ABORTED) {
126
                $overallResult = self::RESULT_ABORTED;
127
                break;
128
            }
129
        }
130
131 1
        return $overallResult;
132
    }
133
}
134