Moduulit
Edellisessä tutoriaalissa Hello World! asensit Piken, ja loit projektiokansion uudelle applikaatiolle. Tässä tutoriaalissa jatkat projektia laajentamalla sen peliaiheiseksi REST-API:ksi.
Sisällysluettelo
- Johdanto
- Step 1. Luo kontrollerit ja moduulit
- Step 2. Luo peleille ja genreille DAO-luokat
- Step 3. Bundlaa moduulit yhden luokan alle
- Yhteenveto
Johdanto
Tässä tutoriaalissa luot REST-backendin kuvitteelliselle peliaiheiselle applikaatiolle. Tutoriaalissa luot API:in kaksi moduulia:
- Game: käsittelee peleihin liittyvät HTTP-pyynnöt
- Genre: käsittelee peligenreihin liittyvät HTTP-pyynnöt
Step 1. Luo kontrollerit ja moduulit
Luo kopio edellisen tutoriaalin projektikansiosta (tut1-hello-pike
) ja anna kopioidulle kansiolle nimeksi tut2-modules
. Luo kansioon kansio tut2-modules/src
, ja sen sisälle kaksi uutta kansiota - src/Game
ja src/Genre
. Luo kumpaankin kansioon kaksi uutta tiedostoa:
src/Game/GamesModule.php
<?php declare(strict_types=1);
namespace Me\MyApp\Game;
use Pike\AppContext;
final class GamesModule {
public function init(AppContext $ctx): void {
$ctx->router->map('GET', '/games/[w:genreSlug]',
[GamesController::class, 'listGamesByCategory']
);
}
}
src/Game/GamesController.php
<?php declare(strict_types=1);
namespace Me\MyApp\Game;
use Pike\{Request, Response};
final class GamesController {
public function listGamesByCategory(Request $req, Response $res): void {
$games = ["@todo pelit kategorialle {$req->params->genreSlug}"];
$res->json($games);
}
}
src/Game/GenresModule.php
<?php declare(strict_types=1);
namespace Me\MyApp\Genre;
use Pike\AppContext;
final class GenresModule {
public function init(AppContext $ctx): void {
$ctx->router->map('GET', '/genres',
[GenresController::class, 'listGenres']
);
}
}
src/Game/GenresController.php
<?php declare(strict_types=1);
namespace Me\MyApp\Genre;
use Pike\Response;
final class GenresController {
public function listGenres(Response $res): void {
$genres = [
(object) ['name' => 'Real time tactics', 'slug' => 'real-time-tactics'],
(object) ['name' => 'Role playing game', 'slug' => 'role-playing-game'],
(object) ['name' => 'First person shooter', 'slug' => 'first-person-shooter'],
(object) ['name' => 'Point-and-click', 'slug' => 'point-and-click'],
(object) ['name' => 'Racing', 'slug' => 'racing'],
];
$res->json($genres);
}
}
Päivitä index.php, composer.json ja testaa
Konfiguroi composerin autoloader lataamaan projektimme nimiavaruus Me\MyApp
.
Päivitä composer.json …
"name": "me/my-app",
"require": {
"ut4/pike": "0.9.0"
+ },
+ "autoload": {
+ "psr-4": {"Me\\MyApp\\": "src/"}
}
}
… ja aja tämän jälkeen komento composer update
(projektikansion juuressa /tut2-modules
).
Lisää Pike-applikaation luontikutsuun edellä luomasi moduulit.
Päivitä index.php
<?php declare(strict_types=1);
$loader = require __DIR__ . '/vendor/autoload.php';
$app = new \Pike\App([new \Me\MyApp\Game\GamesModule,
new \Me\MyApp\Genre\GenresModule]);
$app->handleRequest($_GET['q'] ?? '/');
Avaa tämän jälkeen selaimesi osoitteissa http://<devausYmpäristösiOsoite>/tut2-modules/index.php?q=/games/real-time-tactics
ja http://<devausYmpäristösiOsoite>/tut2-modules/index.php?q=/genres
, joka pitäisi listata kontrollerien palauttaman kovakoodatun datan.
Step 2. Luo peleille ja genreille DAO-luokat
Korvataan konrollereihin kovakoodattu data luokilla, jotka lukee ne json-tiedostoista:
Luo uusi tiedosto src/Game/GamesDao.php
<?php declare(strict_types=1);
namespace Me\MyApp\Game;
use Pike\{ArrayUtils, FileSystem};
final class GamesDao {
/** @var \Pike\FileSystem */
private $fs;
public function __construct(FileSystem $fs) {
$this->fs = $fs;
$this->dataFilePath = dirname(__DIR__, 2) . '/data/games.json';
}
public function listByGenreSlug(string $genreSlug): array {
$all = json_decode($this->fs->read($this->dataFilePath));
$filtered = ArrayUtils::filterByKey($all, $genreSlug, 'genreSlug');
return $filtered;
}
}
Päivitä src/GamesController.php
use Pike\{Request, Response};
final class GamesController {
- public function listGamesByCategory(Request $req, Response $res): void {
- $games = ["@todo pelit kategorialle {$req->params->genreSlug}"];
+ public function listGamesByCategory(Request $req,
+ Response $res,
+ GamesDao $gamesDao): void {
+ $games = $gamesDao->listByGenreSlug($req->params->genreSlug);
$res->json($games);
}
}
Luo uusi tiedosto src/Genre/GenresDao.php
<?php declare(strict_types=1);
namespace Me\MyApp\Genre;
use Pike\FileSystem;
final class GenresDao {
/** @var \Pike\FileSystem */
private $fs;
public function __construct(FileSystem $fs) {
$this->fs = $fs;
$this->dataFilePath = dirname(__DIR__, 2) . '/data/genres.json';
}
public function listAll(): array {
$all = json_decode($this->fs->read($this->dataFilePath));
return $all;
}
}
Päivitä src/GenresController.php
use Pike\Response;
final class GenresController {
- public function listGenres(Response $res): void {
- $genres = [
- (object) ['name' => 'Real time tactics', 'slug' => 'real-time-tactics'],
- (object) ['name' => 'Role playing game', 'slug' => 'role-playing-game'],
- (object) ['name' => 'First person shooter', 'slug' => 'first-person-shooter'],
- (object) ['name' => 'Point-and-click', 'slug' => 'point-and-click'],
- (object) ['name' => 'Racing', 'slug' => 'racing'],
- ];
+ public function listGenres(Response $res, GenresDao $genresDao): void {
+ $genres = $genresDao->listAll();
$res->json($genres);
}
}
Luo datatiedostot ja testaa
Luo uusi kansio tut2-modules/data
ja sinne kaksi uutta tiedostoa:
data/games.json
[
{"name":"Desperados III","genreSlug":"real-time-tactics"},
{"name":"Shadow Tactics: Blades of the Shogun","genreSlug":"real-time-tactics"},
{"name":"Cyberpunk 2077","genreSlug":"role-playing-game"},
{"name":"The Elder Scrolls V: Skyrim","genreSlug":"role-playing-game"},
{"name":"Wasteland 3","genreSlug":"role-playing-game"},
{"name":"Doom","genreSlug":"first-person-shooter"},
{"name":"Control","genreSlug":"first-person-shooter"},
{"name":"Beautiful Desolation","genreSlug":"point-and-click"},
{"name":"Life Is Strange","genreSlug":"point-and-click"},
{"name":"Wreckfest","genreSlug":"racing"},
{"name":"Trials Evolution","genreSlug":"racing"},
{"name":"Ridge Racer Unbounded","genreSlug":"racing"}
]
data/genres.json
[
{"name":"Real time tactics","slug":"real-time-tactics"},
{"name":"Role playing game","slug":"role-playing-game"},
{"name":"First person shooter","slug":"first-person-shooter"},
{"name":"Point-and-click","slug":"point-and-click"},
{"name":"Racing","genreSlug":"racing"}
]
Tämän jälkeen REST-reittimme pitäisi palauttaa kovakoodatun datan sijaan json-tiedostojen sisältämä data. Cool!
Step 3. Bundlaa moduulit yhden luokan alle
Tehdään applikaatiostamme testattavampi irroittamalla se index.php
-tiedostosta omaksi luokakseen.
Luo uusi tiedosto src/MyGamingSiteApp.php
<?php declare(strict_types=1);
namespace Me\MyApp;
use Pike\App;
use Me\MyApp\Game\GamesModule;
use Me\MyApp\Genre\GenresModule;
final class MyGamingSiteApp {
public static function create(): App {
return new App([
new GamesModule,
new GenresModule
]);
}
}
Päivitä index.php
$loader = require __DIR__ . '/vendor/autoload.php';
-$app = new \Pike\App([new \Me\MyApp\Game\GamesModule,
- new \Me\MyApp\Genre\GenresModule]);
+$app = \Me\MyApp\MyGamingSiteApp::create();
$app->handleRequest($_GET['q'] ?? '/');
Yhteenveto
Tässä tutoriaalissa:
- Korvasit yhden tiedoston Hei Maailma -applikaation melkein oikealla REST-API-applikaatiolla
- Konfiguroit composerin automaattisesti lataamaan applikaation
src
-kansiossa sijaitsevat luokat - Huomasit miten Pike injektoi automaattisesti luokistasi (
GamesDao
,GenresDao
) instansseja kontrollereihin
Seuraavaksi Tutoriaali #3: Testaus.