Completed
Push — master ( 00ed35...63fbb3 )
by Oscar
10:20
created

ImageTransformer::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
rs 9.4286
cc 1
eloc 3
nc 1
nop 1
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
20
    /**
21
     * @var array Available sizes
22
     */
23
    protected $sizes = [];
24
25
    /**
26
     * Define the available sizes, for example:
27
     * [
28
     *    'small'  => 'resizeCrop,50,50',
29
     *    'medium' => 'resize,500',
30
     *    'big'    => 'resize,1000',
31
     * ].
32
     * 
33
     * @param array $sizes
34
     * 
35
     * @return self
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
36
     */
37
    public function __construct(array $sizes)
38
    {
39
        $this->sizes = $sizes;
40
41
        return $this;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
42
    }
43
44
    /**
45
     * Execute the middleware.
46
     *
47
     * @param ServerRequestInterface $request
48
     * @param ResponseInterface      $response
49
     * @param callable               $next
50
     *
51
     * @return ResponseInterface
52
     */
53
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
54
    {
55
        if (!Middleware::hasAttribute($request, FormatNegotiator::KEY)) {
56
            throw new RuntimeException('ResponsiveImage middleware needs FormatNegotiator executed before');
57
        }
58
59
        //If it's not an image or basePath does not match or invalid transform values, don't do anything
60
        if (!in_array(FormatNegotiator::getFormat($request), ['jpg', 'jpeg', 'gif', 'png']) || !$this->testBasePath($request->getUri()->getPath()) || !($info = $this->parsePath($request->getUri()->getPath()))) {
61
            return $next($request, $response);
62
        }
63
64
        list($path, $transform) = $info;
65
        $uri = $request->getUri()->withPath($path);
66
        $request = $request->withUri($uri);
67
68
        $response = $next($request, $response);
69
70
        //Check the response and transform the image
71
        if ($transform && $response->getStatusCode() === 200 && $response->getBody()->getSize()) {
72
            return $this->transform($response, $transform);
73
        }
74
75
        return $response;
76
    }
77
78
    /**
79
     * Transform the image.
80
     * 
81
     * @param ResponseInterface $response
82
     * @param string            $transform
83
     * 
84
     * @return ResponseInterface
85
     */
86
    private function transform(ResponseInterface $response, $transform)
87
    {
88
        $image = Image::createFromString((string) $response->getBody());
89
        $image->transform($transform);
90
91
        $body = Middleware::createStream();
92
        $body->write($image->getString());
93
94
        return $response
95
            ->withBody($body)
96
            ->withHeader('Content-Type', $image->getMimeType());
97
    }
98
99
    /**
100
     * Parses the path and return the file and transform values.
101
     * For example, the path "/images/small.avatar.jpg" returns:
102
     * ["/images/avatar.jpg", "resizeCrop,50,50"].
103
     * 
104
     * @param string $path
105
     * 
106
     * @return null|array [file, transform]
107
     */
108
    private function parsePath($path)
109
    {
110
        $info = pathinfo($path);
111
112
        try {
113
            $pieces = explode('.', $info['filename'], 2);
114
        } catch (Exception $e) {
115
            return;
116
        }
117
118
        if (count($pieces) === 2) {
119
            list($transform, $file) = $pieces;
120
121
            //Check if the size is valid
122
            if (!isset($this->sizes[$transform])) {
123
                return;
124
            }
125
126
            return [Utils\Helpers::joinPath($info['dirname'], "{$file}.".$info['extension']), $this->sizes[$transform]];
127
        }
128
    }
129
}
130