Completed
Branch master (ead0c7)
by Atanas
01:54
created

PhpViewEngine   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 165
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 1
Metric Value
eloc 42
c 3
b 0
f 1
dl 0
loc 165
ccs 37
cts 37
cp 1
rs 10
wmc 16

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getLayoutContent() 0 12 2
A popLayoutContent() 0 2 1
A pushLayoutContent() 0 2 1
A __construct() 0 3 1
A getViewLayout() 0 17 3
A makeView() 0 12 2
A renderView() 0 7 1
A make() 0 9 3
A canonical() 0 2 1
A exists() 0 2 1
1
<?php
2
/**
3
 * @package   WPEmerge
4
 * @author    Atanas Angelov <[email protected]>
5
 * @copyright 2018 Atanas Angelov
6
 * @license   https://www.gnu.org/licenses/gpl-2.0.html GPL-2.0
7
 * @link      https://wpemerge.com/
8
 */
9
10
namespace WPEmerge\View;
11
12
/**
13
 * Render view files with php.
14
 */
15
class PhpViewEngine implements ViewEngineInterface {
16
	/**
17
	 * View compose action.
18
	 *
19
	 * @var callable
20
	 */
21
	protected $compose_action = null;
22
23
	/**
24
	 * View finder.
25
	 *
26
	 * @var PhpViewFilesystemFinder
27
	 */
28
	protected $finder = null;
29
30
	/**
31
	 * Stack of views ready to be rendered.
32
	 *
33
	 * @var array<ViewInterface>
34
	 */
35
	protected $layout_content_stack = [];
36
37
	/**
38
	 * Constructor.
39
	 *
40
	 * @codeCoverageIgnore
41
	 * @param callable                $compose_action
42
	 * @param PhpViewFilesystemFinder $finder
43
	 */
44
	public function __construct( callable $compose_action, PhpViewFilesystemFinder $finder ) {
45
		$this->compose_action = $compose_action;
46
		$this->finder = $finder;
47
	}
48
49
	/**
50
	 * {@inheritDoc}
51
	 */
52 1
	public function exists( $view ) {
53 1
		return $this->finder->exists( $view );
54
	}
55
56
	/**
57
	 * {@inheritDoc}
58
	 */
59 1
	public function canonical( $view ) {
60 1
		return $this->finder->canonical( $view );
61
	}
62
63
	/**
64
	 * {@inheritDoc}
65
	 * @throws ViewNotFoundException
66
	 */
67 2
	public function make( $views ) {
68 2
		foreach ( $views as $view ) {
69 2
			if ( $this->exists( $view ) ) {
70 1
				$filepath = $this->finder->resolveFilepath( $view );
71 1
				return $this->makeView( $view, $filepath );
72
			}
73 1
		}
74
75 1
		throw new ViewNotFoundException( 'View not found for "' . implode( ', ', $views ) . '"' );
76
	}
77
78
	/**
79
	 * Create a view instance.
80
	 *
81
	 * @param  string $name
82
	 * @param  string $filepath
83
	 * @return ViewInterface
84
	 * @throws ViewNotFoundException
85
	 */
86 2
	protected function makeView( $name, $filepath ) {
87 2
		$view = (new PhpView( $this ))
88 2
			->setName( $name )
89 2
			->setFilepath( $filepath );
90
91 2
		$layout = $this->getViewLayout( $view );
92
93 2
		if ( $layout !== null ) {
94 1
			$view->setLayout( $layout );
95 1
		}
96
97 2
		return $view;
98
	}
99
100
	/**
101
	 * Create a view instance for the given view's layout header, if any.
102
	 *
103
	 * @param  PhpView $view
104
	 * @return ViewInterface
105
	 * @throws ViewNotFoundException
106
	 */
107 2
	protected function getViewLayout( PhpView $view ) {
108 2
		$layout_headers = array_filter( get_file_data(
109 2
			$view->getFilepath(),
110 2
			['Layout']
111 2
		) );
112
113 2
		if ( empty( $layout_headers ) ) {
114 1
			return null;
115
		}
116
117 2
		$layout_file = trim( $layout_headers[0] );
118
119 2
		if ( ! $this->exists( $layout_file ) ) {
120 1
			throw new ViewNotFoundException( 'View layout not found for "' . $layout_file . '"' );
121
		}
122
123 1
		return $this->makeView( $this->canonical( $layout_file ), $this->finder->resolveFilepath( $layout_file ) );
124
	}
125
126
	/**
127
	 * Render a view.
128
	 *
129
	 * @param  PhpView $__view
130
	 * @return string
131
	 */
132 1
	protected function renderView( PhpView $__view ) {
133 1
		$__context = $__view->getContext();
134 1
		ob_start();
135 1
		extract( $__context, EXTR_OVERWRITE );
136
		/** @noinspection PhpIncludeInspection */
137 1
		include $__view->getFilepath();
138 1
		return ob_get_clean();
139
	}
140
141
	/**
142
	 * Push layout content to the top of the stack.
143
	 *
144
	 * @codeCoverageIgnore
145
	 * @param PhpView $view
146
	 * @return void
147
	 */
148
	public function pushLayoutContent( PhpView $view ) {
149
		$this->layout_content_stack[] = $view;
150
	}
151
152
	/**
153
	 * Pop the top-most layout content from the stack.
154
	 *
155
	 * @codeCoverageIgnore
156
	 * @return PhpView|null
157
	 */
158
	public function popLayoutContent() {
159
		return array_pop( $this->layout_content_stack );
160
	}
161
162
	/**
163
	 * Pop the top-most layout content from the stack, render and return it.
164
	 *
165
	 * @codeCoverageIgnore
166
	 * @return string
167
	 */
168
	public function getLayoutContent() {
169
		$view = $this->popLayoutContent();
170
171
		if ( ! $view ) {
172
			return '';
173
		}
174
175
		$clone = clone $view;
176
177
		call_user_func( $this->compose_action, $clone );
178
179
		return $this->renderView( $clone );
180
	}
181
}
182