Refactor filter in LinkDB
* search type now carried by LinkDB in order to factorize code between different search sources. * LinkDB->filter split in 3 method: filterSearch, filterHash, filterDay (we know what type of filter is needed). * filterHash now throw a LinkNotFoundException if it doesn't exist: internal implementation choice, still displays a 404. * Smallhash regex has been rewritten. * Unit tests update
This commit is contained in:
parent
ee88a4bcc2
commit
528a6f8a23
8 changed files with 158 additions and 106 deletions
|
@ -103,23 +103,7 @@ public function __construct($linkDB, $feedType, $serverInfo, $userInput, $isLogg
|
|||
public function buildData()
|
||||
{
|
||||
// Optionally filter the results:
|
||||
$searchtags = !empty($this->userInput['searchtags']) ? escape($this->userInput['searchtags']) : '';
|
||||
$searchterm = !empty($this->userInput['searchterm']) ? escape($this->userInput['searchterm']) : '';
|
||||
if (! empty($searchtags) && ! empty($searchterm)) {
|
||||
$linksToDisplay = $this->linkDB->filter(
|
||||
LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT,
|
||||
array($searchtags, $searchterm)
|
||||
);
|
||||
}
|
||||
elseif ($searchtags) {
|
||||
$linksToDisplay = $this->linkDB->filter(LinkFilter::$FILTER_TAG, $searchtags);
|
||||
}
|
||||
elseif ($searchterm) {
|
||||
$linksToDisplay = $this->linkDB->filter(LinkFilter::$FILTER_TEXT, $searchterm);
|
||||
}
|
||||
else {
|
||||
$linksToDisplay = $this->linkDB;
|
||||
}
|
||||
$linksToDisplay = $this->linkDB->filterSearch($this->userInput);
|
||||
|
||||
$nblinksToDisplay = $this->getNbLinks(count($linksToDisplay));
|
||||
|
||||
|
|
|
@ -341,17 +341,71 @@ public function getLinkFromUrl($url)
|
|||
}
|
||||
|
||||
/**
|
||||
* Filter links.
|
||||
* Returns the shaare corresponding to a smallHash.
|
||||
*
|
||||
* @param string $type Type of filter.
|
||||
* @param mixed $request Search request, string or array.
|
||||
* @param string $request QUERY_STRING server parameter.
|
||||
*
|
||||
* @return array $filtered array containing permalink data.
|
||||
*
|
||||
* @throws LinkNotFoundException if the smallhash is malformed or doesn't match any link.
|
||||
*/
|
||||
public function filterHash($request)
|
||||
{
|
||||
$request = substr($request, 0, 6);
|
||||
$linkFilter = new LinkFilter($this->_links);
|
||||
return $linkFilter->filter(LinkFilter::$FILTER_HASH, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of articles for a given day.
|
||||
*
|
||||
* @param string $request day to filter. Format: YYYYMMDD.
|
||||
*
|
||||
* @return array list of shaare found.
|
||||
*/
|
||||
public function filterDay($request) {
|
||||
$linkFilter = new LinkFilter($this->_links);
|
||||
return $linkFilter->filter(LinkFilter::$FILTER_DAY, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter links according to search parameters.
|
||||
*
|
||||
* @param array $filterRequest Search request content. Supported keys:
|
||||
* - searchtags: list of tags
|
||||
* - searchterm: term search
|
||||
* @param bool $casesensitive Optional: Perform case sensitive filter
|
||||
* @param bool $privateonly Optional: Returns private links only if true.
|
||||
*
|
||||
* @return array filtered links
|
||||
* @return array filtered links, all links if no suitable filter was provided.
|
||||
*/
|
||||
public function filter($type = '', $request = '', $casesensitive = false, $privateonly = false)
|
||||
public function filterSearch($filterRequest = array(), $casesensitive = false, $privateonly = false)
|
||||
{
|
||||
// Filter link database according to parameters.
|
||||
$searchtags = !empty($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : '';
|
||||
$searchterm = !empty($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : '';
|
||||
|
||||
// Search tags + fullsearch.
|
||||
if (empty($type) && ! empty($searchtags) && ! empty($searchterm)) {
|
||||
$type = LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT;
|
||||
$request = array($searchtags, $searchterm);
|
||||
}
|
||||
// Search by tags.
|
||||
elseif (! empty($searchtags)) {
|
||||
$type = LinkFilter::$FILTER_TAG;
|
||||
$request = $searchtags;
|
||||
}
|
||||
// Fulltext search.
|
||||
elseif (! empty($searchterm)) {
|
||||
$type = LinkFilter::$FILTER_TEXT;
|
||||
$request = $searchterm;
|
||||
}
|
||||
// Otherwise, display without filtering.
|
||||
else {
|
||||
$type = '';
|
||||
$request = '';
|
||||
}
|
||||
|
||||
$linkFilter = new LinkFilter($this->_links);
|
||||
return $linkFilter->filter($type, $request, $casesensitive, $privateonly);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public function __construct($links)
|
|||
* Filter links according to parameters.
|
||||
*
|
||||
* @param string $type Type of filter (eg. tags, permalink, etc.).
|
||||
* @param string $request Filter content.
|
||||
* @param mixed $request Filter content.
|
||||
* @param bool $casesensitive Optional: Perform case sensitive filter if true.
|
||||
* @param bool $privateonly Optional: Only returns private links if true.
|
||||
*
|
||||
|
@ -110,6 +110,8 @@ private function noFilter($privateonly = false)
|
|||
* @param string $smallHash permalink hash.
|
||||
*
|
||||
* @return array $filtered array containing permalink data.
|
||||
*
|
||||
* @throws LinkNotFoundException if the smallhash doesn't match any link.
|
||||
*/
|
||||
private function filterSmallHash($smallHash)
|
||||
{
|
||||
|
@ -121,6 +123,11 @@ private function filterSmallHash($smallHash)
|
|||
return $filtered;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($filtered)) {
|
||||
throw new LinkNotFoundException();
|
||||
}
|
||||
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
|
@ -318,3 +325,8 @@ public static function tagsStrToArray($tags, $casesensitive)
|
|||
return array_filter(explode(' ', trim($tagsOut)), 'strlen');
|
||||
}
|
||||
}
|
||||
|
||||
class LinkNotFoundException extends Exception
|
||||
{
|
||||
protected $message = 'The link you are trying to reach does not exist or has been deleted.';
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ public function updateMethodMergeDeprecatedConfigFile()
|
|||
*/
|
||||
public function updateMethodRenameDashTags()
|
||||
{
|
||||
$linklist = $this->linkDB->filter();
|
||||
$linklist = $this->linkDB->filterSearch();
|
||||
foreach ($linklist as $link) {
|
||||
$link['tags'] = preg_replace('/(^| )\-/', '$1', $link['tags']);
|
||||
$link['tags'] = implode(' ', array_unique(LinkFilter::tagsStrToArray($link['tags'], true)));
|
||||
|
|
95
index.php
95
index.php
|
@ -816,7 +816,7 @@ function showDaily($pageBuilder)
|
|||
}
|
||||
|
||||
try {
|
||||
$linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_DAY, $day);
|
||||
$linksToDisplay = $LINKSDB->filterDay($day);
|
||||
} catch (Exception $exc) {
|
||||
error_log($exc);
|
||||
$linksToDisplay = array();
|
||||
|
@ -962,24 +962,7 @@ function renderPage()
|
|||
if ($targetPage == Router::$PAGE_PICWALL)
|
||||
{
|
||||
// Optionally filter the results:
|
||||
$searchtags = !empty($_GET['searchtags']) ? escape($_GET['searchtags']) : '';
|
||||
$searchterm = !empty($_GET['searchterm']) ? escape($_GET['searchterm']) : '';
|
||||
if (! empty($searchtags) && ! empty($searchterm)) {
|
||||
$links = $LINKSDB->filter(
|
||||
LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT,
|
||||
array($searchtags, $searchterm)
|
||||
);
|
||||
}
|
||||
elseif ($searchtags) {
|
||||
$links = $LINKSDB->filter(LinkFilter::$FILTER_TAG, $searchtags);
|
||||
}
|
||||
elseif ($searchterm) {
|
||||
$links = $LINKSDB->filter(LinkFilter::$FILTER_TEXT, $searchterm);
|
||||
}
|
||||
else {
|
||||
$links = $LINKSDB;
|
||||
}
|
||||
|
||||
$links = $LINKSDB->filterSearch($_GET);
|
||||
$linksToDisplay = array();
|
||||
|
||||
// Get only links which have a thumbnail.
|
||||
|
@ -1071,7 +1054,7 @@ function renderPage()
|
|||
startsWith($query,'do='. $targetPage) && !isLoggedIn()
|
||||
);
|
||||
$cached = $cache->cachedVersion();
|
||||
if (!empty($cached)) {
|
||||
if (false && !empty($cached)) {
|
||||
echo $cached;
|
||||
exit;
|
||||
}
|
||||
|
@ -1354,7 +1337,7 @@ function renderPage()
|
|||
if (isset($_POST['deletetag']) && !empty($_POST['fromtag'])) {
|
||||
$needle = trim($_POST['fromtag']);
|
||||
// True for case-sensitive tag search.
|
||||
$linksToAlter = $LINKSDB->filter(LinkFilter::$FILTER_TAG, $needle, true);
|
||||
$linksToAlter = $LINKSDB->filterSearch(array('searchtags' => $needle), true);
|
||||
foreach($linksToAlter as $key=>$value)
|
||||
{
|
||||
$tags = explode(' ',trim($value['tags']));
|
||||
|
@ -1371,7 +1354,7 @@ function renderPage()
|
|||
if (isset($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag'])) {
|
||||
$needle = trim($_POST['fromtag']);
|
||||
// True for case-sensitive tag search.
|
||||
$linksToAlter = $LINKSDB->filter(LinkFilter::$FILTER_TAG, $needle, true);
|
||||
$linksToAlter = $LINKSDB->filterSearch(array('searchtags' => $needle), true);
|
||||
foreach($linksToAlter as $key=>$value)
|
||||
{
|
||||
$tags = explode(' ',trim($value['tags']));
|
||||
|
@ -1807,60 +1790,32 @@ function importFile()
|
|||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Template for the list of links (<div id="linklist">)
|
||||
// This function fills all the necessary fields in the $PAGE for the template 'linklist.html'
|
||||
/**
|
||||
* Template for the list of links (<div id="linklist">)
|
||||
* This function fills all the necessary fields in the $PAGE for the template 'linklist.html'
|
||||
*
|
||||
* @param pageBuilder $PAGE pageBuilder instance.
|
||||
* @param LinkDB $LINKSDB LinkDB instance.
|
||||
*/
|
||||
function buildLinkList($PAGE,$LINKSDB)
|
||||
{
|
||||
// Filter link database according to parameters.
|
||||
// Used in templates
|
||||
$searchtags = !empty($_GET['searchtags']) ? escape($_GET['searchtags']) : '';
|
||||
$searchterm = !empty($_GET['searchterm']) ? escape(trim($_GET['searchterm'])) : '';
|
||||
$privateonly = !empty($_SESSION['privateonly']) ? true : false;
|
||||
$searchterm = !empty($_GET['searchterm']) ? escape($_GET['searchterm']) : '';
|
||||
|
||||
// Search tags + fullsearch.
|
||||
if (! empty($searchtags) && ! empty($searchterm)) {
|
||||
$linksToDisplay = $LINKSDB->filter(
|
||||
LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT,
|
||||
array($searchtags, $searchterm),
|
||||
false,
|
||||
$privateonly
|
||||
);
|
||||
}
|
||||
// Search by tags.
|
||||
elseif (! empty($searchtags)) {
|
||||
$linksToDisplay = $LINKSDB->filter(
|
||||
LinkFilter::$FILTER_TAG,
|
||||
$searchtags,
|
||||
false,
|
||||
$privateonly
|
||||
);
|
||||
}
|
||||
// Fulltext search.
|
||||
elseif (! empty($searchterm)) {
|
||||
$linksToDisplay = $LINKSDB->filter(
|
||||
LinkFilter::$FILTER_TEXT,
|
||||
$searchterm,
|
||||
false,
|
||||
$privateonly
|
||||
);
|
||||
}
|
||||
// Detect smallHashes in URL.
|
||||
elseif (! empty($_SERVER['QUERY_STRING'])
|
||||
&& preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/', $_SERVER['QUERY_STRING'])
|
||||
) {
|
||||
$linksToDisplay = $LINKSDB->filter(
|
||||
LinkFilter::$FILTER_HASH,
|
||||
substr(trim($_SERVER["QUERY_STRING"], '/'), 0, 6)
|
||||
);
|
||||
|
||||
if (count($linksToDisplay) == 0) {
|
||||
$PAGE->render404('The link you are trying to reach does not exist or has been deleted.');
|
||||
// Smallhash filter
|
||||
if (! empty($_SERVER['QUERY_STRING'])
|
||||
&& preg_match('/^[a-zA-Z0-9-_@]{6}($|&|#)/', $_SERVER['QUERY_STRING'])) {
|
||||
try {
|
||||
$linksToDisplay = $LINKSDB->filterHash($_SERVER['QUERY_STRING']);
|
||||
} catch (LinkNotFoundException $e) {
|
||||
$PAGE->render404($e->getMessage());
|
||||
exit;
|
||||
}
|
||||
}
|
||||
// Otherwise, display without filtering.
|
||||
else {
|
||||
$linksToDisplay = $LINKSDB->filter('', '', false, $privateonly);
|
||||
} else {
|
||||
// Filter links according search parameters.
|
||||
$privateonly = !empty($_SESSION['privateonly']);
|
||||
$linksToDisplay = $LINKSDB->filterSearch($_GET, false, $privateonly);
|
||||
}
|
||||
|
||||
// ---- Handle paging.
|
||||
|
|
|
@ -17,8 +17,20 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
|
|||
{
|
||||
// datastore to test write operations
|
||||
protected static $testDatastore = 'sandbox/datastore.php';
|
||||
|
||||
/**
|
||||
* @var ReferenceLinkDB instance.
|
||||
*/
|
||||
protected static $refDB = null;
|
||||
|
||||
/**
|
||||
* @var LinkDB public LinkDB instance.
|
||||
*/
|
||||
protected static $publicLinkDB = null;
|
||||
|
||||
/**
|
||||
* @var LinkDB private LinkDB instance.
|
||||
*/
|
||||
protected static $privateLinkDB = null;
|
||||
|
||||
/**
|
||||
|
@ -335,9 +347,10 @@ public function testLinkRealUrlWithRedirector()
|
|||
public function testFilterString()
|
||||
{
|
||||
$tags = 'dev cartoon';
|
||||
$request = array('searchtags' => $tags);
|
||||
$this->assertEquals(
|
||||
2,
|
||||
count(self::$privateLinkDB->filter(LinkFilter::$FILTER_TAG, $tags, true, false))
|
||||
count(self::$privateLinkDB->filterSearch($request, true, false))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -347,9 +360,10 @@ public function testFilterString()
|
|||
public function testFilterArray()
|
||||
{
|
||||
$tags = array('dev', 'cartoon');
|
||||
$request = array('searchtags' => $tags);
|
||||
$this->assertEquals(
|
||||
2,
|
||||
count(self::$privateLinkDB->filter(LinkFilter::$FILTER_TAG, $tags, true, false))
|
||||
count(self::$privateLinkDB->filterSearch($request, true, false))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -360,14 +374,48 @@ public function testFilterArray()
|
|||
public function testHiddenTags()
|
||||
{
|
||||
$tags = '.hidden';
|
||||
$request = array('searchtags' => $tags);
|
||||
$this->assertEquals(
|
||||
1,
|
||||
count(self::$privateLinkDB->filter(LinkFilter::$FILTER_TAG, $tags, true, false))
|
||||
count(self::$privateLinkDB->filterSearch($request, true, false))
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
0,
|
||||
count(self::$publicLinkDB->filter(LinkFilter::$FILTER_TAG, $tags, true, false))
|
||||
count(self::$publicLinkDB->filterSearch($request, true, false))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test filterHash() with a valid smallhash.
|
||||
*/
|
||||
public function testFilterHashValid()
|
||||
{
|
||||
$request = smallHash('20150310_114651');
|
||||
$this->assertEquals(
|
||||
1,
|
||||
count(self::$publicLinkDB->filterHash($request))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test filterHash() with an invalid smallhash.
|
||||
*
|
||||
* @expectedException LinkNotFoundException
|
||||
*/
|
||||
public function testFilterHashInValid1()
|
||||
{
|
||||
$request = 'blabla';
|
||||
self::$publicLinkDB->filterHash($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test filterHash() with an empty smallhash.
|
||||
*
|
||||
* @expectedException LinkNotFoundException
|
||||
*/
|
||||
public function testFilterHashInValid()
|
||||
{
|
||||
self::$publicLinkDB->filterHash('');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -165,13 +165,12 @@ public function testFilterSmallHash()
|
|||
|
||||
/**
|
||||
* No link for this hash
|
||||
*
|
||||
* @expectedException LinkNotFoundException
|
||||
*/
|
||||
public function testFilterUnknownSmallHash()
|
||||
{
|
||||
$this->assertEquals(
|
||||
0,
|
||||
count(self::$linkFilter->filter(LinkFilter::$FILTER_HASH, 'Iblaah'))
|
||||
);
|
||||
self::$linkFilter->filter(LinkFilter::$FILTER_HASH, 'Iblaah');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -236,9 +236,9 @@ public function testRenameDashTags()
|
|||
$refDB = new ReferenceLinkDB();
|
||||
$refDB->write(self::$testDatastore);
|
||||
$linkDB = new LinkDB(self::$testDatastore, true, false);
|
||||
$this->assertEmpty($linkDB->filter(LinkFilter::$FILTER_TAG, 'exclude'));
|
||||
$this->assertEmpty($linkDB->filterSearch(array('searchtags' => 'exclude')));
|
||||
$updater = new Updater(array(), self::$configFields, $linkDB, true);
|
||||
$updater->updateMethodRenameDashTags();
|
||||
$this->assertNotEmpty($linkDB->filter(LinkFilter::$FILTER_TAG, 'exclude'));
|
||||
$this->assertNotEmpty($linkDB->filterSearch(array('searchtags' => 'exclude')));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue