diff --git a/Admin/Install/db.json b/Admin/Install/db.json index 6a1d675..1d98c15 100755 --- a/Admin/Install/db.json +++ b/Admin/Install/db.json @@ -9,11 +9,6 @@ "primary": true, "autoincrement": true }, - "qa_category_name": { - "name": "qa_category_name", - "type": "VARCHAR(255)", - "null": false - }, "qa_category_parent": { "name": "qa_category_parent", "type": "INT", @@ -24,6 +19,38 @@ } } }, + "qa_category_l11n": { + "name": "qa_category_l11n", + "fields": { + "qa_category_l11n_id": { + "name": "qa_category_l11n_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "qa_category_l11n_name": { + "name": "qa_category_l11n_name", + "type": "VARCHAR(255)", + "null": false + }, + "qa_category_l11n_category": { + "name": "qa_category_l11n_category", + "type": "INT", + "null": false, + "foreignTable": "qa_category", + "foreignKey": "qa_category_id" + }, + "qa_category_l11n_language": { + "name": "qa_category_l11n_language", + "type": "VARCHAR(2)", + "default": null, + "null": true, + "foreignTable": "language", + "foreignKey": "language_639_1" + } + } + }, "qa_question": { "name": "qa_question", "fields": { @@ -77,6 +104,32 @@ } } }, + "qa_tag": { + "name": "qa_tag", + "fields": { + "qa_tag_id": { + "name": "qa_tag_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "qa_tag_dst": { + "name": "qa_tag_dst", + "type": "INT", + "null": false, + "foreignTable": "qa_question", + "foreignKey": "qa_question_id" + }, + "qa_tag_src": { + "name": "qa_tag_src", + "type": "INT", + "null": false, + "foreignTable": "tag", + "foreignKey": "tag_id" + } + } + }, "qa_answer": { "name": "qa_answer", "fields": { diff --git a/Controller/ApiController.php b/Controller/ApiController.php index de4a6b5..9220ffc 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -29,6 +29,13 @@ use phpOMS\Message\RequestAbstract; use phpOMS\Message\ResponseAbstract; use phpOMS\Model\Message\FormValidation; use phpOMS\Utils\Parser\Markdown\Markdown; +use phpOMS\Message\Http\HttpRequest; +use phpOMS\Message\NotificationLevel; +use Modules\QA\Models\QACategoryL11n; +use Modules\Tag\Models\NullTag; +use phpOMS\Message\Http\HttpResponse; +use Modules\Admin\Models\NullAccount; +use Modules\QA\Models\QACategoryL11nMapper; /** * Task class. @@ -69,21 +76,23 @@ final class ApiController extends Controller return; } - $question = $this->createQAQuestionFromRquest($request); - QAQuestionMapper::create($question); - $response->set('question', $question->jsonSerialize()); + $question = $this->createQAQuestionFromRequest($request, $response, $data); + $this->createModel($request->getHeader()->getAccount(), $question, QAQuestionMapper::class, 'question', $request->getOrigin()); + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Question', 'Question successfully created.', $question); } /** * Method to create question from request. * - * @param RequestAbstract $request Request + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data * * @return QAQuestion Returns the created question from the request * * @since 1.0.0 */ - public function createQAQuestionFromRquest(RequestAbstract $request) : QAQuestion + public function createQAQuestionFromRequest(RequestAbstract $request, ResponseAbstract $response, $data = null) : QAQuestion { $mardkownParser = new Markdown(); @@ -93,7 +102,23 @@ final class ApiController extends Controller $question->setLanguage((string) $request->getData('language')); $question->setCategory(new NullQACategory((int) $request->getData('category'))); $question->setStatus((int) $request->getData('status')); - $question->setBadges((array) $request->getData('badges')); + $question->setCreatedBy(new NullAccount($request->getHeader()->getAccount())); + + if (!empty($tags = $request->getDataJson('tags'))) { + foreach ($tags as $tag) { + if (!isset($tag['id'])) { + $request->setData('title', $tag['title'], true); + $request->setData('color', $tag['color'], true); + $request->setData('language', $tag['language'], true); + + $internalResponse = new HttpResponse(); + $this->app->moduleManager->get('Tag')->apiTagCreate($request, $internalResponse, $data); + $question->addTag($internalResponse->get($request->getUri()->__toString())['response']); + } else { + $question->addTag(new NullTag((int) $tag['id'])); + } + } + } return $question; } @@ -114,7 +139,6 @@ final class ApiController extends Controller || ($val['plain'] = empty($request->getData('plain'))) || ($val['language'] = empty($request->getData('language'))) || ($val['category'] = empty($request->getData('category'))) - || ($val['badges'] = empty($request->getData('badges'))) || ($val['status'] = ( $request->getData('status') !== null && !QAQuestionStatus::isValidValue((int) $request->getData('status')) @@ -148,9 +172,9 @@ final class ApiController extends Controller return; } - $answer = $this->createQAAnswerFromRquest($request); - QAAnswerMapper::create($answer); - $response->set('answer', $answer->jsonSerialize()); + $answer = $this->createQAAnswerFromRequest($request); + $this->createModel($request->getHeader()->getAccount(), $answer, QAAnswerMapper::class, 'answer', $request->getOrigin()); + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Answer', 'Answer successfully created.', $answer); } /** @@ -162,7 +186,7 @@ final class ApiController extends Controller * * @since 1.0.0 */ - public function createQAAnswerFromRquest(RequestAbstract $request) : QAAnswer + public function createQAAnswerFromRequest(RequestAbstract $request) : QAAnswer { $mardkownParser = new Markdown(); @@ -170,6 +194,7 @@ final class ApiController extends Controller $answer->setAnswer((string) $request->getData('plain')); $answer->setQuestion(new NullQAQuestion((int) $request->getData('question'))); $answer->setStatus((int) $request->getData('status')); + $answer->setCreatedBy(new NullAccount($request->getHeader()->getAccount())); return $answer; } @@ -186,8 +211,7 @@ final class ApiController extends Controller private function validateQAAnswerCreate(RequestAbstract $request) : array { $val = []; - if (($val['title'] = empty($request->getData('title'))) - || ($val['plain'] = empty($request->getData('plain'))) + if (($val['plain'] = empty($request->getData('plain'))) || ($val['question'] = empty($request->getData('question'))) || ($val['status'] = ( $request->getData('status') !== null @@ -222,9 +246,20 @@ final class ApiController extends Controller return; } - $category = $this->createQACategoryFromRquest($request); - QACategoryMapper::create($category); - $response->set('category', $category->jsonSerialize()); + $category = $this->createQACategoryFromRequest($request); + $this->createModel($request->getHeader()->getAccount(), $category, QACategoryMapper::class, 'category', $request->getOrigin()); + + $l11nRequest = new HttpRequest($request->getUri()); + $l11nRequest->setData('category', $category->getId()); + $l11nRequest->setData('name', $request->getData('name')); + $l11nRequest->setData('language', $request->getData('language')); + + $l11nQACategory = $this->createQACategoryL11nFromRequest($l11nRequest); + $this->createModel($request->getHeader()->getAccount(), $l11nQACategory, QACategoryL11nMapper::class, 'tag_l11n', $request->getOrigin()); + + $category->setName($l11nQACategory); + + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Category', 'Category successfully created.', $category); } /** @@ -236,13 +271,14 @@ final class ApiController extends Controller * * @since 1.0.0 */ - public function createQACategoryFromRquest(RequestAbstract $request) : QACategory + public function createQACategoryFromRequest(RequestAbstract $request) : QACategory { - $mardkownParser = new Markdown(); - $category = new QACategory(); - $category->setName((string) $request->getData('title')); - $category->setParent($request->getData('parent') === null ? null : new NullQACategory((int) $request->getData('parent'))); + //$category->setApp(new NullQAApp((int) ($request->getData('app') ?? 1))); + + if ($request->getData('parent') !== null) { + $category->setParent(new NullQACategory((int) $request->getData('parent'))); + } return $category; } @@ -259,12 +295,80 @@ final class ApiController extends Controller private function validateQACategoryCreate(RequestAbstract $request) : array { $val = []; - if (($val['title'] = empty($request->getData('title'))) - || ($val['parent'] = empty($request->getData('parent'))) + if (($val['name'] = empty($request->getData('name')))) { + return $val; + } + + return []; + } + + /** + * Validate tag l11n create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateQACategoryL11nCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['name'] = empty($request->getData('name'))) + || ($val['category'] = empty($request->getData('category'))) ) { return $val; } return []; } + + /** + * Api method to create tag localization + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiQACategoryL11nCreate(RequestAbstract $request, ResponseAbstract $response, $data = null) : void + { + if (!empty($val = $this->validateQACategoryL11nCreate($request))) { + $response->set('qa_category_l11n_create', new FormValidation($val)); + $response->getHeader()->setStatusCode(RequestStatusCode::R_400); + + return; + } + + $l11nQACategory = $this->createQACategoryL11nFromRequest($request); + $this->createModel($request->getHeader()->getAccount(), $l11nQACategory, QACategoryL11nMapper::class, 'qa_category_l11n', $request->getOrigin()); + + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Localization', 'Category localization successfully created', $l11nQACategory); + } + + /** + * Method to create tag localization from request. + * + * @param RequestAbstract $request Request + * + * @return QACategoryL11n + * + * @since 1.0.0 + */ + private function createQACategoryL11nFromRequest(RequestAbstract $request) : QACategoryL11n + { + $l11nQACategory = new QACategoryL11n(); + $l11nQACategory->setCategory((int) ($request->getData('category') ?? 0)); + $l11nQACategory->setLanguage((string) ( + $request->getData('language') ?? $request->getLanguage() + )); + $l11nQACategory->setName((string) ($request->getData('name') ?? '')); + + return $l11nQACategory; + } } diff --git a/Controller/BackendController.php b/Controller/BackendController.php index e051c3c..3a3c3c1 100755 --- a/Controller/BackendController.php +++ b/Controller/BackendController.php @@ -71,7 +71,7 @@ final class BackendController extends Controller $view->setTemplate('/Modules/QA/Theme/Backend/qa-dashboard'); $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1006001001, $request, $response)); - $list = QAQuestionMapper::getNewest(50); + $list = QAQuestionMapper::withConditional('language', $response->getLanguage())::getNewest(50); $view->setData('questions', $list); return $view; diff --git a/Models/QACategory.php b/Models/QACategory.php index 09d064d..d8440a8 100755 --- a/Models/QACategory.php +++ b/Models/QACategory.php @@ -14,6 +14,8 @@ declare(strict_types=1); namespace Modules\QA\Models; +use phpOMS\Localization\ISO639x1Enum; + /** * Task class. * @@ -35,10 +37,10 @@ class QACategory implements \JsonSerializable /** * Name. * - * @var string + * @var string|QACategoryL11n * @since 1.0.0 */ - private string $name = ''; + private $name = ''; /** * Parent category. @@ -69,21 +71,29 @@ class QACategory implements \JsonSerializable */ public function getName() : string { - return $this->name; + return $this->name instanceof QACategoryL11n ? $this->name->getName() : $this->name; } /** * Set name * - * @param string $name Name + * @param string|TagL11n $name Tag article name * * @return void * * @since 1.0.0 */ - public function setName(string $name) : void + public function setName($name, string $lang = ISO639x1Enum::_EN) : void { - $this->name = $name; + if ($name instanceof QACategoryL11n) { + $this->name = $name; + } elseif ($this->name instanceof QACategoryL11n && \is_string($name)) { + $this->name->setName($name); + } elseif (\is_string($name)) { + $this->name = new QACategoryL11n(); + $this->name->setName($name); + $this->name->setLanguage($lang); + } } /** diff --git a/Models/QACategoryL11n.php b/Models/QACategoryL11n.php new file mode 100644 index 0000000..58dcd01 --- /dev/null +++ b/Models/QACategoryL11n.php @@ -0,0 +1,185 @@ +name = $name; + $this->language = $language; + } + + /** + * Get id + * + * @return int + * + * @since 1.0.0 + */ + public function getId() : int + { + return $this->id; + } + + /** + * Set category. + * + * @param int $category Category id + * + * @return void + * + * @since 1.0.0 + */ + public function setCategory(int $category) : void + { + $this->category = $category; + } + + /** + * Get category + * + * @return int + * + * @since 1.0.0 + */ + public function getCategory() : int + { + return $this->category; + } + + /** + * Get language + * + * @return string + * + * @since 1.0.0 + */ + public function getLanguage() : string + { + return $this->language; + } + + /** + * Set language + * + * @param string $language Language + * + * @return void + * + * @since 1.0.0 + */ + public function setLanguage(string $language) : void + { + $this->language = $language; + } + + /** + * Get category name. + * + * @return string + * + * @since 1.0.0 + */ + public function getName() : string + { + return $this->name; + } + + /** + * Set name + * + * @param string $name Name + * + * @return void + * + * @since 1.0.0 + */ + public function setName(string $name) : void + { + $this->name = $name; + } + + /** + * {@inheritdoc} + */ + public function toArray() : array + { + return [ + 'id' => $this->id, + 'name' => $this->name, + 'category' => $this->category, + 'language' => $this->language, + ]; + } + + /** + * {@inheritdoc} + */ + public function jsonSerialize() + { + return $this->toArray(); + } +} diff --git a/Models/QACategoryL11nMapper.php b/Models/QACategoryL11nMapper.php new file mode 100644 index 0000000..1dc5d7c --- /dev/null +++ b/Models/QACategoryL11nMapper.php @@ -0,0 +1,76 @@ + + * @since 1.0.0 + */ + protected static array $columns = [ + 'qa_category_l11n_id' => ['name' => 'qa_category_l11n_id', 'type' => 'int', 'internal' => 'id'], + 'qa_category_l11n_name' => ['name' => 'qa_category_l11n_name', 'type' => 'string', 'internal' => 'name', 'autocomplete' => true], + 'qa_category_l11n_category' => ['name' => 'qa_category_l11n_category', 'type' => 'int', 'internal' => 'category'], + 'qa_category_l11n_language' => ['name' => 'qa_category_l11n_language', 'type' => 'string', 'internal' => 'language'], + ]; + + /** + * Has one relation. + * + * @var array + * @since 1.0.0 + */ + protected static array $ownsOne = [ + 'language' => [ + 'mapper' => LanguageMapper::class, + 'external' => 'qa_category_l11n_language', + 'by' => 'code2', + 'column' => 'code2', + 'conditional' => true, + ], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + protected static string $table = 'qa_category_l11n'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + protected static string $primaryField = 'qa_category_l11n_id'; +} diff --git a/Models/QACategoryMapper.php b/Models/QACategoryMapper.php index 20e7705..2b6f3b9 100755 --- a/Models/QACategoryMapper.php +++ b/Models/QACategoryMapper.php @@ -34,7 +34,6 @@ final class QACategoryMapper extends DataMapperAbstract */ protected static array $columns = [ 'qa_category_id' => ['name' => 'qa_category_id', 'type' => 'int', 'internal' => 'id'], - 'qa_category_name' => ['name' => 'qa_category_name', 'type' => 'string', 'internal' => 'name'], 'qa_category_parent' => ['name' => 'qa_category_parent', 'type' => 'int', 'internal' => 'parent'], ]; @@ -51,6 +50,23 @@ final class QACategoryMapper extends DataMapperAbstract ], ]; + /** + * Has many relation. + * + * @var array + * @since 1.0.0 + */ + protected static array $hasMany = [ + 'name' => [ + 'mapper' => QACategoryL11nMapper::class, + 'table' => 'qa_category_l11n', + 'self' => 'qa_category_l11n_category', + 'column' => 'name', + 'conditional' => true, + 'external' => null, + ], + ]; + /** * Primary table. * diff --git a/Models/QAQuestion.php b/Models/QAQuestion.php index 6dc6eda..e2a62f5 100755 --- a/Models/QAQuestion.php +++ b/Models/QAQuestion.php @@ -93,12 +93,12 @@ class QAQuestion implements \JsonSerializable private \DateTimeImmutable $createdAt; /** - * Badges. + * Tags. * * @var array * @since 1.0.0 */ - private array $badges = []; + private array $tags = []; /** * Answers. @@ -336,35 +336,35 @@ class QAQuestion implements \JsonSerializable } /** - * Get badges + * Get tags * * @return array * * @since 1.0.0 */ - public function getBadges() : array + public function getTags() : array { - return $this->badges; + return $this->tags; } /** - * Add badge to question + * Add tag to question * - * @param int|Tag $badge Badge + * @param int|Tag $tag Tag */ - public function addBadge($badge) : void + public function addTag($tag) : void { - $this->badges[] = $badge; + $this->tags[] = $tag; } /** - * Set badges to question + * Set tags to question * - * @param array $badges Badges + * @param array $tags Tags */ - public function setBadges(array $badges) : void + public function setTags(array $tags) : void { - $this->badges = $badges; + $this->tags = $tags; } /** diff --git a/Models/QAQuestionMapper.php b/Models/QAQuestionMapper.php index f65e594..9a4f698 100755 --- a/Models/QAQuestionMapper.php +++ b/Models/QAQuestionMapper.php @@ -16,6 +16,7 @@ namespace Modules\QA\Models; use Modules\Admin\Models\AccountMapper; use phpOMS\DataStorage\Database\DataMapperAbstract; +use Modules\Tag\Models\TagMapper; /** * Mapper class. @@ -57,6 +58,12 @@ final class QAQuestionMapper extends DataMapperAbstract 'self' => 'qa_answer_question', 'external' => null, ], + 'tags' => [ + 'mapper' => TagMapper::class, + 'table' => 'qa_tag', + 'self' => 'qa_tag_dst', + 'external' => 'qa_tag_src', + ], ]; /** diff --git a/Theme/Backend/qa-dashboard.tpl.php b/Theme/Backend/qa-dashboard.tpl.php index c706dec..11a863d 100755 --- a/Theme/Backend/qa-dashboard.tpl.php +++ b/Theme/Backend/qa-dashboard.tpl.php @@ -18,8 +18,8 @@ echo $this->getData('nav')->render(); ?>
-
-
+
+
printHtml(\count($question->getAnswers())); ?> @@ -29,8 +29,8 @@ echo $this->getData('nav')->render(); ?>
- getBadges(); foreach ($badges as $badge) : ?> - printHtml($badge->getName()); ?> + getTags(); foreach ($tags as $tag) : ?> + printHtml($tag->getTitle()); ?>
diff --git a/info.json b/info.json index 36ec3e2..48b9444 100755 --- a/info.json +++ b/info.json @@ -17,6 +17,7 @@ "description": "QA module.", "directory": "QA", "dependencies": { + "Tag": "1.0.0", "Admin": "1.0.0", "Editor": "1.0.0", "Tools": "1.0.0"