f43252e45201cfe781c1994d807882ac53722cb4
[yaffs-website] / web / modules / contrib / linkchecker / linkchecker.pages.inc
1 <?php
2
3 /**
4  * @file
5  * User page callbacks for the linkchecker module.
6  */
7
8 use Drupal\Component\Utility\Html;
9
10 /**
11  * Menu callback for general reporting.
12  *
13  * @return string
14  *   Themed report page.
15  */
16 function linkchecker_admin_report_page() {
17
18   $ignore_response_codes = preg_split('/(\r\n?|\n)/', \Drupal::config('linkchecker.settings')->get('linkchecker_ignore_response_codes'));
19
20   // Search for broken links in nodes and comments and blocks of all users.
21   // @todo Try to make UNION'ed subselect resultset smaller.
22   $subquery4 = db_select('linkchecker_node', 'ln')
23     ->distinct()
24     ->fields('ln', ['lid']);
25
26   $subquery3 = db_select('linkchecker_comment', 'lc')
27     ->distinct()
28     ->fields('lc', ['lid']);
29
30   $subquery2 = db_select('linkchecker_block_custom', 'lb')
31     ->distinct()
32     ->fields('lb', ['lid']);
33
34   // UNION all linkchecker type tables.
35   $subquery1 = db_select($subquery2->union($subquery3)->union($subquery4), 'q1')->fields('q1', ['lid']);
36
37   // Build pager query.
38   $query = db_select('linkchecker_link', 'll')->extend('PagerDefault')->extend('TableSort');
39   $query->innerJoin($subquery1, 'q2', 'q2.lid = ll.lid');
40   $query->fields('ll');
41   $query->condition('ll.last_checked', 0, '<>');
42   $query->condition('ll.status', 1);
43   $query->condition('ll.code', $ignore_response_codes, 'NOT IN');
44
45   return _linkchecker_report_page($query);
46 }
47
48 /**
49  * Menu callback for author specific reporting.
50  *
51  * @param object $account
52  *   The user account.
53  *
54  * @return string
55  *   Themed report page.
56  */
57 function linkchecker_user_report_page($account) {
58   drupal_set_title($account->name);
59
60   $ignore_response_codes = preg_split('/(\r\n?|\n)/', \Drupal::config('linkchecker.settings')->get('linkchecker_ignore_response_codes'));
61
62   // Build query for broken links in nodes of the current user.
63   $subquery2 = db_select('node', 'n');
64   $subquery2->innerJoin('node_revision', 'r', 'r.vid = n.vid');
65   $subquery2->innerJoin('linkchecker_node', 'ln', 'ln.nid = n.nid');
66   $subquery2->innerJoin('linkchecker_link', 'll', 'll.lid = ln.lid');
67   $subquery2->condition('ll.last_checked', 0, '<>');
68   $subquery2->condition('ll.status', 1);
69   $subquery2->condition('ll.code', $ignore_response_codes, 'NOT IN');
70   $subquery2->condition(db_or()
71     ->condition('n.uid', $account->uid)
72     ->condition('r.uid', $account->uid)
73   );
74   $subquery2->distinct();
75   $subquery2->fields('ll', ['lid']);
76
77   $comment_types = linkchecker_scan_comment_types();
78   if (!empty($comment_types)) {
79     // Build query for broken links in nodes and comments of the current user.
80     $subquery3 = db_select('comment', 'c');
81     $subquery3->innerJoin('linkchecker_comment', 'lc', 'lc.cid = c.cid');
82     $subquery3->innerJoin('linkchecker_link', 'll', 'll.lid = lc.lid');
83     $subquery3->condition('ll.last_checked', 0, '<>');
84     $subquery3->condition('ll.status', 1);
85     $subquery3->condition('ll.code', $ignore_response_codes, 'NOT IN');
86     $subquery3->condition('c.uid', $account->uid);
87     $subquery3->distinct();
88     $subquery3->fields('ll', ['lid']);
89
90     // UNION the linkchecker_node and linkchecker_comment tables.
91     $subquery1 = db_select($subquery2->union($subquery3), 'q1')->fields('q1', ['lid']);
92   }
93   else {
94     // Build query for broken links in nodes of the current user.
95     $subquery1 = db_select($subquery2, 'q1')->fields('q1', ['lid']);
96   }
97
98   // Build pager query.
99   $query = db_select('linkchecker_link', 'll')->extend('PagerDefault')->extend('TableSort');
100   $query->innerJoin($subquery1, 'q2', 'q2.lid = ll.lid');
101   $query->fields('ll');
102   $query->condition('ll.last_checked', 0, '<>');
103   $query->condition('ll.status', 1);
104   $query->condition('ll.code', $ignore_response_codes, 'NOT IN');
105
106   return _linkchecker_report_page($query, $account);
107 }
108
109 /**
110  * Builds the HTML report page table with pager.
111  *
112  * @param SelectQueryInterface $query
113  *   The pager query for the report page. Can be per user report or global.
114  * @param object|null $account
115  *   The user account object.
116  *
117  * @return string
118  *   Themed report page.
119  */
120 function _linkchecker_report_page($query, $account = NULL) {
121
122   $links_unchecked = db_query('SELECT COUNT(1) FROM {linkchecker_link} WHERE last_checked = :last_checked AND status = :status', [':last_checked' => 0, ':status' => 1])->fetchField();
123   if ($links_unchecked > 0) {
124     $links_all = db_query('SELECT COUNT(1) FROM {linkchecker_link} WHERE status = :status', [':status' => 1])->fetchField();
125     drupal_set_message(\Drupal::translation()->formatPlural($links_unchecked,
126       'There is 1 unchecked link of about @links_all links in the database. Please be patient until all links have been checked via cron.',
127       'There are @count unchecked links of about @links_all links in the database. Please be patient until all links have been checked via cron.',
128       ['@links_all' => $links_all]), 'warning');
129   }
130
131   $header = [
132     ['data' => t('URL'), 'field' => 'url', 'sort' => 'desc'],
133     ['data' => t('Response'), 'field' => 'code', 'sort' => 'desc'],
134     ['data' => t('Error'), 'field' => 'error'],
135     ['data' => t('Operations')],
136   ];
137
138   $result = $query
139     ->limit(50)
140     ->orderByHeader($header)
141     ->execute();
142
143   // Evaluate permission once for performance reasons.
144   $access_edit_link_settings = \Drupal::currentUser()->hasPermission('edit link settings');
145   $access_administer_blocks = \Drupal::currentUser()->hasPermission('administer blocks');
146   $access_administer_redirects = \Drupal::currentUser()->hasPermission('administer redirects');
147
148   $rows = [];
149   foreach ($result as $link) {
150     // Get the node, block and comment IDs that refer to this broken link and
151     // that the current user has access to.
152     $nids = _linkchecker_link_node_ids($link, $account);
153     $cids = _linkchecker_link_comment_ids($link, $account);
154     $bids = _linkchecker_link_block_ids($link);
155
156     // If the user does not have access to see this link anywhere, do not
157     // display it, for reasons explained in _linkchecker_link_access(). We
158     // still need to fill the table row, though, so as not to throw off the
159     // number of items in the pager.
160     if (empty($nids) && empty($cids) && empty($bids)) {
161       $rows[] = [['data' => t('Permission restrictions deny you access to this broken link.'), 'colspan' => count($header)]];
162       continue;
163     }
164
165     $links = [];
166
167     // Show links to link settings.
168     if ($access_edit_link_settings) {
169       $links[] = l(t('Edit link settings'), 'linkchecker/' . $link->lid . '/edit', ['query' => drupal_get_destination()]);
170     }
171
172     // Show link to nodes having this broken link.
173     foreach ($nids as $nid) {
174       $links[] = l(t('Edit node @node', ['@node' => $nid]), 'node/' . $nid . '/edit', ['query' => drupal_get_destination()]);
175     }
176
177     // Show link to comments having this broken link.
178     $comment_types = linkchecker_scan_comment_types();
179     if (\Drupal::moduleHandler()->moduleExists('comment') && !empty($comment_types)) {
180       foreach ($cids as $cid) {
181         $links[] = l(t('Edit comment @comment', ['@comment' => $cid]), 'comment/' . $cid . '/edit', ['query' => drupal_get_destination()]);
182       }
183     }
184
185     // Show link to blocks having this broken link.
186     if ($access_administer_blocks) {
187       foreach ($bids as $bid) {
188         $links[] = l(t('Edit block @block', ['@block' => $bid]), 'admin/structure/block/manage/block/' . $bid . '/configure', ['query' => drupal_get_destination()]);
189       }
190     }
191
192     // Show link to redirect this broken internal link.
193     if (\Drupal::moduleHandler()->moduleExists('redirect') && $access_administer_redirects && _linkchecker_is_internal_url($link)) {
194       $links[] = l(t('Create redirection'), 'admin/config/search/redirect/add', ['query' => ['source' => $link->internal, drupal_get_destination()]]);
195     }
196
197     // Create table data for output.
198     $rows[] = [
199       'data' => [
200         l(_filter_url_trim($link->url, 40), $link->url),
201         $link->code,
202         Html::escape($link->error),
203         theme('item_list', ['items' => $links]),
204       ],
205     ];
206   }
207
208   $build['linkchecker_table'] = [
209     '#theme' => 'table',
210     '#header' => $header,
211     '#rows' => $rows,
212     '#empty' => t('No broken links have been found.'),
213   ];
214   $build['linkchecker_pager'] = ['#theme' => 'pager'];
215
216   return $build;
217 }
218
219 /**
220  * Check if the link is an internal URL or not.
221  *
222  * @param object $link
223  *   Link object.
224  *
225  * @return bool
226  *   TRUE if link is internal, otherwise FALSE.
227  */
228 function _linkchecker_is_internal_url(&$link) {
229   global $base_url;
230
231   if (strpos($link->url, $base_url) === 0) {
232     $link->internal = trim(substr($link->url, strlen($base_url)), " \t\r\n\0\\/");
233     return TRUE;
234   }
235 }