Completed
Push — master ( ed4471...bf07bf )
by Oscar
04:47
created

ImageTransformer::transform()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 12
rs 9.4286
cc 1
eloc 8
nc 1
nop 2
1
<?php
2
3
namespace Psr7Middlewares\Middleware;
4
5
use Psr7Middlewares\Utils;
6
use Psr7Middlewares\Middleware;
7
use Psr\Http\Message\ServerRequestInterface;
8
use Psr\Http\Message\ResponseInterface;
9
use Imagecow\Image;
10
use RuntimeException;
11
use Exception;
12
13
/**
14
 * Middleware to manipulate images on demand.
15
 */
16
class ImageTransformer
17
{
18
    use Utils\BasePathTrait;
19
    use Utils\CryptTrait;
20
21
    protected $sizes;
22
23
    /**
24
     * Define the available sizes, for example:
25
     * [
26
     *    'small'  => 'resizeCrop,50,50',
27
     *    'medium' => 'resize,500',
28
     *    'big'    => 'resize,1000',
29
     * ].
30
     * 
31
     * @param array $sizes
32
     * 
33
     * @return self
34
     */
35
    public function sizes(array $sizes)
36
    {
37
        $this->sizes = $sizes;
38
39
        return $this;
40
    }
41
42
    /**
43
     * Execute the middleware.
44
     *
45
     * @param ServerRequestInterface $request
46
     * @param ResponseInterface      $response
47
     * @param callable               $next
48
     *
49
     * @return ResponseInterface
50
     */
51
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
52
    {
53
        if (!Middleware::hasAttribute($request, FormatNegotiator::KEY)) {
54
            throw new RuntimeException('ResponsiveImage middleware needs FormatNegotiator executed before');
55
        }
56
57
        //If it's not an image or basePath does not match or invalid transform values, don't do anything
58
        if (!in_array(FormatNegotiator::getFormat($request), ['jpg', 'jpeg', 'gif', 'png']) || !$this->testBasePath($request->getUri()->getPath()) || !($info = $this->parsePath($request->getUri()->getPath()))) {
59
            return $next($request, $response);
60
        }
61
62
        list($path, $transform) = $info;
63
        $uri = $request->getUri()->withPath($path);
64
        $request = $request->withUri($uri);
65
66
        $response = $next($request, $response);
67
68
        //Check the response and transform the image
69
        if ($transform && $response->getStatusCode() === 200 && $response->getBody()->getSize()) {
70
            return $this->transform($response, $transform);
71
        }
72
73
        return $response;
74
    }
75
76
    /**
77
     * Transform the image.
78
     * 
79
     * @param ResponseInterface $response
80
     * @param string            $transform
81
     * 
82
     * @return ResponseInterface
83
     */
84
    private function transform(ResponseInterface $response, $transform)
85
    {
86
        $image = Image::createFromString((string) $response->getBody());
87
        $image->transform($transform);
88
89
        $body = Middleware::createStream();
90
        $body->write($image->getString());
91
92
        return $response
93
            ->withBody($body)
94
            ->withHeader('Content-Type', $image->getMimeType());
95
    }
96
97
    /**
98
     * Parses the path and return the file and transform values.
99
     * For example, the path "/images/small.avatar.jpg" returns:
100
     * ["/images/avatar.jpg", "resizeCrop,50,50"].
101
     * 
102
     * @param string $path
103
     * 
104
     * @return null|array [file, transform]
105
     */
106
    private function parsePath($path)
107
    {
108
        $path = $this->getBasePath($path);
109
        $info = pathinfo($path);
110
111
        try {
112
            $pieces = explode('.', $this->decrypt($info['filename']), 2);
113
        } catch (Exception $e) {
114
            return;
115
        }
116
117
        if (count($pieces) === 2) {
118
            list($transform, $file) = $pieces;
119
120
            //Check if the size is valid
121
            if (is_array($this->sizes)) {
122
                if (!isset($this->sizes[$transform])) {
123
                    return;
124
                }
125
126
                $transform = $this->sizes[$transform];
127
            }
128
129
            return [Utils\Path::join($info['dirname'], "{$file}.".$info['extension']), $transform];
130
        }
131
    }
132
}
133