diff options
Diffstat (limited to 'index.php')
-rw-r--r-- | index.php | 204 |
1 files changed, 109 insertions, 95 deletions
@@ -225,27 +225,6 @@ function setup_login_state($conf) | |||
225 | } | 225 | } |
226 | $userIsLoggedIn = setup_login_state($conf); | 226 | $userIsLoggedIn = setup_login_state($conf); |
227 | 227 | ||
228 | /** | ||
229 | * PubSubHubbub protocol support (if enabled) [UNTESTED] | ||
230 | * (Source: http://aldarone.fr/les-flux-rss-shaarli-et-pubsubhubbub/ ) | ||
231 | * | ||
232 | * @param ConfigManager $conf Configuration Manager instance. | ||
233 | */ | ||
234 | function pubsubhub($conf) | ||
235 | { | ||
236 | $pshUrl = $conf->get('config.PUBSUBHUB_URL'); | ||
237 | if (!empty($pshUrl)) | ||
238 | { | ||
239 | include_once './publisher.php'; | ||
240 | $p = new Publisher($pshUrl); | ||
241 | $topic_url = array ( | ||
242 | index_url($_SERVER).'?do=atom', | ||
243 | index_url($_SERVER).'?do=rss' | ||
244 | ); | ||
245 | $p->publish_update($topic_url); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | // ------------------------------------------------------------------------------------------ | 228 | // ------------------------------------------------------------------------------------------ |
250 | // Session management | 229 | // Session management |
251 | 230 | ||
@@ -308,6 +287,7 @@ function logout() { | |||
308 | unset($_SESSION['ip']); | 287 | unset($_SESSION['ip']); |
309 | unset($_SESSION['username']); | 288 | unset($_SESSION['username']); |
310 | unset($_SESSION['privateonly']); | 289 | unset($_SESSION['privateonly']); |
290 | unset($_SESSION['untaggedonly']); | ||
311 | } | 291 | } |
312 | setcookie('shaarli_staySignedIn', FALSE, 0, WEB_PATH); | 292 | setcookie('shaarli_staySignedIn', FALSE, 0, WEB_PATH); |
313 | } | 293 | } |
@@ -706,6 +686,7 @@ function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager) { | |||
706 | * @param ConfigManager $conf Configuration Manager instance. | 686 | * @param ConfigManager $conf Configuration Manager instance. |
707 | * @param PluginManager $pluginManager Plugin Manager instance, | 687 | * @param PluginManager $pluginManager Plugin Manager instance, |
708 | * @param LinkDB $LINKSDB | 688 | * @param LinkDB $LINKSDB |
689 | * @param History $history instance | ||
709 | */ | 690 | */ |
710 | function renderPage($conf, $pluginManager, $LINKSDB, $history) | 691 | function renderPage($conf, $pluginManager, $LINKSDB, $history) |
711 | { | 692 | { |
@@ -811,7 +792,9 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
811 | // -------- Tag cloud | 792 | // -------- Tag cloud |
812 | if ($targetPage == Router::$PAGE_TAGCLOUD) | 793 | if ($targetPage == Router::$PAGE_TAGCLOUD) |
813 | { | 794 | { |
814 | $tags= $LINKSDB->allTags(); | 795 | $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all'; |
796 | $filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : []; | ||
797 | $tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility); | ||
815 | 798 | ||
816 | // We sort tags alphabetically, then choose a font size according to count. | 799 | // We sort tags alphabetically, then choose a font size according to count. |
817 | // First, find max value. | 800 | // First, find max value. |
@@ -820,20 +803,13 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
820 | $maxcount = max($maxcount, $value); | 803 | $maxcount = max($maxcount, $value); |
821 | } | 804 | } |
822 | 805 | ||
823 | // Sort tags alphabetically: case insensitive, support locale if available. | 806 | alphabetical_sort($tags, true, true); |
824 | uksort($tags, function($a, $b) { | ||
825 | // Collator is part of PHP intl. | ||
826 | if (class_exists('Collator')) { | ||
827 | $c = new Collator(setlocale(LC_COLLATE, 0)); | ||
828 | if (!intl_is_failure(intl_get_error_code())) { | ||
829 | return $c->compare($a, $b); | ||
830 | } | ||
831 | } | ||
832 | return strcasecmp($a, $b); | ||
833 | }); | ||
834 | 807 | ||
835 | $tagList = array(); | 808 | $tagList = array(); |
836 | foreach($tags as $key => $value) { | 809 | foreach($tags as $key => $value) { |
810 | if (in_array($key, $filteringTags)) { | ||
811 | continue; | ||
812 | } | ||
837 | // Tag font size scaling: | 813 | // Tag font size scaling: |
838 | // default 15 and 30 logarithm bases affect scaling, | 814 | // default 15 and 30 logarithm bases affect scaling, |
839 | // 22 and 6 are arbitrary font sizes for max and min sizes. | 815 | // 22 and 6 are arbitrary font sizes for max and min sizes. |
@@ -845,6 +821,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
845 | } | 821 | } |
846 | 822 | ||
847 | $data = array( | 823 | $data = array( |
824 | 'search_tags' => implode(' ', $filteringTags), | ||
848 | 'tags' => $tagList, | 825 | 'tags' => $tagList, |
849 | ); | 826 | ); |
850 | $pluginManager->executeHooks('render_tagcloud', $data, array('loggedin' => isLoggedIn())); | 827 | $pluginManager->executeHooks('render_tagcloud', $data, array('loggedin' => isLoggedIn())); |
@@ -853,7 +830,37 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
853 | $PAGE->assign($key, $value); | 830 | $PAGE->assign($key, $value); |
854 | } | 831 | } |
855 | 832 | ||
856 | $PAGE->renderPage('tagcloud'); | 833 | $PAGE->renderPage('tag.cloud'); |
834 | exit; | ||
835 | } | ||
836 | |||
837 | // -------- Tag list | ||
838 | if ($targetPage == Router::$PAGE_TAGLIST) | ||
839 | { | ||
840 | $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all'; | ||
841 | $filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : []; | ||
842 | $tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility); | ||
843 | foreach ($filteringTags as $tag) { | ||
844 | if (array_key_exists($tag, $tags)) { | ||
845 | unset($tags[$tag]); | ||
846 | } | ||
847 | } | ||
848 | |||
849 | if (! empty($_GET['sort']) && $_GET['sort'] === 'alpha') { | ||
850 | alphabetical_sort($tags, false, true); | ||
851 | } | ||
852 | |||
853 | $data = [ | ||
854 | 'search_tags' => implode(' ', $filteringTags), | ||
855 | 'tags' => $tags, | ||
856 | ]; | ||
857 | $pluginManager->executeHooks('render_taglist', $data, ['loggedin' => isLoggedIn()]); | ||
858 | |||
859 | foreach ($data as $key => $value) { | ||
860 | $PAGE->assign($key, $value); | ||
861 | } | ||
862 | |||
863 | $PAGE->renderPage('tag.list'); | ||
857 | exit; | 864 | exit; |
858 | } | 865 | } |
859 | 866 | ||
@@ -1012,6 +1019,19 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1012 | exit; | 1019 | exit; |
1013 | } | 1020 | } |
1014 | 1021 | ||
1022 | // -------- User wants to see only untagged links (toggle) | ||
1023 | if (isset($_GET['untaggedonly'])) { | ||
1024 | $_SESSION['untaggedonly'] = empty($_SESSION['untaggedonly']); | ||
1025 | |||
1026 | if (! empty($_SERVER['HTTP_REFERER'])) { | ||
1027 | $location = generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('untaggedonly')); | ||
1028 | } else { | ||
1029 | $location = '?'; | ||
1030 | } | ||
1031 | header('Location: '. $location); | ||
1032 | exit; | ||
1033 | } | ||
1034 | |||
1015 | // -------- Handle other actions allowed for non-logged in users: | 1035 | // -------- Handle other actions allowed for non-logged in users: |
1016 | if (!isLoggedIn()) | 1036 | if (!isLoggedIn()) |
1017 | { | 1037 | { |
@@ -1170,6 +1190,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1170 | if ($targetPage == Router::$PAGE_CHANGETAG) | 1190 | if ($targetPage == Router::$PAGE_CHANGETAG) |
1171 | { | 1191 | { |
1172 | if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { | 1192 | if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { |
1193 | $PAGE->assign('fromtag', ! empty($_GET['fromtag']) ? escape($_GET['fromtag']) : ''); | ||
1173 | $PAGE->renderPage('changetag'); | 1194 | $PAGE->renderPage('changetag'); |
1174 | exit; | 1195 | exit; |
1175 | } | 1196 | } |
@@ -1178,41 +1199,18 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1178 | die('Wrong token.'); | 1199 | die('Wrong token.'); |
1179 | } | 1200 | } |
1180 | 1201 | ||
1181 | // Delete a tag: | 1202 | $alteredLinks = $LINKSDB->renameTag(escape($_POST['fromtag']), escape($_POST['totag'])); |
1182 | if (isset($_POST['deletetag']) && !empty($_POST['fromtag'])) { | 1203 | $LINKSDB->save($conf->get('resource.page_cache')); |
1183 | $needle = trim($_POST['fromtag']); | 1204 | foreach ($alteredLinks as $link) { |
1184 | // True for case-sensitive tag search. | 1205 | $history->updateLink($link); |
1185 | $linksToAlter = $LINKSDB->filterSearch(array('searchtags' => $needle), true); | ||
1186 | foreach($linksToAlter as $key=>$value) | ||
1187 | { | ||
1188 | $tags = explode(' ',trim($value['tags'])); | ||
1189 | unset($tags[array_search($needle,$tags)]); // Remove tag. | ||
1190 | $value['tags']=trim(implode(' ',$tags)); | ||
1191 | $LINKSDB[$key]=$value; | ||
1192 | $history->updateLink($LINKSDB[$key]); | ||
1193 | } | ||
1194 | $LINKSDB->save($conf->get('resource.page_cache')); | ||
1195 | echo '<script>alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?do=changetag\';</script>'; | ||
1196 | exit; | ||
1197 | } | ||
1198 | |||
1199 | // Rename a tag: | ||
1200 | if (isset($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag'])) { | ||
1201 | $needle = trim($_POST['fromtag']); | ||
1202 | // True for case-sensitive tag search. | ||
1203 | $linksToAlter = $LINKSDB->filterSearch(array('searchtags' => $needle), true); | ||
1204 | foreach($linksToAlter as $key=>$value) { | ||
1205 | $tags = preg_split('/\s+/', trim($value['tags'])); | ||
1206 | // Replace tags value. | ||
1207 | $tags[array_search($needle, $tags)] = trim($_POST['totag']); | ||
1208 | $value['tags'] = implode(' ', array_unique($tags)); | ||
1209 | $LINKSDB[$key] = $value; | ||
1210 | $history->updateLink($LINKSDB[$key]); | ||
1211 | } | ||
1212 | $LINKSDB->save($conf->get('resource.page_cache')); // Save to disk. | ||
1213 | echo '<script>alert("Tag was renamed in '.count($linksToAlter).' links.");document.location=\'?searchtags='.urlencode(escape($_POST['totag'])).'\';</script>'; | ||
1214 | exit; | ||
1215 | } | 1206 | } |
1207 | $delete = empty($_POST['totag']); | ||
1208 | $redirect = $delete ? 'do=changetag' : 'searchtags='. urlencode(escape($_POST['totag'])); | ||
1209 | $alert = $delete | ||
1210 | ? sprintf(t('The tag was removed from %d links.'), count($alteredLinks)) | ||
1211 | : sprintf(t('The tag was renamed in %d links.'), count($alteredLinks)); | ||
1212 | echo '<script>alert("'. $alert .'");document.location=\'?'. $redirect .'\';</script>'; | ||
1213 | exit; | ||
1216 | } | 1214 | } |
1217 | 1215 | ||
1218 | // -------- User wants to add a link without using the bookmarklet: Show form. | 1216 | // -------- User wants to add a link without using the bookmarklet: Show form. |
@@ -1258,13 +1256,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1258 | // Remove duplicates. | 1256 | // Remove duplicates. |
1259 | $tags = implode(' ', array_unique(explode(' ', $tags))); | 1257 | $tags = implode(' ', array_unique(explode(' ', $tags))); |
1260 | 1258 | ||
1261 | $url = trim($_POST['lf_url']); | 1259 | $url = whitelist_protocols(trim($_POST['lf_url']), $conf->get('security.allowed_protocols')); |
1262 | if (! startsWith($url, 'http:') && ! startsWith($url, 'https:') | ||
1263 | && ! startsWith($url, 'ftp:') && ! startsWith($url, 'magnet:') | ||
1264 | && ! startsWith($url, '?') && ! startsWith($url, 'javascript:') | ||
1265 | ) { | ||
1266 | $url = 'http://' . $url; | ||
1267 | } | ||
1268 | 1260 | ||
1269 | $link = array( | 1261 | $link = array( |
1270 | 'id' => $id, | 1262 | 'id' => $id, |
@@ -1329,18 +1321,21 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1329 | // -------- User clicked the "Delete" button when editing a link: Delete link from database. | 1321 | // -------- User clicked the "Delete" button when editing a link: Delete link from database. |
1330 | if ($targetPage == Router::$PAGE_DELETELINK) | 1322 | if ($targetPage == Router::$PAGE_DELETELINK) |
1331 | { | 1323 | { |
1332 | // We do not need to ask for confirmation: | ||
1333 | // - confirmation is handled by JavaScript | ||
1334 | // - we are protected from XSRF by the token. | ||
1335 | |||
1336 | if (! tokenOk($_GET['token'])) { | 1324 | if (! tokenOk($_GET['token'])) { |
1337 | die('Wrong token.'); | 1325 | die('Wrong token.'); |
1338 | } | 1326 | } |
1339 | 1327 | ||
1340 | $id = intval(escape($_GET['lf_linkdate'])); | 1328 | if (strpos($_GET['lf_linkdate'], ' ') !== false) { |
1341 | $link = $LINKSDB[$id]; | 1329 | $ids = array_values(array_filter(preg_split('/\s+/', escape($_GET['lf_linkdate'])))); |
1342 | $pluginManager->executeHooks('delete_link', $link); | 1330 | } else { |
1343 | unset($LINKSDB[$id]); | 1331 | $ids = [$_GET['lf_linkdate']]; |
1332 | } | ||
1333 | foreach ($ids as $id) { | ||
1334 | $id = (int) escape($id); | ||
1335 | $link = $LINKSDB[$id]; | ||
1336 | $pluginManager->executeHooks('delete_link', $link); | ||
1337 | unset($LINKSDB[$id]); | ||
1338 | } | ||
1344 | $LINKSDB->save($conf->get('resource.page_cache')); // save to disk | 1339 | $LINKSDB->save($conf->get('resource.page_cache')); // save to disk |
1345 | $history->deleteLink($link); | 1340 | $history->deleteLink($link); |
1346 | 1341 | ||
@@ -1372,7 +1367,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1372 | 'link' => $link, | 1367 | 'link' => $link, |
1373 | 'link_is_new' => false, | 1368 | 'link_is_new' => false, |
1374 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), | 1369 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), |
1375 | 'tags' => $LINKSDB->allTags(), | 1370 | 'tags' => $LINKSDB->linksCountPerTag(), |
1376 | ); | 1371 | ); |
1377 | $pluginManager->executeHooks('render_editlink', $data); | 1372 | $pluginManager->executeHooks('render_editlink', $data); |
1378 | 1373 | ||
@@ -1430,7 +1425,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1430 | 'url' => $url, | 1425 | 'url' => $url, |
1431 | 'description' => $description, | 1426 | 'description' => $description, |
1432 | 'tags' => $tags, | 1427 | 'tags' => $tags, |
1433 | 'private' => $private | 1428 | 'private' => $private, |
1434 | ); | 1429 | ); |
1435 | } else { | 1430 | } else { |
1436 | $link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT); | 1431 | $link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT); |
@@ -1441,7 +1436,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1441 | 'link_is_new' => $link_is_new, | 1436 | 'link_is_new' => $link_is_new, |
1442 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), | 1437 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), |
1443 | 'source' => (isset($_GET['source']) ? $_GET['source'] : ''), | 1438 | 'source' => (isset($_GET['source']) ? $_GET['source'] : ''), |
1444 | 'tags' => $LINKSDB->allTags(), | 1439 | 'tags' => $LINKSDB->linksCountPerTag(), |
1445 | 'default_private_links' => $conf->get('privacy.default_private_links', false), | 1440 | 'default_private_links' => $conf->get('privacy.default_private_links', false), |
1446 | ); | 1441 | ); |
1447 | $pluginManager->executeHooks('render_editlink', $data); | 1442 | $pluginManager->executeHooks('render_editlink', $data); |
@@ -1597,6 +1592,13 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1597 | exit; | 1592 | exit; |
1598 | } | 1593 | } |
1599 | 1594 | ||
1595 | // Get a fresh token | ||
1596 | if ($targetPage == Router::$GET_TOKEN) { | ||
1597 | header('Content-Type:text/plain'); | ||
1598 | echo getToken($conf); | ||
1599 | exit; | ||
1600 | } | ||
1601 | |||
1600 | // -------- Otherwise, simply display search form and links: | 1602 | // -------- Otherwise, simply display search form and links: |
1601 | showLinkList($PAGE, $LINKSDB, $conf, $pluginManager); | 1603 | showLinkList($PAGE, $LINKSDB, $conf, $pluginManager); |
1602 | exit; | 1604 | exit; |
@@ -1614,7 +1616,15 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1614 | function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | 1616 | function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) |
1615 | { | 1617 | { |
1616 | // Used in templates | 1618 | // Used in templates |
1617 | $searchtags = !empty($_GET['searchtags']) ? escape(normalize_spaces($_GET['searchtags'])) : ''; | 1619 | if (isset($_GET['searchtags'])) { |
1620 | if (! empty($_GET['searchtags'])) { | ||
1621 | $searchtags = escape(normalize_spaces($_GET['searchtags'])); | ||
1622 | } else { | ||
1623 | $searchtags = false; | ||
1624 | } | ||
1625 | } else { | ||
1626 | $searchtags = ''; | ||
1627 | } | ||
1618 | $searchterm = !empty($_GET['searchterm']) ? escape(normalize_spaces($_GET['searchterm'])) : ''; | 1628 | $searchterm = !empty($_GET['searchterm']) ? escape(normalize_spaces($_GET['searchterm'])) : ''; |
1619 | 1629 | ||
1620 | // Smallhash filter | 1630 | // Smallhash filter |
@@ -1629,7 +1639,11 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | |||
1629 | } else { | 1639 | } else { |
1630 | // Filter links according search parameters. | 1640 | // Filter links according search parameters. |
1631 | $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all'; | 1641 | $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all'; |
1632 | $linksToDisplay = $LINKSDB->filterSearch($_GET, false, $visibility); | 1642 | $request = [ |
1643 | 'searchtags' => $searchtags, | ||
1644 | 'searchterm' => $searchterm, | ||
1645 | ]; | ||
1646 | $linksToDisplay = $LINKSDB->filterSearch($request, false, $visibility, !empty($_SESSION['untaggedonly'])); | ||
1633 | } | 1647 | } |
1634 | 1648 | ||
1635 | // ---- Handle paging. | 1649 | // ---- Handle paging. |
@@ -1676,7 +1690,7 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | |||
1676 | } | 1690 | } |
1677 | 1691 | ||
1678 | // Compute paging navigation | 1692 | // Compute paging navigation |
1679 | $searchtagsUrl = empty($searchtags) ? '' : '&searchtags=' . urlencode($searchtags); | 1693 | $searchtagsUrl = $searchtags === '' ? '' : '&searchtags=' . urlencode($searchtags); |
1680 | $searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm); | 1694 | $searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm); |
1681 | $previous_page_url = ''; | 1695 | $previous_page_url = ''; |
1682 | if ($i != count($keys)) { | 1696 | if ($i != count($keys)) { |
@@ -2223,6 +2237,12 @@ if (!isset($_SESSION['LINKS_PER_PAGE'])) { | |||
2223 | $_SESSION['LINKS_PER_PAGE'] = $conf->get('general.links_per_page', 20); | 2237 | $_SESSION['LINKS_PER_PAGE'] = $conf->get('general.links_per_page', 20); |
2224 | } | 2238 | } |
2225 | 2239 | ||
2240 | try { | ||
2241 | $history = new History($conf->get('resource.history')); | ||
2242 | } catch(Exception $e) { | ||
2243 | die($e->getMessage()); | ||
2244 | } | ||
2245 | |||
2226 | $linkDb = new LinkDB( | 2246 | $linkDb = new LinkDB( |
2227 | $conf->get('resource.datastore'), | 2247 | $conf->get('resource.datastore'), |
2228 | isLoggedIn(), | 2248 | isLoggedIn(), |
@@ -2231,12 +2251,6 @@ $linkDb = new LinkDB( | |||
2231 | $conf->get('redirector.encode_url') | 2251 | $conf->get('redirector.encode_url') |
2232 | ); | 2252 | ); |
2233 | 2253 | ||
2234 | try { | ||
2235 | $history = new History($conf->get('resource.history')); | ||
2236 | } catch(Exception $e) { | ||
2237 | die($e->getMessage()); | ||
2238 | } | ||
2239 | |||
2240 | $container = new \Slim\Container(); | 2254 | $container = new \Slim\Container(); |
2241 | $container['conf'] = $conf; | 2255 | $container['conf'] = $conf; |
2242 | $container['plugins'] = $pluginManager; | 2256 | $container['plugins'] = $pluginManager; |