Initial commit
This commit is contained in:
commit
e6ad944f79
1
.env.example
Normal file
1
.env.example
Normal file
@ -0,0 +1 @@
|
||||
SQLITE_DB_NAME=app.db
|
58
.gitignore
vendored
Normal file
58
.gitignore
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
# ---> Symfony
|
||||
# Cache and logs (Symfony2)
|
||||
/app/cache/*
|
||||
/app/logs/*
|
||||
!app/cache/.gitkeep
|
||||
!app/logs/.gitkeep
|
||||
|
||||
# Email spool folder
|
||||
/app/spool/*
|
||||
|
||||
# Cache, session files and logs (Symfony3)
|
||||
/var/cache/*
|
||||
/var/logs/*
|
||||
/var/sessions/*
|
||||
!var/cache/.gitkeep
|
||||
!var/logs/.gitkeep
|
||||
!var/sessions/.gitkeep
|
||||
|
||||
# Logs (Symfony4)
|
||||
/var/log/*
|
||||
!var/log/.gitkeep
|
||||
|
||||
# Parameters
|
||||
/app/config/parameters.yml
|
||||
/app/config/parameters.ini
|
||||
|
||||
# Managed by Composer
|
||||
/app/bootstrap.php.cache
|
||||
/var/bootstrap.php.cache
|
||||
/bin/*
|
||||
!bin/console
|
||||
!bin/symfony_requirements
|
||||
!bin/doctrine
|
||||
/vendor/
|
||||
|
||||
# Assets and user uploads
|
||||
/web/bundles/
|
||||
/web/uploads/
|
||||
|
||||
# PHPUnit
|
||||
/app/phpunit.xml
|
||||
/phpunit.xml
|
||||
|
||||
# Build data
|
||||
/build/
|
||||
|
||||
# Composer PHAR
|
||||
/composer.phar
|
||||
|
||||
# Backup entities generated with doctrine:generate:entities command
|
||||
**/Entity/*~
|
||||
|
||||
# Embedded web-server pid file
|
||||
/.web-server-pid
|
||||
|
||||
|
||||
.env
|
||||
/*.db
|
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
96
.idea/feacher.iml
Normal file
96
.idea/feacher.iml
Normal file
@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="Lewisdale\App\" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/masterminds/html5" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/lexer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/deprecations" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/event-manager" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/collections" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/persistence" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/instantiator" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/inflector" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/fig/http-message-util" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/dbal" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpoption/phpoption" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/league/uri" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/league/uri-interfaces" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/common" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/orm" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-server-handler" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/ralouphie/getallheaders" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-factory" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/container" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-message" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-server-middleware" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/log" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/type" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/diff" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/lines-of-code" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/laravel/serializable-closure" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-enumerator" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/comparator" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/code-unit" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/exporter" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/cli-parser" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/version" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/complexity" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/recursion-context" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/graham-campbell/result-type" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/brick/math" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/environment" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/global-state" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-reflector" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/ramsey/collection" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/ramsey/uuid" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/ramsey/uuid-doctrine" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/myclabs/deep-copy" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/php-di/php-di" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/php-di/invoker" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/nikic/fast-route" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-timer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache-contracts" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/nikic/php-parser" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-file-iterator" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/console" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-invoker" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/deprecation-contracts" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-text-template" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/phpunit" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-client" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-code-coverage" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-client-contracts" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-exporter" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/css-selector" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php80" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php81" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dom-crawler" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/service-contracts" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/string" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-ctype" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php72" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/slim/psr7" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/twig" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/slim/slim" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/slim/twig-view" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/slim/csrf" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/version" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/manifest" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/vlucas/phpdotenv" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/theseer/tokenizer" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/feacher.iml" filepath="$PROJECT_DIR$/.idea/feacher.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
113
.idea/php.xml
Normal file
113
.idea/php.xml
Normal file
@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MessDetectorOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCSFixerOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCodeSnifferOptionsConfiguration">
|
||||
<option name="highlightLevel" value="WARNING" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpIncludePathManager">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/vendor/masterminds/html5" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/collections" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/persistence" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/fig/http-message-util" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/dbal" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpoption/phpoption" />
|
||||
<path value="$PROJECT_DIR$/vendor/league/uri" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/league/uri-interfaces" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/common" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/orm" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/http-server-handler" />
|
||||
<path value="$PROJECT_DIR$/vendor/ralouphie/getallheaders" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/http-factory" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/http-message" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/http-server-middleware" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/log" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
||||
<path value="$PROJECT_DIR$/vendor/laravel/serializable-closure" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
||||
<path value="$PROJECT_DIR$/vendor/graham-campbell/result-type" />
|
||||
<path value="$PROJECT_DIR$/vendor/brick/math" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/ramsey/collection" />
|
||||
<path value="$PROJECT_DIR$/vendor/ramsey/uuid" />
|
||||
<path value="$PROJECT_DIR$/vendor/ramsey/uuid-doctrine" />
|
||||
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
||||
<path value="$PROJECT_DIR$/vendor/php-di/php-di" />
|
||||
<path value="$PROJECT_DIR$/vendor/php-di/invoker" />
|
||||
<path value="$PROJECT_DIR$/vendor/nikic/fast-route" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-client" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-client-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/css-selector" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php80" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php81" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/dom-crawler" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/string" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-ctype" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php72" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
<path value="$PROJECT_DIR$/vendor/slim/psr7" />
|
||||
<path value="$PROJECT_DIR$/vendor/twig/twig" />
|
||||
<path value="$PROJECT_DIR$/vendor/slim/slim" />
|
||||
<path value="$PROJECT_DIR$/vendor/slim/twig-view" />
|
||||
<path value="$PROJECT_DIR$/vendor/slim/csrf" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
||||
<path value="$PROJECT_DIR$/vendor/vlucas/phpdotenv" />
|
||||
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="8.2" />
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpUnit">
|
||||
<phpunit_settings>
|
||||
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" />
|
||||
</phpunit_settings>
|
||||
</component>
|
||||
<component name="PsalmOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
18
README.md
Normal file
18
README.md
Normal file
@ -0,0 +1,18 @@
|
||||
# PHP Project Template
|
||||
|
||||
This is a template for PHP projects. It includes a basic project structure, with Doctrine ORM
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
1. Run `composer install`
|
||||
2. Copy `.env.example` to `.env` and edit the values
|
||||
3. Run `php bin/doctrine orm:schema-tool:create` to create the database
|
||||
|
||||
## Running locally
|
||||
|
||||
1. Run `php -S localhost:8000 -t public` to start the web server
|
||||
|
||||
## Running tests
|
||||
|
||||
1. Run `php vendor/bin/phpunit` to run the tests
|
16
bin/doctrine
Normal file
16
bin/doctrine
Normal file
@ -0,0 +1,16 @@
|
||||
<?php declare(strict_types=1);
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\Tools\Console\ConsoleRunner;
|
||||
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
|
||||
|
||||
$dotenv = Dotenv\Dotenv::createImmutable([__DIR__, __DIR__ . "/.."]);
|
||||
$dotenv->load();
|
||||
|
||||
require_once __DIR__ . '/../src/dependencies.php';
|
||||
global $container;
|
||||
|
||||
ConsoleRunner::run(
|
||||
new SingleManagerProvider($container->get(EntityManager::class))
|
||||
);
|
39
composer.json
Normal file
39
composer.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "lewisdale/app",
|
||||
"type": "project",
|
||||
"require": {
|
||||
"slim/slim": "^4.11",
|
||||
"twig/twig": "^3.5",
|
||||
"slim/psr7": "^1.6",
|
||||
"slim/twig-view": "^3.3",
|
||||
"vlucas/phpdotenv": "^5.5",
|
||||
"php-di/php-di": "^7.0",
|
||||
"psr/log": "^3.0",
|
||||
"doctrine/orm": "^2.14",
|
||||
"doctrine/dbal": "^3.6",
|
||||
"symfony/cache": "^6.2",
|
||||
"ext-pdo": "*",
|
||||
"ext-readline": "*",
|
||||
"slim/csrf": "^1.3",
|
||||
"ramsey/uuid-doctrine": "^2.0",
|
||||
"ramsey/uuid": "^4.7",
|
||||
"symfony/dom-crawler": "^6.3",
|
||||
"symfony/css-selector": "^6.3",
|
||||
"symfony/http-client": "^6.3",
|
||||
"league/uri": "^6.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^10.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Lewisdale\\App\\": "src/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Lewis Dale",
|
||||
"email": "lewis@ihd.software"
|
||||
}
|
||||
]
|
||||
}
|
5913
composer.lock
generated
Normal file
5913
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
9
index.php
Normal file
9
index.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . "/vendor/autoload.php";
|
||||
|
||||
if (php_sapi_name() === "cli-server" && preg_match('/\.(?:png|jpg|jpeg|gif|css|ico|js|mjs|css\.map|webp)$/', $_SERVER["REQUEST_URI"])) {
|
||||
return false; // serve the requested resource as-is.
|
||||
}
|
||||
|
||||
require_once __DIR__ . "/src/app.php";
|
23
src/Controllers/SampleController.php
Normal file
23
src/Controllers/SampleController.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Lewisdale\App\Controllers;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
class SampleController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Twig $view,
|
||||
private readonly LoggerInterface $logger
|
||||
) {}
|
||||
|
||||
public function get(ServerRequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
$this->logger->info("SampleController::get() called");
|
||||
return $this->view->render($response, 'index.twig.html');
|
||||
}
|
||||
}
|
21
src/Logging/FileLogger.php
Normal file
21
src/Logging/FileLogger.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Lewisdale\App\Logging;
|
||||
|
||||
use DateTime;
|
||||
use Psr\Log\AbstractLogger;
|
||||
use Stringable;
|
||||
|
||||
class FileLogger extends AbstractLogger
|
||||
{
|
||||
function __construct(private readonly string $filename = 'php://stdout') {}
|
||||
public function log($level, Stringable|string $message, array $context = []): void
|
||||
{
|
||||
$timestamp = new DateTime();
|
||||
$callingClass = debug_backtrace()[2]['class'];
|
||||
$callingFunction = debug_backtrace()[2]['function'];
|
||||
$log = $timestamp->format(DATE_ATOM) . " [$level] $callingClass::$callingFunction $message " . json_encode($context);
|
||||
fwrite(fopen($this->filename, 'w'), $log . PHP_EOL);
|
||||
}
|
||||
}
|
||||
|
61
src/Models/Data/User.php
Normal file
61
src/Models/Data/User.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Lewisdale\App\Models\Data;
|
||||
|
||||
use Lewisdale\App\Models\Traits\AutoUpdate;
|
||||
use Lewisdale\App\Models\View;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity]
|
||||
#[ORM\Table(name: 'users')]
|
||||
#[ORM\UniqueConstraint(name: "email", columns: ["email"])]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class User
|
||||
{
|
||||
use AutoUpdate;
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
#[ORM\GeneratedValue]
|
||||
private ?int $id;
|
||||
#[ORM\Column(type: 'string')]
|
||||
private string $password;
|
||||
#[ORM\Column(type: 'string')]
|
||||
private string $email;
|
||||
#[ORM\Column(type: 'string')]
|
||||
private string $salt;
|
||||
|
||||
function __construct(
|
||||
string $password,
|
||||
string $email,
|
||||
?string $salt = null,
|
||||
?int $id = null,
|
||||
) {
|
||||
$this->password = $password;
|
||||
$this->email = $email;
|
||||
$this->id = $id;
|
||||
$this->salt = $salt ?? bin2hex(random_bytes(32));
|
||||
}
|
||||
|
||||
public function hash(string $password): string {
|
||||
return password_hash($password . $this->salt, PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
public function validate(string $password): bool {
|
||||
return password_verify($password . $this->salt, $this->password);
|
||||
}
|
||||
|
||||
public function updatePassword(string $password): void {
|
||||
$this->password = $this->hash($password);
|
||||
}
|
||||
|
||||
public function toViewModel() : View\User {
|
||||
return new View\User(
|
||||
$this->email,
|
||||
$this->createdAt->format(DATE_ATOM),
|
||||
$this->updatedAt->format(DATE_ATOM),
|
||||
$this->id
|
||||
);
|
||||
}
|
||||
}
|
25
src/Models/Traits/AutoUpdate.php
Normal file
25
src/Models/Traits/AutoUpdate.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Lewisdale\App\Models\Traits;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
trait AutoUpdate
|
||||
{
|
||||
#[ORM\Column(type: 'datetime')]
|
||||
protected DateTime $createdAt;
|
||||
#[ORM\Column(type: 'datetime')]
|
||||
protected DateTime $updatedAt;
|
||||
|
||||
#[ORM\PrePersist]
|
||||
public function onPrePersist(): void {
|
||||
$this->createdAt = new DateTime('now');
|
||||
$this->updatedAt = new DateTime('now');
|
||||
}
|
||||
|
||||
#[ORM\PreUpdate]
|
||||
public function onPreUpdate(): void {
|
||||
$this->updatedAt = new DateTime('now');
|
||||
}
|
||||
}
|
15
src/Models/View/User.php
Normal file
15
src/Models/View/User.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Lewisdale\App\Models\View;
|
||||
|
||||
class User
|
||||
{
|
||||
public function __construct(
|
||||
public string $email,
|
||||
public string $createdAt,
|
||||
public string $updatedAt,
|
||||
public ?int $id = null,
|
||||
) {}
|
||||
}
|
39
src/TwigExtensions/CsrfExtension.php
Normal file
39
src/TwigExtensions/CsrfExtension.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Lewisdale\App\TwigExtensions;
|
||||
|
||||
use Slim\Csrf\Guard;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
class CsrfExtension extends AbstractExtension
|
||||
{
|
||||
protected Guard $guard;
|
||||
|
||||
public function __construct(Guard $guard)
|
||||
{
|
||||
$this->guard = $guard;
|
||||
}
|
||||
|
||||
public function getFunctions() : array
|
||||
{
|
||||
return [
|
||||
new TwigFunction('csrf', [$this, 'csrf'])
|
||||
];
|
||||
}
|
||||
|
||||
public function csrf() : string
|
||||
{
|
||||
$nameKey = $this->guard->getTokenNameKey();
|
||||
$nameValue = $this->guard->getTokenName();
|
||||
$tokenKey = $this->guard->getTokenValueKey();
|
||||
$tokenValue = $this->guard->getTokenValue();
|
||||
|
||||
return "
|
||||
<input type=\"hidden\" name=\"$nameKey\" value=\"$nameValue\">
|
||||
<input type=\"hidden\" name=\"$tokenKey\" value=\"$tokenValue\">
|
||||
";
|
||||
}
|
||||
}
|
23
src/app.php
Normal file
23
src/app.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
use Lewisdale\App\Controllers\SampleController;
|
||||
use Slim\Views\TwigMiddleware;
|
||||
|
||||
require_once __DIR__ . "/dependencies.php";
|
||||
|
||||
global $container;
|
||||
global $app;
|
||||
|
||||
$dotenv = Dotenv\Dotenv::createImmutable([__DIR__, __DIR__ . "/.."]);
|
||||
$dotenv->load();
|
||||
|
||||
require_once __DIR__ . "/session.php";
|
||||
|
||||
$app->add(TwigMiddleware::createFromContainer($app));
|
||||
$app->add('csrf');
|
||||
|
||||
$app->get("/", [SampleController::class, 'get']);
|
||||
|
||||
$app->addErrorMiddleware(true, true, true);
|
||||
|
||||
$app->run();
|
56
src/dependencies.php
Normal file
56
src/dependencies.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
use DI\Container;
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\ORMSetup;
|
||||
use Lewisdale\App\Logging\FileLogger;
|
||||
use Lewisdale\App\TwigExtensions\CsrfExtension;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Ramsey\Uuid\Doctrine\UuidType;
|
||||
use Slim\Factory\AppFactory;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
require_once __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
$container = new Container();
|
||||
|
||||
AppFactory::setContainer($container);
|
||||
$app = AppFactory::create();
|
||||
|
||||
|
||||
$container->set('csrf', function() use ($app) {
|
||||
return new Slim\Csrf\Guard($app->getResponseFactory());
|
||||
});
|
||||
|
||||
$container->set('view', function() use ($container) {
|
||||
$twig = Twig::create(__DIR__ . "/../views");
|
||||
$twig->addExtension(new CsrfExtension($container->get('csrf')));
|
||||
|
||||
return $twig;
|
||||
});
|
||||
|
||||
$container->set(Twig::class, function() use ($container) {
|
||||
return $container->get('view');
|
||||
});
|
||||
|
||||
$container->set(LoggerInterface::class, $container->get(FileLogger::class));
|
||||
|
||||
|
||||
$container->set(EntityManager::class, static function() {
|
||||
Type::addType('uuid', UuidType::class);
|
||||
|
||||
$config = ORMSetup::createAttributeMetadataConfiguration(
|
||||
paths: array(__DIR__."/Models/Data"),
|
||||
isDevMode: true,
|
||||
);
|
||||
|
||||
$connection = DriverManager::getConnection([
|
||||
'driver' => 'pdo_sqlite',
|
||||
'path' => __DIR__ . '/../' . $_ENV["SQLITE_DB_NAME"],
|
||||
], $config);
|
||||
|
||||
return new EntityManager($connection, $config);
|
||||
});
|
||||
|
14
src/session.php
Normal file
14
src/session.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
session_start();
|
||||
|
||||
// Protect against session hijacking
|
||||
if (!isset($_SESSION['fingerprint'])) {
|
||||
session_regenerate_id();
|
||||
$_SESSION['fingerprint'] = $_SERVER['HTTP_USER_AGENT'];
|
||||
}
|
||||
|
||||
if ($_SESSION['fingerprint'] !== $_SERVER['HTTP_USER_AGENT']) {
|
||||
session_unset();
|
||||
}
|
4
views/index.twig.html
Normal file
4
views/index.twig.html
Normal file
@ -0,0 +1,4 @@
|
||||
<h1>Hello, world.</h1>
|
||||
|
||||
<p>This is a boilerplate PHP app. You should start by adding some routes, controllers, and maybe making me look
|
||||
good.</p>
|
Loading…
Reference in New Issue
Block a user