Yaffs site version 1.1
[yaffs-website] / web / modules / contrib / advagg / advagg_validator / src / Form / BaseValidatorForm.php
1 <?php
2
3 namespace Drupal\advagg_validator\Form;
4
5 use Drupal\advagg\Form\AdvaggFormBase;
6 use Drupal\Component\Render\HtmlEscapedText;
7
8 /**
9  * Base form for all advagg validator options.
10  */
11 abstract class BaseValidatorForm extends AdvaggFormBase {
12
13   /**
14    * {@inheritdoc}
15    */
16   protected function getEditableConfigNames() {
17     return ['advagg_validator.settings'];
18   }
19
20   /**
21    * Generate a heirachical form sorted by path from asset files.
22    *
23    * @param string $type
24    *   The asset extension - usually 'css' or 'js'.
25    * @param bool $run_client_side
26    *   Determines whether to assign submit functions to buttons.
27    *
28    * @return array
29    *   A Form API array.
30    */
31   public function generateForm($type, $run_client_side = TRUE) {
32     $form = [];
33     $files = $this->scanAllDirs($type);
34     rsort($files);
35     foreach ($files as $file) {
36       $dir = dirname($file);
37
38       // Build the directory structure.
39       $levels = explode('/', $dir === '.' ? '{ROOT}' : $dir);
40       $point = &$form;
41       $built = [];
42       foreach ($levels as $key => $value) {
43         // Build directory structure.
44         $built[] = $value;
45         $point = &$point[$value];
46         if (!is_array($point)) {
47           $form_api_dirname = str_replace(['/', '.'], ['__', '--'], $dir);
48           $wrapper = 'advagg-validator-' . $type . '-validator-ajax' . $form_api_dirname;
49
50           $point = [
51             '#type' => 'details',
52             '#title' => $value,
53             '#description' => '<strong>' . t('Directory:') . ' </strong>' . implode('/', $built),
54             '#weight' => 100,
55           ];
56           if (!isset($point['check_all_levels']) && $value !== '{ROOT}' && count($levels) != $key + 1) {
57             $point['check_all_levels'] = [
58               '#type' => 'submit',
59               '#value' => t('Check directory and all subdirectories'),
60               '#name' => implode('/', $built),
61             ];
62             if (!$run_client_side) {
63               $point['check_all_levels'] += [
64                 '#submit' => ['::submitCheckAll'],
65                 '#ajax' => [
66                   'callback' => '::ajaxCheck',
67                   'wrapper' => $wrapper,
68                 ],
69               ];
70             }
71             else {
72               $point['check_all_levels'] += [
73                 '#attributes' => [
74                   'class' => ['advagg_validator_recursive_' . $type],
75                 ],
76               ];
77             }
78           }
79           $point['break'] = [
80             '#markup' => '<div></div>',
81           ];
82
83           $point['wrapper'] = [
84             '#markup' => "<div id='" . $wrapper . "' class='results'></div>",
85             '#weight' => 90,
86           ];
87         }
88
89         // Drop in button and info if we reached the point where a file lives.
90         if (count($levels) == $key + 1) {
91           $form_api_filename = str_replace(['/', '.'], ['__', '--'], $file);
92
93           if (!isset($point['check_this_level'])) {
94             $point['check_this_level'] = [
95               '#type' => 'submit',
96               '#value' => t('Check directory'),
97             ];
98             if (!$run_client_side) {
99               $point['check_this_level'] += [
100                 '#submit' => ['::submitCheckDirectory'],
101                 '#name' => $dir,
102                 '#ajax' => [
103                   'callback' => '::ajaxCheck',
104                   'wrapper' => $wrapper,
105                 ],
106               ];
107             }
108             else {
109               $point['check_this_level'] += [
110                 '#attributes' => [
111                   'class' => ['advagg_validator_' . $type],
112                 ],
113               ];
114             }
115           }
116           if (!isset($point['start'])) {
117             $point['start'] = [
118               '#markup' => '<br /><strong>' . t('File:') . ' </strong><div class="filenames">',
119             ];
120           }
121           else {
122             $point['start'] = [
123               '#markup' => '<br /><strong>' . t('Files:') . ' </strong><div class="filenames">',
124             ];
125           }
126           $point[$form_api_filename] = [
127             '#markup' => $file . " </br>\n",
128           ];
129           if (!isset($point['end'])) {
130             $point['end'] = [
131               '#markup' => '</div>',
132             ];
133           }
134
135           $point['hidden_' . $form_api_filename] = [
136             '#type' => 'hidden',
137             '#value' => $file,
138             '#attributes' => [
139               'class' => ['filenames'],
140             ],
141           ];
142
143         }
144       }
145     }
146     return $form;
147   }
148
149   /**
150    * Do not display info on a file if it is valid.
151    *
152    * @param array $info
153    *   Array containing info about validators and if the file is valid.
154    *
155    * @return array
156    *   $info array minus data if that file is valid.
157    */
158   protected function hideGoodFiles(array $info) {
159     $output = [];
160     foreach ($info as $filename => $validators) {
161       foreach ($validators as $v_name => $v_data) {
162         $output[$filename][$v_name] = ['#prefix' => '<em>' . $filename . ':</em> '];
163         if (!empty($v_data['validity'])) {
164           $output[$filename][$v_name]['#markup'] = t('valid');
165         }
166         elseif (isset($v_data['error'])) {
167           $output[$filename][$v_name]['error'] = $v_data['error'];
168         }
169         else {
170           $output[$filename][$v_name]['options'] = [
171             '#markup' => '<em>' . t('Options:') . '</em><br/>',
172           ];
173           foreach ($v_data['options'] as $option => $value) {
174             $output[$filename][$v_name]['options'][] = [
175               '#markup' => new HtmlEscapedText($option) . ': ' . new HtmlEscapedText($value),
176               '#suffix' => '</br>',
177             ];
178           }
179           if (isset($v_data['errors'])) {
180             $output[$filename][$v_name]['errors'] = [
181               '#markup' => '<em>' . t('Errors:') . '</em>',
182             ];
183             foreach ($v_data['errors'] as $error) {
184               $output[$filename][$v_name]['errors'][] = [
185                 '#prefix' => '<pre>',
186                 '#plain_text' => print_r($error, TRUE),
187                 '#suffix' => '</pre>',
188               ];
189             }
190           }
191           if (isset($v_data['warnings'])) {
192             $output[$filename][$v_name]['warnings'] = [
193               '#markup' => '<em>' . t('Warnings:') . '</em>',
194             ];
195             foreach ($v_data['warnings'] as $warning) {
196               $output[$filename][$v_name]['warnings'][] = [
197                 '#prefix' => '<pre>',
198                 '#plain_text' => print_r($warning, TRUE),
199                 '#suffix' => '</pre>',
200               ];
201             }
202           }
203         }
204       }
205     }
206     return $output;
207   }
208
209   /**
210    * Recursively scan the drupal webroot for files matching the given extension.
211    *
212    * @param string $ext
213    *   Usually css or js.
214    *
215    * @return array
216    *   An array of files.
217    */
218   protected function scanAllDirs($ext) {
219     $options = [
220       'nodirmask' => '/(\.git|.*\/files*)/',
221     ];
222     $output = $this->scanDirectory(\Drupal::root(), '/.*\.' . $ext . '$/', $options);
223     $files = [];
224     foreach ($output as $values) {
225       $files[] = str_replace(\Drupal::root() . '/', '', $values->uri);
226     }
227     return $files;
228   }
229
230   /**
231    * Finds all files that match a given mask in a given directory.
232    *
233    * Directories and files beginning with a period are excluded; this
234    * prevents hidden files and directories (such as SVN working directories)
235    * from being scanned.
236    *
237    * @param string $dir
238    *   The base directory or URI to scan, without trailing slash.
239    * @param string $mask
240    *   The preg_match() regular expression of the files to find.
241    * @param array $options
242    *   An associative array of additional options, with the following elements:
243    *   - 'nomask': The preg_match() regular expression of the files to ignore.
244    *     Defaults to '/(\.\.?|CVS)$/'.
245    *   - 'nomask': The preg_match() regular expression of the dirs to ignore.
246    *     Defaults to '/(\.git)/'.
247    *   - 'callback': The callback function to call for each match. There is no
248    *     default callback.
249    *   - 'recurse': When TRUE, the directory scan will recurse the entire tree
250    *     starting at the provided directory. Defaults to TRUE.
251    *   - 'key': The key to be used for the returned associative array of files.
252    *     Possible values are 'uri', for the file's URI; 'filename', for the
253    *     basename of the file; and 'name' for the name of the file without the
254    *     extension. Defaults to 'uri'.
255    *   - 'min_depth': Minimum depth of directories to return files from.
256    *     Defaults to 0.
257    * @param int $depth
258    *   Current depth of recursion. This parameter is only used internally and
259    *   should not be passed in.
260    *
261    * @return array
262    *   An associative array (keyed on the chosen key) of objects with 'uri',
263    *   'filename', and 'name' members corresponding to the matching files.
264    */
265   protected function scanDirectory($dir, $mask, array $options = [], $depth = 0) {
266     // Merge in defaults.
267     $options += [
268       'nomask' => '/(\.\.?|CVS)$/',
269       'nodirmask' => '/(\.git)/',
270       'callback' => 0,
271       'recurse' => TRUE,
272       'key' => 'uri',
273       'min_depth' => 0,
274     ];
275
276     $options['key'] = in_array($options['key'], ['uri', 'filename', 'name']) ? $options['key'] : 'uri';
277     $files = [];
278
279     if (is_dir($dir)) {
280       $handle = opendir($dir);
281       if ($handle) {
282         while (FALSE !== ($filename = readdir($handle))) {
283           // Skip if filename matches the nomask or is '.'.
284           if (preg_match($options['nomask'], $filename) || $filename[0] === '.') {
285             continue;
286           }
287
288           $uri = "$dir/$filename";
289           $uri = file_stream_wrapper_uri_normalize($uri);
290           if (is_dir($uri) && $options['recurse'] && !preg_match($options['nodirmask'], $uri)) {
291             // Give priority to files in this folder by merging them in after
292             // any subdirectory files.
293             $files = array_merge($this->scanDirectory($uri, $mask, $options, $depth + 1), $files);
294           }
295           elseif ($depth >= $options['min_depth'] && preg_match($mask, $filename)) {
296             // Always use this match over anything already set in $files with
297             // the same $$options['key'].
298             $file = new \stdClass();
299             $file->uri = $uri;
300             $file->filename = $filename;
301             $file->name = pathinfo($filename, PATHINFO_FILENAME);
302             $key = $options['key'];
303             $files[$file->$key] = $file;
304             if ($options['callback']) {
305               $options['callback']($uri);
306             }
307           }
308         }
309
310         closedir($handle);
311       }
312     }
313
314     return $files;
315   }
316
317   /**
318    * Perform server side test(s) on all given files.
319    *
320    * @param array $files
321    *   An array of files to be tested.
322    * @param array $options
323    *   (optional) An array of options to use in the test.
324    *
325    * @return array
326    *   An array of files with the result.
327    */
328   protected function testFiles(array $files, array $options = []) {
329     return $files;
330   }
331
332   /**
333    * Extract info from the DOMNode Object.
334    *
335    * @param object $dom
336    *   DOMNode Class.
337    *
338    * @return array
339    *   Key Value pair from the DOM Node.
340    */
341   protected function domExtractor($dom) {
342     $node = $dom->firstChild;
343     $output = [];
344     do {
345       $text = trim($node->nodeValue);
346       if (!empty($text)) {
347         $key = str_replace('m:', '', $node->nodeName);
348         $output[$key] = $text;
349       }
350     } while ($node = $node->nextSibling);
351     return $output;
352   }
353
354   /**
355    * Get array element that corresponds to directory.
356    *
357    * @param array $array
358    *   An associative array to check for the key. Usually a form array.
359    * @param array $keys_array
360    *   An array of keys to check sequentially in a heirachical manner.
361    */
362   protected function getElement(array $array, array $keys_array) {
363     foreach ($keys_array as $key) {
364       if (!isset($key, $array)) {
365         return FALSE;
366       }
367       $array = $array[$key];
368     }
369     return $array;
370   }
371
372 }