aboutsummaryrefslogtreecommitdiffstats
path: root/core/namespace
diff options
context:
space:
mode:
Diffstat (limited to 'core/namespace')
-rw-r--r--core/namespace/Application.php24
-rw-r--r--core/namespace/Attribute.php84
-rw-r--r--core/namespace/Entity.php47
-rw-r--r--core/namespace/EntityInterface.php8
-rw-r--r--core/namespace/Item.php98
-rw-r--r--core/namespace/ItemFactory.php23
-rw-r--r--core/namespace/ItemInterface.php4
-rw-r--r--core/namespace/Page/Attribute.php22
-rw-r--r--core/namespace/Page/Entity.php13
-rw-r--r--core/namespace/Page/Exception.php4
-rw-r--r--core/namespace/Page/Factory.php4
-rw-r--r--core/namespace/Page/Item.php20
-rw-r--r--core/namespace/Page/Repository.php17
-rw-r--r--core/namespace/Post/Attribute.php22
-rw-r--r--core/namespace/Post/Entity.php13
-rw-r--r--core/namespace/Post/Exception.php4
-rw-r--r--core/namespace/Post/Factory.php4
-rw-r--r--core/namespace/Post/Item.php27
-rw-r--r--core/namespace/Post/Repository.php17
-rw-r--r--core/namespace/Repository.php323
-rw-r--r--core/namespace/User/Attribute.php24
-rw-r--r--core/namespace/User/Entity.php15
-rw-r--r--core/namespace/User/Exception.php4
-rw-r--r--core/namespace/User/Factory.php8
-rw-r--r--core/namespace/User/Item.php6
-rw-r--r--core/namespace/User/Repository.php7
26 files changed, 480 insertions, 362 deletions
diff --git a/core/namespace/Application.php b/core/namespace/Application.php
index f9a8196..7473e1f 100644
--- a/core/namespace/Application.php
+++ b/core/namespace/Application.php
@@ -6,6 +6,7 @@ class Application {
#===============================================================================
private static $Database;
private static $Language;
+ private static $repositories = [];
#===============================================================================
# Configuration array
@@ -68,6 +69,21 @@ class Application {
}
#===============================================================================
+ # Return singleton repository instance
+ #===============================================================================
+ public function getRepository(string $namespace): Repository {
+ $identifier = strtolower($namespace);
+ $repository = "$namespace\Repository";
+
+ if(!isset(self::$repositories[$identifier])) {
+ $Repository = new $repository(self::getDatabase());
+ self::$repositories[$identifier] = $Repository;
+ }
+
+ return self::$repositories[$identifier];
+ }
+
+ #===============================================================================
# Return unique CSRF token for the current session
#===============================================================================
public static function getSecurityToken(): string {
@@ -142,15 +158,15 @@ class Application {
#===============================================================================
# Return absolute URL of a specifc entity
#===============================================================================
- public function getEntityURL(Item $Entity) {
+ public function getEntityURL(EntityInterface $Entity) {
switch($class = get_class($Entity)) {
- case 'Page\Item':
+ case 'Page\Entity':
$attr = self::get('PAGE.SLUG_URLS') ? 'slug' : 'id';
return self::getPageURL($Entity->get($attr).'/');
- case 'Post\Item':
+ case 'Post\Entity':
$attr = self::get('POST.SLUG_URLS') ? 'slug' : 'id';
return self::getPostURL($Entity->get($attr).'/');
- case 'User\Item':
+ case 'User\Entity':
$attr = self::get('USER.SLUG_URLS') ? 'slug' : 'id';
return self::getUserURL($Entity->get($attr).'/');
default:
diff --git a/core/namespace/Attribute.php b/core/namespace/Attribute.php
deleted file mode 100644
index c874a57..0000000
--- a/core/namespace/Attribute.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-abstract class Attribute {
-
- #===============================================================================
- # Set attribute
- #===============================================================================
- public function set($attribute, $value) {
- return $this->{$attribute} = $value;
- }
-
- #===============================================================================
- # Get attribute
- #===============================================================================
- public function get($attribute) {
- return $this->{$attribute} ?? NULL;
- }
-
- #===============================================================================
- # Get all attributes
- #===============================================================================
- public function getAll($exclude = []): array {
- $attributes = get_object_vars($this);
-
- return array_filter($attributes, function($attribute) use($exclude) {
- return !in_array($attribute, $exclude);
- }, ARRAY_FILTER_USE_KEY);
- }
-
- #===============================================================================
- # Get array with not FALSE attributes
- #===============================================================================
- protected function getFilteredAttributes(): array {
- return array_filter(get_object_vars($this), function($value) {
- return $value !== FALSE;
- });
- }
-
- #===============================================================================
- # Insert database item
- #===============================================================================
- public function insert(\Database $Database): bool {
- $part[0] = '';
- $part[1] = '';
-
- $attributes = $this->getFilteredAttributes();
-
- foreach($attributes as $column => $value) {
- $part[0] .= "{$column},";
- $part[1] .= '?,';
- }
-
- $part[0] = rtrim($part[0], ',');
- $part[1] = rtrim($part[1], ',');
-
- $Statement = $Database->prepare('INSERT INTO '.static::TABLE." ({$part[0]}) VALUES ({$part[1]})");
- return $Statement->execute(array_values($attributes));
- }
-
- #===============================================================================
- # Update database item
- #===============================================================================
- public function update(\Database $Database): bool {
- $part = '';
-
- $attributes = $this->getFilteredAttributes();
-
- foreach($attributes as $column => $value) {
- $part .= "{$column} = ?,";
- }
-
- $part = rtrim($part, ',');
-
- $Statement = $Database->prepare('UPDATE '.static::TABLE.' SET '.$part.' WHERE id = '.(int) $this->get('id'));
- return $Statement->execute(array_values($attributes));
- }
-
- #===============================================================================
- # Delete database item
- #===============================================================================
- public function delete(\Database $Database): bool {
- $Statement = $Database->prepare('DELETE FROM '.static::TABLE.' WHERE id = ?');
- return $Statement->execute([$this->get('id')]);
- }
-}
diff --git a/core/namespace/Entity.php b/core/namespace/Entity.php
new file mode 100644
index 0000000..4bedd37
--- /dev/null
+++ b/core/namespace/Entity.php
@@ -0,0 +1,47 @@
+<?php
+abstract class Entity implements EntityInterface {
+ protected $id;
+ protected $time_insert;
+ protected $time_update;
+
+ #===============================================================================
+ # Get attribute
+ #===============================================================================
+ public function get(string $attribute) {
+ return $this->{$attribute} ?? NULL;
+ }
+
+ #===============================================================================
+ # Set attribute
+ #===============================================================================
+ public function set(string $attribute, $value) {
+ return $this->{$attribute} = $value;
+ }
+
+ #===============================================================================
+ # Return ID
+ #===============================================================================
+ final public function getID(): int {
+ return $this->id;
+ }
+
+ #===============================================================================
+ # Get all attributes
+ #===============================================================================
+ public function getAll(array $exclude = []): array {
+ $attributes = get_object_vars($this);
+
+ return array_filter($attributes, function($attribute) use($exclude) {
+ return !in_array($attribute, $exclude);
+ }, ARRAY_FILTER_USE_KEY);
+ }
+
+ #===============================================================================
+ # Get array with all non-false attributes
+ #===============================================================================
+ public function getFilteredAttributes(): array {
+ return array_filter(get_object_vars($this), function($value) {
+ return $value !== FALSE;
+ });
+ }
+}
diff --git a/core/namespace/EntityInterface.php b/core/namespace/EntityInterface.php
new file mode 100644
index 0000000..8eaa089
--- /dev/null
+++ b/core/namespace/EntityInterface.php
@@ -0,0 +1,8 @@
+<?php
+interface EntityInterface {
+ public function get(string $attribute);
+ public function set(string $attribute, $value);
+
+ public function getID(): int;
+ public function getAll(array $exclude = []): array;
+}
diff --git a/core/namespace/Item.php b/core/namespace/Item.php
deleted file mode 100644
index 453a3e6..0000000
--- a/core/namespace/Item.php
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-abstract class Item implements ItemInterface {
- protected $Database = NULL;
- protected $Attribute = NULL;
- protected $Reflection = NULL;
-
- #===============================================================================
- # Abstract item constructor
- #===============================================================================
- public final function __construct($itemID, \Database $Database) {
- $this->Database = $Database;
-
- $this->Reflection = new ReflectionObject($this);
-
- $attribute = "{$this->Reflection->getNamespaceName()}\\Attribute";
- $exception = "{$this->Reflection->getNamespaceName()}\\Exception";
-
- #===============================================================================
- # Checking if item in database exists
- #===============================================================================
- $Statement = $Database->prepare(sprintf('SELECT * FROM %s WHERE id = ?', $attribute::TABLE));
- $Statement->execute([$itemID]);
-
- #===============================================================================
- # Checking if retrieving data failed
- #===============================================================================
- if(!$this->Attribute = $Statement->fetchObject($attribute)) {
- throw new $exception(sprintf('%s\\Item with ID %s does not exist', $this->Reflection->getNamespaceName(), (int) $itemID));
- }
- }
-
- #===============================================================================
- # Return attribute by name (short hand wrapper)
- #===============================================================================
- public function get($attribute) {
- return $this->Attribute->get($attribute);
- }
-
- #===============================================================================
- # Return Attribute object
- #===============================================================================
- public final function getAttribute(): Attribute {
- return $this->Attribute;
- }
-
- #===============================================================================
- # Return unique ID
- #===============================================================================
- public final function getID(): int {
- return $this->Attribute->get('id');
- }
-
- #===============================================================================
- # Return previous item ID
- #===============================================================================
- public function getPrevID(): int {
- $execute = 'SELECT id FROM %s WHERE time_insert < ? ORDER BY time_insert DESC LIMIT 1';
-
- $attribute = "{$this->Reflection->getNamespaceName()}\\Attribute";
- $Statement = $this->Database->prepare(sprintf($execute, $attribute::TABLE));
-
- if($Statement->execute([$this->Attribute->get('time_insert')])) {
- return $Statement->fetchColumn();
- }
-
- return 0;
- }
-
- #===============================================================================
- # Return next item ID
- #===============================================================================
- public function getNextID(): int {
- $execute = 'SELECT id FROM %s WHERE time_insert > ? ORDER BY time_insert ASC LIMIT 1';
-
- $attribute = "{$this->Reflection->getNamespaceName()}\\Attribute";
- $Statement = $this->Database->prepare(sprintf($execute, $attribute::TABLE));
-
- if($Statement->execute([$this->Attribute->get('time_insert')])) {
- return $Statement->fetchColumn();
- }
-
- return 0;
- }
-
- #===============================================================================
- # Return unique ID based on specific field comparison with value
- #===============================================================================
- public static function getIDByField($field, $value, \Database $Database): int {
- $attribute = (new ReflectionClass(get_called_class()))->getNamespaceName().'\\Attribute';
- $Statement = $Database->prepare('SELECT id FROM '.$attribute::TABLE." WHERE {$field} = ?");
-
- if($Statement->execute([$value])) {
- return $Statement->fetchColumn();
- }
-
- return 0;
- }
-}
diff --git a/core/namespace/ItemFactory.php b/core/namespace/ItemFactory.php
deleted file mode 100644
index d81ff9f..0000000
--- a/core/namespace/ItemFactory.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-abstract class ItemFactory extends Factory {
-
- #===========================================================================
- # Build instance by ID
- #===========================================================================
- public static function build($itemID): Item {
- if(!$Instance = parent::fetchInstance($itemID)) {
- $Item = (new ReflectionClass(get_called_class()))->getNamespaceName().'\\Item';
- $Instance = parent::storeInstance($itemID, new $Item($itemID, \Application::getDatabase()));
- }
-
- return $Instance;
- }
-
- #===========================================================================
- # Build instance by slug
- #===========================================================================
- public static function buildBySlug($slug): Item {
- $Item = (new ReflectionClass(get_called_class()))->getNamespaceName().'\\Item';
- return self::build($Item::getIDByField('slug', $slug, \Application::getDatabase()));
- }
-}
diff --git a/core/namespace/ItemInterface.php b/core/namespace/ItemInterface.php
deleted file mode 100644
index efee734..0000000
--- a/core/namespace/ItemInterface.php
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-interface ItemInterface {
- public function __construct($itemID, \Database $Database);
-}
diff --git a/core/namespace/Page/Attribute.php b/core/namespace/Page/Attribute.php
deleted file mode 100644
index 05eaa33..0000000
--- a/core/namespace/Page/Attribute.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-namespace Page;
-
-class Attribute extends \Attribute {
-
- #===============================================================================
- # Pre-Define database table columns
- #===============================================================================
- protected $id = FALSE;
- protected $user = FALSE;
- protected $slug = FALSE;
- protected $name = FALSE;
- protected $body = FALSE;
- protected $argv = FALSE;
- protected $time_insert = FALSE;
- protected $time_update = FALSE;
-
- #===============================================================================
- # Define database table name
- #===============================================================================
- const TABLE = 'page';
-}
diff --git a/core/namespace/Page/Entity.php b/core/namespace/Page/Entity.php
new file mode 100644
index 0000000..6ca5979
--- /dev/null
+++ b/core/namespace/Page/Entity.php
@@ -0,0 +1,13 @@
+<?php
+namespace Page;
+
+class Entity extends \Entity {
+ protected $id = FALSE;
+ protected $user = FALSE;
+ protected $slug = FALSE;
+ protected $name = FALSE;
+ protected $body = FALSE;
+ protected $argv = FALSE;
+ protected $time_insert = FALSE;
+ protected $time_update = FALSE;
+}
diff --git a/core/namespace/Page/Exception.php b/core/namespace/Page/Exception.php
deleted file mode 100644
index c41bddc..0000000
--- a/core/namespace/Page/Exception.php
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-namespace Page;
-
-class Exception extends \Exception {}
diff --git a/core/namespace/Page/Factory.php b/core/namespace/Page/Factory.php
deleted file mode 100644
index 2fcc361..0000000
--- a/core/namespace/Page/Factory.php
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-namespace Page;
-
-class Factory extends \ItemFactory {}
diff --git a/core/namespace/Page/Item.php b/core/namespace/Page/Item.php
deleted file mode 100644
index cbc99e6..0000000
--- a/core/namespace/Page/Item.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-namespace Page;
-
-class Item extends \Item {
- const CONFIGURATION = 'PAGE';
-
- #===============================================================================
- # Return unique page IDs for search results
- #===============================================================================
- public static function getSearchResultIDs($search, \Database $Database): array {
- $Statement = $Database->prepare(sprintf("SELECT id FROM %s WHERE
- MATCH(name, body) AGAINST(? IN BOOLEAN MODE) LIMIT 20", Attribute::TABLE));
-
- if($Statement->execute([$search])) {
- return $Statement->fetchAll($Database::FETCH_COLUMN);
- }
-
- return [];
- }
-}
diff --git a/core/namespace/Page/Repository.php b/core/namespace/Page/Repository.php
new file mode 100644
index 0000000..b76ef85
--- /dev/null
+++ b/core/namespace/Page/Repository.php
@@ -0,0 +1,17 @@
+<?php
+namespace Page;
+
+class Repository extends \Repository {
+ public static function getTableName(): string { return 'page'; }
+ public static function getClassName(): string { return 'Page\Entity'; }
+
+ public function getCountByUser(\User\Entity $User): int {
+ $query = 'SELECT COUNT(id) FROM %s WHERE user = ?';
+ $query = sprintf($query, static::getTableName());
+
+ $Statement = $this->Database->prepare($query);
+ $Statement->execute([$User->getID()]);
+
+ return $Statement->fetchColumn();
+ }
+}
diff --git a/core/namespace/Post/Attribute.php b/core/namespace/Post/Attribute.php
deleted file mode 100644
index 20aafae..0000000
--- a/core/namespace/Post/Attribute.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-namespace Post;
-
-class Attribute extends \Attribute {
-
- #===============================================================================
- # Pre-Define database table columns
- #===============================================================================
- protected $id = FALSE;
- protected $user = FALSE;
- protected $slug = FALSE;
- protected $name = FALSE;
- protected $body = FALSE;
- protected $argv = FALSE;
- protected $time_insert = FALSE;
- protected $time_update = FALSE;
-
- #===============================================================================
- # Define database table name
- #===============================================================================
- const TABLE = 'post';
-}
diff --git a/core/namespace/Post/Entity.php b/core/namespace/Post/Entity.php
new file mode 100644
index 0000000..399f5bb
--- /dev/null
+++ b/core/namespace/Post/Entity.php
@@ -0,0 +1,13 @@
+<?php
+namespace Post;
+
+class Entity extends \Entity {
+ protected $id = FALSE;
+ protected $user = FALSE;
+ protected $slug = FALSE;
+ protected $name = FALSE;
+ protected $body = FALSE;
+ protected $argv = FALSE;
+ protected $time_insert = FALSE;
+ protected $time_update = FALSE;
+}
diff --git a/core/namespace/Post/Exception.php b/core/namespace/Post/Exception.php
deleted file mode 100644
index 29b9345..0000000
--- a/core/namespace/Post/Exception.php
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-namespace Post;
-
-class Exception extends \Exception {}
diff --git a/core/namespace/Post/Factory.php b/core/namespace/Post/Factory.php
deleted file mode 100644
index 20b29cc..0000000
--- a/core/namespace/Post/Factory.php
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-namespace Post;
-
-class Factory extends \ItemFactory {}
diff --git a/core/namespace/Post/Item.php b/core/namespace/Post/Item.php
deleted file mode 100644
index e8b4615..0000000
--- a/core/namespace/Post/Item.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-namespace Post;
-
-class Item extends \Item {
- const CONFIGURATION = 'POST';
-
- #===============================================================================
- # Return unique post IDs for search results
- #===============================================================================
- public static function getSearchResultIDs($search, array $date, \Database $Database): array {
- $D = ($D = intval($date[0])) !== 0 ? $D : 'NULL';
- $M = ($M = intval($date[1])) !== 0 ? $M : 'NULL';
- $Y = ($Y = intval($date[2])) !== 0 ? $Y : 'NULL';
-
- $Statement = $Database->prepare(sprintf("SELECT id FROM %s WHERE
- ({$Y} IS NULL OR YEAR(time_insert) = {$Y}) AND
- ({$M} IS NULL OR MONTH(time_insert) = {$M}) AND
- ({$D} IS NULL OR DAY(time_insert) = {$D}) AND
- MATCH(name, body) AGAINST(? IN BOOLEAN MODE) LIMIT 20", Attribute::TABLE));
-
- if($Statement->execute([$search])) {
- return $Statement->fetchAll($Database::FETCH_COLUMN);
- }
-
- return [];
- }
-}
diff --git a/core/namespace/Post/Repository.php b/core/namespace/Post/Repository.php
new file mode 100644
index 0000000..5a3d834
--- /dev/null
+++ b/core/namespace/Post/Repository.php
@@ -0,0 +1,17 @@
+<?php
+namespace Post;
+
+class Repository extends \Repository {
+ public static function getTableName(): string { return 'post'; }
+ public static function getClassName(): string { return 'Post\Entity'; }
+
+ public function getCountByUser(\User\Entity $User): int {
+ $query = 'SELECT COUNT(id) FROM %s WHERE user = ?';
+ $query = sprintf($query, static::getTableName());
+
+ $Statement = $this->Database->prepare($query);
+ $Statement->execute([$User->getID()]);
+
+ return $Statement->fetchColumn();
+ }
+}
diff --git a/core/namespace/Repository.php b/core/namespace/Repository.php
new file mode 100644
index 0000000..2c238b8
--- /dev/null
+++ b/core/namespace/Repository.php
@@ -0,0 +1,323 @@
+<?php
+abstract class Repository {
+ protected $Database;
+ protected $entities = [];
+
+ abstract public static function getTableName(): string;
+ abstract public static function getClassName(): string;
+
+ public function __construct(Database $Database) {
+ $this->Database = $Database;
+ }
+
+ #===============================================================================
+ # Adds an entity to the runtime cache
+ #===============================================================================
+ protected function storeInstance(int $identifier, EntityInterface $Entity) {
+ return $this->entities[$identifier] = $Entity;
+ }
+
+ #===============================================================================
+ # Adds an array of entities to the runtime cache
+ #===============================================================================
+ protected function storeMultipleInstances(array $entities) {
+ foreach($entities as $Entity) {
+ $this->storeInstance($Entity->getID(), $Entity);
+ }
+
+ return $entities;
+ }
+
+ #===============================================================================
+ # Gets an entity from the runtime cache
+ #===============================================================================
+ protected function fetchInstance(int $identifier) {
+ return $this->entities[$identifier] ?? FALSE;
+ }
+
+ #===============================================================================
+ # Removes an entity from the runtime cache
+ #===============================================================================
+ protected function removeInstance(int $identifier) {
+ if(isset($this->cache[$identifier])) {
+ unset($this->cache[$identifier]);
+ }
+ }
+
+ #===========================================================================
+ # Insert entity
+ #===========================================================================
+ public function insert(EntityInterface $Entity): bool {
+ $attributes = $Entity->getFilteredAttributes();
+
+ foreach($attributes as $field => $value) {
+ $fields[] = $field;
+ $values[] = '?';
+ }
+
+ $fields = implode(', ', $fields ?? []);
+ $values = implode(', ', $values ?? []);
+
+ $query = 'INSERT INTO %s (%s) VALUES(%s)';
+ $query = sprintf($query, static::getTableName(), $fields, $values);
+
+ $Statement = $this->Database->prepare($query);
+ return $Statement->execute(array_values($attributes));
+ }
+
+ #===========================================================================
+ # Update entity
+ #===========================================================================
+ public function update(EntityInterface $Entity): bool {
+ $attributes = $Entity->getFilteredAttributes();
+
+ foreach($attributes as $field => $value) {
+ $params[] = "$field = ?";
+ }
+
+ $params = implode(', ', $params ?? []);
+
+ $query = 'UPDATE %s SET %s WHERE id = '.intval($Entity->getID());
+ $query = sprintf($query, static::getTableName(), $params);
+
+ $Statement = $this->Database->prepare($query);
+ return $Statement->execute(array_values($attributes));
+ }
+
+ #===========================================================================
+ # Delete entity
+ #===========================================================================
+ public function delete(EntityInterface $Entity): bool {
+ $query = 'DELETE FROM %s WHERE id = ?';
+ $query = sprintf($query, static::getTableName());
+
+ $Statement = $this->Database->prepare($query);
+ return $Statement->execute([$Entity->getID()]);
+ }
+
+ #===========================================================================
+ # Find entity based on primary key
+ #===========================================================================
+ public function find(int $id): ?EntityInterface {
+ if($Entity = $this->fetchInstance($id)) {
+ return $Entity;
+ }
+
+ return $this->findBy('id', $id);
+ }
+
+ #===============================================================================
+ # Find entity based on specific field comparison
+ #===============================================================================
+ public function findBy(string $field, $value): ?EntityInterface {
+ $query = 'SELECT * FROM %s WHERE %s = ?';
+ $query = sprintf($query, static::getTableName(), $field);
+
+ $Statement = $this->Database->prepare($query);
+ $Statement->execute([$value]);
+
+ if($Entity = $Statement->fetchObject(static::getClassName())) {
+ $this->storeInstance($Entity->getID(), $Entity);
+ return $Entity;
+ }
+
+ return NULL;
+ }
+
+ #===============================================================================
+ # Find previous entitiy
+ #===============================================================================
+ public function findPrev(EntityInterface $Entity): ?EntityInterface {
+ $query = 'SELECT * FROM %s WHERE time_insert < ? ORDER BY time_insert DESC LIMIT 1';
+ $query = sprintf($query, static::getTableName());
+
+ $Statement = $this->Database->prepare($query);
+ $Statement->execute([$Entity->get('time_insert')]);
+
+ if($Entity = $Statement->fetchObject(static::getClassName())) {
+ $this->storeInstance($Entity->getID(), $Entity);
+ return $Entity;
+ }
+
+ return NULL;
+ }
+
+ #===============================================================================
+ # Find next entity
+ #===============================================================================
+ public function findNext(EntityInterface $Entity): ?EntityInterface {
+ $query = 'SELECT * FROM %s WHERE time_insert > ? ORDER BY time_insert ASC LIMIT 1';
+ $query = sprintf($query, static::getTableName());
+
+ $Statement = $this->Database->prepare($query);
+ $Statement->execute([$Entity->get('time_insert')]);
+
+ if($Entity = $Statement->fetchObject(static::getClassName())) {
+ $this->storeInstance($Entity->getID(), $Entity);
+ return $Entity;
+ }
+
+ return NULL;
+ }
+
+ #===========================================================================
+ # Find last (which means the newest) entity
+ #===========================================================================
+ public function getLast(): ?EntityInterface {
+ $query = 'SELECT * FROM %s ORDER BY time_insert DESC LIMIT 1';
+ $query = sprintf($query, static::getTableName());
+
+ $Statement = $this->Database->query($query);
+
+ if($Entity = $Statement->fetchObject(static::getClassName())) {
+ $this->storeInstance($Entity->getID(), $Entity);
+ return $Entity;
+ }
+
+ return NULL;
+ }
+
+ #===========================================================================
+ # Get entity count
+ #===========================================================================
+ public function getCount(): int {
+ $query = 'SELECT COUNT(id) FROM %s';
+ $query = sprintf($query, static::getTableName());
+
+ return $this->Database->query($query)->fetchColumn();
+ }
+
+ #===========================================================================
+ # Get paginated entity list
+ #===========================================================================
+ public function getPaginated(string $order, int $limit, int $offset = 0): array {
+ return $this->getAll([], $order, "$offset,$limit");
+ }
+
+ #===========================================================================
+ # Get all entities
+ #===========================================================================
+ public function getAll(array $filter = [], string $order = null, string $limit = null): array {
+ $select = 'SELECT * FROM '.static::getTableName();
+ $wheres = [];
+ $params = [];
+
+ if(!empty($filter)) {
+ foreach($filter as $column => $value) {
+ $wheres[] = "$column = ?";
+ $params[] = $value;
+ }
+
+ $where = 'WHERE '.implode(' AND ', $wheres);
+ }
+
+ if($order) {
+ $order = "ORDER BY $order";
+ }
+
+ if($limit) {
+ $limit = "LIMIT $limit";
+ }
+
+ $query = "$select %s %s %s";
+ $query = sprintf($query, $where ?? '', $order ?? '', $limit ?? '');
+
+ $Statement = $this->Database->prepare($query);
+ $Statement->execute($params);
+
+ if($entities = $Statement->fetchAll($this->Database::FETCH_CLASS, static::getClassName())) {
+ $this->storeMultipleInstances($entities);
+ return $entities;
+ }
+
+ return [];
+ }
+
+ #===============================================================================
+ # Get entities based on search query
+ #===============================================================================
+ public function search(string $search, array $filter = []): array {
+ if($search === '*') {
+ return $this->getAll([], NULL, 20);
+ }
+
+ if(strlen($filter['year'] ?? '') !== 0) {
+ $extend[] = 'YEAR(time_insert) = ? AND';
+ $params[] = $filter['year'];
+ }
+
+ if(strlen($filter['month'] ?? '') !== 0) {
+ $extend[] = 'MONTH(time_insert) = ? AND';
+ $params[] = $filter['month'];
+ }
+
+ if(strlen($filter['day'] ?? '') !== 0) {
+ $extend[] = 'DAY(time_insert) = ? AND';
+ $params[] = $filter['day'];
+ }
+
+ $dateparts = implode(' ', $extend ?? []);
+
+ $query = 'SELECT * FROM %s WHERE %s MATCH(name, body)
+ AGAINST(? IN BOOLEAN MODE) LIMIT 20';
+ $query = sprintf($query, static::getTableName(), $dateparts);
+
+ $Statement = $this->Database->prepare($query);
+ $Statement->execute(array_merge($params ?? [], [$search]));
+
+ if($entities = $Statement->fetchAll($this->Database::FETCH_CLASS, static::getClassName())) {
+ $this->storeMultipleInstances($entities);
+ return $entities;
+ }
+
+ return [];
+ }
+
+ #===============================================================================
+ # Get a list of distinct days
+ #===============================================================================
+ public function getDistinctDays(): array {
+ $query = 'SELECT DISTINCT DAY(time_insert) AS d FROM %s ORDER BY d';
+ $query = sprintf($query, static::getTableName());
+
+ $Statement = $this->Database->query($query);
+
+ if($result = $Statement->fetchAll($this->Database::FETCH_COLUMN)) {
+ return $result;
+ }
+
+ return [];
+ }
+
+ #===============================================================================
+ # Get a list of distinct months
+ #===============================================================================
+ public function getDistinctMonths(): array {
+ $query = 'SELECT DISTINCT MONTH(time_insert) AS m FROM %s ORDER BY m';
+ $query = sprintf($query, static::getTableName());
+
+ $Statement = $this->Database->query($query);
+
+ if($result = $Statement->fetchAll($this->Database::FETCH_COLUMN)) {
+ return $result;
+ }
+
+ return [];
+ }
+
+ #===============================================================================
+ # Get a list of distinct years
+ #===============================================================================
+ public function getDistinctYears(): array {
+ $query = 'SELECT DISTINCT YEAR(time_insert) AS y FROM %s ORDER BY y';
+ $query = sprintf($query, static::getTableName());
+
+ $Statement = $this->Database->query($query);
+
+ if($result = $Statement->fetchAll($this->Database::FETCH_COLUMN)) {
+ return $result;
+ }
+
+ return [];
+ }
+}
diff --git a/core/namespace/User/Attribute.php b/core/namespace/User/Attribute.php
deleted file mode 100644
index ccd31b5..0000000
--- a/core/namespace/User/Attribute.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-namespace User;
-
-class Attribute extends \Attribute {
-
- #===============================================================================
- # Pre-Define database table columns
- #===============================================================================
- protected $id = FALSE;
- protected $slug = FALSE;
- protected $username = FALSE;
- protected $password = FALSE;
- protected $fullname = FALSE;
- protected $mailaddr = FALSE;
- protected $body = FALSE;
- protected $argv = FALSE;
- protected $time_insert = FALSE;
- protected $time_update = FALSE;
-
- #===============================================================================
- # Define database table name
- #===============================================================================
- const TABLE = 'user';
-}
diff --git a/core/namespace/User/Entity.php b/core/namespace/User/Entity.php
new file mode 100644
index 0000000..fdfaf9e
--- /dev/null
+++ b/core/namespace/User/Entity.php
@@ -0,0 +1,15 @@
+<?php
+namespace User;
+
+class Entity extends \Entity {
+ protected $id = FALSE;
+ protected $slug = FALSE;
+ protected $username = FALSE;
+ protected $password = FALSE;
+ protected $fullname = FALSE;
+ protected $mailaddr = FALSE;
+ protected $body = FALSE;
+ protected $argv = FALSE;
+ protected $time_insert = FALSE;
+ protected $time_update = FALSE;
+}
diff --git a/core/namespace/User/Exception.php b/core/namespace/User/Exception.php
deleted file mode 100644
index fdbe733..0000000
--- a/core/namespace/User/Exception.php
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-namespace User;
-
-class Exception extends \Exception {}
diff --git a/core/namespace/User/Factory.php b/core/namespace/User/Factory.php
deleted file mode 100644
index 81930e6..0000000
--- a/core/namespace/User/Factory.php
+++ /dev/null
@@ -1,8 +0,0 @@
-<?php
-namespace User;
-
-class Factory extends \ItemFactory {
- public static function buildByUsername($username): \Item {
- return self::build(Item::getIDByField('username', $username, \Application::getDatabase()));
- }
-}
diff --git a/core/namespace/User/Item.php b/core/namespace/User/Item.php
deleted file mode 100644
index 5039287..0000000
--- a/core/namespace/User/Item.php
+++ /dev/null
@@ -1,6 +0,0 @@
-<?php
-namespace User;
-
-class Item extends \Item {
- const CONFIGURATION = 'USER';
-}
diff --git a/core/namespace/User/Repository.php b/core/namespace/User/Repository.php
new file mode 100644
index 0000000..59205b3
--- /dev/null
+++ b/core/namespace/User/Repository.php
@@ -0,0 +1,7 @@
+<?php
+namespace User;
+
+class Repository extends \Repository {
+ public static function getTableName(): string { return 'user'; }
+ public static function getClassName(): string { return 'User\Entity'; }
+}