Passed
Pull Request — develop (#931)
by Nikola
07:45
created

RApiHalDocumentDocument   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 257
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 30
eloc 78
dl 0
loc 257
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 22 4
A setName() 0 5 1
A getName() 0 3 1
B relToAbs() 0 44 11
A addUriParameters() 0 21 6
B render() 0 54 6
A setHal() 0 5 1
1
<?php
2
/**
3
 * @package     Redcore
4
 * @subpackage  Document
5
 *
6
 * @copyright   Copyright (C) 2008 - 2021 redWEB.dk. All rights reserved.
7
 * @license     GNU General Public License version 2 or later, see LICENSE.
8
 */
9
10
defined('JPATH_BASE') or die;
11
12
/**
13
 * ApiDocumentHal class, provides an easy interface to parse and display HAL+JSON or HAL+XML output
14
 *
15
 * @package     Redcore
16
 * @subpackage  Document
17
 * @see         http://stateless.co/hal_specification.html
18
 * @since       1.2
19
 */
20
class RApiHalDocumentDocument extends JDocument
21
{
22
	/**
23
	 * Document name
24
	 *
25
	 * @var    string
26
	 * @since  1.2
27
	 */
28
	protected $name = 'joomla';
29
30
	/**
31
	 * Render all hrefs as absolute, relative is default
32
	 */
33
	protected $absoluteHrefs = false;
34
35
	/**
36
	 * Document format (xml or json)
37
	 */
38
	protected $documentFormat = false;
39
40
	/**
41
	 * @var    RApiHalHal  Main HAL object
42
	 * @since  1.2
43
	 */
44
	public $hal = null;
45
46
	/**
47
	 * Class constructor
48
	 *
49
	 * @param   array  $options  Associative array of options
50
	 *
51
	 * @since  1.2
52
	 */
53
	public function __construct($options = array())
54
	{
55
		parent::__construct($options);
56
57
		$this->documentFormat = $options['documentFormat'];
58
59
		if (!in_array($this->documentFormat, array('xml', 'json')))
60
		{
61
			$this->documentFormat = 'json';
62
		}
63
64
		// Set default mime type.
65
		$this->_mime = 'application/hal+' . $this->documentFormat;
66
67
		// Set document type.
68
		$this->_type = 'hal+' . $this->documentFormat;
69
70
		// Set absolute/relative hrefs.
71
		$this->absoluteHrefs = isset($options['absoluteHrefs']) ? $options['absoluteHrefs'] : true;
72
73
		// Set token if needed
74
		$this->uriParams = isset($options['uriParams']) ? $options['uriParams'] : array();
0 ignored issues
show
Bug Best Practice introduced by
The property uriParams does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
75
	}
76
77
	/**
78
	 * Render the document.
79
	 *
80
	 * @param   boolean  $cache   If true, cache the output
81
	 * @param   array    $params  Associative array of attributes
82
	 *
83
	 * @return  string   The rendered data
84
	 *
85
	 * @since  1.2
86
	 */
87
	public function render($cache = false, $params = array())
88
	{
89
		// Get the HAL object from the buffer.
90
		/** @var $hal RApiHalDocumentResource */
91
		$hal = $this->getBuffer();
92
93
		// If required, change relative links to absolute.
94
		if (is_object($hal))
95
		{
96
			// Adjust hrefs in the _links object.
97
			$this->relToAbs($hal, $this->absoluteHrefs);
98
		}
99
100
		if ($this->documentFormat == 'xml')
101
		{
102
			$content = $hal->getXML()->asXML();
103
		}
104
		else
105
		{
106
			$content = (string) $hal;
107
		}
108
109
		$runtime = microtime(true) - $this->hal->startTime;
110
		$app = JFactory::getApplication();
111
		$language = explode('-', $app->input->get('lang', RTranslationHelper::getSiteLanguage()));
112
		$language = $language[0];
113
114
		if ($this->hal->options->get('enable_gzip_compression', 0) && RBootstrap::$config->get('webservice_enable_gzip_compression', '1') == '1')
115
		{
116
			$app->setHeader('Content-Encoding', 'gzip', true);
117
			$content = gzencode($content, 1);
0 ignored issues
show
Bug introduced by
It seems like $content can also be of type true; however, parameter $data of gzencode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

117
			$content = gzencode(/** @scrutinizer ignore-type */ $content, 1);
Loading history...
118
		}
119
120
		$app->setHeader('Status', $this->hal->statusCode . ' ' . $this->hal->statusText, true);
121
		$app->setHeader('Server', '', true);
122
        if (RBootstrap::$config->get('enable_access_control_header', '1') == '1')
123
        {
124
            $app->setHeader('Access-Control-Allow-Origin', '*', true);
125
        }
126
		$app->setHeader('Pragma', 'public', true);
127
		$app->setHeader('Expires', '0', true);
128
		$app->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true);
129
		$app->setHeader('Cache-Control', 'private', false);
130
		$app->setHeader('Content-type', $this->_mime . '; charset=UTF-8', true);
131
		$app->setHeader('X-Runtime', $runtime, true);
132
		$app->setHeader('X-Webservice-name', $this->hal->webserviceName, true);
133
		$app->setHeader('X-Webservice-version', $this->hal->webserviceVersion, true);
134
		$app->setHeader('X-Webservice-Output-Format', $this->documentFormat, true);
135
		$app->setHeader('Content-length', strlen($content), true);
0 ignored issues
show
Bug introduced by
It seems like $content can also be of type true; however, parameter $string of strlen() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

135
		$app->setHeader('Content-length', strlen(/** @scrutinizer ignore-type */ $content), true);
Loading history...
136
		$app->setHeader('Content-Language', $language, true);
137
138
		$app->sendHeaders();
139
140
		echo $content;
0 ignored issues
show
Bug introduced by
Are you sure $content of type string|true can be used in echo? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

140
		echo /** @scrutinizer ignore-type */ $content;
Loading history...
141
	}
142
143
	/**
144
	 * Returns the document name
145
	 *
146
	 * @return  string
147
	 *
148
	 * @since  1.2
149
	 */
150
	public function getName()
151
	{
152
		return $this->name;
153
	}
154
155
	/**
156
	 * Sets HAL object to the document
157
	 *
158
	 * @param   RApiHalHal  $hal  Hal object
159
	 *
160
	 * @return   RApiHalDocumentDocument
161
	 *
162
	 * @since  1.2
163
	 */
164
	public function setHal($hal)
165
	{
166
		$this->hal = $hal;
167
168
		return $this;
169
	}
170
171
	/**
172
	 * Method to convert relative to absolute links.
173
	 *
174
	 * @param   RApiHalDocumentResource  $hal            Hal object which contains links (_links).
175
	 * @param   boolean                  $absoluteHrefs  Should we replace link Href with absolute.
176
	 *
177
	 * @return  void
178
	 */
179
	protected function relToAbs($hal, $absoluteHrefs)
180
	{
181
		if ($links = $hal->getLinks())
182
		{
183
			// Adjust hrefs in the _links object.
184
			/* @var $link RApiHalDocumentLink */
185
			foreach ($links as $link)
186
			{
187
				if (is_array($link))
188
				{
189
					foreach ($link as $group => $arrayLink)
190
					{
191
						$href = $arrayLink->getHref();
192
						$href = $this->addUriParameters($href, $absoluteHrefs);
193
						$arrayLink->setHref($href);
194
						$hal->setReplacedLink($arrayLink, $group);
195
					}
196
				}
197
				else
198
				{
199
					$href = $link->getHref();
200
					$href = $this->addUriParameters($href, $absoluteHrefs);
201
					$link->setHref($href);
202
					$hal->setReplacedLink($link);
203
				}
204
			}
205
		}
206
207
		// Adjust hrefs in the _embedded object (if there is one).
208
		if ($embedded = $hal->getEmbedded())
209
		{
210
			foreach ($embedded as $resources)
211
			{
212
				if (is_object($resources))
213
				{
214
					$this->relToAbs($resources, $absoluteHrefs);
215
				}
216
				elseif (is_array($resources))
217
				{
218
					foreach ($resources as $resource)
219
					{
220
						if (is_object($resource))
221
						{
222
							$this->relToAbs($resource, $absoluteHrefs);
223
						}
224
					}
225
				}
226
			}
227
		}
228
	}
229
230
	/**
231
	 * Prepares link
232
	 *
233
	 * @param   string   $href           Link location
234
	 * @param   boolean  $absoluteHrefs  Should we replace link Href with absolute.
235
	 *
236
	 * @return  string  Modified link
237
	 *
238
	 * @since   1.2
239
	 */
240
	public function addUriParameters($href, $absoluteHrefs)
241
	{
242
		if ($absoluteHrefs && substr($href, 0, 1) == '/')
243
		{
244
			$href = rtrim(JUri::base(), '/') . $href;
245
		}
246
247
		$uri = JUri::getInstance($href);
248
249
		if (!empty($this->uriParams))
250
		{
251
			foreach ($this->uriParams as $paramKey => $param)
252
			{
253
				if (!$uri->hasVar($paramKey))
254
				{
255
					$uri->setVar($paramKey, $param);
256
				}
257
			}
258
		}
259
260
		return $uri->toString();
261
	}
262
263
	/**
264
	 * Sets the document name
265
	 *
266
	 * @param   string  $name  Document name
267
	 *
268
	 * @return  RApiHalDocumentDocument instance of $this to allow chaining
269
	 *
270
	 * @since   1.2
271
	 */
272
	public function setName($name = 'joomla')
273
	{
274
		$this->name = $name;
275
276
		return $this;
277
	}
278
}
279