A feladat, hogy a kiinduló szkriptet refaktoráljuk, hogy egy fenntarthatóbb és átláthatóbb kódot kapjunk.
- kiindulo: Kiinduló állapot
- refactor: Refaktorált állapot
- framework: Refaktorálva keretrendszer segítségével
- demo2023: Végső állapot
- kiindulo2022: Kiinduló állapot
- demo2022: Végső állapot
- Vizsgáljuk meg, hogy mitől nehezen fenntartható a kiinduló projekt!
- Refaktoráljuk a kódot, és készítsünk egy routert!
- Válasszuk szét a logikai és megjelenítési réteget!
- Elemezzük a framework branchen található projektet!
- Implementáljuk a szerkesztés funkciót!
A projektben található php fájlok számos duplikációt tartalmaznak. Láthatjuk, hogy ugyanazt az alap html-t használja mindegyik, pl.: fejléc. Ez azt jelenti, ha szeretnénk egy újabb menüpontot felvenni, akkor minden fájlban módosítani kell ezt a részt, ami sok fájlnál nehezen karbantartható.
A logikai részben is látható számos duplikáció. Például mindegyik fájl elején kapcsolódunk az adatbázishoz. Tegyük fel a projektünk életében eljön a pillanat, hogy más típusú adatbázis kapcsolatot is szeretnénk támogatni. Ebben az esetben minden fájlban módosítani kell az adatbázis kapcsolathoz kapcsolódó kódrészleteket, ami szintén sok veszélyt rejt önmagába.
Ha vizsgáljuk a tasks.php
fájlt, láthatjuk hogy egy kódblokkban található a listázás, az új elem beszúrás, a módosítás és a törlés is. Az egymástól független funkciók befolyásolhatják a többi funkció működését ezért már a kódolásnál figyelembe kell vennünk, hogy ezek milyen hatással vannak egymásra. Ez azt eredményezi, hogy nem tudunk csak a lényegre koncentrálni és a kódunk hamar nehezen átláthatóvá válik. Egy esetleges módosítás során sok időt vehet igénybe, mire megtaláljuk a kérdéses kódrészletet.
Az előző problémából következően az új funkcióknak sincs hely. Egy esetleges új funkció implementálása során a meglévő kódsorok közé kell beszúrni új kódot, ami potenciálisan elronthatja a meglévő kódot is. Egy komplex alkalmazás esetében nehéz lehet átlátni, hogy hova kell beszúrni a kérdéses új funkciót. Arról nem is beszélve, ha nem a saját kódunkat kell kiegészíteni, hanem valaki más kódját.
Hozzunk létre egy új mappát pages
néven, és másoljuk át a php fájlokat ebbe a mappába! Így a kapott struktúra a következő lesz:
htdocs
│ .gitignore
│ db.sql
│ README.md
└─pages
│ index.php
│ tasks.php
└ users.php
Hozzunk létre egy új index.php fájlt a projekt gyökerében, és másoljuk be a következő kódrészletet:
<?php
// Define routes
$routes = [
'/' => './pages/index.php',
'/users' => './pages/users.php',
'/tasks' => './pages/tasks.php'
];
// Determine current root
// $_SERVER["REQUEST_URI"] contains the requested uri, eg.: /tasks?user=1
// strtok(...) removes the query string
// trim(....) removes the '/' characters from the beginning and in the end
$path = '/' . trim(strtok($_SERVER["REQUEST_URI"],'?'), '/');
// Check if route exists
// If not exists, then return with "404 - Not found" error message
if(!array_key_exists($path, $routes)){
http_response_code(404);
die("404 - Not found");
}
// Return with the requested page
require $routes[$path];
Ahhoz, hogy a kód működjön, szükség van arra, hogy minden kérést az index.php
-ra dolgozzon fel. Hozzunk létre a projekt gyökerében egy .htaccess
fájlt és másoljuk be a következő kódrészletet:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php [NC,L,QSA]
Cseréljük ki az összes fájlban az index.php
, users.php
és tasks.php
linkeket /
, /users
és /tasks
linkekre.
- Nevezzük át a
pages
mappátcontrollers
névre, és frissítsük ennek megfelelően azindex.php
-t is. - Hozzunk létre egy
views
mappát és abbanlayout.view.php
,index.view.php
,users.view.php
éstasks.view.php
fájlokat! Az így kapott struktúra a következő:
htdocs
│ .gitignore
│ .htaccess
│ db.sql
│ index.php
│ README.md
├ controllers
│ │ index.php
│ │ tasks.php
│ └ users.php
└ views
│ index.view.php
│ tasks.view.php
└ users.view.php
- Másoljuk az
index.php
tartalmát alayout.view.php
fájlba! - Cseréljük ki a
div.container.my-4.flex-grow-1
elemet a fájlban a<?php require $view; ?>
elemre! - Másoljuk át az egyes view fájlokba az eredeti fájlokból a
div.container.my-4.flex-grow-1
elemet és tartalmát! - Az eredeti fájlokban törüljük ki a teljes html tartalmat és másoljuk be a fájlok végére a megfelelő sorokat:
// index.php
$view = 'views/index.view.php';
require 'views/layout.view.php';
// users.php
$view = 'views/users.view.php';
require 'views/layout.view.php';
// tasks.php
$view = 'views/tasks.view.php';
require 'views/layout.view.php';
Nézzük át részletesen az egyes funkciók működését!
A TaskController
osztályba vegyük fel az edit
és update
új metódust!
/**
* Show the form for editing the specified resource.
*/
public function edit(Task $task): View
{
return view('edit', compact('task'));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Task $task): RedirectResponse
{
$request->validate([
'title' => 'required',
'description' => 'required'
], [], [
'title' => 'cím',
'description' => 'leírás'
]);
$task->update($request->input());
$task->save();
return redirect()->route('tasks.index', $task->user);
}
Készítsük el a megfelelő route-okat a két új metódusra:
Route::get('/tasks/{task}/edit', [TaskController::class, 'edit'])->name('tasks.edit');
Route::put('/tasks/{task}/edit', [TaskController::class, 'update'])->name('tasks.update');
Illesszünk be egy linket a szerkesztő nézetre a tasks.blade.php
fájlba:
...
@if($task->status == 'new')
<div class="d-flex gap-2">
<a href="{{route('tasks.edit', $task)}}" class="btn btn-outline-warning">
<i class="bi bi-pencil"></i>
</a>
...
</div>
@endif
...
Végül készítsünk egy edit.blade.php
view fájlt:
@extends('layout')
@section('content')
<div class="container my-4 flex-grow-1">
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{{route('index')}}">Kezdőlap</a></li>
<li class="breadcrumb-item"><a href="{{route('users')}}">Felhasználók</a></li>
<li class="breadcrumb-item"><a href="{{route('tasks.index', $task->user)}}">{{$task->user->name}}</a></li>
<li class="breadcrumb-item active" aria-current="page">{{$task->title}}</li>
</ol>
</nav>
<div class="card shadow-sm border-0 mb-4">
<div class="card-body">
<h5 class="card-title">
Feladat szerkesztése
</h5>
<form method="post" action="{{route('tasks.update', $task)}}">
@csrf
@method("put")
<div class="mb-3">
<label for="title" class="form-label">Cím</label>
<input type="text" id="title" name="title" value="{{old('title') ? old('title') : $task->title}}"
class="form-control @error('title') is-invalid @enderror">
@error('title')
<div class="invalid-feedback">
{{$message}}
</div>
@enderror
</div>
<div class="mb-3">
<label for="description" class="form-label">Leírás</label>
<textarea id="description" name="description"
class="form-control @error('description') is-invalid @enderror"
rows="10">{{old('description') ? old('description') : $task->description}}</textarea>
@error('description')
<div class="invalid-feedback">
{{$message}}
</div>
@enderror
</div>
<button type="submit" class="btn btn-primary">Mentés</button>
</form>
</div>
</div>
</div>
@endsection