diff --git a/data/config.ini b/data/config.ini
index 3359b8db..7eaf1174 100644
--- a/data/config.ini
+++ b/data/config.ini
@@ -10,3 +10,4 @@ minPasswordLength = 5
[users]
minUserNameLength = 1
maxUserNameLength = 32
+usersPerPage = 20
diff --git a/public_html/css/core.css b/public_html/css/core.css
index 21c92654..0b07536f 100644
--- a/public_html/css/core.css
+++ b/public_html/css/core.css
@@ -23,3 +23,7 @@ a {
color: #6a2;
text-decoration: none;
}
+
+a:hover {
+ color: #7b3;
+}
diff --git a/public_html/css/pager.css b/public_html/css/pager.css
new file mode 100644
index 00000000..e1e3177b
--- /dev/null
+++ b/public_html/css/pager.css
@@ -0,0 +1,27 @@
+.pager {
+ text-align: center;
+ margin-top: 1em;
+}
+
+.pager ul {
+ list-style-type: none;
+ padding: 0;
+ margin: 0 auto;
+ display: inline-block;
+}
+
+.pager li {
+ display: inline-block;
+}
+
+.pager li a {
+ display: inline-block;
+ padding: 0.4em 1.2em;
+}
+
+.pager li:hover a {
+ background: #efa;
+}
+.pager li.active a {
+ background: #faffca;
+}
diff --git a/public_html/css/user-list.css b/public_html/css/user-list.css
new file mode 100644
index 00000000..2bf223aa
--- /dev/null
+++ b/public_html/css/user-list.css
@@ -0,0 +1,27 @@
+#user-list {
+ min-width: 20em;
+}
+
+#user-list ul {
+ list-style-type: none;
+ padding: 0;
+ margin: 0;
+}
+
+#user-list ul.order {
+ margin: -0.5em -0.5em 0.5em -0.5em;
+}
+#user-list ul.order li {
+ display: inline-block;
+ margin: 0 0.5em;
+}
+
+#user-list ul.order li.active a {
+ background: #faffca;
+}
+
+#user-list ul.order a {
+ cursor: pointer;
+ display: inline-block;
+ padding: 0.2em 0.5em;
+}
diff --git a/public_html/index.html b/public_html/index.html
index 51920f55..c3e85446 100644
--- a/public_html/index.html
+++ b/public_html/index.html
@@ -12,8 +12,10 @@
+
+
@@ -31,6 +33,7 @@
+
diff --git a/public_html/js/Presenters/PagedCollectionPresenter.js b/public_html/js/Presenters/PagedCollectionPresenter.js
new file mode 100644
index 00000000..b54897e2
--- /dev/null
+++ b/public_html/js/Presenters/PagedCollectionPresenter.js
@@ -0,0 +1,114 @@
+var App = App || {};
+App.Presenters = App.Presenters || {};
+
+App.Presenters.PagedCollectionPresenter = function(api, util) {
+
+ var searchOrder;
+ var searchQuery;
+ var pageNumber;
+ var baseUri;
+ var backendUri;
+ var renderCallback;
+
+ var template;
+ var pageSize;
+ var totalRecords;
+
+ function init(args) {
+ parseSearchArgs(args.searchArgs);
+ baseUri = args.baseUri;
+ backendUri = args.backendUri;
+ renderCallback = args.renderCallback;
+
+ util.loadTemplate('pager').then(function(html) {
+ template = _.template(html);
+ //renderCallback({entities: [], totalRecords: 0});
+
+ changePage(pageNumber);
+ });
+ }
+
+ function changePage(newPageNumber) {
+ pageNumber = newPageNumber;
+
+ api.get(backendUri, {
+ order: searchOrder,
+ query: searchQuery,
+ page: pageNumber
+ }).then(function(response) {
+ totalRecords = response.json.totalRecords;
+ pageSize = response.json.pageSize;
+ renderCallback({
+ entities: response.json.data,
+ totalRecords: response.json.totalRecords});
+ }).catch(function(response) {
+ console.log(Error(response.json && response.json.error || response));
+ });
+ }
+
+ function render($target) {
+ var totalPages = Math.ceil(totalRecords / pageSize);
+ var pages = [1, totalPages];
+ var pagesAroundCurrent = 2;
+ for (var i = -pagesAroundCurrent; i <= pagesAroundCurrent; i ++)
+ if (pageNumber + i >= 1 && pageNumber + i <= totalPages)
+ pages.push(pageNumber + i);
+ if (pageNumber - pagesAroundCurrent - 1 == 2)
+ pages.push(2);
+ if (pageNumber + pagesAroundCurrent + 1 == totalPages - 1)
+ pages.push(totalPages - 1);
+
+ pages = pages.sort(function(a, b) { return a - b; }).filter(function(item, pos) {
+ return !pos || item != pages[pos - 1];
+ });
+
+ $target.html(template({
+ pages: pages,
+ pageNumber: pageNumber,
+ link: getPageChangeLink,
+ }));
+ }
+
+ function getSearchQueryChangeLink(newSearchQuery) {
+ return util.compileComplexRouteArgs(baseUri, {
+ page: 1,
+ order: searchOrder,
+ query: newSearchQuery,
+ });
+ }
+
+ function getSearchOrderChangeLink(newSearchOrder) {
+ return util.compileComplexRouteArgs(baseUri, {
+ page: 1,
+ order: newSearchOrder,
+ query: searchQuery,
+ });
+ }
+
+ function getPageChangeLink(newPageNumber) {
+ return util.compileComplexRouteArgs(baseUri, {
+ page: newPageNumber,
+ order: searchOrder,
+ query: searchQuery,
+ });
+ }
+
+ function parseSearchArgs(searchArgs) {
+ var args = util.parseComplexRouteArgs(searchArgs);
+ pageNumber = parseInt(args.page) || 1;
+ searchOrder = args.order;
+ searchQuery = args.query;
+ }
+
+ return {
+ init: init,
+ render: render,
+ changePage: changePage,
+ getSearchQueryChangeLink: getSearchQueryChangeLink,
+ getSearchOrderChangeLink: getSearchOrderChangeLink,
+ getPageChangeLink: getPageChangeLink
+ };
+
+};
+
+App.DI.register('pagedCollectionPresenter', App.Presenters.PagedCollectionPresenter);
diff --git a/public_html/js/Presenters/UserListPresenter.js b/public_html/js/Presenters/UserListPresenter.js
index 77b40009..f2b77c77 100644
--- a/public_html/js/Presenters/UserListPresenter.js
+++ b/public_html/js/Presenters/UserListPresenter.js
@@ -1,19 +1,56 @@
var App = App || {};
App.Presenters = App.Presenters || {};
-App.Presenters.UserListPresenter = function(jQuery, topNavigationPresenter, appState) {
+App.Presenters.UserListPresenter = function(
+ jQuery,
+ util,
+ router,
+ pagedCollectionPresenter,
+ topNavigationPresenter) {
var $el = jQuery('#content');
+ var template;
+ var userList = [];
+ var activeSearchOrder;
- function init() {
+ function init(args) {
topNavigationPresenter.select('users');
- render();
+ activeSearchOrder = util.parseComplexRouteArgs(args.searchArgs).order;
+
+ util.loadTemplate('user-list').then(function(html) {
+ template = _.template(html);
+
+ pagedCollectionPresenter.init({
+ searchArgs: args.searchArgs,
+ baseUri: '#/users',
+ backendUri: '/users',
+ renderCallback: function updateCollection(data) {
+ userList = data.entities;
+ render();
+ }});
+ });
}
function render() {
- $el.html('Logged in: ' + appState.get('loggedIn'));
+ $el.html(template({
+ userList: userList,
+ }));
+ $el.find('.order a').click(orderLinkClicked);
+ $el.find('.order [data-order="' + activeSearchOrder + '"]').parent('li').addClass('active');
+ console.log(activeSearchOrder);
+
+ var $pager = $el.find('.pager');
+ pagedCollectionPresenter.render($pager);
};
+ function orderLinkClicked(e)
+ {
+ e.preventDefault();
+ var $orderLink = jQuery(this);
+ activeSearchOrder = $orderLink.attr('data-order');
+ router.navigate(pagedCollectionPresenter.getSearchOrderChangeLink(activeSearchOrder));
+ }
+
return {
init: init,
render: render
diff --git a/public_html/js/Router.js b/public_html/js/Router.js
index 7755ff0e..fafea7e6 100644
--- a/public_html/js/Router.js
+++ b/public_html/js/Router.js
@@ -23,7 +23,8 @@ App.Router = function(jQuery, util) {
inject('#/logout', function() { return App.DI.get('logoutPresenter'); });
inject('#/register', function() { return App.DI.get('registrationPresenter'); });
inject('#/users', function() { return App.DI.get('userListPresenter'); });
- inject('#/users/:userName', function() { return App.DI.get('userPresenter'); });
+ inject('#/users/:searchArgs', function() { return App.DI.get('userListPresenter'); });
+ inject('#/user/:userName', function() { return App.DI.get('userPresenter'); });
setRoot('#/users');
};
diff --git a/public_html/js/Util.js b/public_html/js/Util.js
index 44e03e8a..843fcd63 100644
--- a/public_html/js/Util.js
+++ b/public_html/js/Util.js
@@ -4,6 +4,30 @@ App.Util = (function(jQuery) {
var templateCache = {};
+ function parseComplexRouteArgs(args) {
+ var result = {};
+ args = (args || '').split(/;/);
+ for (var i = 0; i < args.length; i ++) {
+ var arg = args[i];
+ if (!arg)
+ continue;
+ kv = arg.split(/=/);
+ result[kv[0]] = kv[1];
+ }
+ return result;
+ }
+
+ function compileComplexRouteArgs(baseUri, args) {
+ var result = baseUri + '/';
+ _.each(args, function(v, k) {
+ if (typeof(v) == 'undefined')
+ return;
+ result += k + '=' + v + ';'
+ });
+ result = result.slice(0, -1);
+ return result;
+ }
+
function loadTemplate(templateName) {
return loadTemplateFromCache(templateName)
|| loadTemplateFromDOM(templateName)
@@ -62,6 +86,8 @@ App.Util = (function(jQuery) {
loadTemplate: loadTemplate,
initPresenter : initPresenter,
initContentPresenter: initContentPresenter,
+ parseComplexRouteArgs: parseComplexRouteArgs,
+ compileComplexRouteArgs: compileComplexRouteArgs,
};
});
diff --git a/public_html/templates/pager.tpl b/public_html/templates/pager.tpl
new file mode 100644
index 00000000..96485413
--- /dev/null
+++ b/public_html/templates/pager.tpl
@@ -0,0 +1,15 @@
+
diff --git a/public_html/templates/top-navigation.tpl b/public_html/templates/top-navigation.tpl
index db4ec709..4f14628d 100644
--- a/public_html/templates/top-navigation.tpl
+++ b/public_html/templates/top-navigation.tpl
@@ -12,7 +12,7 @@
<% } else { %>
- <%= user.name %>
+ <%= user.name %>
Logout
diff --git a/public_html/templates/user-list.tpl b/public_html/templates/user-list.tpl
new file mode 100644
index 00000000..f009f657
--- /dev/null
+++ b/public_html/templates/user-list.tpl
@@ -0,0 +1,24 @@
+
+
+
+ <% _.each(userList, function(user) { %>
+
+ User name: <%= user.name %>
+
+ <% }); %>
+
+
+
diff --git a/src/Config.php b/src/Config.php
index ac678aff..051db826 100644
--- a/src/Config.php
+++ b/src/Config.php
@@ -1,7 +1,7 @@
post('/api/users', [$this, 'register']);
- $router->get('/api/users', [$this, 'getAll']);
+ $router->get('/api/users', [$this, 'getFiltered']);
$router->get('/api/users/:id', [$this, 'getById']);
$router->put('/api/users/:id', [$this, 'update']);
$router->delete('/api/users/:id', [$this, 'delete']);
}
+ public function getFiltered()
+ {
+ //todo: move this to form data constructor
+ $searchFormData = new \Szurubooru\FormData\SearchFormData;
+ $searchFormData->query = $this->inputReader->query;
+ $searchFormData->order = $this->inputReader->order;
+ $searchFormData->pageNumber = $this->inputReader->page;
+ $searchResult = $this->userService->getFiltered($searchFormData);
+ $entities = array_map(function($user) { return new \Szurubooru\ViewProxies\User($user); }, $searchResult->entities);
+ return [
+ 'data' => $entities,
+ 'pageSize' => $searchResult->filter->pageSize,
+ 'totalRecords' => $searchResult->totalRecords];
+ }
+
+ public function getById($id)
+ {
+ throw new \BadMethodCallException('Not implemented');
+ }
+
public function register()
{
$input = new \Szurubooru\FormData\RegistrationFormData;
+ //todo: move this to form data constructor
$input->name = $this->inputReader->userName;
$input->password = $this->inputReader->password;
$input->email = $this->inputReader->email;
@@ -40,16 +61,6 @@ final class UserController extends AbstractController
throw new \BadMethodCallException('Not implemented');
}
- public function getAll()
- {
- throw new \BadMethodCallException('Not implemented');
- }
-
- public function getById($id)
- {
- throw new \BadMethodCallException('Not implemented');
- }
-
public function delete($id)
{
throw new \BadMethodCallException('Not implemented');
diff --git a/src/Dao/AbstractDao.php b/src/Dao/AbstractDao.php
index 06fe0e19..ecd14385 100644
--- a/src/Dao/AbstractDao.php
+++ b/src/Dao/AbstractDao.php
@@ -19,6 +19,16 @@ abstract class AbstractDao implements ICrudDao
$this->entityName = $entityName;
}
+ public function getCollection()
+ {
+ return $this->collection;
+ }
+
+ public function getEntityConverter()
+ {
+ return $this->entityConverter;
+ }
+
public function save(&$entity)
{
$arrayEntity = $this->entityConverter->toArray($entity);
diff --git a/src/Dao/SearchFilter.php b/src/Dao/SearchFilter.php
new file mode 100644
index 00000000..5788f4b8
--- /dev/null
+++ b/src/Dao/SearchFilter.php
@@ -0,0 +1,21 @@
+pageSize = $pageSize;
+ if ($searchFormData)
+ {
+ $this->query = $searchFormData->query;
+ $this->order = $searchFormData->order;
+ $this->pageNumber = $searchFormData->pageNumber;
+ }
+ }
+}
diff --git a/src/Dao/SearchResult.php b/src/Dao/SearchResult.php
new file mode 100644
index 00000000..24e1582a
--- /dev/null
+++ b/src/Dao/SearchResult.php
@@ -0,0 +1,17 @@
+filter = $filter;
+ $this->entities = $entities;
+ $this->totalRecords = $totalRecords;
+ }
+}
+
diff --git a/src/Dao/Services/AbstractSearchService.php b/src/Dao/Services/AbstractSearchService.php
new file mode 100644
index 00000000..6e523eb7
--- /dev/null
+++ b/src/Dao/Services/AbstractSearchService.php
@@ -0,0 +1,122 @@
+collection = $dao->getCollection();
+ $this->entityConverter = $dao->getEntityConverter();
+ }
+
+ 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;
+
+ $cursor = $this->collection->find($filter);
+ $totalRecords = $cursor->count();
+ $cursor->sort($order);
+ $cursor->skip($pageSize * $pageNumber);
+ $cursor->limit($pageSize);
+
+ $entities = [];
+ foreach ($cursor as $arrayEntity)
+ $entities []= $this->entityConverter->toEntity($arrayEntity);
+
+ 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);
+ if (count($token) == 2)
+ {
+ $orderDir = $token[1] == 'desc' ? self::ORDER_DESC : self::ORDER_ASC;
+ $orderToken = $token[0];
+ }
+ else
+ {
+ $orderDir = self::ORDER_ASC;
+ $orderToken = $token;
+ }
+ $orderColumn = $this->getOrderColumn($token[0]);
+ if ($orderColumn === null)
+ throw new \InvalidArgumentException('Invalid search order token: ' . $token);
+ $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];
+ }
+}
diff --git a/src/Dao/Services/UserSearchService.php b/src/Dao/Services/UserSearchService.php
new file mode 100644
index 00000000..f52dfda5
--- /dev/null
+++ b/src/Dao/Services/UserSearchService.php
@@ -0,0 +1,31 @@
+config = $config;
$this->validator = $validator;
$this->userDao = $userDao;
+ $this->userSearchService = $userSearchService;
$this->passwordService = $passwordService;
$this->emailService = $emailService;
$this->timeService = $timeService;
}
+ public function getFiltered(\Szurubooru\FormData\SearchFormData $formData)
+ {
+ $pageSize = intval($this->config->users->usersPerPage);
+ $this->validator->validateNumber($formData->page);
+ $searchFilter = new \Szurubooru\Dao\SearchFilter($pageSize, $formData);
+ return $this->userSearchService->getFiltered($searchFilter);
+ }
+
public function register(\Szurubooru\FormData\RegistrationFormData $formData)
{
$this->validator->validateUserName($formData->name);
diff --git a/src/Validator.php b/src/Validator.php
index 32dc006b..dda0248c 100644
--- a/src/Validator.php
+++ b/src/Validator.php
@@ -10,6 +10,10 @@ class Validator
$this->config = $config;
}
+ public function validateNumber(&$subject) {
+ $subject = intval($subject);
+ }
+
public function validateNonEmpty($subject, $subjectName = 'Object')
{
if (!$subject)
diff --git a/tests/AbstractTestCase.php b/tests/AbstractTestCase.php
index da069619..98c5e5eb 100644
--- a/tests/AbstractTestCase.php
+++ b/tests/AbstractTestCase.php
@@ -8,3 +8,5 @@ abstract class AbstractTestCase extends \PHPUnit_Framework_TestCase
return $this->getMockBuilder($className)->disableOriginalConstructor()->getMock();
}
}
+
+date_default_timezone_set('UTC');
diff --git a/tests/Dao/Services/UserSearchServiceTest.php b/tests/Dao/Services/UserSearchServiceTest.php
new file mode 100644
index 00000000..d634a67b
--- /dev/null
+++ b/tests/Dao/Services/UserSearchServiceTest.php
@@ -0,0 +1,67 @@
+userDao = new \Szurubooru\Dao\UserDao($this->databaseConnection);
+ }
+
+ public function testNothing()
+ {
+ $searchFilter = new \Szurubooru\Dao\SearchFilter(1);
+ $expected = new \Szurubooru\Dao\SearchResult($searchFilter, [], 0);
+
+ $userSearchService = $this->getUserSearchService();
+ $actual = $userSearchService->getFiltered($searchFilter);
+ $this->assertEquals($expected, $actual);
+ }
+
+ public function testSorting()
+ {
+ $user1 = new \Szurubooru\Entities\User();
+ $user1->name = 'reginald';
+ $user1->registrationTime = date('c', mktime(3, 2, 1));
+ $user2 = new \Szurubooru\Entities\User();
+ $user2->name = 'beartato';
+ $user2->registrationTime = date('c', mktime(1, 2, 3));
+
+ $this->userDao->save($user1);
+ $this->userDao->save($user2);
+
+ $userSearchService = $this->getUserSearchService();
+ $searchFilter = new \Szurubooru\Dao\SearchFilter(1);
+ $expected = new \Szurubooru\Dao\SearchResult($searchFilter, [$user2], 2);
+ $actual = $userSearchService->getFiltered($searchFilter);
+ $this->assertEquals($expected, $actual);
+
+ $searchFilter->order = 'name,asc';
+ $expected = new \Szurubooru\Dao\SearchResult($searchFilter, [$user2], 2);
+ $actual = $userSearchService->getFiltered($searchFilter);
+ $this->assertEquals($expected, $actual);
+
+ $searchFilter->order = 'name,desc';
+ $expected = new \Szurubooru\Dao\SearchResult($searchFilter, [$user1], 2);
+ $actual = $userSearchService->getFiltered($searchFilter);
+ $this->assertEquals($expected, $actual);
+
+ $searchFilter->order = 'registrationTime,desc';
+ $expected = new \Szurubooru\Dao\SearchResult($searchFilter, [$user1], 2);
+ $actual = $userSearchService->getFiltered($searchFilter);
+ $this->assertEquals($expected, $actual);
+
+ $searchFilter->order = 'registrationTime';
+ $expected = new \Szurubooru\Dao\SearchResult($searchFilter, [$user2], 2);
+ $actual = $userSearchService->getFiltered($searchFilter);
+ $this->assertEquals($expected, $actual);
+ }
+
+ private function getUserSearchService()
+ {
+ return new \Szurubooru\Dao\Services\UserSearchService($this->userDao);
+ }
+}
diff --git a/tests/Dao/UserDaoTest.php b/tests/Dao/UserDaoTest.php
index b0b0ac11..aeb6033b 100644
--- a/tests/Dao/UserDaoTest.php
+++ b/tests/Dao/UserDaoTest.php
@@ -5,7 +5,7 @@ final class UserDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
{
public function testRetrievingByValidName()
{
- $userDao = new \Szurubooru\Dao\UserDao($this->databaseConnection);
+ $userDao = $this->getUserDao();
$user = new \Szurubooru\Entities\User();
$user->name = 'test';
@@ -19,7 +19,7 @@ final class UserDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
public function testRetrievingByInvalidName()
{
- $userDao = new \Szurubooru\Dao\UserDao($this->databaseConnection);
+ $userDao = $this->getUserDao();
$actual = $userDao->getByName('rubbish');
@@ -28,7 +28,7 @@ final class UserDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
public function testCheckingUserPresence()
{
- $userDao = new \Szurubooru\Dao\UserDao($this->databaseConnection);
+ $userDao = $this->getUserDao();
$this->assertFalse($userDao->hasAnyUsers());
@@ -38,4 +38,9 @@ final class UserDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
$this->assertTrue($userDao->hasAnyUsers());
}
+
+ private function getUserDao()
+ {
+ return new \Szurubooru\Dao\UserDao($this->databaseConnection);
+ }
}
diff --git a/tests/Services/UserServiceTest.php b/tests/Services/UserServiceTest.php
index 025a36a3..a421a3dc 100644
--- a/tests/Services/UserServiceTest.php
+++ b/tests/Services/UserServiceTest.php
@@ -3,21 +3,44 @@ namespace Szurubooru\Tests\Services;
final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
{
+ private $configMock;
private $validatorMock;
private $userDaoMock;
+ private $userSearchServiceMock;
private $passwordServiceMock;
private $emailServiceMock;
private $timeServiceMock;
public function setUp()
{
+ $this->configMock = $this->mock(\Szurubooru\Config::class);
$this->validatorMock = $this->mock(\Szurubooru\Validator::class);
$this->userDaoMock = $this->mock(\Szurubooru\Dao\UserDao::class);
+ $this->userSearchService = $this->mock(\Szurubooru\Dao\Services\UserSearchService::class);
$this->passwordServiceMock = $this->mock(\Szurubooru\Services\PasswordService::class);
$this->emailServiceMock = $this->mock(\Szurubooru\Services\EmailService::class);
$this->timeServiceMock = $this->mock(\Szurubooru\Services\TimeService::class);
}
+ public function testGettingFilteredUsers()
+ {
+ $mockUser = new \Szurubooru\Entities\User();
+ $mockUser->name = 'user';
+ $expected = [$mockUser];
+ $this->userSearchService->method('getFiltered')->willReturn($expected);
+
+ $this->configMock->users = new \StdClass;
+ $this->configMock->users->usersPerPage = 1;
+ $searchFormData = new \Szurubooru\FormData\SearchFormData;
+ $searchFormData->query = '';
+ $searchFormData->order = 'joined';
+ $searchFormData->page = 2;
+
+ $userService = $this->getUserService();
+ $actual = $userService->getFiltered($searchFormData);
+ $this->assertEquals($expected, $actual);
+ }
+
public function testValidRegistration()
{
$formData = new \Szurubooru\FormData\RegistrationFormData;
@@ -76,8 +99,10 @@ final class UserServiceTest extends \Szurubooru\Tests\AbstractTestCase
private function getUserService()
{
return new \Szurubooru\Services\UserService(
+ $this->configMock,
$this->validatorMock,
$this->userDaoMock,
+ $this->userSearchService,
$this->passwordServiceMock,
$this->emailServiceMock,
$this->timeServiceMock);