Completed
Push — 4.0 ( 125a8d...b89114 )
by Marco
08:12
created

Model::setLocation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
crap 1
1
<?php namespace Comodojo\Dispatcher\Response;
2
3
use \Comodojo\Dispatcher\Components\AbstractModel;
4
use \Comodojo\Dispatcher\Request\Model as Request;
5
use \Comodojo\Dispatcher\Router\Route;
6
use \Comodojo\Foundation\Timing\TimingTrait;
7
use \Comodojo\Foundation\Base\Configuration;
8
use \Comodojo\Cookies\CookieManager;
9
use \Psr\Log\LoggerInterface;
10
use \Serializable;
11
12
/**
13
 * @package     Comodojo Dispatcher
14
 * @author      Marco Giovinazzi <[email protected]>
15
 * @author      Marco Castiello <[email protected]>
16
 * @license     GPL-3.0+
17
 *
18
 * LICENSE:
19
 *
20
 * This program is free software: you can redistribute it and/or modify
21
 * it under the terms of the GNU Affero General Public License as
22
 * published by the Free Software Foundation, either version 3 of the
23
 * License, or (at your option) any later version.
24
 *
25
 * This program is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28
 * GNU Affero General Public License for more details.
29
 *
30
 * You should have received a copy of the GNU Affero General Public License
31
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32
 */
33
34
class Model extends AbstractModel implements Serializable {
35
36
    use TimingTrait;
37
38
    protected static $no_content_statuses = [100, 101, 102, 204, 304];
39
40
    protected static $cacheable_methods = ['GET', 'HEAD', 'POST', 'PUT'];
41
42
    protected static $cacheable_statuses = [200, 203, 300, 301, 302, 404, 410];
43
44
    protected $headers;
45
46
    protected $cookies;
47
48
    protected $status;
49
50
    protected $content;
51
52
    protected $location;
53
54 5
    public function __construct(Configuration $configuration, LoggerInterface $logger) {
55
56 5
        parent::__construct($configuration, $logger);
57
58 5
        $this->setHeaders(new Headers());
59 5
        $this->setCookies(new CookieManager());
60 5
        $this->setStatus(new Status());
61 5
        $this->setContent(new Content());
62 5
        $this->setLocation(new Location());
63
        
64 5
        $this->setTiming();
65
66 5
    }
67
68 5
    public function getHeaders() {
69
70 5
        return $this->headers;
71
72
    }
73
74 5
    public function setHeaders(Headers $headers) {
75
76 5
        $this->headers = $headers;
77
78 5
        return $this;
79
80
    }
81
82 5
    public function getCookies() {
83
84 5
        return $this->cookies;
85
86
    }
87
88 5
    public function setCookies(CookieManager $cookies) {
89
90 5
        $this->cookies = $cookies;
91
92 5
        return $this;
93
94
    }
95
96 7
    public function getStatus() {
97
98 7
        return $this->status;
99
100
    }
101
102 5
    public function setStatus(Status $status) {
103
104 5
        $this->status = $status;
105
106 5
        return $this;
107
108
    }
109
110 7
    public function getContent() {
111
112 7
        return $this->content;
113
114
    }
115
116 5
    public function setContent(Content $content) {
117
118 5
        $this->content = $content;
119
120 5
        return $this;
121
122
    }
123
124 2
    public function getLocation() {
125
126 2
        return $this->location;
127
128
    }
129
130 5
    public function setLocation(Location $location) {
131
132 5
        $this->location = $location;
133
134 5
        return $this;
135
136
    }
137
138
    public function serialize() {
139
140
        return serialize($this->export());
141
142
    }
143
144
    public function unserialize($data) {
145
146
        $this->import(unserialize($data));
147
148
    }
149
150
    public function export() {
151
152
        return (object)[
153
            'headers' => $this->getHeaders(),
154
            'cookies' => $this->getCookies()->getAll(),
155
            'status' => $this->getStatus(),
156
            'content' => $this->getContent(),
157
            'location' => $this->getLocation()
158
        ];
159
160
    }
161
162
    public function import($data) {
163
164
        if (isset($data->headers)) $this->setHeaders($data->headers);
165
        if (isset($data->status)) $this->setStatus($data->status);
166
        if (isset($data->content)) $this->setContent($data->content);
167
        if (isset($data->location)) $this->setLocation($data->location);
168
169
        if (isset($data->cookies) && is_array($data->cookies)) {
170
            $cookies = $this->getCookies();
171
            foreach ($data->cookies as $name => $cookie) $cookies->add($cookie);
172
        }
173
174
    }
175
176 2
    public function consolidate(Request $request, Route $route = null) {
177
178 2
        $status = $this->getStatus()->get();
179
180 2
        $output_class_name = "\\Comodojo\\Dispatcher\\Response\\Preprocessor\\Status".$status;
181
182
        // @TODO: this condition will be removed when all preprocessors ready
183 2
        if (class_exists($output_class_name)) {
184 2
            $output = new $output_class_name($this);
185 2
        } else {
186
            $output = new \Comodojo\Dispatcher\Response\Preprocessor\Status200($this);
187
        }
188
189 2
        $output->consolidate();
190
191 2
        if ($route != null) {
192
            $this->setClientCache($request, $route);
193
        }
194
195
        // extra checks
196 2
        $content = $this->getContent();
197 2
        $headers = $this->getHeaders();
198
199 2
        if ((string)$request->getMethod() == 'HEAD' && !in_array($status, self::$no_content_statuses)) {
200
            $length = $content->length();
201
            $content->set(null);
202
            if ($length) {
203
                $headers->set('Content-Length', $length);
204
            }
205
        }
206
207 2
        if ($headers->get('Transfer-Encoding') != null) {
208
            $headers->delete('Content-Length');
209
        }
210
211 2
        if ((string)$request->getVersion() == '1.0' && false !== strpos($headers->get('Cache-Control'), 'no-cache')) {
212
            $headers->set('pragma', 'no-cache');
213
            $headers->set('expires', -1);
214
        }
215
216 2
    }
217
218
    private function setClientCache(Request $request, Route $route) {
219
220
        $cache = strtoupper($route->getParameter('cache'));
221
        $ttl = (int)$route->getParameter('ttl');
222
223
        if (
224
            ($cache == 'CLIENT' || $cache == 'BOTH') &&
225
            in_array((string)$request->getMethod(), self::$cacheable_methods) &&
226
            in_array($this->getStatus()->get(), self::$cacheable_statuses)
227
            // @TODO: here we should also check for Cache-Control no-store or private;
228
            //        the cache layer will be improoved in future versions.
229
        ) {
230
231
            $headers = $this->getHeaders();
232
            $timestamp = (int) $this->getTime()->format('U')+$ttl;
233
234
            if ($ttl > 0) {
235
236
                $headers->set("Cache-Control", "max-age=".$ttl.", must-revalidate");
237
                $headers->set("Expires", gmdate("D, d M Y H:i:s", $timestamp)." GMT");
238
239
            } else {
240
241
                $headers->set("Cache-Control", "no-cache, must-revalidate");
242
                $headers->set("Expires", "Mon, 26 Jul 1997 05:00:00 GMT");
243
244
            }
245
246
        }
247
248
    }
249
250
}
251