diff --git a/CHANGELOG.md b/CHANGELOG.md index 3da4c67..c241a53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [undecided] - unreleased + +### Added +- Admin controller +- Template for admin controller +- Example of extending of current admin template +- ``oxNew`` object factory example + ## [v3.1.0] - Unreleased ### Removed diff --git a/README.md b/README.md index a906325..02cc03e 100644 --- a/README.md +++ b/README.md @@ -214,7 +214,8 @@ Story: * extending a shop model (`OxidEsales\ModuleTemplate\Extension\Model\User`) / (`OxidEsales\ModuleTemplate\Extension\Model\Basket`) * extending a shop controller (`OxidEsales\ModuleTemplate\Extension\Controller\StartController`) * extending a shop database table (`oxuser`) -* extending a shop template block (`start_welcome_text`) +* extending a shop template block (`start_newest_articles`) +* extending a shop admin template block (`admin_user_main_form` - only an extension of a block, without functionality) **HINT**: only extend the shop core if there is no other way like listen and handle shop events, decorate/replace some DI service. Your module might be one of many in the class chain and you should @@ -227,10 +228,12 @@ If you need to extend the shop class chain by overwriting, try to stick to the p #### Sometimes we need to bring our own * own module controller (`oemtgreeting` with own template and own translations) +* own module admin controller (`oemt_admin_greeting` with own template and own translations) * module setting (`oemoduletemplate_GreetingMode`) * event subscriber (`OxidEsales\ModuleTemplate\Tracker\Subscriber\BeforeModelUpdate`) * model with a database (`OxidEsales\ModuleTemplate\Tracker\Model\GreetingTracker`) * DI service examples +* ``oxNew`` object factory example (`OxidEsales\ModuleTemplate\Greeting\Infrastructure\UserModelFactory`) #### Whatever you do, ensure it is covered with tests * unit/integration test diff --git a/menu.xml b/menu.xml new file mode 100644 index 0000000..be2a624 --- /dev/null +++ b/menu.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/metadata.php b/metadata.php index 3fda7f7..0ede64c 100644 --- a/metadata.php +++ b/metadata.php @@ -28,7 +28,8 @@ \OxidEsales\Eshop\Application\Model\User::class => \OxidEsales\ModuleTemplate\Extension\Model\User::class, ], 'controllers' => [ - 'oemtgreeting' => \OxidEsales\ModuleTemplate\Greeting\Controller\GreetingController::class + 'oemtgreeting' => \OxidEsales\ModuleTemplate\Greeting\Controller\GreetingController::class, + 'oemt_admin_greeting' => \OxidEsales\ModuleTemplate\Greeting\Controller\Admin\GreetingAdminController::class, ], 'events' => [ 'onActivate' => '\OxidEsales\ModuleTemplate\Core\ModuleEvents::onActivate', diff --git a/src/Core/Module.php b/src/Core/Module.php index fd95178..64cf660 100644 --- a/src/Core/Module.php +++ b/src/Core/Module.php @@ -18,4 +18,6 @@ final class Module public const OEMT_COUNTER_TEMPLATE_VARNAME = 'oemt_greeting_counter'; public const DEFAULT_PERSONAL_GREETING_LANGUAGE_CONST = 'OEMODULETEMPLATE_GREETING_GENERIC'; + + public const OEMT_ADMIN_GREETING_TEMPLATE_VARNAME = 'greeting_message'; } diff --git a/src/Greeting/Controller/Admin/GreetingAdminController.php b/src/Greeting/Controller/Admin/GreetingAdminController.php new file mode 100644 index 0000000..ba03e10 --- /dev/null +++ b/src/Greeting/Controller/Admin/GreetingAdminController.php @@ -0,0 +1,32 @@ +getService(UserServiceInterface::class); + if ($this->getEditObjectId()) { + /** @var TemplateModelUser $oUser */ + $oUser = $userService->getUserById($this->getEditObjectId()); + $this->addTplParam(ModuleCore::OEMT_ADMIN_GREETING_TEMPLATE_VARNAME, $oUser->getPersonalGreeting()); + } + + return parent::render(); + } +} diff --git a/src/Greeting/Infrastructure/UserModelFactory.php b/src/Greeting/Infrastructure/UserModelFactory.php new file mode 100644 index 0000000..ee02c1c --- /dev/null +++ b/src/Greeting/Infrastructure/UserModelFactory.php @@ -0,0 +1,23 @@ +userModelFactory = $userModelFactory; + } + + public function getUserById(string $userId): EshopModelUser + { + $userModel = $this->userModelFactory->create(); + $userModel->load($userId); + + return $userModel; + } +} diff --git a/src/Greeting/Service/UserServiceInterface.php b/src/Greeting/Service/UserServiceInterface.php new file mode 100644 index 0000000..df3d645 --- /dev/null +++ b/src/Greeting/Service/UserServiceInterface.php @@ -0,0 +1,17 @@ +setGreetingModeGeneric(); + $this->setUserPersonalGreeting($I, 'Hello there!'); + } + + public function _after(AcceptanceTester $I): void + { + //clean up after each test + $I->setGreetingModeGeneric(); + } + + /** @param AcceptanceTester $I */ + public function seeGreetingOptionsForUser(AcceptanceTester $I): void + { + $I->openAdmin(); + $adminPage = $I->loginAdmin(); + + $userList = $adminPage->openUsers(); + $userList->find("where[oxuser][oxusername]", $I->getDemoUserName()); + + $I->selectEditFrame(); + $I->see(Translator::translate('OEMODULETEMPLATE_ALLOW_GREETING')); + + $I->selectListFrame(); + $I->click(Translator::translate('tbcluser_greetings')); + + $I->selectEditFrame(); + $I->see(Translator::translate('OEMODULETEMPLATE_GREETING_TITLE')); + $I->see('Hello there!'); + } + + private function setUserPersonalGreeting(AcceptanceTester $I, string $value = ''): void + { + $I->updateInDatabase( + 'oxuser', + [ + 'oemtgreeting' => $value, + ], + [ + 'oxusername' => $I->getDemoUserName(), + ] + ); + } +} diff --git a/tests/Codeception/Acceptance/GreetingCest.php b/tests/Codeception/Acceptance/GreetingCest.php index 8089231..0696853 100644 --- a/tests/Codeception/Acceptance/GreetingCest.php +++ b/tests/Codeception/Acceptance/GreetingCest.php @@ -7,7 +7,7 @@ declare(strict_types=1); -namespace OxidEsales\ModuleTemplate\Tests\Codeception\Helper; +namespace OxidEsales\ModuleTemplate\Tests\Codeception\Acceptance; use OxidEsales\Codeception\Module\Translation\Translator; use OxidEsales\ModuleTemplate\Tests\Codeception\Support\AcceptanceTester; diff --git a/tests/Codeception/Acceptance/ModuleCest.php b/tests/Codeception/Acceptance/ModuleCest.php index 9242193..88df3b5 100644 --- a/tests/Codeception/Acceptance/ModuleCest.php +++ b/tests/Codeception/Acceptance/ModuleCest.php @@ -7,7 +7,7 @@ declare(strict_types=1); -namespace OxidEsales\ModuleTemplate\Tests\Codeception\Helper; +namespace OxidEsales\ModuleTemplate\Tests\Codeception\Acceptance; use OxidEsales\Codeception\Module\Translation\Translator; use OxidEsales\ModuleTemplate\Core\Module; diff --git a/tests/Codeception/Acceptance/UpdateGreetingCest.php b/tests/Codeception/Acceptance/UpdateGreetingCest.php index 748c1eb..2af51e1 100644 --- a/tests/Codeception/Acceptance/UpdateGreetingCest.php +++ b/tests/Codeception/Acceptance/UpdateGreetingCest.php @@ -7,7 +7,7 @@ declare(strict_types=1); -namespace OxidEsales\ModuleTemplate\Tests\Codeception\Helper; +namespace OxidEsales\ModuleTemplate\Tests\Codeception\Acceptance; use OxidEsales\Codeception\Module\Translation\Translator; use OxidEsales\ModuleTemplate\Core\Module as ModuleCore; diff --git a/tests/Codeception/Support/AcceptanceTester.php b/tests/Codeception/Support/AcceptanceTester.php index eb1acbd..6a18554 100644 --- a/tests/Codeception/Support/AcceptanceTester.php +++ b/tests/Codeception/Support/AcceptanceTester.php @@ -10,6 +10,8 @@ namespace OxidEsales\ModuleTemplate\Tests\Codeception\Support; use Codeception\Util\Fixtures; +use OxidEsales\Codeception\Admin\AdminLoginPage; +use OxidEsales\Codeception\Admin\AdminPanel; use OxidEsales\Codeception\Page\Home; use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory; use OxidEsales\Facts\Facts; @@ -91,6 +93,21 @@ public function getShopUrl(): string return $facts->getShopUrl(); } + public function openAdmin(): AdminLoginPage + { + $I = $this; + $adminLogin = new AdminLoginPage($I); + $I->amOnPage($adminLogin->URL); + return $adminLogin; + } + + public function loginAdmin(): AdminPanel + { + $adminPage = $this->openAdmin(); + $admin = Fixtures::get('adminUser'); + return $adminPage->login($admin['email'], $admin['password']); + } + protected function getServiceFromContainer(string $serviceName) { return ContainerFactory::getInstance() diff --git a/tests/Codeception/Support/Data/fixtures.php b/tests/Codeception/Support/Data/fixtures.php index f0a0ec2..8203c99 100644 --- a/tests/Codeception/Support/Data/fixtures.php +++ b/tests/Codeception/Support/Data/fixtures.php @@ -13,4 +13,9 @@ 'email' => 'user@oxid-esales.com', 'password' => 'useruser', ], + 'adminUser' => [ + 'OXID' => 'oxadminuser', + 'email' => 'admin@oxid-esales.com', + 'password' => 'useruser', + ], ]; diff --git a/tests/Codeception/Support/Data/fixtures.sql b/tests/Codeception/Support/Data/fixtures.sql index b46ea9b..f0c7152 100644 --- a/tests/Codeception/Support/Data/fixtures.sql +++ b/tests/Codeception/Support/Data/fixtures.sql @@ -1,3 +1,4 @@ #Add default user REPLACE INTO `oxuser` (`OXID`, `OXACTIVE`, `OXRIGHTS`, `OXSHOPID`, `OXUSERNAME`, `OXPASSWORD`, `OXPASSSALT`, `OXCREATE`, `OXREGISTER`, `OXTIMESTAMP`, `OXBIRTHDATE`) VALUES -('oxdefaultuser',1,'user',1,'user@oxid-esales.com','$2y$10$ljaDXMPHOyC7ELlnC5ErK.3ET4B0oAN3WVr/Tk.RKlUfiuBcQEVVC','', '2003-01-01 00:00:00', '2003-01-01 00:00:00', '2003-01-01 00:00:00', '1985-01-01'); +('oxdefaultuser',1,'user',1,'user@oxid-esales.com','$2y$10$ljaDXMPHOyC7ELlnC5ErK.3ET4B0oAN3WVr/Tk.RKlUfiuBcQEVVC','', '2003-01-01 00:00:00', '2003-01-01 00:00:00', '2003-01-01 00:00:00', '1985-01-01'), +('oxadminuser',1,'malladmin',1,'admin@oxid-esales.com','$2y$10$ljaDXMPHOyC7ELlnC5ErK.3ET4B0oAN3WVr/Tk.RKlUfiuBcQEVVC','', '2003-01-01 00:00:00', '2003-01-01 00:00:00', '2003-01-01 00:00:00', '1985-01-01'); diff --git a/tests/Integration/Greeting/Controller/Admin/GreetingAdminControllerTest.php b/tests/Integration/Greeting/Controller/Admin/GreetingAdminControllerTest.php new file mode 100644 index 0000000..fb7e1bf --- /dev/null +++ b/tests/Integration/Greeting/Controller/Admin/GreetingAdminControllerTest.php @@ -0,0 +1,52 @@ +createTestUser(); + + $controller = oxNew(GreetingAdminController::class); + $controller->setEditObjectId(self::TEST_USER_ID); + + $this->assertSame('@oe_moduletemplate/admin/user_greetings', $controller->render()); + + $viewData = $controller->getViewData(); + + $this->assertSame(self::TEST_GREETING, $viewData[ModuleCore::OEMT_ADMIN_GREETING_TEMPLATE_VARNAME]); + } + + private function createTestUser(): void + { + $user = oxNew(EshopModelUser::class); + $user->assign( + [ + 'oxid' => self::TEST_USER_ID, + 'oemtgreeting' => self::TEST_GREETING, + ] + ); + $user->save(); + } +} diff --git a/tests/Integration/Greeting/Service/GreetingMessageServiceTest.php b/tests/Integration/Greeting/Service/GreetingMessageServiceTest.php index 8202911..6d04324 100644 --- a/tests/Integration/Greeting/Service/GreetingMessageServiceTest.php +++ b/tests/Integration/Greeting/Service/GreetingMessageServiceTest.php @@ -54,7 +54,7 @@ private function getSut( ): GreetingMessageService { return new GreetingMessageService( moduleSettings: $moduleSettings ?? $this->createStub(ModuleSettingsServiceInterface::class), - shopRequest: $shopRequest ?? $this->createStub(CoreRequest::class), + shopRequest: $this->createStub(CoreRequest::class), shopLanguage: $shopLanguage ?? $this->createStub(CoreLanguage::class), ); } diff --git a/tests/Unit/Greeting/Infrastructure/UserModelFactoryTest.php b/tests/Unit/Greeting/Infrastructure/UserModelFactoryTest.php new file mode 100644 index 0000000..2e4bd71 --- /dev/null +++ b/tests/Unit/Greeting/Infrastructure/UserModelFactoryTest.php @@ -0,0 +1,29 @@ +getMockBuilder(UserModelFactory::class) + ->onlyMethods(['create']) + ->getMock(); + + $this->assertInstanceOf(User::class, $coreRequestFactoryMock->create()); + } +} diff --git a/views/admin_twig/de/module_options.php b/views/admin_twig/de/module_options.php index e9e60fe..2befaa8 100644 --- a/views/admin_twig/de/module_options.php +++ b/views/admin_twig/de/module_options.php @@ -9,6 +9,15 @@ $aLang = [ 'charset' => 'UTF-8', + 'tbcluser_greetings' => 'Greetings', + + 'OEMODULETEMPLATE_GREETING_TITLE' => 'Beispiel Admin Controller', + 'OEMODULETEMPLATE_GREETING_MESSAGE_TEXT' => 'Begrüßungsnachricht: ', + 'OEMODULETEMPLATE_NO_GREETING_TEXT' => 'Es wurde keine Begrüßungsnachricht hinzugefügt!', + 'OEMODULETEMPLATE_ALLOW_GREETING' => 'Benutzer erlauben die Begrüßungsnachricht zu setzen', + 'OEMODULETEMPLATE_HELP_ALLOW_GREETING' => 'Dies ist ein Beispiel, wie ein Admintemplate erweitert werden kann. Momentan ist keine Funktionalität hinter dieser Checkbox hinterlegt, es wird keine Einstellung in der Datenbank gespeichert.', + + # Module settings 'SHOP_MODULE_GROUP_oemoduletemplate_main' => 'Einstellungen', 'SHOP_MODULE_oemoduletemplate_GreetingMode' => 'Begrüßungsmodus', 'SHOP_MODULE_oemoduletemplate_GreetingMode_generic' => 'höflich', diff --git a/views/admin_twig/en/module_options.php b/views/admin_twig/en/module_options.php index 80de61c..839a250 100644 --- a/views/admin_twig/en/module_options.php +++ b/views/admin_twig/en/module_options.php @@ -9,6 +9,15 @@ $aLang = [ 'charset' => 'UTF-8', + 'tbcluser_greetings' => 'Greetings', + + 'OEMODULETEMPLATE_GREETING_TITLE' => 'Admin controller example', + 'OEMODULETEMPLATE_GREETING_MESSAGE_TEXT' => 'Greeting message: ', + 'OEMODULETEMPLATE_NO_GREETING_TEXT' => 'No greeting message added!', + 'OEMODULETEMPLATE_ALLOW_GREETING' => 'Allow user to set greeting', + 'OEMODULETEMPLATE_HELP_ALLOW_GREETING' => 'This is an example of extending admin template. There is no functionality implemented behind this checkbox and does not save anything to the database', + + # Module settings 'SHOP_MODULE_GROUP_oemoduletemplate_main' => 'Settings', 'SHOP_MODULE_oemoduletemplate_GreetingMode' => 'Greeting mode', 'SHOP_MODULE_oemoduletemplate_GreetingMode_generic' => 'generic', diff --git a/views/twig/admin/user_greetings.html.twig b/views/twig/admin/user_greetings.html.twig new file mode 100644 index 0000000..26b8789 --- /dev/null +++ b/views/twig/admin/user_greetings.html.twig @@ -0,0 +1,18 @@ +{% include "headitem.html.twig" with {title: "GENERAL_ADMIN_TITLE"|translate} %} + +
+ {{ oViewConf.getHiddenSid()|raw }} + + +
+ +

{{ translate({ ident: "OEMODULETEMPLATE_GREETING_TITLE" }) }}

+ +{% if greeting_message %} +
{{ translate({ ident: "OEMODULETEMPLATE_GREETING_MESSAGE_TEXT" }) }} {{ greeting_message }}
+{% else %} +
{{ translate({ ident: "OEMODULETEMPLATE_NO_GREETING_TEXT" }) }}
+{% endif %} + +{% include "bottomnaviitem.html.twig" %} +{% include "bottomitem.html.twig" %} diff --git a/views/twig/extensions/themes/admin_twig/user_main.html.twig b/views/twig/extensions/themes/admin_twig/user_main.html.twig new file mode 100644 index 0000000..77b240d --- /dev/null +++ b/views/twig/extensions/themes/admin_twig/user_main.html.twig @@ -0,0 +1,16 @@ +{% extends 'user_main.html.twig' %} + +{% block admin_user_main_form %} + + + + {{ translate({ ident: "OEMODULETEMPLATE_ALLOW_GREETING" }) }} + + + + {% include "inputhelp.html.twig" with {'sHelpId': help_id("OEMODULETEMPLATE_HELP_ALLOW_GREETING"), 'sHelpText': help_text("OEMODULETEMPLATE_HELP_ALLOW_GREETING")} %} + + + + {{ parent() }} +{% endblock %}