Switched to sqlite (closed #38)

This commit is contained in:
Marcin Kurczewski 2014-09-14 16:16:15 +02:00
parent d450f5794e
commit 4526345e5b
25 changed files with 303 additions and 134 deletions

View file

@ -1,6 +1,7 @@
{ {
"require": { "require": {
"mnapoli/php-di": "~4.0", "mnapoli/php-di": "~4.0",
"jbrooksuk/phpcheckstyle": "dev-master" "jbrooksuk/phpcheckstyle": "dev-master",
"lichtner/fluentpdo": "dev-master"
} }
} }

2
data/.gitignore vendored
View file

@ -1,2 +1,4 @@
db.sqlite
executed_upgrades.txt
local.ini local.ini
thumbnails thumbnails

View file

@ -11,9 +11,7 @@ activationSubject = szuru2 - account activation
activationBodyPath = mail/activation.txt activationBodyPath = mail/activation.txt
[database] [database]
host = localhost dsn = sqlite:db.sqlite
port = 27017
name = booru-dev
[security] [security]
secret = change secret = change

View file

@ -77,6 +77,10 @@ module.exports = function(grunt) {
tests: { tests: {
command: 'phpunit --strict --bootstrap src/AutoLoader.php tests/', command: 'phpunit --strict --bootstrap src/AutoLoader.php tests/',
}, },
upgrade: {
command: 'php upgrade.php',
},
}, },
cssmin: { cssmin: {
@ -130,6 +134,8 @@ module.exports = function(grunt) {
grunt.registerTask('default', ['checkstyle', 'tests']); grunt.registerTask('default', ['checkstyle', 'tests']);
grunt.registerTask('checkstyle', ['jshint', 'shell:phpcheckstyle']); grunt.registerTask('checkstyle', ['jshint', 'shell:phpcheckstyle']);
grunt.registerTask('tests', ['shell:tests']); grunt.registerTask('tests', ['shell:tests']);
grunt.registerTask('update', ['shell:upgrade']);
grunt.registerTask('upgrade', ['shell:upgrade']);
grunt.registerTask('clean', function() { grunt.registerTask('clean', function() {
fs.unlink('public_html/app.min.html'); fs.unlink('public_html/app.min.html');

View file

@ -3,25 +3,28 @@ namespace Szurubooru\Dao;
abstract class AbstractDao implements ICrudDao abstract class AbstractDao implements ICrudDao
{ {
protected $db; protected $pdo;
protected $collection; protected $fpdo;
protected $tableName;
protected $entityName; protected $entityName;
protected $entityConverter; protected $entityConverter;
public function __construct( public function __construct(
\Szurubooru\DatabaseConnection $databaseConnection, \Szurubooru\DatabaseConnection $databaseConnection,
$collectionName, $tableName,
$entityName) $entityName)
{ {
$this->entityConverter = new EntityConverter($entityName); $this->entityConverter = new EntityConverter($entityName);
$this->db = $databaseConnection->getDatabase();
$this->collection = $this->db->selectCollection($collectionName);
$this->entityName = $entityName; $this->entityName = $entityName;
$this->tableName = $tableName;
$this->pdo = $databaseConnection->getPDO();
$this->fpdo = new \FluentPDO($this->pdo);
} }
public function getCollection() public function getTableName()
{ {
return $this->collection; return $this->tableName;
} }
public function getEntityConverter() public function getEntityConverter()
@ -34,14 +37,12 @@ abstract class AbstractDao implements ICrudDao
$arrayEntity = $this->entityConverter->toArray($entity); $arrayEntity = $this->entityConverter->toArray($entity);
if ($entity->getId()) if ($entity->getId())
{ {
$savedId = $arrayEntity['_id']; $this->fpdo->update($this->tableName)->set($arrayEntity)->where('id', $entity->getId())->execute();
unset($arrayEntity['_id']);
$this->collection->update(['_id' => new \MongoId($entity->getId())], $arrayEntity, ['w' => true]);
$arrayEntity['_id'] = $savedId;
} }
else else
{ {
$this->collection->insert($arrayEntity, ['w' => true]); $this->fpdo->insertInto($this->tableName)->values($arrayEntity)->execute();
$arrayEntity['id'] = $this->pdo->lastInsertId();
} }
$entity = $this->entityConverter->toEntity($arrayEntity); $entity = $this->entityConverter->toEntity($arrayEntity);
return $entity; return $entity;
@ -50,27 +51,43 @@ abstract class AbstractDao implements ICrudDao
public function findAll() public function findAll()
{ {
$entities = []; $entities = [];
foreach ($this->collection->find() as $key => $arrayEntity) $query = $this->fpdo->from($this->tableName);
foreach ($query as $arrayEntity)
{ {
$entity = $this->entityConverter->toEntity($arrayEntity); $entity = $this->entityConverter->toEntity($arrayEntity);
$entities[$key] = $entity; $entities[$entity->getId()] = $entity;
} }
return $entities; return $entities;
} }
public function findById($entityId) public function findById($entityId)
{ {
$arrayEntity = $this->collection->findOne(['_id' => new \MongoId($entityId)]); return $this->findOneBy('id', $entityId);
return $this->entityConverter->toEntity($arrayEntity);
} }
public function deleteAll() public function deleteAll()
{ {
$this->collection->remove(); $this->fpdo->deleteFrom($this->tableName)->execute();
} }
public function deleteById($entityId) public function deleteById($entityId)
{ {
$this->collection->remove(['_id' => new \MongoId($entityId)]); return $this->deleteBy('id', $entityId);
}
protected function hasAnyRecords()
{
return count(iterator_to_array($this->fpdo->from($this->tableName)->limit(1))) > 0;
}
protected function findOneBy($columnName, $value)
{
$arrayEntity = iterator_to_array($this->fpdo->from($this->tableName)->where($columnName, $value));
return $arrayEntity ? $this->entityConverter->toEntity($arrayEntity[0]) : null;
}
protected function deleteBy($columnName, $value)
{
$this->fpdo->deleteFrom($this->tableName)->where($columnName, $value)->execute();
} }
} }

View file

@ -20,11 +20,6 @@ final class EntityConverter
$reflectionProperty->setAccessible(true); $reflectionProperty->setAccessible(true);
$arrayEntity[$reflectionProperty->getName()] = $reflectionProperty->getValue($entity); $arrayEntity[$reflectionProperty->getName()] = $reflectionProperty->getValue($entity);
} }
if ($entity->getId())
{
$arrayEntity['_id'] = $arrayEntity['id'];
unset($arrayEntity['id']);
}
return $arrayEntity; return $arrayEntity;
} }
@ -46,12 +41,6 @@ final class EntityConverter
} }
} }
$reflectionProperty = $reflectionClass->getProperty('id');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($entity, isset($arrayEntity['_id'])
? (string) $arrayEntity['_id']
: null);
return $entity; return $entity;
} }
} }

View file

@ -6,14 +6,17 @@ abstract class AbstractSearchService
const ORDER_DESC = -1; const ORDER_DESC = -1;
const ORDER_ASC = 1; const ORDER_ASC = 1;
private $collection; private $tableName;
private $entityConverter; private $entityConverter;
private $fpdo;
public function __construct( public function __construct(
\Szurubooru\DatabaseConnection $databaseConnection,
\Szurubooru\Dao\AbstractDao $dao) \Szurubooru\Dao\AbstractDao $dao)
{ {
$this->collection = $dao->getCollection(); $this->tableName = $dao->getTableName();
$this->entityConverter = $dao->getEntityConverter(); $this->entityConverter = $dao->getEntityConverter();
$this->fpdo = new \FluentPDO($databaseConnection->getPDO());
} }
public function getFiltered( public function getFiltered(
@ -31,16 +34,26 @@ abstract class AbstractSearchService
$pageSize = min(100, max(1, $searchFilter->pageSize)); $pageSize = min(100, max(1, $searchFilter->pageSize));
$pageNumber = max(1, $searchFilter->pageNumber) - 1; $pageNumber = max(1, $searchFilter->pageNumber) - 1;
$cursor = $this->collection->find($filter); //todo: clean up
$totalRecords = $cursor->count(); $orderByString = '';
$cursor->sort($order); foreach ($order as $orderColumn => $orderDir)
$cursor->skip($pageSize * $pageNumber); {
$cursor->limit($pageSize); $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 = []; $entities = [];
foreach ($cursor as $arrayEntity) foreach ($query as $arrayEntity)
$entities[] = $this->entityConverter->toEntity($arrayEntity); $entities[] = $this->entityConverter->toEntity($arrayEntity);
$query->select('COUNT(1) AS c');
$totalRecords = intval(iterator_to_array($query)[0]['c']);
return new \Szurubooru\Dao\SearchResult($searchFilter, $entities, $totalRecords); return new \Szurubooru\Dao\SearchResult($searchFilter, $entities, $totalRecords);
} }
@ -61,7 +74,7 @@ abstract class AbstractSearchService
protected function getDefaultOrderColumn() protected function getDefaultOrderColumn()
{ {
return '_id'; return 'id';
} }
protected function getDefaultOrderDir() protected function getDefaultOrderDir()

View file

@ -3,9 +3,11 @@ namespace Szurubooru\Dao\Services;
class UserSearchService extends AbstractSearchService class UserSearchService extends AbstractSearchService
{ {
public function __construct(\Szurubooru\Dao\UserDao $userDao) public function __construct(
\Szurubooru\DatabaseConnection $databaseConnection,
\Szurubooru\Dao\UserDao $userDao)
{ {
parent::__construct($userDao); parent::__construct($databaseConnection, $userDao);
} }
protected function getOrderColumn($token) protected function getOrderColumn($token)

View file

@ -10,17 +10,16 @@ class TokenDao extends AbstractDao
public function findByName($tokenName) public function findByName($tokenName)
{ {
$arrayEntity = $this->collection->findOne(['name' => $tokenName]); return $this->findOneBy('name', $tokenName);
return $this->entityConverter->toEntity($arrayEntity);
} }
public function deleteByName($tokenName) public function deleteByName($tokenName)
{ {
$this->collection->remove(['name' => $tokenName]); return $this->deleteBy('name', $tokenName);
} }
public function deleteByAdditionalData($additionalData) public function deleteByAdditionalData($additionalData)
{ {
$this->collection->remove(['additionalData' => $additionalData]); return $this->deleteBy('additionalData', $additionalData);
} }
} }

View file

@ -11,27 +11,27 @@ class UserDao extends AbstractDao implements ICrudDao
public function findByName($userName) public function findByName($userName)
{ {
$arrayEntity = $this->collection->findOne(['name' => $userName]); return $this->findOneBy('name', $userName);
return $this->entityConverter->toEntity($arrayEntity);
} }
public function findByEmail($userEmail, $allowUnconfirmed = false) public function findByEmail($userEmail, $allowUnconfirmed = false)
{ {
$arrayEntity = $this->collection->findOne(['email' => $userEmail]); $result = $this->findOneBy('email', $userEmail);
if (!$arrayEntity and $allowUnconfirmed) if (!$result and $allowUnconfirmed)
$arrayEntity = $this->collection->findOne(['emailUnconfirmed' => $userEmail]); {
return $this->entityConverter->toEntity($arrayEntity); $result = $this->findOneBy('emailUnconfirmed', $userEmail);
}
return $result;
} }
public function hasAnyUsers() public function hasAnyUsers()
{ {
return (bool) $this->collection->findOne(); return $this->hasAnyRecords();
} }
public function deleteByName($userName) public function deleteByName($userName)
{ {
$this->collection->remove(['name' => $userName]); $this->deleteBy('name', $userName);
$tokens = $this->db->selectCollection('tokens'); $this->fpdo->deleteFrom('tokens')->where('additionalData', $userName);
$tokens->remove(['additionalData' => $userName]);
} }
} }

View file

@ -3,32 +3,35 @@ namespace Szurubooru;
final class DatabaseConnection final class DatabaseConnection
{ {
private $database; private $pdo;
private $connection; private $config;
public function __construct(\Szurubooru\Config $config) public function __construct(\Szurubooru\Config $config)
{ {
$connectionString = $this->getConnectionString($config); $this->config = $config;
$this->connection = new \MongoClient($connectionString);
$this->database = $this->connection->selectDb($config->database->name);
} }
public function getConnection() public function getPDO()
{ {
return $this->connection; if (!$this->pdo)
{
$this->createPDO();
}
return $this->pdo;
} }
public function getDatabase() public function close()
{ {
return $this->database; $this->pdo = null;
} }
private function getConnectionString(\Szurubooru\Config $config) private function createPDO()
{ {
return sprintf( $cwd = getcwd();
'mongodb://%s:%d/%s', if ($this->config->getDataDirectory())
$config->database->host, chdir($this->config->getDataDirectory());
$config->database->port, $this->pdo = new \PDO($this->config->database->dsn);
$config->database->name); $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
chdir($cwd);
} }
} }

View file

@ -3,9 +3,9 @@ namespace Szurubooru\Entities;
final class Token extends Entity final class Token extends Entity
{ {
const PURPOSE_LOGIN = 'login'; const PURPOSE_LOGIN = 0;
const PURPOSE_ACTIVATE = 'activate'; const PURPOSE_ACTIVATE = 1;
const PURPOSE_PASSWORD_RESET = 'passwordReset'; const PURPOSE_PASSWORD_RESET = 2;
protected $name; protected $name;
protected $purpose; protected $purpose;

View file

@ -0,0 +1,75 @@
<?php
namespace Szurubooru\Services;
final class UpgradeService
{
private $config;
private $upgrades;
private $databaseConnection;
private $executedUpgradeNames = [];
public function __construct(
\Szurubooru\Config $config,
\Szurubooru\DatabaseConnection $databaseConnection,
\Szurubooru\Upgrades\UpgradeRepository $upgradeRepository)
{
$this->config = $config;
$this->databaseConnection = $databaseConnection;
$this->upgrades = $upgradeRepository->getUpgrades();
$this->loadExecutedUpgradeNames();
}
public function runUpgradesVerbose()
{
$this->runUpgrades(true);
}
public function runUpgradesQuiet()
{
$this->runUpgrades(false);
}
private function runUpgrades($verbose)
{
foreach ($this->upgrades as $upgrade)
{
if ($this->isUpgradeNeeded($upgrade))
{
if ($verbose)
echo 'Running ' . get_class($upgrade) . PHP_EOL;
$this->runUpgrade($upgrade);
}
}
}
private function isUpgradeNeeded(\Szurubooru\Upgrades\IUpgrade $upgrade)
{
return !in_array(get_class($upgrade), $this->executedUpgradeNames);
}
private function runUpgrade(\Szurubooru\Upgrades\IUpgrade $upgrade)
{
$upgrade->run($this->databaseConnection);
$this->executedUpgradeNames[] = get_class($upgrade);
$this->saveExecutedUpgradeNames();
}
private function loadExecutedUpgradeNames()
{
$infoFilePath = $this->getExecutedUpgradeNamesFilePath();
if (!file_exists($infoFilePath))
return;
$this->executedUpgradeNames = explode("\n", file_get_contents($infoFilePath));
}
private function saveExecutedUpgradeNames()
{
$infoFilePath = $this->getExecutedUpgradeNamesFilePath();
file_put_contents($infoFilePath, implode("\n", $this->executedUpgradeNames));
}
private function getExecutedUpgradeNamesFilePath()
{
return $this->config->getDataDirectory() . DIRECTORY_SEPARATOR . 'executed_upgrades.txt';
}
}

View file

@ -1,29 +0,0 @@
<?php
namespace Szurubooru;
final class UpgradeService
{
private $db;
public function __construct(\Szurubooru\DatabaseConnection $databaseConnection)
{
$this->db = $databaseConnection->getDatabase();
}
public function prepareForUsage()
{
$this->db->createCollection('posts');
}
public function removeAllData()
{
foreach ($this->db->getCollectionNames() as $collectionName)
$this->removeCollectionData($collectionName);
}
private function removeCollectionData($collectionName)
{
$this->db->$collectionName->remove();
$this->db->$collectionName->deleteIndexes();
}
}

View file

@ -0,0 +1,7 @@
<?php
namespace Szurubooru\Upgrades;
interface IUpgrade
{
public function run(\Szurubooru\DatabaseConnection $databaseConnection);
}

View file

@ -0,0 +1,40 @@
<?php
namespace Szurubooru\Upgrades;
class Upgrade01 implements IUpgrade
{
public function run(\Szurubooru\DatabaseConnection $databaseConnection)
{
$databaseConnection->getPDO()->exec('
CREATE TABLE "users"
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
passwordHash TEXT NOT NULL,
email TEXT,
emailUnconfirmed TEXT,
accessRank INTEGER NOT NULL,
browsingSettings TEXT,
banned INTEGER,
registrationTime INTEGER DEFAULT NULL,
lastLoginTime INTEGER DEFAULT NULL,
avatarStyle INTEGER DEFAULT 1
);');
$databaseConnection->getPDO()->exec('
CREATE TABLE "tokens"
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
purpose INTEGER NOT NULL,
additionalData TEXT
);');
$databaseConnection->getPDO()->exec('
CREATE TABLE "posts"
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL
);');
}
}

View file

@ -0,0 +1,17 @@
<?php
namespace Szurubooru\Upgrades;
class UpgradeRepository
{
private $upgrades = [];
public function __construct(array $upgrades)
{
$this->upgrades = $upgrades;
}
public function getUpgrades()
{
return $this->upgrades;
}
}

View file

@ -5,6 +5,13 @@ return [
\Szurubooru\Config::class => DI\object()->constructor($dataDirectory), \Szurubooru\Config::class => DI\object()->constructor($dataDirectory),
\Szurubooru\ControllerRepository::class => DI\object()->constructor(DI\link('controllers')), \Szurubooru\ControllerRepository::class => DI\object()->constructor(DI\link('controllers')),
\Szurubooru\Upgrades\UpgradeRepository::class => DI\object()->constructor(DI\link('upgrades')),
'upgrades' => DI\factory(function (DI\container $container) {
return [
$container->get(\Szurubooru\Upgrades\Upgrade01::class),
];
}),
'controllers' => DI\factory(function (DI\container $container) { 'controllers' => DI\factory(function (DI\container $container) {
return [ return [

View file

@ -4,24 +4,24 @@ namespace Szurubooru\Tests;
abstract class AbstractDatabaseTestCase extends \Szurubooru\Tests\AbstractTestCase abstract class AbstractDatabaseTestCase extends \Szurubooru\Tests\AbstractTestCase
{ {
protected $databaseConnection; protected $databaseConnection;
protected $upgradeService;
public function setUp() public function setUp()
{ {
$host = 'localhost'; parent::setUp();
$port = 27017; $config = $this->mockConfig($this->createTestDirectory());
$database = 'test'; $config->set('database/dsn', 'sqlite::memory:');
$config = $this->mockConfig();
$config->set('database/host', 'localhost');
$config->set('database/port', '27017');
$config->set('database/name', 'test');
$this->databaseConnection = new \Szurubooru\DatabaseConnection($config); $this->databaseConnection = new \Szurubooru\DatabaseConnection($config);
$this->upgradeService = new \Szurubooru\UpgradeService($this->databaseConnection);
$this->upgradeService->prepareForUsage(); $upgradeRepository = \Szurubooru\Injector::get(\Szurubooru\Upgrades\UpgradeRepository::class);
$upgradeService = new \Szurubooru\Services\UpgradeService($config, $this->databaseConnection, $upgradeRepository);
$upgradeService->runUpgradesQuiet();
} }
public function tearDown() public function tearDown()
{ {
$this->upgradeService->removeAllData(); parent::tearDown();
if ($this->databaseConnection)
$this->databaseConnection->close();
} }
} }

View file

@ -54,4 +54,9 @@ abstract class AbstractTestCase extends \PHPUnit_Framework_TestCase
} }
} }
require_once __DIR__
. DIRECTORY_SEPARATOR . '..'
. DIRECTORY_SEPARATOR . 'vendor'
. DIRECTORY_SEPARATOR . 'autoload.php';
date_default_timezone_set('UTC'); date_default_timezone_set('UTC');

View file

@ -1,11 +1,6 @@
<?php <?php
namespace Szurubooru\Tests; namespace Szurubooru\Tests;
require_once __DIR__
. DIRECTORY_SEPARATOR . '..'
. DIRECTORY_SEPARATOR . 'vendor'
. DIRECTORY_SEPARATOR . 'autoload.php';
class ControllerRepositoryTest extends \Szurubooru\Tests\AbstractTestCase class ControllerRepositoryTest extends \Szurubooru\Tests\AbstractTestCase
{ {
public function testInjection() public function testInjection()

View file

@ -23,11 +23,9 @@ class UserSearchServiceTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
public function testSorting() public function testSorting()
{ {
$user1 = new \Szurubooru\Entities\User(); $user1 = $this->getTestUser('reginald');
$user1->setName('reginald'); $user2 = $this->getTestUser('beartato');
$user1->setRegistrationTime(date('c', mktime(3, 2, 1))); $user1->setRegistrationTime(date('c', mktime(3, 2, 1)));
$user2 = new \Szurubooru\Entities\User();
$user2->setName('beartato');
$user2->setRegistrationTime(date('c', mktime(1, 2, 3))); $user2->setRegistrationTime(date('c', mktime(1, 2, 3)));
$this->userDao->save($user1); $this->userDao->save($user1);
@ -62,6 +60,17 @@ class UserSearchServiceTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
private function getUserSearchService() private function getUserSearchService()
{ {
return new \Szurubooru\Dao\Services\UserSearchService($this->userDao); return new \Szurubooru\Dao\Services\UserSearchService($this->databaseConnection, $this->userDao);
}
private function getTestUser($userName)
{
$user = new \Szurubooru\Entities\User();
$user->setName($userName);
$user->setPasswordHash('whatever');
$user->setLastLoginTime('whatever');
$user->setRegistrationTime('whatever');
$user->setAccessRank('whatever');
return $user;
} }
} }

View file

@ -9,6 +9,7 @@ final class TokenDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
$token = new \Szurubooru\Entities\Token(); $token = new \Szurubooru\Entities\Token();
$token->setName('test'); $token->setName('test');
$token->setPurpose(\Szurubooru\Entities\Token::PURPOSE_LOGIN);
$tokenDao->save($token); $tokenDao->save($token);
$expected = $token; $expected = $token;

View file

@ -7,13 +7,11 @@ final class UserDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
{ {
$userDao = $this->getUserDao(); $userDao = $this->getUserDao();
$user = new \Szurubooru\Entities\User(); $user = $this->getTestUser();
$user->setName('test');
$userDao->save($user); $userDao->save($user);
$expected = $user; $expected = $user;
$actual = $userDao->findByName($user->getName()); $actual = $userDao->findByName($user->getName());
$this->assertEquals($actual, $expected); $this->assertEquals($actual, $expected);
} }
@ -29,13 +27,10 @@ final class UserDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
public function testCheckingUserPresence() public function testCheckingUserPresence()
{ {
$userDao = $this->getUserDao(); $userDao = $this->getUserDao();
$this->assertFalse($userDao->hasAnyUsers()); $this->assertFalse($userDao->hasAnyUsers());
$user = new \Szurubooru\Entities\User(); $user = $this->getTestUser();
$user->setName('test');
$userDao->save($user); $userDao->save($user);
$this->assertTrue($userDao->hasAnyUsers()); $this->assertTrue($userDao->hasAnyUsers());
} }
@ -43,4 +38,15 @@ final class UserDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
{ {
return new \Szurubooru\Dao\UserDao($this->databaseConnection); return new \Szurubooru\Dao\UserDao($this->databaseConnection);
} }
private function getTestUser()
{
$user = new \Szurubooru\Entities\User();
$user->setName('test');
$user->setPasswordHash('whatever');
$user->setLastLoginTime('whatever');
$user->setRegistrationTime('whatever');
$user->setAccessRank('whatever');
return $user;
}
} }

6
upgrade.php Normal file
View file

@ -0,0 +1,6 @@
<?php
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php');
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'AutoLoader.php');
$upgradeService = Szurubooru\Injector::get(\Szurubooru\Services\UpgradeService::class);
$upgradeService->runUpgradesVerbose();