changements faits

This commit is contained in:
Florian Bouillon 2019-03-02 00:49:48 +01:00
parent 91806d4112
commit cb6f9a967b
15 changed files with 349 additions and 327 deletions

View File

@ -5,3 +5,4 @@
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous" />
<link rel="stylesheet" type="text/css" media="screen" href="/assets/css/style.css"/>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script src="/assets/js/script.js" defer=""></script>

View File

@ -0,0 +1,84 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<header>
<tag type="includes" file="header" />
</header>
<main class="test container">
<div class="bloc-post">
<div class="container-post post column-cat">
<h2 class="title"><tag type="article" column="title" /></h2>
<div class="etiquettes">
<span class="cat"><tag type="article" column="category"/></span>
<span class="date"><tag type="article" column="datetime"/></span>
</div>
<p class="post text">
<tag type="article" column="content"/>
</p>
</div>
<div class="credit">
<h3>Auteur</h3>
<div class="author">
<a>
<tag type="svg" file="avatar" style="color: white; height: 64px" /></a>
<div class="by">
<h3 class="name"><tag type="authorTag" column="username" /></h3>
<h3 class="job"><tag type="authorTag" column="job" /></h3>
</div>
</div>
</div>
</div>
<div class="bloc-filter">
<h3>Plus d'articles</h3>
<p class="title-small">Catégories</p>
<div class="filtre dev-color">dev</div>
<div class="filtre digi-color">digi</div>
<div class="filtre ops-color">ops</div>
<div class="filtre devops-color">devops</div>
<p class="title-small">Tags</p>
<tag type="tags" />
</div>
<div class="bloc-recent">
<div class="contenue-recent">Article précédent</div>
<div class="contenue-recent next">Article suivant</div>
</div>
<h3 id="titre-between">Dans le même thème</h3>
<div class="row articles">
<tag type="loop" for="posts" limit="6" category="true">
<a class="col-12 col-md-6 col-lg-4 column-link">
<div class="article column-category">
<h4 class="title">
<loop column="title" />
</h4>
<div class="etiquettes">
<span class="cat">
<loop column="category" />
</span>
<span class="date">
<loop column="datetime" />
</span>
</div>
<div class="text">
<loop column="content" />
</p>
</div>
</div>
</a>
</tag>
</div>
</main>
</body>
<footer>
<tag type="includes" file="footer" />
</footer>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"></script>
</html>

43
assets/html/post_new.html Normal file
View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<header>
<tag type="includes" file="header" />
</header>
<main class="test container">
<div class="bloc-post">
<div class="container-post post column-cat">
<h2 class="title">
<tag type="editor" element="title"/>
</h2>
<div class="etiquettes">
<span class="cat"><select>
<tag type="editor" element="categories"/>
</select></span>
<span class="date">
<tag type="editor" element="datetime"/>
</span>
</div>
<p class="post text">
<tag type="editor" element="content"/>
</p>
</div>
</div>
<div class="bloc-filter">
<p class="title-small">Tags</p>
<tag type="editor" element="tags" />
</div>
</main>
</body>
<footer>
<tag type="includes" file="footer" />
</footer>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"></script>
</html>

View File

@ -8,4 +8,57 @@ var processForm = () => {
request.send(form);
}
document.querySelector("button").addEventListener("click", processForm);
// document.querySelector("button").addEventListener("click", processForm);
var addTag = (element) => {
console.log(this);
console.log(element.target);
/** @var HTMLButtonElement btn */
var btn = element.target;
var tag = document.createElement("input");
tag.classList.add("add-tag");
tag.style.width = "100%";
var cancelBtn = document.createElement("button");
cancelBtn.classList.add("cancelBtn");
cancelBtn.innerText = "Annuler";
cancelBtn.addEventListener("click", function(element) {
var input = element.target.parentElement.querySelector(".add-tag");
input.parentElement.querySelector(".addTag").innerText = "Add Tag";
input.parentElement.removeChild(input);
element.target.parentElement.removeChild(element.target);
});
btn.removeEventListener("click", addTag);
btn.addEventListener("click", addingTag);
btn.parentElement.insertBefore(tag, btn);
btn.parentElement.insertBefore(cancelBtn, btn);
btn.innerText = "Ajouter le tag";
}
var addingTag = (element) => {
var input = document.createElement("input");
var uuid = Math.floor(Math.random() * Math.floor(10000));
input.setAttribute("type", "checkbox");
input.setAttribute("id", uuid);
var label = document.createElement("label");
label.setAttribute("for", uuid);
var addtag = element.target.parentElement.querySelector(".add-tag");
label.innerText = addtag.value;
element.target.parentElement.insertBefore(input, element.target);
element.target.parentElement.insertBefore(label, element.target);
var cbtn = addtag.parentElement.querySelector(".cancelBtn");
cbtn.parentElement.removeChild(cbtn);
addtag.parentElement.removeChild(addtag);
element.target.removeEventListener("click", addingTag);
element.target.addEventListener("click", addTag);
}
document.querySelector(".addTag").addEventListener("click", addTag);

View File

@ -3,22 +3,34 @@
namespace App;
use ReflectionClass;
use Composer\Autoload\ClassLoader;
class Controller {
public function getContent(String $route, $loader) {
$map = array_filter(CLASSMAP, function($var) {
/**
* get content of controller
*
* @param String $route
* @param ClassLoader $loader
*
* @return String
*/
public function getContent(String $route, ClassLoader $loader) {
$map = array_filter($loader->getClassMap(), function($var) {
return strpos($var, "App\Controller\\") === 0;
}, ARRAY_FILTER_USE_KEY);
foreach ($map as $key => $t) {
$loader->loadClass($key);
}
/** @var String $class */
foreach (get_declared_classes() as $class) {
if(is_subclass_of( $class, 'App\Controller')) {
$r = new ReflectionClass($class);
foreach ($r->getMethods() as $method) {
preg_match_all('#@(.*?)\n#s', $method->getDocComment(), $annotations);
/** @var String $annot */
foreach ($annotations[1] as $annot) {
/** @var String[] $arr */
$arr = preg_split("/ /", $annot);
if($arr[0] === "route") {
if(preg_match($arr[1], $route)) {

View File

@ -2,7 +2,9 @@
namespace App\Controller;
class HomeController extends \App\Controller {
use App\Controller;
class HomeController extends Controller {
/**
@ -13,12 +15,30 @@ class HomeController extends \App\Controller {
}
/**
* @route /^\/post\/[a-z0-9]+\/*$/
* @route /^\/post\/new\/*$/
*/
public function postAdd() {
return file_get_contents(DIR."/html/post_new.html");
}
/**
* @route /^\/post\/[a-z0-9]+\/$/
*/
public function post() {
return file_get_contents(DIR."/html/post.html");
}
/**
* @route /^\/post\/[a-z0-9]+\/edit\/$/
*/
public function postEdit() {
return file_get_contents(DIR."/html/post_edit.html");
}
/**
* @route /^\/search\//
*/

View File

@ -5,14 +5,19 @@ namespace App;
use DOMDocument;
use DOMNode;
use PDO;
use App\Router;
use PDOException;
/**
* @author Avior <florian.bouillon@delta-wings.net>
* @author Clément Fourrier
*/
class Functions {
public static function endsWith($haystack, $needle) {
/**
* check the end of $needl
*
* @param String $haystack
* @param String $needle
*
* @return bool
*/
public static function endsWith(String $haystack, String $needle): bool {
$length = strlen($needle);
if ($length == 0) {
return true;
@ -21,7 +26,13 @@ class Functions {
return (substr($haystack, -$length) === $needle);
}
public static function connect() {
/**
* Connect to Database
*
* @return PDO
*/
public static function connect(): PDO {
$host = "127.0.0.1";
$db = "blog";
$user = "blog";
@ -31,23 +42,19 @@ class Functions {
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
try {
$pdo = new PDO($dsn, $user, $pass, null);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
} catch (PDOException $e) {
throw new PDOException($e->getMessage(), (int)$e->getCode());
}
return $pdo;
}
/**
* Undocumented function
* Append HTML to DOMDocument
*
* @param DOMNode $parent
* @param [type] $source
*
* @var DOMNode $node
*
* @return void
* @param String $source
*/
public static function appendHTML(DOMNode $parent, $source) {
public static function appendHTML(DOMNode $parent, String $source) {
$tmpDoc = new DOMDocument("1.0", "UTF-8");
$html = "<html><body>";
$html .= $source;
@ -66,84 +73,4 @@ class Functions {
$parent->appendChild($importedNode);
}
}
public static function loadRoutes() {
//recupération du router
$router = Router::getRouter();
$postCharacters = "[a-z0-9-]";
//page d'accueil
$home = function () {
return file_get_contents("../html/index.html");
};
$router->addRoute("/^\/$/", $home); // route : "/"
//page de post
$post = function () {
return file_get_contents("../html/post.html");
};
$router->addRoute("/^\/post\/" . $postCharacters . "+\/*$/", $post); // route "/post/*"
//page de recherche
$search = function () {
return file_get_contents("../html/search.html");
};
$router->addRoute("/^\/search\/$/", $search); // route "/search/*"
$edit = function() {
$_POST = array_merge($_POST, $_GET); //debug uniquement
var_dump($_POST);
/*
$_POST should contain
post :
id
title
content
category
author
UPDATE posts
SET
title = title,
url = strtolower(preg_replace(["/\ /", '/[\'\/~`\!@#\$%\^&\*\(\)\+=\{\}\[\]\|;:"\<\>,\.\?\\\]/'], ["_", ""], title));
content = content,
short = substr(content, 0, 253) . "...";
category = categoryId
author = authorId
WHERE id = id
*/
$request = "UPDATE posts SET `title`=:title, `url`=:url, `content`=:content, `short`=:short, `category`=:category, `author`=:author, WHERE `id`=:id";
$title = $_POST["title"];
$url = strtolower(preg_replace(["/\ /", '/[\'\/~`\!@#\$%\^&\*\(\)\+=\{\}\[\]\|;:"\<\>,\.\?\\\]/'], ["_", ""], $title));
$content = $_POST["content"];
$short = substr($content, 0, 253) . "...";
$category = intval($_POST["category"]);
$author = intval($_POST["author"]);
$id = intval($_POST["id"]);
$pdo = Functions::connect();
$prepared = $pdo->prepare($request);
$prepared->bindParam(":title", $title);
$prepared->bindParam(":url", $url);
$prepared->bindParam(":content", $content);
$prepared->bindParam(":short", $short);
$prepared->bindParam(":category", $category, PDO::PARAM_INT);
$prepared->bindParam(":author", $author, PDO::PARAM_INT);
$prepared->bindParam(":id", $id, PDO::PARAM_INT);
$prepared->execute();
};
$router->addRoute("/^\/post\/" . $postCharacters . "+\/edit\/*$/", $edit);
}
}

View File

@ -1,49 +0,0 @@
<?php
namespace App;
/**
* classe pour gerer le routage des pages
* la variable static $router sert a utiliser le router dans plusieurs fichier
* sans forcement avoir une obligation de nom de variable
* de plus ils sert a garder une route unique
*/
class Router {
//variable static pour stocker le router
private static $router = null;
//definit le router
public function __construct() {
//TODO faire que si un router existe déjà retourner le routeur existant
if(Router::$router != null) {
return Router::$router;
} else Router::$router = $this;
}
//fonction static pour recuperer un router déjà crée
public static function getRouter() {
return Router::$router;
}
//liste des routes
private $routeList = array();
//ajout d'une route
public function addRoute($route, $page) {
$this->routeList[$route] = $page;
}
//fonction de recherche d'une route par rapport a un texte
//return function
public function search($path) {
foreach ($this->routeList as $reg => $page) {
if(preg_match($reg, $path)) {
return $page;
}
}
return function () {
return file_get_contents("../html/404.html");
};
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace App\Tags;
use App\DB\Category;
use DateTime;
use App\DB\Tag;
class Editor extends \App\Tags\Tag {
public function render() {
//recuperation de la balise de base (<tag type="bold">pouet</tag>)
$pok = $this->getElement();
//recuperation du document (necessaire a la création de balises
$doc = $this->getDoc();
$type = $pok->getAttribute("element");
switch ($type) {
case 'categories':
$option = $doc->createElement("option");
$text = $doc->createTextNode("Categorie");
$option->setAttribute("value", "-1");
$option->setAttribute("disabled", "true");
$option->setAttribute("selected", "selected");
$option->appendChild($text);
$pok->parentNode->insertBefore($option, $pok);
foreach (Category::list() as $cat) {
$option = $doc->createElement("option");
$text = $doc->createTextNode($cat->getName());
$option->appendChild($text);
$option->setAttribute("value", $cat->getId());
$pok->parentNode->insertBefore($option, $pok);
}
break;
case 'datetime':
$dt = new DateTime();
$pok->parentNode->insertBefore($doc->createTextNode($dt->format('d/m/Y H:i:s')), $pok);
break;
case 'content':
$tarea = $doc->createElement("textarea");
$tarea->setAttribute("style", "width: 100%; min-height: 200px");
$pok->parentNode->insertBefore($tarea, $pok);
break;
case 'title':
$input = $doc->createElement("input");
$input->setAttribute("style", "width: 100%");
$input->setAttribute("placeholder", "titre");
$pok->parentNode->insertBefore($input, $pok);
break;
case 'tags':
foreach (Tag::list() as $el) {
$tg = $doc->createElement("input");
$tg->setAttribute("id", $el->getId());
$tg->setAttribute("type", "checkbox");
$txt = $doc->createElement("label");
$txt->appendChild($doc->createTextNode($el->getName()));
$txt->setAttribute("for", $el->getId());
$pok->parentNode->insertBefore($tg, $pok);
$pok->parentNode->insertBefore($txt, $pok);
}
$btn = $doc->createElement("button");
$btn->appendChild($doc->createTextNode("Add Tag"));
$btn->setAttribute("class", "addTag");
$pok->parentNode->insertBefore($btn, $pok);
default:
# code...
break;
}
}
}

View File

@ -1,122 +0,0 @@
<?php
namespace App\Tags;
use App\Tags\Tag;
use App\DB\Post;
class Search extends Tag {
public function render() {
$isRecent = isset($_GET["recent"]) && $_GET["recent"] == "false" ? false : true;
$category = isset($_GET["category"]) && intval($_GET["category"]) ? (int) $_GET["category"] : -1;
$tag = isset($_GET["tag"]) && intval($_GET["tag"]) ? (int) $_GET["tag"] : -1;
if($category != -1) {
$posts = Post::listByCategory($category, $isRecent, 20);
} else {
$posts = Post::list($isRecent, 10);
}
if($tag != -1) {
$tposts = array();
foreach ($posts as $post) {
foreach ($post->getTags() as $ptag) {
if($tag == $ptag->getId()) {
$tposts[] = $post;
}
}
}
$posts = $tposts;
}
var_dump($posts);
}
}
class Loop extends Tag {
public function render() {
$el = $this->getElement();
$doc = $this->getDoc();
$limit = (int) $el->getAttribute("limit");
$parent = $el->parentNode;
$isRecent = isset($_GET["recent"]) && $_GET["recent"] == "false" ? false : true;
$category = isset($_GET["category"]) && intval($_GET["category"]) ? (int) $_GET["category"] : -1;
$tag = isset($_GET["tag"]) && intval($_GET["tag"]) ? (int) $_GET["tag"] : -1;
if($el->getAttribute("category") != '') {
$posts = Post::listByCategory(Post::get($_GET["post"])->getCategory()->getId(), $isRecent, 6);
$postsList = array();
foreach ($posts as $post) {
if($post->getId() != $_GET["post"]) $postsList[] = $post;
}
$posts = $postsList;
} else {
$posts = Post::list(true, 6);
}
if($category != -1) {
$posts = Post::listByCategory($category, $isRecent, 20);
} else {
$posts = Post::list($isRecent, 10);
}
if($tag != -1) {
$tposts = array();
foreach ($posts as $post) {
foreach ($post->getTags() as $ptag) {
if($tag == $ptag->getId()) {
$tposts[] = $post;
}
}
}
$posts = $tposts;
}
$limit = $limit > count($posts) ? count($posts) : $limit;
for ($i=0; $i < $limit; $i++) {
$pok = $el->childNodes->item(0)->cloneNode(true);
$parent->insertBefore($pok, $el);
$elements = $pok->getElementsByTagName("loop");
foreach ($elements as $ele) {
if($ele->getAttribute("column") == "content") {
Functions::appendHTML($ele->parentNode, $posts[$i]->getShort());
} elseif($ele->getAttribute("column") == "category") {
$txt = $doc->createTextNode($posts[$i]->getCategory()->getName());
$ele->parentNode->insertBefore($txt, $ele);
} else {
$col = 'get' . ucfirst($ele->getAttribute("column"));
$txt = $doc->createTextNode($posts[$i]->$col());
$ele->parentNode->insertBefore($txt, $ele);
}
}
$finder = new DomXPath($doc);
$nodes = $finder->query("//*[contains(@class, 'column-cat')]");
if(count($nodes) >= 1) $nodes[0]->setAttribute("class", str_replace("column-category", $posts[$i]->getCategory()->getName() , $nodes[0]->getAttribute("class")));
$nodes = $finder->query("//*[contains(@class, 'column-link')]");
if(count($nodes) >= 1) $nodes[0]->setAttribute("href", "/post/".$posts[$i]->getId());
if(count($nodes) >= 1) $nodes[0]->setAttribute("class", str_replace("column-link", "", $nodes[0]->getAttribute("class")));
$loop = $pok->getElementsByTagName("loop");
while ($loop->count() >= 1) {
$loop->item(0)->parentNode->removeChild($loop->item(0));
}
}
}
}

View File

@ -6,11 +6,6 @@ use DOMDocument;
use DOMElement;
use DOMNode;
/**
* @author Avior <florian.bouillon@delta-wings.net>
*
* @version 1.0.0
*/
class Tag {
/** @var DOMDocument */

View File

@ -5,23 +5,18 @@ namespace App\Tags;
use App\Tags\Tag;
use App\DB\Post;
//ce tag est juste la pour donner les possibilité de mon composant
/**
* input <tag type="bold">test</tag>
* result <span style="font-weight: bold">test</span>
*/
class Tags extends Tag {
public function render() {
//recuperation de la balise de base (<tag type="bold">pouet</tag>)
$pok = $this->getElement();
//recuperation du document (necessaire a la création de balises
$doc = $this->getDoc();
//creation de la balise "span"
$post = Post::get($_GET["post"]);
/** @var \App\DB\Tag $tag */
foreach ($post->getTags() as $tag) {
$res = $doc->createElement("a");
$res->setAttribute("href", "/search?tag=" . $tag->getId());
$res->setAttribute("href", "/search/?tag=" . $tag->getId());
$res->setAttribute("class", "tag");
$text = $doc->createTextNode($tag->getName());
$res->appendChild($text);

View File

@ -65,7 +65,7 @@ class Category {
*/
public static function list($recent = true, $limit = 100) {
$sort = $recent ? "DESC" : "ASC";
$query = "SELECT * FROM categories ORDER BY " . $sort . " LIMIT " . $limit;
$query = "SELECT * FROM categories ORDER BY name " . $sort . " LIMIT " . $limit;
$pdo = Functions::connect();
$cats = $pdo->query($query)->fetchAll();

View File

@ -31,7 +31,7 @@ class Tag {
*/
public static function list($recent = true, $limit = 100) {
$sort = $recent ? "DESC" : "ASC";
$query = "SELECT * FROM tag ORDER BY " . $sort . " LIMIT " . $limit;
$query = "SELECT * FROM tag ORDER BY name " . $sort . " LIMIT " . $limit;
$pdo = Functions::connect();
$cats = $pdo->query($query)->fetchAll();

View File

@ -1,80 +1,72 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 'On');
$loader = require "../../vendor/autoload.php";
// var_dump($loader->getClassMap());
define("CLASSMAP", $loader->getClassMap());
define("DIR", str_replace("/php", "", __DIR__));
use App\Router;
use App\Functions;
use App\Tags\Tag;
use App\Controller;
error_reporting(E_ALL);
ini_set('display_errors', 'On');
/** @var Composer\Autoload\ClassLoader $loader */
$loader = require "../../vendor/autoload.php";
define("DIR", str_replace("/php", "", __DIR__));
//renvoie vers le fichier css si il est demandé
if(Functions::endsWith($_GET["page"], ".css")) {
echo file_get_contents("../css/style.css");
echo file_get_contents(DIR . "/css/style.css");
die;
}
//renvoie vers le fichier js si demand<6E>
//renvoie vers le fichier js si demandé
if(Functions::endsWith($_GET["page"], ".js")) {
echo file_get_contents("../js/script.js");
echo file_get_contents(DIR . "/js/script.js");
die;
}
// var_dump(sizeof($_GET));
// si page non / & finit pas par / at pas de ?
if($_GET["page"] != "" && !Functions::endsWith($_GET["page"], "/") && count($_GET) <= 1) {
if($_GET["page"] != "" && !Functions::endsWith($_GET["page"], "/") && count($_GET) <= 2) {
header("Location: /".$_GET["page"]."/");
die;
}
//enleve les / du début & fin
/**
* ex: /post/test/ => post/test
* utilité ? pouet simplefier la séparation pour les lignes d'après
*/
$_GET['page'] = trim($_GET['page'], '/');
// si taille supérieur à 1 $_getpost = element
/**
* ex: $_GET['page'] = post/test => $_GET['page'] = post/test & $_GET['post'] = test
*/
if(count(explode("/", $_GET["page"])) > 1) {
$_GET["post"] = explode("/", $_GET["page"])[1];
}
// $_get[page] = $_get[page][0]
/**
* changer le $_GET["page"] pour rajouter le slash avant
* ex : post/test => /post/test
*/
$_GET['page'] = "/" . $_GET['page'];
// si len $_get[page] > 1 (mot ou autre) on rajoute le slash de fin
/**
* si page ne finit pas par / rajouter un /
* ex : /post/test => /post/test/
* utilité ? afin de faire la recherche des controllers
*/
if(strlen($_GET['page']) > 1) {
$_GET['page'] = $_GET["page"] . "/";
}
// var_dump($_GET["page"]);
//page de test pour des functions
// A ENLEVER LORS DES COMMITS DE FIN
// var_dump($_GET);
//debug
if($_GET["page"] == "/test/") {
// $controller = new Controller();
// echo $controller->getContent("/search", $loader);
require "test.php";
die;
}
/**
* D<EFBFBD>marrage du routage du contenu
* Démarrage du routage du contenu
*/
$router = new Router();
Functions::loadRoutes();
$controller = new Controller();
echo Tag::loadTags($controller->getContent($_GET["page"], $loader));
// //chargement des tags contenu sur la page
// $pokemon = Tag::loadTags($router->search($_GET["page"])(), false);
// echo $pokemon;