diff --git a/Admin/Install/Navigation.install.json b/Admin/Install/Navigation.install.json
new file mode 100644
index 0000000..8456344
--- /dev/null
+++ b/Admin/Install/Navigation.install.json
@@ -0,0 +1,48 @@
+[
+ {
+ "id": 1007501001,
+ "pid": "/",
+ "type": 2,
+ "subtype": 1,
+ "name": "Tag",
+ "uri": "{/prefix}tag/list?{?}",
+ "target": "self",
+ "icon": null,
+ "order": 75,
+ "from": "Tag",
+ "permission": { "permission": 2, "type": null, "element": null },
+ "parent": 1003301001,
+ "children": [
+ {
+ "id": 1007502001,
+ "pid": "/tag",
+ "type": 3,
+ "subtype": 1,
+ "name": "List",
+ "uri": "{/prefix}tag/list?{?}",
+ "target": "self",
+ "icon": null,
+ "order": 1,
+ "from": "Tag",
+ "permission": { "permission": 2, "type": null, "element": null },
+ "parent": 1007501001,
+ "children": []
+ },
+ {
+ "id": 1007502101,
+ "pid": "/tag",
+ "type": 3,
+ "subtype": 5,
+ "name": "Create",
+ "uri": "{/prefix}tag/create?{?}",
+ "target": "self",
+ "icon": null,
+ "order": 15,
+ "from": "Tag",
+ "permission": { "permission": 4, "type": null, "element": null },
+ "parent": 1007501001,
+ "children": []
+ }
+ ]
+ }
+]
diff --git a/Admin/Install/Navigation.php b/Admin/Install/Navigation.php
new file mode 100644
index 0000000..a357c62
--- /dev/null
+++ b/Admin/Install/Navigation.php
@@ -0,0 +1,43 @@
+ __DIR__ . '/Navigation.install.json']);
+ }
+}
diff --git a/Admin/Install/db.json b/Admin/Install/db.json
index 09c918c..27587c5 100644
--- a/Admin/Install/db.json
+++ b/Admin/Install/db.json
@@ -16,7 +16,7 @@
},
"tag_color": {
"name": "tag_color",
- "type": "VARCHAR(8)",
+ "type": "VARCHAR(9)",
"null": false
},
"tag_type": {
diff --git a/Admin/Routes/Web/Api.php b/Admin/Routes/Web/Api.php
index 18f1e74..11b2975 100644
--- a/Admin/Routes/Web/Api.php
+++ b/Admin/Routes/Web/Api.php
@@ -6,7 +6,7 @@ use phpOMS\Account\PermissionType;
use phpOMS\Router\RouteVerb;
return [
- '^.*/tag.*$' => [
+ '^.*/tag$' => [
[
'dest' => '\Modules\Tag\Controller\ApiController:apiTagCreate',
'verb' => RouteVerb::PUT,
@@ -35,4 +35,15 @@ return [
],
],
],
+ '^.*/tag/find.*$' => [
+ [
+ 'dest' => '\Modules\Tag\Controller\ApiController:apiTagFind',
+ 'verb' => RouteVerb::GET,
+ 'permission' => [
+ 'module' => ApiController::MODULE_NAME,
+ 'type' => PermissionType::READ,
+ 'state' => PermissionState::TAG,
+ ],
+ ],
+ ],
];
diff --git a/Admin/Routes/Web/Backend.php b/Admin/Routes/Web/Backend.php
new file mode 100644
index 0000000..4f32bed
--- /dev/null
+++ b/Admin/Routes/Web/Backend.php
@@ -0,0 +1,42 @@
+ [
+ [
+ 'dest' => '\Modules\Tag\Controller\BackendController:viewTagCreate',
+ 'verb' => RouteVerb::GET,
+ 'permission' => [
+ 'module' => BackendController::MODULE_NAME,
+ 'type' => PermissionType::CREATE,
+ 'state' => PermissionState::TAG,
+ ],
+ ],
+ ],
+ '^.*/tag/list.*$' => [
+ [
+ 'dest' => '\Modules\Tag\Controller\BackendController:viewTagList',
+ 'verb' => RouteVerb::GET,
+ 'permission' => [
+ 'module' => BackendController::MODULE_NAME,
+ 'type' => PermissionType::READ,
+ 'state' => PermissionState::TAG,
+ ],
+ ],
+ ],
+ '^.*/tag/single.*$' => [
+ [
+ 'dest' => '\Modules\Tag\Controller\BackendController:viewTagSingle',
+ 'verb' => RouteVerb::GET,
+ 'permission' => [
+ 'module' => BackendController::MODULE_NAME,
+ 'type' => PermissionType::READ,
+ 'state' => PermissionState::TAG,
+ ],
+ ],
+ ],
+];
diff --git a/Controller/ApiController.php b/Controller/ApiController.php
index 80cac03..95cb4aa 100644
--- a/Controller/ApiController.php
+++ b/Controller/ApiController.php
@@ -21,6 +21,7 @@ use phpOMS\Message\NotificationLevel;
use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract;
use phpOMS\Model\Message\FormValidation;
+use phpOMS\System\MimeType;
/**
* Tag controller class.
@@ -49,7 +50,7 @@ final class ApiController extends Controller
{
$val = [];
if (($val['title'] = empty($request->getData('title')))
- || ($val['color'] = (!empty($request->getData('color')) && !\ctype_xdigit($request->getData('color'))))
+ || ($val['color'] = (!empty($request->getData('color')) && !\ctype_xdigit(\ltrim($request->getData('color'), '#'))))
) {
return $val;
}
@@ -135,7 +136,7 @@ final class ApiController extends Controller
{
$tag = new Tag();
$tag->setTitle((string) ($request->getData('title') ?? ''));
- $tag->setColor($request->getData('color') ?? '00000000');
+ $tag->setColor($request->getData('color') ?? '#00000000');
return $tag;
}
@@ -178,4 +179,29 @@ final class ApiController extends Controller
$this->deleteModel($request->getHeader()->getAccount(), $tag, TagMapper::class, 'tag');
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Tag', 'Tag successfully deleted', $tag);
}
+
+ /**
+ * Api method to find tags
+ *
+ * @param RequestAbstract $request Request
+ * @param ResponseAbstract $response Response
+ * @param mixed $data Generic data
+ *
+ * @return void
+ *
+ * @api
+ *
+ * @since 1.0.0
+ */
+ public function apiTagFind(RequestAbstract $request, ResponseAbstract $response, $data = null) : void
+ {
+ $response->getHeader()->set('Content-Type', MimeType::M_JSON, true);
+ $response->set(
+ $request->getUri()->__toString(),
+ \array_values(
+ TagMapper::find((string) ($request->getData('search') ?? ''))
+ )
+ );
+ }
+
}
diff --git a/Controller/BackendController.php b/Controller/BackendController.php
new file mode 100644
index 0000000..81c666c
--- /dev/null
+++ b/Controller/BackendController.php
@@ -0,0 +1,107 @@
+app->l11nManager, $request, $response);
+
+ $view->setTemplate('/Modules/Tag/Theme/Backend/tag-create');
+ $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1007501001, $request, $response));
+
+ return $view;
+ }
+
+ /**
+ * Routing end-point for application behaviour.
+ *
+ * @param RequestAbstract $request Request
+ * @param ResponseAbstract $response Response
+ * @param mixed $data Generic data
+ *
+ * @return RenderableInterface
+ *
+ * @since 1.0.0
+ * @codeCoverageIgnore
+ */
+ public function viewTagList(RequestAbstract $request, ResponseAbstract $response, $data = null) : RenderableInterface
+ {
+ $view = new View($this->app->l11nManager, $request, $response);
+
+ $view->setTemplate('/Modules/Tag/Theme/Backend/tag-list');
+ $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1007501001, $request, $response));
+
+ $tags = TagMapper::getNewest(50);
+ $view->addData('tags', $tags);
+
+ return $view;
+ }
+
+ /**
+ * Routing end-point for application behaviour.
+ *
+ * @param RequestAbstract $request Request
+ * @param ResponseAbstract $response Response
+ * @param mixed $data Generic data
+ *
+ * @return RenderableInterface
+ *
+ * @since 1.0.0
+ * @codeCoverageIgnore
+ */
+ public function viewTagSingle(RequestAbstract $request, ResponseAbstract $response, $data = null) : RenderableInterface
+ {
+ $view = new View($this->app->l11nManager, $request, $response);
+ $tag = TagMapper::get((int) $request->getData('id'));
+
+ $view->setTemplate('/Modules/Tag/Theme/Backend/tag-single');
+ $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1007501001, $request, $response));
+ $view->addData('tag', $tag);
+
+ return $view;
+ }
+}
diff --git a/Models/Tag.php b/Models/Tag.php
index 3a82158..5b904b7 100644
--- a/Models/Tag.php
+++ b/Models/Tag.php
@@ -17,7 +17,7 @@ namespace Modules\Tag\Models;
use phpOMS\Contract\ArrayableInterface;
/**
- * Tag article class.
+ * Tag class.
*
* @package Modules\Tag\Models
* @license OMS License 1.0
@@ -53,10 +53,10 @@ class Tag implements ArrayableInterface, \JsonSerializable
/**
* Creator.
*
- * @var int
+ * @var null|int|\Modules\Admin\Models\Account
* @since 1.0.0
*/
- protected $owner = 0;
+ protected $owner = null;
/**
* Tag type.
@@ -69,7 +69,7 @@ class Tag implements ArrayableInterface, \JsonSerializable
/**
* Get created by
*
- * @return null|int|\phpOMS\Account\Account
+ * @return null|int|\Modules\Admin\Models\Account
*
* @since 1.0.0
*/
@@ -192,14 +192,6 @@ class Tag implements ArrayableInterface, \JsonSerializable
];
}
- /**
- * {@inheritdoc}
- */
- public function __toString()
- {
- return (string) \json_encode($this->toArray());
- }
-
/**
* {@inheritdoc}
*/
diff --git a/Models/TagMapper.php b/Models/TagMapper.php
index 65a5f22..0a238fa 100644
--- a/Models/TagMapper.php
+++ b/Models/TagMapper.php
@@ -35,7 +35,7 @@ final class TagMapper extends DataMapperAbstract
*/
protected static array $columns = [
'tag_id' => ['name' => 'tag_id', 'type' => 'int', 'internal' => 'id'],
- 'tag_title' => ['name' => 'tag_title', 'type' => 'string', 'internal' => 'title'],
+ 'tag_title' => ['name' => 'tag_title', 'type' => 'string', 'internal' => 'title', 'autocomplete' => true],
'tag_color' => ['name' => 'tag_color', 'type' => 'string', 'internal' => 'color'],
'tag_type' => ['name' => 'tag_type', 'type' => 'int', 'internal' => 'type'],
'tag_owner' => ['name' => 'tag_owner', 'type' => 'int', 'internal' => 'owner'],
diff --git a/Theme/Backend/Components/TagSelector/BaseView.php b/Theme/Backend/Components/TagSelector/BaseView.php
new file mode 100644
index 0000000..5df92a0
--- /dev/null
+++ b/Theme/Backend/Components/TagSelector/BaseView.php
@@ -0,0 +1,92 @@
+setTemplate('/Modules/Tag/Theme/Backend/Components/TagSelector/base');
+ }
+
+ /**
+ * Get selector id
+ *
+ * @return string
+ *
+ * @since 1.0.0
+ */
+ public function getId() : string
+ {
+ return $this->id;
+ }
+
+ /**
+ * Get name
+ *
+ * @return string
+ *
+ * @since 1.0.0
+ */
+ public function getName() : string
+ {
+ return $this->name;
+ }
+
+ /**
+ * Is required?
+ *
+ * @return bool
+ *
+ * @since 1.0.0
+ */
+ public function isRequired() : bool
+ {
+ return $this->isRequired;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function render(...$data) : string
+ {
+ $this->id = $data[0];
+ $this->name = $data[1];
+ $this->isRequired = $data[2] ?? false;
+ return parent::render();
+ }
+}
diff --git a/Theme/Backend/Components/TagSelector/base.tpl.php b/Theme/Backend/Components/TagSelector/base.tpl.php
new file mode 100644
index 0000000..ba6c972
--- /dev/null
+++ b/Theme/Backend/Components/TagSelector/base.tpl.php
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Theme/Backend/Lang/Navigation.en.lang.php b/Theme/Backend/Lang/Navigation.en.lang.php
new file mode 100644
index 0000000..0000326
--- /dev/null
+++ b/Theme/Backend/Lang/Navigation.en.lang.php
@@ -0,0 +1,19 @@
+ [
+ 'Create' => 'Create',
+ 'List' => 'List',
+ 'Tag' => 'Tag',
+]];
diff --git a/Theme/Backend/Lang/en.lang.php b/Theme/Backend/Lang/en.lang.php
index c240819..83a3bdc 100644
--- a/Theme/Backend/Lang/en.lang.php
+++ b/Theme/Backend/Lang/en.lang.php
@@ -13,6 +13,10 @@
declare(strict_types=1);
return ['Tag' => [
- 'Tag' => 'Tag',
- 'Tags' => 'Tags',
+ 'Color' => 'Color',
+ 'Create' => 'Create',
+ 'List' => 'List',
+ 'Tag' => 'Tag',
+ 'Tags' => 'Tags',
+ 'Title' => 'Title',
]];
diff --git a/Theme/Backend/tag-create.tpl.php b/Theme/Backend/tag-create.tpl.php
new file mode 100644
index 0000000..4603ce3
--- /dev/null
+++ b/Theme/Backend/tag-create.tpl.php
@@ -0,0 +1,40 @@
+getData('nav')->render(); ?>
+
\ No newline at end of file
diff --git a/Theme/Backend/tag-list.tpl.php b/Theme/Backend/tag-list.tpl.php
new file mode 100644
index 0000000..2cd18ea
--- /dev/null
+++ b/Theme/Backend/tag-list.tpl.php
@@ -0,0 +1,44 @@
+getData('tags');
+
+echo $this->getData('nav')->render(); ?>
+
+
+
+
= $this->getHtml('Tags') ?>
+
+
+
+ | = $this->getHtml('Title') ?>
+ | = $this->getHtml('Color') ?>
+ |
+ $value) : ++$count;
+ $url = \phpOMS\Uri\UriFactory::build('{/prefix}tag/single?{?}&id=' . $value->getId()); ?>
+
+ | = $this->printHtml($value->getTitle()); ?>
+ |
+
+
+ |
| = $this->getHtml('Empty', '0', '0'); ?>
+
+ |
+
+
+
diff --git a/Theme/Backend/tag-single.tpl.php b/Theme/Backend/tag-single.tpl.php
new file mode 100644
index 0000000..09bc338
--- /dev/null
+++ b/Theme/Backend/tag-single.tpl.php
@@ -0,0 +1,42 @@
+getData('tag');
+
+/**
+ * @var \phpOMS\Views\View $this
+ */
+echo $this->getData('nav')->render(); ?>
+
\ No newline at end of file
diff --git a/info.json b/info.json
index ca8d7d6..fa2a790 100644
--- a/info.json
+++ b/info.json
@@ -24,5 +24,23 @@
"Navigation": "*"
},
"load": [
+ {
+ "pid": [
+ "/tag"
+ ],
+ "type": 4,
+ "for": "Tag",
+ "file": "Tag",
+ "from": "Tag"
+ },
+ {
+ "pid": [
+ "/"
+ ],
+ "type": 5,
+ "from": "Tag",
+ "for": "Navigation",
+ "file": "Navigation"
+ }
]
}