├── .codeclimate.yml ├── .github └── workflows │ └── tests.yml ├── .gitignore ├── .php-cs-fixer.dist.php ├── 1.0.0-cms.png ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── SECURITY.md ├── UPGRADE.md ├── actions.phpunit.xml ├── composer.json ├── docker-compose.yml ├── log └── testdox.html ├── phpstan.neon ├── phpunit.xml.dist ├── rector.php ├── src ├── Exception.php ├── LinkConverter.php ├── Menu.php ├── Website.php ├── admin │ ├── Module.php │ ├── apis │ │ ├── AdminController.php │ │ ├── BlockController.php │ │ ├── BlockgroupController.php │ │ ├── LayoutController.php │ │ ├── LogController.php │ │ ├── MenuController.php │ │ ├── NavContainerController.php │ │ ├── NavController.php │ │ ├── NavItemBlockController.php │ │ ├── NavItemController.php │ │ ├── NavItemPageBlockItemController.php │ │ ├── NavItemPageController.php │ │ ├── RedirectController.php │ │ ├── ThemeController.php │ │ └── WebsiteController.php │ ├── assets │ │ └── Main.php │ ├── aws │ │ └── BlockPagesActiveWindow.php │ ├── controllers │ │ ├── BlockController.php │ │ ├── BlockgroupController.php │ │ ├── ConfigController.php │ │ ├── DefaultController.php │ │ ├── LayoutController.php │ │ ├── LogController.php │ │ ├── NavcontainerController.php │ │ ├── PageController.php │ │ ├── PermissionController.php │ │ ├── RedirectController.php │ │ ├── ThemeController.php │ │ └── WebsiteController.php │ ├── helpers │ │ └── MenuHelper.php │ ├── importers │ │ ├── BlockImporter.php │ │ ├── CmslayoutImporter.php │ │ ├── PropertyConsistencyImporter.php │ │ └── ThemeImporter.php │ ├── messages │ │ ├── bg │ │ │ └── cmsadmin.php │ │ ├── cn │ │ │ └── cmsadmin.php │ │ ├── de │ │ │ └── cmsadmin.php │ │ ├── el │ │ │ └── cmsadmin.php │ │ ├── en │ │ │ └── cmsadmin.php │ │ ├── es │ │ │ └── cmsadmin.php │ │ ├── fa │ │ │ └── cmsadmin.php │ │ ├── fr │ │ │ └── cmsadmin.php │ │ ├── hu │ │ │ └── cmsadmin.php │ │ ├── id │ │ │ └── cmsadmin.php │ │ ├── it │ │ │ └── cmsadmin.php │ │ ├── kr │ │ │ └── cmsadmin.php │ │ ├── nl │ │ │ └── cmsadmin.php │ │ ├── pl │ │ │ └── cmsadmin.php │ │ ├── pt │ │ │ └── cmsadmin.php │ │ ├── ru │ │ │ └── cmsadmin.php │ │ ├── th │ │ │ └── cmsadmin.php │ │ ├── tr │ │ │ └── cmsadmin.php │ │ ├── ua │ │ │ └── cmsadmin.php │ │ └── vi │ │ │ └── cmsadmin.php │ ├── migrations │ │ ├── m141203_143052_cms_cat.php │ │ ├── m141203_143059_cms_nav.php │ │ ├── m141203_143111_cms_nav_item.php │ │ ├── m141208_134038_cms_nav_item_page.php │ │ ├── m150106_095003_cms_layout.php │ │ ├── m150108_154017_cms_block.php │ │ ├── m150108_155009_cms_nav_item_page_block_item.php │ │ ├── m150122_125429_cms_nav_item_module.php │ │ ├── m150205_141350_block_group.php │ │ ├── m150924_112309_cms_nav_prop.php │ │ ├── m151012_072207_cms_log.php │ │ ├── m151022_143429_cms_nav_item_redirect.php │ │ ├── m160629_092417_cmspermissiontable.php │ │ ├── m170116_120553_cms_block_variation_field.php │ │ ├── m170218_215610_cms_nav_layout_file.php │ │ ├── m170301_084325_cms_config.php │ │ ├── m170619_103728_cms_blocksettings.php │ │ ├── m171003_065811_add_class_column_to_block_group_table.php │ │ ├── m171121_170909_add_publish_at_date.php │ │ ├── m171206_113949_cms_redirection_table.php │ │ ├── m180723_123237_indexes.php │ │ ├── m190219_142706_og_image.php │ │ ├── m190220_105505_cms_redirect_target_field.php │ │ ├── m190227_123549_cms_nav_item_strict_url_parsing.php │ │ ├── m190529_123549_cms_nav_item_module_route_and_params.php │ │ ├── m190728_084936_cms_theme.php │ │ ├── m200226_211908_nav_item_is_cacheable.php │ │ ├── m200706_202002_cms_website.php │ │ ├── m210605_172811_cms_website_permissions.php │ │ ├── m210708_091145_v4.php │ │ └── m230720_130000_page_link_anchor.php │ ├── resources │ │ ├── dist │ │ │ ├── main.css │ │ │ ├── main.js │ │ │ └── main.unglue │ │ ├── img │ │ │ └── empty-placeholder-arrow.png │ │ ├── js │ │ │ ├── cmsadmin.js │ │ │ └── services.js │ │ └── scss │ │ │ ├── browser-fixes │ │ │ ├── _ie.scss │ │ │ └── _safari.scss │ │ │ ├── cmsadmin.scss │ │ │ ├── components │ │ │ ├── _block-elements.scss │ │ │ ├── _block.scss │ │ │ ├── _blockholder.scss │ │ │ ├── _card.scss │ │ │ ├── _cmsadmin.scss │ │ │ ├── _cmsnav.scss │ │ │ ├── _empty-placeholder.scss │ │ │ ├── _menu-dropdown.scss │ │ │ ├── _toolbar.scss │ │ │ └── _treeview.scss │ │ │ └── variables │ │ │ └── _variables.scss │ └── views │ │ ├── aws │ │ └── blockpages │ │ │ └── index.php │ │ ├── config │ │ └── index.php │ │ ├── default │ │ ├── _angulardirectives.php │ │ └── index.php │ │ ├── page │ │ ├── _navitem.php │ │ ├── _navitem_settings.php │ │ ├── _settings.php │ │ ├── create.php │ │ ├── drafts.php │ │ └── update.php │ │ └── permission │ │ └── index.php ├── base │ ├── BaseBlockInjector.php │ ├── BlockCfg.php │ ├── BlockConfigElement.php │ ├── BlockGroup.php │ ├── BlockInterface.php │ ├── BlockVar.php │ ├── BlockVariationRegister.php │ ├── InternalBaseBlock.php │ ├── NavItemType.php │ ├── NavItemTypeInterface.php │ ├── PhpBlock.php │ ├── PhpBlockInterface.php │ └── PhpBlockView.php ├── behaviours │ └── WebsiteScopeBehavior.php ├── frontend │ ├── Bootstrap.php │ ├── Module.php │ ├── base │ │ └── Controller.php │ ├── blockgroups │ │ ├── DevelopmentGroup.php │ │ ├── LayoutGroup.php │ │ ├── MainGroup.php │ │ ├── MediaGroup.php │ │ ├── ProjectGroup.php │ │ └── TextGroup.php │ ├── blocks │ │ ├── HtmlBlock.php │ │ ├── MirrorLanguageBlock.php │ │ └── ModuleBlock.php │ ├── commands │ │ ├── BlockController.php │ │ ├── PageController.php │ │ └── UpdaterController.php │ ├── components │ │ ├── CatchAllUrlRule.php │ │ ├── RouteBehaviorUrlRule.php │ │ └── WebsiteBehaviorUrlRule.php │ ├── controllers │ │ ├── BlockController.php │ │ ├── DefaultController.php │ │ ├── ErrorController.php │ │ └── PreviewController.php │ ├── events │ │ ├── BeforeRenderEvent.php │ │ └── MenuItemEvent.php │ ├── messages │ │ ├── bg │ │ │ └── cms.php │ │ ├── cn │ │ │ └── cms.php │ │ ├── de │ │ │ └── cms.php │ │ ├── el │ │ │ └── cms.php │ │ ├── en │ │ │ └── cms.php │ │ ├── es │ │ │ └── cms.php │ │ ├── fa │ │ │ └── cms.php │ │ ├── fr │ │ │ └── cms.php │ │ ├── hu │ │ │ └── cms.php │ │ ├── id │ │ │ └── cms.php │ │ ├── it │ │ │ └── cms.php │ │ ├── nl │ │ │ └── cms.php │ │ ├── pl │ │ │ └── cms.php │ │ ├── pt │ │ │ └── cms.php │ │ ├── ru │ │ │ └── cms.php │ │ ├── th │ │ │ └── cms.php │ │ ├── tr │ │ │ └── cms.php │ │ ├── ua │ │ │ └── cms.php │ │ └── vi │ │ │ └── cms.php │ └── views │ │ ├── _toolbar.php │ │ ├── blocks │ │ ├── HtmlBlock.php │ │ └── ModuleBlock.php │ │ ├── commands │ │ └── block │ │ │ ├── create_block.php │ │ │ └── create_block_view.php │ │ ├── error │ │ └── index.php │ │ └── inline │ │ ├── toolbar.css │ │ └── toolbar.js ├── helpers │ ├── BlockHelper.php │ └── Url.php ├── injectors │ ├── ActiveQueryCheckboxInjector.php │ ├── ActiveQueryRadioInjector.php │ ├── ActiveQuerySelectInjector.php │ ├── BaseActiveQueryInjector.php │ ├── LinkInjector.php │ └── TagInjector.php ├── menu │ ├── InjectItem.php │ ├── InjectItemInterface.php │ ├── Item.php │ ├── Query.php │ ├── QueryIterator.php │ ├── QueryIteratorFilter.php │ └── QueryOperatorFieldInterface.php ├── models │ ├── Block.php │ ├── BlockGroup.php │ ├── Config.php │ ├── Layout.php │ ├── Log.php │ ├── Nav.php │ ├── NavContainer.php │ ├── NavItem.php │ ├── NavItemModule.php │ ├── NavItemPage.php │ ├── NavItemPageBlockItem.php │ ├── NavItemRedirect.php │ ├── NavPermission.php │ ├── Property.php │ ├── Redirect.php │ ├── Theme.php │ └── Website.php ├── tags │ ├── AliasTag.php │ ├── MenuTag.php │ └── PageTag.php └── widgets │ ├── LangSwitcher.php │ └── NavTree.php └── tests ├── BlockTestCase.php ├── CmsConsoleTestCase.php ├── CmsFrontendTestCase.php ├── CmsNgRestTestCase.php ├── Dockerfile ├── ModelTestCase.php ├── WebModelTestCase.php ├── data ├── assets │ └── .gitignore ├── blocks │ ├── ConcretImplementationBlock.php │ ├── PhpTestBlock.php │ ├── TestBlock.php │ ├── UnitTestBlock.php │ └── import │ │ └── TestBlock.php ├── cmslayouts │ ├── layoutwithjson.json │ ├── layoutwithjson.php │ └── phplayout.php ├── configs │ └── cms.php ├── env.php ├── fixtures │ └── TagFixture.php ├── images │ └── blocks │ │ └── TestBlock.jpg ├── items │ └── RootItem.php ├── modules │ ├── CmsUnitModule.php │ ├── CmsUrlRuleModule.php │ ├── controllers │ │ ├── DefaultController.php │ │ └── FooController.php │ ├── otherThemes │ │ └── otherTheme │ │ │ └── theme.json │ └── themes │ │ └── testTheme │ │ ├── theme.json │ │ └── views │ │ └── cmslayouts │ │ └── themeLayout.php ├── sql │ ├── 1.0.0-RC1.sql │ ├── 1.0.0-RC2.sql │ ├── 1.0.0-RC3.sql │ ├── 1.0.0-RC4.sql │ ├── 1.0.0-beta7.sql │ ├── 1.0.0-beta8.sql │ ├── 1.0.0.sql │ ├── 3.0.0.sql │ ├── 4.0.0.sql │ └── latest │ │ └── 5.0.0.sql ├── themes │ ├── appTheme │ │ ├── theme.json │ │ └── views │ │ │ └── cmslayouts │ │ │ └── appThemeLayout.php │ └── testTheme │ │ └── theme.json └── views │ ├── blocks │ └── PhpTestBlock.php │ ├── cmslayouts │ └── main.php │ └── layouts │ └── main.php ├── runtime └── .gitkeep └── src ├── LinkConverterTest.php ├── MenuTest.php ├── MessageFileTest.php ├── admin ├── apis │ ├── AdminControllerTest.php │ ├── MenuControllerTest.php │ ├── NavControllerTest.php │ └── NavItemControllerTest.php ├── controllers │ ├── DefaultControllerTest.php │ ├── PageControllerTest.php │ └── PermissionControllerTest.php └── importers │ ├── BlockImporterTest.php │ ├── CmslayoutImporterTest.php │ └── ThemeImporterTest.php ├── base ├── BaseBlockInjectorTest.php ├── BlockPlaceholderIterationTest.php ├── BlockTest.php ├── BlockVariationRegisterTest.php ├── InternalBaseBlockTest.php ├── PhpBlockTest.php └── PhpBlockViewTest.php ├── controllers ├── BlockControllerTest.php.bkp ├── DefaultControllerTest.php └── PreviewControllerTest.php.bkp ├── frontend ├── BootstrapErrorPageTest.php ├── ModuleTest.php ├── blockgroups │ ├── DevelopmentGroupTest.php │ ├── LayoutGroupTest.php │ ├── MainGroupTest.php │ ├── MediaGroupTest.php │ ├── ProjectGroupTest.php │ └── TextGroupTest.php ├── blocks │ ├── HtmlBlockTest.php │ ├── MirrorLanguageBlockTest.php │ └── ModuleBlockTest.php ├── commands │ ├── BlockControllerTest.php │ └── PageControllerTest.php ├── components │ ├── CatchAllUrlRuleTest.php │ └── WebsiteBehaviorUrlRuleTest.php └── controllers │ └── BlockControllerTest.php ├── helpers ├── BlockHelperTest.php └── UrlTest.php ├── injectors ├── ActiveQueryCheckboxInjectorTest.php ├── ActiveQuerySelectInjectorTest.php ├── LinkInjectorTest.php └── TagInjectorTest.php ├── menu ├── InjectItemTest.php ├── ItemSqliteTest.php ├── ItemTest.php ├── QuerySqliteTest.php ├── QueryTest.php └── _dataFrArray.php ├── models ├── BlockGroupTest.php ├── BlockTest.php ├── NavContainerTest.php ├── NavItemModuleTest.php ├── NavItemPageBlockItemTest.php ├── NavItemPageTest.php ├── NavItemTest.php ├── NavTest.php ├── RedirectTest.php └── ThemeTest.php ├── tags ├── MenuTagTest.php └── PageTagTest.php └── widgets ├── LangSwitcherSqliteTest.php ├── LangSwitcherTest.php └── NavTreeTest.php /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | exclude_patterns: 2 | - "src/frontend/messages/**/*.php" 3 | - "src/admin/messages/**/*.php" 4 | - "src/admin/migrations/*.php" 5 | - "src/admin/views/" 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /.php_cs.cache 3 | /.buildpath 4 | /.project 5 | /.settings/ 6 | /phpunit.xml 7 | /luya 8 | node_modules/ 9 | composer.lock 10 | .phpunit.result.cache 11 | /tests/_output/* 12 | .php-cs-fixer.cache 13 | .tmp -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | in(__DIR__) 5 | ; 6 | 7 | $config = new PhpCsFixer\Config(); 8 | return $config->setRules([ 9 | '@PSR12' => true, 10 | 'array_syntax' => ['syntax' => 'short'], 11 | 'ordered_imports' => ['sort_algorithm' => 'alpha'], 12 | 'no_unused_imports' => true, 13 | ]) 14 | ->setFinder($finder) 15 | ; -------------------------------------------------------------------------------- /1.0.0-cms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyadev/luya-module-cms/8a3472acfc2620374fb8de6aed1f2736926cca2b/1.0.0-cms.png -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2014-2018 Zephir Software Design AG. https://luya.io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | LUYA Logo 3 |

4 | 5 | # LUYA Content Management System 6 | 7 | 8 | [![LUYA](https://img.shields.io/badge/Powered%20by-LUYA-brightgreen.svg)](https://luya.io) 9 | ![Tests](https://github.com/luyadev/luya-module-cms/workflows/Tests/badge.svg) 10 | [![Maintainability](https://api.codeclimate.com/v1/badges/17b07525cbb9d23c7b3d/maintainability)](https://codeclimate.com/github/luyadev/luya-module-cms/maintainability) 11 | [![Test Coverage](https://api.codeclimate.com/v1/badges/17b07525cbb9d23c7b3d/test_coverage)](https://codeclimate.com/github/luyadev/luya-module-cms/test_coverage) 12 | [![Latest Stable Version](https://poser.pugx.org/luyadev/luya-module-cms/v/stable)](https://packagist.org/packages/luyadev/luya-module-cms) 13 | [![Total Downloads](https://poser.pugx.org/luyadev/luya-module-cms/downloads)](https://packagist.org/packages/luyadev/luya-module-cms) 14 | 15 | The LUYA CMS module provides a full functional Content Management System for adding contents based on blocks. 16 | 17 | ![LUYA CMS MODULE](https://raw.githubusercontent.com/luyadev/luya/master/docs/images/cms.png) 18 | 19 | To use the LUYA CMS module you have to run a LUYA Application which is provided by the LUYA core. 20 | 21 | For installation and usage please check: [LUYA.IO](https://luya.io) 22 | 23 | ## Installation 24 | 25 | For the installation of modules Composer is required. 26 | 27 | ```sh 28 | composer require luyadev/luya-module-cms 29 | ``` 30 | 31 | ### Configuration 32 | 33 | Add the frontend and admin module of the cms module to your configuration modules section and bootstrap the cms frontend module: 34 | 35 | ```php 36 | 'modules' => [ 37 | // ... 38 | 'cms' => 'luya\cms\frontend\Module', 39 | 'cmsadmin' => 'luya\cms\admin\Module', 40 | // ... 41 | ] 42 | ``` 43 | 44 | 45 | ### Initialization 46 | 47 | After successfully installation and configuration run the migrate, import and setup command to initialize the module in your project. 48 | 49 | 1.) Migrate your database. 50 | 51 | ```sh 52 | ./vendor/bin/luya migrate 53 | ``` 54 | 55 | 2.) Import the module and migrations into your LUYA project. 56 | 57 | ```sh 58 | ./vendor/bin/luya import 59 | ``` 60 | 61 | > Please note that the module names *cms* and *cmsadmin* are required and should not be changed! 62 | 63 | ## Developers 64 | 65 | If you want to contribute, make sure to read the [guidelines](https://luya.io/guide/dev/guideline). 66 | 67 | ## Unit Testing 68 | 69 | 1. `cp phpunit.xml.dist phpunit.xml` 70 | 2. `docker compose up` 71 | 3. `docker compose run luyacmsphpunit tests` to run all tests or `docker compose run luyacmsphpunit tests/src/helpers/UrlTest.php` to run a specific test. 72 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | Please use the email security@luya.io to report to us any security issue you find in LUYA. 4 | DO NOT use the issue tracker or discuss it in the public forum as it will cause more damage than help. 5 | 6 | Please note that as a non-commercial OpenSource project we are not able to pay bounties at the moment. 7 | -------------------------------------------------------------------------------- /actions.phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | 14 | ./tests 15 | 16 | 17 | 18 | 19 | ./vendor 20 | ./tests 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "luyadev/luya-module-cms", 3 | "description": "The LUYA CMS module provides a full functional Content Management System for adding contents based on blocks.", 4 | "type": "luya-core", 5 | "keywords": [ 6 | "php", 7 | "luya", 8 | "module", 9 | "cms", 10 | "yii2", 11 | "yii", 12 | "contentmanager", 13 | "content", 14 | "yii2-cms" 15 | ], 16 | "license": "MIT", 17 | "homepage": "https://luya.io", 18 | "authors": [ 19 | { 20 | "name": "Basil Suter", 21 | "email": "git@nadar.io", 22 | "homepage": "https://github.com/nadar" 23 | } 24 | ], 25 | "support": { 26 | "issues": "https://github.com/luyadev/luya-module-cms/issues" 27 | }, 28 | "require": { 29 | "php": ">=8.0" 30 | }, 31 | "require-dev": { 32 | "luyadev/luya-module-admin": "^5.0.0", 33 | "luyadev/luya-testsuite": "^3.1.4", 34 | "twbs/bootstrap": "^4.3.0", 35 | "unglue/client": "^1.3", 36 | "friendsofphp/php-cs-fixer": "^3.2", 37 | "phpstan/phpstan": "^1.7", 38 | "rector/rector": "^0.14.2" 39 | }, 40 | "autoload": { 41 | "psr-4": { 42 | "luya\\cms\\": "src/" 43 | } 44 | }, 45 | "autoload-dev": { 46 | "psr-4": { 47 | "cmstests\\": "tests/" 48 | } 49 | }, 50 | "config": { 51 | "fxp-asset": { 52 | "enabled": false 53 | }, 54 | "platform": { 55 | "php": "8.0" 56 | }, 57 | "allow-plugins": { 58 | "yiisoft/yii2-composer": true, 59 | "luyadev/luya-composer": true 60 | } 61 | }, 62 | "extra": { 63 | "luya": { 64 | "bootstrap": [ 65 | "\\luya\\cms\\frontend\\Bootstrap" 66 | ], 67 | "blocks": [ 68 | "src{{DS}}frontend{{DS}}blocks" 69 | ] 70 | } 71 | }, 72 | "repositories": [ 73 | { 74 | "type": "composer", 75 | "url": "https://asset-packagist.org" 76 | } 77 | ], 78 | "scripts": { 79 | "phpstan": "vendor/bin/phpstan -v", 80 | "phpcsfixer": "vendor/bin/php-cs-fixer fix", 81 | "rector": "vendor/bin/rector" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | luyacmsdb: 4 | image: mysql:5.7 5 | container_name: luyacmsdb 6 | volumes: 7 | - ./tests/data/sql/latest:/docker-entrypoint-initdb.d 8 | command: 9 | - --character-set-server=utf8 10 | - --collation-server=utf8_general_ci 11 | environment: 12 | MYSQL_ROOT_PASSWORD: luyacms 13 | MYSQL_DATABASE: luyacms 14 | MYSQL_USER: luyacms 15 | MYSQL_PASSWORD: luyacms 16 | 17 | luyacmscomposer: 18 | image: composer:latest 19 | volumes: 20 | - ./:/app 21 | command: composer install 22 | 23 | luyacmsphpunit: 24 | build: 'tests/' 25 | entrypoint: vendor/bin/phpunit 26 | volumes: 27 | - .:/app 28 | working_dir: /app 29 | 30 | luyacmsrector: 31 | image: php:8.0-cli 32 | entrypoint: vendor/bin/rector 33 | volumes: 34 | - .:/app 35 | working_dir: /app 36 | 37 | -------------------------------------------------------------------------------- /log/testdox.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 0 3 | paths: 4 | - src 5 | bootstrapFiles: 6 | - vendor/yiisoft/yii2/Yii.php 7 | tmpDir: .tmp -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | 14 | ./tests 15 | 16 | 17 | 18 | 19 | ./vendor 20 | ./tests 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /rector.php: -------------------------------------------------------------------------------- 1 | paths([ 11 | __DIR__ . '/src' 12 | ]); 13 | 14 | // register a single rule 15 | $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class); 16 | 17 | // define sets of rules 18 | $rectorConfig->sets([ 19 | LevelSetList::UP_TO_PHP_80 20 | ]); 21 | 22 | $rectorConfig->skip([ 23 | __DIR__ . '/src/base/BlockInterface.php' 24 | ]); 25 | }; 26 | -------------------------------------------------------------------------------- /src/Exception.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0.0 10 | */ 11 | class Exception extends \luya\Exception 12 | { 13 | /** 14 | * @return string the user-friendly name of this exception 15 | */ 16 | public function getName() 17 | { 18 | return 'CMS-Module Exception'; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/admin/apis/BlockController.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 1.0.0 12 | */ 13 | class BlockController extends \luya\admin\ngrest\base\Api 14 | { 15 | public $modelClass = 'luya\cms\models\Block'; 16 | 17 | public function actionToFav() 18 | { 19 | $block = Yii::$app->request->getBodyParam('block'); 20 | 21 | if (!empty($block)) { 22 | return Yii::$app->adminuser->identity->setting->set("blockfav.{$block['id']}", $block); 23 | } 24 | } 25 | 26 | public function actionRemoveFav() 27 | { 28 | $block = Yii::$app->request->getBodyParam('block'); 29 | 30 | if (!empty($block)) { 31 | return Yii::$app->adminuser->identity->setting->remove("blockfav.{$block['id']}"); 32 | } 33 | } 34 | 35 | public function actionToggleGroup() 36 | { 37 | $group = Yii::$app->request->getBodyParam('group'); 38 | 39 | if (!empty($group)) { 40 | return Yii::$app->adminuser->identity->setting->set("togglegroup.{$group['id']}", (int) $group['toggle_open']); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/admin/apis/BlockgroupController.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0.0 10 | */ 11 | class BlockgroupController extends \luya\admin\ngrest\base\Api 12 | { 13 | public $modelClass = 'luya\cms\models\BlockGroup'; 14 | } 15 | -------------------------------------------------------------------------------- /src/admin/apis/LayoutController.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0.0 10 | */ 11 | class LayoutController extends \luya\admin\ngrest\base\Api 12 | { 13 | public $modelClass = 'luya\cms\models\Layout'; 14 | } 15 | -------------------------------------------------------------------------------- /src/admin/apis/LogController.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0.0 10 | */ 11 | class NavContainerController extends \luya\admin\ngrest\base\Api 12 | { 13 | public $modelClass = 'luya\cms\models\NavContainer'; 14 | } 15 | -------------------------------------------------------------------------------- /src/admin/apis/NavItemBlockController.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0.0 13 | */ 14 | class NavItemBlockController extends \luya\admin\base\RestController 15 | { 16 | /** 17 | * Copy all attached sub blocks (referencing sourceId) into new context and update prevId to sourceId 18 | * 19 | * @param $sourceId 20 | * @param $targetPrevId 21 | * @param $targetNavItemPageId 22 | */ 23 | private function copySubBlocksTo($sourceId, $targetPrevId, $targetNavItemPageId) 24 | { 25 | if ($sourceId) { 26 | $subBlocks = NavItemPageBlockItem::findAll(['prev_id' => $sourceId]); 27 | foreach ($subBlocks as $block) { 28 | $newBlock = new NavItemPageBlockItem(); 29 | $newBlock->attributes = $block->toArray(); 30 | $newBlock->nav_item_page_id = $targetNavItemPageId; 31 | $newBlock->prev_id = $targetPrevId; 32 | $newBlock->insert(); 33 | 34 | // check for attached sub blocks and start recursion 35 | $attachedBlocks = NavItemPageBlockItem::findAll(['prev_id' => $block->id]); 36 | if ($attachedBlocks) { 37 | $this->copySubBlocksTo($block->id, $newBlock->id, $targetNavItemPageId); 38 | } 39 | } 40 | } 41 | } 42 | 43 | public function actionCopyBlockFromStack() 44 | { 45 | $model = NavItemPageBlockItem::findOne((int) Yii::$app->request->getBodyParam('copyBlockId', 0)); 46 | 47 | if (($model) && ((Yii::$app->request->getBodyParam('copyBlockId', 0) !== Yii::$app->request->getBodyParam('prev_id', false)))) { 48 | $newModel = new NavItemPageBlockItem(); 49 | $newModel->attributes = $model->toArray(); 50 | $newModel->is_dirty = true; 51 | $newModel->prev_id = Yii::$app->request->getBodyParam('prev_id', false); 52 | $newModel->placeholder_var = Yii::$app->request->getBodyParam('placeholder_var', false); 53 | $newModel->sort_index = Yii::$app->request->getBodyParam('sort_index', false); 54 | $newModel->nav_item_page_id = Yii::$app->request->getBodyParam('nav_item_page_id', false); 55 | 56 | if ($newModel->insert()) { 57 | $this->copySubBlocksTo(Yii::$app->request->getBodyParam('copyBlockId', false), $newModel->id, $newModel->nav_item_page_id); 58 | return ['response' => true]; 59 | } 60 | } 61 | 62 | return ['response' => false]; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/admin/apis/NavItemPageBlockItemController.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 1.0.0 12 | */ 13 | class NavItemPageBlockItemController extends RestActiveController 14 | { 15 | public $modelClass = 'luya\cms\models\NavItemPageBlockItem'; 16 | } 17 | -------------------------------------------------------------------------------- /src/admin/apis/NavItemPageController.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0.1 13 | */ 14 | class NavItemPageController extends RestActiveController 15 | { 16 | public $modelClass = 'luya\cms\models\NavItemPage'; 17 | 18 | /** 19 | * Returns all versions/pages for a given navItemId 20 | * 21 | * @param $navItemId 22 | * @return array 23 | */ 24 | public function actionVersions($navItemId) 25 | { 26 | return NavItemPage::find()->where(['nav_item_id' => $navItemId])->asArray()->all(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/admin/apis/RedirectController.php: -------------------------------------------------------------------------------- 1 | request->pathInfo 24 | * 25 | * url: https://example.com/hello/world 26 | * path: hello/world 27 | * 28 | * @param string $path The path to check inside the redirect list. 29 | * @since 1.0.9 30 | */ 31 | public function actionCatch($path) 32 | { 33 | $compositePath = Yii::$app->composition->prependTo($path); 34 | foreach (Redirect::find()->all() as $redirect) { 35 | if ($redirect->matchRequestPath($path)) { 36 | return $redirect; 37 | } 38 | 39 | // if its a multi linguage website and the language has not been omited form request path compare this version too. 40 | // this is requred since the luya UrlManager can change the pathInfo 41 | if ($path !== $compositePath) { 42 | if ($redirect->matchRequestPath($compositePath)) { 43 | return $redirect; 44 | } 45 | } 46 | } 47 | 48 | return false; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/admin/apis/ThemeController.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 3.0.0 12 | */ 13 | class ThemeController extends \luya\admin\ngrest\base\Api 14 | { 15 | public $modelClass = 'luya\cms\models\Theme'; 16 | } 17 | -------------------------------------------------------------------------------- /src/admin/apis/WebsiteController.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 4.0.0 12 | */ 13 | class WebsiteController extends \luya\admin\ngrest\base\Api 14 | { 15 | public $modelClass = 'luya\cms\models\Website'; 16 | } 17 | -------------------------------------------------------------------------------- /src/admin/assets/Main.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0.0 10 | */ 11 | class Main extends \yii\web\AssetBundle 12 | { 13 | /** 14 | * @inheritdoc 15 | */ 16 | public $sourcePath = '@cmsadmin/resources'; 17 | 18 | /** 19 | * @inheritdoc 20 | */ 21 | public $js = [ 22 | 'dist/main.js' 23 | ]; 24 | 25 | /** 26 | * @inheritdoc 27 | */ 28 | public $css = [ 29 | 'dist/main.css', 30 | ]; 31 | 32 | /** 33 | * @inheritdoc 34 | */ 35 | public $depends = [ 36 | 'luya\admin\assets\Main', 37 | ]; 38 | 39 | /** 40 | * @inheritdoc 41 | */ 42 | public $publishOptions = [ 43 | 'except' => [ 44 | 'node_modules/', 45 | ] 46 | ]; 47 | } 48 | -------------------------------------------------------------------------------- /src/admin/aws/BlockPagesActiveWindow.php: -------------------------------------------------------------------------------- 1 | model->translationName; 43 | } 44 | 45 | /** 46 | * The default action which is going to be requested when clicking the ActiveWindow. 47 | * 48 | * @return string The response string, render and displayed trough the angular ajax request. 49 | */ 50 | public function index() 51 | { 52 | return $this->render('index', [ 53 | 'blocks' => $this->model->getNavItemPageBlockItems() 54 | ->select(['nav_item_page_id', 'is_hidden', 'title']) 55 | ->with(['navItemPage.forceNavItem.lang', 'navItemPage.forceNavItem.nav']) 56 | ->joinWith(['navItemPage.forceNavItem']) 57 | ->distinct() 58 | ->orderBy(['title' => SORT_ASC]) 59 | ->all(), 60 | ]); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/admin/controllers/BlockController.php: -------------------------------------------------------------------------------- 1 | 13 | * @since 1.0.0 14 | */ 15 | class BlockController extends Controller 16 | { 17 | public $modelClass = 'luya\cms\models\Block'; 18 | 19 | /** 20 | * Generate the the block preview. 21 | * 22 | * @param int $blockId 23 | * @return string 24 | * @throws NotFoundHttpException 25 | * @since 1.0.8 26 | */ 27 | public function actionPreview($blockId) 28 | { 29 | $blockItem = Block::findOne($blockId); 30 | if (!$blockItem) { 31 | throw new NotFoundHttpException(); 32 | } 33 | 34 | /** @var $blockObject \luya\cms\base\InternalBaseBlock */ 35 | $blockObject = $blockItem->getObject('preview', 'admin-preview'); 36 | 37 | return $blockObject->renderAdminPreview(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/admin/controllers/BlockgroupController.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 1.0.0 12 | */ 13 | class BlockgroupController extends Controller 14 | { 15 | public $modelClass = 'luya\cms\models\BlockGroup'; 16 | } 17 | -------------------------------------------------------------------------------- /src/admin/controllers/ConfigController.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 1.0.0 12 | */ 13 | class ConfigController extends Controller 14 | { 15 | public function actionIndex() 16 | { 17 | return $this->render('index'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/admin/controllers/DefaultController.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 1.0.0 12 | */ 13 | class DefaultController extends Controller 14 | { 15 | public function actionIndex() 16 | { 17 | return $this->render('index'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/admin/controllers/LayoutController.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 1.0.0 12 | */ 13 | class LayoutController extends Controller 14 | { 15 | public $modelClass = 'luya\cms\models\Layout'; 16 | } 17 | -------------------------------------------------------------------------------- /src/admin/controllers/LogController.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 1.0.0 12 | */ 13 | class NavcontainerController extends Controller 14 | { 15 | public $modelClass = 'luya\cms\models\NavContainer'; 16 | } 17 | -------------------------------------------------------------------------------- /src/admin/controllers/PageController.php: -------------------------------------------------------------------------------- 1 | 15 | * @since 1.0.0 16 | */ 17 | class PageController extends Controller 18 | { 19 | public function actionCreate() 20 | { 21 | return $this->render('create'); 22 | } 23 | 24 | public function actionUpdate() 25 | { 26 | return $this->render('update', [ 27 | 'canBlockUpdate' => Yii::$app->auth->matchApi(Yii::$app->adminuser->id, 'api-cms-navitempageblockitem', Auth::CAN_UPDATE), 28 | 'canBlockDelete' => Yii::$app->auth->matchApi(Yii::$app->adminuser->id, 'api-cms-navitempageblockitem', Auth::CAN_DELETE), 29 | 'canBlockCreate' => Yii::$app->auth->matchApi(Yii::$app->adminuser->id, 'api-cms-navitempageblockitem', Auth::CAN_CREATE), 30 | ]); 31 | } 32 | 33 | public function actionDrafts() 34 | { 35 | return $this->render('drafts'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/admin/controllers/PermissionController.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 1.0.0 12 | */ 13 | class PermissionController extends Controller 14 | { 15 | public function actionIndex() 16 | { 17 | return $this->render('index'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/admin/controllers/RedirectController.php: -------------------------------------------------------------------------------- 1 | 13 | * @since 3.0.0 14 | */ 15 | class ThemeController extends Controller 16 | { 17 | public $modelClass = 'luya\cms\models\Theme'; 18 | } 19 | -------------------------------------------------------------------------------- /src/admin/controllers/WebsiteController.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 4.0.0 12 | */ 13 | class WebsiteController extends Controller 14 | { 15 | public $modelClass = 'luya\cms\models\Website'; 16 | } 17 | -------------------------------------------------------------------------------- /src/admin/importers/PropertyConsistencyImporter.php: -------------------------------------------------------------------------------- 1 | 13 | * @since 1.0.0 14 | */ 15 | class PropertyConsistencyImporter extends Importer 16 | { 17 | public $queueListPosition = self::QUEUE_POSITION_LAST; 18 | 19 | public function run() 20 | { 21 | foreach (CmsProperty::find()->all() as $cmsPropertyModel) { 22 | $adminProperty = AdminProperty::findOne($cmsPropertyModel->admin_prop_id); 23 | if (!$adminProperty) { 24 | $cmsPropertyModel->delete(); 25 | $this->addLog('Old property values has been removed due to not existing property object.'); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/admin/migrations/m141203_143052_cms_cat.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class m141203_143052_cms_cat extends Migration 14 | { 15 | public function safeUp() 16 | { 17 | $this->createTable('cms_nav_container', [ 18 | 'id' => $this->primaryKey(), 19 | 'name' => $this->string(180)->notNull(), 20 | 'alias' => $this->string(180)->notNull(), 21 | 'is_deleted' => $this->boolean()->defaultValue(false), 22 | ]); 23 | } 24 | 25 | public function safeDown() 26 | { 27 | $this->dropTable('cms_nav_container'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/admin/migrations/m141203_143059_cms_nav.php: -------------------------------------------------------------------------------- 1 | createTable('cms_nav', [ 10 | 'id' => $this->primaryKey(), 11 | 'nav_container_id' => $this->integer(11)->notNull(), 12 | 'parent_nav_id' => $this->integer(11)->notNull(), 13 | 'sort_index' => $this->integer(11)->notNull(), 14 | 'is_deleted' => $this->boolean()->defaultValue(false), 15 | 'is_hidden' => $this->boolean()->defaultValue(false), 16 | 'is_home' => $this->boolean()->defaultValue(false), 17 | 'is_offline' => $this->boolean()->defaultValue(false), 18 | 'is_draft' => $this->boolean()->defaultValue(false), 19 | ]); 20 | } 21 | 22 | public function safeDown() 23 | { 24 | $this->dropTable('cms_nav'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/admin/migrations/m141203_143111_cms_nav_item.php: -------------------------------------------------------------------------------- 1 | createTable('cms_nav_item', [ 11 | 'id' => $this->primaryKey(), 12 | 'nav_id' => $this->integer(11)->notNull(), 13 | 'lang_id' => $this->integer(11)->notNull(), 14 | 'nav_item_type' => $this->integer(11)->notNull(), 15 | 'nav_item_type_id' => $this->integer(11)->notNull(), 16 | 'create_user_id' => $this->integer(11)->notNull(), 17 | 'update_user_id' => $this->integer(11)->notNull(), 18 | 'timestamp_create' => $this->integer(11)->defaultValue(0), 19 | 'timestamp_update' => $this->integer(11)->defaultValue(0), 20 | 'title' => $this->string(180)->notNull(), 21 | 'alias' => $this->string(80)->notNull(), 22 | 'description' => $this->text(), 23 | 'keywords' => $this->text(), 24 | 'title_tag' => $this->string(255), 25 | ]); 26 | } 27 | 28 | public function safeDown() 29 | { 30 | $this->dropTable('cms_nav_item'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/admin/migrations/m141208_134038_cms_nav_item_page.php: -------------------------------------------------------------------------------- 1 | createTable('cms_nav_item_page', [ 11 | 'id' => $this->primaryKey(), 12 | 'layout_id' => $this->integer(11)->notNull(), 13 | 'nav_item_id' => $this->integer(11)->notNull(), 14 | 'timestamp_create' => $this->integer(11)->notNull(), 15 | 'create_user_id' => $this->integer(11)->notNull(), 16 | 'version_alias' => $this->string(250), 17 | ]); 18 | } 19 | 20 | public function safeDown() 21 | { 22 | $this->dropTable('cms_nav_item_page'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/admin/migrations/m150106_095003_cms_layout.php: -------------------------------------------------------------------------------- 1 | createTable('cms_layout', [ 11 | 'id' => $this->primaryKey(), 12 | 'name' => $this->string(255), 13 | 'json_config' => $this->text(), 14 | 'view_file' => $this->string(255), 15 | ]); 16 | } 17 | 18 | public function safeDown() 19 | { 20 | $this->dropTable('cms_layout'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/admin/migrations/m150108_154017_cms_block.php: -------------------------------------------------------------------------------- 1 | createTable('cms_block', [ 11 | 'id' => $this->primaryKey(), 12 | 'group_id' => $this->integer(11)->notNull(), 13 | 'class' => $this->string(255)->notNull(), 14 | ]); 15 | } 16 | 17 | public function safeDown() 18 | { 19 | $this->dropTable('cms_block'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/admin/migrations/m150108_155009_cms_nav_item_page_block_item.php: -------------------------------------------------------------------------------- 1 | createTable('cms_nav_item_page_block_item', [ 11 | 'id' => $this->primaryKey(), 12 | 'block_id' => $this->integer(11)->notNull(), 13 | 'placeholder_var' => $this->string(80)->notNull(), 14 | 'nav_item_page_id' => $this->integer(11), 15 | 'prev_id' => $this->integer(11), 16 | 'json_config_values' => $this->text(), 17 | 'json_config_cfg_values' => $this->text(), 18 | 'is_dirty' => $this->boolean()->defaultValue(false), 19 | 'create_user_id' => $this->integer(11)->defaultValue(0), 20 | 'update_user_id' => $this->integer(11)->defaultValue(0), 21 | 'timestamp_create' => $this->integer(11)->defaultValue(0), 22 | 'timestamp_update' => $this->integer(11)->defaultValue(0), 23 | 'sort_index' => $this->integer(11)->defaultValue(0), 24 | 'is_hidden' => $this->boolean()->defaultValue(false), 25 | ]); 26 | } 27 | 28 | public function safeDown() 29 | { 30 | $this->dropTable('cms_nav_item_page_block_item'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/admin/migrations/m150122_125429_cms_nav_item_module.php: -------------------------------------------------------------------------------- 1 | createTable('cms_nav_item_module', [ 11 | 'id' => $this->primaryKey(), 12 | 'module_name' => $this->string(255)->notNull(), 13 | ]); 14 | } 15 | 16 | public function safeDown() 17 | { 18 | $this->dropTable('cms_nav_item_module'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/admin/migrations/m150205_141350_block_group.php: -------------------------------------------------------------------------------- 1 | createTable('cms_block_group', [ 11 | 'id' => $this->primaryKey(), 12 | 'name' => $this->string(255)->notNull(), 13 | 'is_deleted' => $this->boolean()->defaultValue(false), 14 | 'identifier' => $this->string(120)->notNull(), 15 | 'created_timestamp' => $this->integer(11)->defaultValue(0), 16 | ]); 17 | } 18 | 19 | public function safeDown() 20 | { 21 | $this->dropTable('cms_block_group'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/admin/migrations/m150924_112309_cms_nav_prop.php: -------------------------------------------------------------------------------- 1 | createTable('cms_nav_property', [ 10 | 'id' => $this->primaryKey(), 11 | 'nav_id' => $this->integer(11)->notNull(), 12 | 'admin_prop_id' => $this->integer(11)->notNull(), 13 | 'value' => $this->text(), 14 | ]); 15 | } 16 | 17 | public function safeDown() 18 | { 19 | $this->dropTable('cms_nav_property'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/admin/migrations/m151012_072207_cms_log.php: -------------------------------------------------------------------------------- 1 | createTable('cms_log', [ 10 | 'id' => $this->primaryKey(), 11 | 'user_id' => $this->integer()->defaultValue(0), 12 | 'is_insertion' => $this->boolean()->defaultValue(false), 13 | 'is_update' => $this->boolean()->defaultValue(false), 14 | 'is_deletion' => $this->boolean()->defaultValue(false), 15 | 'timestamp' => $this->integer(11)->notNull(), 16 | 'message' => $this->string(255), 17 | 'data_json' => $this->text(), 18 | 'table_name' => $this->string(120), 19 | 'row_id' => $this->integer(11)->defaultValue(0), 20 | ]); 21 | } 22 | 23 | public function safeDown() 24 | { 25 | $this->dropTable('cms_log'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/admin/migrations/m151022_143429_cms_nav_item_redirect.php: -------------------------------------------------------------------------------- 1 | createTable('cms_nav_item_redirect', [ 10 | 'id' => $this->primaryKey(), 11 | 'type' => $this->integer(11)->notNull(), 12 | 'value' => $this->string(255)->notNull(), 13 | ]); 14 | } 15 | 16 | public function safeDown() 17 | { 18 | $this->dropTable('cms_nav_item_redirect'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/admin/migrations/m160629_092417_cmspermissiontable.php: -------------------------------------------------------------------------------- 1 | createTable('cms_nav_permission', [ 10 | 'group_id' => $this->integer(11)->notNull(), 11 | 'nav_id' => $this->integer(11)->notNull(), 12 | 'inheritance' => $this->boolean()->defaultValue(false), 13 | ]); 14 | } 15 | 16 | public function safeDown() 17 | { 18 | $this->dropTable('cms_nav_permission'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/admin/migrations/m170116_120553_cms_block_variation_field.php: -------------------------------------------------------------------------------- 1 | addColumn('cms_nav_item_page_block_item', 'variation', $this->string(255)->defaultValue(0)); 10 | } 11 | 12 | public function safeDown() 13 | { 14 | $this->dropColumn('cms_nav_item_page_block_item', 'variation'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/admin/migrations/m170218_215610_cms_nav_layout_file.php: -------------------------------------------------------------------------------- 1 | addColumn('cms_nav', 'layout_file', $this->string()); 11 | } 12 | 13 | public function safeDown() 14 | { 15 | $this->dropColumn('cms_nav', 'layout_file'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/admin/migrations/m170301_084325_cms_config.php: -------------------------------------------------------------------------------- 1 | createTable('cms_config', [ 11 | 'name' => $this->string(80), 12 | 'value' => $this->string(255)->notNull(), 13 | 'PRIMARY KEY(name)', 14 | ]); 15 | } 16 | 17 | public function safeDown() 18 | { 19 | $this->dropTable('cms_config'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/admin/migrations/m170619_103728_cms_blocksettings.php: -------------------------------------------------------------------------------- 1 | addColumn('cms_block', 'is_disabled', $this->boolean()->defaultValue(false)); 10 | } 11 | 12 | public function safeDown() 13 | { 14 | $this->dropColumn('cms_block', 'is_disabled'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/admin/migrations/m171003_065811_add_class_column_to_block_group_table.php: -------------------------------------------------------------------------------- 1 | addColumn('cms_block_group', 'class', $this->string()->notNull()->defaultValue(null)); // default value supports upgrading and sync from previous system.s 16 | } 17 | 18 | /** 19 | * @inheritdoc 20 | */ 21 | public function safeDown() 22 | { 23 | $this->dropColumn('cms_block_group', 'class'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/admin/migrations/m171121_170909_add_publish_at_date.php: -------------------------------------------------------------------------------- 1 | addColumn('cms_nav', 'publish_from', $this->integer()->null()); 10 | $this->addColumn('cms_nav', 'publish_till', $this->integer()->null()); 11 | } 12 | 13 | public function safeDown() 14 | { 15 | $this->dropColumn('cms_nav', 'publish_from'); 16 | $this->dropColumn('cms_nav', 'publish_till'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/admin/migrations/m171206_113949_cms_redirection_table.php: -------------------------------------------------------------------------------- 1 | createTable('cms_redirect', [ 16 | 'id' => $this->primaryKey(), 17 | 'timestamp_create' => $this->integer(), 18 | 'catch_path' => $this->string()->notNull(), 19 | 'redirect_path' => $this->string()->notNull(), 20 | 'redirect_status_code' => $this->integer()->notNull(), 21 | ]); 22 | } 23 | 24 | /** 25 | * @inheritdoc 26 | */ 27 | public function safeDown() 28 | { 29 | $this->dropTable('cms_redirect'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/admin/migrations/m190219_142706_og_image.php: -------------------------------------------------------------------------------- 1 | addColumn('cms_nav_item', 'image_id', $this->integer()); 16 | } 17 | 18 | /** 19 | * {@inheritdoc} 20 | */ 21 | public function safeDown() 22 | { 23 | $this->dropColumn('cms_nav_item', 'image_id'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/admin/migrations/m190220_105505_cms_redirect_target_field.php: -------------------------------------------------------------------------------- 1 | addColumn('cms_nav_item_redirect', 'target', $this->string()); 16 | } 17 | 18 | /** 19 | * {@inheritdoc} 20 | */ 21 | public function safeDown() 22 | { 23 | $this->dropColumn('cms_nav_item_redirect', 'target'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/admin/migrations/m190227_123549_cms_nav_item_strict_url_parsing.php: -------------------------------------------------------------------------------- 1 | addColumn('cms_nav_item', 'is_url_strict_parsing_disabled', $this->boolean()->defaultValue(false)); 16 | } 17 | 18 | /** 19 | * {@inheritdoc} 20 | */ 21 | public function safeDown() 22 | { 23 | $this->dropColumn('cms_nav_item', 'is_url_strict_parsing_disabled'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/admin/migrations/m190529_123549_cms_nav_item_module_route_and_params.php: -------------------------------------------------------------------------------- 1 | addColumn('cms_nav_item_module', 'controller_name', $this->string()); 16 | $this->addColumn('cms_nav_item_module', 'action_name', $this->string()); 17 | $this->addColumn('cms_nav_item_module', 'action_params', $this->text()); 18 | } 19 | 20 | /** 21 | * {@inheritdoc} 22 | */ 23 | public function safeDown() 24 | { 25 | $this->dropColumn('cms_nav_item_module', 'controller_name'); 26 | $this->dropColumn('cms_nav_item_module', 'action_name'); 27 | $this->dropColumn('cms_nav_item_module', 'action_params'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/admin/migrations/m190728_084936_cms_theme.php: -------------------------------------------------------------------------------- 1 | createTable('cms_theme', [ 13 | 'id' => $this->primaryKey(), 14 | 'is_active' => $this->boolean()->defaultValue(false), 15 | 'base_path' => $this->string(191)->notNull()->unique(), 16 | 'json_config' => $this->text()->notNull(), 17 | ]); 18 | } 19 | 20 | public function safeDown() 21 | { 22 | $this->dropTable('cms_theme'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/admin/migrations/m200226_211908_nav_item_is_cacheable.php: -------------------------------------------------------------------------------- 1 | addColumn('cms_nav_item', 'is_cacheable', $this->boolean()->defaultValue(false)); 16 | } 17 | 18 | /** 19 | * {@inheritdoc} 20 | */ 21 | public function safeDown() 22 | { 23 | $this->dropColumn('cms_nav_item', 'is_cacheable'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/admin/migrations/m200706_202002_cms_website.php: -------------------------------------------------------------------------------- 1 | createTable('cms_website', [ 16 | 'id' => $this->primaryKey(), 17 | 'name' => $this->string(120)->unique()->notNull(), 18 | 'is_default' => $this->boolean()->notNull()->defaultValue(false), 19 | 'is_active' => $this->boolean()->notNull()->defaultValue(false), 20 | 'is_deleted' => $this->boolean()->notNull()->defaultValue(false), 21 | 'host' => $this->string(191)->unique()->notNull(), 22 | 'aliases' => $this->string(255)->null()->defaultValue(null), 23 | 'redirect_to_host' => $this->boolean()->notNull()->defaultValue(false), 24 | 'theme_id' => $this->integer()->defaultValue(null), 25 | 'default_lang' => $this->string(2)->defaultValue(null), 26 | ]); 27 | 28 | $this->insert('cms_website', [ 29 | 'id' => 1, 30 | 'name' => 'default', 31 | 'is_default' => true, 32 | 'is_active' => true, 33 | 'host' => '', 34 | 'theme_id' => $this->db->createCommand('SELECT id FROM cms_theme WHERE is_active = 1')->queryScalar() ?: null 35 | ]); 36 | 37 | $this->addColumn('cms_nav_container', 'website_id', $this->integer()->notNull()->defaultValue(1)->after('id')); 38 | 39 | $this->alterColumn('cms_nav', 'parent_nav_id', $this->integer(11)->notNull()->defaultValue(0)); 40 | 41 | $this->alterColumn('cms_nav_item_page', 'nav_item_id', $this->integer(11)->defaultValue(null)); 42 | $this->update('cms_nav_item_page', ['nav_item_id' => 0], ['nav_item_id' => null]); 43 | 44 | // $this->alterColumn('cms_nav', 'parent_nav_id', $this->integer(11)->defaultValue(null)); 45 | // $this->update('cms_nav', ['parent_nav_id' => null], ['parent_nav_id' => 0]); 46 | 47 | $this->renameColumn('cms_theme', 'is_active', 'is_default'); 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function safeDown() 54 | { 55 | $this->dropColumn('cms_nav_container', 'website_id'); 56 | $this->dropTable('cms_website'); 57 | $this->renameColumn('cms_theme', 'is_default', 'is_active'); 58 | 59 | return true; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/admin/migrations/m210605_172811_cms_website_permissions.php: -------------------------------------------------------------------------------- 1 | addColumn(Website::tableName(), 'group_ids', $this->text()); 17 | $this->addColumn(Website::tableName(), 'user_ids', $this->text()); 18 | 19 | $this->update(Website::tableName(), [ 20 | 'group_ids' => '[{"value":0}]', 21 | 'user_ids' => '[{"value":0}]', 22 | ]); 23 | } 24 | 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | public function safeDown() 29 | { 30 | $this->dropColumn(Website::tableName(), 'group_ids'); 31 | $this->dropColumn(Website::tableName(), 'user_ids'); 32 | 33 | return true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/admin/migrations/m210708_091145_v4.php: -------------------------------------------------------------------------------- 1 | addColumn('cms_nav_item_page', 'timestamp_update', $this->integer()); 16 | $this->alterColumn('cms_nav_item', 'alias', $this->string(180)->notNull()); 17 | } 18 | 19 | /** 20 | * {@inheritdoc} 21 | */ 22 | public function safeDown() 23 | { 24 | $this->dropColumn('cms_nav_item_page', 'timestamp_update'); 25 | $this->alterColumn('cms_nav_item', 'alias', $this->string(80)->notNull()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/admin/migrations/m230720_130000_page_link_anchor.php: -------------------------------------------------------------------------------- 1 | addColumn(NavItemRedirect::tableName(), 'anchor', $this->string()); 17 | } 18 | 19 | /** 20 | * {@inheritdoc} 21 | */ 22 | public function safeDown() 23 | { 24 | $this->dropColumn(NavItemRedirect::tableName(), 'anchor'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/admin/resources/dist/main.unglue: -------------------------------------------------------------------------------- 1 | { 2 | "js" : [ 3 | "../js/cmsadmin.js", 4 | "../js/services.js" 5 | ], 6 | "css": [ 7 | "../scss/cmsadmin.scss" 8 | ], 9 | "options": { 10 | "compress" : false, 11 | "maps" : true 12 | } 13 | } -------------------------------------------------------------------------------- /src/admin/resources/img/empty-placeholder-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyadev/luya-module-cms/8a3472acfc2620374fb8de6aed1f2736926cca2b/src/admin/resources/img/empty-placeholder-arrow.png -------------------------------------------------------------------------------- /src/admin/resources/scss/browser-fixes/_ie.scss: -------------------------------------------------------------------------------- 1 | // Internet Explorer 2 | 3 | // IE 10 4 | body[class*='internet-explorer-'] { 5 | 6 | /** 7 | * ==================== 8 | * Block 9 | * ==================== 10 | */ 11 | 12 | .block-toolbar { 13 | display: none; 14 | } 15 | 16 | .block:hover > .block-toolbar, 17 | .block-is-layout > .block-toolbar, 18 | .block-is-layout:hover > .block-toolbar { 19 | display: flex; 20 | } 21 | 22 | .cmsadmin-frame { 23 | height: calc(100vh - 25px); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/admin/resources/scss/browser-fixes/_safari.scss: -------------------------------------------------------------------------------- 1 | body[class*='safari'] { 2 | } -------------------------------------------------------------------------------- /src/admin/resources/scss/cmsadmin.scss: -------------------------------------------------------------------------------- 1 | // ================================================== 2 | // Include Bootstrap Mixins / Functions 3 | // ================================================== 4 | 5 | @import "../../../../vendor/twbs/bootstrap/scss/mixins/clearfix"; 6 | @import "../../../../vendor/twbs/bootstrap/scss/functions"; 7 | 8 | // ================================================== 9 | // Variables 10 | // ================================================== 11 | 12 | @import "../../../../vendor/luyadev/luya-module-admin/src/resources/scss/variables/colors"; 13 | @import "../../../../vendor/luyadev/luya-module-admin/src/resources/scss/variables/bootstrap"; 14 | @import "../../../../vendor/luyadev/luya-module-admin/src/resources/scss/variables/custom"; 15 | @import "../../../../vendor/luyadev/luya-module-admin/src/resources/scss/variables/flags"; 16 | @import "../../../../vendor/luyadev/luya-module-admin/src/resources/scss/variables/zindex"; 17 | 18 | // ================================================== 19 | // Include Bootstrap variables 20 | // ================================================== 21 | 22 | @import "../../../../vendor/twbs/bootstrap/scss/variables"; 23 | 24 | // ================================================== 25 | // Helpers 26 | // ================================================== 27 | 28 | @import "../../../../vendor/luyadev/luya-module-admin/src/resources/scss/helpers/google-chrome-font-offset-fix"; 29 | @import "../../../../vendor/luyadev/luya-module-admin/src/resources/scss/helpers/zindex"; 30 | 31 | 32 | // ================================================== 33 | // Variables 34 | // ================================================== 35 | 36 | @import "variables/variables"; 37 | 38 | // ================================================== 39 | // Components 40 | // ================================================== 41 | 42 | @import "components/block"; 43 | @import "components/block-elements"; 44 | @import "components/blockholder"; 45 | @import "components/card"; 46 | @import "components/cmsadmin"; 47 | @import "components/cmsnav"; 48 | @import "components/empty-placeholder"; 49 | @import "components/menu-dropdown"; 50 | @import "components/toolbar"; 51 | @import "components/treeview"; 52 | 53 | // ================================================== 54 | // Browser fixes – always last cause they suck balls 55 | // ================================================== 56 | 57 | @import "browser-fixes/ie"; 58 | @import "browser-fixes/safari"; 59 | -------------------------------------------------------------------------------- /src/admin/resources/scss/components/_block-elements.scss: -------------------------------------------------------------------------------- 1 | .block-front { 2 | 3 | h1, h2, h3, h4, h5 { 4 | color: $black; 5 | } 6 | 7 | > *:last-of-type { 8 | margin-bottom: 0; 9 | } 10 | 11 | table { 12 | margin: 0; 13 | 14 | td > p:first-of-type:last-of-type, 15 | th > p:first-of-type:last-of-type { 16 | margin: 0; 17 | } 18 | } 19 | 20 | hr { 21 | margin-bottom: 1rem !important; 22 | margin-top: 1rem !important; 23 | } 24 | 25 | img { 26 | max-width: 100%; 27 | width: auto; 28 | } 29 | 30 | blockquote { 31 | background-color: map-get($grays, 100); 32 | border-left: 3px solid theme-color(primary); 33 | display: block; 34 | padding: 15px; 35 | position: relative; 36 | width: 100%; 37 | 38 | p { 39 | font-family: $font-family-sans-serif; 40 | font-style: italic; 41 | margin: 0; 42 | position: relative; 43 | text-indent: 40px; 44 | 45 | &:before { 46 | color: theme-color(primary); 47 | content: '\201C'; 48 | font-size: 70px; 49 | font-weight: 700; 50 | left: 0; 51 | line-height: 0; 52 | position: absolute; 53 | text-indent: 0; 54 | text-shadow: 3px 7px 5px rgba(0, 0, 0, 0.1); 55 | top: 20px; 56 | } 57 | } 58 | } 59 | 60 | iframe { 61 | max-width: 100%; 62 | } 63 | 64 | .iframe-container { 65 | height: 0; 66 | margin: 0; 67 | overflow: hidden; 68 | padding-bottom: 56.25%; /* ratio 16x9 */ 69 | pointer-events: none; 70 | position: relative; 71 | width: 100%; 72 | 73 | iframe { 74 | height: 100%; 75 | left: 0; 76 | position: absolute; 77 | top: 0; 78 | width: 100%; 79 | } 80 | } 81 | 82 | } -------------------------------------------------------------------------------- /src/admin/resources/scss/components/_card.scss: -------------------------------------------------------------------------------- 1 | // Extend default bootstrap card behaviour 2 | 3 | .card-no-container-title { 4 | .block-front .row:not(:first-of-type) & { 5 | margin-top: 5px; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/admin/resources/scss/components/_cmsnav.scss: -------------------------------------------------------------------------------- 1 | .cmsnav { 2 | display: block; 3 | margin-bottom: 10px; 4 | width: 100%; 5 | } 6 | 7 | // ================================================== 8 | // General lists 9 | // ================================================== 10 | 11 | .cmsnav-list { 12 | display: block; 13 | list-style: none; 14 | margin: 0; 15 | padding: 0; 16 | 17 | &:not(:first-of-type) { 18 | margin-top: 15px; 19 | } 20 | } 21 | 22 | // ================================================== 23 | // Buttons 24 | // ================================================== 25 | 26 | .cmsnav-button:not(:first-of-type) { 27 | margin-top: 5px; 28 | } 29 | 30 | // ================================================== 31 | // Switches 32 | // ================================================== 33 | 34 | 35 | 36 | // ================================================== 37 | // Treeview 38 | // ================================================== 39 | 40 | .cmsnav-treeview { 41 | display: block; 42 | } -------------------------------------------------------------------------------- /src/admin/resources/scss/components/_empty-placeholder.scss: -------------------------------------------------------------------------------- 1 | .empty-placeholder { 2 | padding: 10px; 3 | text-align: center; 4 | 5 | &--drag-hover { 6 | background-color: theme-color(primary); 7 | color: $white; 8 | } 9 | } -------------------------------------------------------------------------------- /src/admin/resources/scss/components/_menu-dropdown.scss: -------------------------------------------------------------------------------- 1 | .menu-dropdown { 2 | clear: both; 3 | display: block; 4 | padding-top: 10px; 5 | 6 | .form-side > & { 7 | padding-top: 0; 8 | } 9 | } 10 | 11 | .menu-dropdown-toggle-all { 12 | font-size: 14px; 13 | cursor: pointer; 14 | 15 | i { 16 | font-size: 24px; 17 | } 18 | } -------------------------------------------------------------------------------- /src/admin/resources/scss/components/_toolbar.scss: -------------------------------------------------------------------------------- 1 | .toolbar-item { 2 | flex: 0 0 auto; 3 | padding: 0 20px; 4 | 5 | &:first-of-type { 6 | padding-left: 0; 7 | } 8 | &-lang + .toolbar-item:not(.toolbar-item-lang) { 9 | border-left: 1px solid $nav-tabs-border-color; 10 | } 11 | 12 | &:last-of-type { 13 | padding-right: 0; 14 | } 15 | 16 | &-lang { 17 | padding: 5px 10px; 18 | } 19 | } -------------------------------------------------------------------------------- /src/admin/resources/scss/variables/_variables.scss: -------------------------------------------------------------------------------- 1 | $block-border-width: 1px !default; 2 | $block-border-color: map-get($grays, 500) !default; 3 | $block-padding: 10px !default; 4 | 5 | $blockholder-width: 255px; 6 | $blockholder-width-small: 48px; -------------------------------------------------------------------------------- /src/admin/views/aws/blockpages/index.php: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
28 | 29 | navItemPage->forceNavItem->nav->is_hidden ? 'visibility_off' : 'visibility'; ?> 30 | 31 | 32 | 33 | navItemPage->forceNavItem->nav->is_offline ? 'cloud_off' : 'cloud_queue'; ?> 34 | 35 | 36 | navItemPage->forceNavItem->title; ?> 37 | navItemPage->forceNavItem->lang->name; ?>navItemPage->version_alias; ?>formatter->asBoolean(!$block->is_hidden); ?>formatter->asDate($block->navItemPage->forceNavItem->timestamp_update); ?>formatter->asDate($block->navItemPage->forceNavItem->timestamp_create); ?>
-------------------------------------------------------------------------------- /src/admin/views/config/index.php: -------------------------------------------------------------------------------- 1 | 5 |

6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 |
-------------------------------------------------------------------------------- /src/admin/views/page/create.php: -------------------------------------------------------------------------------- 1 | 5 |
6 |

7 | 8 |
-------------------------------------------------------------------------------- /src/admin/views/page/drafts.php: -------------------------------------------------------------------------------- 1 | 5 |

6 |

7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 |
{{item.title}} 19 |
21 |
22 |
-------------------------------------------------------------------------------- /src/base/BlockCfg.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0.0 10 | */ 11 | class BlockCfg extends BlockConfigElement 12 | { 13 | public function toArray() 14 | { 15 | return [ 16 | 'id' => $this->id, 17 | 'var' => $this->item['var'], 18 | 'label' => $this->item['label'], 19 | 'type' => $this->item['type'], 20 | 'placeholder' => $this->get('placeholder'), 21 | 'options' => $this->get('options'), 22 | 'initvalue' => $this->get('initvalue'), 23 | 'required' => $this->get('required', 0), 24 | ]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/base/BlockConfigElement.php: -------------------------------------------------------------------------------- 1 | 17 | * @since 1.0.0 18 | */ 19 | abstract class BlockConfigElement 20 | { 21 | protected $id; 22 | 23 | /** 24 | * 25 | * @param array $item The element config with all fields. 26 | * @throws Exception 27 | */ 28 | public function __construct(public array $item) 29 | { 30 | if (!$this->has(['var', 'label', 'type'])) { 31 | throw new Exception('Required attributes in config var element is missing. var, label and type are required.'); 32 | } 33 | $this->id = md5($this->get('var').uniqid()); 34 | } 35 | 36 | /** 37 | * Has the config element an element or not. 38 | * 39 | * @param string $key 40 | * @return boolean 41 | */ 42 | protected function has($key) 43 | { 44 | if (!is_array($key)) { 45 | return (array_key_exists($key, $this->item)); 46 | } 47 | 48 | foreach ($key as $value) { 49 | if (!array_key_exists($value, $this->item)) { 50 | return false; 51 | } 52 | } 53 | 54 | return true; 55 | } 56 | 57 | /** 58 | * Get the element value. 59 | * 60 | * @param string $key 61 | * @return string 62 | */ 63 | protected function get($key, mixed $default = null) 64 | { 65 | if (!$this->has($key)) { 66 | return $default; 67 | } 68 | 69 | return $this->item[$key]; 70 | } 71 | 72 | /** 73 | * Extract the data from the element. 74 | * 75 | * @return array 76 | */ 77 | abstract public function toArray(); 78 | } 79 | -------------------------------------------------------------------------------- /src/base/BlockGroup.php: -------------------------------------------------------------------------------- 1 | 15 | * @since 1.0.0 16 | */ 17 | abstract class BlockGroup extends BaseObject 18 | { 19 | /** 20 | * The unique identifier of the block group 21 | * 22 | * @return string 23 | */ 24 | abstract public function identifier(); 25 | 26 | /** 27 | * The label used in the administration are for this group 28 | * 29 | * @return string 30 | */ 31 | abstract public function label(); 32 | 33 | /** 34 | * The position index, lower will be a the top, higher will be at the bottom of the blocks list. 35 | * 36 | * Endless Numbers are available. 37 | * 38 | * @return number The number for sort position in the administration area. 0 = Top, 100 = Bottom. 39 | */ 40 | public function getPosition() 41 | { 42 | return 50; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/base/BlockVar.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0.0 10 | */ 11 | class BlockVar extends BlockConfigElement 12 | { 13 | public function toArray() 14 | { 15 | return [ 16 | 'id' => $this->id, 17 | 'var' => $this->item['var'], 18 | 'label' => $this->item['label'], 19 | 'type' => $this->item['type'], 20 | 'placeholder' => $this->get('placeholder'), 21 | 'options' => $this->get('options'), 22 | 'initvalue' => $this->get('initvalue'), 23 | 'required' => $this->get('required', 0), 24 | ]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/base/NavItemType.php: -------------------------------------------------------------------------------- 1 | 17 | * @since 1.0.0 18 | */ 19 | abstract class NavItemType extends ActiveRecord implements NavItemTypeInterface 20 | { 21 | /** 22 | * Get the response content for the item type 23 | * 24 | * @return mixed 25 | */ 26 | abstract public function getContent(); 27 | 28 | /** 29 | * Get the corresponding nav item type for this type object 30 | * 31 | * @return NavItem An active record type. 32 | */ 33 | public function getNavItem() 34 | { 35 | return $this->hasOne(NavItem::class, ['nav_item_type_id' => 'id'])->where(['nav_item_type' => static::getNummericType()]); 36 | } 37 | 38 | /** 39 | * Context properts array. 40 | * 41 | * @return array 42 | */ 43 | public function getContextPropertysArray() 44 | { 45 | return []; // override 46 | } 47 | 48 | private $_controller; 49 | 50 | /** 51 | * Setter method to store the current controller Object 52 | * @param Controller $controller The controller object. 53 | */ 54 | public function setController(Controller $controller) 55 | { 56 | $this->_controller = $controller; 57 | } 58 | 59 | /** 60 | * Getter method for the controller object. 61 | * 62 | * @return Controller 63 | */ 64 | public function getController() 65 | { 66 | return $this->_controller; 67 | } 68 | 69 | private array $_options = []; 70 | 71 | /** 72 | * Setter method for options. 73 | */ 74 | public function setOptions(array $options) 75 | { 76 | $this->_options = $options; 77 | } 78 | 79 | /** 80 | * Getter method for options. 81 | * @return array 82 | */ 83 | public function getOptions() 84 | { 85 | return $this->_options; 86 | } 87 | 88 | /** 89 | * Get a specific option value for a defined eky. 90 | * 91 | * @param string $key The array key to lookup inside the $options array. 92 | * @return boolean|mixed 93 | */ 94 | public function getOption($key) 95 | { 96 | return $this->_options[$key] ?? false; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/base/NavItemTypeInterface.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0.0 10 | */ 11 | interface NavItemTypeInterface 12 | { 13 | /** 14 | * Returns the databas-nummeric identifier to make the navItem relation. 15 | * 16 | * @return integer The numeric identifier for the type (1=page, 2=module, 3=redirect, ...) 17 | */ 18 | public static function getNummericType(); 19 | } 20 | -------------------------------------------------------------------------------- /src/base/PhpBlockInterface.php: -------------------------------------------------------------------------------- 1 | 9 | * @since 1.0.0 10 | */ 11 | interface PhpBlockInterface 12 | { 13 | public function frontend(); 14 | 15 | public function admin(); 16 | } 17 | -------------------------------------------------------------------------------- /src/behaviours/WebsiteScopeBehavior.php: -------------------------------------------------------------------------------- 1 | 'initEvent', 15 | ]; 16 | } 17 | 18 | public function initEvent(Event $event) 19 | { 20 | /** @var NgRestActiveQuery $query */ 21 | $query = $event->sender; 22 | $query->andWhere(['website_id' => Yii::$app->website->current['id']]); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/frontend/blockgroups/DevelopmentGroup.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0.0 13 | */ 14 | class DevelopmentGroup extends BlockGroup 15 | { 16 | public function identifier() 17 | { 18 | return 'development-group'; 19 | } 20 | 21 | public function label() 22 | { 23 | return Module::t('block_group_dev_elements'); 24 | } 25 | 26 | public function getPosition() 27 | { 28 | return 90; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/frontend/blockgroups/LayoutGroup.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0.0 13 | */ 14 | class LayoutGroup extends BlockGroup 15 | { 16 | public function identifier() 17 | { 18 | return 'layout-group'; 19 | } 20 | 21 | public function label() 22 | { 23 | return Module::t('block_group_layout_elements'); 24 | } 25 | 26 | public function getPosition() 27 | { 28 | return 67; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/frontend/blockgroups/MainGroup.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 1.0.0 15 | */ 16 | class MainGroup extends BlockGroup 17 | { 18 | public function identifier() 19 | { 20 | return 'main-group'; 21 | } 22 | 23 | public function label() 24 | { 25 | return Module::t('block_group_basic_elements'); 26 | } 27 | 28 | public function getPosition() 29 | { 30 | return 66; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/frontend/blockgroups/MediaGroup.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0.0 13 | */ 14 | class MediaGroup extends BlockGroup 15 | { 16 | public function identifier() 17 | { 18 | return 'media-group'; 19 | } 20 | 21 | public function label() 22 | { 23 | return Module::t('block_group_media_group'); 24 | } 25 | 26 | public function getPosition() 27 | { 28 | return 62; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/frontend/blockgroups/ProjectGroup.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 1.0.0 15 | */ 16 | class ProjectGroup extends BlockGroup 17 | { 18 | public function identifier() 19 | { 20 | return 'project-group'; 21 | } 22 | 23 | public function label() 24 | { 25 | return Module::t('block_group_project_elements'); 26 | } 27 | 28 | public function getPosition() 29 | { 30 | return 64; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/frontend/blockgroups/TextGroup.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 1.0.0 15 | */ 16 | class TextGroup extends BlockGroup 17 | { 18 | public function identifier() 19 | { 20 | return 'text-group'; 21 | } 22 | 23 | public function label() 24 | { 25 | return Module::t('block_group_text_elements'); 26 | } 27 | 28 | public function getPosition() 29 | { 30 | return 60; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/frontend/blocks/HtmlBlock.php: -------------------------------------------------------------------------------- 1 | 13 | * @since 1.0.0 14 | */ 15 | final class HtmlBlock extends PhpBlock 16 | { 17 | /** 18 | * @inheritdoc 19 | */ 20 | public $module = 'cms'; 21 | 22 | /** 23 | * @inheritdoc 24 | */ 25 | public $cacheEnabled = true; 26 | 27 | /** 28 | * @inheritdoc 29 | */ 30 | public function blockGroup() 31 | { 32 | return DevelopmentGroup::class; 33 | } 34 | 35 | /** 36 | * @inheritdoc 37 | */ 38 | public function name() 39 | { 40 | return Module::t('block_html_name'); 41 | } 42 | 43 | /** 44 | * @inheritdoc 45 | */ 46 | public function icon() 47 | { 48 | return 'code'; 49 | } 50 | 51 | /** 52 | * @inheritdoc 53 | */ 54 | public function config() 55 | { 56 | return [ 57 | 'vars' => [ 58 | ['var' => 'html', 'label' => Module::t('block_html_html_label'), 'type' => self::TYPE_TEXTAREA], 59 | ], 60 | 'cfgs' => [ 61 | ['var' => 'raw', 'label' => Module::t('block_html_cfg_raw_label'), 'type' => self::TYPE_CHECKBOX] 62 | ], 63 | ]; 64 | } 65 | 66 | /** 67 | * @inheritdoc 68 | */ 69 | public function admin() 70 | { 71 | $message = Module::t('block_html_no_content'); 72 | return <<{$message}{% else %} 75 | {% if cfgs.raw == 1 %} 76 | {{ vars.html | raw }} 77 | {% else %} 78 | {{ vars.html | escape }} 79 | {% endif %} 80 | {% endif %} 81 | EOT; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/frontend/components/CatchAllUrlRule.php: -------------------------------------------------------------------------------- 1 | 17 | * @since 1.0.0 18 | */ 19 | class CatchAllUrlRule extends UrlRule 20 | { 21 | /** 22 | * @inheritdoc 23 | */ 24 | public $pattern = ''; 25 | 26 | /** 27 | * @inheritdoc 28 | */ 29 | public $route = 'cms/default/index'; 30 | 31 | /** 32 | * @inheritdoc 33 | */ 34 | public $encodeParams = false; 35 | 36 | /** 37 | * @inheritdoc 38 | */ 39 | public function parseRequest($manager, $request) 40 | { 41 | // add trace info 42 | Yii::info('LUYA-CMS CatchAllUrlRule is parsing the Request for path info \'' . $request->pathInfo .'\'', __METHOD__); 43 | 44 | $pathInfo = $request->pathInfo; 45 | 46 | // if no path is given, the route should not apply. 47 | if (empty($pathInfo)) { 48 | return false; 49 | } 50 | 51 | // if there is a trailing slash given, the request is invalid as long as the urlManager suffix 52 | // does not contain a trailing slash. 53 | if (rtrim($pathInfo, '//') !== $pathInfo && !str_ends_with($manager->suffix, '/')) { 54 | return false; 55 | } 56 | 57 | // return the custom route 58 | return [$this->route, ['path' => $request->pathInfo]]; 59 | } 60 | 61 | /** 62 | * @inheritdoc 63 | */ 64 | public function createUrl($manager, $route, $params) 65 | { 66 | if (ltrim($route, '/') !== $this->route) { 67 | $this->createStatus = self::CREATE_STATUS_ROUTE_MISMATCH; 68 | return false; 69 | } 70 | 71 | if (!isset($params['path']) || empty($params['path'])) { 72 | $this->createStatus = self::CREATE_STATUS_PARAMS_MISMATCH; 73 | return false; 74 | } 75 | 76 | $path = ArrayHelper::remove($params, 'path'); 77 | 78 | if (empty($params)) { 79 | return $path; 80 | } 81 | 82 | return $path .'?'.http_build_query($params); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/frontend/components/RouteBehaviorUrlRule.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 1.0.0 15 | */ 16 | class RouteBehaviorUrlRule extends UrlRule 17 | { 18 | /** 19 | * @inheritdoc 20 | */ 21 | public $pattern = '//'; 22 | 23 | /** 24 | * @inheritdoc 25 | */ 26 | public $route = '//'; 27 | 28 | /** 29 | * @inheritdoc 30 | */ 31 | public $defaults = ['controller' => 'default', 'action' => 'index']; 32 | 33 | /** 34 | * @inheritdoc 35 | */ 36 | public $mode = UrlRule::PARSING_ONLY; 37 | 38 | /** 39 | * @inheritdoc 40 | */ 41 | public function parseRequest($manager, $request) 42 | { 43 | // return route in parts where key 0 should be the module assuming routed strings. 44 | $parts = explode("/", $request->pathInfo); 45 | 46 | // if there is no key 0, the module does not exists in module list or the module name is cms, its an invalid request. 47 | if (!isset($parts[0]) || !Yii::$app->hasModule($parts[0]) || $parts[0] === 'cms') { 48 | return false; 49 | } 50 | 51 | // add trace info 52 | Yii::info('LUYA-CMS RouteBehaviorUrlRule is parsing the Request for path info \'' . $request->pathInfo .'\'', __METHOD__); 53 | 54 | return parent::parseRequest($manager, $request); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/frontend/components/WebsiteBehaviorUrlRule.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 4.0.0 17 | */ 18 | class WebsiteBehaviorUrlRule extends UrlRule 19 | { 20 | /** 21 | * @inheritdoc 22 | */ 23 | public $pattern = '//'; 24 | 25 | /** 26 | * @inheritdoc 27 | */ 28 | public $route = '//'; 29 | 30 | /** 31 | * @inheritdoc 32 | */ 33 | public $defaults = ['controller' => 'default', 'action' => 'index']; 34 | 35 | /** 36 | * @inheritdoc 37 | */ 38 | public $mode = UrlRule::PARSING_ONLY; 39 | 40 | /** 41 | * @inheritdoc 42 | */ 43 | public function parseRequest($manager, $request) 44 | { 45 | $matchedWebsite = Yii::$app->website->findOneByHostName($request->hostName); 46 | if (boolval($matchedWebsite['redirect_to_host']) && $matchedWebsite['host'] !== $request->hostName) { 47 | $request->setHostInfo($matchedWebsite['host']); 48 | throw new UrlNormalizerRedirectException(Url::to($request->getAbsoluteUrl()), 301); 49 | } 50 | 51 | return false; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/frontend/controllers/BlockController.php: -------------------------------------------------------------------------------- 1 | 18 | * @since 1.0.0 19 | */ 20 | class BlockController extends Controller 21 | { 22 | /** 23 | * @inheritdoc 24 | */ 25 | public $enableCsrfValidation = false; 26 | 27 | /** 28 | * Run the callback for a given block. 29 | * 30 | * @param string $callback The name of the callback to call inside the block object. 31 | * @param integer $id The id of the block item where the callbacke is located. 32 | * @throws \luya\cms\Exception 33 | * @return mixed 34 | */ 35 | public function actionIndex($callback, $id) 36 | { 37 | $model = NavItemPageBlockItem::findOne($id); 38 | 39 | if (!$model) { 40 | throw new Exception("Unable to find item id."); 41 | } 42 | 43 | $block = $model->block->getObject($model->id, 'callback'); 44 | 45 | if (!$block) { 46 | throw new Exception("Unable to find block object."); 47 | } 48 | 49 | return ObjectHelper::callMethodSanitizeArguments($block, $this->callbackToMethod($callback), Yii::$app->request->get()); 50 | } 51 | 52 | /** 53 | * Ensure the callback method from a given name. 54 | * 55 | * The callback method must start with 'callback'. 56 | * 57 | * @param string $callbackName The name of the callback, like `my-action` 58 | * @return string Convert the callbackname to `callbackMyAction` 59 | */ 60 | protected function callbackToMethod($callbackName) 61 | { 62 | if (!StringHelper::startsWith($callbackName, 'callback')) { 63 | return 'callback' . Inflector::id2camel($callbackName); 64 | } 65 | 66 | return lcfirst(Inflector::id2camel($callbackName)); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/frontend/controllers/ErrorController.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 1.0.0 12 | */ 13 | class ErrorController extends \luya\web\Controller 14 | { 15 | public function actionIndex() 16 | { 17 | return $this->renderPartial($this->module->errorViewFile, [ 18 | 'exception' => Yii::$app->errorHandler->exception 19 | ]); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/frontend/controllers/PreviewController.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 1.0.0 17 | */ 18 | class PreviewController extends Controller 19 | { 20 | /** 21 | * Renders the preview action. 22 | * 23 | * @param integer $itemId The nav item to render. 24 | * @param integer $version The version to display. 25 | * @param integer $date The date from the preview frame, is false when not using the preview frame from the cms. 26 | * @throws ForbiddenHttpException 27 | * @throws NotFoundHttpException 28 | */ 29 | public function actionIndex($itemId, $version = false, $date = false): \yii\web\Response|string 30 | { 31 | if (Yii::$app->adminuser->isGuest) { 32 | throw new ForbiddenHttpException('Unable to see the preview page, session expired or not logged in.'); 33 | } 34 | 35 | $navItem = NavItem::findOne($itemId); 36 | 37 | if (!$navItem) { 38 | throw new NotFoundHttpException("The requested nav item with id {$itemId} does not exist."); 39 | } 40 | 41 | $langShortCode = $navItem->lang->short_code; 42 | 43 | Yii::$app->composition['langShortCode'] = $langShortCode; 44 | 45 | $item = Yii::$app->menu->find()->where(['id' => $itemId])->with('hidden')->lang($langShortCode)->one(); 46 | 47 | if ($item && !$date && $navItem->nav_item_type_id == $version) { 48 | return $this->redirect($item->link); 49 | } 50 | 51 | // this item is still offline so we have to inject and fake it with the inject api 52 | if (!$item) { 53 | // create new item to inject 54 | $inject = new InjectItem([ 55 | 'id' => $itemId, 56 | 'navId' => $navItem->nav->id, 57 | 'childOf' => Yii::$app->menu->home->id, 58 | 'title' => $navItem->title, 59 | 'alias' => $navItem->alias, 60 | 'isHidden' => true, 61 | ]); 62 | // inject item into menu component 63 | Yii::$app->menu->injectItem($inject); 64 | // find the inject menu item 65 | $item = Yii::$app->menu->find()->where(['id' => $inject->id])->with('hidden')->lang($langShortCode)->one(); 66 | // something really went wrong while finding injected item 67 | if (!$item) { 68 | throw new NotFoundHttpException("Unable to find the preview for this ID, maybe the page is still Offline?"); 69 | } 70 | } 71 | 72 | // set the current item, as it would be resolved wrong from the url manager / request path 73 | Yii::$app->menu->current = $item; 74 | 75 | return $this->renderContent($this->renderItem($itemId, null, $version)); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/frontend/events/BeforeRenderEvent.php: -------------------------------------------------------------------------------- 1 | 11 | * @since 1.0.0 12 | */ 13 | class BeforeRenderEvent extends \yii\base\Event 14 | { 15 | /** 16 | * @var boolean Whether current request is valid or not, if $isValid is false an {{MethodNotAllowedHttpException}} will 17 | * be thrown while rendering. 18 | */ 19 | public $isValid = true; 20 | 21 | /** 22 | * @var \luya\cms\menu\Item The current menu item resolved from {{luya\cms\Menu::getCurrent()}}. 23 | */ 24 | public $menu; 25 | } 26 | -------------------------------------------------------------------------------- /src/frontend/events/MenuItemEvent.php: -------------------------------------------------------------------------------- 1 | [ 15 | * 'class' => 'luya\cms\Menu', 16 | * 'on eventOnItemFind' => function(MenuItemEvent $event) { 17 | * if ($event->item->alias == 'this-is-my-alias') { 18 | * // will turn this item to invisble 19 | * $event->visible = false; 20 | * } 21 | * } 22 | * ], 23 | * ``` 24 | * 25 | * @property integer $visible Menu item visibility getter/setter. 26 | * 27 | * @author Basil Suter 28 | * @since 1.0.0 29 | */ 30 | class MenuItemEvent extends \yii\base\Event 31 | { 32 | /** 33 | * @var Item 34 | */ 35 | public $item; 36 | 37 | /** 38 | * Whether the item is visible or not 39 | * 40 | * @return boolean 41 | */ 42 | public function getVisible() 43 | { 44 | return !$this->item->isHidden; 45 | } 46 | 47 | /** 48 | * Setter method for the item visibility 49 | * 50 | * @param integer $state 51 | */ 52 | public function setVisible($state) 53 | { 54 | $this->item->isHidden = !$state; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/frontend/messages/cn/cms.php: -------------------------------------------------------------------------------- 1 | '语言', 5 | 'tb_properties' => '属性', 6 | 'tb_seo' => 'SEO搜索优化', 7 | 'tb_seo_title' => '标题', 8 | 'tb_seo_description' => '描述', 9 | 'tb_seo_description_notfound' => '当前页面没有添加描述.', 10 | 'tb_seo_link' => 'URL链接', 11 | 'tb_seo_keywords' => '关键字', 12 | 'tb_seo_keywords_notfound' => '未找到关键字.您应该添加关键字来分析您的内容.', 13 | 'tb_seo_warning' => '您的某些关键字在您的内容中找不到,您应该通过更改关键字或将缺少的关键字添加到内容来解决这个问题。', 14 | 'tb_edit_alt' => '在CMS管理中编辑此页面', 15 | 'tb_visible_not_alt' => '这个网页对访客不可见', 16 | 'tb_visible_alt' => '这个页面对访问者是可见的', 17 | 'block_html_html_label' => 'HTML代码', 18 | 'block_html_no_content' => '没有添加HTML代码。', 19 | 'block_module_name' => '模块', 20 | 'block_module_modulename_label' => '模块名称', 21 | 'block_module_modulecontroller_label' => '控制器名称(不带controller后缀)', 22 | 'block_module_moduleaction_label' => '动作名称(不带action前缀)', 23 | 'block_module_moduleactionargs_label' => '动作参数(json: {"var":"value"})', 24 | 'block_module_no_module' => '尚未指定模块。', 25 | 'block_module_integration' => '模块整合', 26 | 'block_html_name' => 'HTML', 27 | 'block_module_modulename_help' => '只列出在配置文件中注册的前端模块。', 28 | 'block_group_dev_elements' => '高级', 29 | 'block_group_layout_elements' => '布局', 30 | 'block_group_basic_elements' => '基础', 31 | 'block_group_project_elements' => '开发', 32 | 'block_group_text_elements' => '文本', 33 | 'block_group_media_group' => '媒体', 34 | 35 | // 1.0.0 36 | 'block_module_strictrender' => '严格渲染', 37 | 'block_module_strictrender_help' => '当严格渲染被启用时,模块将只运行提供的路由(模块,控制器,动作,参数)而不监听动作和控制器路由。', 38 | 'block_html_cfg_raw_label' => '在Admin中渲染HTML', 39 | 40 | // 3.4.0 41 | 'tag_alias_readme' => 'The alias tag allows you to use aliases defined in your application as well as predefined aliases. As an example, you can use `alias[@web]` to link to images in the public html folder: ``', 42 | 'tag_menu_readme' => 'Generate a link to a menu item where the key is the page id (you can see the page ids when hovering over the site navigation in the administration).', 43 | 'tag_page_readme' => 'Get the content of a full page or of a placeholder of a page. The first parameter is the page id (which you get by hovering over the site navigation in the administration): `page[1]`. If you only want to get the content of a placeholder of the cmslayout, use the second parameter: `page[1](placeholderName)`.', 44 | 'block_mirror_language_name' => 'Mirror Language', 45 | 'block_mirror_config_language_label' => 'Source Language', 46 | 'block_mirror_admin_empty_language' => 'Configure a edit source language to mirror its content for the current placeholder.', 47 | 'block_mirror_admin_configured_language' => 'Mirroring this placeholder from arrow_right_alt {name}.', 48 | ]; 49 | -------------------------------------------------------------------------------- /src/frontend/views/blocks/HtmlBlock.php: -------------------------------------------------------------------------------- 1 | 6 | varValue('html'); ?> -------------------------------------------------------------------------------- /src/frontend/views/blocks/ModuleBlock.php: -------------------------------------------------------------------------------- 1 | 6 | extraValue('moduleContent');?> -------------------------------------------------------------------------------- /src/frontend/views/commands/block/create_block_view.php: -------------------------------------------------------------------------------- 1 | 4 | /** 5 | * View file for block: 6 | * 7 | * 8 | * 9 | 10 | * @param 11 | 12 | 13 | * 14 | * @var \luya\cms\base\PhpBlockView $this 15 | */ 16 | ?> 17 | -------------------------------------------------------------------------------- /src/frontend/views/error/index.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 23 | 24 | 25 |
26 |
27 |
28 |
29 | 30 |

getMessage()); ?> 31 |

32 |

Error statusCode; ?>

33 |

34 | 35 |
36 |

The above error occurred while the Web server was processing your request.

37 |

Please contact us if you think this is a server error. Thank you.

38 |
39 |
40 |
41 |
42 |
43 | 44 | 45 | -------------------------------------------------------------------------------- /src/injectors/ActiveQueryCheckboxInjector.php: -------------------------------------------------------------------------------- 1 | \newsadmin\models\Article::find()->where(['cat_id' => 1]), 19 | * 'label' => 'title', // This attribute from the model is used to render the admin block dropdown selection. 20 | * ]); 21 | * ``` 22 | * 23 | * In order to configure the ActiveQueryCheckboxInjector used the {{\luya\cms\base\InternalBaseBlock::injectors}} method: 24 | * 25 | * ```php 26 | * public function injectors() 27 | * { 28 | * return [ 29 | * 'theData' => new ActiveQueryCheckboxInjector([ 30 | * 'query' => News::find()->where(['is_deleted' => 0]), 31 | * 'label' => function($model) { 32 | * return $model->title . " - " . $model->description; 33 | * }, 34 | * ]); 35 | * ]; 36 | * } 37 | * ``` 38 | * 39 | * @property \yii\db\ActiveQueryInterface $query The ActiveQuery object 40 | * 41 | * @author Basil Suter 42 | * @since 1.0.0 43 | */ 44 | final class ActiveQueryCheckboxInjector extends BaseActiveQueryInjector 45 | { 46 | /** 47 | * @inheritdoc 48 | */ 49 | public function setup() 50 | { 51 | // injecto the config 52 | $this->setContextConfig([ 53 | 'var' => $this->varName, 54 | 'type' => TypesInterface::TYPE_CHECKBOX_ARRAY, 55 | 'label' => $this->varLabel, 56 | 'options' => [ 57 | 'items' => $this->getQueryData(), 58 | ], 59 | ]); 60 | // provide the extra data 61 | $this->context->addExtraVar($this->varName, $this->getExtraAssignArrayData()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/injectors/ActiveQueryRadioInjector.php: -------------------------------------------------------------------------------- 1 | \newsadmin\models\Article::find()->where(['cat_id' => 1]), 18 | * 'label' => 'title', // This attribute from the model is used to render the admin block dropdown selection. 19 | * ]); 20 | * ``` 21 | * 22 | * In order to configure the ActiveQueryRadioInjector used the {{\luya\cms\base\InternalBaseBlock::injectors}} method: 23 | * 24 | * ```php 25 | * public function injectors() 26 | * { 27 | * return [ 28 | * 'theData' => new ActiveQueryRadioInjector([ 29 | * 'query' => News::find()->where(['is_deleted' => 0]), 30 | * 'label' => function($model) { 31 | * return $model->title . " - " . $model->description; 32 | * }, 33 | * ]); 34 | * ]; 35 | * } 36 | * ``` 37 | * 38 | * @property \yii\db\ActiveQueryInterface $query The ActiveQuery object 39 | * 40 | * @author Basil Suter 41 | * @since 1.0.0 42 | */ 43 | final class ActiveQueryRadioInjector extends BaseActiveQueryInjector 44 | { 45 | /** 46 | * @inheritdoc 47 | */ 48 | public function setup() 49 | { 50 | // injecto the config 51 | $this->setContextConfig([ 52 | 'var' => $this->varName, 53 | 'type' => TypesInterface::TYPE_RADIO, 54 | 'label' => $this->varLabel, 55 | 'options' => $this->getQueryData(), 56 | ]); 57 | // provide the extra data 58 | $this->context->addExtraVar($this->varName, $this->getExtraAssignSingleData()); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/injectors/ActiveQuerySelectInjector.php: -------------------------------------------------------------------------------- 1 | \newsadmin\models\Article::find()->where(['cat_id' => 1]), 18 | * 'label' => 'title', // This attribute from the model is used to render the admin block dropdown selection. 19 | * ]); 20 | * ``` 21 | * 22 | * In order to configure the ActiveQuerySelectInjector used the {{\luya\cms\base\InternalBaseBlock::injectors}} method: 23 | * 24 | * ```php 25 | * public function injectors() 26 | * { 27 | * return [ 28 | * 'theData' => new ActiveQuerySelectInjector([ 29 | * 'query' => News::find()->where(['is_deleted' => 0]), 30 | * 'label' => function($model) { 31 | * return $model->title . " - " . $model->description; 32 | * }, 33 | * ]); 34 | * ]; 35 | * } 36 | * ``` 37 | * 38 | * @property \yii\db\ActiveQueryInterface $query The ActiveQuery object 39 | * 40 | * @author Basil Suter 41 | * @since 2.1.0 42 | */ 43 | class ActiveQuerySelectInjector extends BaseActiveQueryInjector 44 | { 45 | /** 46 | * @inheritdoc 47 | */ 48 | public function setup() 49 | { 50 | // injecto the config 51 | $this->setContextConfig([ 52 | 'var' => $this->varName, 53 | 'type' => TypesInterface::TYPE_SELECT, 54 | 'label' => $this->varLabel, 55 | 'options' => $this->getQueryData(), 56 | ]); 57 | 58 | // provide the extra data 59 | $this->context->addExtraVar($this->varName, $this->getExtraAssignSingleData()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/injectors/LinkInjector.php: -------------------------------------------------------------------------------- 1 | new \luya\cms\injectors\LinkInjector() 24 | * ]; 25 | * } 26 | * ``` 27 | * 28 | * The value of the `$this->extraValue('theLink')` is a {{luya\web\LinkInterface}} therefor you can access the `getHref` and `getTarget` methods in order to generate the link: 29 | * 30 | * ```php 31 | * Go There 32 | * ``` 33 | * 34 | * @author Basil Suter 35 | * @since 1.0.0 36 | */ 37 | final class LinkInjector extends BaseBlockInjector 38 | { 39 | private function getLinkUrl() 40 | { 41 | $content = $this->getContextConfigValue($this->varName); 42 | 43 | return BlockHelper::linkObject($content); 44 | } 45 | 46 | /** 47 | * @inheritdoc 48 | */ 49 | public function setup() 50 | { 51 | $this->setContextConfig([ 52 | 'var' => $this->varName, 53 | 'type' => 'zaa-link', 54 | 'label' => $this->varLabel, 55 | ]); 56 | 57 | $this->context->addExtraVar($this->varName, $this->getLinkUrl()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/injectors/TagInjector.php: -------------------------------------------------------------------------------- 1 | 20 | * @since 1.0.0 21 | */ 22 | class TagInjector extends BaseBlockInjector 23 | { 24 | /** 25 | * Returns all avialable Tags. 26 | * 27 | * @return \luya\admin\models\Tag Tag Model ActiveQuery. 28 | */ 29 | public function getCheckboxArray() 30 | { 31 | return Tag::find()->select(['name'])->indexBy('id')->column(); 32 | } 33 | 34 | private $_assignedTags; 35 | 36 | /** 37 | * Get assigned models for the current Block. 38 | * 39 | * @return \luya\admin\models\Tag All selected tags within the tag model. 40 | */ 41 | public function getAssignedTags() 42 | { 43 | if ($this->_assignedTags === null) { 44 | $ids = ArrayHelper::getColumn($this->getContextConfigValue($this->varName, []), 'value'); 45 | $this->_assignedTags = Tag::find()->where(['in','id', $ids])->indexBy('name')->all(); 46 | } 47 | 48 | return $this->_assignedTags; 49 | } 50 | 51 | /** 52 | * @inheritdoc 53 | */ 54 | public function setup() 55 | { 56 | $this->setContextConfig([ 57 | 'var' => $this->varName, 58 | 'type' => TypesInterface::TYPE_CHECKBOX_ARRAY, 59 | 'label' => $this->varLabel, 60 | 'options' => BlockHelper::checkboxArrayOption($this->getCheckboxArray()), 61 | ]); 62 | 63 | $this->context->addExtraVar($this->varName, $this->getAssignedTags()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/menu/InjectItemInterface.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 1.0.0 15 | */ 16 | interface InjectItemInterface 17 | { 18 | /** 19 | * Getter method for the language on which the item is injected. The language is the short code 20 | * based from the composition component. 21 | * 22 | * @return string A language short code string (like de, en) 23 | */ 24 | public function getLang(); 25 | 26 | /** 27 | * Getter method for the unqiue id of a language item which can be auto generated or directly from 28 | * the injection item. Ensure the unique identifier when setting this property. 29 | * 30 | * @return integer|string The unique identifier can be either a string or a number, or a concat of both. 31 | */ 32 | public function getId(); 33 | 34 | /** 35 | * This method provides all setter variables for the item. 36 | * 37 | * @return array An array where the key is the name of the setter property like `title`, `alias` etc. 38 | */ 39 | public function toArray(); 40 | } 41 | -------------------------------------------------------------------------------- /src/models/Config.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 1.0.0 15 | */ 16 | class Config extends \yii\db\ActiveRecord 17 | { 18 | use RegistryTrait; 19 | 20 | public const HTTP_EXCEPTION_NAV_ID = 'httpExceptionNavId'; 21 | 22 | /** 23 | * @inheritdoc 24 | */ 25 | public static function tableName() 26 | { 27 | return 'cms_config'; 28 | } 29 | 30 | /** 31 | * @inheritdoc 32 | */ 33 | public function rules() 34 | { 35 | return [ 36 | [['name', 'value'], 'required'], 37 | [['name'], 'unique'], 38 | ]; 39 | } 40 | 41 | /** 42 | * @inheritdoc 43 | */ 44 | public function attributeLabels() 45 | { 46 | return [ 47 | 'name' => 'Name', 48 | 'value' => 'Value', 49 | ]; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/models/Layout.php: -------------------------------------------------------------------------------- 1 | 18 | * @since 1.0.0 19 | */ 20 | class Layout extends NgRestModel 21 | { 22 | /** 23 | * @inheritdoc 24 | */ 25 | public static function tableName() 26 | { 27 | return 'cms_layout'; 28 | } 29 | 30 | /** 31 | * @inheritdoc 32 | */ 33 | public static function ngRestApiEndpoint() 34 | { 35 | return 'api-cms-layout'; 36 | } 37 | 38 | /** 39 | * @inheritdoc 40 | */ 41 | public function rules() 42 | { 43 | return [ 44 | [['name', 'json_config', 'view_file'], 'required'], 45 | [['json_config'], 'string'], 46 | [['name', 'view_file'], 'string', 'max' => 255], 47 | ]; 48 | } 49 | 50 | /** 51 | * @inheritdoc 52 | */ 53 | public function attributeLabels() 54 | { 55 | return [ 56 | 'name' => Module::t('model_layout_name_label'), 57 | 'json_config' => Module::t('model_layout_json_config_label'), 58 | 'view_file' => Module::t('model_layout_view_file_label'), 59 | ]; 60 | } 61 | 62 | /** 63 | * @inheritdoc 64 | */ 65 | public function ngRestAttributeTypes() 66 | { 67 | return [ 68 | 'name' => 'text', 69 | 'json_config' => ['textarea', 'encoding' => false], 70 | 'view_file' => 'text', 71 | ]; 72 | } 73 | 74 | /** 75 | * @inheritdoc 76 | */ 77 | public function ngRestScopes() 78 | { 79 | return [ 80 | ['list', ['name', 'json_config', 'view_file']], 81 | [['update'], ['name']], 82 | ]; 83 | } 84 | 85 | /** 86 | * Get the json config as array. 87 | * 88 | * @param string $node Get a given key from the config array. 89 | * @return array If the given node is not found an empty array will be returned. 90 | */ 91 | public function getJsonConfig($node = null) 92 | { 93 | $json = Json::decode($this->json_config); 94 | 95 | if (!$node) { 96 | return $json; 97 | } 98 | 99 | if (isset($json[$node])) { 100 | return $json[$node]; 101 | } 102 | 103 | return []; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/models/NavItemRedirect.php: -------------------------------------------------------------------------------- 1 | 22 | * @since 1.0.0 23 | */ 24 | class NavItemRedirect extends NavItemType implements NavItemTypeInterface 25 | { 26 | /** 27 | * @inheritdoc 28 | */ 29 | public static function tableName() 30 | { 31 | return 'cms_nav_item_redirect'; 32 | } 33 | 34 | /** 35 | * @inheritdoc 36 | */ 37 | public static function getNummericType() 38 | { 39 | return NavItem::TYPE_REDIRECT; 40 | } 41 | 42 | /** 43 | * @inheritdoc 44 | */ 45 | public function rules() 46 | { 47 | return [ 48 | [['type', 'value'], 'required'], 49 | [['type'], 'integer'], 50 | [['target', 'anchor'], 'string', 'max' => 255], 51 | [['value'], 'string', 'max' => 255, 'strict' => false], 52 | ]; 53 | } 54 | 55 | /** 56 | * @inheritdoc 57 | */ 58 | public function attributeLabels() 59 | { 60 | return [ 61 | 'value' => Module::t('model_navitemredirect_value_label'), 62 | 'type' => Module::t('model_navitemredirect_type_label'), 63 | 'target' => 'Target', 64 | ]; 65 | } 66 | 67 | /** 68 | * Resolve the values with {{luya\cms\LinkConverter}}. 69 | */ 70 | public function resolveValue(): \luya\web\LinkInterface|bool 71 | { 72 | $converter = new LinkConverter(); 73 | $converter->value = $this->value; 74 | $converter->type = $this->type; 75 | $converter->target = $this->target; 76 | $converter->anchor = $this->anchor; 77 | return $converter->getLink(); 78 | } 79 | 80 | /** 81 | * @inheritdoc 82 | */ 83 | public function getContent() 84 | { 85 | $link = $this->resolveValue(); 86 | 87 | if (!$link) { 88 | throw new InvalidConfigException(sprintf("Unable to redirect to the given page, invalid link object. Make sure the target page with id '%s' is online!", $this->value)); 89 | } 90 | 91 | Yii::$app->getResponse()->redirect($link->getHref()); 92 | Yii::$app->end(); 93 | 94 | return; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/models/NavPermission.php: -------------------------------------------------------------------------------- 1 | 13 | * @since 1.0.4 14 | */ 15 | class NavPermission extends \yii\db\ActiveRecord 16 | { 17 | /** 18 | * {@inheritdoc} 19 | */ 20 | public static function tableName() 21 | { 22 | return 'cms_nav_permission'; 23 | } 24 | 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | public function rules() 29 | { 30 | return [ 31 | [['group_id', 'nav_id'], 'required'], 32 | [['group_id', 'nav_id', 'inheritance'], 'integer'], 33 | ]; 34 | } 35 | 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | public function attributeLabels() 40 | { 41 | return [ 42 | 'group_id' => 'Group ID', 43 | 'nav_id' => 'Nav ID', 44 | 'inheritance' => 'Inheritance', 45 | ]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/models/Property.php: -------------------------------------------------------------------------------- 1 | 15 | * @since 1.0.0 16 | */ 17 | final class Property extends \yii\db\ActiveRecord 18 | { 19 | /** 20 | * @inheritdoc 21 | */ 22 | public static function tableName() 23 | { 24 | return 'cms_nav_property'; 25 | } 26 | 27 | /** 28 | * @inheritdoc 29 | */ 30 | public function rules() 31 | { 32 | return [ 33 | [['nav_id', 'admin_prop_id', 'value'], 'required'], 34 | ]; 35 | } 36 | 37 | /** 38 | * Property Active Query. 39 | * 40 | * @return \luya\admin\models\Property 41 | */ 42 | public function getAdminProperty() 43 | { 44 | return $this->hasOne(AdminProperty::class, ['id' => 'admin_prop_id']); 45 | } 46 | 47 | private $_object; 48 | 49 | /** 50 | * Create the Property object with the given value. 51 | * 52 | * @return \luya\admin\base\Property 53 | */ 54 | public function getObject() 55 | { 56 | if ($this->_object === null) { 57 | $this->_object = $this->adminProperty->createObject($this->value); 58 | } 59 | 60 | return $this->_object; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/tags/AliasTag.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 1.0.0 15 | */ 16 | class MenuTag extends BaseTag 17 | { 18 | public function example() 19 | { 20 | return 'menu[123](Go to Page 123)'; 21 | } 22 | 23 | public function readme() 24 | { 25 | return Module::t('tag_menu_readme'); 26 | } 27 | 28 | public function parse($value, $sub) 29 | { 30 | $menuItem = Yii::$app->menu->find()->where(['nav_id' => $value])->with('hidden')->one(); 31 | 32 | if ($menuItem) { 33 | $alias = (empty($sub)) ? $menuItem->title : $sub; 34 | 35 | return Html::a($alias, $menuItem->link); 36 | } 37 | 38 | return false; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/tags/PageTag.php: -------------------------------------------------------------------------------- 1 | parse(1, 'placeholderName'); // where 1 is the Nav ID if no placeholder name is given us null to render the whole page. 21 | * ``` 22 | * 23 | * @author Basil Suter 24 | * @since 1.0.0 25 | */ 26 | class PageTag extends BaseTag 27 | { 28 | /** 29 | * @inheritdoc 30 | */ 31 | public function example() 32 | { 33 | return 'page[1](placeholder)'; 34 | } 35 | 36 | /** 37 | * @inheritdoc 38 | */ 39 | public function readme() 40 | { 41 | return Module::t('tag_page_readme'); 42 | } 43 | 44 | /** 45 | * Get the content of Nav for the current active language with cmslayout or placeholder. 46 | * 47 | * If the page does not have a corresponding activeLanguageItem, null is returned. 48 | * 49 | * @param string $value The value of the Nav ID e.g 1 (hover the cms menu to see the ID). 50 | * @param string|null $sub If null this parameter will be ignored otherwise its the name of the placeholder inside this cmslayout. 51 | * @return string The content rendered with the cmslayout, or if $sub is provided and not null with its placeholder name. 52 | * @see \luya\tag\TagInterface::parse() 53 | */ 54 | public function parse($value, $sub) 55 | { 56 | $page = Nav::findOne(['id' => $value]); 57 | 58 | // verify if the page is of type content 59 | 60 | if ($page && $page->activeLanguageItem) { 61 | if ($page->activeLanguageItem->nav_item_type !== NavItem::TYPE_PAGE) { 62 | return null; 63 | } 64 | 65 | if (empty($sub)) { 66 | return $page->activeLanguageItem->getContent(); 67 | } else { 68 | return $page->activeLanguageItem->type->renderPlaceholder($sub); 69 | } 70 | } 71 | 72 | return null; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/BlockTestCase.php: -------------------------------------------------------------------------------- 1 | 'basetestcase', 13 | 'basePath' => dirname(__DIR__), 14 | 'aliases' => [ 15 | '@cmstests' => '.', 16 | ], 17 | 'components' => [ 18 | 'db' => [ 19 | 'class' => 'yii\db\Connection', 20 | 'dsn' => 'sqlite::memory:', 21 | ], 22 | 'urlManager' => [ 23 | 'cache' => null, 24 | ] 25 | ], 26 | 'modules' => [ 27 | 'admin' => [ 28 | 'class' => 'luya\admin\Module', 29 | 'queueMutexClass' => 'yii\mutex\FileMutex', 30 | ], 31 | 'cms' => [ 32 | 'class' => '\luya\cms\frontend\Module' 33 | ], 34 | 'cmsadmin' => [ 35 | 'class' => 'luya\cms\admin\Module', 36 | 'blocks' => ['@cmstests/tests/data/blocks/import'], 37 | 'cmsLayouts' => ['@cmstests/tests/data/cmslayouts'], 38 | ], 39 | 'CmsUnitModule' => '\cmstests\data\modules\CmsUnitModule', 40 | ], 41 | ]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/CmsFrontendTestCase.php: -------------------------------------------------------------------------------- 1 | 1]); 26 | $data[] = self::generateMenuItem(2, 'Page 1', []); 27 | $data[] = self::generateMenuItem(3, 'Page 1.1', ['parent_nav_id' => 2, 'depth' => 2]); 28 | $data[] = self::generateMenuItem(4, 'Page 1.2', ['parent_nav_id' => 2, 'depth' => 2]); 29 | $data[] = self::generateMenuItem(5, 'Page 1.3', ['parent_nav_id' => 2, 'depth' => 2]); 30 | $data[] = self::generateMenuItem(6, 'Page 1.2.1', ['parent_nav_id' => 4, 'depth' => 3]); 31 | $data[] = self::generateMenuItem(7, 'Page 1.2.2', ['parent_nav_id' => 4, 'depth' => 3]); 32 | $data[] = self::generateMenuItem(8, 'Page 1.2.3', ['parent_nav_id' => 4, 'depth' => 3]); 33 | return $data; 34 | } 35 | 36 | public static function mockMenuContainerArray() 37 | { 38 | $data[] = self::generateMenuItem(1, 'homepage', ['is_home' => 1]); 39 | $data[] = self::generateMenuItem(2, 'Page 1', []); 40 | $data[] = self::generateMenuItem(3, '(c1) Page 1', ['container' => 'c1']); 41 | $data[] = self::generateMenuItem(5, '(c2) Page 1', ['container' => 'c2']); 42 | $data[] = self::generateMenuItem(6, '(c2) Page 2', ['container' => 'c2']); 43 | 44 | return $data; 45 | } 46 | 47 | public static function generateMenuItem($id, $title, array $args) 48 | { 49 | return array_merge([ 50 | 'id' => $id, 51 | 'nav_id' => $id, 52 | 'lang' => 'en', 53 | 'link' => Inflector::slug($title), 54 | 'title' => $title, 55 | 'alias' => Inflector::slug($title), 56 | 'type' => 1, 57 | 'container' => 'default', 58 | 'description' => 0, 59 | 'keyowrds' => null, 60 | 'create_user_id' => 0, 61 | 'update_user_id' => 0, 62 | 'image_id' => 0, 63 | 'timestamp_create' => time(), 64 | 'timestamp_update' => time(), 65 | 'parent_nav_id' => 0, 66 | 'is_home' => 0, 67 | 'sort_index' => 1000, 68 | 'depth' => 1, 69 | ], $args); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tests/CmsNgRestTestCase.php: -------------------------------------------------------------------------------- 1 | 'ngresttest', 13 | 'basePath' => dirname(__DIR__), 14 | 'components' => [ 15 | 'db' => [ 16 | 'class' => 'yii\db\Connection', 17 | 'dsn' => 'sqlite::memory:', 18 | ], 19 | 'urlManager' => [ 20 | 'cache' => null, 21 | ] 22 | ] 23 | ]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.1-cli 2 | RUN apt-get update -yqq \ 3 | && apt-get install -y libicu-dev sqlite3 \ 4 | && docker-php-ext-install intl mysqli pdo pdo_mysql -------------------------------------------------------------------------------- /tests/ModelTestCase.php: -------------------------------------------------------------------------------- 1 | 'basetestcase', 14 | 'basePath' => dirname(__DIR__), 15 | 'components' => [ 16 | 'db' => [ 17 | 'class' => 'yii\db\Connection', 18 | 'dsn' => 'sqlite::memory:', 19 | ], 20 | 'urlManager' => [ 21 | 'cache' => null, 22 | ], 23 | 'adminLanguage' => [ 24 | 'class' => AdminLanguage::class, 25 | ] 26 | ] 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/WebModelTestCase.php: -------------------------------------------------------------------------------- 1 | 'webmodel', 13 | 'basePath' => dirname(__DIR__), 14 | 'components' => [ 15 | 'db' => [ 16 | 'class' => 'yii\db\Connection', 17 | 'dsn' => 'sqlite::memory:', 18 | ], 19 | 'urlManager' => [ 20 | 'cache' => null, 21 | ] 22 | ], 23 | 'modules' => [ 24 | 'admin' => [ 25 | 'class' => 'luya\admin\Module', 26 | 'queueMutexClass' => 'yii\mutex\FileMutex', 27 | ], 28 | 'cms' => 'luya\cms\frontend\Module', 29 | 'cmsadmin' => 'luya\cms\admin\Module', 30 | ] 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/data/assets/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /tests/data/blocks/PhpTestBlock.php: -------------------------------------------------------------------------------- 1 | 'bar']; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/data/blocks/TestBlock.php: -------------------------------------------------------------------------------- 1 | [ 25 | ['var' => 'var1', 'label' => 'VAR 1', 'type' => 'zaa-text', 'placeholder' => 'VAR 1 PLACEHOLDER'], 26 | ['var' => 'var2', 'label' => 'VAR 2', 'type' => 'zaa-text'], 27 | ], 28 | 'cfgs' => [ 29 | ['var' => 'cfg1', 'label' => 'CFG 1', 'type' => 'zaa-text'], 30 | ], 31 | ]; 32 | } 33 | 34 | public function admin() 35 | { 36 | return [ 37 | $this->getVarValue('var1'), 38 | $this->getVarValue('var2'), 39 | $this->getCfgValue('cfg1'), 40 | $this->getEnvOptions(), 41 | ]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/data/blocks/UnitTestBlock.php: -------------------------------------------------------------------------------- 1 | [ 25 | ['var' => 'var1', 'label' => 'VAR 1', 'type' => 'zaa-text', 'placeholder' => 'VAR 1 PLACEHOLDER'], 26 | ['var' => 'var2', 'label' => 'VAR 2', 'type' => 'zaa-text'], 27 | ], 28 | 'cfgs' => [ 29 | ['var' => 'cfg1', 'label' => 'CFG 1', 'type' => 'zaa-text'], 30 | ], 31 | ]; 32 | } 33 | 34 | public function admin() 35 | { 36 | return [ 37 | $this->getVarValue('var1'), 38 | $this->getVarValue('var2'), 39 | $this->getCfgValue('cfg1'), 40 | $this->getEnvOptions(), 41 | ]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/data/cmslayouts/layoutwithjson.json: -------------------------------------------------------------------------------- 1 | { 2 | "rows" : [ 3 | [ 4 | {"cols": 8, "var": "left", "label": "Main content Left"}, 5 | {"cols": 4, "var": "right", "label": "Sidebar Right"} 6 | ] 7 | ] 8 | } -------------------------------------------------------------------------------- /tests/data/cmslayouts/layoutwithjson.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 | 7 |
8 |
-------------------------------------------------------------------------------- /tests/data/cmslayouts/phplayout.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 | 7 |
8 |
-------------------------------------------------------------------------------- /tests/data/configs/cms.php: -------------------------------------------------------------------------------- 1 | 'testenv', 5 | 'siteTitle' => 'Luya Tests', 6 | 'remoteToken' => 'testtoken', 7 | 'basePath' => dirname(__DIR__), 8 | 'defaultRoute' => 'cms', 9 | 'aliases' => [ 10 | 'cmstests' => dirname(__DIR__) . '/../', 11 | ], 12 | 'language' => 'en', 13 | 'modules' => [ 14 | 'admin' => [ 15 | 'class' => 'luya\admin\Module', 16 | 'queueMutexClass' => 'yii\mutex\FileMutex', 17 | ], 18 | 'cms' => [ 19 | 'class' => '\luya\cms\frontend\Module' 20 | ], 21 | 'cmsadmin' => 'luya\cms\admin\Module', 22 | 'CmsUnitModule' => '\cmstests\data\modules\CmsUnitModule', 23 | ], 24 | 'components' => [ 25 | 'request' => [ 26 | 'forceWebRequest' => true, 27 | ], 28 | 'composition' => [ 29 | 'hidden' => false, 30 | ], 31 | 'db' => [ 32 | 'class' => 'yii\db\Connection', 33 | 'dsn' => DB_DSN, 34 | 'username' => DB_USER, 35 | 'password' => DB_PASS, 36 | 'charset' => 'utf8', 37 | ], 38 | 'cache' => \yii\caching\ArrayCache::class, 39 | 'assetManager' => [ 40 | 'basePath' => dirname(__DIR__) . '/assets', 41 | ], 42 | 'website' => [ 43 | 'class' => \luya\cms\Website::class, 44 | ] 45 | ], 46 | ]; 47 | -------------------------------------------------------------------------------- /tests/data/env.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'id' => '1', 16 | 'name' => 'John', 17 | ], 18 | 'tag2' => [ 19 | 'id' => '2', 20 | 'name' => 'Jane', 21 | ], 22 | ]; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/data/images/blocks/TestBlock.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyadev/luya-module-cms/8a3472acfc2620374fb8de6aed1f2736926cca2b/tests/data/images/blocks/TestBlock.jpg -------------------------------------------------------------------------------- /tests/data/items/RootItem.php: -------------------------------------------------------------------------------- 1 | $this->getId(), 23 | 'nav_id' => 1, 24 | 'lang' => $this->getLang(), 25 | 'link' => '/', 26 | 'title' => 'Root', 27 | 'title_tag' => 'Root', 28 | 'alias' => 'root', 29 | 'description' => null, 30 | 'keywords' => null, 31 | 'create_user_id' => 0, 32 | 'update_user_id' => 0, 33 | 'timestamp_create' => time(), 34 | 'timestamp_update' => time(), 35 | 'is_home' => 1, 36 | 'parent_nav_id' => 0, 37 | 'sort_index' => 0, 38 | 'is_hidden' => false, 39 | 'type' => 1, 40 | 'redirect' => false, 41 | 'container' => 'default', 42 | 'depth' => 0, 43 | ]; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/data/modules/CmsUnitModule.php: -------------------------------------------------------------------------------- 1 | /' => 'cmsurlrulemodule/default/index', 11 | ]; 12 | } 13 | -------------------------------------------------------------------------------- /tests/data/modules/controllers/DefaultController.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/data/themes/testTheme/theme.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /tests/data/views/blocks/PhpTestBlock.php: -------------------------------------------------------------------------------- 1 | frontend -------------------------------------------------------------------------------- /tests/data/views/cmslayouts/main.php: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /tests/data/views/layouts/main.php: -------------------------------------------------------------------------------- 1 | beginPage(); 10 | ?> 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | <?= $this->title; ?> 19 | head() ?> 20 | 21 | 22 | beginBody() ?> 23 | 24 | endBody() ?> 25 | 26 | 27 | endPage() ?> -------------------------------------------------------------------------------- /tests/runtime/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyadev/luya-module-cms/8a3472acfc2620374fb8de6aed1f2736926cca2b/tests/runtime/.gitkeep -------------------------------------------------------------------------------- /tests/src/LinkConverterTest.php: -------------------------------------------------------------------------------- 1 | LinkConverter::TYPE_INTERNAL_PAGE, 'value' => 1, 'target' => null]); 16 | 17 | $this->assertInstanceOf(\luya\cms\menu\Item::class, $converter->getLink()); 18 | } 19 | 20 | public function testExternalLink() 21 | { 22 | $converter = LinkConverter::fromArray(['type' => LinkConverter::TYPE_EXTERNAL_URL, 'value' => "luya.io", 'target' => null]); 23 | 24 | $this->assertInstanceOf(WebsiteLink::class, $converter->getLink()); 25 | } 26 | 27 | public function testFileLink() 28 | { 29 | $this->markTestSkipped('Require a file entry in the test database.'); 30 | 31 | $converter = LinkConverter::fromArray(['type' => LinkConverter::TYPE_LINK_TO_FILE, 'value' => 1, 'target' => null]); 32 | 33 | $this->assertInstanceOf(\luya\admin\file\Item::class, $converter->getLink()); 34 | } 35 | 36 | public function testEmailLink() 37 | { 38 | $converter = LinkConverter::fromArray(['type' => LinkConverter::TYPE_LINK_TO_EMAIL, 'value' => 'mail@luya.io', 'target' => null]); 39 | 40 | $this->assertInstanceOf(EmailLink::class, $converter->getLink()); 41 | } 42 | 43 | public function testTelephoneLink() 44 | { 45 | $converter = LinkConverter::fromArray(['type' => LinkConverter::TYPE_LINK_TO_TELEPHONE, 'value' => '0123456', 'target' => null]); 46 | 47 | $this->assertInstanceOf(TelephoneLink::class, $converter->getLink()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/src/MenuTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(is_object(Yii::$app->menu)); 18 | } 19 | 20 | public function testSelfClass() 21 | { 22 | $objectData = new Menu((new \luya\web\Request())); 23 | $current = $objectData->current; 24 | $this->assertEquals("Homepage", $current->title); 25 | $this->assertEquals(Yii::$app->urlManager->prependBaseUrl(''), $current->link); 26 | } 27 | 28 | public function testGetCurrent() 29 | { 30 | $current = Yii::$app->menu->current; 31 | $this->assertEquals("Homepage", $current->title); 32 | $this->assertEquals(Yii::$app->urlManager->prependBaseUrl(''), $current->link); 33 | } 34 | 35 | public function testGetHome() 36 | { 37 | $home = Yii::$app->menu->home; 38 | $this->assertEquals("Homepage", $home->title); 39 | $this->assertEquals(Yii::$app->urlManager->prependBaseUrl(''), $home->link); 40 | } 41 | 42 | public function testOffsetArrayAccess() 43 | { 44 | $menu = Yii::$app->menu; 45 | $this->assertEquals(17, count($menu['en'])); 46 | } 47 | 48 | public function testCurrentAppendix() 49 | { 50 | $this->assertEmpty(Yii::$app->menu->currentAppendix); 51 | } 52 | 53 | public function testFind() 54 | { 55 | $obj = Yii::$app->menu->find(); 56 | $this->assertTrue($obj instanceof Query); 57 | } 58 | 59 | public function testFindOne() 60 | { 61 | $obj = Yii::$app->menu->findOne(['id' => 1]); 62 | $this->assertTrue($obj instanceof Item); 63 | } 64 | 65 | public function testFindOneFalse() 66 | { 67 | $obj = Yii::$app->menu->findOne(['id' => 2000]); 68 | $this->assertFalse($obj); 69 | } 70 | 71 | public function testFindAll() 72 | { 73 | $iterator = Yii::$app->menu->findAll(['parent_nav_id' => 0]); 74 | $this->assertTrue($iterator instanceof QueryIteratorFilter); 75 | } 76 | 77 | public function testOffsetLangaugeDoesNotExists() 78 | { 79 | $this->expectException(NotFoundHttpException::class); 80 | Yii::$app->menu['ru']; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /tests/src/MessageFileTest.php: -------------------------------------------------------------------------------- 1 | compareMessages(Yii::getAlias('@cmsadmin/messages'), 'en'); 16 | } 17 | 18 | public function testFrontendMessages() 19 | { 20 | $this->compareMessages(Yii::getAlias('@cms/messages'), 'en'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/src/admin/apis/AdminControllerTest.php: -------------------------------------------------------------------------------- 1 | createAdminLangFixture([]); 16 | $this->createCmsLog([ 17 | 1 => [ 18 | 'id' => 1, 19 | 'user_id' => 1, 20 | 'is_insertion' => 1, 21 | 'is_update' => 0, 22 | 'is_deletion' => 0, 23 | 'timestamp' => time(), 24 | 'table_name' => 'xyz', 25 | 'row_id' => 1, 26 | ] 27 | ]); 28 | $this->createAdminUserFixture(); 29 | $ctrl = new AdminController('id', $this->app); 30 | 31 | $log = $ctrl->actionDashboardLog(); 32 | 33 | $this->assertNotEmpty($log); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/src/admin/apis/NavItemControllerTest.php: -------------------------------------------------------------------------------- 1 | createAdminLangFixture(); 20 | $this->createCmsNavItemPageFixture([ 21 | 2 => [ 22 | 'id' => 2, 23 | 'layout_id' => 1, 24 | 'nav_item_id' => 1, 25 | 'version_alias' => 'test', 26 | ] 27 | ]); 28 | 29 | $this->createCmsNavItemFixture([ 30 | 1 => [ 31 | 'id' => 1, 32 | ] 33 | ]); 34 | } 35 | 36 | public function testChangePageVersionLayoutNotFound() 37 | { 38 | $ctrl = new NavItemController('nav-item', $this->app->getModule('cmsadmin')); 39 | 40 | Yii::$app->request->setBodyParams(['pageItemId' => 1, 'layoutId' => 1, 'alias' => 1]); 41 | $this->expectException(NotFoundHttpException::class); 42 | $ctrl->actionChangePageVersionLayout(); 43 | } 44 | 45 | public function testChangePageVersionLayout() 46 | { 47 | $ctrl = new NavItemController('nav-item', $this->app->getModule('cmsadmin')); 48 | 49 | Yii::$app->request->setBodyParams(['pageItemId' => 2, 'layoutId' => 1, 'alias' => 'foobar']); 50 | $r = $ctrl->actionChangePageVersionLayout(); 51 | 52 | $this->assertInstanceOf(NavItemType::class, $r); 53 | 54 | $this->assertSame(1, $r->layout_id); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/src/admin/controllers/DefaultControllerTest.php: -------------------------------------------------------------------------------- 1 | app, function (PermissionScope $scope) { 17 | $ctrl = new DefaultController('default', $this->app->getModule('cmsadmin')); 18 | $this->assertNotEmpty($ctrl->actionIndex()); 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/src/admin/controllers/PageControllerTest.php: -------------------------------------------------------------------------------- 1 | app, function (PermissionScope $scope) { 17 | $ctrl = new PageController('page', $this->app->getModule('cmsadmin')); 18 | $this->assertNotEmpty($ctrl->actionUpdate()); 19 | $this->assertNotEmpty($ctrl->actionDrafts()); 20 | $this->assertNotEmpty($ctrl->actionCreate()); 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/src/admin/controllers/PermissionControllerTest.php: -------------------------------------------------------------------------------- 1 | app->getModule('cmsadmin')); 16 | $this->assertNotEmpty($ctrl->actionIndex()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/src/base/BaseBlockInjectorTest.php: -------------------------------------------------------------------------------- 1 | [ 20 | ['var' => 'text-input', 'type' => 'zaa-text', 'label' => 'text'], 21 | ], 22 | ]; 23 | } 24 | } 25 | 26 | class StubInjector extends BaseBlockInjector 27 | { 28 | /** 29 | * @inheritdoc 30 | */ 31 | public function setup() 32 | { 33 | $this->setContextConfig([ 34 | 'var' => $this->varName, 35 | 'label' => $this->varLabel, 36 | 'type' => 'injector-test', 37 | ]); 38 | 39 | $this->context->addExtraVar($this->varName, 'injector-output'); 40 | } 41 | } 42 | 43 | class BaseBlockInjectorTest extends CmsFrontendTestCase 44 | { 45 | public function testLinkInjector() 46 | { 47 | $block = new StubBlock(); 48 | $injector = new StubInjector(['context' => $block]); 49 | $injector->setup(); 50 | 51 | $cfgs = $block->getConfigVarsExport(); 52 | 53 | $this->assertSame('injector-test', $cfgs[0]['type']); 54 | $this->assertSame('zaa-text', $cfgs[1]['type']); 55 | } 56 | 57 | public function testAppendOfVar() 58 | { 59 | $block = new StubBlock(); 60 | $injector = new StubInjector(['context' => $block, 'append' => true]); 61 | $injector->setup(); 62 | 63 | $cfgs = $block->getConfigVarsExport(); 64 | 65 | $this->assertSame('injector-test', $cfgs[1]['type']); 66 | $this->assertSame('zaa-text', $cfgs[0]['type']); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/src/base/PhpBlockTest.php: -------------------------------------------------------------------------------- 1 | assertSame('admin', $block->renderAdmin()); 15 | } 16 | 17 | public function testFrontendResponse() 18 | { 19 | $block = new PhpTestBlock(); 20 | return $this->assertSame('frontend', $block->renderFrontend()); 21 | } 22 | 23 | public function testExtraVarsGetter() 24 | { 25 | $block = new PhpTestBlock(); 26 | $this->assertArrayHasKey('foo', $block->extraVars()); 27 | } 28 | 29 | public function testExtraVarsValueGetter() 30 | { 31 | $block = new PhpTestBlock(); 32 | $this->assertSame('bar', $block->getExtraValue('foo')); 33 | } 34 | 35 | public function textExtraVarValuesGetter() 36 | { 37 | $block = new PhpTestBlock(); 38 | $this->assertArrayHasKey('foo', $block->getExtraVarValues()); 39 | } 40 | 41 | /** 42 | * @todo Test register multiple asset bundles 43 | */ 44 | public function testOnRegister() 45 | { 46 | $block = new PhpTestBlock(); 47 | $block->cacheEnabled = true; 48 | 49 | $block->getView()->registerAssetBundle(AssetBundle::class); 50 | // $block->getView()->registerAssetBundle(JqueryAsset::class); 51 | 52 | $block->onRegister(); 53 | 54 | $this->assertSame([AssetBundle::class], \Yii::$app->cache->get(['blockassetbundles', $block->getEnvOption('id')])); 55 | // $this->assertSame([AssetBundle::class, JqueryAsset::class], \Yii::$app->cache->get(['blockassetbundles', $block->getEnvOption('id')])); 56 | } 57 | 58 | public function testRelativeViewPath() 59 | { 60 | $block = new PhpTestBlock(); 61 | $block->module = null; 62 | 63 | $this->assertStringContainsString('tests'.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'blocks'.DIRECTORY_SEPARATOR.'views', $block->getViewPath()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/src/controllers/BlockControllerTest.php.bkp: -------------------------------------------------------------------------------- 1 | runAction('block/index'); 18 | } 19 | 20 | /** 21 | * @expectedException yii\base\Exception 22 | */ 23 | public function testUnableToFindItemId() 24 | { 25 | $response = (new Module('cms'))->runAction('block/index', ['callback' => 'test', 'id' => 0]); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/src/controllers/PreviewControllerTest.php.bkp: -------------------------------------------------------------------------------- 1 | getModule('cms')->runAction('preview/index'); 18 | } 19 | 20 | /** 21 | * itemId param is missing 22 | * @expectedException yii\web\ForbiddenHttpException 23 | */ 24 | public function testNoAuthToView() 25 | { 26 | $response = Yii::$app->getModule('cms')->runAction('preview/index', ['itemId' => 1]); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/src/frontend/BootstrapErrorPageTest.php: -------------------------------------------------------------------------------- 1 | bootstrap($this->app); 19 | 20 | $event = new ErrorHandlerExceptionRenderEvent(); 21 | $event->exception = new NotFoundHttpException("not found"); 22 | 23 | 24 | new ActiveRecordFixture([ 25 | 'modelClass' => Config::class, 26 | ]); 27 | 28 | Config::set(Config::HTTP_EXCEPTION_NAV_ID, 1); 29 | 30 | $this->expectException('yii\web\HeadersAlreadySentException'); 31 | $this->app->errorHandler->trigger(ErrorHandler::EVENT_BEFORE_EXCEPTION_RENDER, $event); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/src/frontend/ModuleTest.php: -------------------------------------------------------------------------------- 1 | fixture = new NgRestModelFixture([ 23 | 'modelClass' => Theme::class, 24 | ]); 25 | } 26 | 27 | public function testBootstrap() 28 | { 29 | /** @var Theme $themeModel */ 30 | $themeModel = $this->fixture->newModel; 31 | $themeModel->is_default = 1; 32 | $themeModel->base_path = '@app/themes/appTheme'; 33 | $themeModel->json_config = '{}'; 34 | $this->assertTrue($themeModel->save()); 35 | 36 | Yii::$app->request->forceWebRequest = true; 37 | Yii::$app->request->setIsConsoleRequest(false); 38 | 39 | /** @var Module $module */ 40 | $module = Yii::$app->getModule('cms'); 41 | $module->luyaBootstrap(Yii::$app); 42 | 43 | Yii::$app->themeManager->activeThemeName = '@app/themes/moduleTest'; 44 | Yii::$app->themeManager->setup(); 45 | 46 | $this->assertTrue(Yii::$app->themeManager->hasActiveTheme); 47 | $this->assertEquals(Yii::getAlias('@app/themes/appTheme'), Yii::$app->themeManager->activeTheme->basePath); 48 | 49 | $this->fixture->cleanup(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/src/frontend/blockgroups/DevelopmentGroupTest.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0.6 13 | */ 14 | class DevelopmentGroupTest extends CmsBlockGroupTestCase 15 | { 16 | public $blockGroupClass = 'luya\cms\frontend\blockgroups\DevelopmentGroup'; 17 | 18 | public $blockGroupIdentifier = 'development-group'; 19 | } 20 | -------------------------------------------------------------------------------- /tests/src/frontend/blockgroups/LayoutGroupTest.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0.6 13 | */ 14 | class LayoutGroupTest extends CmsBlockGroupTestCase 15 | { 16 | public $blockGroupClass = 'luya\cms\frontend\blockgroups\LayoutGroup'; 17 | 18 | public $blockGroupIdentifier = 'layout-group'; 19 | } 20 | -------------------------------------------------------------------------------- /tests/src/frontend/blockgroups/MainGroupTest.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0.6 13 | */ 14 | class MainGroupTest extends CmsBlockGroupTestCase 15 | { 16 | public $blockGroupClass = 'luya\cms\frontend\blockgroups\MainGroup'; 17 | 18 | public $blockGroupIdentifier = 'main-group'; 19 | } 20 | -------------------------------------------------------------------------------- /tests/src/frontend/blockgroups/MediaGroupTest.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0.6 13 | */ 14 | class MediaGroupTest extends CmsBlockGroupTestCase 15 | { 16 | public $blockGroupClass = 'luya\cms\frontend\blockgroups\MediaGroup'; 17 | 18 | public $blockGroupIdentifier = 'media-group'; 19 | } 20 | -------------------------------------------------------------------------------- /tests/src/frontend/blockgroups/ProjectGroupTest.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0.6 13 | */ 14 | class ProjectGroupTest extends CmsBlockGroupTestCase 15 | { 16 | public $blockGroupClass = 'luya\cms\frontend\blockgroups\ProjectGroup'; 17 | 18 | public $blockGroupIdentifier = 'project-group'; 19 | } 20 | -------------------------------------------------------------------------------- /tests/src/frontend/blockgroups/TextGroupTest.php: -------------------------------------------------------------------------------- 1 | 12 | * @since 1.0.6 13 | */ 14 | class TextGroupTest extends CmsBlockGroupTestCase 15 | { 16 | public $blockGroupClass = 'luya\cms\frontend\blockgroups\TextGroup'; 17 | 18 | public $blockGroupIdentifier = 'text-group'; 19 | } 20 | -------------------------------------------------------------------------------- /tests/src/frontend/blocks/HtmlBlockTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('', $this->renderFrontend()); 14 | } 15 | 16 | public function testInputHtml() 17 | { 18 | $this->block->setVarValues([ 19 | 'html' => '
Hello World
', 20 | ]); 21 | 22 | $this->assertSame('
Hello World
', $this->renderFrontendNoSpace()); 23 | } 24 | 25 | public function testAdminRawOutput() 26 | { 27 | $this->block->setVarValues([ 28 | 'html' => '

hello

', 29 | ]); 30 | 31 | $this->assertSame('<p>hello</p>', $this->renderAdminNoSpace()); 32 | 33 | $this->block->setCfgValues(['raw' => 1]); 34 | 35 | $this->assertSame('

hello

', $this->renderAdminNoSpace()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/src/frontend/blocks/MirrorLanguageBlockTest.php: -------------------------------------------------------------------------------- 1 | createAdminLangFixture([ 16 | 1 => [ 17 | 'id' => 1, 18 | 'name' => 'en', 19 | 'short_code' => 'en', 20 | 'is_default' => 1, 21 | 'is_deleted' => 0, 22 | ], 23 | 2 => [ 24 | 'id' => 2, 25 | 'name' => 'de', 26 | 'short_code' => 'de', 27 | 'is_default' => 0, 28 | 'is_deleted' => 0, 29 | ] 30 | ]); 31 | $this->createCmsNavItemPageBlockItemFixture([ 32 | 1 => [ 33 | 'id' => 1, 34 | 'placeholder_var' => 'xyz', 35 | 'nav_item_page_id' => 1, 36 | ] 37 | ]); 38 | $this->createCmsNavItemPageFixture([ 39 | 1 => [ 40 | 'id' => 1, 41 | 'nav_item_id' => 1 42 | ] 43 | ]); 44 | 45 | $this->createCmsNavItemFixture([ 46 | 1 => [ 47 | 'id' => 1, 48 | 'lang_id' => 1, 49 | 'nav_item_type' => 1, 50 | ], 51 | 2 => [ 52 | 'id' => 2, 53 | 'lang_id' => 2, 54 | 'nav_item_type' => 1, 55 | ] 56 | ]); 57 | 58 | $block = new MirrorLanguageBlock(); 59 | 60 | $this->assertEmpty($block->frontend()); 61 | $this->assertNotEmpty($block->name()); 62 | $this->assertNotEmpty($block->icon()); 63 | $this->assertNotEmpty($block->config()); 64 | $this->assertNotEmpty($block->admin()); 65 | 66 | $block->setVarValues(['language' => 2]); 67 | 68 | $r = $block->frontend(); 69 | 70 | $block->setVarValues(['language' => 1]); 71 | 72 | $r = $block->frontend(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/src/frontend/commands/PageControllerTest.php: -------------------------------------------------------------------------------- 1 | app, function (PageScope $scope) { 15 | $scope->createCmsNavFixture([]); 16 | $scope->createCmsNavItemFixture([]); 17 | $scope->createCmsNavItemPageFixture([]); 18 | $scope->createCmsNavItemPageBlockItemFixture([ 19 | 'item1' => [ 20 | 'id' => 1, 21 | 'json_config_values' => '', 22 | 'json_config_cfg_values' => '', 23 | 'block_id' => 0, 24 | 'placeholder_var' => 'default', 25 | 'nav_item_page_id' => 1, 26 | ] 27 | ]); 28 | $scope->createCmsPropertyFixture([]); 29 | $scope->createCmsNavPermissionFixture([]); 30 | $ctrl = new PageControllerStub('page', $this->app); 31 | $ctrl->sendInput('yes'); 32 | $r = $ctrl->actionCleanup(); 33 | 34 | $this->assertSame(0, $r); 35 | }); 36 | 37 | 38 | PageScope::run($this->app, function (PageScope $scope) { 39 | $scope->createCmsNavFixture([]); 40 | $scope->createCmsNavItemFixture([]); 41 | $scope->createCmsNavItemPageFixture([]); 42 | $scope->createCmsNavItemPageBlockItemFixture([ 43 | 'item1' => [ 44 | 'id' => 1, 45 | 'json_config_values' => '', 46 | 'json_config_cfg_values' => '', 47 | 'block_id' => 0, 48 | 'placeholder_var' => 'default', 49 | 'nav_item_page_id' => 1, 50 | ] 51 | ]); 52 | $scope->createCmsPropertyFixture([]); 53 | $scope->createCmsNavPermissionFixture([]); 54 | $ctrl = new PageControllerStub('page', $this->app); 55 | $ctrl->truncateStreams(); 56 | $r = $ctrl->actionCleanup(); 57 | 58 | $this->assertSame(1, $r); 59 | }); 60 | } 61 | } 62 | 63 | class PageControllerStub extends PageController 64 | { 65 | use CommandStdStreamTrait; 66 | } 67 | -------------------------------------------------------------------------------- /tests/src/frontend/components/CatchAllUrlRuleTest.php: -------------------------------------------------------------------------------- 1 | assertFalse($rule->createUrl($this->app->urlManager, '/cms/default/index/', ['path' => 'foo/bar'])); 15 | $this->assertFalse($rule->createUrl($this->app->urlManager, '/wrong/route', ['path' => 'foo/bar'])); 16 | $this->assertFalse($rule->createUrl($this->app->urlManager, 'cms/default/index', [])); 17 | 18 | $this->assertSame('foo/bar', $rule->createUrl($this->app->urlManager, 'cms/default/index', ['path' => 'foo/bar'])); 19 | $this->assertSame('foo/bar', $rule->createUrl($this->app->urlManager, '/cms/default/index', ['path' => 'foo/bar'])); 20 | $this->assertSame('foo/bar?page=1', $rule->createUrl($this->app->urlManager, 'cms/default/index', ['path' => 'foo/bar', 'page' => 1])); 21 | } 22 | 23 | public function testParseRequest() 24 | { 25 | $rule = new CatchAllUrlRule(); 26 | 27 | $this->assertFalse($rule->parseRequest($this->app->urlManager, $this->app->request)); 28 | 29 | $this->app->request->pathInfo = 'foo/bar'; 30 | $this->assertSame([ 31 | 'cms/default/index', 32 | ['path' => 'foo/bar'], 33 | ], $rule->parseRequest($this->app->urlManager, $this->app->request)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/src/frontend/controllers/BlockControllerTest.php: -------------------------------------------------------------------------------- 1 | app); 13 | 14 | $this->assertSame('callbackMyAction', $this->invokeMethod($ctrl, 'callbackToMethod', ['my-action'])); 15 | $this->assertSame('callbackMyAction', $this->invokeMethod($ctrl, 'callbackToMethod', ['myAction'])); 16 | $this->assertSame('callbackMyAction', $this->invokeMethod($ctrl, 'callbackToMethod', ['callback-my-action'])); 17 | $this->assertSame('callbackMyAction', $this->invokeMethod($ctrl, 'callbackToMethod', ['callbackMyAction'])); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/src/helpers/BlockHelperTest.php: -------------------------------------------------------------------------------- 1 | assertSame([['label' => 'World', 'value' => 'Hello']], BlockHelper::selectArrayOption(['Hello' => 'World'])); 13 | 14 | $this->assertSame([ 15 | ['label' => 'bar', 'value' => 'foo'] 16 | ], BlockHelper::selectArrayOption(['foo' => 'bar'])); 17 | 18 | $this->assertSame([ 19 | ['label' => 'Prompt!', 'value' => 0], 20 | ['label' => 'bar', 'value' => 'foo'] 21 | ], BlockHelper::selectArrayOption(['foo' => 'bar'], 'Prompt!')); 22 | } 23 | 24 | public function testCheckboxArrayOption() 25 | { 26 | $this->assertSame(['items' => [['label' => 'World', 'value' => 'Hello']]], BlockHelper::checkboxArrayOption(['Hello' => 'World'])); 27 | } 28 | 29 | public function testImageUpload() 30 | { 31 | $this->assertFalse(BlockHelper::imageUpload(1)); 32 | } 33 | public function testImageArrayUpload() 34 | { 35 | $this->assertSame([], BlockHelper::imageArrayUpload([ 36 | ['imageId' => 1], 37 | ['imageId' => 2] 38 | ])); 39 | } 40 | 41 | public function testFileUpload() 42 | { 43 | $this->assertFalse(BlockHelper::fileUpload(1)); 44 | } 45 | public function testFileArrayUpload() 46 | { 47 | $this->assertSame([], BlockHelper::fileArrayUpload( 48 | [ 49 | ['fileId' => 1], 50 | ['fileId' => 2] 51 | ] 52 | )); 53 | } 54 | 55 | public function testInternalGenerateLinkObject() 56 | { 57 | $url = BlockHelper::linkObject(['type' => 1, 'value' => 2]); 58 | $this->assertInstanceOf('luya\web\LinkInterface', $url); 59 | 60 | $this->assertSame('_self', $url->getTarget()); 61 | } 62 | 63 | public function testExternalGenerateLinkObject() 64 | { 65 | $url = BlockHelper::linkObject(['type' => 2, 'value' => 'https://luya.io']); 66 | $this->assertInstanceOf('luya\web\LinkInterface', $url); 67 | 68 | $this->assertSame('_blank', $url->getTarget()); 69 | } 70 | 71 | public function testMarkdown() 72 | { 73 | $this->assertSameTrimmed('

barfoo

', BlockHelper::markdown('**barfoo**')); 74 | } 75 | 76 | public function testRadioArrayOption() 77 | { 78 | $this->assertSame([ 79 | ['label' => 'bar', 'value' => 'foo'] 80 | ], BlockHelper::radioArrayOption(['foo' => 'bar'])); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /tests/src/helpers/UrlTest.php: -------------------------------------------------------------------------------- 1 | assertSame('foobar', Url::toModule('foobar')); 13 | $this->assertSame('foobar', Url::toModule('foobar', true)); 14 | } 15 | 16 | public function testToModuleRoute() 17 | { 18 | $this->expectException('luya\cms\Exception'); 19 | Url::toModuleRoute('foobar', ['/module/controller/action']); 20 | } 21 | 22 | public function testToMenuItem() 23 | { 24 | $this->assertStringContainsString('en/module/controller/action', Url::toMenuNavItem(1, ['/module/controller/action'])); 25 | $https = Url::toMenuNavItem(1, ['/module/controller/action'], 'https'); 26 | $this->assertStringContainsString('en/module/controller/action', $https); 27 | $this->assertStringContainsString('https://', $https); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/src/injectors/ActiveQueryCheckboxInjectorTest.php: -------------------------------------------------------------------------------- 1 | NavItem::find(), 'varName' => 'test', 'varLabel' => 'test label', 'context' => $block]); 29 | $injector->setup(); 30 | 31 | $vars = $block->getConfigVarsExport(); 32 | 33 | $v = $vars[0]; 34 | 35 | $this->assertSame('test', $v['var']); 36 | $this->assertSame('test label', $v['label']); 37 | 38 | $items = $v['options']['items']; 39 | 40 | $this->assertNotEmpty(count($items)); 41 | 42 | $item1 = $v['options']['items'][0]; 43 | 44 | $this->assertStringContainsString('Homepage, homepage,', $item1['label']); 45 | } 46 | 47 | public function testFieldSelectionBasicInjector() 48 | { 49 | $block = new Block(); 50 | $injector = new ActiveQueryCheckboxInjector(['query' => NavItem::find()->select(['title']), 'label' => 'title', 'varName' => 'test', 'varLabel' => 'test label', 'context' => $block]); 51 | $injector->setup(); 52 | 53 | $vars = $block->getConfigVarsExport(); 54 | 55 | $v = $vars[0]; 56 | 57 | $this->assertSame('test', $v['var']); 58 | $this->assertSame('test label', $v['label']); 59 | 60 | $items = $v['options']['items']; 61 | 62 | $this->assertNotEmpty(count($items)); 63 | 64 | $item1 = $v['options']['items'][0]; 65 | 66 | $this->assertSame('Homepage', $item1['label']); 67 | } 68 | 69 | /** 70 | * https://github.com/luyadev/luya/issues/1187 71 | */ 72 | public function testLabelLambda() 73 | { 74 | $block = new Block(); 75 | $injector = new ActiveQueryCheckboxInjector(['query' => NavItem::find(), 'label' => function ($model) { 76 | return $model->id . '@' . $model->title; 77 | }, 'varName' => 'test', 'varLabel' => 'test label', 'context' => $block]); 78 | $injector->setup(); 79 | $vars = $block->getConfigVarsExport(); 80 | $this->assertSame('1@Homepage', $vars[0]['options']['items'][0]['label']); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /tests/src/injectors/ActiveQuerySelectInjectorTest.php: -------------------------------------------------------------------------------- 1 | Layout::class, 19 | 'fixtureData' => [ 20 | 1 => [ 21 | 'id' => 1, 22 | 'name' => 'foo', 23 | 'json_config' => '{"node":"value"}', 24 | 'view_file' => 'none.php', 25 | ] 26 | ] 27 | ]); 28 | } 29 | 30 | public function testVariableResponse() 31 | { 32 | $block = new TestBlock(); 33 | $block->setVarValues([ 34 | 'foobar' => 1, 35 | ]); 36 | 37 | $injector = new ActiveQuerySelectInjector([ 38 | 'query' => Layout::find(), 39 | 'varName' => 'foobar', 40 | 'varLabel' => 'test', 41 | 'label' => 'name', 42 | 'context' => $block, 43 | ]); 44 | $injector->setup(); 45 | 46 | 47 | $f = $block->getExtraValue('foobar'); 48 | $x = $block->getVarValue('foobar'); 49 | $y = $block->getConfigVarsExport(); 50 | 51 | $this->assertSame('foo', $y[0]['options'][0]['label']); 52 | $this->assertSame(1, $x); 53 | $this->assertSame(['node' => 'value'], $f->getJsonConfig()); 54 | $this->assertSame('value', $f->getJsonConfig('node')); 55 | } 56 | 57 | public function testVariableNotFoundId() 58 | { 59 | $block = new TestBlock(); 60 | $block->setVarValues([ 61 | 'foobar' => 0, 62 | ]); 63 | 64 | $injector = new ActiveQuerySelectInjector([ 65 | 'query' => Layout::find(), 66 | 'varName' => 'foobar', 67 | 'varLabel' => 'test', 68 | 'label' => 'name', 69 | 'context' => $block, 70 | ]); 71 | $injector->setup(); 72 | 73 | $this->assertFalse($block->getExtraValue('foobar')); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/src/injectors/LinkInjectorTest.php: -------------------------------------------------------------------------------- 1 | $block]); 28 | $injector->setup(); 29 | 30 | $vars = $block->getConfigVarsExport(); 31 | 32 | $this->assertArrayHasKey('type', $vars[0]); 33 | $this->assertSame('zaa-link', $vars[0]['type']); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/src/injectors/TagInjectorTest.php: -------------------------------------------------------------------------------- 1 | createAdminLangFixture([ 34 | 1 => [ 35 | 'id' => 1, 36 | 'name' => 'en', 37 | 'short_code' => 'en', 38 | 'is_default' => 1, 39 | 'is_deleted' => 0, 40 | ] 41 | ]); 42 | } 43 | 44 | public function testTagInjector() 45 | { 46 | new ActiveRecordFixture([ 47 | 'modelClass' => Tag::class, 48 | 'fixtureData' => [ 49 | 'tag1' => [ 50 | 'id' => '1', 51 | 'name' => 'John', 52 | ], 53 | 'tag2' => [ 54 | 'id' => '2', 55 | 'name' => 'Jane', 56 | ], 57 | ] 58 | ]); 59 | 60 | $block = new StubTagBlock(); 61 | $injector = new TagInjector(['context' => $block]); 62 | $injector->setup(); 63 | 64 | $vars = $block->getConfigVarsExport(); 65 | 66 | $this->assertSame(['items' => [ 67 | ['label' => 'John', 'value' => 1], 68 | ['label' => 'Jane', 'value' => 2], 69 | ]], $vars[0]['options']); 70 | } 71 | 72 | public function testEvalTagInjector() 73 | { 74 | new ActiveRecordFixture([ 75 | 'modelClass' => Tag::class, 76 | 'fixtureData' => [ 77 | 'tag1' => [ 78 | 'name' => 'John', 79 | 'id' => '1', 80 | ], 81 | 'tag2' => [ 82 | 83 | 'name' => 'Jane', 84 | 'id' => '2', 85 | ], 86 | ] 87 | ]); 88 | 89 | $block = new StubTagBlock(); 90 | $block->setVarValues(['tags' => [['value' => 2]]]); 91 | $injector = new TagInjector(['context' => $block, 'varName' => 'tags']); 92 | $injector->setup(); 93 | $this->assertArrayHasKey('Jane', $injector->getAssignedTags()); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /tests/src/menu/InjectItemTest.php: -------------------------------------------------------------------------------- 1 | expectException('luya\cms\Exception'); 14 | $item = new InjectItem(['alias' => 'foo bar', 'childOf' => 0, 'title' => 'Hello Word']); 15 | $item->toArray(); 16 | } 17 | 18 | public function testToArray() 19 | { 20 | $item = new InjectItem(['alias' => 'foo bar', 'childOf' => 1, 'title' => 'Hello Word']); 21 | $a = $item->toArray(); 22 | 23 | $this->assertSame('homepage/foo-bar', $a['alias']); 24 | $this->assertSame('homepage/foo-bar', $item->alias); 25 | } 26 | 27 | public function testChainMethodToArray() 28 | { 29 | $array = (new InjectItem())->setAlias('bar-foo')->setItem(Yii::$app->menu->home)->setTitle('World Hello')->toArray(); 30 | 31 | $this->assertSame('homepage/bar-foo', $array['alias']); 32 | } 33 | 34 | public function testSetAliasFromTitle() 35 | { 36 | $object = (new InjectItem())->setTitle('Hello ! World!')->setChildOf(1); 37 | 38 | $this->assertSame('homepage/hello-world', $object->alias); 39 | 40 | $alis = (new InjectItem())->setTitle('Foo Bar')->setAlias('luya-alias')->setChildOf(1); 41 | 42 | $this->assertSame('homepage/luya-alias', $alis->alias); 43 | 44 | $notoverride = (new InjectItem())->setAlias('luya-io')->setTitle('Hello')->setChildOf(1); 45 | 46 | $this->assertSame('homepage/luya-io', $notoverride->alias); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/src/models/BlockGroupTest.php: -------------------------------------------------------------------------------- 1 | [ 13 | 'id' => 1, 14 | 'group_id' => 1, 15 | 'class' => 'path\to\Block', 16 | 'is_disabled' => 0, 17 | ] 18 | ]; 19 | 20 | public $modelClass = 'luya\cms\models\Block'; 21 | public $apiClass = 'luya\cms\admin\apis\BlockController'; 22 | public $controllerClass = 'luya\cms\admin\controllers\BlockController'; 23 | 24 | /* 25 | public function testFindOne() 26 | { 27 | $fixture = $this->modelFixture; 28 | 29 | $relationFixture = new ActiveRecordFixture([ 30 | 'modelClass' => 'luya\cms\models\NavItemPageBlockItem', 31 | 'fixtureData' => [ 32 | 'model1' => [ 33 | 'id' => '1', 34 | 'block_id' => '1', 35 | 'placeholder_var' => 'content', 36 | 'nav_item_page_id' => 0, 37 | 'prev_id' => '', 38 | 'json_config_values' => '{}', 39 | 'json_config_cfg_values' => '{}', 40 | 'is_dirty' => 0, 41 | 'create_user_id' => 1, 42 | 'update_user_id' => 1, 43 | 'timestamp_create' => time(), 44 | 'timestamp_update' => time(), 45 | ] 46 | ] 47 | ]); 48 | 49 | $pageFixture = new ActiveRecordFixture([ 50 | 'modelClass' => 'luya\cms\models\NavItemPage', 51 | ]); 52 | 53 | $pageFixture = new ActiveRecordFixture([ 54 | 'modelClass' => 'luya\cms\models\Log', 55 | ]); 56 | 57 | // get existing 58 | $block = $fixture->getModel('model1'); 59 | $this->assertSame(1, $block->id); 60 | $this->assertEquals(1, $block->usageCount); 61 | $this->assertSame(1, $block->delete()); 62 | 63 | 64 | 65 | // add new model 66 | $model = $fixture->getNewModel(); 67 | $model->attributes = ['group_id' => 2, 'class' => 'FooBar', 'is_disabled' => 0]; 68 | $this->assertTrue($model->save()); 69 | //$this->assertSame(0, $model->fileExists); 70 | 71 | } 72 | */ 73 | 74 | public function testControllerMethods() 75 | { 76 | $this->assertNull($this->api->actionToFav()); 77 | $this->assertNull($this->api->actionRemoveFav()); 78 | $this->assertNull($this->api->actionToggleGroup()); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /tests/src/models/NavContainerTest.php: -------------------------------------------------------------------------------- 1 | app, function (PageScope $scope) { 18 | $this->createAdminGroupFixture(1); 19 | $this->createAdminUserFixture(); 20 | 21 | $this->createCmsWebsiteFixture([ 22 | [ 23 | 'id' => 2, 24 | 'name' => 'test', 25 | 'host' => 'test', 26 | 'aliases' => '', 27 | 'is_default' => 0, 28 | 'is_active' => 1, 29 | 'is_deleted' => 0, 30 | ] 31 | ]); 32 | $this->createCmsNavContainerFixture([ 33 | [ 34 | 'id' => 2, 35 | 'name' => 'test container', 36 | 'alias' => 'test container', 37 | 'website_id' => 2, 38 | 'is_deleted' => 0, 39 | ] 40 | ]); 41 | Yii::$app->request->setHostInfo("http://test"); 42 | 43 | $this->assertFalse(NavContainer::find()->andWhere(['id' => 1])->exists()); 44 | 45 | $navContainer = NavContainer::findOne(2); 46 | 47 | $this->assertEquals(2, $navContainer->website_id); 48 | $this->assertSame('test container', $navContainer->name); 49 | 50 | $website = $navContainer->website; 51 | 52 | $this->assertEquals(2, $website->id); 53 | $this->assertSame('test', $website->name); 54 | }); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/src/models/NavItemModuleTest.php: -------------------------------------------------------------------------------- 1 | NavItemModule::class, 15 | ]); 16 | 17 | $model = $fixture->newModel; 18 | $model->action_params = ['foo' => 'bar']; 19 | $model->validate(); 20 | 21 | // test encoding 22 | $this->assertSame('{"foo":"bar"}', $model->action_params); 23 | $this->assertSame(['foo' => 'bar'], $model->getDecodedActionParams()); 24 | $model->action_params = $model->getDecodedActionParams(); 25 | $this->assertSame(['foo' => 'bar'], $model->getDecodedActionParams()); // if already is array 26 | 27 | 28 | // empty model test 29 | $emptyModel = $fixture->newModel; 30 | 31 | $this->assertSame([], $emptyModel->getDecodedActionParams()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/src/models/NavItemPageBlockItemTest.php: -------------------------------------------------------------------------------- 1 | NavItemPageBlockItem::class, 18 | ]); 19 | 20 | new NgRestModelFixture([ 21 | 'modelClass' => NavItemPage::class, 22 | ]); 23 | 24 | new NgRestModelFixture([ 25 | 'modelClass' => Block::class, 26 | 'fixtureData' => [ 27 | 1 => [ 28 | 'id' => 1, 29 | ] 30 | ] 31 | ]); 32 | 33 | new NgRestModelFixture([ 34 | 'modelClass' => Log::class, 35 | ]); 36 | 37 | $model = $fixtures->newModel; 38 | $model->block_id = 1; 39 | $model->placeholder_var = 'container'; 40 | 41 | $this->assertTrue($model->save()); 42 | 43 | $model->prev_id = 1; 44 | $this->assertFalse($model->update()); 45 | 46 | $this->assertArrayHasKey('prev_id', $model->getErrors()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/src/models/NavItemTest.php: -------------------------------------------------------------------------------- 1 | createCmsNavItemFixture(); 18 | $model = new NavItem(); 19 | 20 | $model->alias = "äÄöÖüÜß<>"; 21 | $model->slugifyAlias(); 22 | $this->assertSame("ääööüüß", $model->alias); 23 | 24 | $model->alias = "這是 LUYA"; 25 | $model->slugifyAlias(); 26 | $this->assertSame("這是-luya", $model->alias); 27 | 28 | $model->alias = "a1Zあ新~!@#$^&*()_[];',:?"; 29 | $model->slugifyAlias(); 30 | $this->assertSame("a1zあ新~!@#$^&*()[];',:?", $model->alias); 31 | } 32 | 33 | public function testGetDefaultLanguageRelationGetter() 34 | { 35 | $this->createCmsNavFixture([ 36 | 1 => [ 37 | 'id' => 1, 38 | ] 39 | ]); 40 | 41 | $this->createCmsNavItemFixture([ 42 | 1 => [ 43 | 'id' => 1, 44 | 'nav_id' => 1, 45 | 'lang_id' => 1, 46 | ] 47 | ]); 48 | 49 | $this->createAdminLangFixture([ 50 | 1 => [ 51 | 'id' => 1, 52 | 'name' => 'English', 53 | 'short_code' => 'en', 54 | 'is_default' => 1, 55 | 'is_deleted' => 0, 56 | ] 57 | ]); 58 | 59 | $nav = Nav::findOne(1); 60 | 61 | $this->assertSame(1, $nav->id); 62 | $this->assertSame(1, $nav->defaultLanguageItem->id); 63 | $this->assertSame(1, $nav->activeLanguageItem->id); 64 | } 65 | 66 | public function testEmptyValidatorForNavItemTypeId() 67 | { 68 | $fixture = new NgRestModelFixture([ 69 | 'modelClass' => NavItem::class, 70 | ]); 71 | 72 | $model = $fixture->newModel; 73 | 74 | $model->isNewRecord = false; 75 | $model->nav_item_type_id = 0; 76 | $this->assertFalse($model->validate(['nav_item_type_id'])); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /tests/src/models/NavTest.php: -------------------------------------------------------------------------------- 1 | activeLanguageItem; 16 | 17 | $this->assertSame('Homepage', $item->title); 18 | $this->assertSame('homepage', $item->alias); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/src/models/ThemeTest.php: -------------------------------------------------------------------------------- 1 | Theme::class 15 | ]); 16 | 17 | $theme = new Theme(); 18 | $values = [ 19 | 'name' => 'lorem', 20 | 'parentTheme' => 'ipsum', 21 | 'author' => 'me', 22 | ]; 23 | $theme->json_config = json_encode($values, JSON_FORCE_OBJECT); 24 | 25 | $theme->afterFind(); 26 | 27 | $this->assertSame('lorem', $theme->getName()); 28 | $this->assertSame('ipsum', $theme->getParentTheme()); 29 | $this->assertSame('me', $theme->getAuthor()); 30 | 31 | $this->assertSame($values, $theme->getJsonConfig()); 32 | $this->assertNull($theme->getJsonConfig('foo')); 33 | } 34 | 35 | public function testInvalidJsonConfig() 36 | { 37 | $fixture = new NgRestModelFixture([ 38 | 'modelClass' => Theme::class 39 | ]); 40 | 41 | $theme = new Theme(); 42 | $theme->json_config = '}['; 43 | 44 | $theme->afterFind(); 45 | 46 | $this->assertEmpty($theme->getJsonConfig()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/src/tags/MenuTagTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('Homepage', $tag->parse(1, null)); 15 | $this->assertEquals('foobar', $tag->parse(1, 'foobar')); 16 | 17 | $this->assertEquals('Page 1', $tag->parse(2, null)); 18 | $this->assertEquals('foobar', $tag->parse(2, 'foobar')); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/src/tags/PageTagTest.php: -------------------------------------------------------------------------------- 1 | assertSame('
', $tag->parse('1', null)); 14 | } 15 | 16 | public function testContentPlaceholderResponse() 17 | { 18 | $tag = new PageTag(); 19 | $this->assertSame('', $tag->parse(1, 'content')); 20 | } 21 | 22 | 23 | public function testRedirectWrongItemTypeResponse() 24 | { 25 | $tag = new PageTag(); 26 | $this->assertNull($tag->parse(14, 'content')); 27 | } 28 | 29 | public function testRedirectWrongItemTypeResponseWithoutPlaceholder() 30 | { 31 | $tag = new PageTag(); 32 | $this->assertNull($tag->parse(14, null)); 33 | } 34 | 35 | public function testContentNotFoundException() 36 | { 37 | $tag = new PageTag(); 38 | $this->assertNull($tag->parse(9999, 'content')); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/src/widgets/LangSwitcherTest.php: -------------------------------------------------------------------------------- 1 | assertSame(str_replace(["\r\n", "\r"], "\n", ''), str_replace(["\r\n", "\r"], "\n", $out)); 18 | } 19 | 20 | public function testCallable() 21 | { 22 | $out = LangSwitcher::widget(['linkLabel' => function ($lang) { 23 | return strtoupper($lang['short_code']); 24 | }]); 25 | 26 | $this->assertSame(str_replace(["\r\n", "\r"], "\n", '
    27 |
  • EN
  • 28 |
  • DE
  • 29 |
'), str_replace(["\r\n", "\r"], "\n", $out)); 30 | } 31 | 32 | public function testSortCallable() 33 | { 34 | $out = LangSwitcher::widget(['itemsCallback' => function ($items) { 35 | ksort($items); 36 | 37 | return $items; 38 | }]); 39 | 40 | 41 | $this->assertSame(str_replace(["\r\n", "\r"], "\n", ''), str_replace(["\r\n", "\r"], "\n", $out)); 45 | } 46 | 47 | public function testOutputWithoutUl() 48 | { 49 | $out = LangSwitcher::widget(['noListTag' => true]); 50 | 51 | $this->assertSame(str_replace(["\r\n", "\r"], "\n", '
  • English
  • 52 |
  • Deutsch
  • '), str_replace(["\r\n", "\r"], "\n", $out)); 53 | } 54 | } 55 | --------------------------------------------------------------------------------