Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
253 / 253
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
1 / 1
SettingsForm
100.00% covered (success)
100.00%
253 / 253
100.00% covered (success)
100.00%
8 / 8
14
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 create
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getFormId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getEditableConfigNames
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 buildForm
100.00% covered (success)
100.00%
214 / 214
100.00% covered (success)
100.00%
1 / 1
4
 submitForm
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
1
 entityTypes
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 roleOptions
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace Drupal\visitors\Form;
4
5use Drupal\Core\Config\Entity\ConfigEntityType;
6use Drupal\Core\Entity\EntityTypeManagerInterface;
7use Drupal\Core\Form\ConfigFormBase;
8use Drupal\Core\Form\FormStateInterface;
9use Drupal\Core\Url;
10use Drupal\visitors\VisitorsVisibilityInterface;
11use Symfony\Component\DependencyInjection\ContainerInterface;
12
13/**
14 * Visitors Settings Form.
15 */
16class SettingsForm extends ConfigFormBase {
17
18  /**
19   * Visitors settings.
20   *
21   * @var string
22   */
23  const SETTINGS = 'visitors.settings';
24
25  /**
26   * An extension discovery instance.
27   *
28   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
29   */
30  protected $entityTypeManager;
31
32  /**
33   * Constructs a Settings form.
34   *
35   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
36   *   The entity type manager.
37   */
38  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
39    $this->entityTypeManager = $entity_type_manager;
40  }
41
42  /**
43   * {@inheritdoc}
44   */
45  public static function create(ContainerInterface $container) {
46    return new self(
47      $container->get('entity_type.manager')
48    );
49  }
50
51  /**
52   * {@inheritdoc}
53   */
54  public function getFormId() {
55    return 'visitors_admin_settings';
56  }
57
58  /**
59   * {@inheritdoc}
60   */
61  protected function getEditableConfigNames() {
62    return [
63      static::SETTINGS,
64    ];
65  }
66
67  /**
68   * {@inheritdoc}
69   */
70  public function buildForm(array $form, FormStateInterface $form_state) {
71    $config = $this->config(self::SETTINGS);
72    $form = parent::buildForm($form, $form_state);
73
74    $form['visitors_disable_tracking'] = [
75      '#type' => 'radios',
76      '#title' => $this->t('Track visitors'),
77      '#options' => [
78        $this->t('Enabled'),
79        $this->t('Disabled'),
80      ],
81      '#description' => $this->t('Enable or disable tracking of visitors.'),
82      '#default_value' => (int) $config->get('disable_tracking'),
83    ];
84
85    $form['tracking_scope'] = [
86      '#type' => 'vertical_tabs',
87      '#title' => $this->t('Tracking scope'),
88      '#title_display' => 'invisible',
89      '#default_tab' => 'edit-tracking',
90      '#attached' => [
91        'library' => [
92          'visitors/visitors.admin',
93        ],
94      ],
95    ];
96
97    $form['page_visibility_settings'] = [
98      '#type' => 'details',
99      '#title' => $this->t('Pages'),
100      '#group' => 'tracking_scope',
101    ];
102
103    $description = $this->t(
104        "Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.",
105        [
106          '%blog' => '/blog',
107          '%blog-wildcard' => '/blog/*',
108          '%front' => '<front>',
109        ]
110      );
111
112    $form['page_visibility_settings']['visitors_visibility_request_path_pages'] = [
113      '#type' => 'textarea',
114      '#title' => $this->t('Pages'),
115      '#title_display' => 'invisible',
116      '#default_value' => $config->get('visibility.request_path_pages') ?? '',
117      '#description' => $description,
118      '#rows' => (int) 10,
119    ];
120    $form['page_visibility_settings']['visitors_visibility_request_path_mode'] = [
121      '#type' => 'radios',
122      '#title' => $this->t('Add tracking to specific pages'),
123      '#title_display' => 'invisible',
124      '#options' => [
125        VisitorsVisibilityInterface::PATH_EXCLUDE => $this->t('All pages except those listed'),
126        VisitorsVisibilityInterface::PATH_INCLUDE => $this->t('Only the listed pages'),
127      ],
128      '#default_value' => $config->get('visibility.request_path_mode'),
129    ];
130
131    $visibility_user_role_roles = $config->get('visibility.user_role_roles');
132
133    $form['role_visibility_settings'] = [
134      '#type' => 'details',
135      '#title' => $this->t('Roles'),
136      '#group' => 'tracking_scope',
137    ];
138
139    $form['role_visibility_settings']['visitors_visibility_user_role_mode'] = [
140      '#type' => 'radios',
141      '#title' => $this->t('Add tracking for specific roles'),
142      '#options' => [
143        $this->t('Add to the selected roles only'),
144        $this->t('Add to every role except the selected ones'),
145      ],
146      '#default_value' => $config->get('visibility.user_role_mode'),
147    ];
148    $form['role_visibility_settings']['visitors_visibility_user_role_roles'] = [
149      '#type' => 'checkboxes',
150      '#title' => $this->t('Roles'),
151      '#default_value' => !empty($visibility_user_role_roles) ? $visibility_user_role_roles : [],
152      '#options' => $this->roleOptions(),
153      '#description' => $this->t('If none of the roles are selected, all users will be tracked. If a user has any of the roles checked, that user will be tracked (or excluded, depending on the setting above).'),
154    ];
155
156    $visibility_user_account_mode = $config->get('visibility.user_account_mode');
157
158    $form['user_visibility_settings'] = [
159      '#type' => 'details',
160      '#title' => $this->t('Users'),
161      '#group' => 'tracking_scope',
162    ];
163    $t_permission = ['%permission' => $this->t('opt-out of visitors tracking')];
164    $form['user_visibility_settings']['visitors_visibility_user_account_mode'] = [
165      '#type' => 'radios',
166      '#title' => $this->t('Allow users to customize tracking on their account page'),
167      '#options' => [
168        VisitorsVisibilityInterface::USER_NO_PERSONALIZATION => $this->t('No customization allowed'),
169        VisitorsVisibilityInterface::USER_OPT_OUT => $this->t('Tracking on by default, users with %permission permission can opt out', $t_permission),
170        VisitorsVisibilityInterface::USER_OPT_IN => $this->t('Tracking off by default, users with %permission permission can opt in', $t_permission),
171      ],
172      '#default_value' => !empty($visibility_user_account_mode) ? $visibility_user_account_mode : 0,
173    ];
174    $form['user_visibility_settings']['visitors_trackuserid'] = [
175      '#type' => 'checkbox',
176      '#title' => $this->t('Track User ID'),
177      '#default_value' => $config->get('track.userid'),
178      '#description' => $this->t('User ID enables the analysis of groups of sessions, across devices, using a unique, persistent, and representing a user. <a href=":url">Learn more about the benefits of using User ID</a>.', [':url' => 'https://matomo.org/docs/user-id/']),
179    ];
180
181    $form['user_visibility_settings']['visibility_exclude_user1'] = [
182      '#type' => 'checkbox',
183      '#title' => $this->t('Exclude user1 from statistics'),
184      '#default_value' => $config->get('visibility.exclude_user1'),
185      '#description' => $this->t('Exclude hits of user1 from statistics.'),
186    ];
187
188    $form['entity'] = [
189      '#type' => 'details',
190      '#title' => $this->t('Entity counter'),
191      '#group' => 'tracking_scope',
192    ];
193    $form['entity']['counter_enabled'] = [
194      '#type' => 'checkbox',
195      '#title' => $this->t('Count entity views'),
196      '#default_value' => $config->get('counter.enabled'),
197      '#description' => $this->t('Count the number of times entities are viewed.'),
198    ];
199    $form['entity']['entity_types'] = [
200      '#type' => 'checkboxes',
201      '#title' => $this->t('Entity Types'),
202      '#options' => $this->entityTypes(),
203      '#default_value' => $config->get('counter.entity_types') ?? [],
204      '#description' => $this->t('Which entity types should be tracked.'),
205    ];
206
207    $form['retention'] = [
208      '#type' => 'details',
209      '#title' => $this->t('Retention'),
210      '#group' => 'tracking_scope',
211    ];
212
213    $form['retention']['flush_log_timer'] = [
214      '#type' => 'select',
215      '#title' => $this->t('Discard visitors logs older than'),
216      '#default_value'   => $config->get('flush_log_timer'),
217      '#options' => [
218        0 => $this->t('Never'),
219        3600 => $this->t('1 hour'),
220        10800 => $this->t('3 hours'),
221        21600 => $this->t('6 hours'),
222        32400 => $this->t('9 hours'),
223        43200 => $this->t('12 hours'),
224        86400 => $this->t('1 day'),
225        172800 => $this->t('2 days'),
226        259200 => $this->t('3 days'),
227        604800 => $this->t('1 week'),
228        1209600 => $this->t('2 weeks'),
229        4838400 => $this->t('1 month 3 weeks'),
230        9676800 => $this->t('3 months 3 weeks'),
231        31536000 => $this->t('1 year'),
232        34214400 => $this->t('13 months'),
233      ],
234      '#description' =>
235      $this->t('Older visitors log entries (including referrer statistics) will be automatically discarded. (Requires a correctly configured <a href="@cron">cron maintenance task</a>.)',
236          ['@cron' => Url::fromRoute('system.status')->toString()]
237      ),
238    ];
239
240    $form['retention']['bot_retention_log'] = [
241      '#type' => 'select',
242      '#title' => $this->t('Discard bot logs older than'),
243      '#default_value'   => $config->get('bot_retention_log'),
244      '#options' => [
245        -1 => $this->t('Do not log'),
246        0 => $this->t('Never'),
247        3600 => $this->t('1 hour'),
248        10800 => $this->t('3 hours'),
249        21600 => $this->t('6 hours'),
250        32400 => $this->t('9 hours'),
251        43200 => $this->t('12 hours'),
252        86400 => $this->t('1 day'),
253        172800 => $this->t('2 days'),
254        259200 => $this->t('3 days'),
255        604800 => $this->t('1 week'),
256        1209600 => $this->t('2 weeks'),
257        4838400 => $this->t('1 month 3 weeks'),
258        9676800 => $this->t('3 months 3 weeks'),
259        31536000 => $this->t('1 year'),
260        34214400 => $this->t('13 months'),
261      ],
262      '#description' =>
263      $this->t('Control how long or if visits by bots are logged.'),
264    ];
265
266    $form['miscellaneous'] = [
267      '#type' => 'details',
268      '#title' => $this->t('Miscellaneous'),
269      '#group' => 'tracking_scope',
270    ];
271    $script_type = $config->get('script_type');
272    $form['miscellaneous']['script_type'] = [
273      '#type' => 'radios',
274      '#title' => $this->t('Script type'),
275      '#options' => [
276        'minified' => $this->t('Minified'),
277        'full' => $this->t('Full'),
278      ],
279      '#default_value' => $script_type == 'full' ? 'full' : 'minified',
280      '#description' => $this->t('Full script is for debugging purposes. Minified script is for production.'),
281    ];
282
283    $form['miscellaneous']['items_per_page'] = [
284      '#type' => 'select',
285      '#title' => 'Items per page',
286      '#default_value' => $config->get('items_per_page'),
287      '#options' => [
288        5 => 5,
289        10 => 10,
290        25 => 25,
291        50 => 50,
292        100 => 100,
293        200 => 200,
294        250 => 250,
295        500 => 500,
296        1000 => 1000,
297      ],
298      '#description' =>
299      $this->t('The default maximum number of items to display per page.'),
300    ];
301
302    return $form;
303  }
304
305  /**
306   * {@inheritdoc}
307   */
308  public function submitForm(array &$form, FormStateInterface $form_state) {
309    $config = $this->config(self::SETTINGS);
310    $values = $form_state->getValues();
311
312    $config
313      ->set('items_per_page', $values['items_per_page'])
314      ->set('flush_log_timer', $values['flush_log_timer'])
315      ->set('bot_retention_log', $values['bot_retention_log'])
316      ->set('track.userid', $values['visitors_trackuserid'])
317      ->set('counter.enabled', $values['counter_enabled'])
318      ->set('counter.entity_types', array_filter($values['entity_types'] ?? []))
319      ->set('disable_tracking', $values['visitors_disable_tracking'])
320      ->set('visibility.request_path_mode', $values['visitors_visibility_request_path_mode'])
321      ->set('visibility.request_path_pages', $values['visitors_visibility_request_path_pages'])
322      ->set('visibility.user_account_mode', $values['visitors_visibility_user_account_mode'])
323      ->set('visibility.user_role_mode', $values['visitors_visibility_user_role_mode'])
324      ->set('visibility.user_role_roles', array_filter($values['visitors_visibility_user_role_roles']))
325      ->set('visibility.exclude_user1', $values['visibility_exclude_user1'])
326      ->set('script_type', $values['script_type'] ?? 'minified')
327      ->save();
328
329    parent::submitForm($form, $form_state);
330  }
331
332  /**
333   * Returns a list of entity types.
334   */
335  protected function entityTypes() {
336    $entity_types_list = [];
337    $entity_definitions = $this->entityTypeManager->getDefinitions();
338    foreach ($entity_definitions as $entity_name => $entity_definition) {
339      if ($entity_definition instanceof ConfigEntityType) {
340        continue;
341      }
342      $entity_types_list[$entity_name] = (string) $entity_definition->getLabel();
343    }
344    asort($entity_types_list);
345
346    return $entity_types_list;
347  }
348
349  /**
350   * Returns a list of roles.
351   */
352  protected function roleOptions() {
353    $user_roles = $this->entityTypeManager->getStorage('user_role')->loadMultiple();
354    $options = [];
355    foreach ($user_roles as $role) {
356      $options[$role->id()] = $role->label();
357    }
358
359    return \array_map('\Drupal\Component\Utility\Html::escape', $options);
360  }
361
362}