Completed
Push — master ( 46ad02...e3f6c6 )
by Pavel
16:43
created

Generator::generateIndex()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 7
nc 1
nop 1
1
<?php
2
3
/**
4
 * @copyright   Copyright (c) 2016 ublaboo <[email protected]>
5
 * @author      Pavel Janda <[email protected]>
6
 * @package     Ublaboo
7
 */
8
9
namespace Ublaboo\ApiDocu;
10
11
use Nette;
12
use Nette\Application\Request;
13
use Nette\Application\IRouter;
14
use Ublaboo\ApiRouter\ApiRoute;
15
use Tracy\Debugger;
16
17
class Generator extends Nette\Object
18
{
19
20
	/**
21
	 * @var Nette\Application\UI\ITemplateFactory
22
	 */
23
	private $templateFactory;
24
25
	/**
26
	 * @var Nette\Http\Request
27
	 */
28
	private $httpRequest;
29
30
	/**
31
	 * @var string
32
	 */
33
	private $api_dir;
34
35
	/**
36
	 * @var array
37
	 */
38
	private $httpAuth;
39
40
41
	/**
42
	 * @param string                                $api_dir
43
	 * @param array                                 $httpAuth
44
	 * @param Nette\Application\UI\ITemplateFactory $templateFactory
45
	 * @param Nette\Http\Request                    $httpRequest
46
	 */
47
	public function __construct(
48
		$api_dir,
49
		array $httpAuth,
50
		Nette\Application\UI\ITemplateFactory $templateFactory,
51
		Nette\Http\Request $httpRequest
52
	) {
53
		$this->api_dir = $api_dir;
54
		$this->httpAuth = $httpAuth;
55
		$this->templateFactory = $templateFactory;
56
		$this->httpRequest = $httpRequest;
57
	}
58
59
60
	/**
61
	 * @param  IRouter $router
62
	 * @return void
63
	 */
64
	public function generateAll(IRouter $router)
65
	{
66
		$sections = $this->splitRoutesIntoSections($router);
67
68
		if (!file_exists($this->api_dir) && !is_dir($this->api_dir)) {
69
			mkdir($this->api_dir);
70
		}
71
72
		/**
73
		 * Create index.php
74
		 */
75
		$this->generateIndex($sections);
76
77
		/**
78
		 * Create *.php for each defined ApiRoute
79
		 */
80
		foreach ($sections as $section_name => $routes) {
81
			if (is_array($routes)) {
82
				foreach ($routes as $file_name => $route) {
83
					$this->generateOne($route, $sections, "$section_name.$file_name");
84
				}
85
			} else {
86
				$this->generateOne($routes, $sections, $section_name);
87
			}
88
		}
89
90
		$this->generateSuccess();
91
	}
92
93
94
	/**
95
	 * @param  ApiRoute $route
96
	 * @param  Request  $request
97
	 * @return void
98
	 */
99
	public function generateTarget(ApiRoute $route, Request $request)
100
	{
101
		$template = $this->createTemplate('api_docu_matched.latte');
102
103
		$template->setParameters([
104
			'route'       => $route,
105
			'request'     => $request,
106
			'httpRequest' => $this->httpRequest
107
		]);
108
109
		if (class_exists('Tracy\Debugger')) {
110
			Debugger::$productionMode = TRUE;
111
		}
112
113
		echo (string) $template;
114
	}
115
116
117
	/**
118
	 * @param  ApiRoute $route
119
	 * @param  array    $sections
120
	 * @param  string   $file_name
121
	 * @return void
122
	 */
123
	public function generateOne(ApiRoute $route, $sections, $file_name)
124
	{
125
		$template = $this->createTemplate('api_docu_one.latte');
126
127
		$template->setParameters([
128
			'route'       => $route,
129
			'sections'    => $sections
130
		]);
131
132
		file_put_contents(
133
			"{$this->api_dir}/{$file_name}.php",
134
			$this->getHttpAuthSnippet() . $template
135
		);
136
	}
137
138
139
	/**
140
	 * @param  array $sections
141
	 * @return void
142
	 */
143
	public function generateIndex($sections)
144
	{
145
		$template = $this->createTemplate('api_docu_index.latte');
146
147
		$template->setParameters([
148
			'sections' => $sections
149
		]);
150
151
		file_put_contents(
152
			"{$this->api_dir}/index.php",
153
			$this->getHttpAuthSnippet() . $template
154
		);
155
	}
156
157
158
	/**
159
	 * @return void
160
	 */
161
	public function generateSuccess()
162
	{
163
		$template = $this->createTemplate('api_docu_success.latte');
164
165
		$template->setParameters([
166
			'apiDir' => $this->api_dir
167
		]);
168
169
		if (class_exists('Tracy\Debugger')) {
170
			Debugger::$productionMode = TRUE;
171
		}
172
173
		echo (string) $template;
174
	}
175
176
177
	/**
178
	 * @param  string
179
	 * @return Nette\Application\UI\ITemplate
180
	 */
181
	public function createTemplate($which)
182
	{
183
		$template = $this->templateFactory->createTemplate();
184
185
		$template->addFilter(NULL, 'Ublaboo\ApiDocu\TemplateFilters::common');
186
187
		$template->setFile(__DIR__ . '/templates/' . $which);
188
189
		if ($template instanceof Nette\Application\UI\ITemplate) {
190
			$template->base_dir = __DIR__ . '/templates';
0 ignored issues
show
Bug introduced by
Accessing base_dir on the interface Nette\Application\UI\ITemplate suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
191
		}
192
193
		$template->addFilter('routeMaskStyles', function($mask) {
194
			return str_replace(['<', '>'], ['<span class="apiDocu-mask-param">&lt;', '&gt;</span>'], $mask);
195
		});
196
197
		$template->addFilter('apiDocuResponseCode', function($code) {
198
			if ($code >= 200 && $code <= 202) {
199
				return "<span class=\"apiDocu-code-success\">{$code}</span>";
200
			} else if ($code >= 300 && $code < 500) {
201
				return "<span class=\"apiDocu-code-warning\">{$code}</span>";
202
			} else if ($code >= 500) {
203
				return "<span class=\"apiDocu-code-error\">{$code}</span>";
204
			}
205
206
			return "<span class=\"apiDocu-code-other\">{$code}</span>";
207
		});
208
209
		return $template;
210
	}
211
212
213
	/********************************************************************************
214
	 *                                   INTERNAL                                   *
215
	 ********************************************************************************/
216
217
218
	private function splitRoutesIntoSections(IRouter $router)
219
	{
220
		$routes = [];
221
		$sections = [];
222
		$file_name = 1;
223
224
		if ($router instanceof ApiRoute) {
225
			$routes = [$router];
226
		} else if ($router instanceof \IteratorAggregate) {
227
			$routes = $this->getApiRoutesFromIterator($router);
228
		}
229
230
		foreach ($routes as $route) {
231
			if ($route->getSection()) {
232
				if (empty($sections[$route->getSection()])) {
233
					$sections[$route->getSection()] = [];
234
				}
235
236
				$sections[$route->getSection()][$file_name++] = $route;
237
			} else {
238
				$sections[$file_name++] = $route;
239
			}
240
		}
241
242
		return $sections;
243
	}
244
245
246
	/**
247
	 * Recursively flatten \IteratorAggregate (probably Nette\Application\Routers\RouteList)
248
	 * @param  \IteratorAggregate $i
249
	 * @return array
250
	 */
251
	private function getApiRoutesFromIterator(\IteratorAggregate $i)
252
	{
253
		$return = [];
254
255
		foreach ($i as $router) {
256
			if ($router instanceof ApiRoute) {
257
				$return[] = $router;
258
			} else if ($router instanceof \IteratorAggregate) {
259
				$routes = $this->getApiRoutesFromIterator($router);
260
261
				foreach ($routes as $route) {
262
					$return[] = $route;
263
				}
264
			}
265
		}
266
267
		return $return;
268
	}
269
270
271
	/**
272
	 * @return string
273
	 */
274
	private function getHttpAuthSnippet()
275
	{
276
		if (!$this->httpAuth['user'] || !$this->httpAuth['password']) {
277
			return '';
278
		}
279
280
		$u = $this->httpAuth['user'];
281
		$p = $this->httpAuth['password'];
282
283
		return "<?php if (!isset(\$_SERVER['PHP_AUTH_USER']) || \$_SERVER['PHP_AUTH_USER'] !== '{$u}' || \$_SERVER['PHP_AUTH_PW'] !== '{$p}') {"
284
			. "	header('WWW-Authenticate: Basic realm=\"Api\"');"
285
			. "	header('HTTP/1.0 401 Unauthorized');"
286
			. "	die('Invalid authentication');"
287
			. "} ?>";
288
	}
289
290
}
291