Compare commits
11 commits
bb3397b751
...
d4e31baed0
| Author | SHA1 | Date | |
|---|---|---|---|
| d4e31baed0 | |||
| 019f3a61e1 | |||
| 52a68319da | |||
| 9a64d1dd50 | |||
| 0853aacdfb | |||
| 21076f10e8 | |||
| e9195fe991 | |||
| 878e4840a2 | |||
| e4001b564a | |||
| 3165bff891 | |||
| 688373f46d |
10 changed files with 194 additions and 8 deletions
108
app/Text/JsonTextRepository.php
Normal file
108
app/Text/JsonTextRepository.php
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Text;
|
||||||
|
|
||||||
|
use App\Text\Text;
|
||||||
|
use App\Text\CreateTextDto;
|
||||||
|
use App\Text\TextRepository;
|
||||||
|
|
||||||
|
class JsonTextRepository implements TextRepository
|
||||||
|
{
|
||||||
|
private string $filePath;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->filePath = __DIR__.'/../../data/texts.json';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(CreateTextDto $dto): Text
|
||||||
|
{
|
||||||
|
$texts = $this->readTexts();
|
||||||
|
$id = $this->getNextId($texts);
|
||||||
|
|
||||||
|
$text = new Text(id: $id, name: $dto->name);
|
||||||
|
$texts[] = ['id' => $id, 'name' => $dto->name];
|
||||||
|
|
||||||
|
$this->writeTexts($texts);
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find(int $id): ?Text
|
||||||
|
{
|
||||||
|
$texts = $this->readTexts();
|
||||||
|
|
||||||
|
foreach ($texts as $data) {
|
||||||
|
if ($data['id'] === $id) {
|
||||||
|
return new Text(
|
||||||
|
id: $data['id'],
|
||||||
|
name: $data['name'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Text[]
|
||||||
|
*/
|
||||||
|
public function getAll(): array
|
||||||
|
{
|
||||||
|
$texts = $this->readTexts();
|
||||||
|
|
||||||
|
return array_map(
|
||||||
|
function (array $data) {
|
||||||
|
return new Text(
|
||||||
|
id: $data['id'],
|
||||||
|
name: $data['name'],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
$texts
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function readTexts(): array
|
||||||
|
{
|
||||||
|
if (!file_exists($this->filePath)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = file_get_contents($this->filePath);
|
||||||
|
|
||||||
|
return json_decode($content, true) ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $texts
|
||||||
|
*/
|
||||||
|
private function writeTexts(array $texts): void
|
||||||
|
{
|
||||||
|
file_put_contents(
|
||||||
|
$this->filePath,
|
||||||
|
json_encode($texts, JSON_PRETTY_PRINT)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $texts
|
||||||
|
*/
|
||||||
|
private function getNextId(array $texts): int
|
||||||
|
{
|
||||||
|
if (empty($texts)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$maxId = 0;
|
||||||
|
foreach ($texts as $text) {
|
||||||
|
if ($text['id'] > $maxId) {
|
||||||
|
$maxId = $text['id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $maxId + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,4 +10,9 @@ interface TextRepository
|
||||||
public function create(CreateTextDto $dto): Text;
|
public function create(CreateTextDto $dto): Text;
|
||||||
|
|
||||||
public function find(int $id): ?Text;
|
public function find(int $id): ?Text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Text[]
|
||||||
|
*/
|
||||||
|
public function getAll(): array;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,15 @@
|
||||||
|
|
||||||
namespace App\View;
|
namespace App\View;
|
||||||
|
|
||||||
|
use App\Text\TextRepository;
|
||||||
use Psr\Http\Message\ResponseInterface as Response;
|
use Psr\Http\Message\ResponseInterface as Response;
|
||||||
|
|
||||||
class ViewController
|
class ViewController
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
private TextRepository $textRepository,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function admin(Response $response): Response
|
public function admin(Response $response): Response
|
||||||
{
|
{
|
||||||
$html = file_get_contents(__DIR__.'/../../views/templates/admin.php', true);
|
$html = file_get_contents(__DIR__.'/../../views/templates/admin.php', true);
|
||||||
|
|
@ -13,4 +18,20 @@ class ViewController
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function texts(Response $response): Response
|
||||||
|
{
|
||||||
|
$texts = $this->textRepository->getAll();
|
||||||
|
|
||||||
|
$textsList = '';
|
||||||
|
foreach ($texts as $text) {
|
||||||
|
$textsList .= '<li>' . htmlspecialchars($text->getName()) . '</li>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$html = file_get_contents(__DIR__.'/../../views/templates/texts.php', true);
|
||||||
|
$html = str_replace('{{texts}}', $textsList, $html);
|
||||||
|
$response->getBody()->write($html);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,5 +12,6 @@ $app = Bridge::create($container);
|
||||||
$app->addErrorMiddleware(true, true, true);
|
$app->addErrorMiddleware(true, true, true);
|
||||||
|
|
||||||
$app->get('/admin', [ViewController::class, 'admin']);
|
$app->get('/admin', [ViewController::class, 'admin']);
|
||||||
|
$app->get('/admin/texts', [ViewController::class, 'texts']);
|
||||||
|
|
||||||
return $app;
|
return $app;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use DI;
|
||||||
use DI\Container;
|
use DI\Container;
|
||||||
|
use App\Text\TextRepository;
|
||||||
|
use App\Text\JsonTextRepository;
|
||||||
|
|
||||||
$container = new Container([
|
$container = new Container([
|
||||||
|
TextRepository::class => DI\create(JsonTextRepository::class),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $container;
|
return $container;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,24 @@
|
||||||
describe('The admin page', () => {
|
describe('The admin page', () => {
|
||||||
it('successfully loads texts', () => {
|
beforeEach(() => {
|
||||||
cy.visit('/admin')
|
cy.visit('/admin')
|
||||||
cy.get('#newTextname').type('new text')
|
})
|
||||||
|
|
||||||
|
it('navigates to texts page', () => {
|
||||||
|
cy.get('#texts').click()
|
||||||
|
cy.url().should('include', '/admin/texts')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows texts page with heading and form', () => {
|
||||||
|
cy.visit('/admin/texts')
|
||||||
|
cy.get('h1').should('contain', 'Texts')
|
||||||
|
cy.get('#newTextName').should('exist')
|
||||||
|
cy.get('#submit').should('exist')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('creates a new text', () => {
|
||||||
|
cy.visit('/admin/texts')
|
||||||
|
cy.get('#newTextName').type('Test Text')
|
||||||
cy.get('#submit').click()
|
cy.get('#submit').click()
|
||||||
|
cy.contains('Test Text')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
1
data/texts.json
Normal file
1
data/texts.json
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
[]
|
||||||
|
|
@ -47,4 +47,20 @@ class FakeTextRepository implements TextRepository
|
||||||
{
|
{
|
||||||
return count($this->existingTexts);
|
return count($this->existingTexts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Text[]
|
||||||
|
*/
|
||||||
|
public function getAll(): array
|
||||||
|
{
|
||||||
|
return array_map(
|
||||||
|
function (Text $text) {
|
||||||
|
return new Text(
|
||||||
|
id: $text->getId(),
|
||||||
|
name: $text->getName(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
$this->existingTexts
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Daily Goals</title>
|
<title>Daily Goals - Admin</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<input id='newTextname'/>
|
<a href="/admin/texts" id="texts">Texts</a>
|
||||||
<button id='submit'>submit</button>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
15
views/templates/texts.php
Normal file
15
views/templates/texts.php
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Daily Goals - Texts</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Texts</h1>
|
||||||
|
<a href="/admin" id="back">Back to Admin</a>
|
||||||
|
<ul id="texts-list">
|
||||||
|
{{texts}}
|
||||||
|
</ul>
|
||||||
|
<input id="newTextName"/>
|
||||||
|
<button id="submit">submit</button>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue