diff options
author | Daniel Weipert <code@drogueronin.de> | 2022-01-10 20:29:04 +0100 |
---|---|---|
committer | Daniel Weipert <code@drogueronin.de> | 2022-01-10 20:29:04 +0100 |
commit | a319f3a419790925bed539ba141038c72a83e70f (patch) | |
tree | dfb24183cc693863df733e190dbbc6da93bb82e5 |
Initial commit
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | cli-config.php | 10 | ||||
-rw-r--r-- | composer.json | 29 | ||||
-rw-r--r-- | public/index.php | 28 | ||||
-rw-r--r-- | src/AppException.php | 7 | ||||
-rw-r--r-- | src/Controller/Card.php | 31 | ||||
-rw-r--r-- | src/Controller/Home.php | 22 | ||||
-rw-r--r-- | src/DB.php | 55 | ||||
-rw-r--r-- | src/Model/Card.php | 87 | ||||
-rw-r--r-- | src/Model/CardMeta.php | 57 | ||||
-rw-r--r-- | src/Router.php | 70 | ||||
-rw-r--r-- | src/Template.php | 23 | ||||
-rw-r--r-- | templates/home.twig | 2 |
13 files changed, 424 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8504ffb --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/vendor/ +db.sqlite + diff --git a/cli-config.php b/cli-config.php new file mode 100644 index 0000000..917e29f --- /dev/null +++ b/cli-config.php @@ -0,0 +1,10 @@ +<?php + +use Elements\DB; + +#require_once __DIR__ . '/vendor/autoload.php'; + +DB::init(); + +return \Doctrine\ORM\Tools\Console\ConsoleRunner::createHelperSet(DB::$entityManager); + diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..5bad5a9 --- /dev/null +++ b/composer.json @@ -0,0 +1,29 @@ +{ + "name": "elements/elements", + "authors": [ + { + "name": "Daniel Weipert", + "email": "code@drogueronin.de" + } + ], + "require": { + "doctrine/orm": "^2.10", + "symfony/cache": "^6.0", + "symfony/http-foundation": "^6.0", + "symfony/routing": "^6.0", + "twig/twig": "^3.3" + }, + "config": { + "allow-plugins": { + "composer/package-versions-deprecated": true + } + }, + "autoload": { + "psr-4": { + "Elements\\": "src/" + } + }, + "scripts": { + "db:refresh": "doctrine orm:schema-tool:drop --force && doctrine orm:schema-tool:create" + } +} diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..57a5d91 --- /dev/null +++ b/public/index.php @@ -0,0 +1,28 @@ +<?php + +require_once dirname(__DIR__) . '/vendor/autoload.php'; + +\Elements\Template::init(); +\Elements\DB::init(); +new \Elements\Router(); + +$fields = [ + 'name' => 'meta[name]', + 'converted mana cost' => 'meta[cmc]', + 'is uno reverse' => 'meta[is_uno_reverse]', +]; +?> + +<form action="<?= '/card/add' ?>" method="post" enctype="multipart/form-data"> + <?php foreach ($fields as $key => $field): ?> + <label> + <?= $key ?> <input type="text" name="<?= $field ?>"> + </label> + <?php endforeach; ?> + <input type="submit" value="Hinzufügen"> +</form> + +<?php + + + diff --git a/src/AppException.php b/src/AppException.php new file mode 100644 index 0000000..d7949a3 --- /dev/null +++ b/src/AppException.php @@ -0,0 +1,7 @@ +<?php + +namespace Elements; + +class AppException extends \Exception +{} + diff --git a/src/Controller/Card.php b/src/Controller/Card.php new file mode 100644 index 0000000..39560bb --- /dev/null +++ b/src/Controller/Card.php @@ -0,0 +1,31 @@ +<?php + +namespace Elements\Controller; + +use Elements\DB; +use Elements\Model\Card as CardModel; +use Elements\Model\CardMeta; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +class Card +{ + public static function add(Request $request) + { + $card = new CardModel(); + + foreach ($request->get('meta') as $key => $value) { + $meta = new CardMeta($key, $value); + $card->addMeta($meta); + DB::save($meta); + } + + DB::save($card); + + $response = new RedirectResponse('/'); + + return $response; + } +} + diff --git a/src/Controller/Home.php b/src/Controller/Home.php new file mode 100644 index 0000000..511b89b --- /dev/null +++ b/src/Controller/Home.php @@ -0,0 +1,22 @@ +<?php + +namespace Elements\Controller; + +use Elements\DB; +use Elements\Model\Card; +use Elements\Template; + +class Home +{ + public static function index() + { + $c = DB::$entityManager->getRepository(Card::class)->findOneBy([], ['id' => 'DESC']); + echo "<pre>"; + $c && var_dump( + array_map(fn ($item) => [$item->key, $item->value], $c->meta->toArray()), + ); + + return Template::render('home.twig'); + } +} + diff --git a/src/DB.php b/src/DB.php new file mode 100644 index 0000000..c04d189 --- /dev/null +++ b/src/DB.php @@ -0,0 +1,55 @@ +<?php + +namespace Elements; + +use Doctrine\ORM\Cache; +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Mapping\Driver\AttributeDriver; +use Doctrine\ORM\Tools\Setup; + +class DB +{ + public static EntityManager $entityManager; + + /** + * DB constructor. + */ + public static function init() + { + $isDevMode = true; + $proxyDir = null; + $cache = null; + $config = Setup::createConfiguration($isDevMode, $proxyDir, $cache); + $config->setMetadataDriverImpl($config->newDefaultAnnotationDriver([__DIR__ . '/Model'], true)); + #$config->setMetadataDriverImpl(new AttributeDriver([__DIR__ . '/Model'])); + + $conn = array( + 'driver' => 'pdo_sqlite', + 'path' => dirname(__DIR__) . '/db.sqlite', + ); + + self::$entityManager = EntityManager::create($conn, $config); + } + + /** + * @param object $entity + * @param array $criteria + */ + public static function save(object $entity, array $criteria = []) + { + $repository = self::$entityManager->getRepository(get_class($entity)); + $exists = $repository->findOneBy($criteria); + + if (! empty($criteria) && ! is_null($exists)) { + foreach (get_object_vars($entity) as $key => $value) { + $exists->$key = $value; + } + } else { + $exists = $entity; + } + + self::$entityManager->persist($exists); + self::$entityManager->flush(); + } +} + diff --git a/src/Model/Card.php b/src/Model/Card.php new file mode 100644 index 0000000..ab421ab --- /dev/null +++ b/src/Model/Card.php @@ -0,0 +1,87 @@ +<?php + +namespace Elements\Model; + +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Doctrine\DBAL\Schema\Column; +use Doctrine\DBAL\Schema\Table; +use Doctrine\ORM\Mapping\Entity; +use Doctrine\ORM\Mapping\GeneratedValue; +use Doctrine\ORM\Mapping\Id; +use Doctrine\ORM\Mapping\OneToMany; +use Doctrine\ORM\PersistentCollection; +use Elements\DB; + +#[Entity] +#[Table(name: 'cards')] +/** + * @Entity + * @Table(name="cards") + */ +class Card +{ + #[Id] + #[Column(type: 'integer')] + #[GeneratedValue] + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + public int $id; + + #[OneToMany(targetEntity: CardMeta::class, mappedBy: 'card')] + /** + * @OneToMany(targetEntity="CardMeta", mappedBy="card") + */ + public Collection|ArrayCollection|PersistentCollection $meta; + + /** + * Card constructor. + */ + public function __construct() + { + $this->meta = new ArrayCollection(); + } + + /** + * @param CardMeta $meta + */ + public function addMeta(CardMeta $meta) + { + $meta->card = $this; + $this->meta[] = $meta; + } + + /** + * @param string $key + * + * @return string + */ + public function getMeta(string $key): ?string + { + // if meta is already hydrated + if ($this->meta->isInitialized()) { + $meta = $this->meta->unwrap() + #->findFirst(fn (CardMeta $item) => $item->key === $key); + ->filter(fn ($item) => $item->key === $key)->first(); + + return $meta->value ?? null; + } + + // get directly from db otherwise + $result = DB::$entityManager + ->createQuery( + 'SELECT cm.value + FROM Elements\Model\CardMeta cm + WHERE cm.key = :key AND cm.card = :card' + ) + ->setParameter('key', $key) + ->setParameter('card', $this) + ->getOneOrNullResult(); + + return $result['value'] ?? null; + } +} + diff --git a/src/Model/CardMeta.php b/src/Model/CardMeta.php new file mode 100644 index 0000000..2ec0da9 --- /dev/null +++ b/src/Model/CardMeta.php @@ -0,0 +1,57 @@ +<?php + +namespace Elements\Model; + +use Doctrine\DBAL\Schema\Column; +use Doctrine\DBAL\Schema\Table; +use Doctrine\ORM\Mapping\Entity; +use Doctrine\ORM\Mapping\GeneratedValue; +use Doctrine\ORM\Mapping\Id; +use Doctrine\ORM\Mapping\ManyToOne; + +#[Entity] +#[Table(name: 'card_meta')] +/** + * @Entity + * @Table(name="card_meta") + */ +class CardMeta +{ + #[Id] + #[Column(type: 'integer')] + #[GeneratedValue] + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + public int $id; + + #[Column(type: 'string')] + /** + * @Column(type="string") + */ + public string $key; + + #[Column(type: 'string')] + /** + * @Column(type="string") + */ + public string $value; + + #[ManyToOne(targetEntity: Card::class, inversedBy: 'meta')] + /** + * @ManyToOne(targetEntity="Card", inversedBy="meta", cascade={"persist"}) + */ + public Card $card; + + /** + * CardMeta constructor. + */ + public function __construct(string $key, string $value) + { + $this->key = $key; + $this->value = $value; + } +} + diff --git a/src/Router.php b/src/Router.php new file mode 100644 index 0000000..377c00b --- /dev/null +++ b/src/Router.php @@ -0,0 +1,70 @@ +<?php + +namespace Elements; + +use Elements\Controller\Card; +use Elements\Controller\Home; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +class Router +{ + private $routes = [ + 'GET' => [ + '/' => [Home::class, 'index'], + ], + + 'POST' => [ + '/card/add' => [Card::class, 'add'], + ], + ]; + + /** + * Router constructor. + */ + public function __construct() + { + $request = Request::createFromGlobals(); + $response = new Response(); + + $method = $request->getMethod(); + $path = $request->getPathInfo(); + + // if the route is defined + if (isset($this->routes[$method][$path])) { + try { + // run controller function + $content = call_user_func($this->routes[$method][$path], $request); + + // set response to new response + if ($content instanceof Response) { + $response = $content; + } + + // set content directly otherwise + else { + $response->setContent($content); + } + } + + // catch any errors + catch (AppException $exception) { + $response->setStatusCode($exception->getCode()); + $response->setContent($exception->getMessage()); + } catch (\Exception $exception) { + $response->setStatusCode(Response::HTTP_BAD_REQUEST); + $response->setContent($exception->getMessage()); + } + } + + // route is not defined + else { + $response->setStatusCode(Response::HTTP_NOT_FOUND); + $response->setContent('Not Found'); + } + + $response->send(); + } +} + diff --git a/src/Template.php b/src/Template.php new file mode 100644 index 0000000..b4360b8 --- /dev/null +++ b/src/Template.php @@ -0,0 +1,23 @@ +<?php + +namespace Elements; + +use Twig\Environment; +use Twig\Loader\FilesystemLoader; + +class Template +{ + public static ?Environment $twig = null; + + public static function init(): void + { + $loader = new FilesystemLoader(dirname(__DIR__) . '/templates'); + self::$twig = new Environment($loader); + } + + public static function render(string $name, array $context = []): string + { + return self::$twig->render($name, $context); + } +} + diff --git a/templates/home.twig b/templates/home.twig new file mode 100644 index 0000000..bc5b812 --- /dev/null +++ b/templates/home.twig @@ -0,0 +1,2 @@ +<h3>Home</h3> + |