DefaultFormatter.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2020 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
12 
17 
18 /**
19  * Default Formatter implementation.
20  *
21  * @author ingo herwig <ingo@wemove.com>
22  */
23 class DefaultFormatter implements Formatter {
24 
25  private $formats = [];
26 
27  /**
28  * Constructor
29  * @param $formats Array of Format instances to use
30  */
31  public function __construct(array $formats) {
32  $this->formats = $formats;
33  }
34 
35  /**
36  * @see Formatter::getFormat()
37  */
38  public function getFormat($name) {
39  if (isset($this->formats[$name])) {
40  return $this->formats[$name];
41  }
42  throw new ConfigurationException("Configuration section 'Formats' does not contain a format definition with name: ".$name);
43  }
44 
45  /**
46  * @see Formatter::getFormatFromMimeType()
47  */
48  public function getFormatFromMimeType($mimeType) {
49  $firstFormat = null;
50  foreach ($this->formats as $name => $instance) {
51  $firstFormat = $firstFormat == null ? $name : $firstFormat;
52  $formatMimeType = $instance->getMimeType();
53  if (strlen($formatMimeType) > 0 && strpos($mimeType, $formatMimeType) !== false) {
54  return $name;
55  }
56  }
57  if ($firstFormat == null) {
58  throw new ConfigurationException("Configuration section 'Formats' does not contain a format definition for: ".$mimeType);
59  }
60  return $firstFormat;
61  }
62 
63  /**
64  * @see Formatter::deserialize()
65  */
66  public function deserialize(Request $request) {
67  // get the format that should be used for this request format
68  $formatName = $request->getFormat();
69  if (strlen($formatName) == 0) {
70  // the format must be given!
71  throw new ConfigurationException("No request format defined for ".$request->__toString());
72  }
73  $format = $this->getFormat($formatName);
74  $format->deserialize($request);
75  }
76 
77  /**
78  * @see Formatter::serialize()
79  */
80  public function serialize(Response $response) {
81  // handle caching
82  $responseSent = false;
83  $cacheId = $response->getCacheId();
84  if ($cacheId != null) {
85  // get the caching request headers
86  $request = $response->getRequest();
87  $ifModifiedSinceHeader = $request->hasHeader("If-Modified-Since") ?
88  $request->getHeader("If-Modified-Since") : false;
89  $etagHeader = $request->hasHeader("If-None-Match") ?
90  trim($request->getHeader("If-None-Match")) : false;
91 
92  // get caching parameters from response
93  $cacheDate = $response->getCacheDate();
94  $lastModified = $cacheDate !== null ? $cacheDate : new \DateTime();
95  $lastModifiedTs = $lastModified->getTimestamp();
96  $etag = hash('sha256', $lastModifiedTs.$cacheId);
97  $maxAge = $response->getCacheLifetime() !== null ? $response->getCacheLifetime() : 31536000;
98 
99  // send caching headers
100  if (!$response->hasHeader("Cache-Control")) {
101  $response->setHeader("Cache-Control", "public, max-age=".$maxAge);
102  }
103  $response->setHeader("Last-Modified", $lastModified->format("D, d M Y H:i:s")." GMT");
104  $response->setHeader("ETag", $etag);
105 
106  // check if page has changed and send 304 if not
107  if (($ifModifiedSinceHeader !== false && strtotime($ifModifiedSinceHeader) == $lastModifiedTs) ||
108  $etagHeader == $etag) {
109  // client has current response already
110  $response->setStatus(304);
111  $responseSent = true;
112  }
113  }
114 
115  // remove unwanted headers
116  $response->setHeader('X-Powered-By', null);
117  $response->setHeader('Expires', null);
118 
119  // delegate serialization to the response format
120  if (!$responseSent) {
121  $formatName = $response->getFormat();
122  if (strlen($formatName) == 0) {
123  // the format must be given!
124  throw new ConfigurationException("No response format defined for ".$response->__toString());
125  }
126  $format = $this->getFormat($formatName);
127 
128  // send headers
129  if (!headers_sent()) {
130  foreach ($format->getResponseHeaders($response) as $name => $value) {
131  if (strlen($value) > 0) {
132  header($name.": ".$value);
133  }
134  else {
135  header_remove($name);
136  }
137  }
138  }
139 
140  // send body
141  $format->serialize($response);
142  }
143 
144  http_response_code($response->getStatus());
145  }
146 }
147 ?>
Response holds the response values that are used as output from Controller instances.
Definition: Response.php:20
Request holds the request values that are used as input to Controller instances.
Definition: Request.php:18
getCacheId()
Get the cache id.
getFormat()
Get the message format.
getRequest()
Get the Request instance belonging to the response.
ConfigurationException signals an exception in the configuration.
Formatter is the single entry point for request/response formatting.
Definition: Formatter.php:23
getCacheLifetime()
Get the lifetime of a cached response.
setStatus($status)
Set the response HTTP status code.
setHeader($name, $value)
Set a header value.
getStatus()
Get the response HTTP status code.
hasHeader($name)
Check for existence of a header.
getCacheDate()
Get the caching date, if the response is cached.