fb93a55ea0d3d0e4fb9db49fc1a81f9ed9c8dd91
[yaffs-website] / web / modules / contrib / advagg / src / Form / InfoForm.php
1 <?php
2
3 namespace Drupal\advagg\Form;
4
5 use Drupal\Component\Utility\Unicode;
6 use Drupal\Component\Utility\Xss;
7 use Drupal\Core\Config\ConfigFactoryInterface;
8 use Drupal\Core\Datetime\DateFormatterInterface;
9 use Drupal\Core\Form\ConfigFormBase;
10 use Drupal\Core\Form\FormBuilderInterface;
11 use Drupal\Core\Form\FormStateInterface;
12 use Drupal\Core\State\StateInterface;
13 use Drupal\Core\StringTranslation\Translator\TranslatorInterface;
14 use Drupal\Core\Theme\Registry;
15 use Symfony\Component\DependencyInjection\ContainerInterface;
16 use Symfony\Component\HttpFoundation\RequestStack;
17
18 /**
19  * View AdvAgg information for this site.
20  */
21 class InfoForm extends ConfigFormBase {
22   /**
23    * The theme registry service.
24    *
25    * @var \Drupal\Core\Theme\Registry
26    */
27   protected $themeRegistry;
28
29   /**
30    * The AdvAgg file status state information storage service.
31    *
32    * @var \Drupal\Core\State\StateInterface
33    */
34   protected $advaggFiles;
35
36   /**
37    * The AdvAgg aggregates state information storage service.
38    *
39    * @var \Drupal\Core\State\StateInterface
40    */
41   protected $advaggAggregates;
42
43   /**
44    * The request stack.
45    *
46    * @var \Symfony\Component\HttpFoundation\RequestStack
47    */
48   protected $requestStack;
49
50   /**
51    * The date formatter service.
52    *
53    * @var \Drupal\Core\Datetime\DateFormatterInterface
54    */
55   protected $dateFormatter;
56
57   /**
58    * The string translation service.
59    *
60    * @var \Drupal\Core\StringTranslation\Translator\TranslatorInterface
61    */
62   protected $translation;
63
64   /**
65    * Constructs a SettingsForm object.
66    *
67    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
68    *   The factory for configuration objects.
69    * @param \Drupal\Core\Theme\Registry $theme_registry
70    *   The theme registry service.
71    * @param \Drupal\Core\State\StateInterface $advagg_files
72    *   The AdvAgg file status state information storage service.
73    * @param \Drupal\Core\State\StateInterface $advagg_aggregates
74    *   The AdvAgg aggregate state information storage service.
75    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
76    *   The request stack.
77    * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
78    *   The Date formatter service.
79    * @param \Drupal\Core\StringTranslation\Translator\TranslatorInterface $string_translation
80    *   The string translation service.
81    */
82   public function __construct(ConfigFactoryInterface $config_factory, Registry $theme_registry, StateInterface $advagg_files, StateInterface $advagg_aggregates, RequestStack $request_stack, DateFormatterInterface $date_formatter, TranslatorInterface $string_translation) {
83     parent::__construct($config_factory);
84
85     $this->themeRegistry = $theme_registry;
86     $this->advaggFiles = $advagg_files;
87     $this->advaggAggregates = $advagg_aggregates;
88     $this->requestStack = $request_stack;
89     $this->dateFormatter = $date_formatter;
90     $this->translation = $string_translation;
91   }
92
93   /**
94    * {@inheritdoc}
95    */
96   public static function create(ContainerInterface $container) {
97     return new static(
98       $container->get('config.factory'),
99       $container->get('theme.registry'),
100       $container->get('state.advagg.files'),
101       $container->get('state.advagg.aggregates'),
102       $container->get('request_stack'),
103       $container->get('date.formatter'),
104       $container->get('string_translation')
105     );
106   }
107
108   /**
109    * {@inheritdoc}
110    */
111   public function getFormId() {
112     return 'advagg_info';
113   }
114
115   /**
116    * {@inheritdoc}
117    */
118   protected function getEditableConfigNames() {
119     return [];
120   }
121
122   /**
123    * {@inheritdoc}
124    */
125   public function buildForm(array $form, FormStateInterface $form_state) {
126     $form = [];
127     $form['tip'] = [
128       '#markup' => '<p>' . $this->t('This page provides debugging information. There are no configuration options here.') . '</p>',
129     ];
130
131     // Get all hooks and variables.
132     $core_hooks = $this->themeRegistry->get();
133     $advagg_hooks = advagg_hooks_implemented();
134
135     // Output html preprocess functions hooks.
136     $form['theme_info'] = [
137       '#type' => 'details',
138       '#title' => $this->t('Hook Theme Info'),
139     ];
140     $data = implode("\n", $core_hooks['html']['preprocess functions']);
141     $form['theme_info']['advagg_theme_info'] = [
142       '#markup' => '<p>preprocess functions on html.</p><pre>' . $data . '</pre>',
143     ];
144
145     $file_data = $this->advaggFiles->getAll();
146
147     // Get all parent css and js files.
148     $types = ['css', 'js'];
149     foreach ($types as $type) {
150       $form[$type] = [
151         '#type' => 'details',
152         '#title' => $this->t('@type files', ['@type' => Unicode::strtoupper($type)]),
153       ];
154     }
155     foreach ($file_data as $name => $info) {
156       if (!in_array($info['fileext'], $types)) {
157         continue;
158       }
159       $form[$info['fileext']][$info['filename_hash']] = [
160         '#markup' => '<details><summary>' . $this->translation->formatPlural($info['changes'], 'changed 1 time - %file<br />', 'changed %changes times - %file<br />', [
161           '%changes' => $info['changes'],
162           '%file' => $name,
163         ]) . '</summary><div class="details-wrapper"><pre>' . print_r($info, TRUE) . '</pre></div></details>',
164       ];
165     }
166
167     // Display as module -> hook instead of hook -> module.
168     ksort($advagg_hooks);
169     $module_hooks = [];
170     foreach ($advagg_hooks as $hook => $values) {
171       if (!empty($values)) {
172         foreach ($values as $module_name) {
173           if (!isset($module_hooks[$module_name])) {
174             $module_hooks[$module_name] = [];
175           }
176           $module_hooks[$module_name][] = $hook;
177         }
178       }
179       else {
180         $module_hooks['not in use'][] = $hook;
181       }
182     }
183     ksort($module_hooks);
184
185     $form['modules_implementing_advagg'] = [
186       '#type' => 'details',
187       '#title' => $this->t('Modules implementing aggregate hooks'),
188     ];
189     $form['hooks_implemented'] = [
190       '#type' => 'details',
191       '#title' => $this->t('AdvAgg CSS/JS hooks implemented by modules'),
192     ];
193
194     // Output all advagg hooks implemented.
195     foreach ($module_hooks as $hook => $values) {
196       if (empty($values)) {
197         $form['modules_implementing_advagg'][$hook] = [
198           '#markup' => '<div><strong>' . $hook . ':</strong> 0</div>',
199         ];
200       }
201       else {
202         $form['modules_implementing_advagg'][$hook] = [
203           '#markup' => '<div><strong>' . $hook . ':</strong> ' . count($values) . $this->formatList($values) . '</div>',
204         ];
205       }
206     }
207
208     // Output all advagg hooks implemented.
209     foreach ($advagg_hooks as $hook => $values) {
210       if (empty($values)) {
211         $form['hooks_implemented'][$hook] = [
212           '#markup' => '<div><strong>' . $hook . ':</strong> 0</div>',
213         ];
214       }
215       else {
216         $form['hooks_implemented'][$hook] = [
217           '#markup' => '<div><strong>' . $hook . ':</strong> ' . count($values) . $this->formatList($values) . '</div>',
218         ];
219       }
220     }
221
222     // Output what is used inside of advagg_get_current_hooks_hash().
223     $form['hooks_variables_hash'] = [
224       '#type' => 'details',
225       '#title' => $this->t('Hooks And Variables Used In Hash'),
226     ];
227     $form['hooks_variables_hash']['description'] = [
228       '#markup' => $this->t('Current Value: %value. Below is the listing of variables and hooks used to generate the 3rd hash of an aggregates filename.', ['%value' => advagg_get_current_hooks_hash()]),
229     ];
230     $form['hooks_variables_hash']['output'] = [
231       // @ignore production_php
232       '#markup' => '<pre>' . print_r(advagg_current_hooks_hash_array(), TRUE) . '</pre>',
233     ];
234     // Get info about a file.
235     $form['get_info_about_agg'] = [
236       '#type' => 'details',
237       '#open' => TRUE,
238       '#title' => $this->t('Get detailed info about an aggregate file'),
239     ];
240     $form['get_info_about_agg']['filename'] = [
241       '#type' => 'textfield',
242       '#size' => 170,
243       '#maxlength' => 256,
244       '#default_value' => '',
245       '#title' => $this->t('Filename'),
246     ];
247     $form['get_info_about_agg']['submit'] = [
248       '#type' => 'submit',
249       '#value' => $this->t('Lookup Details'),
250       '#submit' => ['::getFileInfoSubmit'],
251       '#validate' => ['::getFileInfoValidate'],
252       '#ajax' => [
253         'callback' => '::getFileInfoAjax',
254         'wrapper' => 'advagg-file-info-ajax',
255         'effect' => 'fade',
256       ],
257     ];
258     $form['get_info_about_agg']['tip'] = [
259       '#markup' => '<p>' . $this->t('Takes input like "@css_file" or a full aggregate name like "@advagg_js"', [
260         '@css_file' => $this->advaggFiles->getRandomKey(),
261         '@advagg_js' => $this->advaggAggregates->getRandom()['uid'],
262       ]) . '</p>',
263     ];
264     $form['get_info_about_agg']['wrapper'] = [
265       '#prefix' => "<div id='advagg-file-info-ajax'>",
266       '#suffix' => "</div>",
267     ];
268     $form = parent::buildForm($form, $form_state);
269     unset($form['actions']);
270     return $form;
271   }
272
273   /**
274    * Format an indented list from array.
275    *
276    * @param array $list
277    *   The array to convert to a string.
278    * @param int $depth
279    *   (optional) Depth multiplier for indentation.
280    *
281    * @return string
282    *   The imploded and spaced array.
283    */
284   private function formatList(array $list, $depth = 1) {
285     $spacer = '<br />' . str_repeat('&nbsp;', 2 * $depth);
286     $output = $spacer . Xss::filter(implode($spacer, $list), ['br']);
287     return $output;
288   }
289
290   /**
291    * Display file info in a drupal message.
292    *
293    * @param array $form
294    *   An associative array containing the structure of the form.
295    * @param \Drupal\Core\Form\FormStateInterface $form_state
296    *   The current state of the form.
297    */
298   public function getFileInfoSubmit(array &$form, FormStateInterface $form_state) {
299     $info = $this->getFileInfo($form_state->getValue('filename'));
300     $output = '<pre>' . print_r($info, TRUE) . '</pre>';
301     if (!$this->isAjax()) {
302       drupal_set_message($output);
303     }
304   }
305
306   /**
307    * Display file info via ajax callback.
308    *
309    * @param array $form
310    *   An associative array containing the structure of the form.
311    * @param \Drupal\Core\Form\FormStateInterface $form_state
312    *   The current state of the form.
313    */
314   public function getFileInfoAjax(array &$form, FormStateInterface $form_state) {
315     $element = $form['get_info_about_agg']['wrapper'];
316     if ($form_state->hasAnyErrors()) {
317       return $element;
318     }
319     $info = $this->getFileInfo($form_state->getValue('filename'));
320     if (empty($info)) {
321       $form_state->setErrorByName('filename', $this->t('Please input a valid aggregate filename.'));
322       return $element;
323     }
324     else {
325       $element['#markup'] = '<pre>' . print_r($info, TRUE) . '</pre>';
326       return $element;
327     }
328   }
329
330   /**
331    * Verify that the filename is correct.
332    *
333    * @param array $form
334    *   An associative array containing the structure of the form.
335    * @param \Drupal\Core\Form\FormStateInterface $form_state
336    *   The current state of the form.
337    */
338   public function getFileInfoValidate(array &$form, FormStateInterface $form_state) {
339     if (empty($form_state->getValue('filename'))) {
340       $form_state->setErrorByName('filename', $this->t('Please input an aggregate filename.'));
341     }
342   }
343
344   /**
345    * Get detailed info about the given filename.
346    *
347    * @param string $filename
348    *   Name of file to lookup.
349    *
350    * @return array
351    *   Returns an array of detailed info about this file.
352    */
353   private function getFileInfo($filename) {
354     // Strip quotes and trim.
355     $filename = trim(str_replace(['"', "'"], '', $filename));
356     if (substr_compare($filename, 'css_', 0) > 0 || substr_compare($filename, 'js_', 0) > 0) {
357       $results = array_column($this->advaggAggregates->getAll(), NULL, 'uid');
358       if (isset($results[$filename])) {
359         return $results[$filename];
360       }
361       else {
362         return "Aggregate name unrecognized, confirm spelling, otherwise likely a very old aggregate that has been expunged.";
363       }
364     }
365     elseif ($data = $this->advaggFiles->get($filename)) {
366       $data['File modification date'] = $this->dateFormatter->format($data['mtime'], 'html_datetime');
367       $data['Information last update'] = $this->dateFormatter->format($data['updated'], 'html_datetime');
368       return $data;
369     }
370     else {
371       return "File not found and AdvAgg has no record of it. Confirm spelling of the path.";
372     }
373   }
374
375   /**
376    * Checks if the form was submitted by AJAX.
377    *
378    * @return bool
379    *   TRUE if the form was submitted via AJAX, otherwise FALSE.
380    */
381   private function isAjax() {
382     $request = $this->requestStack->getCurrentRequest();
383     if ($request->query->has(FormBuilderInterface::AJAX_FORM_REQUEST)) {
384       return TRUE;
385     }
386     return FALSE;
387   }
388
389 }