Skip to content

Commit 330ef5b

Browse files
committed
init
0 parents  commit 330ef5b

19 files changed

+820
-0
lines changed

Application.php

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
namespace App\Core;
4+
5+
use App\Core\DB\Database;
6+
use Exception;
7+
8+
class Application
9+
{
10+
public static string $ROOT_DIR;
11+
public static Application $app;
12+
public string $layout = 'main';
13+
public string $userClass;
14+
public Router $router;
15+
public Request $request;
16+
public Response $response;
17+
public ?Controller $controller = null;
18+
public Database $db;
19+
public Session $session;
20+
public ?UserModel $user;
21+
public View $view;
22+
23+
public function __construct($rootPath, array $config)
24+
{
25+
$this->userClass = $config['userClass'];
26+
self::$ROOT_DIR = $rootPath;
27+
self::$app = $this;
28+
$this->request = new Request();
29+
$this->response = new Response();
30+
$this->session = new Session();
31+
$this->router = new Router($this->request, $this->response);
32+
$this->view = new View();
33+
34+
$this->db = new Database($config['db']);
35+
36+
$primaryValue = $this->session->get('user');
37+
if ($primaryValue) {
38+
$primaryKey = $this->userClass::primaryKey();
39+
$this->user = $this->userClass::findOne([$primaryKey => $primaryValue]);
40+
} else {
41+
$this->user = null;
42+
}
43+
44+
}
45+
46+
public static function isGuest(): bool
47+
{
48+
return !self::$app->user;
49+
}
50+
51+
public function run()
52+
{
53+
try {
54+
echo $this->router->resolve();
55+
} catch (Exception $e) {
56+
$this->response->setStatusCode($e->getCode());
57+
echo $this->view->renderView('_error', [
58+
'e' => $e
59+
]);
60+
}
61+
}
62+
63+
public function login(UserModel $user): bool
64+
{
65+
$this->user = $user;
66+
$primaryKey = $user->primaryKey();
67+
68+
$primaryValue = $user->{$primaryKey};
69+
70+
$this->session->set('user', $primaryValue);
71+
72+
return true;
73+
}
74+
75+
public function logout()
76+
{
77+
$this->user = null;
78+
$this->session->remove('user');
79+
}
80+
}

Controller.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace App\Core;
4+
5+
use App\Core\Middlewares\BaseMiddleware;
6+
7+
class Controller
8+
{
9+
public string $layout = 'main';
10+
public string $action = '';
11+
12+
/** @var BaseMiddleware[] */
13+
protected array $middlewares = [];
14+
15+
public function registerMiddleware(BaseMiddleware $middleware)
16+
{
17+
$this->middlewares[] = $middleware;
18+
}
19+
20+
public function setLayout($layout)
21+
{
22+
$this->layout = $layout;
23+
}
24+
25+
public function render($view, $params = [])
26+
{
27+
return Application::$app->view->renderView($view, $params);
28+
}
29+
30+
/**
31+
* @return BaseMiddleware[]
32+
*/
33+
public function getMiddlewares(): array
34+
{
35+
return $this->middlewares;
36+
}
37+
}

DB/Database.php

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
namespace App\Core\DB;
4+
5+
use App\Core\Application;
6+
use PDO;
7+
8+
class Database
9+
{
10+
public PDO $pdo;
11+
12+
13+
public function __construct(array $config)
14+
{
15+
$dsn = $config['dsn'] ?? '';
16+
$user = $config['user'] ?? '';
17+
$password = $config['password'] ?? '';
18+
$this->pdo = new PDO($dsn, $user, $password);
19+
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
20+
}
21+
22+
public function applyMigrations()
23+
{
24+
$this->createMigrationsTable();
25+
26+
$appliedMigrations = $this->getAppliedMigrations();
27+
28+
$files = scandir(Application::$ROOT_DIR . '/migrations');
29+
30+
$toApplyMigrations = array_diff($files, $appliedMigrations);
31+
$newMigrations = [];
32+
33+
foreach ($toApplyMigrations as $migration) {
34+
if ($migration === '.' || $migration === '..') {
35+
continue;
36+
}
37+
38+
require_once Application::$ROOT_DIR . '/migrations/' . $migration;
39+
40+
$className = pathinfo($migration, PATHINFO_FILENAME);
41+
42+
$instance = new $className();
43+
$this->log("Applying migration $migration");
44+
$instance->up();
45+
46+
$this->log("Applied migration $migration");
47+
48+
$newMigrations[] = $migration;
49+
}
50+
51+
if (!empty($newMigrations)) {
52+
$this->saveMigrations($newMigrations);
53+
} else {
54+
$this->log("All Migrations are applied");
55+
}
56+
}
57+
58+
public function createMigrationsTable()
59+
{
60+
$this->pdo->exec("
61+
CREATE TABLE IF NOT EXISTS migrations(
62+
id INT AUTO_INCREMENT PRIMARY KEY,
63+
migration VARCHAR(255),
64+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
65+
)
66+
ENGINE=INNODB;
67+
");
68+
}
69+
70+
public function getAppliedMigrations()
71+
{
72+
$statement = $this->pdo->prepare("SELECT migration from migrations");
73+
$statement->execute();
74+
75+
return $statement->fetchAll(PDO::FETCH_COLUMN);
76+
}
77+
78+
protected function log($message)
79+
{
80+
echo '[' . date('Y-m-d H:i:s') . '] - ' . $message . PHP_EOL;
81+
}
82+
83+
public function saveMigrations(array $migrations)
84+
{
85+
$str = implode(",", array_map(fn($migration) => "('$migration')", $migrations));
86+
87+
$statement = $this->pdo->prepare("
88+
INSERT INTO migrations (migration) VALUES
89+
$str
90+
");
91+
92+
$statement->execute();
93+
}
94+
95+
public function prepare($sql)
96+
{
97+
return $this->pdo->prepare($sql);
98+
}
99+
}

DB/DbModel.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace App\Core\DB;
4+
5+
use App\Core\Application;
6+
use App\Core\Model;
7+
8+
abstract class DbModel extends Model
9+
{
10+
public static function findOne(array $where)
11+
{
12+
$tableName = static::tableName();
13+
$attributes = array_keys($where);
14+
15+
$sql = implode("AND", array_map(fn($attr) => "$attr = :$attr", $attributes));
16+
17+
$statement = self::prepare("SELECT * FROM $tableName WHERE $sql");
18+
19+
foreach ($where as $key => $value) {
20+
$statement->bindValue(":$key", $value);
21+
}
22+
23+
$statement->execute();
24+
return $statement->fetchObject(static::class);
25+
}
26+
27+
public function save(): bool
28+
{
29+
$tableName = $this->tableName();
30+
$attributes = $this->attributes();
31+
32+
$params = array_map(fn($p) => ":$p", $attributes);
33+
34+
$statement = self::prepare("INSERT INTO $tableName (" . implode(',', $attributes) . ") VALUES (" . implode(',', $params) . ")");
35+
36+
foreach ($attributes as $attribute) {
37+
$statement->bindValue(":$attribute", $this->{$attribute});
38+
}
39+
40+
$statement->execute();
41+
return true;
42+
}
43+
44+
abstract public function tableName(): string;
45+
46+
abstract public function attributes(): array;
47+
48+
public static function prepare($sql)
49+
{
50+
return Application::$app->db->pdo->prepare($sql);
51+
}
52+
53+
abstract public function primaryKey(): string;
54+
}

Exceptions/ForbiddenException.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace App\Core\Exceptions;
4+
5+
class ForbiddenException extends \Exception
6+
{
7+
protected $code = 403;
8+
protected $message = "You don't have permission to access this page";
9+
}

Exceptions/NotFoundException.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace App\Core\Exceptions;
4+
5+
class NotFoundException extends \Exception
6+
{
7+
protected $code = 404;
8+
protected $message = 'Not Found';
9+
}

Form/BaseField.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace App\Core\Form;
4+
5+
use App\Core\Model;
6+
7+
abstract class BaseField
8+
{
9+
public Model $model;
10+
public string $attribute;
11+
12+
public function __construct(Model $model, string $attribute)
13+
{
14+
$this->model = $model;
15+
$this->attribute = $attribute;
16+
}
17+
18+
public function __toString()
19+
{
20+
return sprintf('
21+
<div class="form-group">
22+
<label>%s</label>
23+
%s
24+
<div class="invalid-feedback">
25+
%s
26+
</div>
27+
</div>
28+
',
29+
$this->model->getLabel($this->attribute),
30+
$this->renderInput(),
31+
$this->model->getFirstError($this->attribute)
32+
);
33+
}
34+
35+
abstract public function renderInput(): string;
36+
}

Form/Form.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace App\Core\Form;
4+
5+
use App\Core\Model;
6+
7+
class Form
8+
{
9+
public static function begin($action, $method): Form
10+
{
11+
echo sprintf('<form action="%s" method="%s">' , $action, $method);
12+
return new self();
13+
}
14+
15+
public static function end(): void
16+
{
17+
echo '</form>';
18+
}
19+
20+
public function field(Model $model , $attribute): InputField
21+
{
22+
return new InputField($model, $attribute);
23+
}
24+
}

0 commit comments

Comments
 (0)