Completed
Pull Request — staging (#840)
by
unknown
18:30
created

BaseView::render()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 6
nop 1
dl 0
loc 33
rs 9.392
c 0
b 0
f 0
1
<?php
2
/**
3
 * YIKES Inc. Easy Forms.
4
 *
5
 * @package   YIKES\EasyForms
6
 * @author    Freddie Mixell
7
 * @license   GPL2
8
 */
9
10
namespace YIKES\EasyForms\View;
11
12
use YIKES\EasyForms\Exception\FailedToLoadView;
13
use YIKES\EasyForms\Exception\InvalidURI;
14
use YIKES\EasyForms\PluginHelper;
15
16
/**
17
 * Class BaseView.
18
 *
19
 * Very basic View class to abstract away PHP view rendering.
20
 *
21
 * Note: This should normally be done through a dedicated package.
22
 *
23
 * @since   %VERSION%
24
 *
25
 * @package YIKES\EasyForms
26
 * @author  Jeremy Pry
27
 */
28
class BaseView implements View {
29
30
	use PluginHelper;
31
32
	/**
33
	 * Extension to use for view files.
34
	 *
35
	 * @since %VERSION%
36
	 */
37
	const VIEW_EXTENSION = 'php';
38
39
	/**
40
	 * Contexts to use for escaping.
41
	 *
42
	 * @since %VERSION%
43
	 */
44
	const CONTEXT_HTML       = 'html';
45
	const CONTEXT_JAVASCRIPT = 'js';
46
47
	/**
48
	 * URI to the view file to render.
49
	 *
50
	 * @since %VERSION%
51
	 *
52
	 * @var string
53
	 */
54
	protected $uri;
55
56
	/**
57
	 * Internal storage for passed-in context.
58
	 *
59
	 * @since %VERSION%
60
	 *
61
	 * @var array
62
	 */
63
	protected $_context_ = [];
64
65
	/**
66
	 * Instantiate a View object.
67
	 *
68
	 * @since %VERSION%
69
	 *
70
	 * @param string $uri URI to the view file to render.
71
	 *
72
	 * @throws InvalidURI If an invalid URI was passed into the View.
73
	 */
74
	public function __construct( $uri ) {
75
		$this->uri = $this->validate( $uri );
76
	}
77
78
	/**
79
	 * Render a given URI.
80
	 *
81
	 * @since %VERSION%
82
	 *
83
	 * @param array $context Context in which to render.
84
	 *
85
	 * @return string Rendered HTML.
86
	 * @throws FailedToLoadView If the View URI could not be loaded.
87
	 */
88
	public function render( array $context = [] ) {
89
90
		// Add context to the current instance to make it available within the
91
		// rendered view.
92
		foreach ( $context as $key => $value ) {
93
			$this->$key = $value;
94
		}
95
96
		// Add entire context as array to the current instance to pass onto
97
		// partial views.
98
		$this->_context_ = $context;
99
100
		// Save current buffering level so we can backtrack in case of an error.
101
		// This is needed because the view itself might also add an unknown
102
		// number of output buffering levels.
103
		$buffer_level = ob_get_level();
104
		ob_start();
105
106
		try {
107
			include $this->uri;
108
		} catch ( \Exception $exception ) {
109
			// Remove whatever levels were added up until now.
110
			while ( ob_get_level() > $buffer_level ) {
111
				ob_end_clean();
112
			}
113
			throw FailedToLoadView::view_exception(
114
				$this->uri,
115
				$exception
116
			);
117
		}
118
119
		return ob_get_clean();
120
	}
121
122
	/**
123
	 * Render a partial view.
124
	 *
125
	 * This can be used from within a currently rendered view, to include
126
	 * nested partials.
127
	 *
128
	 * The passed-in context is optional, and will fall back to the parent's
129
	 * context if omitted.
130
	 *
131
	 * @since %VERSION%
132
	 *
133
	 * @param string     $uri     URI of the partial to render.
134
	 * @param array|null $context Context in which to render the partial.
135
	 *
136
	 * @return string Rendered HTML.
137
	 * @throws InvalidURI If the provided URI was not valid.
138
	 * @throws FailedToLoadView If the view could not be loaded.
139
	 */
140
	public function render_partial( $uri, array $context = null ) {
141
		$view = new static( $uri );
142
143
		return $view->render( $context ?: $this->_context_ );
144
	}
145
146
	/**
147
	 * Validate an URI.
148
	 *
149
	 * @since %VERSION%
150
	 *
151
	 * @param string $uri URI to validate.
152
	 *
153
	 * @return string Validated URI.
154
	 * @throws InvalidURI If an invalid URI was passed into the View.
155
	 */
156 View Code Duplication
	protected function validate( $uri ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
157
		$uri = $this->check_extension( $uri, static::VIEW_EXTENSION );
158
		$uri = trailingslashit( $this->get_root_dir() ) . $uri;
159
160
		if ( ! is_readable( $uri ) ) {
161
			throw InvalidURI::from_uri( $uri );
162
		}
163
164
		return $uri;
165
	}
166
167
	/**
168
	 * Check that the URI has the correct extension.
169
	 *
170
	 * Optionally adds the extension if none was detected.
171
	 *
172
	 * @since %VERSION%
173
	 *
174
	 * @param string $uri       URI to check the extension of.
175
	 * @param string $extension Extension to use.
176
	 *
177
	 * @return string URI with correct extension.
178
	 */
179 View Code Duplication
	protected function check_extension( $uri, $extension ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
		$detected_extension = pathinfo( $uri, PATHINFO_EXTENSION );
181
182
		if ( $extension !== $detected_extension ) {
183
			$uri .= '.' . $extension;
184
		}
185
186
		return $uri;
187
	}
188
}