** Models
Le classi "Model" gestiscono i dati presenti nel database e controlla che i dati seguano delle determinate regole.
-Tutte le classi Model derivano dalla classe "BaseModel".
+Tutte le classi Model derivano dalla classe "BaseModel" o "DbModel".
-*** Registration model
+*** Registration model - User model
Il model di registrazione si occupa della gestione dei dati di nuovi utenti e dell'interazione con il database.
Attraverso l'implementazione del metodo astratto "rules()" si possono impostare le regole che i campi della form dovranno seguire.
-*Attenzione*: i nomi dei parametri, i nomi inseriti nella array resistituito da "rules()" ed i nomi dei [[./www/core/forms/Field.php][Field]] _devono_ essere uguali.
-# TODO: register()
+I nomi dei parametri di questa classe non devono necessariamente coincidere con i label visibili dall'utente.
+Questo perchè utilizzando il metodo "labels()" è possibile mappare i nomi dei parametri ai label che appaiono all'utente.
+
+L'effettiva registrazione dell'utente attraverso l'inserimento dei valori all'interno del database viene eseguita dal metodo "save()".
+"save()" è un metodo a cui tutti i model che estendono "DbModel" possono accedere, questo perchè sono la rappresentazione della tabella presente nel database.
+
+*** Login model - LoginForm model
+Model molto semplice, non basato sul DbModel ma bensì sul BaseModel in quanto non deve interagire direttamente con il database.
+
+Inviata la POST request per effettuare il login esso cerca nel database un utente che abbia l'indirizzo email fornito dall'utente, se lo trova controlla la correttezza della password.
+
+*** Vtuber model
+Model utilizzato per interagire con il database di vtuber.
+
+Simile al model di registrazione ma con 2 importanti metodi:
+- *getVtuberInfo()*: controlla che il link inserito sia l'URL ad un canale twitch o youtube ed utilizzando i rispettivi API(Twitch o Google) recupara le informazioni della vtuber in questione
+- *isLive()*: controlla se la vtuber in questione è live o no, utilizzando l'API Twitch o tramite curl request per canali YT
** Controllers
Le classi "Controller" svolgono il ruolo di ponte.
L'authentication controller ha 2 compiti fondamentali:
- registrare nuovi utenti con l'aiuto della classe "RegisterModel"
- permettere l'accesso ad utenti già registrati
-# TODO
<?php
namespace app\controllers;
+use app\core\Application;
use app\core\BaseController;
use app\core\Request;
+use app\models\LoginForm;
use app\models\User;
class AuthController extends BaseController{
- public function login() {
- // $this->setLayout("auth");
- return $this->render("login");
+ public function login(Request $req) {
+ $loginForm = new LoginForm;
+
+ if ($req->getMethod() == "post"){
+ $loginForm->loadData($req->getBody());
+
+ if ($loginForm->validate() && $loginForm->login()) {
+ Application::$app->res->redirect("/");
+ return;
+ }
+ }
+
+ return $this->render("login", [ "model" => $loginForm ]);
}
public function register(Request $req) {
- // $this->setLayout("auth");
- $errors = [];
$registerModel = new User;
if ($req->getMethod() == "post") {
$registerModel->loadData($req->getBody());
if ($registerModel->validate() && $registerModel->register()) {
- return "Success";
+ Application::$app->res->redirect("/");
}
}
return $this->render("register", [ "model" => $registerModel ]);
public function live(Request $req)
{
$params = [];
+ $statement = Application::$app->db->pdo->prepare("SELECT * FROM vtubers;");
$vtuberModel = new Vtubers;
if ($req->getMethod() == "post") {
$vtuberModel->loadData($req->getBody());
- $vtuberModel->getVtuberName();
+ $vtuberModel->getVtuberInfo();
if ($vtuberModel->validate() && $vtuberModel->register()) {
- return "Success";
+ Application::$app->res->redirect("/");
}
} else if ($req->getMethod() == "get") {
- $statement = Application::$app->db->pdo->prepare("SELECT * FROM vtubers;");
+ if (isset($_GET["id"])) {
+ $this->setLayout("live");
+ $statement = Application::$app->db->pdo->prepare("SELECT * from vtubers where id={$_GET['id']}");
+ }
$statement->execute();
foreach ($statement->fetchAll() as $vtuber) {
- $params[] = ["vtuber" => [ $vtuber, $vtuberModel->isLive($vtuber["login"], $vtuber["link"]) ]];
+ $params[] = [ $vtuber, $vtuberModel->isLive($vtuber["login"], $vtuber["link"]) ];
}
- // echo "<pre>";
- // var_dump($params);
- // echo "</pre";
}
- if (isset($_GET["id"]))
- $this->setLayout("live");
return $this->render("live", ["model" => $vtuberModel, $params]);
}
}
class Application {
private BaseController $controller;
+ public $userClass;
+ public array $config;
public Router $router;
public Request $req;
public Response $res;
public Database $db;
- public array $config;
+ public Session $session;
+ public ?DbModel $user = null;
public static Application $app;
public static string $ROOT_DIR;
self::$ROOT_DIR = $root;
self::$app = $this;
+ $this->userClass = $config["userClass"];
$this->config = $config;
$this->req = new Request();
$this->res = new Response();
$this->router = new Router($this->req, $this->res);
+ $this->session = new Session;
+
$this->db = new Database($config["db"]);
+
+ $primaryValue = $this->session->get("user");
+ if ($primaryValue) {
+ $primaryKey = $this->userClass::primaryKey();
+ $this->user = $this->userClass::findOne([$primaryKey => $primaryValue]);
+ }
}
public function run() {
public function setController(BaseController $controller) {
$this->controller = $controller;
}
+
+ public function login(DbModel $user) {
+ $this->user = $user;
+ $primaryKey = $user->primaryKey();
+ $primaryValue = $user->{$primaryKey};
+
+ $this->session->set("user", $primaryValue);
+
+ return true;
+ }
+
+ public function logout() {
+ $this->user = null;
+ $this->session->remove("user");
+ }
}
?>
abstract public function rules(): array;
+ public function labels(): array {
+ return [];
+ }
+
+ public function getLabel(string $attribute) {
+ return $this->labels()[$attribute] ?? $attribute;
+ }
+
public function validate() {
foreach ($this->rules() as $attribute => $rules) {
$value = $this->{$attribute};
}
if ($ruleName == self::RULE_REQUIRED && !$value) {
- $this->addError($attribute, self::RULE_REQUIRED);
+ $this->internalAddError($attribute, self::RULE_REQUIRED);
}
if ($ruleName == self::RULE_EMAIL && !filter_var($value, FILTER_VALIDATE_EMAIL)) {
- $this->addError($attribute, self::RULE_EMAIL);
+ $this->internalAddError($attribute, self::RULE_EMAIL);
}
if ($ruleName == self::RULE_MIN && strlen($value) < $rule["min"]) {
- $this->addError($attribute, self::RULE_MIN, $rule);
+ $this->internalAddError($attribute, self::RULE_MIN, $rule);
}
if ($ruleName == self::RULE_MAX && strlen($value) > $rule["max"]) {
- $this->addError($attribute, self::RULE_MAX, $rule);
+ $this->internalAddError($attribute, self::RULE_MAX, $rule);
}
if ($ruleName == self::RULE_MATCH && $value != $this->{$rule["match"]}) {
- $this->addError($attribute, self::RULE_MATCH, $rule);
+ $this->internalAddError($attribute, self::RULE_MATCH, $rule);
}
if ($ruleName == self::RULE_UNIQUE) {
$className = $rule["class"];
$statement->execute();
if($statement->fetchObject()) {
- $this->addError($attribute, self::RULE_UNIQUE, ["field" => $attribute]);
+ $this->internalAddError($attribute, self::RULE_UNIQUE, ["field" => $this->getLabel($attribute)]);
}
}
}
return empty($this->errors);
}
- public function addError(string $attribute, string $rule, $params = []) {
+ private function internalAddError(string $attribute, string $rule, $params = []) {
$message = $this->errorMessages()[$rule] ?? "";
foreach ($params as $key => $value) {
- $message = str_replace("{{$key}}", $value, $message);
+ $message = str_replace("{{$key}}", strtolower($this->getLabel($value)), $message);
}
$this->errors[$attribute][] = $message;
}
+ public function addError(string $attribute, string $message) {
+ $this->errors[$attribute][] = $message;
+ }
+
public function errorMessages() {
return [
self::RULE_REQUIRED => "This field is required",
abstract class DbModel extends BaseModel
{
- abstract public function tableName(): string;
+ abstract public static function tableName(): string;
+ abstract public static function primaryKey(): string;
abstract public function attributes(): array;
public function save()
return true;
}
+ public static function findOne(array $where) {
+ $tableName = static::tableName();
+ $attributes = array_keys($where);
+
+ $sql = implode(" AND ", array_map(fn($attr) => "$attr = :$attr", $attributes));
+
+ $statement = self::prepare("SELECT * FROM $tableName WHERE $sql");
+ foreach ($where as $key => $value) {
+ $statement->bindValue(":$key", $value);
+ }
+ $statement->execute();
+
+ return $statement->fetchObject(static::class);
+ }
+
public static function prepare(string $sql) {
return Application::$app->db->pdo->prepare($sql);
}
public function setStatusCode(int $code) {
http_response_code($code);
}
+
+ public function redirect(string $url) {
+ header("Location: $url");
+ }
}
?>
--- /dev/null
+<?php
+namespace app\core;
+
+class Session {
+
+ public function __construct()
+ {
+ session_start();
+ }
+
+ public function get($key) {
+ return $_SESSION[$key] ?? false;
+ }
+
+ public function set($key, $value) {
+ $_SESSION[$key] = $value;
+ }
+
+ public function remove($key) {
+ unset($_SESSION[$key]);
+ }
+}
+?>
<input name="%s" type="%s" value="%s" class="form-control%s"/>
<div class="invalid-feedback">%s</div>
</div>',
- ucfirst($this->attribute),
+ $this->model->getLabel($this->attribute),
$this->attribute,
$this->type,
$this->model->{$this->attribute},
--- /dev/null
+<?php
+namespace app\models;
+
+use app\core\Application;
+use app\core\BaseModel;
+
+class LoginForm extends BaseModel
+{
+ public string $email = "";
+ public string $password = "";
+
+ public function rules(): array
+ {
+ return [
+ "email" => [self::RULE_REQUIRED, self::RULE_EMAIL],
+ "password" => [self::RULE_REQUIRED]
+ ];
+ }
+
+ public function login() {
+ $user = User::findOne(["email" => $this->email]);
+
+ if (!$user) {
+ $this->addError("email", "User does not exist!");
+ return false;
+ } else {
+ if (!password_verify($this->password, $user->password)) {
+ $this->addError("password", "Password is incorrect");
+ return false;
+ }
+ }
+
+ return Application::$app->login($user);
+ }
+
+ public function labels(): array
+ {
+ return [
+ "email" => "Your account email",
+ "password" => "The super secret password to your epic account"
+ ];
+ }
+}
public string $password = "";
public string $confirm = "";
- public function tableName(): string
+ public static function tableName(): string
{
return "users";
}
+ public static function primaryKey(): string
+ {
+ return "id";
+ }
+
public function attributes(): array {
return [ "firstname", "lastname", "email", "username", "password" ];
}
"lastname" => [self::RULE_REQUIRED],
"username" => [self::RULE_REQUIRED],
"email" => [self::RULE_REQUIRED, self::RULE_EMAIL, [self::RULE_UNIQUE, "class" => self::class ]],
- "password" => [self::RULE_REQUIRED, [self::RULE_MIN, "min" => 20], [self::RULE_MAX, "max" => 100]],
+ "password" => [self::RULE_REQUIRED, [self::RULE_MIN, "min" => 1], [self::RULE_MAX, "max" => 100]],
"confirm" => [self::RULE_REQUIRED, [self::RULE_MATCH, "match" => "password"]]
];
}
+
+ public function labels(): array
+ {
+ return [
+ "firstname" => "First name",
+ "lastname" => "Last name",
+ "username" => "Your username",
+ "email" => "Email",
+ "password" => "Your super secret password",
+ "confirm" => "Confirm your super secret password",
+ ];
+ }
}
public string $img = "";
public string $link = "";
- public function tableName(): string
+ public static function tableName(): string
{
return "vtubers";
}
+ public static function primaryKey(): string
+ {
+ return "id";
+ }
+
public function attributes(): array
{
return ["username", "login", "img", "link"];
}
+ public function labels(): array
+ {
+ return [
+ "link" => "Vtuber channel link",
+ ];
+ }
+
public function register()
{
return $this->save();
];
}
- public function getVtuberName()
+ public function getVtuberInfo()
{
if (str_contains($this->link, "twitch.tv")) {
$clientID = Application::$app->config["twitch"]["clientid"] ?? "";
$this->img = $response["items"][0]["snippet"]["thumbnails"]["default"]["url"];
return;
}
- $this->username = "i got you bro";
- $this->login = "i got you bro";
- $this->img = "i got you bro";
}
public function isLive(string $login, string $link)
{
- if (str_contains($link, "twitch.tv")) {
- $clientID = Application::$app->config["twitch"]["clientid"] ?? "";
- $token = Application::$app->config["twitch"]["token"] ?? "";
+ // if (str_contains($link, "twitch.tv")) {
+ // $clientID = Application::$app->config["twitch"]["clientid"] ?? "";
+ // $token = Application::$app->config["twitch"]["token"] ?? "";
- $url = "https://api.twitch.tv/helix/streams?user_login=$login";
+ // $url = "https://api.twitch.tv/helix/streams?user_login=$login";
- $ch = curl_init($url);
- curl_setopt($ch, CURLOPT_URL, $url);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($ch, CURLOPT_HTTPHEADER, array("Client-ID: $clientID", "Authorization: Bearer $token"));
+ // $ch = curl_init($url);
+ // curl_setopt($ch, CURLOPT_URL, $url);
+ // curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ // curl_setopt($ch, CURLOPT_HTTPHEADER, array("Client-ID: $clientID", "Authorization: Bearer $token"));
- $result = get_object_vars(json_decode(curl_exec($ch)));
- curl_close($ch);
+ // $result = get_object_vars(json_decode(curl_exec($ch)));
+ // curl_close($ch);
- return count($result["data"]) ? $result["data"] : [];
- }
+ // return count($result["data"]) ? $result["data"] : [];
+ // }
- if (str_contains($link, "youtube.com")) {
- $url = "https://www.youtube.com/channel/$login/live";
+ // if (str_contains($link, "youtube.com")) {
+ // $url = "https://www.youtube.com/channel/$login/live";
- $ch = curl_init($url);
- curl_setopt($ch, CURLOPT_URL, $url);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ // $ch = curl_init($url);
+ // curl_setopt($ch, CURLOPT_URL, $url);
+ // curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
- $result = curl_exec($ch);
- curl_close($ch);
+ // $result = curl_exec($ch);
+ // curl_close($ch);
- $doc = new DOMDocument();
- libxml_use_internal_errors(true);
- $doc->loadHTML($result);
- $length = $doc->getElementsByTagName('link')->length;
+ // $doc = new DOMDocument();
+ // libxml_use_internal_errors(true);
+ // $doc->loadHTML($result);
- for ($i = 0; $i < $length; $i++) {
- $result = $doc->getElementsByTagName("link")->item($i)->getAttribute("href");
- if (str_contains($result, "https://www.youtube.com/watch?v=")) {
- return [str_replace( "https://www.youtube.com/watch?v=", "", $result)];
- }
- }
+ // $result = $doc->getElementsByTagName("link");
+ // $length = $result->length;
- return [];
- }
+ // for ($i = 0; $i < $length; $i++) {
+ // $tag = $result->item($i)->getAttribute("href");
+ // if (str_contains($tag, "https://www.youtube.com/watch?v=")) {
+ // return [str_replace("https://www.youtube.com/watch?v=", "", $tag)];
+ // }
+ // }
+
+ // unset($doc);
+ // }
+
+ return [];
}
}
$dotenv->load();
$config = [
+ "userClass" => \app\models\User::class,
"db" => [
"dsn" => $_ENV["DB_DSN"],
"user" => $_ENV["DB_USER"],
+<?php
+
+use app\core\Application;
+
+echo " <pre>";
+var_dump(Application::$app->user);
+echo "</pre>";
+?>
+
<!doctype html>
<html lang="en">
echo "<h2>Currently live</h2>";
echo "<ul>";
foreach ($params[0] as $idol) {
- if (count($idol["vtuber"][1]) > 0)
- echo "<li><a href='/live?id=" . $idol["vtuber"][0]["id"] . "'>" . ucfirst($idol["vtuber"][0]["username"]) . "</a></li>";
+ if (count($idol[1]) > 0)
+ echo "<li><a href='/live?id=" . $idol[0]["id"] . "'>" . ucfirst($idol[0]["username"]) . "</a></li>";
}
echo "</ul>";
echo "<h2>Currently offline</h2>";
echo "<ul>";
foreach ($params[0] as $idol) {
- if (count($idol["vtuber"][1]) == 0)
- echo "<li><a href='/live?id=" . $idol["vtuber"][0]["id"] . "'>" . ucfirst($idol["vtuber"][0]["username"]) . "</a></li>";
+ if (count($idol[1]) == 0)
+ echo "<li><a href='/live?id=" . $idol[0]["id"] . "'>" . ucfirst($idol[0]["username"]) . "</a></li>";
}
echo "</ul>";
} else {
foreach ($params[0] as $vtuber) {
- if ($_GET["id"] == $vtuber["vtuber"][0]["id"]) {
+ if ($_GET["id"] == $vtuber[0]["id"]) {
echo "
<div id=\"parent\">
<div>
<nav class=\"navbar bg-dark text-white\">
<div class=\"container-fluid\">
- <h1>" . ucfirst($vtuber["vtuber"][0]["username"]) . "</h1><img class=\"idolLogo\" src=\"" . $vtuber["vtuber"][0]["img"] . "\"/>
+ <h1>" . ucfirst($vtuber[0]["username"]) . "</h1><img class=\"idolLogo\" src=\"" . $vtuber[0]["img"] . "\"/>
</div>
</nav>
<div id=\"child\">";
- if (str_contains($vtuber["vtuber"][0]["link"], "twitch.tv")) {
- echo "<iframe src=\"https://player.twitch.tv/?channel=".$vtuber["vtuber"][0]["login"]."&parent=localhost\" frameborder=\"0\" allowfullscreen=\"true\" scrolling=\"no\"></iframe>";
+ if (str_contains($vtuber[0]["link"], "twitch.tv")) {
+ echo "<iframe src=\"https://player.twitch.tv/?channel=".$vtuber[0]["login"]."&parent=localhost\" frameborder=\"0\" allowfullscreen=\"true\" scrolling=\"no\"></iframe>";
} else {
- echo "<iframe src=\"https://www.youtube.com/embed/".$vtuber["vtuber"][1][0]."\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>";
+ echo "<iframe src=\"https://www.youtube.com/embed/".$vtuber[1][0]."\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>";
}
echo "</div></div>";
<h1>Login page</h1>
<div class="container">
-<form action="" method="post">
- <div class="mb-3">
- <label for="exampleInputEmail1" class="form-label">Email address</label>
- <input name="email" type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp">
- <div id="emailHelp" class="form-text">We'll never share your email with anyone else.</div>
- </div>
- <div class="mb-3">
- <label for="exampleInputPassword1" class="form-label">Password</label>
- <input name="pass" type="password" class="form-control" id="exampleInputPassword1">
- </div>
- <div class="mb-3 form-check">
- <input name="check" type="checkbox" class="form-check-input" id="exampleCheck1">
- <label class="form-check-label" for="exampleCheck1">Check me out</label>
- </div>
- <button type="submit" class="btn btn-primary">Submit</button>
-</form>
+ <?php $form = app\core\forms\Form::begin("", "post"); ?>
+ <?php echo $form->field($model, "email"); ?>
+ <?php echo $form->field($model, "password")->passwordField(); ?>
+
+ <button type="submit" class="btn btn-primary">Submit</button>
+ <?php app\core\forms\Form::end(); ?>
</div>