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

PrepareResourceMiddlewareAbstract   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 158
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 0%

Importance

Changes 15
Bugs 1 Features 1
Metric Value
wmc 23
c 15
b 1
f 1
lcom 1
cbo 7
dl 0
loc 158
ccs 0
cts 86
cp 0
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A __invoke() 0 17 2
A fillResource() 0 48 3
fillResourceSpecialFields() 0 1 ?
A cleanup() 0 7 1
A getParamFromRequest() 0 20 4
B defaultValidator() 0 18 6
B namespaceValidator() 0 17 6
1
<?php
2
namespace Staticus\Resources\Middlewares;
3
4
use Staticus\Config\ConfigInterface;
5
use Staticus\Diactoros\Response\ResourceDoResponse;
6
use Staticus\Middlewares\MiddlewareAbstract;
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Staticus\Exceptions\WrongRequestException;
10
use Staticus\Resources\ResourceDOInterface;
11
use Zend\Diactoros\Response\EmptyResponse;
12
13
abstract class PrepareResourceMiddlewareAbstract extends MiddlewareAbstract
14
{
15
    protected $resourceDO;
16
    /**
17
     * @var Config
18
     */
19
    protected $config;
20
21
    public function __construct(ResourceDOInterface $resourceDO, ConfigInterface $config)
22
    {
23
        $this->resourceDO = $resourceDO;
24
        $this->config = $config;
0 ignored issues
show
Documentation Bug introduced by
It seems like $config of type object<Staticus\Config\ConfigInterface> is incompatible with the declared type object<Staticus\Resources\Middlewares\Config> of property $config.

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...
25
    }
26
27
    public function __invoke(
28
        ServerRequestInterface $request,
29
        ResponseInterface $response,
30
        callable $next = null
31
    )
32
    {
33
        parent::__invoke($request, $response, $next);
34
        if (!$this->fillResource()) {
35
36
            return new EmptyResponse(404, $response->getHeaders());
37
        }
38
39
        // Pass the resource to the next middleware
40
        $response = new ResourceDoResponse($this->resourceDO, $response->getStatusCode(), $response->getHeaders());
41
42
        return $next($request, $response);
43
    }
44
45
    /**
46
     * @throws WrongRequestException
47
     * @todo: Write separate cleanup rules for each parameter
48
     */
49
    protected function fillResource()
50
    {
51
        $name = static::getParamFromRequest('name', $this->request);
52
        $name = $this->cleanup($name);
53
        $namespace = dirname($name);
54
        $name = basename($name);
55
        $name = $this->defaultValidator('name', $name, false
56
            , ResourceDOInterface::NAME_REG_SYMBOLS, $this->config->get('staticus.clean_resource_name'));
57
        $namespace = $this->defaultValidator('namespace', $namespace, true
58
            , ResourceDOInterface::NAMESPACE_REG_SYMBOLS, $this->config->get('staticus.clean_resource_name'));
59
        if (!$this->namespaceValidator($namespace)) {
60
61
            return false;
62
        }
63
        $alt = static::getParamFromRequest('alt', $this->request);
64
        $alt = $this->cleanup($alt);
65
        $var = static::getParamFromRequest('var', $this->request);
66
        $var = $this->cleanup($var);
67
        $var = $this->defaultValidator('var', $var, true, '\w\d\-\._');
68
        $v = (int)static::getParamFromRequest('v', $this->request);
69
        $author = static::getParamFromRequest('author', $this->request);
70
        $author = $this->cleanup($author);
71
72
        $dataDir = $this->config->get('staticus.data_dir');
73
        /**
74
         * You shouldn't check 'recreate' and 'destroy' params here.
75
         * @see \Staticus\Action\StaticMiddlewareAbstract::postAction
76
         * @see \Staticus\Action\StaticMiddlewareAbstract::deleteAction
77
         */
78
        $this->resourceDO
79
            ->reset()
80
            ->setBaseDirectory($dataDir)
81
            ->setNamespace($namespace)
82
            ->setName($name)
83
            ->setNameAlternative($alt)
84
            ->setVariant($var)
85
            ->setVersion($v)
86
            ->setAuthor($author);
87
        if (!$this->resourceDO->getType()) {
88
            $type = static::getParamFromRequest('type', $this->request);
89
            $type = $this->cleanup($type);
90
            $type = $this->defaultValidator('type', $type);
91
            $this->resourceDO->setType($type);
92
        }
93
        $this->fillResourceSpecialFields();
94
95
        return true;
96
    }
97
    abstract protected function fillResourceSpecialFields();
98
99
    protected function cleanup($name)
100
    {
101
        $name = preg_replace('/\s+/u', ' ', trim(mb_strtolower(rawurldecode((string)$name), 'UTF-8')));
102
        $name = str_replace(['\\'], '', $name);
103
104
        return $name;
105
    }
106
107
    /**
108
     * @param $name
109
     * @param ServerRequestInterface $request
110
     * @return string
111
     * @todo move this method somethere
112
     */
113
    public static function getParamFromRequest($name, ServerRequestInterface $request)
114
    {
115
        $attribute = $request->getAttribute($name);
116
        if ($attribute) {
117
118
            return $attribute;
119
        }
120
        $paramsGET = $request->getQueryParams();
121
        $paramsPOST = (array)$request->getParsedBody();
122
123
        $str = isset($paramsPOST[$name])
124
            ? $paramsPOST[$name]
125
            : (
126
                isset($paramsGET[$name])
127
                ? $paramsGET[$name]
128
                : ''
129
            );
130
131
        return $str;
132
    }
133
134
    protected function defaultValidator($name, $value, $canBeEmpty = false, $allowedRegexpSymbols = '\w\d\-_', $replaceDeniedSymbols = false)
135
    {
136
        if (!empty($value)) {
137
            if ($replaceDeniedSymbols) {
138
                $value = preg_replace('/\s+/u', ' ', preg_replace('/[^' . $allowedRegexpSymbols . ']+/ui', '', $value));
139
                $value = trim(preg_replace('/\/+/u', '/', $value));
140
            } else {
141
                if (!preg_match('/^[' . $allowedRegexpSymbols . ']+$/ui', $value)) {
142
                    throw new WrongRequestException('Wrong request param "' . $name . '": ' . $value);
143
                }
144
            }
145
        }
146
        if (empty($value) && !$canBeEmpty) {
147
            throw new WrongRequestException('Empty request param "' . $name . '"');
148
        }
149
150
        return $value;
151
    }
152
153
    protected function namespaceValidator($namespace)
154
    {
155
        $allowed = $this->config->get('staticus.namespaces');
156
        if ($namespace && !in_array($namespace, $allowed, true)) {
157
            foreach ($allowed as $item) {
158
                if (false !== strpos($item, '*') && fnmatch($item, $namespace)) {
159
                    // TODO: limitations for nested namespaces
160
161
                    return true;
162
                }
163
            }
164
165
            return false;
166
        }
167
168
        return true;
169
    }
170
}
171