first commit
This commit is contained in:
109
Classes/Controller/BookmarksController.php
Normal file
109
Classes/Controller/BookmarksController.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the package buepro/bookmark_pages.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace WapplerSystems\BookmarkPages\Controller;
|
||||
|
||||
use WapplerSystems\BookmarkPages\Model\Bookmark;
|
||||
use WapplerSystems\BookmarkPages\Model\Bookmarks;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
/**
|
||||
* Plugin controller
|
||||
*/
|
||||
class BookmarksController extends ActionController
|
||||
{
|
||||
|
||||
/**
|
||||
* display bookmarks list
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$bookmark = Bookmark::createFromCurrent();
|
||||
$this->view->assignMultiple([
|
||||
'bookmark' => $bookmark->toArray()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the current page as bookmark and renders/returns updated list as html
|
||||
*
|
||||
* This is meant to be called by ajax (typoscript_rendering)
|
||||
*
|
||||
* @param array $localBookmarks
|
||||
*/
|
||||
public function bookmarkAction($localBookmarks = [])
|
||||
{
|
||||
// use the parameter directly and ignore chash because url is submitted by JS
|
||||
$url = GeneralUtility::_GP('url');
|
||||
$url = $url ? $url : null;
|
||||
|
||||
$bookmark = Bookmark::createFromCurrent($url);
|
||||
|
||||
$bookmarks = new Bookmarks();
|
||||
$bookmarks->merge($localBookmarks);
|
||||
$bookmarks->addBookmark($bookmark);
|
||||
$bookmarks->persist();
|
||||
|
||||
$this->updateAndSendList($bookmarks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a bookmark from list and renders/returns updated list as html
|
||||
*
|
||||
* This is meant to be called by ajax (typoscript_rendering)
|
||||
*
|
||||
* @param string $id
|
||||
* @param array $localBookmarks
|
||||
*/
|
||||
public function deleteAction($id = '', $localBookmarks = [])
|
||||
{
|
||||
$bookmarks = new Bookmarks();
|
||||
$bookmarks->merge($localBookmarks);
|
||||
if ($id) {
|
||||
$bookmarks->removeBookmark($id);
|
||||
$bookmarks->persist();
|
||||
}
|
||||
$this->updateAndSendList($bookmarks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to get bookmark list
|
||||
*
|
||||
* @param array $localBookmarks
|
||||
*/
|
||||
public function listEntriesAction($localBookmarks = [])
|
||||
{
|
||||
$bookmarks = new Bookmarks();
|
||||
$bookmarks->merge($localBookmarks);
|
||||
$this->updateAndSendList($bookmarks);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is for ajax requests
|
||||
*
|
||||
* @param Bookmarks $bookmarks
|
||||
*/
|
||||
public function updateAndSendList(Bookmarks $bookmarks)
|
||||
{
|
||||
// check if we bookmarked the current page
|
||||
$bookmark = Bookmark::createFromCurrent();
|
||||
$isBookmarked = $bookmarks->bookmarkExists($bookmark);
|
||||
|
||||
// build the ajax response data
|
||||
$response = [
|
||||
'isBookmarked' => $isBookmarked,
|
||||
'bookmarks' => $bookmarks->getBookmarksForLocalStorage()
|
||||
];
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($response);
|
||||
die();
|
||||
}
|
||||
}
|
237
Classes/Model/Bookmark.php
Normal file
237
Classes/Model/Bookmark.php
Normal file
@@ -0,0 +1,237 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the package buepro/bookmark_pages.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace WapplerSystems\BookmarkPages\Model;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Bookmark
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $title;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $url;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $pid;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $parameter;
|
||||
|
||||
/**
|
||||
* Bookmark constructor.
|
||||
* Initialize the bookmark with data
|
||||
*
|
||||
* @param string|array $url Full url or bookmark data array (same as array from toArray())
|
||||
* @param null $title
|
||||
* @param null $pid page id
|
||||
* @param null $parameter
|
||||
*/
|
||||
public function __construct($url, $title=null, $pid=null, $parameter=null)
|
||||
{
|
||||
if (is_array($url)) {
|
||||
$this->id = $url['id'];
|
||||
$this->title = $url['title'];
|
||||
$this->url = $url['url'];
|
||||
$this->pid = $url['pid'];
|
||||
$this->parameter = $url['parameter'];
|
||||
} else {
|
||||
$this->id = md5($pid . ':' . $parameter);
|
||||
$this->title = $title;
|
||||
$this->url = $url;
|
||||
$this->pid = $pid;
|
||||
$this->parameter = $parameter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create bookmark from the current TSFE page
|
||||
*
|
||||
* @param string url to bookmark, if null TYPO3_REQUEST_URL will be used - which is wrong when we're in ajax context, then we use HTTP_REFERER
|
||||
* @return Bookmark
|
||||
*/
|
||||
public static function createFromCurrent($url = null)
|
||||
{
|
||||
if ($url === null) {
|
||||
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
|
||||
//request is ajax
|
||||
$url = GeneralUtility::getIndpEnv('HTTP_REFERER');
|
||||
} else {
|
||||
$url = GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL');
|
||||
}
|
||||
}
|
||||
|
||||
$pid = self::getFrontend()->id;
|
||||
$title = self::getCurrentPageTitle();
|
||||
|
||||
/*
|
||||
|
||||
The idea was to store get parameters to make bookmark handling more flexible.
|
||||
Unfortunately that didn't worked out.
|
||||
|
||||
When we use ajax to trigger bookmarking the current page, we can pass the current url as parameter.
|
||||
But the url doesn't have the parameters in it when you use speaking urls (realurl, simulatestatic, ...).
|
||||
The problem is that there's no common api to decode urls and get the parameters.
|
||||
|
||||
One solution would be to make the parameters available to the ajax javascript during page rendering.
|
||||
|
||||
We skip all this and use a bit from the url for hashing and add the page id.
|
||||
|
||||
*/
|
||||
|
||||
$urlParts = parse_url($url);
|
||||
$parameter = $urlParts['path'] . '?' . $urlParts['query'] . '#' . $urlParts['fragment'];
|
||||
|
||||
return new self($url, $title, $pid, $parameter);
|
||||
|
||||
/*
|
||||
* So what is the idea of storing the pid and the get vars?
|
||||
*
|
||||
* This might makes sense if urls changed for the same page (realurl).
|
||||
* With this information the new working url can be restored.
|
||||
*
|
||||
* Not sure which way is better ...
|
||||
*/
|
||||
// $parameter = (array)GeneralUtility::_GET();
|
||||
// unset($parameter['id']);
|
||||
// // @todo remove cHash?
|
||||
// ksort($parameter);
|
||||
// $parameter = $parameter ? GeneralUtility::implodeArrayForUrl(false, $parameter) : '';
|
||||
//
|
||||
// return new self($url, $title, $pid, $parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
*/
|
||||
public function setId($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $title
|
||||
*/
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl()
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*/
|
||||
public function setUrl($url)
|
||||
{
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getPid()
|
||||
{
|
||||
return $this->pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $pid
|
||||
*/
|
||||
public function setPid($pid)
|
||||
{
|
||||
$this->pid = $pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getParameter()
|
||||
{
|
||||
return $this->parameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $parameter
|
||||
*/
|
||||
public function setParameter($parameter)
|
||||
{
|
||||
$this->parameter = $parameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bookmark data as array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'title' => $this->title,
|
||||
'url' => $this->url,
|
||||
'pid' => $this->pid,
|
||||
'parameter' => $this->parameter,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current page title
|
||||
* @return string
|
||||
*/
|
||||
protected static function getCurrentPageTitle()
|
||||
{
|
||||
return self::getFrontend()->altPageTitle? self::getFrontend()->altPageTitle : self::getFrontend()->page['title'];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
|
||||
*/
|
||||
protected static function getFrontend()
|
||||
{
|
||||
return $GLOBALS['TSFE'];
|
||||
}
|
||||
}
|
241
Classes/Model/Bookmarks.php
Normal file
241
Classes/Model/Bookmarks.php
Normal file
@@ -0,0 +1,241 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the package buepro/bookmark_pages.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace WapplerSystems\BookmarkPages\Model;
|
||||
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Provide access to a list of Bookmark
|
||||
*/
|
||||
class Bookmarks
|
||||
{
|
||||
|
||||
/**
|
||||
* column in db
|
||||
*/
|
||||
const BOOKMARKS_COLUMN = 'tx_bookmarks_pages';
|
||||
|
||||
/**
|
||||
* @var array|Bookmark[]
|
||||
*/
|
||||
protected $bookmarks = [];
|
||||
|
||||
/**
|
||||
* @var bool Flag if bookmarks has changed an need to be saved
|
||||
*/
|
||||
protected $changeFlag = false;
|
||||
|
||||
/**
|
||||
* Initialize bookmarks
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// is login user?
|
||||
if (is_array($this->getUser()->user) && $this->getUser()->user[$this->getUser()->userid_column]) {
|
||||
$bookmarks = $this->getUser()->user[self::BOOKMARKS_COLUMN];
|
||||
$bookmarks = (array)GeneralUtility::xml2array($bookmarks);
|
||||
foreach ($bookmarks as $bookmark) {
|
||||
if (isset($bookmark['id'])) {
|
||||
$this->bookmarks[$bookmark['id']] = new Bookmark($bookmark);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* persist bookmarks if needed
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->persist();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all Bookmarks
|
||||
*
|
||||
* @return array|Bookmark[]
|
||||
*/
|
||||
public function getBookmarks()
|
||||
{
|
||||
return (array)$this->bookmarks;
|
||||
}
|
||||
|
||||
/**
|
||||
* clear all bookmarks
|
||||
*/
|
||||
public function clearBookmarks()
|
||||
{
|
||||
$this->bookmarks = [];
|
||||
$this->changeFlag = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a bookmark
|
||||
*
|
||||
* @param Bookmark $bookmark
|
||||
*/
|
||||
public function addBookmark(Bookmark $bookmark)
|
||||
{
|
||||
$this->bookmarks[$bookmark->getId()] = $bookmark;
|
||||
$this->changeFlag = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Bookmark by given id
|
||||
*
|
||||
* @param string $id
|
||||
* @return Bookmark|mixed
|
||||
*/
|
||||
public function getBookmark($id)
|
||||
{
|
||||
return $this->bookmarks[$id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given bookmark is stored already
|
||||
*
|
||||
* @param Bookmark $bookmark
|
||||
* @return bool
|
||||
*/
|
||||
public function bookmarkExists(Bookmark $bookmark)
|
||||
{
|
||||
return isset($this->bookmarks[$bookmark->getId()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove bookmark by given id
|
||||
*
|
||||
* @param string $id
|
||||
*/
|
||||
public function removeBookmark($id)
|
||||
{
|
||||
unset($this->bookmarks[$id]);
|
||||
$this->changeFlag = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* persist bookmarks if needed
|
||||
*/
|
||||
public function persist()
|
||||
{
|
||||
if ($this->changeFlag && is_array($this->getUser()->user) && $this->getUser()->user[$this->getUser()->userid_column]) {
|
||||
$bookmarks = [];
|
||||
foreach ($this->bookmarks as $bookmark) {
|
||||
$bookmarks[] = $bookmark->toArray();
|
||||
}
|
||||
/*
|
||||
* Why xml?
|
||||
*
|
||||
* Why not! You can even process it in the db if you like
|
||||
* (And dooon't tell me json would be a good idea, or serialized php ... haaahaaaaaa)
|
||||
*/
|
||||
$bookMarksXml = GeneralUtility::array2xml($bookmarks);
|
||||
|
||||
/** @var QueryBuilder $queryBuilder */
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable($this->getUser()->user_table);
|
||||
$queryBuilder
|
||||
->update($this->getUser()->user_table)
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
$this->getUser()->userid_column,
|
||||
$queryBuilder->createNamedParameter((int)$this->getUser()->user[$this->getUser()->userid_column], \PDO::PARAM_INT)
|
||||
)
|
||||
)
|
||||
->set(self::BOOKMARKS_COLUMN, $bookMarksXml)
|
||||
->execute();
|
||||
|
||||
$this->changeFlag = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get global frontend user
|
||||
* @return \TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication
|
||||
*/
|
||||
protected function getUser()
|
||||
{
|
||||
return $GLOBALS['TSFE']->fe_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getAccessibleBookmarks()
|
||||
{
|
||||
$bookmarks = $this->getBookmarks();
|
||||
if (!$bookmarks) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Create an array association the page uid with the bookmark id (uid => id)
|
||||
$pageMap = array_flip(array_map(static function ($bookmark) {
|
||||
return (int) $bookmark->getPid();
|
||||
}, $bookmarks));
|
||||
|
||||
// Get accessible pages
|
||||
/** @var QueryBuilder $queryBuilder */
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
|
||||
$queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
|
||||
$pages = $queryBuilder
|
||||
->select('uid')
|
||||
->from('pages')
|
||||
->where($queryBuilder->expr()->in('uid', array_keys($pageMap)))
|
||||
->execute()
|
||||
->fetchAll();
|
||||
|
||||
// Collect accessible bookmarks
|
||||
$accessibleBookmarks = [];
|
||||
foreach ($pages as $page) {
|
||||
if (isset($pageMap[$page['uid']])) {
|
||||
$accessibleBookmarks[$pageMap[$page['uid']]] = $bookmarks[$pageMap[$page['uid']]];
|
||||
}
|
||||
}
|
||||
|
||||
// Order the bookmarks (same sequence as at the beginning)
|
||||
return array_intersect_key($bookmarks, $accessibleBookmarks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge bookmarks into the current ones.
|
||||
*
|
||||
* @param $bookmarks
|
||||
* @return array|Bookmark[]
|
||||
*/
|
||||
public function merge($bookmarks)
|
||||
{
|
||||
$bookmarksChanged = false;
|
||||
foreach ($bookmarks as $id => $bookmark) {
|
||||
if (!isset($this->bookmarks[$id])) {
|
||||
$bookmarksChanged = true;
|
||||
$this->bookmarks[$id] = new Bookmark($bookmark);
|
||||
}
|
||||
}
|
||||
if ($bookmarksChanged) {
|
||||
$this->persist();
|
||||
}
|
||||
return $this->getBookmarks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bookmarks for local storage in browser
|
||||
*/
|
||||
public function getBookmarksForLocalStorage(): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($this->getAccessibleBookmarks() as $bookmark) {
|
||||
$result[$bookmark->getId()] = $bookmark->toArray();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user