├── .gitignore ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── composer.json ├── docs ├── create_plugin.md ├── img │ ├── demo_events.jpg │ ├── event_edit.jpg │ ├── tab_events.jpg │ ├── tab_info.jpg │ ├── tab_install.jpg │ └── tab_plugins.jpg └── install_plugin.md └── src ├── BasePlugin.php ├── BaseShortcode.php ├── Module.php ├── components ├── FlashNotification.php ├── PluginsManager.php ├── Transaction.php ├── View.php └── ViewEvent.php ├── controllers ├── CategoryController.php ├── EventController.php ├── PluginController.php └── ShortcodeController.php ├── core ├── SeoHandler.php ├── ShortcodeHandler.php ├── extralinks │ ├── ExternalLinks.php │ ├── README.md │ ├── RedirectController.php │ ├── RedirectEvent.php │ └── extralinks.jpg ├── helloworld │ ├── HelloWorld.php │ └── README.md └── httpauth │ ├── Httpauth.php │ └── README.md ├── dto ├── EventsDiffDto.php ├── EventsPoolDto.php ├── PluginDataDto.php ├── PluginsDiffDto.php ├── PluginsPoolDto.php ├── ShortcodesDbCallbacksDto.php ├── ShortcodesDiffDto.php └── ShortcodesPoolDto.php ├── helpers ├── BS.php ├── ClassHelper.php ├── JsonHelper.php └── ShortcodesHelper.php ├── interfaces ├── IPlugin.php └── IShortcode.php ├── messages ├── en │ └── plugin.php └── ru │ └── plugin.php ├── migrations ├── Migration.php ├── m170105_094230_drop_tables.php ├── m170105_094233_plugins_app.php ├── m170105_094235_plugins_category.php ├── m170105_094917_plugins_plugin.php ├── m170105_094942_plugins_event.php ├── m170105_094958_plugins_shortcode.php └── m170105_094960_seo_clear_url.php ├── models ├── App.php ├── Category.php ├── Event.php ├── Plugin.php ├── Shortcode.php ├── query │ ├── CategoryQuery.php │ ├── EventQuery.php │ ├── PluginQuery.php │ └── ShortcodeQuery.php └── search │ ├── CategorySearch.php │ ├── EventSearch.php │ ├── PluginSearch.php │ └── ShortcodeSearch.php ├── repositories ├── EventDbRepository.php ├── EventDbRepositoryMap.php ├── EventDirRepository.php ├── EventRepository.php ├── PluginDbRepository.php ├── PluginDbRepositoryMap.php ├── PluginDirRepository.php ├── PluginRepository.php ├── ShortcodeDbRepository.php ├── ShortcodeDbRepositoryMap.php ├── ShortcodeDirRepository.php └── ShortcodeRepository.php ├── services ├── PluginService.php └── ShortcodeService.php ├── shortcodes ├── ShortcodeParser.php ├── ShortcodeParserMap.php └── ShortcodeWidget.php ├── validators ├── CallableValidator.php ├── ClassNameValidator.php └── JsonValidator.php └── views ├── _menu.php ├── category ├── _form.php ├── _search.php ├── create.php ├── index.php ├── update.php └── view.php ├── event ├── _form.php ├── _search.php ├── create.php ├── index.php ├── update.php └── view.php ├── plugin ├── _form.php ├── _item.php ├── _search.php ├── create.php ├── index.php ├── info.php ├── install.php ├── update.php └── view.php └── shortcode ├── _form.php ├── _search.php ├── index.php └── update.php /.gitignore: -------------------------------------------------------------------------------- 1 | ### Composer 2 | composer.phar 3 | composer.lock 4 | vendor/ 5 | 6 | phpunit.xml 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to this project 2 | 3 | Please take a moment to review this document in order to make the contribution 4 | process easy and effective for everyone involved. 5 | 6 | Following these guidelines helps to communicate that you respect the time of 7 | the developers managing and developing this open source project. In return, 8 | they should reciprocate that respect in addressing your issue or assessing 9 | patches and features. 10 | 11 | ## Using the issue tracker 12 | 13 | The issue tracker is the preferred channel for [bug reports](#bugs), 14 | [features requests](#features) and [submitting pull 15 | requests](#pull-requests), but please respect the following restrictions: 16 | 17 | * Please **do not** use the issue tracker for personal support requests. 18 | 19 | * Please **do not** derail or troll issues. Keep the discussion on topic and 20 | respect the opinions of others. 21 | 22 | 23 | 24 | ## Bug reports 25 | 26 | A bug is a _demonstrable problem_ that is caused by the code in the repository. 27 | Good bug reports are extremely helpful - thank you! 28 | 29 | Guidelines for bug reports: 30 | 31 | 1. **Use the GitHub issue search** — check if the issue has already been 32 | reported. 33 | 34 | 2. **Check if the issue has been fixed** — try to reproduce it using the 35 | latest `master` or development branch in the repository. 36 | 37 | 3. **Isolate the problem** — create a [reduced test 38 | case](http://css-tricks.com/reduced-test-cases/) and a live example. 39 | 40 | A good bug report shouldn't leave others needing to chase you up for more 41 | information. Please try to be as detailed as possible in your report. What is 42 | your environment? What steps will reproduce the issue? What browser(s) and OS 43 | experience the problem? What would you expect to be the outcome? All these 44 | details will help people to fix any potential bugs. 45 | 46 | Example: 47 | 48 | > Short and descriptive example bug report title 49 | > 50 | > A summary of the issue and the Yii2 and Yii2-plugins-system versions in which it occurs. If 51 | > suitable, include the steps required to reproduce the bug. 52 | > 53 | > 1. This is the first step 54 | > 2. This is the second step 55 | > 3. Further steps, etc. 56 | > 57 | > `` - a link to the reduced test case 58 | > 59 | > Any other information you want to share that is relevant to the issue being 60 | > reported. This might include the lines of code that you have identified as 61 | > causing the bug, and potential solutions (and your opinions on their 62 | > merits). 63 | 64 | 65 | 66 | ## Feature requests 67 | 68 | Feature requests are welcome. But take a moment to find out whether your idea 69 | fits with the scope and aims of the project. It's up to *you* to make a strong 70 | case to convince the project's developers of the merits of this feature. Please 71 | provide as much detail and context as possible. 72 | 73 | 74 | 75 | ## Pull requests 76 | 77 | Good pull requests - patches, improvements, new features - are a fantastic 78 | help. They should remain focused in scope and avoid containing unrelated 79 | commits. 80 | 81 | **Please ask first** before embarking on any significant pull request (e.g. 82 | implementing features, refactoring code, porting to a different language), 83 | otherwise you risk spending a lot of time working on something that the 84 | project's developers might not want to merge into the project. 85 | 86 | Please adhere to the coding conventions used throughout a project (indentation, 87 | accurate comments, etc.) and any other requirements (such as test coverage). 88 | 89 | Follow this process if you'd like your work considered for inclusion in the 90 | project: 91 | 92 | 1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork, 93 | and configure the remotes: 94 | 95 | ```bash 96 | # Clone your fork of the repo into the current directory 97 | git clone https://github.com// 98 | # Navigate to the newly cloned directory 99 | cd 100 | # Assign the original repo to a remote called "upstream" 101 | git remote add upstream https://github.com// 102 | ``` 103 | 104 | 2. If you cloned a while ago, get the latest changes from upstream: 105 | 106 | ```bash 107 | git checkout 108 | git pull upstream 109 | ``` 110 | 111 | 3. Create a new topic branch (off the main project development branch) to 112 | contain your feature, change, or fix: 113 | 114 | ```bash 115 | git checkout -b 116 | ``` 117 | 118 | 4. Commit your changes in logical chunks. Please adhere to these [git commit 119 | message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 120 | or your code is unlikely be merged into the main project. Use Git's 121 | [interactive rebase](https://help.github.com/articles/interactive-rebase) 122 | feature to tidy up your commits before making them public. 123 | 124 | 5. Locally merge (or rebase) the upstream development branch into your topic branch: 125 | 126 | ```bash 127 | git pull [--rebase] upstream 128 | ``` 129 | 130 | 6. Push your topic branch up to your fork: 131 | 132 | ```bash 133 | git push origin 134 | ``` 135 | 136 | 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) 137 | with a clear title and description. 138 | 139 | **IMPORTANT**: By submitting a patch, you agree to allow the project owner to 140 | license your work under the same license as that used by the project. 141 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 LoveOrigami 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 all 13 | 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 THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Getting started with Yii2-plugins-system 2 | [![Latest Stable Version](https://poser.pugx.org/loveorigami/yii2-plugins-system/v/stable)](https://packagist.org/packages/loveorigami/yii2-plugins-system) 3 | [![Total Downloads](https://poser.pugx.org/loveorigami/yii2-plugins-system/downloads)](https://packagist.org/packages/loveorigami/yii2-plugins-system) 4 | [![License](https://poser.pugx.org/loveorigami/yii2-plugins-system/license)](https://packagist.org/packages/loveorigami/yii2-plugins-system) 5 | 6 | Yii2-plugins-system is designed to work out of the box. It means that installation requires 7 | minimal steps. Only one configuration step should be taken and you are ready to 8 | have plugin system on your Yii2 website. 9 | 10 | !["Plugins"](docs/img/tab_plugins.jpg) 11 | 12 | ### 1. Download 13 | 14 | Yii2-plugins-system can be installed using composer. Run following command to download and 15 | install Yii2-plugins-system: 16 | 17 | ```bash 18 | composer require "loveorigami/yii2-plugins-system": ">=3.*" 19 | ``` 20 | 21 | ### 2. Update database schema 22 | 23 | The last thing you need to do is updating your database schema by applying the 24 | migrations. Make sure that you have properly configured `db` application component, 25 | add in our console config namespace migration - [more here](http://www.yiiframework.com/doc-2.0/guide-db-migrations.html#namespaced-migrations) 26 | 27 | ```php 28 | return [ 29 | 'controllerMap' => [ 30 | 'migrate' => [ 31 | 'class' => 'yii\console\controllers\MigrateController', 32 | 'migrationNamespaces' => [ 33 | ... 34 | 'lo\plugins\migrations' 35 | ], 36 | ], 37 | ], 38 | ]; 39 | ``` 40 | 41 | and run the following command: 42 | 43 | ```php 44 | $ php yii migrate 45 | ``` 46 | 47 | ### 3. Configure application 48 | 49 | Let's start with defining module in `@backend/config/main.php`: 50 | 51 | ```php 52 | 'modules' => [ 53 | 'plugins' => [ 54 | 'class' => 'lo\plugins\Module', 55 | 'pluginsDir'=>[ 56 | '@lo/plugins/core', // default dir with core plugins 57 | // '@common/plugins', // dir with our plugins 58 | ] 59 | ], 60 | ], 61 | ``` 62 | That's all, now you have module installed and configured in advanced template. 63 | 64 | Next, open `@frontend/config/main.php` and add following: 65 | 66 | ```php 67 | ... 68 | 'bootstrap' => ['log', 'plugins'], 69 | ... 70 | 'components' => [ 71 | 'plugins' => [ 72 | 'class' => lo\plugins\components\PluginsManager::class, 73 | 'appId' => 1 // lo\plugins\BasePlugin::APP_FRONTEND, 74 | // by default 75 | 'enablePlugins' => true, 76 | 'shortcodesParse' => true, 77 | 'shortcodesIgnoreBlocks' => [ 78 | ']*>' => '<\/pre>', 79 | //'
=2.0.10", 25 | "php": ">=5.5.0", 26 | "loveorigami/yii2-jsoneditor": "*" 27 | }, 28 | "autoload": { 29 | "psr-4": { 30 | "lo\\plugins\\": "src/" 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /docs/create_plugin.md: -------------------------------------------------------------------------------- 1 | # Create your plugin 2 | 3 | To create your plugin you need to run the following required steps 4 | 5 | ### 1. Create in dir with our plugins `@common\plugins` new folder: 6 | * For example: `test` 7 | 8 | ### 2. In this folder create: 9 | * `README.md` with usage instruction for this plugin 10 | * New class `TestPlugin`, with information about plugin 11 | 12 | ```php 13 | 14 | use lo\plugins\BasePlugin; 15 | 16 | namespace common\plugins\test; 17 | 18 | /** 19 | * Plugin Name: Test plugin 20 | * Plugin URI: 21 | * Version: 1.0 22 | * Description: Small test plugin 23 | * Author: Andrey Lukyanov 24 | * Author URI: https://github.com/loveorigami 25 | */ 26 | 27 | class TestPlugin extends BasePlugin 28 | { 29 | ... 30 | } 31 | 32 | ``` 33 | 34 | * Add static property `$appId` 35 | 36 | ```php 37 | 38 | /** 39 | * Application id, where plugin will be worked. 40 | * @var appId integer 41 | */ 42 | public static $appId = self::APP_FRONTEND; 43 | 44 | ``` 45 | 46 | * And default configuration 47 | 48 | ```php 49 | /** 50 | * Default configuration for plugin. 51 | * @var config array() 52 | */ 53 | public static $config = [ 54 | 'term' => 'Hello, world!', 55 | ]; 56 | ``` 57 | 58 | * Then, assign a template events 59 | 60 | ```php 61 | public static function events() 62 | { 63 | return [ 64 | $eventSenderClassName => [ 65 | $eventName => [$handlerMethodName, self::$config] 66 | ], 67 | ]; 68 | } 69 | ``` 70 | 71 | for example: 72 | 73 | ```php 74 | public static function events() 75 | { 76 | return [ 77 | yii\web\Response::class => [ 78 | yii\web\Response::EVENT_AFTER_PREPARE => ['foo', self::$config] 79 | ], 80 | ]; 81 | } 82 | ``` 83 | more about `$eventSenderClassName` and `$eventName` you can be found on the info tab of this module 84 | 85 | !["Info tab"](img/tab_info.jpg) 86 | 87 | * Create a handler method `foo` with the necessary logic 88 | 89 | ```php 90 | /** 91 | * handler method foo 92 | */ 93 | public static function foo($event) 94 | { 95 | $term = ($event->data['term']) ? $event->data['term'] : self::$config['term']; 96 | $event->sender->content = str_replace($term,"

$term

", $event->sender->content); 97 | return true; 98 | } 99 | ``` 100 | 101 | * That's all. Then you have to [install](install_plugin.md) this plugin -------------------------------------------------------------------------------- /docs/img/demo_events.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loveorigami/yii2-plugins-system/9f2d926237910b5ff24d2c6e0993a7f3ba4607f1/docs/img/demo_events.jpg -------------------------------------------------------------------------------- /docs/img/event_edit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loveorigami/yii2-plugins-system/9f2d926237910b5ff24d2c6e0993a7f3ba4607f1/docs/img/event_edit.jpg -------------------------------------------------------------------------------- /docs/img/tab_events.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loveorigami/yii2-plugins-system/9f2d926237910b5ff24d2c6e0993a7f3ba4607f1/docs/img/tab_events.jpg -------------------------------------------------------------------------------- /docs/img/tab_info.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loveorigami/yii2-plugins-system/9f2d926237910b5ff24d2c6e0993a7f3ba4607f1/docs/img/tab_info.jpg -------------------------------------------------------------------------------- /docs/img/tab_install.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loveorigami/yii2-plugins-system/9f2d926237910b5ff24d2c6e0993a7f3ba4607f1/docs/img/tab_install.jpg -------------------------------------------------------------------------------- /docs/img/tab_plugins.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loveorigami/yii2-plugins-system/9f2d926237910b5ff24d2c6e0993a7f3ba4607f1/docs/img/tab_plugins.jpg -------------------------------------------------------------------------------- /docs/install_plugin.md: -------------------------------------------------------------------------------- 1 | # Install plugin 2 | 3 | After [creating](create_plugin.md) your `TestPlugin` first, you must make sure that the our directory plugins included in the module configuration 4 | 5 | ```php 6 | 'modules' => [ 7 | 'plugins' => [ 8 | 'class' => 'lo\plugins\Module', 9 | 'pluginsDir'=>[ 10 | '@lo/plugins/plugins', // default dir with core plugins 11 | '@common/plugins', // dir with our plugins 12 | ] 13 | ], 14 | ], 15 | ``` 16 | 17 | * Then go to the install tab and press button 18 | 19 | !["Install tab"](img/tab_install.jpg) 20 | 21 | * Go to the events tab for enabled and configure plugin event 22 | 23 | !["Events tab"](img/tab_events.jpg) 24 | 25 | * If you want, change configuration, update... 26 | 27 | !["Event edit"](img/event_edit.jpg) 28 | 29 | * Go to the website to see the result 30 | 31 | !["Result"](img/demo_events.jpg) -------------------------------------------------------------------------------- /src/BasePlugin.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | abstract class BasePlugin implements IPlugin 12 | { 13 | const APP_FRONTEND = 1; 14 | const APP_BACKEND = 2; 15 | const APP_COMMON = 3; 16 | const APP_API = 4; 17 | const APP_CONSOLE = 5; 18 | 19 | /** 20 | * Application id, where plugin will be worked. 21 | * Support values: frontend, backend, common, api 22 | * Default: frontend 23 | * @var string $appId 24 | */ 25 | public static $appId = self::APP_FRONTEND; 26 | 27 | /** 28 | * Default configuration for plugin. 29 | * @var array $config 30 | */ 31 | public static $config = []; 32 | 33 | } -------------------------------------------------------------------------------- /src/BaseShortcode.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | abstract class BaseShortcode implements IShortcode 12 | { 13 | const APP_FRONTEND = 1; 14 | const APP_BACKEND = 2; 15 | const APP_COMMON = 3; 16 | 17 | const SHORTCODES_METHOD = 'shortcodes'; 18 | 19 | /** 20 | * Application id, where plugin will be worked. 21 | * Support values: frontend, backend, common, api 22 | * Default: frontend 23 | * @var string $appId 24 | */ 25 | public static $appId = self::APP_FRONTEND; 26 | 27 | } -------------------------------------------------------------------------------- /src/Module.php: -------------------------------------------------------------------------------- 1 | i18n->translations['plugin'])) { 21 | Yii::$app->i18n->translations['plugin'] = [ 22 | 'class' => 'yii\i18n\PhpMessageSource', 23 | 'sourceLanguage' => 'en', 24 | 'basePath' => '@lo/plugins/messages' 25 | ]; 26 | } 27 | 28 | //user did not define the Navbar? 29 | if (!$this->pluginsDir) { 30 | throw new InvalidConfigException('"pluginsDir" must be set'); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/components/FlashNotification.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class FlashNotification 13 | { 14 | /** 15 | * @param $message 16 | */ 17 | public function success($message) 18 | { 19 | Yii::$app->session->setFlash('success', $message); 20 | } 21 | 22 | /** 23 | * @param $message 24 | */ 25 | public function error($message) 26 | { 27 | Yii::$app->session->setFlash('error', $message); 28 | } 29 | } -------------------------------------------------------------------------------- /src/components/PluginsManager.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class PluginsManager extends Component implements BootstrapInterface 20 | { 21 | /** 22 | * Application id for category plugins. 23 | * Support constants: APP_FRONTEND, APP_BACKEND, APP_COMMON 24 | * @var integer $appId 25 | */ 26 | public $appId; 27 | 28 | /** 29 | * Attaches events to all app models. 30 | * @var bool 31 | */ 32 | public $enablePlugins = true; 33 | 34 | /** 35 | * Shortcodes plugin 36 | * @var bool 37 | */ 38 | public $shortcodesParse = true; 39 | 40 | /** 41 | * Ignore blocks from parsing. 42 | * Set as array regex ['openTag' => 'closeTag'] 43 | * ``` 44 | * [ 45 | * ']*>' => '<\/pre>', 46 | * ']*>' => '<\/style>', 47 | * ']*>' => '<\/script>', 48 | * ] 49 | * ``` 50 | * @var null|array 51 | */ 52 | public $shortcodesIgnoreBlocks = null; 53 | 54 | 55 | /** 56 | * @param \yii\base\Application $app 57 | * @throws InvalidConfigException 58 | */ 59 | public function bootstrap($app) 60 | { 61 | 62 | if (!isset($app->plugins)) { 63 | throw new InvalidConfigException('Component "plugins" must be set'); 64 | } 65 | 66 | if ($this->enablePlugins && $this->appId) { 67 | $this->registerEvents($this->appId); 68 | } 69 | 70 | if ($this->shortcodesParse) { 71 | Yii::$container->setSingleton(ShortcodeParser::class); 72 | Yii::$container->set(ShortcodeService::class); 73 | Event::on(View::class, View::EVENT_DO_BODY, [ 74 | ShortcodeHandler::class, ShortcodeHandler::PARSE_SHORTCODES 75 | ], $this); 76 | } 77 | } 78 | 79 | /** 80 | * @param $appId 81 | */ 82 | protected function registerEvents($appId) 83 | { 84 | $repository = new EventDbRepository(); 85 | /** @var \lo\plugins\models\Event [] $events */ 86 | $events = $repository->findEventsByApp($appId); 87 | if ($events) { 88 | foreach ($events as $event) { 89 | $triggerClass = $event->getTriggerClass(); 90 | $triggerEvent = $event->getTriggerEvent(); 91 | $handler = $event->getHandler(); 92 | if (is_array($handler) && is_callable($handler[0])) { 93 | $data = isset($handler[1]) ? array_pop($handler) : null; 94 | $append = isset($handler[2]) ? array_pop($handler) : null; 95 | Event::on($triggerClass, $triggerEvent, $handler[0], $data, $append); 96 | } else if (is_callable($handler)) { 97 | Event::on($triggerClass, $triggerEvent, $handler); 98 | } 99 | } 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /src/components/Transaction.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class Transaction 13 | { 14 | /** 15 | * @return \yii\db\Transaction 16 | */ 17 | public function begin() 18 | { 19 | return Yii::$app->db->beginTransaction(); 20 | } 21 | 22 | /** 23 | * @param \yii\db\Transaction $transaction 24 | */ 25 | public function commit($transaction) 26 | { 27 | $transaction->commit(); 28 | } 29 | 30 | /** 31 | * @param \yii\db\Transaction $transaction 32 | */ 33 | public function rollBack($transaction) 34 | { 35 | $transaction->rollBack(); 36 | } 37 | } -------------------------------------------------------------------------------- /src/components/View.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class View extends WebView 13 | { 14 | /** 15 | * @event Event an event that is triggered by [[doBody()]]. 16 | */ 17 | const EVENT_DO_BODY = 'doBody'; 18 | 19 | /** 20 | * @var string 21 | */ 22 | private $_body; 23 | private $_from_ajax = false; 24 | 25 | /** 26 | * Content manipulation. Need for correct replacement shortcodes 27 | */ 28 | public function doBody() 29 | { 30 | if ($this->hasEventHandlers(self::EVENT_DO_BODY)) { 31 | $event = new ViewEvent([ 32 | 'content' => $this->_body, 33 | ]); 34 | $this->trigger(self::EVENT_DO_BODY, $event); 35 | $this->_body = $event->content; 36 | } 37 | } 38 | 39 | /** 40 | * Renders a view in response to an AJAX request. 41 | * 42 | * This method is similar to [[render()]] except that it will surround the view being rendered 43 | * with the calls of [[beginPage()]], [[head()]], [[beginBody()]], [[endBody()]] and [[endPage()]]. 44 | * By doing so, the method is able to inject into the rendering result with JS/CSS scripts and files 45 | * that are registered with the view. 46 | * 47 | * @param string $view the view name. Please refer to [[render()]] on how to specify this parameter. 48 | * @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file. 49 | * @param object $context the context that the view should use for rendering the view. If null, 50 | * existing [[context]] will be used. 51 | * @return string the rendering result 52 | * @see render() 53 | */ 54 | public function renderAjax($view, $params = [], $context = null) 55 | { 56 | $viewFile = $this->findViewFile($view, $context); 57 | $this->_body = $this->renderFile($viewFile, $params, $context); 58 | $this->_from_ajax = true; 59 | 60 | ob_start(); 61 | ob_implicit_flush(false); 62 | 63 | $this->beginPage(); 64 | $this->head(); 65 | $this->beginBody(); 66 | $this->doBody(); 67 | echo $this->_body; 68 | $this->endBody(); 69 | $this->endPage(true); 70 | 71 | return ob_get_clean(); 72 | } 73 | 74 | /** 75 | * Marks the ending of an HTML body section. 76 | */ 77 | public function endBody() 78 | { 79 | if (!$this->_body) { 80 | $this->_body = ob_get_clean(); 81 | $this->doBody(); 82 | ob_start(); 83 | } 84 | 85 | $this->trigger(self::EVENT_END_BODY); 86 | echo self::PH_BODY_END; 87 | 88 | foreach (array_keys($this->assetBundles) as $bundle) { 89 | $this->registerAssetFiles($bundle); 90 | } 91 | } 92 | 93 | /** 94 | * Marks the ending of an HTML page. 95 | * @param bool $ajaxMode whether the view is rendering in AJAX mode. 96 | * If true, the JS scripts registered at [[POS_READY]] and [[POS_LOAD]] positions 97 | * will be rendered at the end of the view like normal scripts. 98 | */ 99 | /** 100 | * Marks the ending of an HTML page. 101 | * @param bool $ajaxMode whether the view is rendering in AJAX mode. 102 | * If true, the JS scripts registered at [[POS_READY]] and [[POS_LOAD]] positions 103 | * will be rendered at the end of the view like normal scripts. 104 | */ 105 | public function endPage($ajaxMode = false) 106 | { 107 | $this->trigger(self::EVENT_END_PAGE); 108 | $endPage = ob_get_clean(); 109 | 110 | if ($this->_from_ajax) { 111 | $content = $endPage; 112 | } else { 113 | $content = $this->_body . $endPage; 114 | } 115 | 116 | echo strtr($content, [ 117 | self::PH_HEAD => $this->renderHeadHtml(), 118 | self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(), 119 | self::PH_BODY_END => $this->renderBodyEndHtml($ajaxMode), 120 | ]); 121 | 122 | $this->clear(); 123 | } 124 | } -------------------------------------------------------------------------------- /src/components/ViewEvent.php: -------------------------------------------------------------------------------- 1 | [ 21 | 'class' => VerbFilter::class, 22 | 'actions' => [ 23 | 'delete' => ['post'], 24 | ], 25 | ], 26 | ]; 27 | } 28 | 29 | /** 30 | * Lists all Category models. 31 | * @return mixed 32 | */ 33 | public function actionIndex() 34 | { 35 | $searchModel = new CategorySearch(); 36 | $dataProvider = $searchModel->search(Yii::$app->request->queryParams); 37 | 38 | return $this->render('index', [ 39 | 'searchModel' => $searchModel, 40 | 'dataProvider' => $dataProvider, 41 | ]); 42 | } 43 | 44 | /** 45 | * Displays a single Category model. 46 | * @param integer $id 47 | * @return mixed 48 | */ 49 | public function actionView($id) 50 | { 51 | return $this->render('view', [ 52 | 'model' => $this->findModel($id), 53 | ]); 54 | } 55 | 56 | /** 57 | * Creates a new Category model. 58 | * If creation is successful, the browser will be redirected to the 'view' page. 59 | * @return mixed 60 | */ 61 | public function actionCreate() 62 | { 63 | $model = new Category(); 64 | 65 | if ($model->load(Yii::$app->request->post()) && $model->save()) { 66 | return $this->redirect('index'); 67 | } else { 68 | return $this->render('create', [ 69 | 'model' => $model, 70 | ]); 71 | } 72 | } 73 | 74 | /** 75 | * Updates an existing Category model. 76 | * If update is successful, the browser will be redirected to the 'view' page. 77 | * @param integer $id 78 | * @return mixed 79 | */ 80 | public function actionUpdate($id) 81 | { 82 | $model = $this->findModel($id); 83 | 84 | if ($model->load(Yii::$app->request->post()) && $model->save()) { 85 | return $this->redirect('index'); 86 | } else { 87 | return $this->render('update', [ 88 | 'model' => $model, 89 | ]); 90 | } 91 | } 92 | 93 | /** 94 | * Deletes an existing Category model. 95 | * If deletion is successful, the browser will be redirected to the 'index' page. 96 | * @param integer $id 97 | * @return mixed 98 | */ 99 | public function actionDelete($id) 100 | { 101 | $this->findModel($id)->delete(); 102 | 103 | return $this->redirect(['index']); 104 | } 105 | 106 | /** 107 | * Finds the Category model based on its primary key value. 108 | * If the model is not found, a 404 HTTP exception will be thrown. 109 | * @param integer $id 110 | * @return Category the loaded model 111 | * @throws NotFoundHttpException if the model cannot be found 112 | */ 113 | protected function findModel($id) 114 | { 115 | if (($model = Category::findOne($id)) !== null) { 116 | return $model; 117 | } else { 118 | throw new NotFoundHttpException('The requested page does not exist.'); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/controllers/EventController.php: -------------------------------------------------------------------------------- 1 | [ 22 | 'class' => VerbFilter::class, 23 | 'actions' => [ 24 | 'delete' => ['post'], 25 | ], 26 | ], 27 | ]; 28 | } 29 | 30 | /** 31 | * Lists all Event models. 32 | * @return mixed 33 | */ 34 | public function actionIndex() 35 | { 36 | $searchModel = new EventSearch(); 37 | $dataProvider = $searchModel->search(Yii::$app->request->queryParams); 38 | 39 | return $this->render('index', [ 40 | 'searchModel' => $searchModel, 41 | 'dataProvider' => $dataProvider, 42 | ]); 43 | } 44 | 45 | /** 46 | * Displays a single Event model. 47 | * @param integer $id 48 | * @return mixed 49 | */ 50 | public function actionView($id) 51 | { 52 | return $this->render('view', [ 53 | 'model' => $this->findModel($id), 54 | ]); 55 | } 56 | 57 | /** 58 | * Creates a new Event model. 59 | * If creation is successful, the browser will be redirected to the 'view' page. 60 | * @return mixed 61 | */ 62 | public function actionCreate() 63 | { 64 | $model = new Event(); 65 | $model->plugin_id = Plugin::EVENTS_CORE; 66 | 67 | if ($model->load(Yii::$app->request->post()) && $model->save()) { 68 | return $this->redirect('index'); 69 | } else { 70 | return $this->render('create', [ 71 | 'model' => $model, 72 | ]); 73 | } 74 | } 75 | 76 | /** 77 | * Updates an existing Event model. 78 | * If update is successful, the browser will be redirected to the 'view' page. 79 | * @param integer $id 80 | * @return mixed 81 | */ 82 | public function actionUpdate($id) 83 | { 84 | $model = $this->findModel($id); 85 | 86 | if ($model->load(Yii::$app->request->post()) && $model->save()) { 87 | return $this->redirect('index'); 88 | } else { 89 | return $this->render('update', [ 90 | 'model' => $model, 91 | ]); 92 | } 93 | } 94 | 95 | /** 96 | * Deletes an existing Event model. 97 | * If deletion is successful, the browser will be redirected to the 'index' page. 98 | * @param integer $id 99 | * @return mixed 100 | */ 101 | public function actionDelete($id) 102 | { 103 | $this->findModel($id)->delete(); 104 | 105 | return $this->redirect(['index']); 106 | } 107 | 108 | /** 109 | * Finds the Event model based on its primary key value. 110 | * If the model is not found, a 404 HTTP exception will be thrown. 111 | * @param integer $id 112 | * @return Event the loaded model 113 | * @throws NotFoundHttpException if the model cannot be found 114 | */ 115 | protected function findModel($id) 116 | { 117 | if (($model = Event::findOne($id)) !== null) { 118 | return $model; 119 | } else { 120 | throw new NotFoundHttpException('The requested page does not exist.'); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/controllers/PluginController.php: -------------------------------------------------------------------------------- 1 | pluginService = $pluginService; 29 | parent::__construct($id, $module, $config); 30 | } 31 | 32 | /** 33 | * @return array 34 | */ 35 | public function behaviors() 36 | { 37 | return [ 38 | 'verbs' => [ 39 | 'class' => VerbFilter::class, 40 | 'actions' => [ 41 | 'delete' => ['post'], 42 | ], 43 | ], 44 | ]; 45 | } 46 | 47 | /** 48 | * Lists all Item models. 49 | * @return mixed 50 | */ 51 | public function actionIndex() 52 | { 53 | $searchModel = new PluginSearch(); 54 | $dataProvider = $searchModel->search(Yii::$app->request->queryParams); 55 | 56 | return $this->render('index', [ 57 | 'searchModel' => $searchModel, 58 | 'dataProvider' => $dataProvider, 59 | ]); 60 | } 61 | 62 | /** 63 | * @param null $id 64 | * @return string 65 | */ 66 | public function actionInstall($id = null) 67 | { 68 | try { 69 | $plugins = $this->pluginService->getPlugins($this->module->pluginsDir); 70 | 71 | $dataProvider = new ArrayDataProvider([ 72 | 'allModels' => $plugins, 73 | 'pagination' => [ 74 | 'pageSize' => 20, 75 | ], 76 | ]); 77 | 78 | if ($id && Yii::$app->request->isPost) { 79 | $this->pluginService->installPlugin($id); 80 | return $this->redirect('install'); 81 | } 82 | 83 | return $this->render('install', compact('dataProvider')); 84 | 85 | } catch (Exception $e) { 86 | $this->pluginService->noty->error($e->getMessage()); 87 | return $this->redirect('index'); 88 | } 89 | } 90 | 91 | /** 92 | * Displays a info page 93 | * @return mixed 94 | */ 95 | public function actionInfo() 96 | { 97 | return $this->render('info'); 98 | } 99 | 100 | /** 101 | * Displays a single Item model. 102 | * @param integer $id 103 | * @return mixed 104 | */ 105 | public function actionView($id) 106 | { 107 | return $this->render('view', [ 108 | 'model' => $this->findModel($id), 109 | ]); 110 | } 111 | 112 | /** 113 | * Updates an existing Item model. 114 | * If update is successful, the browser will be redirected to the 'view' page. 115 | * @param integer $id 116 | * @return mixed 117 | */ 118 | public function actionUpdate($id) 119 | { 120 | $model = $this->findModel($id); 121 | 122 | if ($model->load(Yii::$app->request->post()) && $model->save()) { 123 | return $this->redirect('index'); 124 | } else { 125 | return $this->render('update', [ 126 | 'model' => $model 127 | ]); 128 | } 129 | } 130 | 131 | /** 132 | * @param $id 133 | * @return \yii\web\Response 134 | * @throws Exception 135 | */ 136 | public function actionDelete($id) 137 | { 138 | $model = $this->findModel($id); 139 | 140 | if ($model->id != $model::EVENTS_CORE) { 141 | $model->delete(); 142 | } else { 143 | throw new Exception('Core plugin not deleted'); 144 | } 145 | 146 | return $this->redirect(['index']); 147 | } 148 | 149 | /** 150 | * Finds the Plugin model based on its primary key value. 151 | * If the model is not found, a 404 HTTP exception will be thrown. 152 | * @param integer $id 153 | * @return Plugin the loaded model 154 | * @throws NotFoundHttpException if the model cannot be found 155 | */ 156 | protected function findModel($id) 157 | { 158 | if (($model = Plugin::findOne($id)) !== null) { 159 | return $model; 160 | } else { 161 | throw new NotFoundHttpException('The requested page does not exist.'); 162 | } 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /src/controllers/ShortcodeController.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | class ShortcodeController extends Controller 18 | { 19 | public function behaviors() 20 | { 21 | return [ 22 | 'verbs' => [ 23 | 'class' => VerbFilter::class, 24 | 'actions' => [ 25 | 'delete' => ['post'], 26 | ], 27 | ], 28 | ]; 29 | } 30 | 31 | /** 32 | * Lists all models. 33 | * @return mixed 34 | */ 35 | public function actionIndex() 36 | { 37 | $searchModel = new ShortcodeSearch(); 38 | $dataProvider = $searchModel->search(Yii::$app->request->queryParams); 39 | 40 | return $this->render('index', [ 41 | 'searchModel' => $searchModel, 42 | 'dataProvider' => $dataProvider, 43 | ]); 44 | } 45 | 46 | /** 47 | * Displays a single Shortcode model. 48 | * @param integer $id 49 | * @return mixed 50 | */ 51 | public function actionView($id) 52 | { 53 | return $this->render('view', [ 54 | 'model' => $this->findModel($id), 55 | ]); 56 | } 57 | 58 | /** 59 | * Creates a new Shortcode model. 60 | * If creation is successful, the browser will be redirected to the 'view' page. 61 | * @return mixed 62 | */ 63 | /* public function actionCreate() 64 | { 65 | $model = new Shortcode(); 66 | 67 | if ($model->load(Yii::$app->request->post()) && $model->save()) { 68 | return $this->redirect('index'); 69 | } else { 70 | return $this->render('create', [ 71 | 'model' => $model, 72 | ]); 73 | } 74 | }*/ 75 | 76 | /** 77 | * Updates an existing Shortcode model. 78 | * If update is successful, the browser will be redirected to the 'view' page. 79 | * @param integer $id 80 | * @return mixed 81 | */ 82 | public function actionUpdate($id) 83 | { 84 | $model = $this->findModel($id); 85 | 86 | if ($model->load(Yii::$app->request->post()) && $model->save()) { 87 | return $this->redirect('index'); 88 | } else { 89 | return $this->render('update', [ 90 | 'model' => $model, 91 | ]); 92 | } 93 | } 94 | 95 | /** 96 | * Deletes an existing Shortcode model. 97 | * If deletion is successful, the browser will be redirected to the 'index' page. 98 | * @param integer $id 99 | * @return mixed 100 | */ 101 | public function actionDelete($id) 102 | { 103 | $this->findModel($id)->delete(); 104 | 105 | return $this->redirect(['index']); 106 | } 107 | 108 | /** 109 | * Finds the Shortcode model based on its primary key value. 110 | * If the model is not found, a 404 HTTP exception will be thrown. 111 | * @param integer $id 112 | * @return Shortcode the loaded model 113 | * @throws NotFoundHttpException if the model cannot be found 114 | */ 115 | protected function findModel($id) 116 | { 117 | if (($model = Shortcode::findOne($id)) !== null) { 118 | return $model; 119 | } else { 120 | throw new NotFoundHttpException('The requested page does not exist.'); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/core/SeoHandler.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class SeoHandler 15 | { 16 | /** 17 | * Set page suffix 18 | * Handler for yii\base\Application::beforeRequest 19 | */ 20 | public static function clearUrl() 21 | { 22 | $request = Yii::$app->request->url; 23 | if ( 24 | ($request == '/index.php') || 25 | ($request == '/site') || 26 | ($request == '/site/index') 27 | ) { 28 | Yii::$app->response->redirect(Yii::$app->homeUrl, 301); 29 | } 30 | } 31 | 32 | /** 33 | * Set page suffix 34 | * Handler for yii\web\View::beginPage 35 | */ 36 | public static function updateTitle() 37 | { 38 | if (Yii::$app instanceof Application === true && Yii::$app->request->get('page') !== null) { 39 | Yii::$app->view->title .= Yii::t( 40 | 'plugin', 41 | ' - Page {page}', 42 | ['page' => (int)Yii::$app->request->get('page')] 43 | ); 44 | } 45 | } 46 | 47 | 48 | } -------------------------------------------------------------------------------- /src/core/ShortcodeHandler.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class ShortcodeHandler 15 | { 16 | const PARSE_SHORTCODES = 'parseShortcodes'; 17 | 18 | /** 19 | * @param ViewEvent $event 20 | */ 21 | public static function parseShortcodes($event) 22 | { 23 | $content = $event->content; 24 | /** @var PluginsManager $data */ 25 | $data = $event->data; 26 | 27 | /** @var ShortcodeService $service */ 28 | $service = self::getShortcodeService(); 29 | if ($blocks = $data->shortcodesIgnoreBlocks) { 30 | $service->addIgnoreBlocks($blocks); 31 | } 32 | $shContent = $service->getShortcodesFromContent($content); 33 | $service->setShortcodesFromDb($shContent, $data->appId); 34 | $event->content = $service->parseShortcodes($content); 35 | } 36 | 37 | /** 38 | * @return ShortcodeService 39 | */ 40 | protected static function getShortcodeService() 41 | { 42 | /** @var ShortcodeService $service */ 43 | $service = Yii::$container->get(ShortcodeService::class); 44 | return $service; 45 | } 46 | } -------------------------------------------------------------------------------- /src/core/extralinks/ExternalLinks.php: -------------------------------------------------------------------------------- 1 | [ 27 | //'google.com' 28 | ], 29 | 'noReplaceLinksOnSubDomains' => [ 30 | //'google.com' 31 | ], 32 | 'noReplaceLocalDomain' => true, 33 | 'redirectRoute' => '/externallinks/redirect', 34 | 'redirectRouteParam' => 'url', 35 | 'enabledB64Encode' => true, 36 | ]; 37 | 38 | /** 39 | * @var array 40 | */ 41 | public static $configController = [ 42 | 'redirectRouteParam' => 'url', 43 | 'enabledB64Encode' => true, 44 | ]; 45 | 46 | /** 47 | * @return array 48 | */ 49 | public static function events() 50 | { 51 | return [ 52 | Response::class => [ 53 | Response::EVENT_AFTER_PREPARE => ['parse', self::$configResponse], 54 | ], 55 | RedirectController::class => [ 56 | RedirectController::EVENT_LOAD_CONFIG => ['loadConfig', self::$configController], 57 | ], 58 | ]; 59 | } 60 | 61 | /** 62 | * @var array 63 | */ 64 | protected static $_config = []; 65 | 66 | /** 67 | * @param Event $event 68 | */ 69 | public static function parse($event) 70 | { 71 | /** @var $response Response */ 72 | $response = $event->sender; 73 | $request = Yii::$app->request; 74 | 75 | if (!$request->isAjax && !$request->isPjax && $response->format == Response::FORMAT_HTML) { 76 | Yii::beginProfile('ExternalLinks'); 77 | 78 | self::initConfig($event->data); 79 | 80 | $content = $response->content; 81 | $matches = []; 82 | 83 | if (preg_match_all("/<[Aa][\s]{1}[^>]*[Hh][Rr][Ee][Ff][^=]*=[ '\"\s]*([^ \"'>\s#]+)[^>]*>/", $content, $matches)) { 84 | if (isset($matches[1])) { 85 | $content = self::parseContent($content, $matches[1]); 86 | } 87 | }; 88 | 89 | $response->content = $content; 90 | Yii::endProfile('ExternalLinks'); 91 | } 92 | } 93 | 94 | /** 95 | * @param RedirectEvent $event 96 | */ 97 | public static function loadConfig($event) 98 | { 99 | $event->config = ArrayHelper::merge(self::$configController, $event->data); 100 | } 101 | 102 | /** 103 | * @param $content 104 | * @param array $links 105 | * @return string 106 | */ 107 | protected static function parseContent($content, array $links) 108 | { 109 | foreach ($links as $link) { 110 | //Относительные ссылки пропускать 111 | if (Url::isRelative($link)) { 112 | continue; 113 | } 114 | 115 | if ($dataLink = parse_url($link)) { 116 | // Для этого хоста не нужно менять ссылку 117 | $host = ArrayHelper::getValue($dataLink, 'host'); 118 | if (in_array($host, self::$_config['noReplaceLinksOnDomains'])) { 119 | continue; 120 | } 121 | 122 | // Не заменять ссылки для субдоменов из списка 123 | $noReplace = false; 124 | 125 | foreach (self::$_config['noReplaceLinksOnSubDomains'] as $sub) { 126 | $pos = strpos($host, $sub); 127 | //echo $host . PHP_EOL; 128 | //echo $sub . "\r\n"; 129 | if ($pos !== false) { 130 | $noReplace = true; 131 | continue; 132 | } 133 | } 134 | 135 | if ($noReplace) { 136 | continue; 137 | } 138 | } 139 | 140 | $linkForUrl = $link; 141 | if (self::$_config['enabledB64Encode']) { 142 | $linkForUrl = base64_encode($link); 143 | } 144 | 145 | $newUrl = Url::to([self::$_config['redirectRoute'], self::$_config['redirectRouteParam'] => $linkForUrl]); 146 | //replacing references only after request; 170 | self::$_config = ArrayHelper::merge(self::$configResponse, $data); 171 | 172 | if (self::$_config['noReplaceLocalDomain'] && $request->hostInfo) { 173 | if ($dataLink = parse_url($request->hostInfo)) { 174 | //Для этого хоста не нужно менять ссылку 175 | $host = ArrayHelper::getValue($dataLink, 'host'); 176 | self::$_config['noReplaceLinksOnDomains'][] = $host; 177 | } 178 | } 179 | } 180 | 181 | } 182 | -------------------------------------------------------------------------------- /src/core/extralinks/README.md: -------------------------------------------------------------------------------- 1 | AutoCorrect external links after rendering html page 2 | =================================== 3 | !["Plugins"](extralinks.jpg) 4 | 5 | ## Default Config 6 | 7 | ``` 8 | [ 9 | 'noReplaceLocalDomain' => true, 10 | 'redirectRoute' => '/externallinks/redirect', 11 | 'redirectRouteParam' => 'url', 12 | 'enabledB64Encode' => true, 13 | 'noReplaceLinksOnDomains' => [ 14 | 'site1.ru', 15 | 'www.site1.ru', 16 | 'site2.ru', 17 | ], 18 | ], 19 | ``` 20 | 21 | ## How to use 22 | 23 | After installation this plugin, open `@frontend/config/main.php` and add following: 24 | 25 | ``` 26 | 'controllerMap' => [ 27 | 'externallinks' => lo\plugins\core\extralinks\RedirectController::class 28 | ], 29 | 'components' => [ 30 | 'urlManager' => [ 31 | 'rules' => [ 32 | //Rewriting the standard route 33 | //And add robots.txt Disallow: /~* 34 | '~re' => '/externallinks/redirect', 35 | ] 36 | ] 37 | ] 38 | ``` 39 | -------------------------------------------------------------------------------- /src/core/extralinks/RedirectController.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class RedirectController extends Controller 14 | { 15 | /** 16 | * load config from plugin 17 | */ 18 | const EVENT_LOAD_CONFIG = 'loadConfig'; 19 | 20 | public $defaultAction = 'redirect'; 21 | 22 | /** 23 | * @return \yii\web\Response 24 | * @throws BadRequestHttpException 25 | */ 26 | public function actionRedirect() 27 | { 28 | $event = new RedirectEvent(); 29 | $this->trigger(self::EVENT_LOAD_CONFIG, $event); 30 | $config = $event->config; 31 | $request = Yii::$app->request; 32 | 33 | if ($url = $request->get($config['redirectRouteParam'])) { 34 | if ($config['enabledB64Encode']) { 35 | $url = base64_decode($url); 36 | } 37 | 38 | if (filter_var($url, FILTER_VALIDATE_URL) === FALSE) { 39 | throw new BadRequestHttpException; 40 | } 41 | 42 | return $this->redirect($url); 43 | } 44 | 45 | throw new BadRequestHttpException; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/core/extralinks/RedirectEvent.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class RedirectEvent extends Event 12 | { 13 | /** 14 | * @var array the parameter array passed to the [[RedirectController->actionRedirect()]] method. 15 | */ 16 | public $config; 17 | 18 | } -------------------------------------------------------------------------------- /src/core/extralinks/extralinks.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loveorigami/yii2-plugins-system/9f2d926237910b5ff24d2c6e0993a7f3ba4607f1/src/core/extralinks/extralinks.jpg -------------------------------------------------------------------------------- /src/core/helloworld/HelloWorld.php: -------------------------------------------------------------------------------- 1 | 'Hello, world!', 24 | 'replace' => 'Hello, Yii!', 25 | 'color' => '#FFDB51' 26 | ]; 27 | 28 | /** 29 | * @return array 30 | */ 31 | public static function events() 32 | { 33 | return [ 34 | Response::class => [ 35 | Response::EVENT_AFTER_PREPARE => ['hello', self::$config] 36 | ] 37 | ]; 38 | } 39 | 40 | /** 41 | * @param $event 42 | */ 43 | public static function hello($event) 44 | { 45 | if (!$content = $event->sender->content) return; 46 | 47 | $search = ArrayHelper::getValue($event->data, 'search', self::$config['search']); 48 | $replace = ArrayHelper::getValue($event->data, 'replace', self::$config['replace']); 49 | $color = ArrayHelper::getValue($event->data, 'color', self::$config['color']); 50 | 51 | $event->sender->content = str_replace($search, Html::tag('span', $replace, [ 52 | 'style' => "background-color:$color;" 53 | ]), $content); 54 | } 55 | } -------------------------------------------------------------------------------- /src/core/helloworld/README.md: -------------------------------------------------------------------------------- 1 | # Hello World plugin 2 | 3 | ### Config 4 | 5 | After installiation in plugins system, you can change default config 6 | 7 | ```php 8 | [ 9 | 'search' => 'Hello, world!', 10 | 'replace' => 'Hello, Yii!', 11 | 'color' => '#FFDB51' 12 | ]; 13 | ``` 14 | 15 | ### Usage 16 | 17 | After enabled this plugin, all phrases `search` will be replaced on `replace`, and highlighted `color` -------------------------------------------------------------------------------- /src/core/httpauth/Httpauth.php: -------------------------------------------------------------------------------- 1 | ['127.0.0.1', '127.0.0.2'], 33 | 'users' => [ 34 | 'admin' => '123456', 35 | ] 36 | ]; 37 | 38 | public static function events() 39 | { 40 | return [ 41 | 'yii\base\Application' => [ 42 | 'beforeRequest' => ['login', self::$config] 43 | ], 44 | ]; 45 | } 46 | 47 | /** 48 | * @var array Username and password pairs. 49 | */ 50 | private static $_users = []; 51 | 52 | /** 53 | * @var array the list of IPs that are allowed to access this application. 54 | */ 55 | private static $_allowedIps = []; 56 | 57 | /** 58 | * Logining 59 | * @param $event 60 | * @return bool|void 61 | * @throws UnauthorizedHttpException 62 | */ 63 | public static function login($event) 64 | { 65 | self::$_allowedIps = ArrayHelper::getValue($event->data, 'allowedIps', self::$config['allowedIps']); 66 | self::$_users = ArrayHelper::getValue($event->data, 'users', self::$config['users']); 67 | 68 | if (Yii::$app->request->isConsoleRequest || self::_checkAllowedIps() || self::_checkHttpAuthentication()) { 69 | return null; 70 | } 71 | 72 | Yii::$app->response->headers->add('WWW-Authenticate', 'Basic realm="HTTP authentication"'); 73 | throw new UnauthorizedHttpException(Yii::t('yii', 'You are not allowed to perform this action.'), 401); 74 | } 75 | 76 | /** 77 | * @return boolean Whether the application can be accessed by the current user. 78 | */ 79 | private static function _checkAllowedIps() 80 | { 81 | if (in_array(Yii::$app->request->getUserIP(), self::$_allowedIps)) { 82 | return true; 83 | } 84 | return false; 85 | } 86 | 87 | /** 88 | * @return boolean Whether the application can be accessed by the current user. 89 | */ 90 | private static function _checkHttpAuthentication() 91 | { 92 | $username = Yii::$app->request->getAuthUser(); 93 | $password = Yii::$app->request->getAuthPassword(); 94 | if ( 95 | isset(self::$_users[$username]) && 96 | ( 97 | $password == self::$_users[$username] || 98 | md5($password) == self::$_users[$username]) 99 | ) { 100 | return true; 101 | } 102 | return false; 103 | } 104 | } -------------------------------------------------------------------------------- /src/core/httpauth/README.md: -------------------------------------------------------------------------------- 1 | # Http Authentication plugin 2 | 3 | ### Config 4 | 5 | After installiation in plugins system, you can change default config 6 | 7 | ```php 8 | [ 9 | 'allowedIps' => ['127.0.0.1', '127.0.0.2'], 10 | 'users' => [ 11 | 'admin' => '123456', 12 | ] 13 | ]; 14 | ``` 15 | 16 | ### Thanks 17 | 18 | * Lajax for idea from [Yii2 Http Authentication] (https://github.com/lajax/yii2-http-auth) extension -------------------------------------------------------------------------------- /src/dto/EventsDiffDto.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class EventsDiffDto 15 | { 16 | protected $_data = []; 17 | 18 | /** 19 | * PluginsDiffDto constructor. 20 | * @param array $data 21 | */ 22 | public function __construct($data = []) 23 | { 24 | foreach ($data as $item) { 25 | $diff = []; 26 | $diff['handler_class'] = ArrayHelper::getValue($item, 'handler_class'); 27 | $diff['handler_method'] = ArrayHelper::getValue($item, 'handler_method'); 28 | $config = ArrayHelper::getValue($item, 'data', null); 29 | if ($config) { 30 | $diff['data'] = $this->prepareConfig($config); // if added new config 31 | } 32 | $this->_data[$diff['handler_class']] = Json::encode($diff); 33 | } 34 | } 35 | 36 | /** 37 | * @return array 38 | */ 39 | public function getDiff() 40 | { 41 | return $this->_data; 42 | } 43 | 44 | /** 45 | * @param $data 46 | * @return array 47 | */ 48 | protected function prepareConfig($data) 49 | { 50 | return array_keys(JsonHelper::decode($data)); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/dto/EventsPoolDto.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class EventsPoolDto 12 | { 13 | public $data = []; 14 | 15 | /** 16 | * EventsPoolDto constructor. 17 | * @param array $data 18 | */ 19 | public function __construct($data = []) 20 | { 21 | foreach ($data as $item) { 22 | $hash = ArrayHelper::getValue($item, 'handler_class'); 23 | if ($hash) { 24 | $this->data[$hash] = $item; 25 | } 26 | } 27 | } 28 | 29 | /** 30 | * @param $key 31 | * @return bool 32 | */ 33 | public function hasKey($key) 34 | { 35 | return isset($this->data[$key]); 36 | } 37 | 38 | /** 39 | * @param $key 40 | * @return array 41 | */ 42 | public function getInfo($key) 43 | { 44 | if ($this->hasKey($key)) { 45 | return $this->data[$key]; 46 | } else { 47 | return []; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/dto/PluginDataDto.php: -------------------------------------------------------------------------------- 1 | $value) { 30 | if (property_exists($this, $key)) { 31 | $this->$key = $value; 32 | } 33 | } 34 | } 35 | 36 | /** 37 | * @return bool 38 | */ 39 | public function isInstalled() 40 | { 41 | return ($this->hash) ? true : false; 42 | } 43 | 44 | /** 45 | * @return bool 46 | */ 47 | public function isShortcodes() 48 | { 49 | return ($this->type == 'shortcodes') ? true : false; 50 | } 51 | 52 | /** 53 | * @return bool 54 | */ 55 | public function isEvents() 56 | { 57 | return ($this->type == 'events') ? true : false; 58 | } 59 | 60 | /** 61 | * @return string 62 | */ 63 | public function getPluginClass() 64 | { 65 | return $this->handler_class; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/dto/PluginsDiffDto.php: -------------------------------------------------------------------------------- 1 | null, 'version' => null]; 26 | 27 | foreach ($item as $key => $value) { 28 | if (in_array($key, $this->_hash)) { 29 | $diff['hash'] = $value; 30 | } 31 | if (in_array($key, $this->_version)) { 32 | $diff['version'] = $value; 33 | } 34 | } 35 | 36 | $this->_data[$diff['hash']] = Json::encode($diff); 37 | } 38 | } 39 | 40 | /** 41 | * @return array 42 | */ 43 | public function getDiff() 44 | { 45 | return $this->_data; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/dto/PluginsPoolDto.php: -------------------------------------------------------------------------------- 1 | data[$hash] = $item; 30 | } 31 | } 32 | 33 | /** 34 | * @param $key 35 | * @return bool 36 | */ 37 | public function hasKey($key) 38 | { 39 | return isset($this->data[$key]); 40 | } 41 | 42 | /** 43 | * @param $key 44 | * @return array 45 | */ 46 | public function getInfo($key) 47 | { 48 | if ($this->hasKey($key)) { 49 | return $this->data[$key]; 50 | } else { 51 | return []; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/dto/ShortcodesDbCallbacksDto.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class ShortcodesDbCallbacksDto 16 | { 17 | public $data; 18 | 19 | public function __construct($data) 20 | { 21 | foreach ($data as $key => $value) { 22 | if ($callback = $this->getCallback($key, $value)) { 23 | $this->data[$key] = $callback; 24 | } 25 | } 26 | } 27 | 28 | /** 29 | * @param $tag 30 | * @param $value 31 | * @return bool|mixed 32 | */ 33 | protected function getCallback($tag, $value) 34 | { 35 | $dataDb = new ShortcodeDbRepositoryMap($value); 36 | $method = 'shortcodes'; 37 | 38 | /** @var BaseShortcode $handler */ 39 | $handler = $dataDb->handler_class; 40 | $configDb = JsonHelper::decode($dataDb->data); 41 | 42 | if (is_callable([$handler, $method])) { 43 | $configSh = $handler::shortcodes(); 44 | $shortcode = ArrayHelper::getValue($configSh, $tag); 45 | /** 46 | * 'shortcode' => function(){...} 47 | * 'shortcode' => [MyCode::class, 'widget'] 48 | */ 49 | if (is_callable($shortcode)) { 50 | return [ 51 | 'callback' => $shortcode, 52 | 'config' => $configDb, 53 | 'tag' => $tag 54 | ]; 55 | } else { 56 | $callback = ArrayHelper::getValue($shortcode, 'callback'); 57 | $config = ArrayHelper::getValue($shortcode, 'config'); 58 | /** 59 | * 'shortcode' => [ 60 | * 'callback' => function(){...} 61 | * 'config' => [...] 62 | * ] 63 | * 'shortcode' => [ 64 | * 'callback' => [MyCode::class, 'widget'], 65 | * 'config' => [...] 66 | * ] 67 | */ 68 | 69 | if (is_callable($callback)) { 70 | return [ 71 | 'callback' => $callback, 72 | 'config' => ArrayHelper::merge($config, $configDb), 73 | 'tag' => $tag 74 | ]; 75 | } 76 | } 77 | return false; 78 | } 79 | return false; 80 | } 81 | 82 | /** 83 | * @param $key 84 | * @return bool 85 | */ 86 | public function hasKey($key) 87 | { 88 | return isset($this->data[$key]); 89 | } 90 | 91 | /** 92 | * @param $key 93 | * @return array 94 | */ 95 | public function getInfo($key) 96 | { 97 | if ($this->hasKey($key)) { 98 | return $this->data[$key]; 99 | } else { 100 | return []; 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/dto/ShortcodesDiffDto.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class ShortcodesDiffDto 15 | { 16 | protected $_data = []; 17 | 18 | /** 19 | * ShortcodesDiffDto constructor. 20 | * @param array $data 21 | */ 22 | public function __construct($data = []) 23 | { 24 | foreach ($data as $item) { 25 | $diff = []; 26 | $handler = ArrayHelper::getValue($item, 'handler_class'); 27 | $tag = ArrayHelper::getValue($item, 'tag'); 28 | $config = ArrayHelper::getValue($item, 'data'); 29 | if ($config) { 30 | $diff['data'] = $this->prepareConfig($config); // if added new config 31 | } 32 | $hash = md5($handler . $tag); 33 | $this->_data[$hash] = Json::encode($diff); 34 | } 35 | } 36 | 37 | /** 38 | * @return array 39 | */ 40 | public function getDiff() 41 | { 42 | return $this->_data; 43 | } 44 | 45 | /** 46 | * @param $data 47 | * @return array 48 | */ 49 | protected function prepareConfig($data) 50 | { 51 | return array_keys(JsonHelper::decode($data)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/dto/ShortcodesPoolDto.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class ShortcodesPoolDto 13 | { 14 | public $data = []; 15 | 16 | /** 17 | * ShortcodesPoolDto constructor. 18 | * @param array $data 19 | */ 20 | public function __construct($data = []) 21 | { 22 | foreach ($data as $item) { 23 | 24 | $handler = ArrayHelper::getValue($item, 'handler_class'); 25 | $tag = ArrayHelper::getValue($item, 'tag'); 26 | $hash = md5($handler . $tag); 27 | 28 | if ($hash) { 29 | $this->data[$hash] = $item; 30 | } 31 | } 32 | } 33 | 34 | /** 35 | * @param $key 36 | * @return bool 37 | */ 38 | public function hasKey($key) 39 | { 40 | return isset($this->data[$key]); 41 | } 42 | 43 | /** 44 | * @param $key 45 | * @return array 46 | */ 47 | public function getInfo($key) 48 | { 49 | if ($this->hasKey($key)) { 50 | return $this->data[$key]; 51 | } else { 52 | return []; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/helpers/BS.php: -------------------------------------------------------------------------------- 1 | ['*.php']]); 33 | 34 | foreach ($files as $filePath) { 35 | 36 | $class = str_replace([$dir, '.php', '/', '@'], [$path, '', '\\', ''], $filePath); 37 | 38 | if ($callback instanceof \Closure) { 39 | $className = call_user_func($callback, $class); 40 | } else { 41 | $className = $class; 42 | } 43 | 44 | if ($className) { 45 | $result[] = $className; 46 | } 47 | } 48 | } 49 | 50 | return $result; 51 | } 52 | 53 | /** 54 | * @param $className 55 | * @return null|string 56 | */ 57 | public static function getPluginInfo($className) 58 | { 59 | try { 60 | if (!$reflection = self::getReflection($className)) { 61 | return null; 62 | } 63 | return $reflection->getDocComment(); 64 | 65 | } catch (\Exception $e) { 66 | echo $className; 67 | exit; 68 | } 69 | } 70 | 71 | /** 72 | * ```php 73 | * ClassHelper::getEventNames(yii\base\View::class); 74 | * ``` 75 | * @param $className 76 | * @return array 77 | */ 78 | public static function getEventNames($className) 79 | { 80 | $result = []; 81 | $reflection = new \ReflectionClass($className); 82 | foreach ($reflection->getConstants() as $name => $value) { 83 | if (!preg_match('/^EVENT/', $name)) { 84 | continue; 85 | } 86 | $result[$name] = $value; 87 | } 88 | return $result; 89 | } 90 | 91 | /** 92 | * @param $className 93 | * @return bool|\ReflectionClass 94 | */ 95 | protected static function getReflection($className) 96 | { 97 | try { 98 | if (in_array($className, ['yii\requirements\YiiRequirementChecker', 'yii\helpers\Markdown'])) { 99 | return false; 100 | } 101 | $reflection = new \ReflectionClass($className); 102 | } catch (\Exception $e) { 103 | return false; 104 | } 105 | return $reflection; 106 | } 107 | } -------------------------------------------------------------------------------- /src/helpers/JsonHelper.php: -------------------------------------------------------------------------------- 1 | [ 13 | * 'afterRender' => ['hello', self::$config] 14 | * ] 15 | * ]; 16 | * @return array 17 | */ 18 | public static function events(); 19 | } -------------------------------------------------------------------------------- /src/interfaces/IShortcode.php: -------------------------------------------------------------------------------- 1 | ['lo\plugins\plugins\code\Code', 'widget'], 13 | * 'anothershortcode'=>function($attrs, $content, $tag){ 14 | * ..... 15 | * }, 16 | * ]; 17 | * @return array 18 | */ 19 | public static function shortcodes(); 20 | } -------------------------------------------------------------------------------- /src/messages/en/plugin.php: -------------------------------------------------------------------------------- 1 | '"{attribute}" must be a callable as [{callableValue}::{value}]', 21 | '"{attribute}" must be a valid JSON' => '"{attribute}" must be a valid JSON', 22 | 23 | 'Are you sure to delete this item?' => 'Are you sure to delete this item?', 24 | 'App' => 'App', 25 | 'App Id' => 'App Id', 26 | 'Author' => 'Author', 27 | 'Author Url' => 'Author Url', 28 | 29 | 'Categories' => 'Categories', 30 | 'Category' => 'Category', 31 | 'Create' => 'Create', 32 | 'Create Category' => 'Create Category', 33 | 'Create Item' => 'Create Plugin', 34 | 'Create {modelClass}' => 'Create {modelClass}', 35 | 36 | 'Data' => 'Data', 37 | 'Delete' => 'Delete', 38 | 'Disabled' => 'Disabled', 39 | 40 | 'Enabled' => 'Enabled', 41 | 'Event' => 'Event', 42 | 'Events' => 'Events', 43 | 44 | 'Handler' => 'Handler', 45 | 'Handler Class' => 'Handler Class', 46 | 'Handler Method' => 'Handler Method', 47 | 'Hash' => 'Hash', 48 | 49 | 'ID' => 'ID', 50 | 'Info' => 'Info', 51 | 'Install' => 'Install', 52 | 'Items' => 'Plugins', 53 | 54 | 'Name' => 'Name', 55 | 'New event installed' => 'New event installed', 56 | 57 | ' - Page {page}' => ' - Page {page}', 58 | 'Plugin ID' => 'Plugin ID', 59 | 'Pos.' => 'Pos.', 60 | 'Position' => 'Position', 61 | 62 | 'Status' => 'Status', 63 | 'Shortcode' => 'Shortcode', 64 | 'Shortcodes' => 'Shortcodes', 65 | 66 | 'Tag' => 'Tag', 67 | 'Text' => 'Text', 68 | 'This plugin alredy installed' => 'This plugin alredy installed', 69 | 'Tooltip' => 'Tooltip', 70 | 'Trigger' => 'Trigger', 71 | 'Trigger Class' => 'Trigger Class', 72 | 'Trigger Event' => 'Trigger Event', 73 | 'Type' => 'Type', 74 | 75 | 'Unable to find specified class' => 'Unable to find specified class', 76 | 'Update' => 'Update', 77 | 'Url' => 'Url', 78 | 79 | 'Ver.' => 'Ver.', 80 | 'Version' => 'Version', 81 | ]; 82 | -------------------------------------------------------------------------------- /src/messages/ru/plugin.php: -------------------------------------------------------------------------------- 1 | '"{attribute}" должен находится в классе [{callableValue}::{value}]', 21 | '"{attribute}" must be a valid JSON' => '"{attribute}" должен содержать валидный JSON', 22 | 23 | 'Are you sure to delete this item?' => 'Уверены, что хотите удалить эту запись?', 24 | 'App' => 'App', 25 | 'App Id' => 'App Id', 26 | 'Author' => 'Автор', 27 | 'Author Url' => 'Url автора', 28 | 29 | 'Categories' => 'Категории', 30 | 'Category' => 'Категория', 31 | 'Create' => 'Добавить', 32 | 'Create Category' => 'Создать категорию', 33 | 'Create Item' => 'Создать плагин', 34 | 'Create {modelClass}' => 'Создать {modelClass}', 35 | 36 | 'Data' => 'Конфигурация', 37 | 'Delete' => 'Удалить', 38 | 'Disabled' => 'Не активно', 39 | 40 | 'Enabled' => 'Активно', 41 | 'Event' => 'Событие', 42 | 'Events' => 'События', 43 | 44 | 'Handler' => 'Handler', 45 | 'Handler Class' => 'Handler class', 46 | 'Handler Method' => 'Handler method', 47 | 'Hash' => 'Хеш', 48 | 49 | 'ID' => 'ID', 50 | 'Info' => 'Информация', 51 | 'Install' => 'Установить', 52 | 'Items' => 'Плагины', 53 | 54 | 'Name' => 'Название', 55 | 'New event installed' => 'Новое событие установлено', 56 | 57 | ' - Page {page}' => ' - Стр. {page}', 58 | 'Plugin ID' => 'Плагин ID', 59 | 'Pos.' => 'Поз.', 60 | 'Position' => 'Позиция', 61 | 62 | 'Status' => 'Статус', 63 | 'Shortcode' => 'Шорткод', 64 | 'Shortcodes' => 'Шорткоды', 65 | 66 | 'Tag' => 'Тег', 67 | 'Text' => 'Описание', 68 | 'This plugin alredy installed' => 'Этот плагин уже установлен', 69 | 'Tooltip' => 'Подсказка', 70 | 'Trigger' => 'Trigger', 71 | 'Trigger Class' => 'Trigger class', 72 | 'Trigger Event' => 'Trigger event', 73 | 'Type' => 'Тип', 74 | 75 | 'Unable to find specified class' => 'Не удалось найти указанный класс', 76 | 'Update' => 'Обновить', 77 | 'Url' => 'Url', 78 | 79 | 'Ver.' => 'Вер.', 80 | 'Version' => 'Версия', 81 | ]; 82 | -------------------------------------------------------------------------------- /src/migrations/Migration.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 44 | // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci 45 | $options = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; 46 | } 47 | parent::createTable($table, $columns, $options); 48 | } 49 | 50 | /** 51 | * Real table name builder 52 | * @param string $name table name 53 | * @return string 54 | */ 55 | protected function tn($name) 56 | { 57 | return '{{%' . $this->tableGroup . '__' . $name . '}}'; 58 | } 59 | 60 | /** 61 | * Foreign key relation names generator 62 | * @param string $table1 first table in relation 63 | * @param string $table2 second table in relation 64 | * @return string 65 | */ 66 | protected function fk($table1, $table2) 67 | { 68 | return 'fk_' . $this->tableGroup . '__' . $table1 . '_' . $table2; 69 | } 70 | 71 | /** 72 | * Creates a smallint column. 73 | * @param int $length column size or precision definition. 74 | * This parameter will be ignored if not supported by the DBMS. 75 | * @return ColumnSchemaBuilder the column instance which can be further customized. 76 | * @since 2.0.6 77 | */ 78 | public function tinyInteger($length = null) 79 | { 80 | return $this->getDb()->getSchema()->createColumnSchemaBuilder('tinyint', $length); 81 | } 82 | } -------------------------------------------------------------------------------- /src/migrations/m170105_094230_drop_tables.php: -------------------------------------------------------------------------------- 1 | tn('event'), $this->getDb()->schema->tableNames)) { 9 | $this->dropTable($this->tn('event')); 10 | } 11 | 12 | if (in_array($this->tn('item'), $this->getDb()->schema->tableNames)) { 13 | $this->dropTable($this->tn('item')); 14 | } 15 | 16 | if (in_array($this->tn('app'), $this->getDb()->schema->tableNames)) { 17 | $this->dropTable($this->tn('app')); 18 | } 19 | } 20 | 21 | public function down() 22 | { 23 | echo "m170105_094230_drop_tables cannot be reverted.\n"; 24 | return false; 25 | } 26 | } -------------------------------------------------------------------------------- /src/migrations/m170105_094233_plugins_app.php: -------------------------------------------------------------------------------- 1 | createTable($this->tn(self::TBL_APP), [ 10 | 'id' => $this->primaryKey(), 11 | 'name' => $this->string()->notNull(), 12 | ]); 13 | 14 | $this->insert($this->tn(self::TBL_APP), [ 15 | 'id' => self::APP_FRONTEND, 16 | 'name' => 'frontend', 17 | ]); 18 | 19 | $this->insert($this->tn(self::TBL_APP), [ 20 | 'id' => self::APP_COMMON, 21 | 'name' => 'common', 22 | ]); 23 | 24 | $this->insert($this->tn(self::TBL_APP), [ 25 | 'id' => self::APP_BACKEND, 26 | 'name' => 'backend', 27 | ]); 28 | 29 | $this->insert($this->tn(self::TBL_APP), [ 30 | 'id' => self::APP_API, 31 | 'name' => 'api', 32 | ]); 33 | 34 | $this->insert($this->tn(self::TBL_APP), [ 35 | 'id' => self::APP_CONSOLE, 36 | 'name' => 'console', 37 | ]); 38 | } 39 | 40 | public function down() 41 | { 42 | $this->dropTable($this->tn(self::TBL_APP)); 43 | } 44 | } -------------------------------------------------------------------------------- /src/migrations/m170105_094235_plugins_category.php: -------------------------------------------------------------------------------- 1 | createTable($this->tn(self::TBL_CATEGORY), [ 10 | 'id' => $this->primaryKey(), 11 | 'name' => $this->string()->notNull(), 12 | ]); 13 | 14 | $this->insert($this->tn(self::TBL_CATEGORY), [ 15 | 'id' => self::CAT_SHORTCODES, 16 | 'name' => 'Shortcodes' 17 | ]); 18 | 19 | $this->insert($this->tn(self::TBL_CATEGORY), [ 20 | 'id' => self::CAT_PLUGINS, 21 | 'name' => 'Plugins' 22 | ]); 23 | 24 | $this->insert($this->tn(self::TBL_CATEGORY), [ 25 | 'id' => self::CAT_SEO, 26 | 'name' => 'SEO' 27 | ]); 28 | } 29 | 30 | public function down() 31 | { 32 | $this->dropTable($this->tn(self::TBL_CATEGORY)); 33 | } 34 | } -------------------------------------------------------------------------------- /src/migrations/m170105_094917_plugins_plugin.php: -------------------------------------------------------------------------------- 1 | createTable($this->tn(self::TBL_PLUGIN), [ 9 | 'id' => $this->primaryKey(), 10 | 'status' => $this->tinyInteger(1)->notNull()->defaultValue(0), 11 | 'name' => $this->string(), 12 | 'url' => $this->string(), 13 | 'version' => $this->string(), 14 | 'author' => $this->string(), 15 | 'author_url' => $this->string(), 16 | 'text' => $this->text(), 17 | 'hash' => $this->string(32), 18 | ]); 19 | 20 | $this->createIndex('idx_plugins_item_status', $this->tn(self::TBL_PLUGIN), 'status'); 21 | 22 | $this->insert($this->tn(self::TBL_PLUGIN), [ 23 | 'id' => self::EVENTS_CORE, 24 | 'status' => self::PLUGIN_ACTIVE, 25 | 'name' => 'Core Events', 26 | 'url' => '', 27 | 'version' => '1.0', 28 | 'author' => 'Lukyanov Andrey', 29 | 'author_url' => 'https://github.com/loveorigami', 30 | 'text' => 'Core events in our system', 31 | 'hash' => '', 32 | ]); 33 | 34 | $this->insert($this->tn(self::TBL_PLUGIN), [ 35 | 'id' => self::EVENTS_CORE + 1, 36 | 'status' => self::PLUGIN_ACTIVE, 37 | 'name' => 'Hello World plugin', 38 | 'url' => 'https://github.com/loveorigami/yii2-plugins-system/tree/master/src/core/code', 39 | 'version' => '1.6', 40 | 'author' => 'Lukyanov Andrey', 41 | 'author_url' => 'https://github.com/loveorigami', 42 | 'text' => 'A simple hello world plugin', 43 | 'hash' => md5('lo\plugins\core\helloworld\HelloWorld'), 44 | ]); 45 | } 46 | 47 | public function down() 48 | { 49 | $this->dropTable($this->tn(self::TBL_PLUGIN)); 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /src/migrations/m170105_094942_plugins_event.php: -------------------------------------------------------------------------------- 1 | createTable($this->tn(self::TBL_EVENT), [ 10 | 'id' => $this->primaryKey(), 11 | 'status' => $this->tinyInteger(1)->notNull()->defaultValue(0), 12 | 'app_id' => $this->integer()->notNull()->defaultValue(self::APP_FRONTEND), 13 | 'category_id' => $this->integer(), 14 | 'plugin_id' => $this->integer()->notNull()->defaultValue(self::EVENTS_CORE), 15 | 'trigger_class' => $this->string(), 16 | 'trigger_event' => $this->string(), 17 | 'handler_class' => $this->string(), 18 | 'handler_method' => $this->string(), 19 | 'data' => $this->text(), 20 | 'text' => $this->text(), 21 | 'pos' => $this->tinyInteger()->notNull()->defaultValue(0), 22 | ]); 23 | 24 | $this->createIndex('idx_plugins_event_app', $this->tn(self::TBL_EVENT), 'app_id'); 25 | $this->createIndex('idx_plugins_event_category', $this->tn(self::TBL_EVENT), 'category_id'); 26 | $this->createIndex('idx_plugins_event_status', $this->tn(self::TBL_EVENT), 'status'); 27 | $this->createIndex('idx_plugins_event_pos', $this->tn(self::TBL_EVENT), 'pos'); 28 | $this->createIndex('idx_plugins_event_trigger', $this->tn(self::TBL_EVENT), ['trigger_class', 'trigger_event']); 29 | $this->createIndex('idx_plugins_event_handler', $this->tn(self::TBL_EVENT), ['handler_class', 'handler_method'], true); 30 | 31 | $this->addForeignKey( 32 | $this->fk(self::TBL_EVENT, self::TBL_PLUGIN), 33 | $this->tn(self::TBL_EVENT), 'plugin_id', 34 | $this->tn(self::TBL_PLUGIN), 'id', 35 | 'CASCADE', 'CASCADE' 36 | ); 37 | 38 | $this->addForeignKey( 39 | $this->fk(self::TBL_EVENT, self::TBL_APP), 40 | $this->tn(self::TBL_EVENT), 'app_id', 41 | $this->tn(self::TBL_APP), 'id', 42 | 'RESTRICT', 'RESTRICT' 43 | ); 44 | 45 | $this->addForeignKey( 46 | $this->fk(self::TBL_EVENT, self::TBL_CATEGORY), 47 | $this->tn(self::TBL_EVENT), 'category_id', 48 | $this->tn(self::TBL_CATEGORY), 'id', 49 | 'RESTRICT', 'RESTRICT' 50 | ); 51 | 52 | $this->insert($this->tn(self::TBL_EVENT), [ 53 | 'id' => 1, 54 | 'app_id' => self::APP_FRONTEND, 55 | 'plugin_id' => self::EVENTS_CORE, 56 | 'category_id' => self::CAT_SEO, 57 | 'trigger_class' => 'yii\web\View', 58 | 'trigger_event' => 'beginPage', 59 | 'handler_class' => 'lo\plugins\core\SeoHandler', 60 | 'handler_method' => 'updateTitle', 61 | 'status' => self::EVENTS_ACTIVE, 62 | 'pos' => 1 63 | ]); 64 | 65 | $this->insert($this->tn(self::TBL_EVENT), [ 66 | 'id' => 2, 67 | 'app_id' => self::APP_FRONTEND, 68 | 'plugin_id' => self::EVENTS_CORE + 1, // Hello, world 69 | 'category_id' => self::CAT_PLUGINS, 70 | 'trigger_class' => 'yii\web\Response', 71 | 'trigger_event' => 'afterPrepare', 72 | 'handler_class' => 'lo\plugins\core\helloworld\HelloWorld', 73 | 'handler_method' => 'hello', 74 | 'data' => '{"search":"Hello, world!","replace":"Hello, Yii!","color":"#FFDB51"}', 75 | 'status' => self::EVENTS_ACTIVE 76 | ]); 77 | 78 | } 79 | 80 | public function down() 81 | { 82 | $this->dropForeignKey( 83 | $this->fk(self::TBL_EVENT, self::TBL_PLUGIN), 84 | $this->tn(self::TBL_EVENT) 85 | ); 86 | 87 | $this->dropForeignKey( 88 | $this->fk(self::TBL_EVENT, self::TBL_APP), 89 | $this->tn(self::TBL_EVENT) 90 | ); 91 | 92 | $this->dropForeignKey( 93 | $this->fk(self::TBL_EVENT, self::TBL_CATEGORY), 94 | $this->tn(self::TBL_EVENT) 95 | ); 96 | 97 | $this->dropTable($this->tn(self::TBL_EVENT)); 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /src/migrations/m170105_094958_plugins_shortcode.php: -------------------------------------------------------------------------------- 1 | createTable($this->tn(self::TBL_SHORTCODE), [ 10 | 'id' => $this->primaryKey(), 11 | 'status' => $this->tinyInteger(1)->notNull()->defaultValue(0), 12 | 'app_id' => $this->integer()->notNull()->defaultValue(self::APP_FRONTEND), 13 | 'category_id' => $this->integer(), 14 | 'plugin_id' => $this->integer()->notNull()->defaultValue(self::EVENTS_CORE), 15 | 'handler_class' => $this->string(), 16 | 'tag' => $this->string(), 17 | 'tooltip' => $this->string(), 18 | 'data' => $this->text(), 19 | 'text' => $this->text(), 20 | ]); 21 | 22 | $this->createIndex('idx_plugins_sh_app', $this->tn(self::TBL_SHORTCODE), 'app_id'); 23 | $this->createIndex('idx_plugins_sh_plugin', $this->tn(self::TBL_SHORTCODE), 'plugin_id'); 24 | $this->createIndex('idx_plugins_sh_category', $this->tn(self::TBL_SHORTCODE), 'category_id'); 25 | $this->createIndex('idx_plugins_sh_status', $this->tn(self::TBL_SHORTCODE), 'status'); 26 | 27 | $this->addForeignKey( 28 | $this->fk(self::TBL_SHORTCODE, self::TBL_PLUGIN), 29 | $this->tn(self::TBL_SHORTCODE), 'plugin_id', 30 | $this->tn(self::TBL_PLUGIN), 'id', 31 | 'CASCADE', 'CASCADE' 32 | ); 33 | 34 | $this->addForeignKey( 35 | $this->fk(self::TBL_SHORTCODE, self::TBL_APP), 36 | $this->tn(self::TBL_SHORTCODE), 'app_id', 37 | $this->tn(self::TBL_APP), 'id', 38 | 'RESTRICT', 'RESTRICT' 39 | ); 40 | 41 | $this->addForeignKey( 42 | $this->fk(self::TBL_SHORTCODE, self::TBL_CATEGORY), 43 | $this->tn(self::TBL_SHORTCODE), 'category_id', 44 | $this->tn(self::TBL_CATEGORY), 'id', 45 | 'RESTRICT', 'RESTRICT' 46 | ); 47 | } 48 | 49 | public function down() 50 | { 51 | $this->dropForeignKey( 52 | $this->fk(self::TBL_SHORTCODE, self::TBL_PLUGIN), 53 | $this->tn(self::TBL_SHORTCODE) 54 | ); 55 | 56 | $this->dropForeignKey( 57 | $this->fk(self::TBL_SHORTCODE, self::TBL_APP), 58 | $this->tn(self::TBL_SHORTCODE) 59 | ); 60 | 61 | $this->dropForeignKey( 62 | $this->fk(self::TBL_SHORTCODE, self::TBL_CATEGORY), 63 | $this->tn(self::TBL_SHORTCODE) 64 | ); 65 | 66 | $this->dropTable($this->tn(self::TBL_SHORTCODE)); 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /src/migrations/m170105_094960_seo_clear_url.php: -------------------------------------------------------------------------------- 1 | insert($this->tn(self::TBL_EVENT), [ 11 | 'id' => 5, 12 | 'app_id' => self::APP_FRONTEND, 13 | 'plugin_id' => self::EVENTS_CORE, // Hello, world 14 | 'category_id' => self::CAT_SEO, 15 | 'trigger_class' => 'yii\base\Application', 16 | 'trigger_event' => 'beforeRequest', 17 | 'handler_class' => 'lo\plugins\core\SeoHandler', 18 | 'handler_method' => 'clearUrl', 19 | 'data' => '{}', 20 | 'status' => self::EVENTS_ACTIVE 21 | ]); 22 | } 23 | 24 | public function down() 25 | { 26 | $this->delete($this->tn(self::TBL_EVENT), ['id' => 5]); 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /src/models/App.php: -------------------------------------------------------------------------------- 1 | 255], 31 | ]; 32 | } 33 | 34 | /** 35 | * @inheritdoc 36 | */ 37 | public function attributeLabels() 38 | { 39 | return [ 40 | 'id' => Yii::t('plugin', 'ID'), 41 | 'name' => Yii::t('plugin', 'Name'), 42 | ]; 43 | } 44 | 45 | /** 46 | * @return \yii\db\ActiveQuery 47 | */ 48 | public function getEvents() 49 | { 50 | return $this->hasMany(Event::class, ['app_id' => 'id']); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/models/Category.php: -------------------------------------------------------------------------------- 1 | 255], 36 | ]; 37 | } 38 | 39 | /** 40 | * @inheritdoc 41 | */ 42 | public function attributeLabels() 43 | { 44 | return [ 45 | 'id' => Yii::t('plugin', 'ID'), 46 | 'name' => Yii::t('plugin', 'Name'), 47 | ]; 48 | } 49 | 50 | /** 51 | * @inheritdoc 52 | * @return CategoryQuery the active query used by this AR class. 53 | */ 54 | public static function find() 55 | { 56 | return new CategoryQuery(get_called_class()); 57 | } 58 | 59 | /** 60 | * @return \yii\db\ActiveQuery 61 | */ 62 | public function getEvents() 63 | { 64 | return $this->hasMany(Event::class, ['category_id' => 'id']); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/models/Event.php: -------------------------------------------------------------------------------- 1 | 255], 52 | [['pos'], 'default', 'value' => 1], 53 | [['data'], JsonValidator::class], 54 | [['handler_class', 'trigger_class'], ClassNameValidator::class], 55 | [['handler_method'], CallableValidator::class, 'callableAttribute' => 'handler_class'] 56 | ]; 57 | } 58 | 59 | /** 60 | * @inheritdoc 61 | */ 62 | public function attributeLabels() 63 | { 64 | return [ 65 | 'id' => Yii::t('plugin', 'ID'), 66 | 'app_id' => Yii::t('plugin', 'App ID'), 67 | 'plugin_id' => Yii::t('plugin', 'Plugin ID'), 68 | 'category_id' => Yii::t('plugin', 'Category'), 69 | 'trigger_class' => Yii::t('plugin', 'Trigger Class'), 70 | 'trigger_event' => Yii::t('plugin', 'Trigger Event'), 71 | 'handler_class' => Yii::t('plugin', 'Handler Class'), 72 | 'handler_method' => Yii::t('plugin', 'Handler Method'), 73 | 'data' => Yii::t('plugin', 'Data'), 74 | 'pos' => Yii::t('plugin', 'Position'), 75 | 'status' => Yii::t('plugin', 'Status'), 76 | 'text' => Yii::t('plugin', 'Text'), 77 | ]; 78 | } 79 | 80 | /** 81 | * @return \yii\db\ActiveQuery 82 | */ 83 | public function getPlugin() 84 | { 85 | return $this->hasOne(Plugin::class, ['id' => 'plugin_id']); 86 | } 87 | 88 | /** 89 | * @return \yii\db\ActiveQuery 90 | */ 91 | public function getCategory() 92 | { 93 | return $this->hasOne(Category::class, ['id' => 'category_id']); 94 | } 95 | 96 | /** 97 | * @inheritdoc 98 | * @return EventQuery the active query used by this AR class. 99 | */ 100 | public static function find() 101 | { 102 | return new EventQuery(get_called_class()); 103 | } 104 | 105 | /** 106 | * @return string 107 | */ 108 | public function getTriggerClass() 109 | { 110 | return $this->trigger_class; 111 | } 112 | 113 | /** 114 | * @return string 115 | */ 116 | public function getTriggerEvent() 117 | { 118 | return $this->trigger_event; 119 | } 120 | 121 | /** 122 | * @return array 123 | */ 124 | public function getHandler() 125 | { 126 | return [ 127 | [$this->handler_class, $this->handler_method], 128 | JsonHelper::decode($this->data) 129 | ]; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/models/Plugin.php: -------------------------------------------------------------------------------- 1 | 255], 49 | [['hash'], 'string', 'max' => 32], 50 | ]; 51 | } 52 | 53 | /** 54 | * @inheritdoc 55 | */ 56 | public function attributeLabels() 57 | { 58 | return [ 59 | 'id' => Yii::t('plugin', 'ID'), 60 | 'name' => Yii::t('plugin', 'Name'), 61 | 'url' => Yii::t('plugin', 'Url'), 62 | 'version' => Yii::t('plugin', 'Version'), 63 | 'text' => Yii::t('plugin', 'Text'), 64 | 'author' => Yii::t('plugin', 'Author'), 65 | 'author_url' => Yii::t('plugin', 'Author Url'), 66 | 'status' => Yii::t('plugin', 'Status'), 67 | 'hash' => Yii::t('plugin', 'Hash'), 68 | ]; 69 | } 70 | 71 | /** 72 | * @return \yii\db\ActiveQuery 73 | */ 74 | public function getEvents() 75 | { 76 | return $this->hasMany(Event::class, ['plugin_id' => 'id']); 77 | } 78 | 79 | /** 80 | * @return \yii\db\ActiveQuery 81 | */ 82 | public function getShortcodes() 83 | { 84 | return $this->hasMany(Shortcode::class, ['plugin_id' => 'id']); 85 | } 86 | 87 | /** 88 | * @inheritdoc 89 | * @return PluginQuery the active query used by this AR class. 90 | */ 91 | public static function find() 92 | { 93 | return new PluginQuery(get_called_class()); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/models/Shortcode.php: -------------------------------------------------------------------------------- 1 | Yii::t('plugin', 'ID'), 63 | 'app_id' => Yii::t('plugin', 'App ID'), 64 | 'plugin_id' => Yii::t('plugin', 'Plugin ID'), 65 | 'category_id' => Yii::t('plugin', 'Category'), 66 | 'handler_class' => Yii::t('plugin', 'Handler Class'), 67 | 'tag' => Yii::t('plugin', 'Tag'), 68 | 'tooltip' => Yii::t('plugin', 'Tooltip'), 69 | 'data' => Yii::t('plugin', 'Data'), 70 | 'text' => Yii::t('plugin', 'Text'), 71 | 'status' => Yii::t('plugin', 'Status') 72 | ]; 73 | } 74 | 75 | /** 76 | * @return \yii\db\ActiveQuery 77 | */ 78 | public function getPlugin() 79 | { 80 | return $this->hasOne(Plugin::class, ['id' => 'plugin_id']); 81 | } 82 | 83 | /** 84 | * @return \yii\db\ActiveQuery 85 | */ 86 | public function getCategory() 87 | { 88 | return $this->hasOne(Category::class, ['id' => 'category_id']); 89 | } 90 | 91 | /** 92 | * @inheritdoc 93 | * @return ShortcodeQuery the active query used by this AR class. 94 | */ 95 | public static function find() 96 | { 97 | return new ShortcodeQuery(get_called_class()); 98 | } 99 | 100 | /** 101 | * @param null $appId 102 | * @return array 103 | */ 104 | public static function shortcodeList($appId = null) 105 | { 106 | if (!$appId) return []; 107 | 108 | return self::find() 109 | ->alias('s') 110 | ->innerJoinWith(['plugin p']) 111 | ->where(['AND', 112 | ['s.status' => self::STATUS_ACTIVE], 113 | ['p.status' => Plugin::STATUS_ACTIVE], 114 | ['s.app_id' => [$appId, BasePlugin::APP_COMMON]] 115 | ]) 116 | ->all(); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/models/query/CategoryQuery.php: -------------------------------------------------------------------------------- 1 | andWhere('[[status]]=1'); 18 | return $this; 19 | }*/ 20 | 21 | /** 22 | * @inheritdoc 23 | * @return Category[]|array 24 | */ 25 | public function all($db = null) 26 | { 27 | return parent::all($db); 28 | } 29 | 30 | /** 31 | * @inheritdoc 32 | * @return Category|array|null 33 | */ 34 | public function one($db = null) 35 | { 36 | return parent::one($db); 37 | } 38 | } -------------------------------------------------------------------------------- /src/models/query/EventQuery.php: -------------------------------------------------------------------------------- 1 | andWhere('[[status]]=1'); 18 | return $this; 19 | }*/ 20 | 21 | /** 22 | * @inheritdoc 23 | * @return Event[]|array 24 | */ 25 | public function all($db = null) 26 | { 27 | return parent::all($db); 28 | } 29 | 30 | /** 31 | * @inheritdoc 32 | * @return Event|array|null 33 | */ 34 | public function one($db = null) 35 | { 36 | return parent::one($db); 37 | } 38 | } -------------------------------------------------------------------------------- /src/models/query/PluginQuery.php: -------------------------------------------------------------------------------- 1 | andWhere('[[status]]=1'); 18 | return $this; 19 | }*/ 20 | 21 | /** 22 | * @inheritdoc 23 | * @return Event[]|array 24 | */ 25 | public function all($db = null) 26 | { 27 | return parent::all($db); 28 | } 29 | 30 | /** 31 | * @inheritdoc 32 | * @return Event|array|null 33 | */ 34 | public function one($db = null) 35 | { 36 | return parent::one($db); 37 | } 38 | } -------------------------------------------------------------------------------- /src/models/search/CategorySearch.php: -------------------------------------------------------------------------------- 1 | $query, 35 | ]); 36 | 37 | $this->load($params); 38 | 39 | if (!$this->validate()) { 40 | // uncomment the following line if you do not want to return any records when validation fails 41 | // $query->where('0=1'); 42 | return $dataProvider; 43 | } 44 | 45 | $query->andFilterWhere([ 46 | 'id' => $this->id 47 | ]); 48 | 49 | $query->andFilterWhere(['like', 'name', $this->name]); 50 | 51 | return $dataProvider; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/models/search/EventSearch.php: -------------------------------------------------------------------------------- 1 | with('category'); 32 | 33 | $dataProvider = new ActiveDataProvider([ 34 | 'query' => $query, 35 | ]); 36 | 37 | $this->load($params); 38 | 39 | if (!$this->validate()) { 40 | // uncomment the following line if you do not want to return any records when validation fails 41 | // $query->where('0=1'); 42 | return $dataProvider; 43 | } 44 | 45 | $query->andFilterWhere([ 46 | 'id' => $this->id, 47 | 'plugin_id' => $this->plugin_id, 48 | 'app_id' => $this->app_id, 49 | 'category_id' => $this->category_id, 50 | 'status' => $this->status 51 | ]); 52 | 53 | $query->andFilterWhere(['like', 'trigger_class', $this->trigger_class]) 54 | ->andFilterWhere(['like', 'trigger_event', $this->trigger_event]) 55 | ->andFilterWhere(['like', 'handler_class', $this->handler_class]) 56 | ->andFilterWhere(['like', 'handler_method', $this->handler_method]) 57 | ->andFilterWhere(['like', 'data', $this->data]); 58 | 59 | return $dataProvider; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/models/search/PluginSearch.php: -------------------------------------------------------------------------------- 1 | $query, 35 | ]); 36 | 37 | $this->load($params); 38 | 39 | if (!$this->validate()) { 40 | // uncomment the following line if you do not want to return any records when validation fails 41 | // $query->where('0=1'); 42 | return $dataProvider; 43 | } 44 | 45 | $query->andFilterWhere([ 46 | 'id' => $this->id, 47 | 'status' => $this->status, 48 | ]); 49 | 50 | $query->andFilterWhere(['like', 'name', $this->name]) 51 | ->andFilterWhere(['like', 'url', $this->url]) 52 | ->andFilterWhere(['like', 'version', $this->version]) 53 | ->andFilterWhere(['like', 'text', $this->text]) 54 | ->andFilterWhere(['like', 'author', $this->author]) 55 | ->andFilterWhere(['like', 'author_url', $this->author_url]); 56 | 57 | return $dataProvider; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/models/search/ShortcodeSearch.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class ShortcodeSearch extends Shortcode 14 | { 15 | /** 16 | * @inheritdoc 17 | */ 18 | public function rules() 19 | { 20 | return [ 21 | [['id', 'plugin_id', 'category_id', 'app_id', 'status'], 'integer'], 22 | [['handler_class', 'data', 'tag', 'tooltip'], 'safe'], 23 | ]; 24 | } 25 | 26 | /** 27 | * Creates data provider instance with search query applied 28 | * @param array $params 29 | * @return ActiveDataProvider 30 | */ 31 | public function search($params) 32 | { 33 | $query = Shortcode::find()->with('category'); 34 | 35 | $dataProvider = new ActiveDataProvider([ 36 | 'query' => $query, 37 | ]); 38 | 39 | $this->load($params); 40 | 41 | if (!$this->validate()) { 42 | // uncomment the following line if you do not want to return any records when validation fails 43 | // $query->where('0=1'); 44 | return $dataProvider; 45 | } 46 | 47 | $query->andFilterWhere([ 48 | 'id' => $this->id, 49 | 'plugin_id' => $this->plugin_id, 50 | 'app_id' => $this->app_id, 51 | 'category_id' => $this->category_id, 52 | 'status' => $this->status 53 | ]); 54 | 55 | $query->andFilterWhere(['like', 'handler_class', $this->handler_class]) 56 | ->andFilterWhere(['like', 'tag', $this->tag]) 57 | ->andFilterWhere(['like', 'tooltip', $this->tooltip]) 58 | ->andFilterWhere(['like', 'data', $this->data]); 59 | 60 | return $dataProvider; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/repositories/EventDbRepository.php: -------------------------------------------------------------------------------- 1 | alias('e') 34 | ->innerJoinWith(['plugin p']) 35 | ->where(['AND', 36 | ['e.status' => Event::STATUS_ACTIVE], 37 | ['p.status' => Plugin::STATUS_ACTIVE], 38 | ['e.app_id' => [$appId, BasePlugin::APP_COMMON]] 39 | ]) 40 | ->orderBy($order) 41 | ->all(); 42 | 43 | return $events; 44 | } 45 | 46 | /** 47 | * @param $pluginClass 48 | */ 49 | public function populate($pluginClass) 50 | { 51 | $this->_data = Event::find()->where(['handler_class' => $pluginClass])->all(); 52 | } 53 | 54 | /** 55 | * @param Event $item 56 | * @throws \Exception 57 | */ 58 | public function add(Event $item) 59 | { 60 | if (!$item->getIsNewRecord()) { 61 | throw new \InvalidArgumentException('Model is exists'); 62 | } 63 | if (!$item->insert()) { 64 | throw new \Exception(Html::errorSummary($item)); 65 | } 66 | } 67 | 68 | /** 69 | * @param Event $item 70 | * @throws \Exception 71 | */ 72 | public function save(Event $item) 73 | { 74 | if ($item->getIsNewRecord()) { 75 | throw new \InvalidArgumentException('Model not exists'); 76 | } 77 | if (!$item->update()) { 78 | throw new \Exception(Html::errorSummary($item)); 79 | } 80 | } 81 | 82 | /** 83 | * @param array $data 84 | * @return Event 85 | */ 86 | public function addEvent($data) 87 | { 88 | $data = (array)new EventDbRepositoryMap($data); 89 | $model = new Event(); 90 | $model->setAttributes($data); 91 | $this->add($model); 92 | return $model; 93 | } 94 | 95 | /** 96 | * @param array $data 97 | */ 98 | public function deleteEvent($data) 99 | { 100 | $data = new EventDbRepositoryMap($data); 101 | $model = $this->find($data->id); 102 | $model->delete(); 103 | } 104 | } -------------------------------------------------------------------------------- /src/repositories/EventDbRepositoryMap.php: -------------------------------------------------------------------------------- 1 | $value) { 33 | if (property_exists($this, $key)) { 34 | $this->$key = $value; 35 | } 36 | } 37 | if ($this->data) { 38 | $this->data = JsonHelper::encode($this->data); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/repositories/EventDirRepository.php: -------------------------------------------------------------------------------- 1 | $events) { 17 | $pos++; 18 | foreach ($events as $eventName => $handler) { 19 | $handlerMethod = is_array($handler) ? $handler[0] : $handler; 20 | $this->_data[] = [ 21 | 'app_id' => $this->checkApp($pluginClass), 22 | 'category_id' => Category::CAT_PLUGINS, 23 | 'trigger_class' => $className, 24 | 'trigger_event' => $eventName, 25 | 'handler_class' => $pluginClass, 26 | 'handler_method' => $handlerMethod, 27 | 'pos' => $pos, 28 | 'data' => isset($handler[1]) ? $handler[1] : [] 29 | ]; 30 | } 31 | }; 32 | } 33 | 34 | /** 35 | * Convert string AppId to int app_id 36 | * @param $pluginClass 37 | * @return int $app_id 38 | */ 39 | protected function checkApp($pluginClass) 40 | { 41 | if (!isset($pluginClass::$appId)) return BasePlugin::APP_FRONTEND; 42 | return $pluginClass::$appId; 43 | } 44 | } -------------------------------------------------------------------------------- /src/repositories/EventRepository.php: -------------------------------------------------------------------------------- 1 | _data) { 16 | $this->populate($pluginClass); 17 | } 18 | return $this->_data; 19 | } 20 | 21 | /** 22 | * @param $pluginClass 23 | */ 24 | abstract protected function populate($pluginClass); 25 | } -------------------------------------------------------------------------------- /src/repositories/PluginDbRepository.php: -------------------------------------------------------------------------------- 1 | where(['<>', 'id', Plugin::EVENTS_CORE])->all(); 31 | return $items; 32 | } 33 | 34 | /** 35 | * @param $hash 36 | * @return Plugin|null 37 | */ 38 | public function findByHash($hash) 39 | { 40 | if (!$item = Plugin::find()->where(['hash' => $hash])->limit(1)->one()) { 41 | throw new \InvalidArgumentException('Model not found'); 42 | } 43 | return $item; 44 | } 45 | 46 | /** 47 | * populate data 48 | */ 49 | protected function populate() 50 | { 51 | $this->_data = Plugin::find()->where(['<>', 'id', Plugin::EVENTS_CORE])->asArray()->all(); 52 | } 53 | 54 | /** 55 | * @param Plugin $item 56 | * @throws \Exception 57 | */ 58 | public function add(Plugin $item) 59 | { 60 | if (!$item->getIsNewRecord()) { 61 | throw new \InvalidArgumentException('Model is exists'); 62 | } 63 | if (!$item->insert()) { 64 | throw new \Exception(Html::errorSummary($item)); 65 | } 66 | } 67 | 68 | /** 69 | * @param Plugin $item 70 | * @throws \Exception 71 | */ 72 | public function save(Plugin $item) 73 | { 74 | if ($item->getIsNewRecord()) { 75 | throw new \InvalidArgumentException('Model not exists'); 76 | } 77 | if (!$item->update()) { 78 | throw new \Exception(Html::errorSummary($item)); 79 | } 80 | } 81 | 82 | /** 83 | * @param $hash 84 | * @param array $data 85 | * @return Plugin|null 86 | */ 87 | public function savePlugin($hash, $data) 88 | { 89 | $data = (array) new PluginDbRepositoryMap($data); 90 | $model = $this->findByHash($hash); 91 | $model->setAttributes($data); 92 | $this->save($model); 93 | return $model; 94 | } 95 | 96 | /** 97 | * @param array $data 98 | * @return Plugin 99 | */ 100 | public function addPlugin($data) 101 | { 102 | $data = (array) new PluginDbRepositoryMap($data); 103 | $model = new Plugin(); 104 | $model->setAttributes($data); 105 | $this->add($model); 106 | return $model; 107 | } 108 | 109 | /** 110 | * @param Plugin $model 111 | * @param Event $event 112 | */ 113 | public function linkEvent(Plugin $model, Event $event){ 114 | $model->link('events', $event); 115 | } 116 | 117 | /** 118 | * @param Plugin $model 119 | * @param Shortcode $shortcode 120 | */ 121 | public function linkShortcode(Plugin $model, Shortcode $shortcode){ 122 | $model->link('shortcodes', $shortcode); 123 | } 124 | 125 | } -------------------------------------------------------------------------------- /src/repositories/PluginDbRepositoryMap.php: -------------------------------------------------------------------------------- 1 | $value) { 29 | if (property_exists($this, $key)) { 30 | $this->$key = $value; 31 | } 32 | } 33 | 34 | if (isset($data['new_version'])) { 35 | $this->version = $data['new_version']; 36 | } 37 | 38 | if (isset($data['new_hash'])) { 39 | $this->hash = $data['new_hash']; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/repositories/PluginDirRepository.php: -------------------------------------------------------------------------------- 1 | _dirs = $dirs; 23 | } 24 | 25 | protected $_methods = ['events', 'shortcodes']; 26 | 27 | /** 28 | * populate pool storage 29 | */ 30 | protected function populate() 31 | { 32 | ClassHelper::getAllClasses($this->_dirs, function ($class) { 33 | foreach ($this->_methods as $type) { 34 | /** @var BasePlugin|BaseShortcode $class */ 35 | if (is_callable([$class, $type])) { 36 | $this->_data[] = $this->getInfo($class, $type); 37 | return $class; 38 | } 39 | } 40 | return null; 41 | }); 42 | } 43 | 44 | /** 45 | * @param $pluginClass 46 | * @param $type 47 | * @return array 48 | */ 49 | protected function getInfo($pluginClass, $type) 50 | { 51 | $plugin_info = ClassHelper::getPluginInfo($pluginClass); 52 | 53 | preg_match('|Plugin Name:(.*)$|mi', $plugin_info, $name); 54 | preg_match('|Plugin URI:(.*)$|mi', $plugin_info, $url); 55 | preg_match('|Version:(.*)$|mi', $plugin_info, $version); 56 | preg_match('|Description:(.*)$|mi', $plugin_info, $text); 57 | preg_match('|Author:(.*)$|mi', $plugin_info, $author); 58 | preg_match('|Author URI:(.*)$|mi', $plugin_info, $author_url); 59 | 60 | return [ 61 | 'handler_class' => $pluginClass, 62 | 'type' => $type, 63 | 'name' => trim(ArrayHelper::getValue($name, 1, 'plugin - ' . $pluginClass)), 64 | 'url' => trim(ArrayHelper::getValue($url, 1)), 65 | 'text' => trim(ArrayHelper::getValue($text, 1)), 66 | 'author' => trim(ArrayHelper::getValue($author, 1)), 67 | 'author_url' => trim(ArrayHelper::getValue($author_url, 1)), 68 | 'new_version' => trim(ArrayHelper::getValue($version, 1, '1.0')), 69 | 'new_hash' => md5($pluginClass) 70 | ]; 71 | } 72 | } -------------------------------------------------------------------------------- /src/repositories/PluginRepository.php: -------------------------------------------------------------------------------- 1 | _data) { 16 | $this->populate(); 17 | } 18 | return $this->_data; 19 | } 20 | 21 | /** 22 | * populate pool 23 | */ 24 | abstract protected function populate(); 25 | 26 | } -------------------------------------------------------------------------------- /src/repositories/ShortcodeDbRepository.php: -------------------------------------------------------------------------------- 1 | _data = Shortcode::find()->where(['handler_class' => $pluginClass])->all(); 30 | } 31 | 32 | /** 33 | * @param $shortcodes 34 | * @param $appId 35 | * @return array 36 | */ 37 | public function findShortcodesByNameAsArray($shortcodes, $appId) 38 | { 39 | return Shortcode::find()->alias('s')->innerJoinWith('plugin p')->where([ 40 | 's.tag' => $shortcodes, 41 | 's.app_id' => $appId, 42 | 's.status' => Shortcode::STATUS_ACTIVE, 43 | 'p.status' => Plugin::STATUS_ACTIVE 44 | 45 | ])->indexBy('tag')->asArray()->all(); 46 | } 47 | 48 | /** 49 | * @param Shortcode $item 50 | * @throws \Exception 51 | */ 52 | public function add(Shortcode $item) 53 | { 54 | if (!$item->getIsNewRecord()) { 55 | throw new \InvalidArgumentException('Model is exists'); 56 | } 57 | if (!$item->insert()) { 58 | throw new \Exception(Html::errorSummary($item)); 59 | } 60 | } 61 | 62 | /** 63 | * @param Shortcode $item 64 | * @throws \Exception 65 | */ 66 | public function save(Shortcode $item) 67 | { 68 | if ($item->getIsNewRecord()) { 69 | throw new \InvalidArgumentException('Model not exists'); 70 | } 71 | if (!$item->update()) { 72 | throw new \Exception(Html::errorSummary($item)); 73 | } 74 | } 75 | 76 | /** 77 | * @param array $data 78 | * @return Shortcode 79 | */ 80 | public function addShortcode($data) 81 | { 82 | $data = (array)new ShortcodeDbRepositoryMap($data); 83 | $model = new Shortcode(); 84 | $model->setAttributes($data); 85 | $this->add($model); 86 | return $model; 87 | } 88 | 89 | /** 90 | * @param array $data 91 | */ 92 | public function deleteShortcode($data) 93 | { 94 | $data = new ShortcodeDbRepositoryMap($data); 95 | $model = $this->find($data->id); 96 | $model->delete(); 97 | } 98 | } -------------------------------------------------------------------------------- /src/repositories/ShortcodeDbRepositoryMap.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class ShortcodeDbRepositoryMap 13 | { 14 | public $id; 15 | public $app_id; 16 | public $handler_class; 17 | public $tag; 18 | public $tooltip; 19 | public $data; 20 | public $text; 21 | public $status = Shortcode::STATUS_ACTIVE; 22 | 23 | /** 24 | * ShortcodeDbRepositoryMap constructor. 25 | * @param array $data 26 | */ 27 | public function __construct($data = []) 28 | { 29 | foreach ($data as $key => $value) { 30 | if (property_exists($this, $key)) { 31 | $this->$key = $value; 32 | } 33 | } 34 | if ($this->data) { 35 | $this->data = JsonHelper::encode($this->data); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/repositories/ShortcodeDirRepository.php: -------------------------------------------------------------------------------- 1 | function(){...}, 13 | * 'tag' => [MyShortcode::class, 'widget'], 14 | * 'tag' => [ 15 | * 'callback' => [], 16 | * 'tooltip' => '', 17 | * 'config' => [], 18 | * ] 19 | * ] 20 | * @param BaseShortcode $pluginClass 21 | * @throws \Exception 22 | */ 23 | public function populate($pluginClass) 24 | { 25 | foreach ($pluginClass::shortcodes() as $tag => $item) { 26 | if ($tag) { 27 | if (is_callable($item)) { 28 | $data = [ 29 | 'app_id' => $this->checkApp($pluginClass), 30 | 'handler_class' => $pluginClass, 31 | 'tag' => $tag, 32 | 'tooltip' => "[$tag]", 33 | 'data' => null 34 | ]; 35 | } else { 36 | if (!isset($item['callback'])) { 37 | throw new \Exception("Callback is empty in shortcode $tag"); 38 | } 39 | if (!is_callable($item['callback'])) { 40 | throw new \Exception("Callback is not callable in shortcode $tag"); 41 | } 42 | $data = [ 43 | 'app_id' => $this->checkApp($pluginClass), 44 | 'handler_class' => $pluginClass, 45 | 'tag' => $tag, 46 | 'tooltip' => ArrayHelper::getValue($item, 'tooltip', "[$tag]"), 47 | 'data' => ArrayHelper::getValue($item, 'config'), 48 | ]; 49 | } 50 | $this->_data[] = $data; 51 | } 52 | }; 53 | } 54 | 55 | /** 56 | * Convert string AppId to int app_id 57 | * @param $pluginClass 58 | * @return int $app_id 59 | */ 60 | protected function checkApp($pluginClass) 61 | { 62 | if (!isset($pluginClass::$appId)) return BaseShortcode::APP_FRONTEND; 63 | return $pluginClass::$appId; 64 | } 65 | } -------------------------------------------------------------------------------- /src/repositories/ShortcodeRepository.php: -------------------------------------------------------------------------------- 1 | _data) { 16 | $this->populate($pluginClass); 17 | } 18 | return $this->_data; 19 | } 20 | 21 | /** 22 | * @param $pluginClass 23 | */ 24 | abstract protected function populate($pluginClass); 25 | } -------------------------------------------------------------------------------- /src/services/PluginService.php: -------------------------------------------------------------------------------- 1 | noty = $noty; 67 | $this->transaction = $transaction; 68 | $this->pluginDirRepository = $pluginDirRepository; 69 | $this->pluginDbRepository = $pluginDbRepository; 70 | $this->eventDirRepository = $eventDirRepository; 71 | $this->eventDbRepository = $eventDbRepository; 72 | $this->shortcodeDirRepository = $shortcodeDirRepository; 73 | $this->shortcodeDbRepository = $shortcodeDbRepository; 74 | } 75 | 76 | 77 | /** 78 | * @param $dirs 79 | * @return mixed 80 | * @throws InvalidConfigException 81 | */ 82 | public function getPlugins($dirs) 83 | { 84 | $this->pluginDirRepository->setDirs($dirs); 85 | 86 | $pluginsDiffDir = $this->getPluginsDiffDir(); 87 | $pluginsDiffDb = $this->getPluginsDiffDb(); 88 | 89 | $pluginsPoolDir = $this->getPluginsPoolDir(); 90 | $pluginsPoolDb = $this->getPluginsPoolDb(); 91 | 92 | $data = []; 93 | foreach (array_filter(array_diff($pluginsDiffDir->getDiff(), $pluginsDiffDb->getDiff())) as $key => $value) { 94 | $pool = ArrayHelper::merge($pluginsPoolDb->getInfo($key), $pluginsPoolDir->getInfo($key)); 95 | $data[$key] = new PluginDataDto($pool); 96 | } 97 | return $data; 98 | } 99 | 100 | /** 101 | * @param $hash 102 | * @throws Exception 103 | */ 104 | public function installPlugin($hash) 105 | { 106 | $pluginsPoolDir = $this->getPluginsPoolDir(); 107 | $pluginInfoDir = $pluginsPoolDir->getInfo($hash); 108 | 109 | if (!$pluginInfoDir) { 110 | throw new Exception("Can't install plugin"); 111 | } 112 | 113 | $pluginsPoolDb = $this->getPluginsPoolDb(); 114 | $pluginInfoDb = $pluginsPoolDb->getInfo($hash); 115 | 116 | $pluginDataDto = new PluginDataDto($pluginInfoDir); 117 | 118 | $pluginClass = $pluginDataDto->getPluginClass(); 119 | 120 | $process = $this->transaction->begin(); 121 | 122 | try { 123 | /** install shortcodes */ 124 | if ($pluginDataDto->isShortcodes()) { 125 | $this->installShortcodes($hash, $pluginClass, $pluginInfoDb, $pluginInfoDir); 126 | } 127 | 128 | /** install events */ 129 | if ($pluginDataDto->isEvents()) { 130 | $this->installEvents($hash, $pluginClass, $pluginInfoDb, $pluginInfoDir); 131 | } 132 | $this->transaction->commit($process); 133 | } catch (\Exception $e) { 134 | $this->transaction->rollBack($process); 135 | $this->noty->error($e->getMessage()); 136 | } 137 | } 138 | 139 | /** 140 | * @param $hash 141 | * @param $pluginClass 142 | * @param $pluginInfoDb 143 | * @param $pluginInfoDir 144 | */ 145 | protected function installEvents($hash, $pluginClass, $pluginInfoDb, $pluginInfoDir) 146 | { 147 | $eventsArrayDir = $this->eventDirRepository->findEventsByHandler($pluginClass); 148 | 149 | if (!$pluginInfoDb) { 150 | /** Install plugin */ 151 | $pluginModel = $this->pluginDbRepository->addPlugin($pluginInfoDir); 152 | 153 | foreach ($eventsArrayDir as $data) { 154 | $eventModel = $this->eventDbRepository->addEvent($data); 155 | $this->pluginDbRepository->linkEvent($pluginModel, $eventModel); 156 | } 157 | 158 | $this->noty->success('Plugin installed'); 159 | 160 | } else { 161 | /** Update plugin */ 162 | $data = ArrayHelper::merge($pluginInfoDb, $pluginInfoDir); 163 | $pluginModel = $this->pluginDbRepository->savePlugin($hash, $data); 164 | 165 | $eventsArrayDb = $this->eventDbRepository->findEventsByHandler($pluginClass); 166 | 167 | $eventsDiffDir = new EventsDiffDto($eventsArrayDir); 168 | $eventsDiffDb = new EventsDiffDto($eventsArrayDb); 169 | 170 | $eventsPoolDir = new EventsPoolDto($eventsArrayDir); 171 | $eventsPoolDb = new EventsPoolDto($eventsArrayDb); 172 | 173 | /** Get Deleted events */ 174 | foreach (array_filter(array_diff($eventsDiffDb->getDiff(), $eventsDiffDir->getDiff())) as $key => $value) { 175 | $data = $eventsPoolDb->getInfo($key); 176 | $this->eventDbRepository->deleteEvent($data); 177 | } 178 | 179 | /** Get Installed events */ 180 | foreach (array_filter(array_diff($eventsDiffDir->getDiff(), $eventsDiffDb->getDiff())) as $key => $value) { 181 | $data = $eventsPoolDir->getInfo($key); 182 | $eventModel = $this->eventDbRepository->addEvent($data); 183 | $this->pluginDbRepository->linkEvent($pluginModel, $eventModel); 184 | } 185 | 186 | $this->noty->success('Plugin updated'); 187 | } 188 | } 189 | 190 | /** 191 | * @param $hash 192 | * @param $pluginClass 193 | * @param $pluginInfoDb 194 | * @param $pluginInfoDir 195 | */ 196 | protected function installShortcodes($hash, $pluginClass, $pluginInfoDb, $pluginInfoDir) 197 | { 198 | $shortcodesArrayDir = $this->shortcodeDirRepository->findShortcodesByHandler($pluginClass); 199 | 200 | if (!$pluginInfoDb) { 201 | /** Install plugin */ 202 | $pluginModel = $this->pluginDbRepository->addPlugin($pluginInfoDir); 203 | 204 | foreach ($shortcodesArrayDir as $data) { 205 | $shortcodeModel = $this->shortcodeDbRepository->addShortcode($data); 206 | $this->pluginDbRepository->linkShortcode($pluginModel, $shortcodeModel); 207 | } 208 | 209 | $this->noty->success('Shortcodes installed'); 210 | 211 | } else { 212 | /** Update plugin */ 213 | $data = ArrayHelper::merge($pluginInfoDb, $pluginInfoDir); 214 | $pluginModel = $this->pluginDbRepository->savePlugin($hash, $data); 215 | 216 | $shortcodesArrayDb = $this->shortcodeDbRepository->findShortcodesByHandler($pluginClass); 217 | 218 | $shortcodesDiffDir = new ShortcodesDiffDto($shortcodesArrayDir); 219 | $shortcodesDiffDb = new ShortcodesDiffDto($shortcodesArrayDb); 220 | 221 | $shortcodesPoolDir = new ShortcodesPoolDto($shortcodesArrayDir); 222 | $shortcodesPoolDb = new ShortcodesPoolDto($shortcodesArrayDb); 223 | 224 | /** Get Deleted shortcodes */ 225 | foreach (array_filter(array_diff($shortcodesDiffDb->getDiff(), $shortcodesDiffDir->getDiff())) as $key => $value) { 226 | $data = $shortcodesPoolDb->getInfo($key); 227 | $this->shortcodeDbRepository->deleteShortcode($data); 228 | } 229 | 230 | /** Get Installed shortcodes */ 231 | foreach (array_filter(array_diff($shortcodesDiffDir->getDiff(), $shortcodesDiffDb->getDiff())) as $key => $value) { 232 | $data = $shortcodesPoolDir->getInfo($key); 233 | $shortcodeModel = $this->shortcodeDbRepository->addShortcode($data); 234 | $this->pluginDbRepository->linkShortcode($pluginModel, $shortcodeModel); 235 | } 236 | 237 | $this->noty->success('Shortcode updated'); 238 | } 239 | } 240 | 241 | /** 242 | * @return PluginsPoolDto 243 | */ 244 | protected function getPluginsPoolDb() 245 | { 246 | if (!$this->_pluginsPoolDb) { 247 | $this->_pluginsPoolDb = new PluginsPoolDto($this->pluginDbRepository->findAllAsArray()); 248 | } 249 | return $this->_pluginsPoolDb; 250 | } 251 | 252 | /** 253 | * @return PluginsPoolDto 254 | */ 255 | protected function getPluginsPoolDir() 256 | { 257 | if (!$this->_pluginsPoolDir) { 258 | $this->_pluginsPoolDir = new PluginsPoolDto($this->pluginDirRepository->findAllAsArray()); 259 | } 260 | return $this->_pluginsPoolDir; 261 | } 262 | 263 | /** 264 | * @return PluginsDiffDto 265 | */ 266 | protected function getPluginsDiffDb() 267 | { 268 | if (!$this->_pluginsDiffDb) { 269 | $this->_pluginsDiffDb = new PluginsDiffDto($this->pluginDbRepository->findAllAsArray()); 270 | } 271 | return $this->_pluginsDiffDb; 272 | } 273 | 274 | /** 275 | * @return PluginsDiffDto 276 | */ 277 | protected function getPluginsDiffDir() 278 | { 279 | if (!$this->_pluginsDiffDir) { 280 | $this->_pluginsDiffDir = new PluginsDiffDto($this->pluginDirRepository->findAllAsArray()); 281 | } 282 | return $this->_pluginsDiffDir; 283 | } 284 | 285 | } 286 | -------------------------------------------------------------------------------- /src/services/ShortcodeService.php: -------------------------------------------------------------------------------- 1 | shortcodeParser = $shortcodeParser; 38 | $this->shortcodeDbRepository = $shortcodeDbRepository; 39 | } 40 | 41 | /** 42 | * @param $blocks 43 | */ 44 | public function addIgnoreBlocks($blocks) 45 | { 46 | $this->shortcodeParser->addIgnoreBlocks($blocks); 47 | } 48 | 49 | /** 50 | * @param $content 51 | * @return array 52 | */ 53 | public function getShortcodesFromContent($content) 54 | { 55 | return $this->shortcodeParser->getShortcodesFromContent($content); 56 | } 57 | 58 | /** 59 | * @param $shortcodes 60 | * @param $appId 61 | */ 62 | public function setShortcodesFromDb($shortcodes, $appId) 63 | { 64 | $shortcodes = $this->shortcodeDbRepository->findShortcodesByNameAsArray($shortcodes, $appId); 65 | if ($shortcodes) { 66 | $callbacs = new ShortcodesDbCallbacksDto($shortcodes); 67 | $this->shortcodesCallback = $callbacs->data; 68 | } 69 | } 70 | 71 | /** 72 | * @param $content 73 | * @return string 74 | */ 75 | public function parseShortcodes($content) 76 | { 77 | if (!$this->shortcodesCallback) return $content; 78 | 79 | foreach ($this->shortcodesCallback as $parser) { 80 | $this->shortcodeParser->addShortcode($parser); 81 | } 82 | 83 | return $this->shortcodeParser->doShortcode($content); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/shortcodes/ShortcodeParserMap.php: -------------------------------------------------------------------------------- 1 | $value) { 22 | if (property_exists($this, $key)) { 23 | $this->$key = $value; 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/shortcodes/ShortcodeWidget.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class ShortcodeWidget extends Widget 12 | { 13 | /** 14 | * Content inner shorcode 15 | * ``` 16 | * [code]...content here...[\code] 17 | * ``` 18 | * @var string 19 | */ 20 | public $content; 21 | 22 | /** 23 | * @param string $name 24 | * @param mixed $string 25 | */ 26 | public function __set($name, $string) 27 | { 28 | if (property_exists($this, $name)) { 29 | $this->$name = $string; 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/validators/CallableValidator.php: -------------------------------------------------------------------------------- 1 | message === null) { 43 | $this->message = Yii::t('plugin', '"{attribute}" must be a callable as [{callableValue}::{value}]'); 44 | } 45 | if ($this->callableAttribute === null) { 46 | throw new InvalidConfigException('CallableValidator::callableAttribute must be set'); 47 | } 48 | } 49 | 50 | /** 51 | * @inheritdoc 52 | */ 53 | public function validateAttribute($model, $attribute) 54 | { 55 | $value = $model->$attribute; 56 | 57 | if (is_array($value)) { 58 | $this->addError($model, $attribute, Yii::t('yii', '{attribute} is invalid.')); 59 | return; 60 | } 61 | 62 | $callableAttribute = $this->callableAttribute; 63 | $this->callableValue = $model->$callableAttribute; 64 | $result = $this->validateValue($value); 65 | 66 | if (!empty($result)) { 67 | $this->addError($model, $attribute, $result[0], $result[1]); 68 | return; 69 | } 70 | } 71 | 72 | /** 73 | * @inheritdoc 74 | */ 75 | protected function validateValue($value) 76 | { 77 | if (!is_callable([$this->callableValue, $value])) { 78 | return [$this->message, [ 79 | 'value' => $value, 80 | 'callableAttribute' => $this->callableAttribute, 81 | 'callableValue' => $this->callableValue 82 | ]]; 83 | } else { 84 | return null; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/validators/ClassNameValidator.php: -------------------------------------------------------------------------------- 1 | message === null) { 21 | $this->message = Yii::t('plugin', '"{attribute}" must be a valid JSON'); 22 | } 23 | } 24 | 25 | /** 26 | * @param mixed $value 27 | * @return array|null 28 | */ 29 | public function validateValue($value) 30 | { 31 | if ($value === null || $value === '') { 32 | return null; 33 | } 34 | 35 | if (!@json_decode($value)) { 36 | return [$this->message, []]; 37 | } 38 | 39 | return null; 40 | } 41 | 42 | /** 43 | * @param \yii\base\Model $model 44 | * @param string $attribute 45 | * @param \yii\web\View $view 46 | * @return string 47 | */ 48 | public function clientValidateAttribute($model, $attribute, $view) 49 | { 50 | $message = Yii::$app->getI18n()->format($this->message, [ 51 | 'attribute' => $model->getAttributeLabel($attribute) 52 | ], Yii::$app->language); 53 | return <<<"JS" 54 | try { 55 | if(value) JSON.parse(value); 56 | } catch (e) { 57 | messages.push('{$message}') 58 | } 59 | JS; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/views/_menu.php: -------------------------------------------------------------------------------- 1 | [ 11 | 'class' => 'nav-tabs', 12 | 'style' => 'margin-bottom: 15px' 13 | ], 14 | 'items' => [ 15 | [ 16 | 'label' => Yii::t('plugin', 'Items'), 17 | 'url' => ['/plugins/plugin/index'], 18 | ], 19 | [ 20 | 'label' => Yii::t('plugin', 'Events'), 21 | 'url' => ['/plugins/event/index'], 22 | ], 23 | [ 24 | 'label' => Yii::t('plugin', 'Shortcodes'), 25 | 'url' => ['/plugins/shortcode/index'], 26 | ], 27 | [ 28 | 'label' => Yii::t('plugin', 'Categories'), 29 | 'url' => ['/plugins/category/index'], 30 | ], 31 | [ 32 | 'label' => Yii::t('plugin', 'Info'), 33 | 'url' => ['/plugins/plugin/info'], 34 | ], 35 | [ 36 | 'label' => Yii::t('plugin', 'Install'), 37 | 'url' => ['/plugins/plugin/install'], 38 | ], 39 | ] 40 | ]); 41 | -------------------------------------------------------------------------------- /src/views/category/_form.php: -------------------------------------------------------------------------------- 1 | 12 | 13 |
14 | 15 | 16 | 17 |
18 | 19 |
20 | field($model, 'name')->textInput(['maxlength' => true]) ?> 21 |
22 |
23 | 24 |
25 | isNewRecord ? Yii::t('plugin', 'Create') : Yii::t('plugin', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> 26 |
27 | 28 | 29 | 30 |
31 | -------------------------------------------------------------------------------- /src/views/category/_search.php: -------------------------------------------------------------------------------- 1 | 12 | 13 | 31 | -------------------------------------------------------------------------------- /src/views/category/create.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('plugin', 'Create Category'); 8 | $this->params['breadcrumbs'][] = ['label' => Yii::t('plugin', 'Categories'), 'url' => ['index']]; 9 | $this->params['breadcrumbs'][] = $this->title; 10 | ?> 11 |
12 | 13 | render('_form', [ 14 | 'model' => $model, 15 | ]) ?> 16 | 17 |
18 | -------------------------------------------------------------------------------- /src/views/category/index.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('plugin', 'Categories'); 14 | $this->params['breadcrumbs'][] = $this->title; 15 | ?> 16 |
17 | Yii::t('plugin', 'Category') 19 | ]), ['create'], ['class' => 'btn btn-success pull-right']) ?> 20 | render('/_menu') ?> 21 | 22 | $dataProvider, 24 | 'filterModel' => $searchModel, 25 | 'columns' => [ 26 | ['class' => 'yii\grid\SerialColumn'], 27 | 'name', 28 | [ 29 | 'class' => 'yii\grid\ActionColumn', 30 | 'template' => '{update} {delete}', 31 | 'options' => ['style' => 'width: 75px;'], 32 | 'buttons' => [ 33 | 'update' => function ($url) { 34 | return Html::a(BS::icon('pencil'), $url, [ 35 | 'class' => 'btn btn-xs btn-primary', 36 | 'title' => Yii::t('plugin', 'Update'), 37 | ]); 38 | }, 39 | 'delete' => function ($url) { 40 | return Html::a(BS::icon('trash'), $url, [ 41 | 'class' => 'btn btn-xs btn-danger', 42 | 'data-method' => 'post', 43 | 'data-confirm' => Yii::t('plugin', 'Are you sure to delete this item?'), 44 | 'title' => Yii::t('plugin', 'Delete'), 45 | ]); 46 | }, 47 | ] 48 | ], 49 | ], 50 | ]); ?> 51 | 52 |
53 | -------------------------------------------------------------------------------- /src/views/category/update.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('plugin', 'Update {modelClass}: ', [ 7 | 'modelClass' => 'Category', 8 | ]) . ' ' . $model->name; 9 | $this->params['breadcrumbs'][] = ['label' => Yii::t('plugin', 'Categories'), 'url' => ['index']]; 10 | $this->params['breadcrumbs'][] = ['label' => $model->id, 'url' => ['view', 'id' => $model->id]]; 11 | $this->params['breadcrumbs'][] = Yii::t('plugin', 'Update'); 12 | ?> 13 |
14 | 15 | render('_form', [ 16 | 'model' => $model, 17 | ]) ?> 18 | 19 |
20 | -------------------------------------------------------------------------------- /src/views/category/view.php: -------------------------------------------------------------------------------- 1 | title = $model->id; 10 | $this->params['breadcrumbs'][] = ['label' => Yii::t('plugin', 'Categories'), 'url' => ['index']]; 11 | $this->params['breadcrumbs'][] = $this->title; 12 | ?> 13 |
14 |

15 | $model->id], ['class' => 'btn btn-primary']) ?> 16 | $model->id], [ 17 | 'class' => 'btn btn-danger', 18 | 'data' => [ 19 | 'confirm' => Yii::t('plugin', 'Are you sure you want to delete this item?'), 20 | 'method' => 'post', 21 | ], 22 | ]) ?> 23 |

24 | 25 | $model, 27 | 'attributes' => [ 28 | 'id', 29 | 'name', 30 | ], 31 | ]) ?> 32 | 33 |
34 | -------------------------------------------------------------------------------- /src/views/event/_form.php: -------------------------------------------------------------------------------- 1 | plugin_id != Plugin::EVENTS_CORE; 16 | ?> 17 | 18 |
19 | 20 | 21 | 22 |
23 | 24 |
25 | field($model, 'trigger_class')->textInput(['disabled' => $disabled, 'maxlength' => true]) ?> 26 | field($model, 'trigger_event')->textInput(['disabled' => $disabled, 'maxlength' => true]) ?> 27 | field($model, 'handler_class')->textInput(['disabled' => $disabled, 'maxlength' => true]) ?> 28 | field($model, 'handler_method')->textInput(['disabled' => $disabled, 'maxlength' => true]) ?> 29 |
30 | 31 |
32 | field($model, 'data')->widget(Jsoneditor::class, 33 | [ 34 | 'editorOptions' => [ 35 | 'modes' => ['code', 'form', 'text', 'tree', 'view'], // available modes 36 | 'mode' => 'form', // current mode 37 | ], 38 | 'options' => ['style' => 'height:225px'], // html options 39 | ] 40 | ); ?> 41 |
42 | 43 |
44 |
45 |
46 | field($model, 'app_id')->dropDownList(ArrayHelper::map(App::find()->all(), 'id', 'name')) ?> 47 |
48 |
49 | field($model, 'category_id')->dropDownList(ArrayHelper::map(\lo\plugins\models\Category::find()->orderBy('name')->all(), 'id', 'name'), [ 50 | 'prompt' => ' ' 51 | ]) ?> 52 |
53 |
54 | 55 |
56 |
57 | field($model, 'status')->dropDownList([ 58 | $model::STATUS_INACTIVE => Yii::t('plugin', 'Disabled'), 59 | $model::STATUS_ACTIVE => Yii::t('plugin', 'Enabled') 60 | ]) ?>
61 |
62 | field($model, 'pos')->textInput() ?> 63 |
64 |
65 | field($model, 'text')->textarea() ?> 66 |
67 |
68 | 69 | 70 |
71 | isNewRecord ? Yii::t('plugin', 'Create') : Yii::t('plugin', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> 72 |
73 | 74 | 75 | 76 |
77 | -------------------------------------------------------------------------------- /src/views/event/_search.php: -------------------------------------------------------------------------------- 1 | 12 | 13 | 35 | -------------------------------------------------------------------------------- /src/views/event/create.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('plugin', 'Create Event'); 10 | $this->params['breadcrumbs'][] = ['label' => Yii::t('plugin', 'Events'), 'url' => ['index']]; 11 | $this->params['breadcrumbs'][] = $this->title; 12 | ?> 13 |
14 | 15 | render('_form', [ 16 | 'model' => $model, 17 | ]) ?> 18 | 19 |
20 | -------------------------------------------------------------------------------- /src/views/event/index.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('plugin', 'Events'); 17 | $this->params['breadcrumbs'][] = $this->title; 18 | ?> 19 |
20 | Yii::t('plugin', 'Event') 22 | ]), ['create'], ['class' => 'btn btn-success pull-right']) ?> 23 | render('/_menu') ?> 24 | 25 | $dataProvider, 27 | 'filterModel' => $searchModel, 28 | 'columns' => [ 29 | ['class' => 'yii\grid\SerialColumn'], 30 | [ 31 | 'attribute' => 'app_id', 32 | 'label' => Yii::t('plugin', 'App'), 33 | 'options' => ['style' => 'width: 25px; align: center;'], 34 | 'value' => function ($model) { 35 | return BS::appLabel($model->app_id); 36 | }, 37 | 'filter' => ArrayHelper::map(App::find()->orderBy('name')->all(), 'id', 'name'), 38 | 'format' => "raw" 39 | ], 40 | [ 41 | 'attribute' => 'category_id', 42 | 'label' => Yii::t('plugin', 'Category'), 43 | 'value' => function ($model) { 44 | if ($model->category_id) { 45 | return BS::label($model->category->name); 46 | } 47 | return ''; 48 | }, 49 | 'filter' => ArrayHelper::map(Category::find()->orderBy('name')->all(), 'id', 'name'), 50 | 'format' => "raw" 51 | ], 52 | [ 53 | 'attribute' => 'trigger_class', 54 | 'label' => Yii::t('plugin', 'Trigger'), 55 | 'value' => function ($model) { 56 | return $model->trigger_class . BS::label('::') . $model->trigger_event; 57 | }, 58 | 'format' => "raw" 59 | ], 60 | [ 61 | 'attribute' => 'handler_class', 62 | 'label' => Yii::t('plugin', 'Handler'), 63 | 'value' => function ($model) { 64 | return $model->handler_class . BS::label('::') . $model->handler_method; 65 | }, 66 | 'format' => "raw" 67 | ], 68 | [ 69 | 'attribute' => 'pos', 70 | 'label' => Yii::t('plugin', 'Pos.') 71 | ], 72 | [ 73 | 'attribute' => 'status', 74 | 'options' => ['style' => 'width: 75px; align: center;'], 75 | 'value' => function ($model) { 76 | return $model->status == $model::STATUS_ACTIVE ? BS::label('Enabled', BS::TYPE_SUCCESS) : BS::label('Disabled', BS::TYPE_DANGER); 77 | }, 78 | 'filter' => [ 79 | 1 => Yii::t('plugin', 'Enabled'), 80 | 0 => Yii::t('plugin', 'Disabled') 81 | ], 82 | 'format' => "raw" 83 | ], 84 | [ 85 | 'class' => 'yii\grid\ActionColumn', 86 | 'template' => '{update} {delete}', 87 | 'options' => ['style' => 'width: 75px;'], 88 | 'buttons' => [ 89 | 'update' => function ($url) { 90 | return Html::a(BS::icon('pencil'), $url, [ 91 | 'class' => 'btn btn-xs btn-primary', 92 | 'title' => Yii::t('plugin', 'Update'), 93 | ]); 94 | }, 95 | 'delete' => function ($url) { 96 | return Html::a(BS::icon('trash'), $url, [ 97 | 'class' => 'btn btn-xs btn-danger', 98 | 'data-method' => 'post', 99 | 'data-confirm' => Yii::t('plugin', 'Are you sure to delete this item?'), 100 | 'title' => Yii::t('plugin', 'Delete'), 101 | ]); 102 | }, 103 | ] 104 | ], 105 | ], 106 | ]); ?> 107 | 108 |
109 | -------------------------------------------------------------------------------- /src/views/event/update.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('plugin', 'Update {modelClass}: ', [ 9 | 'modelClass' => 'Event', 10 | ]) . ' ' . $model->plugin->name; 11 | $this->params['breadcrumbs'][] = ['label' => Yii::t('plugin', 'Events'), 'url' => ['index']]; 12 | $this->params['breadcrumbs'][] = ['label' => $model->id, 'url' => ['view', 'id' => $model->id]]; 13 | $this->params['breadcrumbs'][] = Yii::t('plugin', 'Update'); 14 | ?> 15 |
16 | 17 | render('_form', [ 18 | 'model' => $model, 19 | ]) ?> 20 | 21 |
22 | -------------------------------------------------------------------------------- /src/views/event/view.php: -------------------------------------------------------------------------------- 1 | title = $model->id; 10 | $this->params['breadcrumbs'][] = ['label' => Yii::t('plugin', 'Events'), 'url' => ['index']]; 11 | $this->params['breadcrumbs'][] = $this->title; 12 | ?> 13 |
14 |

15 | $model->id], ['class' => 'btn btn-primary']) ?> 16 | $model->id], [ 17 | 'class' => 'btn btn-danger', 18 | 'data' => [ 19 | 'confirm' => Yii::t('plugin', 'Are you sure you want to delete this item?'), 20 | 'method' => 'post', 21 | ], 22 | ]) ?> 23 |

24 | 25 | $model, 27 | 'attributes' => [ 28 | 'id', 29 | 'plugin_id', 30 | 'trigger_class', 31 | 'trigger_event', 32 | 'handler_class', 33 | 'handler_method', 34 | 'data', 35 | 'pos', 36 | 'status', 37 | ], 38 | ]) ?> 39 | 40 |
41 | -------------------------------------------------------------------------------- /src/views/plugin/_form.php: -------------------------------------------------------------------------------- 1 | 10 | 11 |
12 | 13 | 14 |
15 |
16 | field($model, 'name')->textInput(['maxlength' => true]) ?> 17 | field($model, 'url')->textInput(['maxlength' => true]) ?> 18 | field($model, 'text')->textarea(['rows' => 6]) ?> 19 |
20 |
21 | field($model, 'author')->textInput(['maxlength' => true]) ?> 22 | field($model, 'author_url')->textInput(['maxlength' => true]) ?> 23 |
24 |
25 | field($model, 'version')->textInput(['maxlength' => true]) ?> 26 | field($model, 'status')->dropDownList([ 27 | $model::STATUS_INACTIVE => Yii::t('plugin', 'Disabled'), 28 | $model::STATUS_ACTIVE => Yii::t('plugin', 'Enabled') 29 | ]) ?> 30 |
31 |
32 | 33 | 34 | 35 |
36 | isNewRecord ? Yii::t('plugin', 'Create') : Yii::t('plugin', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> 37 |
38 | 39 | 40 | 41 |
42 | -------------------------------------------------------------------------------- /src/views/plugin/_item.php: -------------------------------------------------------------------------------- 1 | isInstalled()) { 11 | $name = 'Update'; 12 | $ver = BS::label($model->version) . ' to ' . BS::label($model->new_version, BS::TYPE_SUCCESS); 13 | $class = BS::TYPE_SUCCESS; 14 | } else { 15 | $name = 'Install'; 16 | $ver = BS::label($model->new_version, BS::TYPE_PRIMARY); 17 | $class = BS::TYPE_PRIMARY; 18 | }; 19 | 20 | echo Html::beginTag('tr'); 21 | echo Html::tag('td', $model->name); 22 | echo Html::tag('td', $ver); 23 | echo Html::tag('td', $model->author); 24 | echo Html::tag('td', $model->text); 25 | 26 | echo Html::tag('td', Html::a($name, ['plugin/install', 'id' => $key], [ 27 | 'class' => 'btn btn-' . $class, 28 | 'data' => [ 29 | 'method' => 'post' 30 | ] 31 | ])); 32 | echo Html::endTag('tr'); 33 | -------------------------------------------------------------------------------- /src/views/plugin/_search.php: -------------------------------------------------------------------------------- 1 | 12 | 13 | 34 | -------------------------------------------------------------------------------- /src/views/plugin/create.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('plugin', 'Create Item'); 10 | $this->params['breadcrumbs'][] = ['label' => Yii::t('plugin', 'Items'), 'url' => ['index']]; 11 | $this->params['breadcrumbs'][] = $this->title; 12 | ?> 13 |
14 | 15 | render('_form', [ 16 | 'model' => $model, 17 | ]) ?> 18 | 19 |
20 | -------------------------------------------------------------------------------- /src/views/plugin/index.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('plugin', 'Items'); 14 | $this->params['breadcrumbs'][] = $this->title; 15 | ?> 16 |
17 | render('/_menu') ?> 18 | 19 | $dataProvider, 21 | 'filterModel' => $searchModel, 22 | 'columns' => [ 23 | ['class' => 'yii\grid\SerialColumn'], 24 | [ 25 | 'attribute' => 'url', 26 | 'format' => "raw", 27 | 'options' => ['style' => 'width: 50px; align: center;'], 28 | 'value' => function ($model) { 29 | if ($model->url) { 30 | return Html::a(BS::icon('link'), $model->url, [ 31 | 'class' => 'btn btn-xs btn-' . BS::TYPE_PRIMARY, 32 | 'target' => '_blank' 33 | ]); 34 | } 35 | return ''; 36 | }, 37 | 'filter' => false 38 | ], 39 | 'name', 40 | [ 41 | 'attribute' => 'version', 42 | 'label' => Yii::t('plugin', 'Ver.'), 43 | 'options' => ['style' => 'width: 65px; align: center;'], 44 | 'filter' => false, 45 | 'format' => "raw", 46 | 'value' => function ($model) { 47 | return BS::label($model->version); 48 | } 49 | ], 50 | 'text:ntext', 51 | [ 52 | 'attribute' => 'status', 53 | 'options' => ['style' => 'width: 75px; align: center;'], 54 | 'value' => function ($model) { 55 | return $model->status == $model::STATUS_ACTIVE ? 'Enabled' : 'Disabled'; 56 | }, 57 | 'filter' => [ 58 | 1 => Yii::t('plugin', 'Enabled'), 59 | 0 => Yii::t('plugin', 'Disabled') 60 | ], 61 | 'format' => "raw" 62 | ], 63 | [ 64 | 'class' => 'yii\grid\ActionColumn', 65 | 'template' => '{update} {delete}', 66 | 'options' => ['style' => 'width: 75px;'], 67 | 'buttons' => [ 68 | 'update' => function ($url) { 69 | return Html::a(BS::icon('pencil'), $url, [ 70 | 'class' => 'btn btn-xs btn-primary', 71 | 'title' => Yii::t('plugin', 'Update'), 72 | ]); 73 | }, 74 | 'delete' => function ($url) { 75 | return Html::a(BS::icon('trash'), $url, [ 76 | 'class' => 'btn btn-xs btn-danger', 77 | 'data-method' => 'post', 78 | 'data-confirm' => Yii::t('plugin', 'Are you sure to delete this item?'), 79 | 'title' => Yii::t('plugin', 'Delete'), 80 | ]); 81 | }, 82 | ] 83 | ], 84 | ], 85 | ]); ?> 86 | 87 |
88 | -------------------------------------------------------------------------------- /src/views/plugin/info.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('plugin', 'Info'); 9 | $this->params['breadcrumbs'][] = ['label' => Yii::t('plugin', 'Items'), 'url' => ['info']]; 10 | $this->params['breadcrumbs'][] = $this->title; 11 | 12 | ?> 13 | 18 |
19 | render('/_menu') ?> 20 | 21 | 22 |
23 |
24 |

MVC

25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
Controller or Module
EVENT_BEFORE_ACTIONbeforeAction
EVENT_AFTER_ACTIONafterAction
Model
EVENT_BEFORE_VALIDATEbeforeValidate
EVENT_AFTER_VALIDATEafterValidate
yii\base\View
EVENT_BEGIN_PAGEbeginPage
EVENT_END_PAGEendPage
EVENT_BEFORE_RENDERbeforeRender
EVENT_AFTER_RENDERafterRender
yii\web\View
EVENT_BEGIN_BODYbeginBody
EVENT_END_BODYendBody
79 | 80 |

Components

81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 |
MessageSource
EVENT_MISSING_TRANSLATIONmissingTranslation
BaseMailer
EVENT_BEFORE_SENDbeforeSend
EVENT_AFTER_SENDafterSend
User
EVENT_BEFORE_LOGINbeforeLogin
EVENT_AFTER_LOGINafterLogin
EVENT_BEFORE_LOGOUTbeforeLogout
EVENT_AFTER_LOGOUTafterLogout
120 |
121 | 122 |
123 |

Database

124 | 125 | 126 | 127 | 128 | 129 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 |
BaseActiveRecord
EVENT_INIT 130 | 131 | init
EVENT_AFTER_FINDafterFind
EVENT_BEFORE_INSERTbeforeInsert
EVENT_AFTER_INSERTafterInsert
EVENT_BEFORE_UPDATEbeforeUpdate
EVENT_AFTER_UPDATEafterUpdate
EVENT_BEFORE_DELETEbeforeDelete
EVENT_AFTER_DELETEafterDelete
ActiveQuery
EVENT_INITinit
Connection
EVENT_AFTER_OPENafterOpen
EVENT_BEGIN_TRANSACTIONbeginTransaction
EVENT_COMMIT_TRANSACTIONcommitTransaction
EVENT_ROLLBACK_TRANSACTIONrollbackTransaction
189 | 190 |

Request

191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 |
yii\base\Application
EVENT_BEFORE_REQUESTbeforeRequest
EVENT_AFTER_REQUESTafterRequest
Response
EVENT_BEFORE_SENDbeforeSend
EVENT_AFTER_SENDafterSend
EVENT_AFTER_PREPAREafterPrepare
219 |
220 | 221 |
222 | 223 | 224 | 225 |
226 | -------------------------------------------------------------------------------- /src/views/plugin/install.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('plugin', 'Install'); 12 | $this->params['breadcrumbs'][] = ['label' => Yii::t('plugin', 'Items'), 'url' => ['info']]; 13 | $this->params['breadcrumbs'][] = $this->title; 14 | ?> 15 |
16 | 17 | render('/_menu') ?> 18 | 20 | 21 | Plugin name 22 | Ver. 23 | Author 24 | Plugin description 25 | 26 | 27 | '; 28 | ?> 29 | 30 | $dataProvider, 32 | 'layout' => "$thead{items}", 33 | 'itemView' => '_item', 34 | 'options' => [ 35 | 'tag' => 'table', 36 | 'class' => 'table table-bordered table-striped', 37 | ], 38 | 'itemOptions' => [ 39 | 'class' => 'item', 40 | 'tag' => false, 41 | ], 42 | ]) ?> 43 | 44 | $dataProvider->pagination, 46 | ]); ?> 47 | 48 |
49 | -------------------------------------------------------------------------------- /src/views/plugin/update.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('plugin', 'Update {modelClass}: ', [ 9 | 'modelClass' => 'Item', 10 | ]) . ' ' . $model->name; 11 | $this->params['breadcrumbs'][] = ['label' => Yii::t('plugin', 'Items'), 'url' => ['index']]; 12 | $this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]]; 13 | $this->params['breadcrumbs'][] = Yii::t('plugin', 'Update'); 14 | ?> 15 |
16 | 17 | render('_form', [ 18 | 'model' => $model, 19 | ]) ?> 20 | 21 |
22 | -------------------------------------------------------------------------------- /src/views/plugin/view.php: -------------------------------------------------------------------------------- 1 | title = $model->name; 10 | $this->params['breadcrumbs'][] = ['label' => Yii::t('plugin', 'Items'), 'url' => ['index']]; 11 | $this->params['breadcrumbs'][] = $this->title; 12 | ?> 13 |
14 | 15 |

16 | $model->id], ['class' => 'btn btn-primary']) ?> 17 | $model->id], [ 18 | 'class' => 'btn btn-danger', 19 | 'data' => [ 20 | 'confirm' => Yii::t('plugin', 'Are you sure you want to delete this item?'), 21 | 'method' => 'post', 22 | ], 23 | ]) ?> 24 |

25 | 26 | $model, 28 | 'attributes' => [ 29 | 'id', 30 | 'name', 31 | 'url:url', 32 | 'version', 33 | 'text:ntext', 34 | 'author', 35 | 'author_url:url', 36 | 'status', 37 | ], 38 | ]) ?> 39 | 40 |
41 | -------------------------------------------------------------------------------- /src/views/shortcode/_form.php: -------------------------------------------------------------------------------- 1 | 16 | 17 |
18 | 19 | 20 | 21 |
22 |
23 | field($model, 'handler_class')->textInput(['disabled' => $disabled, 'maxlength' => true]) ?> 24 | field($model, 'tag')->textInput(['disabled' => $disabled, 'maxlength' => true]) ?> 25 | field($model, 'tooltip')->textInput(['maxlength' => true]) ?> 26 |
27 |
28 | field($model, 'data')->widget(Jsoneditor::class, 29 | [ 30 | 'editorOptions' => [ 31 | 'modes' => ['code', 'form', 'text', 'tree', 'view'], // available modes 32 | 'mode' => 'form', // current mode 33 | ], 34 | 'options' => ['style' => 'height:225px'], // html options 35 | ] 36 | ); ?> 37 |
38 |
39 |
40 |
41 | field($model, 'app_id')->dropDownList(ArrayHelper::map(App::find()->all(), 'id', 'name')) ?> 42 |
43 |
44 | field($model, 'status')->dropDownList([ 45 | $model::STATUS_INACTIVE => Yii::t('plugin', 'Disabled'), 46 | $model::STATUS_ACTIVE => Yii::t('plugin', 'Enabled') 47 | ]) ?> 48 |
49 |
50 | field($model, 'category_id')->dropDownList(ArrayHelper::map(\lo\plugins\models\Category::find()->orderBy('name')->all(), 'id', 'name'), [ 51 | 'prompt' => ' ' 52 | ]) ?> 53 | field($model, 'text')->textarea() ?> 54 |
55 |
56 | 57 | 58 |
59 | isNewRecord ? Yii::t('plugin', 'Create') : Yii::t('plugin', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> 60 |
61 | 62 | 63 | 64 |
65 | -------------------------------------------------------------------------------- /src/views/shortcode/_search.php: -------------------------------------------------------------------------------- 1 | 12 | 13 | 31 | -------------------------------------------------------------------------------- /src/views/shortcode/index.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('plugin', 'Shortcodes'); 17 | $this->params['breadcrumbs'][] = $this->title; 18 | ?> 19 |
20 | 21 | render('/_menu') ?> 22 | 23 | $dataProvider, 25 | 'filterModel' => $searchModel, 26 | 'columns' => [ 27 | ['class' => 'yii\grid\SerialColumn'], 28 | [ 29 | 'attribute' => 'app_id', 30 | 'label' => Yii::t('plugin', 'App'), 31 | 'options' => ['style' => 'width: 25px; align: center;'], 32 | 'value' => function ($model) { 33 | return BS::appLabel($model->app_id); 34 | }, 35 | 'filter' => ArrayHelper::map(App::find()->orderBy('name')->all(), 'id', 'name'), 36 | 'format' => "raw" 37 | ], 38 | 'tag', 39 | 'tooltip', 40 | [ 41 | 'attribute' => 'data', 42 | 'value' => function ($model) { 43 | return StringHelper::truncate($model->data, 60); 44 | }, 45 | ], 46 | [ 47 | 'attribute' => 'status', 48 | 'options' => ['style' => 'width: 75px; align: center;'], 49 | 'value' => function ($model) { 50 | return $model->status == $model::STATUS_ACTIVE ? BS::label('Enabled', BS::TYPE_SUCCESS) : BS::label('Disabled', BS::TYPE_DANGER); 51 | }, 52 | 'filter' => [ 53 | 1 => Yii::t('plugin', 'Enabled'), 54 | 0 => Yii::t('plugin', 'Disabled') 55 | ], 56 | 'format' => "raw" 57 | ], 58 | [ 59 | 'class' => 'yii\grid\ActionColumn', 60 | 'template' => '{update} {delete}', 61 | 'options' => ['style' => 'width: 75px;'], 62 | 'buttons' => [ 63 | 'update' => function ($url) { 64 | return Html::a(BS::icon('pencil'), $url, [ 65 | 'class' => 'btn btn-xs btn-primary', 66 | 'title' => Yii::t('plugin', 'Update'), 67 | ]); 68 | }, 69 | 'delete' => function ($url) { 70 | return Html::a(BS::icon('trash'), $url, [ 71 | 'class' => 'btn btn-xs btn-danger', 72 | 'data-method' => 'post', 73 | 'data-confirm' => Yii::t('plugin', 'Are you sure to delete this item?'), 74 | 'title' => Yii::t('plugin', 'Delete'), 75 | ]); 76 | }, 77 | ] 78 | ], 79 | ], 80 | ]); ?> 81 | 82 |
83 | -------------------------------------------------------------------------------- /src/views/shortcode/update.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('plugin', 'Update {modelClass}: ', [ 7 | 'modelClass' => 'Shortcode', 8 | ]) . ' ' . $model->tag; 9 | $this->params['breadcrumbs'][] = ['label' => Yii::t('plugin', 'Shortcodes'), 'url' => ['index']]; 10 | $this->params['breadcrumbs'][] = ['label' => $model->id, 'url' => ['view', 'id' => $model->id]]; 11 | $this->params['breadcrumbs'][] = Yii::t('plugin', 'Update'); 12 | ?> 13 |
14 | 15 | render('_form', [ 16 | 'model' => $model, 17 | ]) ?> 18 | 19 |
20 | --------------------------------------------------------------------------------