PluginProbe
FakerPress / 0.8.0
FakerPress v0.8.0
0.9.2 trunk 0.1.0 0.1.1 0.1.2 0.1.3 0.5.2 0.5.3 0.6.1 0.6.2 0.6.3 0.6.4 0.6.5 0.6.6 0.7.0 0.7.1 0.7.2 0.8.0 0.9.0 0.9.1
fakerpress / src / FakerPress / Provider / HTML.php

HTML.php in FakerPress 0.8.0, at src/FakerPress/Provider/HTML.php

365 lines 9.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FakerPress\Provider;
4
5 use FakerPress\Module\Attachment;
6 use FakerPress\Provider\Image\LoremPicsum;
7 use FakerPress\Provider\Image\Placeholder;
8 use FakerPress\Utils;
9 use FakerPress\ThirdParty\Faker\Provider\Base;
10 use FakerPress\ThirdParty\Faker\Provider\Lorem;
11 use FakerPress\ThirdParty\Faker\Provider\Internet;
12 use function FakerPress\make;
13
14 class HTML extends Base {
15 /**
16 * @param \FakerPress\ThirdParty\Faker\Generator $generator
17 */
18 public function __construct( \FakerPress\ThirdParty\Faker\Generator $generator ) {
19 parent::__construct( $generator );
20
21 $provider = new Internet( $this->generator );
22 $this->generator->addProvider( $provider );
23
24 $provider = new Image\Placeholder( $this->generator );
25 $this->generator->addProvider( $provider );
26
27 $provider = new Image\LoremPicsum( $this->generator );
28 $this->generator->addProvider( $provider );
29 }
30
31 /**
32 * Set of elements based on a grouping.
33 *
34 * @since 0.1.0
35 *
36 * @var string[][]
37 */
38 public static $sets = [
39 'self_close' => [ 'img', 'hr', '!--more--' ],
40 'header' => [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ],
41 'list' => [ 'ul', 'ol' ],
42 'block' => [ 'div', 'p', 'blockquote' ],
43 'item' => [ 'li' ],
44 'inline' => [
45 'b',
46 'big',
47 'i',
48 'small',
49 'tt',
50 'abbr',
51 'cite',
52 'code',
53 'em',
54 'strong',
55 'a',
56 'bdo',
57 'br',
58 'img',
59 'q',
60 'span',
61 'sub',
62 'sup',
63 'hr',
64 ],
65 'wp' => [ '!--more--' ]
66 ];
67
68 /**
69 * Prevents HTML comments to be included in our codebase.
70 *
71 * @since 0.1.0
72 *
73 * @param $element
74 *
75 * @return bool
76 */
77 private function filter_html_comments( $element = '' ) {
78 return ! preg_match( '/<?!--(.*?)-->?/i', $element );
79 }
80
81 /**
82 * Checks if a haystack of elements contains the needle provided.
83 *
84 * @since 0.1.0
85 *
86 * @param string $needle
87 * @param array $haystack
88 *
89 * @return bool
90 */
91 private function has_element( $needle = '', $haystack = [] ) {
92 $needle = trim( $needle );
93 $filtered = array_filter( $haystack, static function ( $element ) use ( $needle ) {
94 return preg_match( "/<?(!--)? ?({$needle})+ ?(--)?>?/i", $element ) !== 0;
95 } );
96
97 return count( $filtered ) > 0;
98 }
99
100 public function html_elements( $args = [] ) {
101 $html = [];
102
103 $defaults = [
104 'qty' => [ 5, 25 ],
105 'elements' => array_merge( self::$sets['header'], self::$sets['list'], self::$sets['block'] ),
106 'attr' => [],
107 'exclude' => [ 'div' ],
108 'allow_html_comments' => false,
109 ];
110
111 $args = (object) wp_parse_args( $args, $defaults );
112 $args->did_more_element = false;
113
114 // Randomize the quantity based on range
115 $args->qty = make( Utils::class )->get_qty_from_range( $args->qty );
116
117 $max_to_more = ( $args->qty / 2 ) + $this->generator->numberBetween( 0, max( floor( $args->qty / 2 ), 1 ) );
118 $min_to_more = ( $args->qty / 2 ) - $this->generator->numberBetween( 0, max( floor( $args->qty / 2 ), 1 ) );
119
120 for ( $i = 0; $i < $args->qty; $i ++ ) {
121 $exclude = $args->exclude;
122 if ( isset( $element ) ) {
123 // Here we check if we need to exclude some elements from the next
124 // This one is to exclude header elements from apearing one after the other, or in the end of the string
125 if ( in_array( $element, self::$sets['header'] ) || $args->qty - 1 === $i ) {
126 $exclude = array_merge( (array) $exclude, self::$sets['header'] );
127 } elseif ( $i > 1 && ( in_array( $els[ $i - 1 ], self::$sets['list'] ) || in_array( $els[ $i - 2 ], self::$sets['list'] ) ) ) {
128 $exclude = array_merge( (array) $exclude, self::$sets['list'] );
129 }
130 }
131
132 $elements = array_diff( $args->elements, $exclude );
133
134 if ( ! $args->allow_html_comments ) {
135 $elements = array_filter( $elements, [ $this, 'filter_html_comments' ] );
136 }
137
138 $els[] = $element = Base::randomElement( $elements );
139
140 $html[] = $this->element( $element, $args->attr, null, $args );
141
142 if (
143 $this->generator->numberBetween( 0, 100 ) <= 80
144 && ! $args->did_more_element
145 && $args->qty > 2
146 && $this->has_element( '!--more--', $args->elements )
147 && $i < $max_to_more
148 && $i > $min_to_more
149 ) {
150 $html[] = $this->element( '!--more--' );
151 $args->did_more_element = true;
152 }
153 }
154
155 return (array) $html;
156 }
157
158 /**
159 * Generates the HTML for the <img> element.
160 *
161 * @since 0.2.0
162 *
163 * @param object|array $element
164 * @param string[] $sources
165 *
166 * @return false|string
167 */
168 private function html_element_img( $element, $sources = [ Placeholder::ID, LoremPicsum::ID ] ) {
169 if ( is_array( $element ) ) {
170 $element = (object) $element;
171 }
172
173 if ( ! isset( $element->attr['class'] ) ) {
174 $element->attr['class'][] = $this->generator->optional( 0.4, null )->randomElement( [ 'aligncenter', 'alignleft', 'alignright' ] );
175 $element->attr['class'] = array_filter( $element->attr['class'] );
176 $element->attr['class'] = implode( ' ', $element->attr['class'] );
177 }
178
179 if ( ! isset( $element->attr['alt'] ) ) {
180 $element->attr['alt'] = rtrim( $this->generator->optional( 0.7, '' )->sentence( Base::randomDigitNotNull() ), '.' );
181 }
182
183 if ( ! isset( $element->attr['src'] ) ) {
184 $image_src = $this->get_img_src( $sources );
185 if ( is_wp_error( $image_src ) ) {
186 return $image_src;
187 }
188
189 $element->attr['src'] = $image_src;
190
191 }
192
193 $element->attr = array_filter( $element->attr );
194
195 return $element;
196 }
197
198 /**
199 * Generates image URLs for the <img> elements, will fetch attachments as a basis for the inline images.
200 *
201 * @since 0.4.0
202 *
203 * @param string[] $sources
204 *
205 * @return false|string
206 */
207 public function get_img_src( $sources = [ Placeholder::ID, LoremPicsum::ID ] ) {
208 $images = \FakerPress\Module\Post::fetch( [ 'post_type' => 'attachment' ] );
209 $image = false;
210 $count_images = count( $images );
211
212 if ( $count_images > 0 ) {
213 $image = $this->generator->optional( 0.2, $image )->randomElement( $images );
214 }
215
216 if ( false === $image ) {
217 $image = make( Attachment::class )
218 ->set( 'attachment_url', $this->generator->randomElement( $sources ) )
219 ->generate()->save();
220 }
221
222 if ( is_wp_error( $image ) ) {
223 return $image;
224 }
225
226 return wp_get_attachment_url( $image );
227 }
228
229 /**
230 * Randomly apply a given element to an existing text.
231 *
232 * @since 0.1.0
233 *
234 * @param string $element
235 * @param int $max
236 * @param string|null $text
237 *
238 * @return string|null
239 */
240 public function random_apply_element( $element = 'a', $max = 5, $text = null ) {
241 $words = explode( ' ', $text );
242 $total_words = count( $words );
243 $sentences = [];
244
245 for ( $i = 0; $i < $total_words; $i ++ ) {
246 $group = Base::numberBetween( 1, Base::numberBetween( 3, 9 ) );
247 $sentence = [];
248
249 for ( $k = 0; $k < $group; $k ++ ) {
250 $index = $i + $k;
251
252 if ( ! isset( $words[ $index ] ) ) {
253 break;
254 }
255
256 $sentence[] = $words[ $index ];
257
258 }
259 $i += $k;
260
261 $sentences[] = implode( ' ', $sentence );
262 }
263
264 $qty = $max - Base::numberBetween( 0, $max );
265
266 if ( 0 === $qty ) {
267 return $text;
268 }
269
270 $indexes = floor( count( $sentences ) / $qty );
271
272 for ( $i = 0; $i < $qty; $i ++ ) {
273 $index = ( $indexes * $i ) + Base::numberBetween( 0, $indexes );
274
275 if ( isset( $sentences[ $index ] ) ) {
276 $sentences[ $index ] = $this->element( $element, [], $sentences[ $index ] );
277 }
278 }
279
280 return implode( ' ', $sentences );
281 }
282
283 /**
284 * Generates a given Element by name with a set of attrs and text based on a set of arguments.
285 *
286 * @since 0.1.0
287 *
288 * @param string $name
289 * @param array $attr
290 * @param string|null $text
291 * @param array|null $args
292 *
293 * @return false|string
294 */
295 public function element( $name = 'div', $attr = [], $text = null, $args = null ) {
296 $element = (object) [
297 'name' => $name,
298 'attr' => $attr,
299 ];
300
301 if ( empty( $element->name ) ) {
302 return false;
303 }
304
305 $element->one_liner = in_array( $element->name, self::$sets['self_close'] );
306
307 $html = [];
308
309 if ( 'a' === $element->name ) {
310 if ( ! isset( $element->attr['title'] ) ) {
311 $element->attr['title'] = Lorem::sentence( Base::numberBetween( 1, Base::numberBetween( 3, 9 ) ) );
312 }
313 if ( ! isset( $element->attr['href'] ) ) {
314 $element->attr['href'] = $this->generator->url();
315 }
316 }
317
318 if ( 'img' === $element->name ) {
319 $sources = [ LoremPicsum::ID, Placeholder::ID ];
320 if ( is_object( $args ) && $args->sources ) {
321 $sources = $args->sources;
322 }
323 $element = $this->html_element_img( $element, $sources );
324
325 // When we fail to create the image we just bail.
326 if ( is_wp_error( $element ) ) {
327 return false;
328 }
329 }
330
331 $attributes = [];
332 foreach ( $element->attr as $key => $value ) {
333 $attributes[] = sprintf( '%s="%s"', $key, esc_attr( $value ) );
334 }
335
336 $html[] = sprintf( '<%s%s>', $element->name, ( ! empty( $attributes ) ? ' ' : '' ) . implode( ' ', $attributes ) );
337
338 if ( ! $element->one_liner ) {
339 if ( ! is_null( $text ) ) {
340 $html[] = $text;
341 } elseif ( in_array( $element->name, self::$sets['inline'] ) ) {
342 $text = Lorem::text( Base::numberBetween( 5, 25 ) );
343 $html[] = substr( $text, 0, strlen( $text ) - 1 );
344 } elseif ( in_array( $element->name, self::$sets['item'] ) ) {
345 $text = Lorem::text( Base::numberBetween( 10, 60 ) );
346 $html[] = substr( $text, 0, strlen( $text ) - 1 );
347 } elseif ( in_array( $element->name, self::$sets['list'] ) ) {
348 for ( $i = 0; $i < Base::numberBetween( 1, 15 ); $i ++ ) {
349 $html[] = $this->element( 'li' );
350 }
351 } elseif ( in_array( $element->name, self::$sets['header'] ) ) {
352 $text = Lorem::text( Base::numberBetween( 60, 200 ) );
353 $html[] = substr( $text, 0, - 1 );
354 } else {
355 $html[] = $this->random_apply_element( 'a', Base::numberBetween( 0, 10 ), Lorem::paragraph( Base::numberBetween( 2, 40 ) ) );
356 }
357
358 $html[] = sprintf( '</%s>', $element->name );
359 }
360
361 return implode( '', $html );
362 }
363
364 }
365