Fixed login remembering
This commit is contained in:
parent
c33817e4ab
commit
7b0d907acc
22 changed files with 357 additions and 204 deletions
9
TODO
9
TODO
|
@ -121,9 +121,6 @@ refactors:
|
||||||
- (idea) keep denormalized data in separate tables, i.e. tag usages in
|
- (idea) keep denormalized data in separate tables, i.e. tag usages in
|
||||||
tag_meta or post favorite count in post_meta, so that it's obvious what
|
tag_meta or post favorite count in post_meta, so that it's obvious what
|
||||||
can be recalculated on demand and what is real data
|
can be recalculated on demand and what is real data
|
||||||
- change AbstractSearchService to AbstractSearchParser
|
|
||||||
- embed AbstractSearchService into Dao (it sucks to include XSearchService
|
|
||||||
together with Dao)
|
|
||||||
- simplify template loading in presenters - right now template loading
|
- simplify template loading in presenters - right now template loading
|
||||||
requires _, util and promise:
|
requires _, util and promise:
|
||||||
promise.wait(util.loadTemplate('blah'))
|
promise.wait(util.loadTemplate('blah'))
|
||||||
|
@ -131,6 +128,12 @@ refactors:
|
||||||
template = _.template(html); });
|
template = _.template(html); });
|
||||||
- change content spinner to nprogress:
|
- change content spinner to nprogress:
|
||||||
http://ricostacruz.com/nprogress/
|
http://ricostacruz.com/nprogress/
|
||||||
|
- add fetchUsers to PostSearchFilter: when AbstractDao fetches entities
|
||||||
|
with query decorated by PostDao::decorateQueryFromFilter, call
|
||||||
|
PostDao::decorateEntitiesWithFilter that will optimally load users and
|
||||||
|
inject them using posts' lazy loaders.
|
||||||
|
- make view proxies less greedy, e.g. favs should be fetched only in post
|
||||||
|
view, not for each of 40 posts in post list. (same goes to other things)
|
||||||
|
|
||||||
miscellaneous:
|
miscellaneous:
|
||||||
- fix mouse trap hotkeys when leaving page
|
- fix mouse trap hotkeys when leaving page
|
||||||
|
|
|
@ -45,7 +45,7 @@ App.Presenters.LoginPresenter = function(
|
||||||
|
|
||||||
var userNameOrEmail = $el.find('[name=user]').val();
|
var userNameOrEmail = $el.find('[name=user]').val();
|
||||||
var password = $el.find('[name=password]').val();
|
var password = $el.find('[name=password]').val();
|
||||||
var remember = $el.find('[name=remember]').val();
|
var remember = $el.find('[name=remember]').is(':checked');
|
||||||
|
|
||||||
if (userNameOrEmail.length === 0) {
|
if (userNameOrEmail.length === 0) {
|
||||||
messagePresenter.showError($messages, 'User name cannot be empty.');
|
messagePresenter.showError($messages, 'User name cannot be empty.');
|
||||||
|
|
|
@ -38,11 +38,11 @@ final class PostController extends AbstractController
|
||||||
{
|
{
|
||||||
$formData = new \Szurubooru\FormData\SearchFormData($this->inputReader);
|
$formData = new \Szurubooru\FormData\SearchFormData($this->inputReader);
|
||||||
$searchResult = $this->postService->getFiltered($formData);
|
$searchResult = $this->postService->getFiltered($formData);
|
||||||
$entities = $this->postViewProxy->fromArray($searchResult->entities);
|
$entities = $this->postViewProxy->fromArray($searchResult->getEntities());
|
||||||
return [
|
return [
|
||||||
'data' => $entities,
|
'data' => $entities,
|
||||||
'pageSize' => $searchResult->filter->pageSize,
|
'pageSize' => $searchResult->getPageSize(),
|
||||||
'totalRecords' => $searchResult->totalRecords];
|
'totalRecords' => $searchResult->getTotalRecords()];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createPost()
|
public function createPost()
|
||||||
|
|
|
@ -48,11 +48,11 @@ final class UserController extends AbstractController
|
||||||
|
|
||||||
$formData = new \Szurubooru\FormData\SearchFormData($this->inputReader);
|
$formData = new \Szurubooru\FormData\SearchFormData($this->inputReader);
|
||||||
$searchResult = $this->userService->getFiltered($formData);
|
$searchResult = $this->userService->getFiltered($formData);
|
||||||
$entities = $this->userViewProxy->fromArray($searchResult->entities);
|
$entities = $this->userViewProxy->fromArray($searchResult->getEntities());
|
||||||
return [
|
return [
|
||||||
'data' => $entities,
|
'data' => $entities,
|
||||||
'pageSize' => $searchResult->filter->pageSize,
|
'pageSize' => $searchResult->getPageSize(),
|
||||||
'totalRecords' => $searchResult->totalRecords];
|
'totalRecords' => $searchResult->getTotalRecords()];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createUser()
|
public function createUser()
|
||||||
|
|
|
@ -54,14 +54,9 @@ abstract class AbstractDao implements ICrudDao
|
||||||
|
|
||||||
public function findAll()
|
public function findAll()
|
||||||
{
|
{
|
||||||
$entities = [];
|
|
||||||
$query = $this->fpdo->from($this->tableName);
|
$query = $this->fpdo->from($this->tableName);
|
||||||
foreach ($query as $arrayEntity)
|
$arrayEntities = iterator_to_array($query);
|
||||||
{
|
return $this->arrayToEntities($arrayEntities);
|
||||||
$entity = $this->entityConverter->toEntity($arrayEntity);
|
|
||||||
$entities[$entity->getId()] = $entity;
|
|
||||||
}
|
|
||||||
return $entities;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findById($entityId)
|
public function findById($entityId)
|
||||||
|
@ -74,6 +69,46 @@ abstract class AbstractDao implements ICrudDao
|
||||||
return $this->findBy($this->getIdColumn(), $entityIds);
|
return $this->findBy($this->getIdColumn(), $entityIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findFiltered(\Szurubooru\SearchServices\AbstractSearchFilter $searchFilter)
|
||||||
|
{
|
||||||
|
$orderByString = $this->compileOrderBy($searchFilter->order);
|
||||||
|
|
||||||
|
$query = $this->fpdo
|
||||||
|
->from($this->tableName)
|
||||||
|
->orderBy($orderByString);
|
||||||
|
|
||||||
|
$this->decorateQueryFromFilter($query, $searchFilter);
|
||||||
|
|
||||||
|
return $this->arrayToEntities(iterator_to_array($query));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findFilteredAndPaged(\Szurubooru\SearchServices\AbstractSearchFilter $searchFilter, $pageNumber, $pageSize)
|
||||||
|
{
|
||||||
|
$orderByString = $this->compileOrderBy($searchFilter->order);
|
||||||
|
|
||||||
|
$query = $this->fpdo
|
||||||
|
->from($this->tableName)
|
||||||
|
->orderBy($orderByString)
|
||||||
|
->limit($pageSize)
|
||||||
|
->offset($pageSize * ($pageNumber - 1));
|
||||||
|
|
||||||
|
$this->decorateQueryFromFilter($query, $searchFilter);
|
||||||
|
|
||||||
|
$entities = $this->arrayToEntities(iterator_to_array($query));
|
||||||
|
$query = $this->fpdo
|
||||||
|
->from($this->tableName)
|
||||||
|
->select('COUNT(1) AS c');
|
||||||
|
$totalRecords = intval(iterator_to_array($query)[0]['c']);
|
||||||
|
|
||||||
|
$pagedSearchResult = new \Szurubooru\SearchServices\PagedSearchResult();
|
||||||
|
$pagedSearchResult->setSearchFilter($searchFilter);
|
||||||
|
$pagedSearchResult->setEntities($entities);
|
||||||
|
$pagedSearchResult->setTotalRecords($totalRecords);
|
||||||
|
$pagedSearchResult->setPageNumber($pageNumber);
|
||||||
|
$pagedSearchResult->setPageSize($pageSize);
|
||||||
|
return $pagedSearchResult;
|
||||||
|
}
|
||||||
|
|
||||||
public function deleteAll()
|
public function deleteAll()
|
||||||
{
|
{
|
||||||
foreach ($this->findAll() as $entity)
|
foreach ($this->findAll() as $entity)
|
||||||
|
@ -153,4 +188,27 @@ abstract class AbstractDao implements ICrudDao
|
||||||
protected function beforeDelete(\Szurubooru\Entities\Entity $entity)
|
protected function beforeDelete(\Szurubooru\Entities\Entity $entity)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function decorateQueryFromFilter($query, \Szurubooru\SearchServices\AbstractSearchFilter $filter)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function arrayToEntities(array $arrayEntities)
|
||||||
|
{
|
||||||
|
$entities = [];
|
||||||
|
foreach ($arrayEntities as $arrayEntity)
|
||||||
|
{
|
||||||
|
$entity = $this->entityConverter->toEntity($arrayEntity);
|
||||||
|
$entities[$entity->getId()] = $entity;
|
||||||
|
}
|
||||||
|
return $entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function compileOrderBy($order)
|
||||||
|
{
|
||||||
|
$orderByString = '';
|
||||||
|
foreach ($order as $orderColumn => $orderDir)
|
||||||
|
$orderByString .= $orderColumn . ' ' . ($orderDir === \Szurubooru\SearchServices\AbstractSearchFilter::ORDER_DESC ? 'DESC' : 'ASC') . ', ';
|
||||||
|
return substr($orderByString, 0, -2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,4 +14,3 @@ class SearchResult
|
||||||
$this->totalRecords = $totalRecords;
|
$this->totalRecords = $totalRecords;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,134 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace Szurubooru\Dao\Services;
|
|
||||||
|
|
||||||
abstract class AbstractSearchService
|
|
||||||
{
|
|
||||||
const ORDER_DESC = -1;
|
|
||||||
const ORDER_ASC = 1;
|
|
||||||
|
|
||||||
private $tableName;
|
|
||||||
private $entityConverter;
|
|
||||||
private $fpdo;
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
\Szurubooru\DatabaseConnection $databaseConnection,
|
|
||||||
\Szurubooru\Dao\AbstractDao $dao)
|
|
||||||
{
|
|
||||||
$this->tableName = $dao->getTableName();
|
|
||||||
$this->entityConverter = $dao->getEntityConverter();
|
|
||||||
$this->fpdo = new \FluentPDO($databaseConnection->getPDO());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFiltered(
|
|
||||||
\Szurubooru\Dao\SearchFilter $searchFilter)
|
|
||||||
{
|
|
||||||
list ($basicTokens, $complexTokens) = $this->tokenize($searchFilter->query);
|
|
||||||
|
|
||||||
$filter = [];
|
|
||||||
if ($basicTokens)
|
|
||||||
$this->decorateFilterWithBasicTokens($filter, $basicTokens);
|
|
||||||
if ($complexTokens)
|
|
||||||
$this->decorateFilterWithComplexTokens($filter, $complexTokens);
|
|
||||||
|
|
||||||
$order = $this->getOrder($searchFilter->order);
|
|
||||||
$pageSize = min(100, max(1, $searchFilter->pageSize));
|
|
||||||
$pageNumber = max(1, $searchFilter->pageNumber) - 1;
|
|
||||||
|
|
||||||
//todo: clean up
|
|
||||||
$orderByString = '';
|
|
||||||
foreach ($order as $orderColumn => $orderDir)
|
|
||||||
{
|
|
||||||
$orderByString .= $orderColumn . ' ' . ($orderDir === self::ORDER_DESC ? 'DESC' : 'ASC') . ', ';
|
|
||||||
}
|
|
||||||
$orderByString = substr($orderByString, 0, -2);
|
|
||||||
|
|
||||||
$query = $this->fpdo
|
|
||||||
->from($this->tableName)
|
|
||||||
->orderBy($orderByString)
|
|
||||||
->limit($pageSize)
|
|
||||||
->offset($pageSize * $pageNumber);
|
|
||||||
|
|
||||||
$entities = [];
|
|
||||||
foreach ($query as $arrayEntity)
|
|
||||||
{
|
|
||||||
$entity = $this->entityConverter->toEntity($arrayEntity);
|
|
||||||
$entities[] = $entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = $this->fpdo
|
|
||||||
->from($this->tableName)
|
|
||||||
->select('COUNT(1) AS c');
|
|
||||||
$totalRecords = intval(iterator_to_array($query)[0]['c']);
|
|
||||||
return new \Szurubooru\Dao\SearchResult($searchFilter, $entities, $totalRecords);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function decorateFilterWithBasicTokens($filter, $basicTokens)
|
|
||||||
{
|
|
||||||
throw new \BadMethodCallException('Not supported');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function decorateFilterWithComplexTokens($filter, $complexTokens)
|
|
||||||
{
|
|
||||||
throw new \BadMethodCallException('Not supported');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getOrderColumn($token)
|
|
||||||
{
|
|
||||||
throw new \BadMethodCallException('Not supported');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getDefaultOrderColumn()
|
|
||||||
{
|
|
||||||
return 'id';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getDefaultOrderDir()
|
|
||||||
{
|
|
||||||
return self::ORDER_DESC;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getOrder($query)
|
|
||||||
{
|
|
||||||
$order = [];
|
|
||||||
$tokens = array_filter(preg_split('/\s+/', $query));
|
|
||||||
foreach ($tokens as $token)
|
|
||||||
{
|
|
||||||
$token = preg_split('/,|\s+/', $token);
|
|
||||||
$orderToken = $token[0];
|
|
||||||
$orderDir = (count($token) === 2 and $token[1] === 'desc') ? self::ORDER_DESC : self::ORDER_ASC;
|
|
||||||
|
|
||||||
$orderColumn = $this->getOrderColumn($orderToken);
|
|
||||||
if ($orderColumn === null)
|
|
||||||
throw new \InvalidArgumentException('Invalid search order token: ' . $orderToken);
|
|
||||||
|
|
||||||
$order[$orderColumn] = $orderDir;
|
|
||||||
}
|
|
||||||
$defaultOrderColumn = $this->getDefaultOrderColumn();
|
|
||||||
$defaultOrderDir = $this->getDefaultOrderDir();
|
|
||||||
if ($defaultOrderColumn)
|
|
||||||
$order[$defaultOrderColumn] = $defaultOrderDir;
|
|
||||||
return $order;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function tokenize($query)
|
|
||||||
{
|
|
||||||
$basicTokens = [];
|
|
||||||
$complexTokens = [];
|
|
||||||
|
|
||||||
$tokens = array_filter(preg_split('/\s+/', $query));
|
|
||||||
foreach ($tokens as $token)
|
|
||||||
{
|
|
||||||
if (strpos($token, ':') !== false)
|
|
||||||
{
|
|
||||||
list ($key, $value) = explode(':', $token, 1);
|
|
||||||
$complexTokens[$key] = $value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$basicTokens[] = $token;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [$basicTokens, $complexTokens];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace Szurubooru\Dao\Services;
|
|
||||||
|
|
||||||
class PostSearchService extends AbstractSearchService
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
\Szurubooru\DatabaseConnection $databaseConnection,
|
|
||||||
\Szurubooru\Dao\PostDao $postDao)
|
|
||||||
{
|
|
||||||
parent::__construct($databaseConnection, $postDao);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace Szurubooru\Dao\Services;
|
|
||||||
|
|
||||||
class UserSearchService extends AbstractSearchService
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
\Szurubooru\DatabaseConnection $databaseConnection,
|
|
||||||
\Szurubooru\Dao\UserDao $userDao)
|
|
||||||
{
|
|
||||||
parent::__construct($databaseConnection, $userDao);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getOrderColumn($token)
|
|
||||||
{
|
|
||||||
if ($token === 'name')
|
|
||||||
return 'name';
|
|
||||||
|
|
||||||
if (in_array($token, ['registrationDate', 'registrationTime', 'registered', 'joinDate', 'joinTime', 'joined']))
|
|
||||||
return 'registrationTime';
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
15
src/SearchServices/AbstractSearchFilter.php
Normal file
15
src/SearchServices/AbstractSearchFilter.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\SearchServices;
|
||||||
|
|
||||||
|
abstract class AbstractSearchFilter
|
||||||
|
{
|
||||||
|
const ORDER_ASC = 1;
|
||||||
|
const ORDER_DESC = -1;
|
||||||
|
|
||||||
|
public $order;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->order = [];
|
||||||
|
}
|
||||||
|
}
|
7
src/SearchServices/NamedSearchToken.php
Normal file
7
src/SearchServices/NamedSearchToken.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\SearchServices;
|
||||||
|
|
||||||
|
class NamedSearchToken extends SearchToken
|
||||||
|
{
|
||||||
|
public $key = false;
|
||||||
|
}
|
61
src/SearchServices/PagedSearchResult.php
Normal file
61
src/SearchServices/PagedSearchResult.php
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\SearchServices;
|
||||||
|
|
||||||
|
class PagedSearchResult
|
||||||
|
{
|
||||||
|
public $pageNumber;
|
||||||
|
public $pageSize;
|
||||||
|
public $searchFilter;
|
||||||
|
public $entities;
|
||||||
|
public $totalRecords;
|
||||||
|
|
||||||
|
public function setSearchFilter(AbstractSearchFilter $searchFilter = null)
|
||||||
|
{
|
||||||
|
$this->searchFilter = $searchFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSearchFilter()
|
||||||
|
{
|
||||||
|
return $this->searchFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPageNumber($pageNumber)
|
||||||
|
{
|
||||||
|
$this->pageNumber = $pageNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPageNumber()
|
||||||
|
{
|
||||||
|
return $this->pageNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPageSize($pageSize)
|
||||||
|
{
|
||||||
|
$this->pageSize = $pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPageSize()
|
||||||
|
{
|
||||||
|
return $this->pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEntities(array $entities)
|
||||||
|
{
|
||||||
|
$this->entities = $entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEntities()
|
||||||
|
{
|
||||||
|
return $this->entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTotalRecords($totalRecords)
|
||||||
|
{
|
||||||
|
$this->totalRecords = $totalRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTotalRecords()
|
||||||
|
{
|
||||||
|
return $this->totalRecords;
|
||||||
|
}
|
||||||
|
}
|
103
src/SearchServices/Parsers/AbstractSearchParser.php
Normal file
103
src/SearchServices/Parsers/AbstractSearchParser.php
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\SearchServices\Parsers;
|
||||||
|
|
||||||
|
abstract class AbstractSearchParser
|
||||||
|
{
|
||||||
|
public function createFilterFromFormData(\Szurubooru\FormData\SearchFormData $formData)
|
||||||
|
{
|
||||||
|
$filter = $this->createFilter();
|
||||||
|
$filter->order = $this->getOrder($formData->order);
|
||||||
|
|
||||||
|
$tokens = $this->tokenize($formData->query);
|
||||||
|
|
||||||
|
foreach ($tokens as $token)
|
||||||
|
{
|
||||||
|
if ($token instanceof \Szurubooru\SearchServices\NamedSearchToken)
|
||||||
|
$this->decorateFilterFromNamedToken($filter, $token);
|
||||||
|
elseif ($token instanceof \Szurubooru\SearchService\SearchToken)
|
||||||
|
$this->decorateFilterFromToken($filter, $token);
|
||||||
|
else
|
||||||
|
throw new \RuntimeException('Invalid search token type');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract function createFilter();
|
||||||
|
|
||||||
|
protected abstract function decorateFilterFromToken($filter, $token);
|
||||||
|
|
||||||
|
protected abstract function decorateFilterFromNamedToken($filter, $namedToken);
|
||||||
|
|
||||||
|
protected abstract function getOrderColumn($token);
|
||||||
|
|
||||||
|
protected function getDefaultOrderColumn()
|
||||||
|
{
|
||||||
|
return 'id';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDefaultOrderDir()
|
||||||
|
{
|
||||||
|
return \Szurubooru\SearchServices\AbstractSearchFilter::ORDER_DESC;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getOrder($query)
|
||||||
|
{
|
||||||
|
$order = [];
|
||||||
|
$tokens = array_filter(preg_split('/\s+/', $query));
|
||||||
|
|
||||||
|
foreach ($tokens as $token)
|
||||||
|
{
|
||||||
|
$token = preg_split('/,|\s+/', $token);
|
||||||
|
$orderToken = $token[0];
|
||||||
|
$orderDir = (count($token) === 2 and $token[1] === 'desc')
|
||||||
|
? \Szurubooru\SearchServices\AbstractSearchFilter::ORDER_DESC
|
||||||
|
: \Szurubooru\SearchServices\AbstractSearchFilter::ORDER_ASC;
|
||||||
|
|
||||||
|
$orderColumn = $this->getOrderColumn($orderToken);
|
||||||
|
if ($orderColumn === null)
|
||||||
|
throw new \InvalidArgumentException('Invalid search order token: ' . $orderToken);
|
||||||
|
|
||||||
|
$order[$orderColumn] = $orderDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
$defaultOrderColumn = $this->getDefaultOrderColumn();
|
||||||
|
$defaultOrderDir = $this->getDefaultOrderDir();
|
||||||
|
if ($defaultOrderColumn)
|
||||||
|
$order[$defaultOrderColumn] = $defaultOrderDir;
|
||||||
|
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function tokenize($query)
|
||||||
|
{
|
||||||
|
$searchTokens = [];
|
||||||
|
|
||||||
|
foreach (array_filter(preg_split('/\s+/', $query)) as $tokenText)
|
||||||
|
{
|
||||||
|
$negated = false;
|
||||||
|
if (substr($tokenText, 0, 1) === '-')
|
||||||
|
{
|
||||||
|
$negated = true;
|
||||||
|
$tokenText = substr($tokenText, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strpos($tokenText, ':') !== false)
|
||||||
|
{
|
||||||
|
$searchToken = new \Szurubooru\SearchServices\NamedSearchToken();
|
||||||
|
list ($searchToken->key, $searchToken->value) = explode(':', $tokenText, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$searchToken = new \Szurubooru\SearchServices\SearchToken();
|
||||||
|
$searchToken->value = $tokenText;
|
||||||
|
}
|
||||||
|
|
||||||
|
$searchToken->negated = $negated;
|
||||||
|
$searchTokens[] = $searchToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $searchTokens;
|
||||||
|
}
|
||||||
|
}
|
25
src/SearchServices/Parsers/PostSearchParser.php
Normal file
25
src/SearchServices/Parsers/PostSearchParser.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\SearchServices\Parsers;
|
||||||
|
|
||||||
|
class PostSearchParser extends AbstractSearchParser
|
||||||
|
{
|
||||||
|
protected function createFilter()
|
||||||
|
{
|
||||||
|
return new \Szurubooru\SearchServices\PostSearchFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function decorateFilterFromToken($filter, $token)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Not supported');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function decorateFilterFromNamedToken($filter, $namedToken)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Not supported');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getOrderColumn($token)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Not supported');
|
||||||
|
}
|
||||||
|
}
|
31
src/SearchServices/Parsers/UserSearchParser.php
Normal file
31
src/SearchServices/Parsers/UserSearchParser.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\SearchServices\Parsers;
|
||||||
|
|
||||||
|
class UserSearchParser extends AbstractSearchParser
|
||||||
|
{
|
||||||
|
protected function createFilter()
|
||||||
|
{
|
||||||
|
return new \Szurubooru\SearchServices\UserSearchFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function decorateFilterFromToken($filter, $token)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Not supported');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function decorateFilterFromNamedToken($filter, $namedToken)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Not supported');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getOrderColumn($token)
|
||||||
|
{
|
||||||
|
if ($token === 'name')
|
||||||
|
return 'name';
|
||||||
|
|
||||||
|
if (in_array($token, ['registrationDate', 'registrationTime', 'registered', 'joinDate', 'joinTime', 'joined']))
|
||||||
|
return 'registrationTime';
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
6
src/SearchServices/PostSearchFilter.php
Normal file
6
src/SearchServices/PostSearchFilter.php
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\SearchServices;
|
||||||
|
|
||||||
|
class PostSearchFilter extends AbstractSearchFilter
|
||||||
|
{
|
||||||
|
}
|
8
src/SearchServices/SearchToken.php
Normal file
8
src/SearchServices/SearchToken.php
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\SearchServices;
|
||||||
|
|
||||||
|
class SearchToken
|
||||||
|
{
|
||||||
|
public $negated = false;
|
||||||
|
public $value;
|
||||||
|
}
|
6
src/SearchServices/UserSearchFilter.php
Normal file
6
src/SearchServices/UserSearchFilter.php
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\SearchServices;
|
||||||
|
|
||||||
|
class UserSearchFilter extends AbstractSearchFilter
|
||||||
|
{
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ class PostService
|
||||||
private $validator;
|
private $validator;
|
||||||
private $transactionManager;
|
private $transactionManager;
|
||||||
private $postDao;
|
private $postDao;
|
||||||
private $postSearchService;
|
private $postSearchParser;
|
||||||
private $timeService;
|
private $timeService;
|
||||||
private $authService;
|
private $authService;
|
||||||
private $fileService;
|
private $fileService;
|
||||||
|
@ -18,7 +18,7 @@ class PostService
|
||||||
\Szurubooru\Validator $validator,
|
\Szurubooru\Validator $validator,
|
||||||
\Szurubooru\Dao\TransactionManager $transactionManager,
|
\Szurubooru\Dao\TransactionManager $transactionManager,
|
||||||
\Szurubooru\Dao\PostDao $postDao,
|
\Szurubooru\Dao\PostDao $postDao,
|
||||||
\Szurubooru\Dao\Services\PostSearchService $postSearchService,
|
\Szurubooru\SearchServices\Parsers\PostSearchParser $postSearchParser,
|
||||||
\Szurubooru\Services\AuthService $authService,
|
\Szurubooru\Services\AuthService $authService,
|
||||||
\Szurubooru\Services\TimeService $timeService,
|
\Szurubooru\Services\TimeService $timeService,
|
||||||
\Szurubooru\Services\FileService $fileService,
|
\Szurubooru\Services\FileService $fileService,
|
||||||
|
@ -28,7 +28,7 @@ class PostService
|
||||||
$this->validator = $validator;
|
$this->validator = $validator;
|
||||||
$this->transactionManager = $transactionManager;
|
$this->transactionManager = $transactionManager;
|
||||||
$this->postDao = $postDao;
|
$this->postDao = $postDao;
|
||||||
$this->postSearchService = $postSearchService;
|
$this->postSearchParser = $postSearchParser;
|
||||||
$this->timeService = $timeService;
|
$this->timeService = $timeService;
|
||||||
$this->authService = $authService;
|
$this->authService = $authService;
|
||||||
$this->fileService = $fileService;
|
$this->fileService = $fileService;
|
||||||
|
@ -66,8 +66,8 @@ class PostService
|
||||||
$transactionFunc = function() use ($formData)
|
$transactionFunc = function() use ($formData)
|
||||||
{
|
{
|
||||||
$this->validator->validate($formData);
|
$this->validator->validate($formData);
|
||||||
$searchFilter = new \Szurubooru\Dao\SearchFilter($this->config->posts->postsPerPage, $formData);
|
$searchFilter = $this->postSearchParser->createFilterFromFormData($formData);
|
||||||
return $this->postSearchService->getFiltered($searchFilter);
|
return $this->postDao->findFilteredAndPaged($searchFilter, $formData->pageNumber, $this->config->posts->postsPerPage);
|
||||||
};
|
};
|
||||||
return $this->transactionManager->rollback($transactionFunc);
|
return $this->transactionManager->rollback($transactionFunc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ class UserService
|
||||||
private $validator;
|
private $validator;
|
||||||
private $transactionManager;
|
private $transactionManager;
|
||||||
private $userDao;
|
private $userDao;
|
||||||
private $userSearchService;
|
private $userSearchParser;
|
||||||
private $passwordService;
|
private $passwordService;
|
||||||
private $emailService;
|
private $emailService;
|
||||||
private $fileService;
|
private $fileService;
|
||||||
|
@ -20,7 +20,7 @@ class UserService
|
||||||
\Szurubooru\Validator $validator,
|
\Szurubooru\Validator $validator,
|
||||||
\Szurubooru\Dao\TransactionManager $transactionManager,
|
\Szurubooru\Dao\TransactionManager $transactionManager,
|
||||||
\Szurubooru\Dao\UserDao $userDao,
|
\Szurubooru\Dao\UserDao $userDao,
|
||||||
\Szurubooru\Dao\Services\UserSearchService $userSearchService,
|
\Szurubooru\SearchServices\Parsers\UserSearchParser $userSearchParser,
|
||||||
\Szurubooru\Services\PasswordService $passwordService,
|
\Szurubooru\Services\PasswordService $passwordService,
|
||||||
\Szurubooru\Services\EmailService $emailService,
|
\Szurubooru\Services\EmailService $emailService,
|
||||||
\Szurubooru\Services\FileService $fileService,
|
\Szurubooru\Services\FileService $fileService,
|
||||||
|
@ -32,7 +32,7 @@ class UserService
|
||||||
$this->validator = $validator;
|
$this->validator = $validator;
|
||||||
$this->transactionManager = $transactionManager;
|
$this->transactionManager = $transactionManager;
|
||||||
$this->userDao = $userDao;
|
$this->userDao = $userDao;
|
||||||
$this->userSearchService = $userSearchService;
|
$this->userSearchParser = $userSearchParser;
|
||||||
$this->passwordService = $passwordService;
|
$this->passwordService = $passwordService;
|
||||||
$this->emailService = $emailService;
|
$this->emailService = $emailService;
|
||||||
$this->fileService = $fileService;
|
$this->fileService = $fileService;
|
||||||
|
@ -87,8 +87,8 @@ class UserService
|
||||||
$transactionFunc = function() use ($formData)
|
$transactionFunc = function() use ($formData)
|
||||||
{
|
{
|
||||||
$this->validator->validate($formData);
|
$this->validator->validate($formData);
|
||||||
$searchFilter = new \Szurubooru\Dao\SearchFilter($this->config->users->usersPerPage, $formData);
|
$searchFilter = $this->userSearchParser->createFilterFromFormData($formData);
|
||||||
return $this->userSearchService->getFiltered($searchFilter);
|
return $this->userDao->findFilteredAndPaged($searchFilter, $formData->pageNumber, $this->config->users->usersPerPage);
|
||||||
};
|
};
|
||||||
return $this->transactionManager->rollback($transactionFunc);
|
return $this->transactionManager->rollback($transactionFunc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
private $validatorMock;
|
private $validatorMock;
|
||||||
private $transactionManagerMock;
|
private $transactionManagerMock;
|
||||||
private $postDaoMock;
|
private $postDaoMock;
|
||||||
private $postSearchServiceMock;
|
private $postSearchParserMock;
|
||||||
private $authServiceMock;
|
private $authServiceMock;
|
||||||
private $timeServiceMock;
|
private $timeServiceMock;
|
||||||
private $fileServiceMock;
|
private $fileServiceMock;
|
||||||
|
@ -19,7 +19,7 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
$this->validatorMock = $this->mock(\Szurubooru\Validator::class);
|
$this->validatorMock = $this->mock(\Szurubooru\Validator::class);
|
||||||
$this->transactionManagerMock = $this->mockTransactionManager();
|
$this->transactionManagerMock = $this->mockTransactionManager();
|
||||||
$this->postDaoMock = $this->mock(\Szurubooru\Dao\PostDao::class);
|
$this->postDaoMock = $this->mock(\Szurubooru\Dao\PostDao::class);
|
||||||
$this->postSearchServiceMock = $this->mock(\Szurubooru\Dao\Services\PostSearchService::class);
|
$this->postSearchParserMock = $this->mock(\Szurubooru\SearchServices\Parsers\PostSearchParser::class);
|
||||||
$this->authServiceMock = $this->mock(\Szurubooru\Services\AuthService::class);
|
$this->authServiceMock = $this->mock(\Szurubooru\Services\AuthService::class);
|
||||||
$this->timeServiceMock = $this->mock(\Szurubooru\Services\TimeService::class);
|
$this->timeServiceMock = $this->mock(\Szurubooru\Services\TimeService::class);
|
||||||
$this->fileServiceMock = $this->mock(\Szurubooru\Services\FileService::class);
|
$this->fileServiceMock = $this->mock(\Szurubooru\Services\FileService::class);
|
||||||
|
@ -178,7 +178,7 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
$this->validatorMock,
|
$this->validatorMock,
|
||||||
$this->transactionManagerMock,
|
$this->transactionManagerMock,
|
||||||
$this->postDaoMock,
|
$this->postDaoMock,
|
||||||
$this->postSearchServiceMock,
|
$this->postSearchParserMock,
|
||||||
$this->authServiceMock,
|
$this->authServiceMock,
|
||||||
$this->timeServiceMock,
|
$this->timeServiceMock,
|
||||||
$this->fileServiceMock,
|
$this->fileServiceMock,
|
||||||
|
|
|
@ -7,7 +7,7 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
private $validatorMock;
|
private $validatorMock;
|
||||||
private $transactionManagerMock;
|
private $transactionManagerMock;
|
||||||
private $userDaoMock;
|
private $userDaoMock;
|
||||||
private $userSearchServiceMock;
|
private $userSearchParserMock;
|
||||||
private $passwordServiceMock;
|
private $passwordServiceMock;
|
||||||
private $emailServiceMock;
|
private $emailServiceMock;
|
||||||
private $fileServiceMock;
|
private $fileServiceMock;
|
||||||
|
@ -22,7 +22,7 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
$this->transactionManagerMock = $this->mockTransactionManager();
|
$this->transactionManagerMock = $this->mockTransactionManager();
|
||||||
$this->validatorMock = $this->mock(\Szurubooru\Validator::class);
|
$this->validatorMock = $this->mock(\Szurubooru\Validator::class);
|
||||||
$this->userDaoMock = $this->mock(\Szurubooru\Dao\UserDao::class);
|
$this->userDaoMock = $this->mock(\Szurubooru\Dao\UserDao::class);
|
||||||
$this->userSearchService = $this->mock(\Szurubooru\Dao\Services\UserSearchService::class);
|
$this->userSearchParserMock = $this->mock(\Szurubooru\SearchServices\Parsers\UserSearchParser::class);
|
||||||
$this->passwordServiceMock = $this->mock(\Szurubooru\Services\PasswordService::class);
|
$this->passwordServiceMock = $this->mock(\Szurubooru\Services\PasswordService::class);
|
||||||
$this->emailServiceMock = $this->mock(\Szurubooru\Services\EmailService::class);
|
$this->emailServiceMock = $this->mock(\Szurubooru\Services\EmailService::class);
|
||||||
$this->fileServiceMock = $this->mock(\Szurubooru\Services\FileService::class);
|
$this->fileServiceMock = $this->mock(\Szurubooru\Services\FileService::class);
|
||||||
|
@ -72,7 +72,7 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
$mockUser = new \Szurubooru\Entities\User;
|
$mockUser = new \Szurubooru\Entities\User;
|
||||||
$mockUser->setName('user');
|
$mockUser->setName('user');
|
||||||
$expected = [$mockUser];
|
$expected = [$mockUser];
|
||||||
$this->userSearchService->method('getFiltered')->willReturn($expected);
|
$this->userDaoMock->method('getFiltered')->willReturn($expected);
|
||||||
|
|
||||||
$this->configMock->set('users/usersPerPage', 1);
|
$this->configMock->set('users/usersPerPage', 1);
|
||||||
$searchFormData = new \Szurubooru\FormData\SearchFormData;
|
$searchFormData = new \Szurubooru\FormData\SearchFormData;
|
||||||
|
@ -292,7 +292,7 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
$this->validatorMock,
|
$this->validatorMock,
|
||||||
$this->transactionManagerMock,
|
$this->transactionManagerMock,
|
||||||
$this->userDaoMock,
|
$this->userDaoMock,
|
||||||
$this->userSearchService,
|
$this->userSearchParserMock,
|
||||||
$this->passwordServiceMock,
|
$this->passwordServiceMock,
|
||||||
$this->emailServiceMock,
|
$this->emailServiceMock,
|
||||||
$this->fileServiceMock,
|
$this->fileServiceMock,
|
||||||
|
|
Loading…
Reference in a new issue