Passed
Branch master (267be1)
by Eugene
03:26
created

ActionPostAbstract::__invoke()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 7

Duplication

Lines 11
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 11
loc 11
ccs 0
cts 4
cp 0
rs 9.4285
cc 1
eloc 7
nc 1
nop 3
crap 2
1
<?php
2
namespace Staticus\Middlewares;
3
4
use League\Flysystem\FilesystemInterface;
5
use Staticus\Diactoros\DownloadedFile;
6
use Staticus\Diactoros\Response\FileUploadedResponse;
7
use Staticus\Exceptions\ErrorException;
8
use Staticus\Resources\Middlewares\PrepareResourceMiddlewareAbstract;
9
use Staticus\Resources\ResourceDOInterface;
10
use Staticus\Diactoros\Response\FileContentResponse;
11
use Zend\Diactoros\Response\EmptyResponse;
12
use Psr\Http\Message\ResponseInterface;
13
use Psr\Http\Message\ServerRequestInterface;
14
use Staticus\Resources\File\ResourceDO;
15
use Zend\Diactoros\UploadedFile;
16
17
abstract class ActionPostAbstract extends MiddlewareAbstract
18
{
19
    const RECREATE_COMMAND = 'recreate';
20
    const URI_COMMAND = 'uri';
21
    const CURL_TIMEOUT = 15;
22
    /**
23
     * Generator provider
24
     * @var mixed
25
     */
26
    protected $generator;
27
28
    /**
29
     * @var ResourceDO
30
     */
31
    protected $resourceDO;
32
    /**
33
     * @var FilesystemInterface
34
     */
35
    protected $filesystem;
36
37
    public function __construct(
38
        ResourceDOInterface $resourceDO, FilesystemInterface $filesystem, $fractal)
39
    {
40
        $this->resourceDO = $resourceDO;
0 ignored issues
show
Documentation Bug introduced by
$resourceDO is of type object<Staticus\Resources\ResourceDOInterface>, but the property $resourceDO was declared to be of type object<Staticus\Resources\File\ResourceDO>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
41
        $this->filesystem = $filesystem;
42
        $this->generator = $fractal;
43
    }
44
45
    /**
46
     * @param ServerRequestInterface $request
47
     * @param ResponseInterface $response
48
     * @param callable|null $next
49
     * @return EmptyResponse
50
     * @throws \Exception
51
     */
52 View Code Duplication
    public function __invoke(
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
53
        ServerRequestInterface $request,
54
        ResponseInterface $response,
55
        callable $next = null
56
    )
57
    {
58
        parent::__invoke($request, $response, $next);
59
        $this->response = $this->action();
60
61
        return $this->next();
62
    }
63
64
    abstract protected function generate(ResourceDOInterface $resourceDO);
65
66
    protected function action()
67
    {
68
        $headers = [
69
            'Content-Type' => $this->resourceDO->getMimeType(),
70
        ];
71
        $filePath = $this->resourceDO->getFilePath();
72
        $fileExists = is_file($filePath);
73
        $recreate = PrepareResourceMiddlewareAbstract::getParamFromRequest(static::RECREATE_COMMAND, $this->request);
74
        $uri = PrepareResourceMiddlewareAbstract::getParamFromRequest(static::URI_COMMAND, $this->request);
75
        $recreate = $fileExists && $recreate;
76
        $this->resourceDO->setNew(!$fileExists);
77
        if (!$fileExists || $recreate) {
78
            $this->resourceDO->setRecreate($recreate);
79
            $upload = $this->upload();
80
81
            // Upload must be with high priority
82
            if ($upload) {
83
84
                /** @see \Zend\Diactoros\Response::$phrases */
85
                return new FileUploadedResponse($upload, 201, $headers);
86
            } elseif ($uri) {
87
                $upload = $this->download($this->resourceDO, $uri);
88
89
                /** @see \Zend\Diactoros\Response::$phrases */
90
                return new FileUploadedResponse($upload, 201, $headers);
91
            } else {
92
                $body = $this->generate($this->resourceDO);
93
94
                /** @see \Zend\Diactoros\Response::$phrases */
95
                return new FileContentResponse($body, 201, $headers);
96
            }
97
98
        }
99
100
        /** @see \Zend\Diactoros\Response::$phrases */
101
        return new EmptyResponse(304, $headers);
102
    }
103
104
    /**
105
     * @return string|null
106
     */
107
    protected function upload()
108
    {
109
        $uploaded = $this->request->getUploadedFiles();
110
        $uploaded = current($uploaded);
111
        if ($uploaded instanceof UploadedFile) {
112
113
            return $uploaded;
114
        }
115
116
        return null;
117
    }
118
119
    /**
120
     * @param ResourceDOInterface $resourceDO
121
     * @param $uri
122
     * @return UploadedFile
123
     * @throws ErrorException
124
     * @throws \Exception
125
     */
126
    protected function download(ResourceDOInterface $resourceDO, $uri)
127
    {
128
        // ------------
129
        // @todo refactoring: move downloading code from here to separate service!
130
        // ------------
131
        set_time_limit(self::CURL_TIMEOUT);
132
        $dir = DATA_DIR . 'download' . DIRECTORY_SEPARATOR;
133
        $file = $this->resourceDO->getUuid() . '_' . time() . '_' . mt_rand(100, 200) . '.tmp';
134
        if(!@mkdir($dir) && !is_dir($dir)) {
135
            throw new ErrorException('Can\'t create the directory: ' . $dir);
136
        }
137
        if (is_file($file)) {
138
            if(!unlink($file)) {
139
                throw new ErrorException('Can\'t remove old file: ' . $dir . $file);
140
            }
141
        }
142
        $resource = fopen($dir . $file, 'w+');
143
        if (!$resource) {
144
            throw new ErrorException('Can\'t create the file for writting: ' . $dir . $file);
145
        }
146
        $uriEnc = str_replace(' ', '%20', $uri);
147
        $headers = [
148
            "Accept: " . $resourceDO->getMimeType(),
149
            "Cache-Control: no-cache",
150
            "Pragma: no-cache",
151
        ];
152
        $ch = curl_init($uriEnc);
153
//        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
154
        curl_setopt($ch, CURLOPT_TIMEOUT, static::CURL_TIMEOUT);
155
        // Save curl result to the file
156
        curl_setopt($ch, CURLOPT_FILE, $resource);
157
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
158
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
159
        // get curl response
160
        curl_exec($ch);
161
        if (curl_errno($ch)) {
162
            curl_close($ch);
163
            fclose($resource);
164
            throw new ErrorException('Curl error for uri: ' . $uri . '; ' . curl_error($ch));
165
        }
166
        $size = (int)curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
167
        curl_close($ch);
168
        fclose($resource);
169
        // ------------
170
171
        $downloaded = new DownloadedFile($dir . $file, $size, UPLOAD_ERR_OK, $resourceDO->getName() . '.' . $resourceDO->getType(), $resourceDO->getMimeType());
172
173
        return $downloaded;
174
    }
175
}