diff --git a/app/Node/JsonNodeRepository.php b/app/Node/JsonNodeRepository.php deleted file mode 100644 index a466bc0..0000000 --- a/app/Node/JsonNodeRepository.php +++ /dev/null @@ -1,129 +0,0 @@ -filePath = __DIR__.'/../../data/nodes.json'; - } - - public function create(CreateNodeDto $dto): Node - { - $nodes = $this->readNodes(); - $id = $this->getNextId($nodes); - - $nodes[] = [ - 'id' => $id, - 'title' => $dto->title, - 'textId' => $dto->text->getId(), - 'parentNodeId' => $dto->parentNode?->getId(), - ]; - - $this->writeNodes($nodes); - - return new Node( - id: $id, - title: $dto->title, - text: $dto->text, - parentNode: $dto->parentNode, - ); - } - - public function find(int $id): ?Node - { - $nodes = $this->readNodes(); - - foreach ($nodes as $data) { - if ($data['id'] === $id) { - return $this->hydrateNode($data, $nodes); - } - } - - return null; - } - - /** - * @return Node[] - */ - public function findByTextId(int $id): array - { - $nodes = $this->readNodes(); - - $matching = array_filter( - $nodes, - fn(array $data) => $data['textId'] === $id - ); - - return array_values(array_map( - fn(array $data) => $this->hydrateNode($data, $nodes), - $matching - )); - } - - private function hydrateNode(array $data, array $allNodes): Node - { - $text = $this->textRepository->find($data['textId']); - - $parentNode = null; - if ($data['parentNodeId'] !== null) { - foreach ($allNodes as $parentData) { - if ($parentData['id'] === $data['parentNodeId']) { - $parentNode = $this->hydrateNode($parentData, $allNodes); - break; - } - } - } - - return new Node( - id: $data['id'], - title: $data['title'], - text: $text, - parentNode: $parentNode, - ); - } - - private function readNodes(): array - { - if (!file_exists($this->filePath)) { - return []; - } - - $content = file_get_contents($this->filePath); - - return json_decode($content, true) ?? []; - } - - private function writeNodes(array $nodes): void - { - file_put_contents( - $this->filePath, - json_encode($nodes, JSON_PRETTY_PRINT) - ); - } - - private function getNextId(array $nodes): int - { - if (empty($nodes)) { - return 1; - } - - $maxId = 0; - foreach ($nodes as $node) { - if ($node['id'] > $maxId) { - $maxId = $node['id']; - } - } - - return $maxId + 1; - } -} diff --git a/app/Node/NodeController.php b/app/Node/NodeController.php deleted file mode 100644 index a02f575..0000000 --- a/app/Node/NodeController.php +++ /dev/null @@ -1,37 +0,0 @@ -textRepository->find($textId); - - if ($text === null) { - return $response->withStatus(404); - } - - $nodes = $this->nodeRepository->findByTextId($textId); - - $data = array_map(function ($node) { - return [ - 'id' => $node->getId(), - 'title' => $node->getTitle(), - 'parentNodeId' => $node->getParentNode()?->getId(), - ]; - }, $nodes); - - $response->getBody()->write(json_encode(array_values($data))); - return $response->withHeader('Content-Type', 'application/json'); - } -} diff --git a/app/Text/TextController.php b/app/Text/TextController.php index c608018..500986e 100644 --- a/app/Text/TextController.php +++ b/app/Text/TextController.php @@ -18,29 +18,12 @@ class TextController { $texts = $this->textRepository->getAll(); - $data = array_map(function ($text) { - return [ - 'id' => $text->getId(), - 'name' => $text->getName(), - ]; - }, $texts); - - $response->getBody()->write(json_encode($data)); - return $response->withHeader('Content-Type', 'application/json'); - } - - public function getText(Response $response, int $textId): Response - { - $text = $this->textRepository->find($textId); - - if ($text === null) { - return $response->withStatus(404); - } - - $response->getBody()->write(json_encode([ + $data = array_map(fn($text) => [ 'id' => $text->getId(), 'name' => $text->getName(), - ])); + ], $texts); + + $response->getBody()->write(json_encode($data)); return $response->withHeader('Content-Type', 'application/json'); } diff --git a/app/Text/UseCases/CreateText.php b/app/Text/UseCases/CreateText.php index bf4715b..062497c 100644 --- a/app/Text/UseCases/CreateText.php +++ b/app/Text/UseCases/CreateText.php @@ -5,28 +5,17 @@ namespace App\Text\UseCases; use App\Text\Text; use App\Text\CreateTextDto; use App\Text\TextRepository; -use App\Node\NodeRepository; -use App\Node\CreateNodeDto; class CreateText { public function __construct( private TextRepository $textRepo, - private NodeRepository $nodeRepo, ) {} public function execute(CreateTextRequest $request): Text { - $text = $this->textRepo->create(new CreateTextDto( + return $this->textRepo->create(new CreateTextDto( name: $request->name, )); - - $this->nodeRepo->create(new CreateNodeDto( - text: $text, - title: $text->getName(), - parentNode: null, - )); - - return $text; } } diff --git a/app/View/ViewController.php b/app/View/ViewController.php index 580c53e..0ee00ea 100644 --- a/app/View/ViewController.php +++ b/app/View/ViewController.php @@ -21,12 +21,4 @@ class ViewController return $response; } - - public function text(Response $response): Response - { - $html = file_get_contents(__DIR__.'/../../views/templates/text.php', true); - $response->getBody()->write($html); - - return $response; - } } diff --git a/bootstrap/app.php b/bootstrap/app.php index bfe8142..ddc3dcd 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -5,7 +5,6 @@ use Psr\Http\Message\ServerRequestInterface as Request; use DI\Bridge\Slim\Bridge; use App\View\ViewController; use App\Text\TextController; -use App\Node\NodeController; $container = require __DIR__.'/container.php'; $app = Bridge::create($container); @@ -15,11 +14,8 @@ $app->addErrorMiddleware(true, true, true); $app->get('/admin', [ViewController::class, 'admin']); $app->get('/admin/texts', [ViewController::class, 'texts']); -$app->get('/admin/texts/{textId}', [ViewController::class, 'text']); $app->get('/api/texts', [TextController::class, 'getTexts']); -$app->get('/api/texts/{textId}', [TextController::class, 'getText']); -$app->get('/api/texts/{textId}/nodes', [NodeController::class, 'getNodes']); $app->post('/api/texts', [TextController::class, 'createText']); return $app; diff --git a/bootstrap/container.php b/bootstrap/container.php index efcfde5..09a0d9a 100644 --- a/bootstrap/container.php +++ b/bootstrap/container.php @@ -4,12 +4,9 @@ use DI; use DI\Container; use App\Text\TextRepository; use App\Text\JsonTextRepository; -use App\Node\NodeRepository; -use App\Node\JsonNodeRepository; $container = new Container([ - TextRepository::class => DI\autowire(JsonTextRepository::class), - NodeRepository::class => DI\autowire(JsonNodeRepository::class), + TextRepository::class => DI\create(JsonTextRepository::class), ]); return $container; diff --git a/cypress/e2e/admin.cy.js b/cypress/e2e/admin.cy.js index e2a3b4e..5dca670 100644 --- a/cypress/e2e/admin.cy.js +++ b/cypress/e2e/admin.cy.js @@ -25,34 +25,4 @@ describe('The admin page', () => { cy.get('#submit').click() cy.contains('Test Text') }) - - it('shows one root node and child node on the seeded text page', () => { - cy.visit('/admin/texts/0') - cy.intercept('GET', '/api/texts/0/nodes').as('getNodes') - cy.wait('@getNodes') - cy.get('#text-detail > ul > li > ul > li').should('have.length', 1) - }) - - it('shows one root node on the text page', () => { - cy.visit('/admin/texts') - cy.get('#newTextName').type('My Node Text') - cy.get('#submit').click() - cy.intercept('GET', '/api/texts/1/nodes').as('getNodes') - cy.get('a').contains('My Node Text').click() - cy.wait('@getNodes') - cy.get('#text-detail > ul').should('have.length', 1) - }) - - it('navigates to a specific texts page', () => { - cy.visit('/admin/texts') - cy.get('#newTextName').type('My New Text') - cy.get('#submit').click() - cy.intercept('GET', '/admin/texts/1').as('textPage') - cy.get('a') - .contains('My New Text') - .should('have.attr', 'href', '/admin/texts/1') - .click() - cy.url().should('include', '/admin/texts/1') - cy.wait('@textPage').its('response.statusCode').should('eq', 200) - }) }) diff --git a/data/seedDb.php b/data/seedDb.php index 28bc820..d8d3698 100644 --- a/data/seedDb.php +++ b/data/seedDb.php @@ -7,24 +7,8 @@ $texts = [ ], ]; -$nodes = [ - [ - 'id' => 0, - 'title' => 'Chapter 1', - 'textId' => 0, - 'parentNodeId' => null, - ], - [ - 'id' => 1, - 'title' => 'Section 1.1', - 'textId' => 0, - 'parentNodeId' => 0, - ], -]; - $fileDataMap = [ 'texts.json' => $texts, - 'nodes.json' => $nodes, ]; foreach ($fileDataMap as $file => $data) { diff --git a/data/wipeDb.php b/data/wipeDb.php index 2d71990..b180c35 100644 --- a/data/wipeDb.php +++ b/data/wipeDb.php @@ -2,7 +2,6 @@ $files = [ 'texts.json', - 'nodes.json', ]; foreach ($files as $file) { diff --git a/public/js/text.js b/public/js/text.js deleted file mode 100644 index 985ca15..0000000 --- a/public/js/text.js +++ /dev/null @@ -1,50 +0,0 @@ -document.addEventListener('DOMContentLoaded', () => { - const textId = window.location.pathname.split('/').pop(); - - fetch('/api/texts/' + textId) - .then(res => res.json()) - .then(text => { - const h1 = document.createElement('h1'); - h1.textContent = text.name; - document.getElementById('text-detail').appendChild(h1); - - return fetch('/api/texts/' + textId + '/nodes'); - }) - .then(res => res.json()) - .then(nodes => { - const tree = buildTree(nodes); - const ul = renderTree(tree); - document.getElementById('text-detail').appendChild(ul); - }); -}); - -function buildTree(nodes) { - const map = {}; - nodes.forEach(node => { - map[node.id] = { ...node, children: [] }; - }); - - const roots = []; - nodes.forEach(node => { - if (node.parentNodeId === null) { - roots.push(map[node.id]); - } else if (map[node.parentNodeId]) { - map[node.parentNodeId].children.push(map[node.id]); - } - }); - - return roots; -} - -function renderTree(nodes) { - const ul = document.createElement('ul'); - nodes.forEach(node => { - const li = document.createElement('li'); - li.textContent = node.title; - if (node.children.length > 0) { - li.appendChild(renderTree(node.children)); - } - ul.appendChild(li); - }); - return ul; -} diff --git a/public/js/texts.js b/public/js/texts.js index 1937749..9421c20 100644 --- a/public/js/texts.js +++ b/public/js/texts.js @@ -5,12 +5,7 @@ document.addEventListener('DOMContentLoaded', () => { async function loadTexts() { const res = await fetch('/api/texts'); const texts = await res.json(); - textsList.innerHTML = texts.map(text => - '
  • ' - + text.name - + '
  • ').join(''); + textsList.innerHTML = texts.map(text => '
  • ' + text.name + '
  • ').join(''); } form.addEventListener('submit', async (e) => { @@ -23,10 +18,7 @@ document.addEventListener('DOMContentLoaded', () => { if (res.ok) { const text = await res.json(); const li = document.createElement('li'); - const a = document.createElement('a'); - a.href = '/admin/texts/' + text.id; - a.textContent = text.name; - li.appendChild(a); + li.textContent = text.name; textsList.appendChild(li); form.reset(); } diff --git a/tests/Unit/Text/UseCases/CreateTextTest.php b/tests/Unit/Text/UseCases/CreateTextTest.php index 4119662..e4b8422 100644 --- a/tests/Unit/Text/UseCases/CreateTextTest.php +++ b/tests/Unit/Text/UseCases/CreateTextTest.php @@ -7,48 +7,19 @@ use App\Text\TextRepository; use App\Text\UseCases\CreateText; use App\Text\UseCases\CreateTextRequest; use PHPUnit\Framework\TestCase; -use Tests\Fakes\FakeNodeRepository; use Tests\Fakes\FakeTextRepository; class CreateTextTest extends TestCase { - private FakeTextRepository $textRepo; - - private FakeNodeRepository $nodeRepo; - - private CreateText $useCase; - - protected function setUp(): void - { - $this->textRepo = new FakeTextRepository; - $this->nodeRepo = new FakeNodeRepository; - $this->useCase = new CreateText( - $this->textRepo, - $this->nodeRepo, - ); - } - public function test_create_text(): void { - $text = $this->useCase->execute(new CreateTextRequest( + $textRepo = new FakeTextRepository; + $useCase = new CreateText($textRepo); + $text = $useCase->execute(new CreateTextRequest( name: 'test', )); - $this->assertInstanceOf(TextRepository::class, $this->textRepo); + $this->assertInstanceOf(TextRepository::class, $textRepo); $this->assertInstanceOf(Text::class, $text); $this->assertEquals('test', $text->getName()); } - - public function test_creates_root_node_on_text_creation(): void - { - $text = $this->useCase->execute(new CreateTextRequest( - name: 'my text', - )); - - $nodes = $this->nodeRepo->findByTextId($text->getId()); - $this->assertCount(1, $nodes); - - $rootNode = array_values($nodes)[0]; - $this->assertEquals('my text', $rootNode->getTitle()); - $this->assertNull($rootNode->getParentNode()); - } } diff --git a/tests/e2e/Controllers/TextControllerTest.php b/tests/e2e/Controllers/TextControllerTest.php deleted file mode 100644 index bcf1e30..0000000 --- a/tests/e2e/Controllers/TextControllerTest.php +++ /dev/null @@ -1,87 +0,0 @@ -textRepo = new FakeTextRepository; - $this->textRepo->create(new CreateTextDto( - name: 'test text', - )); - $this->controller = new TextController($this->textRepo); - } - - public function test_get_one_text(): void - { - $response = $this->controller->getText( - new Response(), - 0, - ); - $this->assertEquals( - json_encode([ - 'id' => 0, - 'name' => 'test text', - ]), - $response->getBody() - ); - } - - public function test_get_all_texts(): void - { - $this->textRepo->create(new CreateTextDto( - name: 'test text 2', - )); - $response = $this->controller->getTexts(new Response()); - $this->assertEquals( - json_encode([ - [ - 'id' => 0, - 'name' => 'test text', - ], - [ - 'id' => 1, - 'name' => 'test text 2', - ] - ]), - $response->getBody() - ); - } - - public function test_create_text(): void - { - $request = (new ServerRequestFactory()) - ->createServerRequest('POST', 'http://localhost/texts') - ->withParsedBody(['name' => 'my new text']); - - $response = $this->controller->createText( - $request, - new Response(), - new CreateText( - $this->textRepo, - new FakeNodeRepository, - ), - ); - $this->assertEquals( - json_encode([ - 'id' => 1, - 'name' => 'my new text', - ]), - $response->getBody() - ); - } -} diff --git a/views/templates/text.php b/views/templates/text.php deleted file mode 100644 index 8f68729..0000000 --- a/views/templates/text.php +++ /dev/null @@ -1,11 +0,0 @@ - - - - Daily Goals - Text - - - Back to Texts -
    - - -