Completed
Pull Request — master (#463)
by Alexander
30:17 queued 05:15
created

CachingTransformer::transform()   C

Complexity

Conditions 13
Paths 19

Size

Total Lines 47

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 15.9464

Importance

Changes 0
Metric Value
dl 0
loc 47
ccs 20
cts 27
cp 0.7407
rs 6.6166
c 0
b 0
f 0
cc 13
nc 19
nop 1
crap 15.9464

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
3
declare(strict_types=1);
4
/*
5
 * Go! AOP framework
6
 *
7
 * @copyright Copyright 2012, Lisachenko Alexander <[email protected]>
8
 *
9
 * This source file is subject to the license that is bundled
10
 * with this source code in the file LICENSE.
11
 */
12
13
namespace Go\Instrument\Transformer;
14
15
use Closure;
16
use Go\Core\AspectKernel;
17
use Go\Instrument\ClassLoading\CachePathManager;
18
use Go\ParserReflection\ReflectionEngine;
19
20
use function dirname;
21
22
/**
23
 * Caching transformer that is able to take the transformed source from a cache
24
 */
25
class CachingTransformer extends BaseSourceTransformer
26
{
27
    /**
28
     * Mask of permission bits for cache files.
29
     * By default, permissions are affected by the umask system setting
30
     */
31
    protected int $cacheFileMode = 0770;
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_STRING, expecting T_FUNCTION or T_CONST
Loading history...
32
33
    /**
34
     * @var array|Closure|SourceTransformer[]
35
     */
36
    protected $transformers = [];
37
38
    /**
39
     * Cache manager
40
     */
41
    protected CachePathManager $cacheManager;
42
43
    /**
44
     * Class constructor
45
     *
46
     * @param array|callable $transformers Source transformers or callable that should return transformers
47 1
     */
48
    public function __construct(AspectKernel $kernel, $transformers, CachePathManager $cacheManager)
49 1
    {
50 1
        parent::__construct($kernel);
51 1
        $this->cacheManager  = $cacheManager;
52 1
        $this->cacheFileMode = $this->options['cacheFileMode'];
53 1
        $this->transformers  = $transformers;
54
    }
55
56
    /**
57
     * This method may transform the supplied source and return a new replacement for it
58
     *
59
     * @return string See RESULT_XXX constants in the interface
60 1
     */
61
    public function transform(StreamMetaData $metadata): string
62 1
    {
63 1
        $originalUri      = $metadata->uri;
64 1
        $processingResult = self::RESULT_ABSTAIN;
65
        $cacheUri         = $this->cacheManager->getCachePathForResource($originalUri);
66 1
        // Guard to disable overwriting of original files
67
        if ($cacheUri === $originalUri) {
68
            return self::RESULT_ABORTED;
69
        }
70 1
71 1
        $lastModified  = filemtime($originalUri);
72 1
        $cacheState    = $this->cacheManager->queryCacheState($originalUri);
73
        $cacheModified = $cacheState ? $cacheState['filemtime'] : 0;
74 1
75
        if ($cacheModified < $lastModified
76 1
            || (isset($cacheState['cacheUri']) && $cacheState['cacheUri'] !== $cacheUri)
77
            || !$this->container->isFresh($cacheModified)
78 1
        ) {
79 1
            $processingResult = $this->processTransformers($metadata);
80 1
            if ($processingResult === self::RESULT_TRANSFORMED) {
81 1
                $parentCacheDir = dirname($cacheUri);
82 1
                if (!is_dir($parentCacheDir)) {
83
                    mkdir($parentCacheDir, $this->cacheFileMode, true);
84 1
                }
85
                file_put_contents($cacheUri, $metadata->source, LOCK_EX);
86 1
                // For cache files we don't want executable bits by default
87
                chmod($cacheUri, $this->cacheFileMode & (~0111));
88 1
            }
89 1
            $this->cacheManager->setCacheState(
90 1
                $originalUri,
91
                [
92
                    'filemtime' => $_SERVER['REQUEST_TIME'] ?? time(),
93 1
                    'cacheUri'  => ($processingResult === self::RESULT_TRANSFORMED) ? $cacheUri : null
94
                ]
95
            );
96
97
            return $processingResult;
98
        }
99
100
        if ($cacheState) {
101
            $processingResult = isset($cacheState['cacheUri']) ? self::RESULT_TRANSFORMED : self::RESULT_ABORTED;
102
        }
103
        if ($processingResult === self::RESULT_TRANSFORMED) {
104
            // Just replace all tokens in the stream
105
            ReflectionEngine::parseFile($cacheUri);
106
            $metadata->setTokenStreamFromRawTokens(
107
                ReflectionEngine::getLexer()
108
                                ->getTokens()
109
            );
110
        }
111
112 1
        return $processingResult;
113
    }
114 1
115 1
    /**
116 1
     * Iterates over transformers
117 1
     *
118
     * @return string See RESULT_XXX constants in the interface
119 1
     */
120 1
    private function processTransformers(StreamMetaData $metadata): string
121 1
    {
122 1
        $overallResult = self::RESULT_ABSTAIN;
123
        if ($this->transformers instanceof Closure) {
124
            $delayedTransformers = $this->transformers;
125 1
            $this->transformers  = $delayedTransformers();
126
        }
127
        foreach ($this->transformers as $transformer) {
128
            $transformationResult = $transformer->transform($metadata);
129
            if ($overallResult === self::RESULT_ABSTAIN && $transformationResult === self::RESULT_TRANSFORMED) {
130
                $overallResult = self::RESULT_TRANSFORMED;
131 1
            }
132
            // transformer reported about termination, next transformers will be skipped
133
            if ($transformationResult === self::RESULT_ABORTED) {
134
                $overallResult = self::RESULT_ABORTED;
135
                break;
136
            }
137
        }
138
139
        return $overallResult;
140
    }
141
}
142