Compare commits

...
Author SHA1 Message Date
bence a4c77c3d32 Merged in bugfix/MAPG-196-fix-compatibility-issues (pull request #180)
MAPG-196 revert link preload to plain stylesheet because it is not supported everywhere
2020-07-06 19:15:32 +00:00
bence 317329ae84 MAPG-196 revert link preload to plain stylesheet because it is not supported everywhere 2020-07-06 21:12:56 +02:00
bence 234cb7f086 Merged in feature/MAPG-196-fix-issues-reported-by-lighthouse (pull request #179)
Feature/MAPG-196 fix issues reported by lighthouse
2020-07-06 18:05:51 +00:00
bence 66c709f00d MAPG-196 reposition of cookie notice 2020-07-06 20:04:39 +02:00
bence 2737c7d6d6 MAPG-196 speed up asset loading, add missing description, add missing image alts 2020-07-06 20:04:39 +02:00
bence 2ccee26424 Merged in feature/MAPG-199-static-analyser-save-artifact (pull request #178)
MAPG-199 save static code analysis results as artifact
2020-07-06 16:52:21 +00:00
bence 8cbf611189 MAPG-199 save static code analysis results as artifact 2020-07-06 18:50:17 +02:00
bence 2ac9794e3f Merged in feature/MAPG-199-introduce-static-php-analyser (pull request #177)
Feature/MAPG-199 introduce static php analyser
2020-07-05 21:23:24 +00:00
bence 9e5f7405d1 MAPG-199 move test views to another folder to prevent code analysis errors 2020-07-05 23:18:57 +02:00
bence af98d71924 MAPG-199 fix issues found by PHPStan 2020-07-05 23:18:56 +02:00
bence 39d691fd7f MAPG-199 add static code analysis step to pipeline 2020-07-05 22:51:36 +02:00
bence 405488cf4e MAPG-199 add PHPStan to require-dev 2020-07-05 21:35:49 +02:00
bence f2736d4d6e Merged in hotfix/MAPG-198-fix-not-working-game (pull request #176)
MAPG-198 re-add table name to Select
2020-07-05 19:19:53 +00:00
bence 88b9821c61 MAPG-198 re-add table name to Select
(table name is used when counting)
2020-07-05 21:17:29 +02:00
53 changed files with 203 additions and 87 deletions

No files matched your search

-1
View File
@@ -1,4 +1,3 @@
.env .env
installed installed
unit_test_results.xml
vendor vendor
+11
View File
@@ -13,3 +13,14 @@ pipelines:
- curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
- composer install - composer install
- vendor/bin/phpunit --log-junit unit_test_results.xml --testdox tests - vendor/bin/phpunit --log-junit unit_test_results.xml --testdox tests
- step:
name: Static Code Analysis
caches:
- composer
artifacts:
- static_code_analysis_results.json
script:
- apt-get update && apt-get install -y unzip
- curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
- composer install
- vendor/bin/phpstan analyse -c phpstan.neon --error-format=prettyJson > static_code_analysis_results.json
+2 -1
View File
@@ -9,7 +9,8 @@
"phpmailer/phpmailer": "^6.1" "phpmailer/phpmailer": "^6.1"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^9" "phpunit/phpunit": "^9",
"phpstan/phpstan": "^0.12.32"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
Generated
+57 -1
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "fb37b0b958cdf02d82468cb4596613ad", "content-hash": "34563bfc619f47473b2e37a5639dd63e",
"packages": [ "packages": [
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
@@ -1379,6 +1379,62 @@
], ],
"time": "2020-03-05T15:02:03+00:00" "time": "2020-03-05T15:02:03+00:00"
}, },
{
"name": "phpstan/phpstan",
"version": "0.12.32",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "d03863f504c8432b3de4d1881f73f6acb8c0e67c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/d03863f504c8432b3de4d1881f73f6acb8c0e67c",
"reference": "d03863f504c8432b3de4d1881f73f6acb8c0e67c",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"conflict": {
"phpstan/phpstan-shim": "*"
},
"bin": [
"phpstan",
"phpstan.phar"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.12-dev"
}
},
"autoload": {
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPStan - PHP Static Analysis Tool",
"funding": [
{
"url": "https://github.com/ondrejmirtes",
"type": "github"
},
{
"url": "https://www.patreon.com/phpstan",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan",
"type": "tidelift"
}
],
"time": "2020-07-01T11:57:52+00:00"
},
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "8.0.2", "version": "8.0.2",
+9
View File
@@ -0,0 +1,9 @@
parameters:
level: 5
checkMissingIterableValueType: false
paths:
- main.php
- mapg
- web.php
- src
- tests
+8
View File
@@ -404,9 +404,17 @@ div.buttonContainer>button {
} }
#cookiesNotice { #cookiesNotice {
position: fixed;
left: 0;
bottom: 0;
right: 0;
margin: 20px;
background-color: #eeeeee; background-color: #eeeeee;
border: solid #888888 1px;
border-radius: 3px;
padding: 10px; padding: 10px;
text-align: center; text-align: center;
z-index: 10;
} }
#loading { #loading {
+1 -1
View File
@@ -10,7 +10,7 @@ use Symfony\Component\Console\Output\OutputInterface;
class AddUserCommand extends Command class AddUserCommand extends Command
{ {
public function configure() public function configure(): void
{ {
$this->setName('user:add') $this->setName('user:add')
->setDescription('Adding of user.') ->setDescription('Adding of user.')
+2 -2
View File
@@ -11,7 +11,7 @@ use Symfony\Component\Console\Output\OutputInterface;
class LinkViewCommand extends Command class LinkViewCommand extends Command
{ {
public function configure() public function configure(): void
{ {
$this->setName('view:link') $this->setName('view:link')
->setDescription('Linking of views.') ->setDescription('Linking of views.')
@@ -39,7 +39,7 @@ class LinkViewCommand extends Command
$view = substr($file->getPath(), $folderLength) . '/' . $file->getBasename('.php'); $view = substr($file->getPath(), $folderLength) . '/' . $file->getBasename('.php');
if (strpos($view, 'templates') === 0) { if (strpos($view, 'templates') === 0 || strpos($view, 'tests') === 0) {
continue; continue;
} }
+5 -5
View File
@@ -14,7 +14,7 @@ use Symfony\Component\Console\Output\OutputInterface;
class MaintainDatabaseCommand extends Command class MaintainDatabaseCommand extends Command
{ {
private PersistentDataManager $persistentDataManager; private PersistentDataManager $pdm;
private UserRepository $userRepository; private UserRepository $userRepository;
@@ -26,13 +26,13 @@ class MaintainDatabaseCommand extends Command
{ {
parent::__construct(); parent::__construct();
$this->persistentDataManager = new PersistentDataManager(); $this->pdm = new PersistentDataManager();
$this->userRepository = new UserRepository(); $this->userRepository = new UserRepository();
$this->userConfirmationRepository = new UserConfirmationRepository(); $this->userConfirmationRepository = new UserConfirmationRepository();
$this->userPasswordResetterRepository = new UserPasswordResetterRepository(); $this->userPasswordResetterRepository = new UserPasswordResetterRepository();
} }
public function configure() public function configure(): void
{ {
$this->setName('db:maintain') $this->setName('db:maintain')
->setDescription('Maintain database.'); ->setDescription('Maintain database.');
@@ -76,7 +76,7 @@ class MaintainDatabaseCommand extends Command
$this->pdm->deleteFromDb($userPasswordResetter); $this->pdm->deleteFromDb($userPasswordResetter);
} }
$this->persistentDataManager->deleteFromDb($user); $this->pdm->deleteFromDb($user);
} }
\Container::$dbConnection->commit(); \Container::$dbConnection->commit();
@@ -85,7 +85,7 @@ class MaintainDatabaseCommand extends Command
private function deleteExpiredPasswordResetters(): void private function deleteExpiredPasswordResetters(): void
{ {
foreach ($this->userPasswordResetterRepository->getAllExpired() as $passwordResetter) { foreach ($this->userPasswordResetterRepository->getAllExpired() as $passwordResetter) {
$this->persistentDataManager->deleteFromDb($passwordResetter); $this->pdm->deleteFromDb($passwordResetter);
} }
} }
+5 -1
View File
@@ -9,7 +9,7 @@ use Symfony\Component\Console\Output\OutputInterface;
class MigrateDatabaseCommand extends Command class MigrateDatabaseCommand extends Command
{ {
public function configure() public function configure(): void
{ {
$this->setName('db:migrate') $this->setName('db:migrate')
->setDescription('Migration of database changes.'); ->setDescription('Migration of database changes.');
@@ -88,6 +88,10 @@ class MigrateDatabaseCommand extends Command
$path = ROOT . '/database/migrations/' . $type; $path = ROOT . '/database/migrations/' . $type;
$dir = opendir($path); $dir = opendir($path);
if ($dir === false) {
throw new \Exception('Cannot open dir: ' . $path);
}
$files = []; $files = [];
while ($file = readdir($dir)) { while ($file = readdir($dir)) {
$filePath = $path . '/' . $file; $filePath = $path . '/' . $file;
+1 -1
View File
@@ -32,7 +32,7 @@ class GameController
return new JsonContent($this->prepareGame($mapId)); return new JsonContent($this->prepareGame($mapId));
} }
private function prepareGame(int $mapId) private function prepareGame(int $mapId): array
{ {
$map = $this->mapRepository->getById($mapId); $map = $this->mapRepository->getById($mapId);
+1 -1
View File
@@ -128,7 +128,7 @@ class GameFlowController
]); ]);
} }
private function addNewRoundToState(&$state, Place $place, array $placesWithoutPano): void private function addNewRoundToState(array &$state, Place $place, array $placesWithoutPano): void
{ {
$state['rounds'][] = [ $state['rounds'][] = [
'placesWithoutPano' => $placesWithoutPano, 'placesWithoutPano' => $placesWithoutPano,
+1 -1
View File
@@ -161,7 +161,7 @@ class MapAdminController implements ISecured
return new JsonContent(['mapId' => $map->getId(), 'added' => $addedIds]); return new JsonContent(['mapId' => $map->getId(), 'added' => $addedIds]);
} }
public function deleteMap() public function deleteMap(): IContent
{ {
$mapId = (int) $this->request->query('mapId'); $mapId = (int) $this->request->query('mapId');
+1 -1
View File
@@ -210,7 +210,7 @@ class UserController implements ISecured
return new JsonContent(['success' => true]); return new JsonContent(['success' => true]);
} }
private function confirmUserIdentity(User $user, ?DateTime $authenticatedWithGoogleUntil, ?string $password, &$error): bool private function confirmUserIdentity(User $user, ?DateTime $authenticatedWithGoogleUntil, ?string $password, string &$error): bool
{ {
if ($authenticatedWithGoogleUntil !== null && $authenticatedWithGoogleUntil > new DateTime()) { if ($authenticatedWithGoogleUntil !== null && $authenticatedWithGoogleUntil > new DateTime()) {
return true; return true;
+2 -2
View File
@@ -12,11 +12,11 @@ class Connection implements IConnection
public function __construct(string $host, string $user, string $password, string $db, int $port = -1, string $socket = null) public function __construct(string $host, string $user, string $password, string $db, int $port = -1, string $socket = null)
{ {
if ($port < 0) { if ($port < 0) {
$port = ini_get('mysqli.default_port'); $port = (int) ini_get('mysqli.default_port');
} }
if ($socket === null) { if ($socket === null) {
$socket = ini_get('mysqli.default_socket'); $socket = (string) ini_get('mysqli.default_socket');
} }
$this->connection = new mysqli($host, $user, $password, $db, $port, $socket); $this->connection = new mysqli($host, $user, $password, $db, $port, $socket);
+5 -5
View File
@@ -30,7 +30,7 @@ class Select
private array $orders = []; private array $orders = [];
private array $limit; private ?array $limit;
public function __construct(IConnection $connection, ?string $table = null) public function __construct(IConnection $connection, ?string $table = null)
{ {
@@ -144,7 +144,7 @@ class Select
$this->limit = null; $this->limit = null;
} }
public function paginate(int $page, int $itemsPerPage) public function paginate(int $page, int $itemsPerPage): Select
{ {
$this->limit($itemsPerPage, ($page - 1) * $itemsPerPage); $this->limit($itemsPerPage, ($page - 1) * $itemsPerPage);
@@ -308,7 +308,7 @@ class Select
return implode(' ', $joins); return implode(' ', $joins);
} }
private function generateConditions(string $type): array private function generateConditions(int $type): array
{ {
$conditions = ''; $conditions = '';
$params = []; $params = [];
@@ -376,9 +376,9 @@ class Select
return [$conditionsString, $params]; return [$conditionsString, $params];
} }
private function generateComplexConditionFragment(string $type, Closure $conditionCallback): array private function generateComplexConditionFragment(int $type, Closure $conditionCallback): array
{ {
$instance = new static($this->connection, $this->table); $instance = new self($this->connection, $this->table);
$instance->tableAliases = $this->tableAliases; $instance->tableAliases = $this->tableAliases;
$conditionCallback($instance); $conditionCallback($instance);
+2 -1
View File
@@ -1,7 +1,8 @@
<?php namespace MapGuesser\Database; <?php namespace MapGuesser\Database;
class Utils { class Utils {
public static function backtick(string $name) { public static function backtick(string $name): string
{
return '`' . $name . '`'; return '`' . $name . '`';
} }
} }
+5 -5
View File
@@ -29,7 +29,7 @@ class Request implements IRequest
$this->method = $method; $this->method = $method;
} }
public function setQuery($query) public function setQuery($query): void
{ {
if (is_string($query)) { if (is_string($query)) {
$this->query = $query; $this->query = $query;
@@ -38,7 +38,7 @@ class Request implements IRequest
} }
} }
public function setHeaders(array $headers) public function setHeaders(array $headers): void
{ {
$this->headers = array_merge($this->headers, $headers); $this->headers = array_merge($this->headers, $headers);
} }
@@ -47,13 +47,13 @@ class Request implements IRequest
{ {
$ch = curl_init(); $ch = curl_init();
if ($this->method === self::HTTP_GET) { if ($this->method === self::HTTP_POST) {
$url = $this->url . '?' . $this->query;
} elseif ($this->method === self::HTTP_POST) {
$url = $this->url; $url = $this->url;
curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->query); curl_setopt($ch, CURLOPT_POSTFIELDS, $this->query);
} else {
$url = $this->url . '?' . $this->query;
} }
curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_URL, $url);
+2 -2
View File
@@ -14,12 +14,12 @@ class Response implements IResponse
$this->headers = $headers; $this->headers = $headers;
} }
public function getBody() public function getBody(): string
{ {
return $this->body; return $this->body;
} }
public function getHeaders() public function getHeaders(): array
{ {
return $this->headers; return $this->headers;
} }
+2 -2
View File
@@ -10,9 +10,9 @@ interface IRequest
public function setMethod(int $method): void; public function setMethod(int $method): void;
public function setQuery($query); public function setQuery($query): void;
public function setHeaders(array $headers); public function setHeaders(array $headers): void;
public function send(): IResponse; public function send(): IResponse;
} }
+2 -2
View File
@@ -2,7 +2,7 @@
interface IResponse interface IResponse
{ {
public function getBody(); public function getBody(): string;
public function getHeaders(); public function getHeaders(): array;
} }
+1 -1
View File
@@ -4,7 +4,7 @@ use MapGuesser\Interfaces\Authentication\IUser;
interface IRequest interface IRequest
{ {
public function setParsedRouteParams(array &$routeParams); public function setParsedRouteParams(array &$routeParams): void;
public function getBase(): string; public function getBase(): string;
+1 -1
View File
@@ -77,7 +77,7 @@ class Mail
} }
} }
private function sendMail(PHPMailer $mailer, array $recipient) private function sendMail(PHPMailer $mailer, array $recipient): void
{ {
$mailer->clearAddresses(); $mailer->clearAddresses();
$mailer->addAddress($recipient[0], $recipient[1]); $mailer->addAddress($recipient[0], $recipient[1]);
+3 -3
View File
@@ -4,9 +4,9 @@ use MapGuesser\Interfaces\Http\IRequest;
class GoogleOAuth class GoogleOAuth
{ {
private static $dialogUrlBase = 'https://accounts.google.com/o/oauth2/v2/auth'; private static string $dialogUrlBase = 'https://accounts.google.com/o/oauth2/v2/auth';
private static $tokenUrlBase = 'https://oauth2.googleapis.com/token'; private static string $tokenUrlBase = 'https://oauth2.googleapis.com/token';
private IRequest $request; private IRequest $request;
@@ -36,7 +36,7 @@ class GoogleOAuth
return self::$dialogUrlBase . '?' . http_build_query($oauthParams); return self::$dialogUrlBase . '?' . http_build_query($oauthParams);
} }
public function getToken(string $code, string $redirectUrl) public function getToken(string $code, string $redirectUrl): array
{ {
$tokenParams = [ $tokenParams = [
'code' => $code, 'code' => $code,
+8 -4
View File
@@ -45,9 +45,9 @@ class User extends Model implements IUser
} }
} }
public function setActive($active): void public function setActive(bool $active): void
{ {
$this->active = (bool) $active; $this->active = $active;
} }
public function setGoogleSub(?string $googleSub): void public function setGoogleSub(?string $googleSub): void
@@ -105,10 +105,10 @@ class User extends Model implements IUser
switch ($permission) { switch ($permission) {
case IUser::PERMISSION_NORMAL: case IUser::PERMISSION_NORMAL:
return true; return true;
break;
case IUser::PERMISSION_ADMIN: case IUser::PERMISSION_ADMIN:
return $this->type === 'admin'; return $this->type === 'admin';
break; default:
throw new \Exception('Permission does not exist: ' . $permission);
} }
} }
@@ -124,6 +124,10 @@ class User extends Model implements IUser
public function checkPassword(string $password): bool public function checkPassword(string $password): bool
{ {
if ($this->password === null) {
return false;
}
return password_verify($password, $this->password); return password_verify($password, $this->password);
} }
} }
+2 -2
View File
@@ -8,7 +8,7 @@ use MapGuesser\PersistentData\Model\Model;
class PersistentDataManager class PersistentDataManager
{ {
public function selectFromDb(Select $select, string $type, bool $withRelations = false): ?Model public function selectFromDb(Select $select, string $type, bool $withRelations = false)
{ {
$select = $this->createSelect($select, $type, $withRelations); $select = $this->createSelect($select, $type, $withRelations);
@@ -37,7 +37,7 @@ class PersistentDataManager
} }
} }
public function selectFromDbById($id, string $type, bool $withRelations = false): ?Model public function selectFromDbById($id, string $type, bool $withRelations = false)
{ {
$select = new Select(\Container::$dbConnection); $select = new Select(\Container::$dbConnection);
$select->whereId($id); $select->whereId($id);
+10 -3
View File
@@ -46,13 +46,20 @@ class PlaceRepository
return $place; return $place;
} }
private function selectRandomFromDbForMap(int $mapId, array $exclude): ?Place private function selectRandomFromDbForMap(int $mapId, array $exclude): Place
{ {
$select = new Select(\Container::$dbConnection); //TODO: omit table name here
$select = new Select(\Container::$dbConnection, 'places');
$select->where('id', 'NOT IN', $exclude); $select->where('id', 'NOT IN', $exclude);
$select->where('map_id', '=', $mapId); $select->where('map_id', '=', $mapId);
$numberOfPlaces = $select->count(); // TODO: what if 0 $numberOfPlaces = $select->count();
//TODO: prevent this
if ($numberOfPlaces === 0) {
throw new \Exception('There is no selectable place (count was 0).');
}
$randomOffset = random_int(0, $numberOfPlaces - 1); $randomOffset = random_int(0, $numberOfPlaces - 1);
$select->orderBy('id'); $select->orderBy('id');
+1 -1
View File
@@ -39,7 +39,7 @@ class Request implements IRequest
} }
} }
public function setParsedRouteParams(array &$routeParams) public function setParsedRouteParams(array &$routeParams): void
{ {
$this->routeParams = &$routeParams; $this->routeParams = &$routeParams;
} }
+4 -4
View File
@@ -11,12 +11,12 @@ class Session implements ISession
$this->data = &$data; $this->data = &$data;
} }
public function has($key): bool public function has(string $key): bool
{ {
return isset($this->data[$key]); return isset($this->data[$key]);
} }
public function get($key) public function get(string $key)
{ {
if (isset($this->data[$key])) { if (isset($this->data[$key])) {
return $this->data[$key]; return $this->data[$key];
@@ -25,12 +25,12 @@ class Session implements ISession
return null; return null;
} }
public function set($key, $value): void public function set(string $key, $value): void
{ {
$this->data[$key] = $value; $this->data[$key] = $value;
} }
public function delete($key): void public function delete(string $key): void
{ {
unset($this->data[$key]); unset($this->data[$key]);
} }
+1
View File
@@ -23,6 +23,7 @@ class HtmlContent extends ContentBase
require ROOT . '/cache/views/' . $this->view . '.php'; require ROOT . '/cache/views/' . $this->view . '.php';
// @phpstan-ignore-next-line - SCRIPT_STARTED is defined in main.php
echo '<!-- __debug__runtime: ' . round((hrtime(true) - SCRIPT_STARTED) / 1e+6, 1) . ' -->'; echo '<!-- __debug__runtime: ' . round((hrtime(true) - SCRIPT_STARTED) / 1e+6, 1) . ' -->';
} }
+1
View File
@@ -9,6 +9,7 @@ class JsonContent extends ContentBase
public function render(): void public function render(): void
{ {
// @phpstan-ignore-next-line - SCRIPT_STARTED is defined in main.php
$this->data['__debug__runtime'] = round((hrtime(true) - SCRIPT_STARTED) / 1e+6, 1); $this->data['__debug__runtime'] = round((hrtime(true) - SCRIPT_STARTED) / 1e+6, 1);
echo json_encode($this->data); echo json_encode($this->data);
+1 -1
View File
@@ -16,7 +16,7 @@ class Redirect implements IRedirect
public function getUrl(): string public function getUrl(): string
{ {
if (preg_match('/^http(s)?/', $this->target)) { if (preg_match('/^http(s)?/', $this->target) === 1) {
$link = $this->target; $link = $this->target;
} else { } else {
$link = \Container::$request->getBase() . '/' . $this->target; $link = \Container::$request->getBase() . '/' . $this->target;
+2 -2
View File
@@ -30,7 +30,7 @@ class Route
$link = []; $link = [];
foreach ($this->pattern as $fragment) { foreach ($this->pattern as $fragment) {
if (preg_match('/^{(\\w+)(\\?)?}$/', $fragment, $matches)) { if (preg_match('/^{(\\w+)(\\?)?}$/', $fragment, $matches) === 1) {
if (isset($parameters[$matches[1]])) { if (isset($parameters[$matches[1]])) {
$link[] = $parameters[$matches[1]]; $link[] = $parameters[$matches[1]];
unset($parameters[$matches[1]]); unset($parameters[$matches[1]]);
@@ -61,7 +61,7 @@ class Route
$parameters = []; $parameters = [];
foreach ($path as $i => $fragment) { foreach ($path as $i => $fragment) {
if (preg_match('/^{(\\w+)(?:\\?)?}$/', $this->pattern[$i], $matches)) { if (preg_match('/^{(\\w+)(?:\\?)?}$/', $this->pattern[$i], $matches) === 1) {
$parameters[$matches[1]] = $fragment; $parameters[$matches[1]] = $fragment;
} elseif ($fragment != $this->pattern[$i]) { } elseif ($fragment != $this->pattern[$i]) {
return null; return null;
+1 -1
View File
@@ -76,7 +76,7 @@ class RouteCollection
$this->searchTable[$method][$groupNumber][] = $route; $this->searchTable[$method][$groupNumber][] = $route;
while (preg_match('/^{\\w+\\?}$/', end($pattern))) { while (preg_match('/^{\\w+\\?}$/', end($pattern)) === 1) {
$groupNumber--; $groupNumber--;
array_pop($pattern); array_pop($pattern);
+2 -2
View File
@@ -69,7 +69,7 @@ class DatabaseSessionHandler implements ISessionHandler
return true; return true;
} }
public function gc($maxlifetime): int public function gc($maxlifetime): bool
{ {
// empty on purpose // empty on purpose
// old sessions are deleted by MaintainDatabaseCommand // old sessions are deleted by MaintainDatabaseCommand
@@ -84,7 +84,7 @@ class DatabaseSessionHandler implements ISessionHandler
public function validateId($id): bool public function validateId($id): bool
{ {
return preg_match('/^[a-f0-9]{32}$/', $id); return preg_match('/^[a-f0-9]{32}$/', $id) === 1;
} }
public function updateTimestamp($id, $data): bool public function updateTimestamp($id, $data): bool
+1 -1
View File
@@ -27,7 +27,7 @@ class Bounds
public static function createDirectly(float $southLat, float $westLng, float $northLat, float $eastLng): Bounds public static function createDirectly(float $southLat, float $westLng, float $northLat, float $eastLng): Bounds
{ {
$instance = new static(); $instance = new self();
$instance->southLat = $southLat; $instance->southLat = $southLat;
$instance->westLng = $westLng; $instance->westLng = $westLng;
+1 -1
View File
@@ -11,7 +11,7 @@ class JwtParser
} }
} }
public function setToken(string $token) public function setToken(string $token): void
{ {
$this->token = explode('.', str_replace(['_', '-'], ['/', '+'], $token)); $this->token = explode('.', str_replace(['_', '-'], ['/', '+'], $token));
} }
+3 -3
View File
@@ -65,7 +65,7 @@ class Linker
while (($line = fgets($inputFileHandle)) !== false) { while (($line = fgets($inputFileHandle)) !== false) {
++$lineNumber; ++$lineNumber;
if (preg_match('/^\s*@yields\(\'([\w\/]+)\'\)\s*$/', $line, $matches)) { if (preg_match('/^\s*@yields\(\'([\w\/]+)\'\)\s*$/', $line, $matches) === 1) {
if (isset($sections[$matches[1]])) { if (isset($sections[$matches[1]])) {
fwrite($outputFileHandle, $sections[$matches[1]]); fwrite($outputFileHandle, $sections[$matches[1]]);
} }
@@ -105,7 +105,7 @@ class Linker
fclose($outputFileHandle); fclose($outputFileHandle);
} }
private function generateAssets(ParsedFragment $fragment, array &$sections) private function generateAssets(ParsedFragment $fragment, array &$sections): void
{ {
foreach ($fragment->getCss() as $cssFile) { foreach ($fragment->getCss() as $cssFile) {
$asset = $this->parseAsset($cssFile); $asset = $this->parseAsset($cssFile);
@@ -134,7 +134,7 @@ class Linker
{ {
$output = []; $output = [];
if (preg_match('/^[\w\/\.]+$/', $asset)) { if (preg_match('/^[\w\/\.]+$/', $asset) === 1) {
if ( if (
empty($_ENV['DEV']) && empty($_ENV['DEV']) &&
filesize(ROOT . '/public/static/' . $asset) < self::INLINE_ASSET_LIMIT filesize(ROOT . '/public/static/' . $asset) < self::INLINE_ASSET_LIMIT
+7 -7
View File
@@ -108,7 +108,7 @@ class Parser
private function matchCss(string $line): ?string private function matchCss(string $line): ?string
{ {
if (preg_match('/^\s*@css\((.*)\)\s*$/', $line, $matches)) { if (preg_match('/^\s*@css\((.*)\)\s*$/', $line, $matches) === 1) {
return $matches[1]; return $matches[1];
} }
@@ -117,7 +117,7 @@ class Parser
private function matchJs(string $line): ?string private function matchJs(string $line): ?string
{ {
if (preg_match('/^\s*@js\((.*)\)\s*$/', $line, $matches)) { if (preg_match('/^\s*@js\((.*)\)\s*$/', $line, $matches) === 1) {
return $matches[1]; return $matches[1];
} }
@@ -126,7 +126,7 @@ class Parser
private function matchExtends(string $line): ?string private function matchExtends(string $line): ?string
{ {
if (preg_match('/^\s*@extends\(([\w\/]+)\)\s*$/', $line, $matches)) { if (preg_match('/^\s*@extends\(([\w\/]+)\)\s*$/', $line, $matches) === 1) {
return $matches[1]; return $matches[1];
} }
@@ -135,7 +135,7 @@ class Parser
private function matchSection(string $line): ?string private function matchSection(string $line): ?string
{ {
if (preg_match('/^\s*@section\((\w+)\)\s*$/', $line, $matches)) { if (preg_match('/^\s*@section\((\w+)\)\s*$/', $line, $matches) === 1) {
return $matches[1]; return $matches[1];
} }
@@ -144,16 +144,16 @@ class Parser
private function matchEndSection(string $line): bool private function matchEndSection(string $line): bool
{ {
return preg_match('/^\s*@endsection(?:\(\))?\s*$/', $line); return preg_match('/^\s*@endsection(?:\(\))?\s*$/', $line) === 1;
} }
private function matchExtra(string $line): bool private function matchExtra(string $line): bool
{ {
return preg_match('/^\s*@extra(?:\(\))?\s*$/', $line); return preg_match('/^\s*@extra(?:\(\))?\s*$/', $line) === 1;
} }
private function matchEndExtra(string $line): bool private function matchEndExtra(string $line): bool
{ {
return preg_match('/^\s*@endextra(?:\(\))?\s*$/', $line); return preg_match('/^\s*@endextra(?:\(\))?\s*$/', $line) === 1;
} }
} }
+4
View File
@@ -3,6 +3,10 @@
use MapGuesser\PersistentData\Model\Model; use MapGuesser\PersistentData\Model\Model;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
class OtherModel
{
}
class DummyModel extends Model class DummyModel extends Model
{ {
protected static string $table = 'test_table'; protected static string $table = 'test_table';
+1 -1
View File
@@ -6,7 +6,7 @@ use PHPUnit\Framework\TestCase;
final class ParserTest extends TestCase final class ParserTest extends TestCase
{ {
const TEST_VIEWS_PATH = __DIR__ . '/../assets/views'; const TEST_VIEWS_PATH = __DIR__ . '/../../views/tests';
public function testCanParseViewWithoutExtends(): void public function testCanParseViewWithoutExtends(): void
{ {
+1 -1
View File
@@ -4,7 +4,7 @@
<header class="small"> <header class="small">
<h1> <h1>
<a href="/" title="<?= $_ENV['APP_NAME'] ?>"> <a href="/" title="<?= $_ENV['APP_NAME'] ?>">
<img class="inline" width="1em" height="1em" src="<?= $_ENV['STATIC_ROOT'] ?>/img/icon.svg?rev=<?= REVISION ?>"><!-- <img class="inline" width="1em" height="1em" src="<?= $_ENV['STATIC_ROOT'] ?>/img/icon.svg?rev=<?= REVISION ?>" alt="<?= $_ENV['APP_NAME'] ?>"><!--
--><span><?= $_ENV['APP_NAME'] ?></span> --><span><?= $_ENV['APP_NAME'] ?></span>
</a> </a>
</h1> </h1>
+1 -1
View File
@@ -3,7 +3,7 @@
@section(content) @section(content)
<header> <header>
<h1> <h1>
<img class="inline" width="1em" height="1em" src="<?= $_ENV['STATIC_ROOT'] ?>/img/icon.svg?rev=<?= REVISION ?>"><!-- <img class="inline" width="1em" height="1em" src="<?= $_ENV['STATIC_ROOT'] ?>/img/icon.svg?rev=<?= REVISION ?>" alt="<?= $_ENV['APP_NAME'] ?>"><!--
--><?= $_ENV['APP_NAME'] ?> --><?= $_ENV['APP_NAME'] ?>
</h1> </h1>
</header> </header>
+1 -1
View File
@@ -4,7 +4,7 @@
<header> <header>
<h1> <h1>
<a href="/" title="<?= $_ENV['APP_NAME'] ?>"> <a href="/" title="<?= $_ENV['APP_NAME'] ?>">
<img class="inline" width="1em" height="1em" src="<?= $_ENV['STATIC_ROOT'] ?>/img/icon.svg?rev=<?= REVISION ?>"><!-- <img class="inline" width="1em" height="1em" src="<?= $_ENV['STATIC_ROOT'] ?>/img/icon.svg?rev=<?= REVISION ?>" alt="<?= $_ENV['APP_NAME'] ?>"><!--
--><span><?= $_ENV['APP_NAME'] ?></span> --><span><?= $_ENV['APP_NAME'] ?></span>
</a> </a>
</h1> </h1>
+21 -11
View File
@@ -1,13 +1,23 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="description" content="<?= $_ENV['APP_NAME'] ?> – A game about guessing where you are based on a street view panorama.">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#198231"> <meta name="theme-color" content="#198231">
<title><?= $_ENV['APP_NAME'] ?></title> <title><?= $_ENV['APP_NAME'] ?></title>
<?php if (preg_match('/^http(s)?/', $_ENV['STATIC_ROOT']) === 1): ?>
<link href="<?= $_ENV['STATIC_ROOT'] ?>" rel="preconnect">
<?php endif; ?>
<link href="https://fonts.gstatic.com" rel="preconnect">
<link href="https://maps.googleapis.com" rel="preconnect">
<?php if (!empty($_ENV['GOOGLE_ANALITICS_ID'])): ?>
<link href="https://www.googletagmanager.com" rel="preconnect">
<link href="https://www.google-analytics.com" rel="preconnect">
<?php endif; ?>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;500&amp;display=swap" rel="stylesheet">
<link href="<?= $_ENV['STATIC_ROOT'] ?>/css/mapguesser.css?rev=<?= REVISION ?>" rel="stylesheet"> <link href="<?= $_ENV['STATIC_ROOT'] ?>/css/mapguesser.css?rev=<?= REVISION ?>" rel="stylesheet">
@yields('externalCss') @yields('externalCss')
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;500&display=swap" rel="stylesheet">
@yields('inlineCss') @yields('inlineCss')
<link rel="icon" type="image/png" sizes="192x192" href="<?= $_ENV['STATIC_ROOT'] ?>/img/favicon/192x192.png?rev=<?= REVISION ?>"> <link rel="icon" type="image/png" sizes="192x192" href="<?= $_ENV['STATIC_ROOT'] ?>/img/favicon/192x192.png?rev=<?= REVISION ?>">
<link rel="icon" type="image/png" sizes="96x96" href="<?= $_ENV['STATIC_ROOT'] ?>/img/favicon/96x96.png?rev=<?= REVISION ?>"> <link rel="icon" type="image/png" sizes="96x96" href="<?= $_ENV['STATIC_ROOT'] ?>/img/favicon/96x96.png?rev=<?= REVISION ?>">
@@ -15,16 +25,8 @@
<link rel="icon" type="image/png" sizes="16x16" href="<?= $_ENV['STATIC_ROOT'] ?>/img/favicon/16x16.png?rev=<?= REVISION ?>"> <link rel="icon" type="image/png" sizes="16x16" href="<?= $_ENV['STATIC_ROOT'] ?>/img/favicon/16x16.png?rev=<?= REVISION ?>">
</head> </head>
<body> <body>
<?php if (!isset($_COOKIE['COOKIES_CONSENT'])): ?>
<div id="cookiesNotice">
<p class="small">
<?= $_ENV['APP_NAME'] ?> uses cookies to improve user experience. By using the app or clicking 'Agree', you consent to our use of cookies.
</p>
<button id="agreeCookiesButton" class="small marginTop">Agree</button>
</div>
<?php endif; ?>
<div id="loading"> <div id="loading">
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/loading.svg?rev=<?= REVISION ?>" width="64" height="64"> <img src="<?= $_ENV['STATIC_ROOT'] ?>/img/loading.svg?rev=<?= REVISION ?>" width="64" height="64" alt="Loading">
</div> </div>
<div id="cover"></div> <div id="cover"></div>
<div id="modal" class="modal"> <div id="modal" class="modal">
@@ -34,6 +36,14 @@
</div> </div>
@yields('pagemodal') @yields('pagemodal')
@yields('content') @yields('content')
<?php if (!isset($_COOKIE['COOKIES_CONSENT'])): ?>
<div id="cookiesNotice">
<p class="small">
<?= $_ENV['APP_NAME'] ?> uses cookies to improve user experience. By using the app or clicking 'Agree', you consent to our use of cookies.
</p>
<button id="agreeCookiesButton" class="small marginTop">Agree</button>
</div>
<?php endif; ?>
<script> <script>
const STATIC_ROOT = '<?= $_ENV['STATIC_ROOT'] ?>'; const STATIC_ROOT = '<?= $_ENV['STATIC_ROOT'] ?>';
const REVISION = '<?= REVISION ?>'; const REVISION = '<?= REVISION ?>';
File renamed without changes.
File renamed without changes.
File renamed without changes.