├── .craftplugin ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── composer.lock ├── resources └── img │ └── plugin-logo.png └── src ├── Elasticraft.php ├── assetbundles ├── elasticraft │ ├── ElasticraftAsset.php │ └── dist │ │ ├── css │ │ └── Elasticraft.css │ │ ├── img │ │ └── Elasticraft-icon.svg │ │ └── js │ │ └── Elasticraft.js ├── elasticraftutilityutility │ ├── ElasticraftUtilityUtilityAsset.php │ └── dist │ │ ├── css │ │ └── ElasticraftUtility.css │ │ ├── img │ │ └── ElasticraftUtility-icon.svg │ │ └── js │ │ └── ElasticraftUtility.js └── elasticraftwidgetwidget │ ├── ElasticraftWidgetWidgetAsset.php │ └── dist │ ├── css │ └── ElasticraftWidget.css │ ├── img │ └── ElasticraftWidget-icon.svg │ └── js │ └── ElasticraftWidget.js ├── config.php ├── console └── controllers │ └── IndexController.php ├── controllers └── DefaultController.php ├── icon-mask.svg ├── icon.svg ├── jobs └── ElasticJob.php ├── models ├── ElasticDocument.php └── Settings.php ├── services └── ElasticraftService.php ├── templates ├── _components │ ├── utilities │ │ └── ElasticraftUtility_content.twig │ └── widgets │ │ ├── ElasticraftWidget_body.twig │ │ └── ElasticraftWidget_settings.twig ├── entriesWidget.twig └── settings.twig ├── transformers ├── BaseTransformer.php └── ExampleEntryTransformer.php ├── translations ├── en │ └── elasticraft.php └── nb │ └── elasticraft.php ├── utilities └── ElasticraftUtility.php └── widgets └── ElasticraftWidget.php /.craftplugin: -------------------------------------------------------------------------------- 1 | {"pluginName":"Elasticraft","pluginDescription":"Desc.","pluginVersion":"0.4.0","pluginAuthorName":"Peter Holme Obrestad","pluginVendorName":"dfo","pluginAuthorUrl":"https://dfo.no","pluginAuthorGithub":"phoob","codeComments":"yes","pluginComponents":["tasks","models","consolecommands","controllers","services","settings","utilities","widgets"],"consolecommandName":"","controllerName":"","cpsectionName":"","elementName":"","fieldName":"","modelName":"elasticDocument","purchasableName":"","recordName":"","serviceName":"","taskName":"elasticIndex","utilityName":"","widgetName":"","apiVersion":"api_version_3_0"} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # CRAFT ENVIRONMENT 2 | .env.php 3 | .env.sh 4 | .env 5 | 6 | # COMPOSER 7 | /vendor 8 | 9 | # BUILD FILES 10 | /bower_components/* 11 | /node_modules/* 12 | /build/* 13 | /yarn-error.log 14 | 15 | # MISC FILES 16 | .cache 17 | .DS_Store 18 | .idea 19 | .project 20 | .settings 21 | *.esproj 22 | *.sublime-workspace 23 | *.sublime-project 24 | *.tmproj 25 | *.tmproject 26 | .vscode/* 27 | !.vscode/settings.json 28 | !.vscode/tasks.json 29 | !.vscode/launch.json 30 | !.vscode/extensions.json 31 | config.codekit3 32 | prepros-6.config 33 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Elasticraft Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | ## 0.4.6 8 | ### Changed 9 | - Do not index elements that do not have transformers. 10 | 11 | ### Fixed 12 | - When publishing drafts, they didn't get uris. Now they do. 13 | - Return values in ElasticraftService 14 | - Indexing drafts via CLI 15 | 16 | ## 0.4.5 17 | ### Fixed 18 | - Index when reverting to older version of entry 19 | 20 | ## 0.4.4 21 | ### Fixed 22 | - Debug error 23 | 24 | ## 0.4.3 25 | ### Fixed 26 | - Uncought error in settings page 27 | 28 | ## 0.4.2 - 2018-01-14 29 | ### Fixed 30 | - Clean up console controller 31 | 32 | ## 0.4.1 - 2018-01-03 33 | ### Fixed 34 | - Edit entry widget styling for Craft RC3 35 | 36 | ## 0.4.0 - 2017-12-21 37 | ### Added 38 | - Cookie for logged in users for use in front end as admin link 39 | 40 | ### Changed 41 | - Indexing drafts. 42 | 43 | ## 0.3.8 – 2017-11-29 44 | ### Fixed 45 | - Fix drafts. 46 | 47 | ## 0.3.7 – 2017-11-27 48 | ### Added 49 | - Index drafts. 50 | 51 | ## 0.3.6 - 2017-11-17 52 | ### Fixed 53 | - postDate and expiryDate is needed for filtering entrie. 54 | 55 | ## 0.3.5 - 2017-11-10 56 | ### Added 57 | - Utility button to remove stale and failed jobs from queue, to allow other jobs to start. 58 | 59 | ### Fixed 60 | - Made main plugin file DRY-er. 61 | - Made elastic jobs and service safer. 62 | - Updated dependencies. 63 | 64 | ## 0.3.4 - 2017-09-13 65 | ### Added 66 | - New option to reindex all elements, and in the same operation deleting stale documents in Elasticsearch, effectively recreating the index with no down time. 67 | 68 | ### Fixed 69 | - Ignore 404 errors in some service methods, handle them in others. 70 | 71 | ## 0.3.3 - 2017-09-13 72 | ### Changed 73 | - Now adding dates to all ElasticDocuments. 74 | 75 | ## 0.3.2 - 2017-09-12 76 | ### Fixed 77 | - Optimize indexing. 78 | - Make widget in entry edit page more informative. Now lets editor know status of Elasticsearch if entry is not found. 79 | - Throw errors in elasticService to make bug hunting easier. 80 | 81 | ## 0.3.1 - 2017-09-10 82 | ### Fixed 83 | - Make plugin more robust if no hosts are configured. 84 | - Make settings actually work. 85 | 86 | ## 0.3.0 - 2017-09-08 87 | ### Changed 88 | - Breaking: document type is now set to `element` for all elements. To access section handles – for entries – or handles – for globals, use ``_source.type.keyword` instead of `_type`. 89 | 90 | ### Added 91 | - Console command for reindexing to Elasticsearch. 92 | - Example page transformers and short description in README. 93 | - Add stuff to settings page. 94 | 95 | ### Removed 96 | - Removed widget for now. 97 | - Removed debug tools from utility page. 98 | 99 | ### Fixed 100 | - Only show last indexed date widget if entry has an associated pagetransformer. 101 | 102 | ## 0.2.3 - 2017-09-07 103 | ### Fixed 104 | - Recreate index now works better and indexes globals as well 105 | - Code cleanup 106 | 107 | ## 0.2.2 - 2017-09-05 108 | ### Added 109 | - Translation files for nb (not complete) 110 | - Document counts by type added to utility page 111 | - dfo\elasticraft\controllers\DefaultController::recreateIndex() 112 | - dfo\elasticraft\controllers\DefaultController::getDocumentCount() 113 | - (private) dfo\elasticraft\controllers\DefaultController::_deleteIndex() 114 | - (private) dfo\elasticraft\controllers\DefaultController::_indexAllElements() 115 | 116 | ### Fixed 117 | - Saving entry with matrix fires `EVENT_AFTER_SAVE_ELEMENT` for each matrix block. To not add unnecessary jobs, the check for if the element is of a type that should be indexed must be done before adding job. 118 | - The widget added in `0.2.1` had an extra ``. Now removed. 119 | - A little cleanup 120 | 121 | ### Removed 122 | - dfo\elasticraft\controllers\DefaultController::getIndexStats() 123 | - dfo\elasticraft\controllers\DefaultController::deleteIndex() 124 | - dfo\elasticraft\controllers\DefaultController::indexAllElements() 125 | 126 | ## 0.2.1 - 2017-09-04 127 | ### Added 128 | - Widget with the date and time of the last indexing when editing an entry 129 | 130 | ### Fixed 131 | - Error in mapping example in `config.php` 132 | 133 | ## 0.2.0 - 2017-08-31 134 | ### Changed 135 | - New handling of dates 136 | 137 | ## 0.1.0 - 2017-07-03 138 | ### Added 139 | - Initial release 140 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Peter Holme Obrestad 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Elasticraft plugin for Craft CMS 3.x 2 | 3 | Elasticsearch plugin for Craft 3 4 | 5 | ## Installation 6 | 7 | To install Elasticraft, follow these steps: 8 | 9 | 1. Download & unzip the file and place the `elasticraft` directory into your `craft/plugins` directory 10 | 2. -OR- do a `git clone https://github.com/phoob/elasticraft.git` directly into your `craft/plugins` folder. You can then update it with `git pull` 11 | 3. -OR- install with Composer via `composer require phoob/elasticraft` 12 | 4. Install plugin in the Craft Control Panel under Settings > Plugins 13 | 5. The plugin folder should be named `elasticraft` for Craft to see it. GitHub recently started appending `-master` (the branch name) to the name of the folder for zip file downloads. 14 | 15 | Elasticraft works on Craft 3.x. 16 | 17 | ## Elasticraft Overview 18 | 19 | Provides basic functionality to index entries and other craft elements to an elasticsearch server. 20 | 21 | The plugin uses the [Elasticesearch PHP Client](https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html). 22 | 23 | ## Configuring Elasticraft 24 | 25 | Copy `src/config.php` to `craft/config/elasticraft.php` and configure hosts and pagetransformers for the elements you wish to index to Elasticsearch. 26 | 27 | Pagetransformers should inherit `League\Fractal\TransformerAbstract` – see examples in `./transformers/`. 28 | 29 | If you want, put the server details in your `.env`.: 30 | 31 | ``` 32 | ELASTIC_HOSTS=localhost:9200 33 | ELASTIC_INDEX_NAME=craftdev 34 | ``` 35 | 36 | ## Using Elasticraft 37 | 38 | Elasticraft indexes elements (and their descendants and ancestors) when you save or move an element. It also deletes the element from elasticsearch when the element is deleted in Craft. 39 | 40 | ## Elasticraft Roadmap 41 | 42 | * Make it more stable and test it. It has not been used in a production environment yet. 43 | * Please note that the settings page and the widget is not in use currently. All settings are configured in the config file. 44 | 45 | Brought to you by [Peter Holme Obrestad](https://dfo.no) 46 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dfo/elasticraft", 3 | "description": "Elasticsearch plugin for Craft 3", 4 | "type": "craft-plugin", 5 | "keywords": [ 6 | "craft", 7 | "cms", 8 | "craftcms", 9 | "craft-plugin", 10 | "elasticraft" 11 | ], 12 | "support": { 13 | "docs": "https://github.com/phoob/elasticraft/blob/master/README.md", 14 | "issues": "https://github.com/phoob/elasticraft/issues" 15 | }, 16 | "license": "MIT", 17 | "authors": [ 18 | { 19 | "name": "Peter Holme Obrestad", 20 | "homepage": "https://dfo.no" 21 | } 22 | ], 23 | "require": { 24 | "craftcms/cms": "^3.0.0-RC2", 25 | "elasticsearch/elasticsearch": "^5.2", 26 | "league/fractal": "^0.16.0", 27 | "craftcms/element-api": "^2.5" 28 | }, 29 | "suggest": { 30 | "craftcms/element-api": "Uses the same kinds of PageTransformers as element-api" 31 | }, 32 | "repositories": [ 33 | { 34 | "type": "composer", 35 | "url": "https://asset-packagist.org" 36 | } 37 | ], 38 | "autoload": { 39 | "psr-4": { 40 | "dfo\\elasticraft\\": "src/" 41 | } 42 | }, 43 | "extra": { 44 | "name": "Elasticraft", 45 | "handle": "elasticraft", 46 | "schemaVersion": "0.3.0", 47 | "hasCpSettings": true, 48 | "hasCpSection": false, 49 | "changelogUrl": "https://raw.githubusercontent.com/phoob/elasticraft/master/CHANGELOG.md", 50 | "components": { 51 | "elasticraftService": "dfo\\elasticraft\\services\\ElasticraftService" 52 | }, 53 | "class": "dfo\\elasticraft\\Elasticraft" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "0204cd9d46a6d079392409245f7ea7fd", 8 | "packages": [ 9 | { 10 | "name": "bower-asset/bootstrap", 11 | "version": "v3.3.7", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/twbs/bootstrap.git", 15 | "reference": "0b9c4a4007c44201dce9a6cc1a38407005c26c86" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/twbs/bootstrap/zipball/0b9c4a4007c44201dce9a6cc1a38407005c26c86", 20 | "reference": "0b9c4a4007c44201dce9a6cc1a38407005c26c86", 21 | "shasum": null 22 | }, 23 | "require": { 24 | "bower-asset/jquery": ">=1.9.1,<4.0" 25 | }, 26 | "type": "bower-asset", 27 | "license": [ 28 | "MIT" 29 | ] 30 | }, 31 | { 32 | "name": "bower-asset/inputmask", 33 | "version": "3.3.11", 34 | "source": { 35 | "type": "git", 36 | "url": "https://github.com/RobinHerbots/Inputmask.git", 37 | "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b" 38 | }, 39 | "dist": { 40 | "type": "zip", 41 | "url": "https://api.github.com/repos/RobinHerbots/Inputmask/zipball/5e670ad62f50c738388d4dcec78d2888505ad77b", 42 | "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b", 43 | "shasum": null 44 | }, 45 | "require": { 46 | "bower-asset/jquery": ">=1.7" 47 | }, 48 | "type": "bower-asset", 49 | "license": [ 50 | "http://opensource.org/licenses/mit-license.php" 51 | ] 52 | }, 53 | { 54 | "name": "bower-asset/jquery", 55 | "version": "3.2.1", 56 | "source": { 57 | "type": "git", 58 | "url": "https://github.com/jquery/jquery-dist.git", 59 | "reference": "77d2a51d0520d2ee44173afdf4e40a9201f5964e" 60 | }, 61 | "dist": { 62 | "type": "zip", 63 | "url": "https://api.github.com/repos/jquery/jquery-dist/zipball/77d2a51d0520d2ee44173afdf4e40a9201f5964e", 64 | "reference": "77d2a51d0520d2ee44173afdf4e40a9201f5964e", 65 | "shasum": null 66 | }, 67 | "type": "bower-asset", 68 | "license": [ 69 | "MIT" 70 | ] 71 | }, 72 | { 73 | "name": "bower-asset/punycode", 74 | "version": "v1.3.2", 75 | "source": { 76 | "type": "git", 77 | "url": "https://github.com/bestiejs/punycode.js.git", 78 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3" 79 | }, 80 | "dist": { 81 | "type": "zip", 82 | "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3", 83 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3", 84 | "shasum": null 85 | }, 86 | "type": "bower-asset" 87 | }, 88 | { 89 | "name": "bower-asset/yii2-pjax", 90 | "version": "2.0.7.1", 91 | "source": { 92 | "type": "git", 93 | "url": "https://github.com/yiisoft/jquery-pjax.git", 94 | "reference": "aef7b953107264f00234902a3880eb50dafc48be" 95 | }, 96 | "dist": { 97 | "type": "zip", 98 | "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/aef7b953107264f00234902a3880eb50dafc48be", 99 | "reference": "aef7b953107264f00234902a3880eb50dafc48be", 100 | "shasum": null 101 | }, 102 | "require": { 103 | "bower-asset/jquery": ">=1.8" 104 | }, 105 | "type": "bower-asset", 106 | "license": [ 107 | "MIT" 108 | ] 109 | }, 110 | { 111 | "name": "cebe/markdown", 112 | "version": "1.1.2", 113 | "source": { 114 | "type": "git", 115 | "url": "https://github.com/cebe/markdown.git", 116 | "reference": "25b28bae8a6f185b5030673af77b32e1163d5c6e" 117 | }, 118 | "dist": { 119 | "type": "zip", 120 | "url": "https://api.github.com/repos/cebe/markdown/zipball/25b28bae8a6f185b5030673af77b32e1163d5c6e", 121 | "reference": "25b28bae8a6f185b5030673af77b32e1163d5c6e", 122 | "shasum": "" 123 | }, 124 | "require": { 125 | "lib-pcre": "*", 126 | "php": ">=5.4.0" 127 | }, 128 | "require-dev": { 129 | "cebe/indent": "*", 130 | "facebook/xhprof": "*@dev", 131 | "phpunit/phpunit": "4.1.*" 132 | }, 133 | "bin": [ 134 | "bin/markdown" 135 | ], 136 | "type": "library", 137 | "extra": { 138 | "branch-alias": { 139 | "dev-master": "1.1.x-dev" 140 | } 141 | }, 142 | "autoload": { 143 | "psr-4": { 144 | "cebe\\markdown\\": "" 145 | } 146 | }, 147 | "notification-url": "https://packagist.org/downloads/", 148 | "license": [ 149 | "MIT" 150 | ], 151 | "authors": [ 152 | { 153 | "name": "Carsten Brandt", 154 | "email": "mail@cebe.cc", 155 | "homepage": "http://cebe.cc/", 156 | "role": "Creator" 157 | } 158 | ], 159 | "description": "A super fast, highly extensible markdown parser for PHP", 160 | "homepage": "https://github.com/cebe/markdown#readme", 161 | "keywords": [ 162 | "extensible", 163 | "fast", 164 | "gfm", 165 | "markdown", 166 | "markdown-extra" 167 | ], 168 | "time": "2017-07-16T21:13:23+00:00" 169 | }, 170 | { 171 | "name": "composer/ca-bundle", 172 | "version": "1.1.0", 173 | "source": { 174 | "type": "git", 175 | "url": "https://github.com/composer/ca-bundle.git", 176 | "reference": "943b2c4fcad1ef178d16a713c2468bf7e579c288" 177 | }, 178 | "dist": { 179 | "type": "zip", 180 | "url": "https://api.github.com/repos/composer/ca-bundle/zipball/943b2c4fcad1ef178d16a713c2468bf7e579c288", 181 | "reference": "943b2c4fcad1ef178d16a713c2468bf7e579c288", 182 | "shasum": "" 183 | }, 184 | "require": { 185 | "ext-openssl": "*", 186 | "ext-pcre": "*", 187 | "php": "^5.3.2 || ^7.0" 188 | }, 189 | "require-dev": { 190 | "phpunit/phpunit": "^4.8.35", 191 | "psr/log": "^1.0", 192 | "symfony/process": "^2.5 || ^3.0 || ^4.0" 193 | }, 194 | "type": "library", 195 | "extra": { 196 | "branch-alias": { 197 | "dev-master": "1.x-dev" 198 | } 199 | }, 200 | "autoload": { 201 | "psr-4": { 202 | "Composer\\CaBundle\\": "src" 203 | } 204 | }, 205 | "notification-url": "https://packagist.org/downloads/", 206 | "license": [ 207 | "MIT" 208 | ], 209 | "authors": [ 210 | { 211 | "name": "Jordi Boggiano", 212 | "email": "j.boggiano@seld.be", 213 | "homepage": "http://seld.be" 214 | } 215 | ], 216 | "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", 217 | "keywords": [ 218 | "cabundle", 219 | "cacert", 220 | "certificate", 221 | "ssl", 222 | "tls" 223 | ], 224 | "time": "2017-11-29T09:37:33+00:00" 225 | }, 226 | { 227 | "name": "composer/composer", 228 | "version": "1.5.5", 229 | "source": { 230 | "type": "git", 231 | "url": "https://github.com/composer/composer.git", 232 | "reference": "aab6229c9a4b6731f23b36107c39f4007c290b50" 233 | }, 234 | "dist": { 235 | "type": "zip", 236 | "url": "https://api.github.com/repos/composer/composer/zipball/aab6229c9a4b6731f23b36107c39f4007c290b50", 237 | "reference": "aab6229c9a4b6731f23b36107c39f4007c290b50", 238 | "shasum": "" 239 | }, 240 | "require": { 241 | "composer/ca-bundle": "^1.0", 242 | "composer/semver": "^1.0", 243 | "composer/spdx-licenses": "^1.0", 244 | "justinrainbow/json-schema": "^3.0 || ^4.0 || ^5.0", 245 | "php": "^5.3.2 || ^7.0", 246 | "psr/log": "^1.0", 247 | "seld/cli-prompt": "^1.0", 248 | "seld/jsonlint": "^1.4", 249 | "seld/phar-utils": "^1.0", 250 | "symfony/console": "^2.7 || ^3.0", 251 | "symfony/filesystem": "^2.7 || ^3.0", 252 | "symfony/finder": "^2.7 || ^3.0", 253 | "symfony/process": "^2.7 || ^3.0" 254 | }, 255 | "require-dev": { 256 | "phpunit/phpunit": "^4.5 || ^5.0.5", 257 | "phpunit/phpunit-mock-objects": "^2.3 || ^3.0" 258 | }, 259 | "suggest": { 260 | "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", 261 | "ext-zip": "Enabling the zip extension allows you to unzip archives", 262 | "ext-zlib": "Allow gzip compression of HTTP requests" 263 | }, 264 | "bin": [ 265 | "bin/composer" 266 | ], 267 | "type": "library", 268 | "extra": { 269 | "branch-alias": { 270 | "dev-master": "1.5-dev" 271 | } 272 | }, 273 | "autoload": { 274 | "psr-4": { 275 | "Composer\\": "src/Composer" 276 | } 277 | }, 278 | "notification-url": "https://packagist.org/downloads/", 279 | "license": [ 280 | "MIT" 281 | ], 282 | "authors": [ 283 | { 284 | "name": "Nils Adermann", 285 | "email": "naderman@naderman.de", 286 | "homepage": "http://www.naderman.de" 287 | }, 288 | { 289 | "name": "Jordi Boggiano", 290 | "email": "j.boggiano@seld.be", 291 | "homepage": "http://seld.be" 292 | } 293 | ], 294 | "description": "Composer helps you declare, manage and install dependencies of PHP projects, ensuring you have the right stack everywhere.", 295 | "homepage": "https://getcomposer.org/", 296 | "keywords": [ 297 | "autoload", 298 | "dependency", 299 | "package" 300 | ], 301 | "time": "2017-12-01T13:42:57+00:00" 302 | }, 303 | { 304 | "name": "composer/semver", 305 | "version": "1.4.2", 306 | "source": { 307 | "type": "git", 308 | "url": "https://github.com/composer/semver.git", 309 | "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573" 310 | }, 311 | "dist": { 312 | "type": "zip", 313 | "url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573", 314 | "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573", 315 | "shasum": "" 316 | }, 317 | "require": { 318 | "php": "^5.3.2 || ^7.0" 319 | }, 320 | "require-dev": { 321 | "phpunit/phpunit": "^4.5 || ^5.0.5", 322 | "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" 323 | }, 324 | "type": "library", 325 | "extra": { 326 | "branch-alias": { 327 | "dev-master": "1.x-dev" 328 | } 329 | }, 330 | "autoload": { 331 | "psr-4": { 332 | "Composer\\Semver\\": "src" 333 | } 334 | }, 335 | "notification-url": "https://packagist.org/downloads/", 336 | "license": [ 337 | "MIT" 338 | ], 339 | "authors": [ 340 | { 341 | "name": "Nils Adermann", 342 | "email": "naderman@naderman.de", 343 | "homepage": "http://www.naderman.de" 344 | }, 345 | { 346 | "name": "Jordi Boggiano", 347 | "email": "j.boggiano@seld.be", 348 | "homepage": "http://seld.be" 349 | }, 350 | { 351 | "name": "Rob Bast", 352 | "email": "rob.bast@gmail.com", 353 | "homepage": "http://robbast.nl" 354 | } 355 | ], 356 | "description": "Semver library that offers utilities, version constraint parsing and validation.", 357 | "keywords": [ 358 | "semantic", 359 | "semver", 360 | "validation", 361 | "versioning" 362 | ], 363 | "time": "2016-08-30T16:08:34+00:00" 364 | }, 365 | { 366 | "name": "composer/spdx-licenses", 367 | "version": "1.1.6", 368 | "source": { 369 | "type": "git", 370 | "url": "https://github.com/composer/spdx-licenses.git", 371 | "reference": "2603a0d7ddc00a015deb576fa5297ca43dee6b1c" 372 | }, 373 | "dist": { 374 | "type": "zip", 375 | "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/2603a0d7ddc00a015deb576fa5297ca43dee6b1c", 376 | "reference": "2603a0d7ddc00a015deb576fa5297ca43dee6b1c", 377 | "shasum": "" 378 | }, 379 | "require": { 380 | "php": "^5.3.2 || ^7.0" 381 | }, 382 | "require-dev": { 383 | "phpunit/phpunit": "^4.5 || ^5.0.5", 384 | "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" 385 | }, 386 | "type": "library", 387 | "extra": { 388 | "branch-alias": { 389 | "dev-master": "1.x-dev" 390 | } 391 | }, 392 | "autoload": { 393 | "psr-4": { 394 | "Composer\\Spdx\\": "src" 395 | } 396 | }, 397 | "notification-url": "https://packagist.org/downloads/", 398 | "license": [ 399 | "MIT" 400 | ], 401 | "authors": [ 402 | { 403 | "name": "Nils Adermann", 404 | "email": "naderman@naderman.de", 405 | "homepage": "http://www.naderman.de" 406 | }, 407 | { 408 | "name": "Jordi Boggiano", 409 | "email": "j.boggiano@seld.be", 410 | "homepage": "http://seld.be" 411 | }, 412 | { 413 | "name": "Rob Bast", 414 | "email": "rob.bast@gmail.com", 415 | "homepage": "http://robbast.nl" 416 | } 417 | ], 418 | "description": "SPDX licenses list and validation library.", 419 | "keywords": [ 420 | "license", 421 | "spdx", 422 | "validator" 423 | ], 424 | "time": "2017-04-03T19:08:52+00:00" 425 | }, 426 | { 427 | "name": "craftcms/cms", 428 | "version": "3.0.0-RC2", 429 | "source": { 430 | "type": "git", 431 | "url": "https://github.com/craftcms/cms.git", 432 | "reference": "526218356fc0c0e272ecc113c969eeb11e46e0ee" 433 | }, 434 | "dist": { 435 | "type": "zip", 436 | "url": "https://api.github.com/repos/craftcms/cms/zipball/526218356fc0c0e272ecc113c969eeb11e46e0ee", 437 | "reference": "526218356fc0c0e272ecc113c969eeb11e46e0ee", 438 | "shasum": "" 439 | }, 440 | "require": { 441 | "composer/composer": "~1.5.2", 442 | "craftcms/oauth2-craftid": "~1.0.0", 443 | "craftcms/plugin-installer": "~1.5.0", 444 | "craftcms/server-check": "~1.1.0", 445 | "creocoder/yii2-nested-sets": "~0.9.0", 446 | "danielstjules/stringy": "~3.1.0", 447 | "enshrined/svg-sanitize": "~0.7.2", 448 | "ext-curl": "*", 449 | "ext-dom": "*", 450 | "ext-json": "*", 451 | "ext-mbstring": "*", 452 | "ext-openssl": "*", 453 | "ext-pcre": "*", 454 | "ext-pdo": "*", 455 | "ext-zip": "*", 456 | "guzzlehttp/guzzle": "~6.3.0", 457 | "league/flysystem": "~1.0.35", 458 | "league/oauth2-client": "~2.2.1", 459 | "mikehaertl/php-shellcommand": "~1.2.5", 460 | "php": ">=7.0.0", 461 | "pixelandtonic/imagine": "~0.7.1.2", 462 | "seld/cli-prompt": "~1.0.3", 463 | "twig/twig": "~2.4.4", 464 | "yiisoft/yii2": "~2.0.13.0", 465 | "yiisoft/yii2-debug": "~2.0.10", 466 | "yiisoft/yii2-queue": "~2.0.1", 467 | "yiisoft/yii2-swiftmailer": "~2.1.0", 468 | "zendframework/zend-feed": "~2.8.0" 469 | }, 470 | "provide": { 471 | "bower-asset/bootstrap": "3.3.* | 3.2.* | 3.1.*", 472 | "bower-asset/inputmask": "~3.2.2 | ~3.3.5", 473 | "bower-asset/jquery": "3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable", 474 | "bower-asset/punycode": "1.3.*", 475 | "bower-asset/yii2-pjax": "~2.0.1" 476 | }, 477 | "require-dev": { 478 | "codeception/codeception": "~2.3.3", 479 | "codeception/mockery-module": "~0.2.2", 480 | "codeception/specify": "~0.4.6", 481 | "codeception/verify": "~0.3.3" 482 | }, 483 | "suggest": { 484 | "ext-iconv": "Adds support for more character encodings than PHP’s built-in mb_convert_encoding() function, which Craft will take advantage of when converting strings to UTF-8.", 485 | "ext-imagick": "Adds support for more image processing formats and options.", 486 | "ext-intl": "Adds rich internationalization support." 487 | }, 488 | "type": "library", 489 | "autoload": { 490 | "psr-4": { 491 | "craft\\": "src/" 492 | } 493 | }, 494 | "notification-url": "https://packagist.org/downloads/", 495 | "license": [ 496 | "proprietary" 497 | ], 498 | "description": "Craft CMS", 499 | "homepage": "https://craftcms.com", 500 | "keywords": [ 501 | "cms", 502 | "craftcms", 503 | "yii2" 504 | ], 505 | "time": "2017-12-12T20:42:34+00:00" 506 | }, 507 | { 508 | "name": "craftcms/element-api", 509 | "version": "2.5.2", 510 | "source": { 511 | "type": "git", 512 | "url": "https://github.com/craftcms/element-api.git", 513 | "reference": "4619d809280fe4a82e6e0859aa51073820065008" 514 | }, 515 | "dist": { 516 | "type": "zip", 517 | "url": "https://api.github.com/repos/craftcms/element-api/zipball/4619d809280fe4a82e6e0859aa51073820065008", 518 | "reference": "4619d809280fe4a82e6e0859aa51073820065008", 519 | "shasum": "" 520 | }, 521 | "require": { 522 | "craftcms/cms": "^3.0.0-beta.31", 523 | "league/fractal": "^0.16.0" 524 | }, 525 | "type": "craft-plugin", 526 | "extra": { 527 | "name": "Element API", 528 | "handle": "element-api", 529 | "changelogUrl": "https://raw.githubusercontent.com/craftcms/element-api/v2/CHANGELOG.md", 530 | "downloadUrl": "https://github.com/craftcms/element-api/archive/v2.zip" 531 | }, 532 | "autoload": { 533 | "psr-4": { 534 | "craft\\elementapi\\": "src/" 535 | } 536 | }, 537 | "notification-url": "https://packagist.org/downloads/", 538 | "license": [ 539 | "MIT" 540 | ], 541 | "authors": [ 542 | { 543 | "name": "Pixel & Tonic", 544 | "homepage": "https://pixelandtonic.com/" 545 | } 546 | ], 547 | "description": "Create a JSON API for your elements in Craft", 548 | "keywords": [ 549 | "api", 550 | "cms", 551 | "craftcms", 552 | "json", 553 | "yii2" 554 | ], 555 | "time": "2017-12-13T11:16:27+00:00" 556 | }, 557 | { 558 | "name": "craftcms/oauth2-craftid", 559 | "version": "1.0.0.1", 560 | "source": { 561 | "type": "git", 562 | "url": "https://github.com/craftcms/oauth2-craftid.git", 563 | "reference": "3f18364139d72d83fb50546d85130beaaa868836" 564 | }, 565 | "dist": { 566 | "type": "zip", 567 | "url": "https://api.github.com/repos/craftcms/oauth2-craftid/zipball/3f18364139d72d83fb50546d85130beaaa868836", 568 | "reference": "3f18364139d72d83fb50546d85130beaaa868836", 569 | "shasum": "" 570 | }, 571 | "require": { 572 | "league/oauth2-client": "^2.2.1" 573 | }, 574 | "require-dev": { 575 | "phpunit/phpunit": "^5.0", 576 | "satooshi/php-coveralls": "^1.0", 577 | "squizlabs/php_codesniffer": "^2.0" 578 | }, 579 | "type": "library", 580 | "autoload": { 581 | "psr-4": { 582 | "craftcms\\oauth2\\client\\": "src/" 583 | } 584 | }, 585 | "notification-url": "https://packagist.org/downloads/", 586 | "license": [ 587 | "MIT" 588 | ], 589 | "authors": [ 590 | { 591 | "name": "Pixel & Tonic", 592 | "homepage": "https://pixelandtonic.com/" 593 | } 594 | ], 595 | "description": "Craft OAuth 2.0 Client Provider for The PHP League OAuth2-Client", 596 | "keywords": [ 597 | "Authentication", 598 | "authorization", 599 | "client", 600 | "cms", 601 | "craftcms", 602 | "craftid", 603 | "oauth", 604 | "oauth2" 605 | ], 606 | "time": "2017-11-22T19:46:18+00:00" 607 | }, 608 | { 609 | "name": "craftcms/plugin-installer", 610 | "version": "1.5.2", 611 | "source": { 612 | "type": "git", 613 | "url": "https://github.com/craftcms/plugin-installer.git", 614 | "reference": "2b75646ce7091d24ef053e8d0b45f89cab04b16f" 615 | }, 616 | "dist": { 617 | "type": "zip", 618 | "url": "https://api.github.com/repos/craftcms/plugin-installer/zipball/2b75646ce7091d24ef053e8d0b45f89cab04b16f", 619 | "reference": "2b75646ce7091d24ef053e8d0b45f89cab04b16f", 620 | "shasum": "" 621 | }, 622 | "require": { 623 | "composer-plugin-api": "^1.0" 624 | }, 625 | "type": "composer-plugin", 626 | "extra": { 627 | "class": "craft\\composer\\Plugin" 628 | }, 629 | "autoload": { 630 | "psr-4": { 631 | "craft\\composer\\": "src/" 632 | } 633 | }, 634 | "notification-url": "https://packagist.org/downloads/", 635 | "license": [ 636 | "MIT" 637 | ], 638 | "description": "Craft CMS Plugin Installer", 639 | "homepage": "https://craftcms.com/", 640 | "keywords": [ 641 | "cms", 642 | "composer", 643 | "craftcms", 644 | "installer", 645 | "plugin" 646 | ], 647 | "time": "2017-07-25T13:26:24+00:00" 648 | }, 649 | { 650 | "name": "craftcms/server-check", 651 | "version": "1.1.0", 652 | "source": { 653 | "type": "git", 654 | "url": "https://github.com/craftcms/server-check.git", 655 | "reference": "6e7ecc427b5252b8b878f028a45738e19e7968b9" 656 | }, 657 | "dist": { 658 | "type": "zip", 659 | "url": "https://api.github.com/repos/craftcms/server-check/zipball/6e7ecc427b5252b8b878f028a45738e19e7968b9", 660 | "reference": "6e7ecc427b5252b8b878f028a45738e19e7968b9", 661 | "shasum": "" 662 | }, 663 | "type": "library", 664 | "autoload": { 665 | "classmap": [ 666 | "server/requirements" 667 | ] 668 | }, 669 | "notification-url": "https://packagist.org/downloads/", 670 | "license": [ 671 | "MIT" 672 | ], 673 | "description": "Craft CMS Server Check", 674 | "homepage": "https://craftcms.com/", 675 | "keywords": [ 676 | "cms", 677 | "craftcms", 678 | "requirements", 679 | "yii2" 680 | ], 681 | "time": "2017-11-11T00:13:31+00:00" 682 | }, 683 | { 684 | "name": "creocoder/yii2-nested-sets", 685 | "version": "0.9.0", 686 | "source": { 687 | "type": "git", 688 | "url": "https://github.com/creocoder/yii2-nested-sets.git", 689 | "reference": "cb8635a459b6246e5a144f096b992dcc30cf9954" 690 | }, 691 | "dist": { 692 | "type": "zip", 693 | "url": "https://api.github.com/repos/creocoder/yii2-nested-sets/zipball/cb8635a459b6246e5a144f096b992dcc30cf9954", 694 | "reference": "cb8635a459b6246e5a144f096b992dcc30cf9954", 695 | "shasum": "" 696 | }, 697 | "require": { 698 | "yiisoft/yii2": "*" 699 | }, 700 | "type": "yii2-extension", 701 | "autoload": { 702 | "psr-4": { 703 | "creocoder\\nestedsets\\": "src" 704 | } 705 | }, 706 | "notification-url": "https://packagist.org/downloads/", 707 | "license": [ 708 | "BSD-3-Clause" 709 | ], 710 | "authors": [ 711 | { 712 | "name": "Alexander Kochetov", 713 | "email": "creocoder@gmail.com" 714 | } 715 | ], 716 | "description": "The nested sets behavior for the Yii framework", 717 | "keywords": [ 718 | "nested sets", 719 | "yii2" 720 | ], 721 | "time": "2015-01-27T10:53:51+00:00" 722 | }, 723 | { 724 | "name": "danielstjules/stringy", 725 | "version": "3.1.0", 726 | "source": { 727 | "type": "git", 728 | "url": "https://github.com/danielstjules/Stringy.git", 729 | "reference": "df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e" 730 | }, 731 | "dist": { 732 | "type": "zip", 733 | "url": "https://api.github.com/repos/danielstjules/Stringy/zipball/df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e", 734 | "reference": "df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e", 735 | "shasum": "" 736 | }, 737 | "require": { 738 | "php": ">=5.4.0", 739 | "symfony/polyfill-mbstring": "~1.1" 740 | }, 741 | "require-dev": { 742 | "phpunit/phpunit": "~4.0" 743 | }, 744 | "type": "library", 745 | "autoload": { 746 | "psr-4": { 747 | "Stringy\\": "src/" 748 | }, 749 | "files": [ 750 | "src/Create.php" 751 | ] 752 | }, 753 | "notification-url": "https://packagist.org/downloads/", 754 | "license": [ 755 | "MIT" 756 | ], 757 | "authors": [ 758 | { 759 | "name": "Daniel St. Jules", 760 | "email": "danielst.jules@gmail.com", 761 | "homepage": "http://www.danielstjules.com" 762 | } 763 | ], 764 | "description": "A string manipulation library with multibyte support", 765 | "homepage": "https://github.com/danielstjules/Stringy", 766 | "keywords": [ 767 | "UTF", 768 | "helpers", 769 | "manipulation", 770 | "methods", 771 | "multibyte", 772 | "string", 773 | "utf-8", 774 | "utility", 775 | "utils" 776 | ], 777 | "time": "2017-06-12T01:10:27+00:00" 778 | }, 779 | { 780 | "name": "doctrine/lexer", 781 | "version": "v1.0.1", 782 | "source": { 783 | "type": "git", 784 | "url": "https://github.com/doctrine/lexer.git", 785 | "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" 786 | }, 787 | "dist": { 788 | "type": "zip", 789 | "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", 790 | "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", 791 | "shasum": "" 792 | }, 793 | "require": { 794 | "php": ">=5.3.2" 795 | }, 796 | "type": "library", 797 | "extra": { 798 | "branch-alias": { 799 | "dev-master": "1.0.x-dev" 800 | } 801 | }, 802 | "autoload": { 803 | "psr-0": { 804 | "Doctrine\\Common\\Lexer\\": "lib/" 805 | } 806 | }, 807 | "notification-url": "https://packagist.org/downloads/", 808 | "license": [ 809 | "MIT" 810 | ], 811 | "authors": [ 812 | { 813 | "name": "Roman Borschel", 814 | "email": "roman@code-factory.org" 815 | }, 816 | { 817 | "name": "Guilherme Blanco", 818 | "email": "guilhermeblanco@gmail.com" 819 | }, 820 | { 821 | "name": "Johannes Schmitt", 822 | "email": "schmittjoh@gmail.com" 823 | } 824 | ], 825 | "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", 826 | "homepage": "http://www.doctrine-project.org", 827 | "keywords": [ 828 | "lexer", 829 | "parser" 830 | ], 831 | "time": "2014-09-09T13:34:57+00:00" 832 | }, 833 | { 834 | "name": "egulias/email-validator", 835 | "version": "2.1.3", 836 | "source": { 837 | "type": "git", 838 | "url": "https://github.com/egulias/EmailValidator.git", 839 | "reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04" 840 | }, 841 | "dist": { 842 | "type": "zip", 843 | "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/1bec00a10039b823cc94eef4eddd47dcd3b2ca04", 844 | "reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04", 845 | "shasum": "" 846 | }, 847 | "require": { 848 | "doctrine/lexer": "^1.0.1", 849 | "php": ">= 5.5" 850 | }, 851 | "require-dev": { 852 | "dominicsayers/isemail": "dev-master", 853 | "phpunit/phpunit": "^4.8.35", 854 | "satooshi/php-coveralls": "^1.0.1" 855 | }, 856 | "suggest": { 857 | "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" 858 | }, 859 | "type": "library", 860 | "extra": { 861 | "branch-alias": { 862 | "dev-master": "2.0.x-dev" 863 | } 864 | }, 865 | "autoload": { 866 | "psr-4": { 867 | "Egulias\\EmailValidator\\": "EmailValidator" 868 | } 869 | }, 870 | "notification-url": "https://packagist.org/downloads/", 871 | "license": [ 872 | "MIT" 873 | ], 874 | "authors": [ 875 | { 876 | "name": "Eduardo Gulias Davis" 877 | } 878 | ], 879 | "description": "A library for validating emails against several RFCs", 880 | "homepage": "https://github.com/egulias/EmailValidator", 881 | "keywords": [ 882 | "email", 883 | "emailvalidation", 884 | "emailvalidator", 885 | "validation", 886 | "validator" 887 | ], 888 | "time": "2017-11-15T23:40:40+00:00" 889 | }, 890 | { 891 | "name": "elasticsearch/elasticsearch", 892 | "version": "v5.3.2", 893 | "source": { 894 | "type": "git", 895 | "url": "https://github.com/elastic/elasticsearch-php.git", 896 | "reference": "4b29a4121e790bbfe690d5ee77da348b62d48eb8" 897 | }, 898 | "dist": { 899 | "type": "zip", 900 | "url": "https://api.github.com/repos/elastic/elasticsearch-php/zipball/4b29a4121e790bbfe690d5ee77da348b62d48eb8", 901 | "reference": "4b29a4121e790bbfe690d5ee77da348b62d48eb8", 902 | "shasum": "" 903 | }, 904 | "require": { 905 | "guzzlehttp/ringphp": "~1.0", 906 | "php": "^5.6|^7.0", 907 | "psr/log": "~1.0" 908 | }, 909 | "require-dev": { 910 | "cpliakas/git-wrapper": "~1.0", 911 | "doctrine/inflector": "^1.1", 912 | "mockery/mockery": "0.9.4", 913 | "phpunit/phpunit": "^4.7|^5.4", 914 | "sami/sami": "~3.2", 915 | "symfony/finder": "^2.8", 916 | "symfony/yaml": "^2.8" 917 | }, 918 | "suggest": { 919 | "ext-curl": "*", 920 | "monolog/monolog": "Allows for client-level logging and tracing" 921 | }, 922 | "type": "library", 923 | "autoload": { 924 | "psr-4": { 925 | "Elasticsearch\\": "src/Elasticsearch/" 926 | } 927 | }, 928 | "notification-url": "https://packagist.org/downloads/", 929 | "license": [ 930 | "Apache-2.0" 931 | ], 932 | "authors": [ 933 | { 934 | "name": "Zachary Tong" 935 | } 936 | ], 937 | "description": "PHP Client for Elasticsearch", 938 | "keywords": [ 939 | "client", 940 | "elasticsearch", 941 | "search" 942 | ], 943 | "time": "2017-11-08T17:04:47+00:00" 944 | }, 945 | { 946 | "name": "enshrined/svg-sanitize", 947 | "version": "0.7.2", 948 | "source": { 949 | "type": "git", 950 | "url": "https://github.com/darylldoyle/svg-sanitizer.git", 951 | "reference": "2768fb1c8868d97145e8f2a5457caf590c8d2062" 952 | }, 953 | "dist": { 954 | "type": "zip", 955 | "url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/2768fb1c8868d97145e8f2a5457caf590c8d2062", 956 | "reference": "2768fb1c8868d97145e8f2a5457caf590c8d2062", 957 | "shasum": "" 958 | }, 959 | "require-dev": { 960 | "codeclimate/php-test-reporter": "^0.1.2", 961 | "phpunit/phpunit": "^4.7" 962 | }, 963 | "type": "library", 964 | "autoload": { 965 | "psr-4": { 966 | "enshrined\\svgSanitize\\": "src" 967 | } 968 | }, 969 | "notification-url": "https://packagist.org/downloads/", 970 | "license": [ 971 | "GPL-2.0+" 972 | ], 973 | "authors": [ 974 | { 975 | "name": "Daryll Doyle", 976 | "email": "daryll@enshrined.co.uk" 977 | } 978 | ], 979 | "description": "An SVG sanitizer for PHP", 980 | "time": "2017-08-31T00:10:18+00:00" 981 | }, 982 | { 983 | "name": "ezyang/htmlpurifier", 984 | "version": "v4.9.3", 985 | "source": { 986 | "type": "git", 987 | "url": "https://github.com/ezyang/htmlpurifier.git", 988 | "reference": "95e1bae3182efc0f3422896a3236e991049dac69" 989 | }, 990 | "dist": { 991 | "type": "zip", 992 | "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/95e1bae3182efc0f3422896a3236e991049dac69", 993 | "reference": "95e1bae3182efc0f3422896a3236e991049dac69", 994 | "shasum": "" 995 | }, 996 | "require": { 997 | "php": ">=5.2" 998 | }, 999 | "require-dev": { 1000 | "simpletest/simpletest": "^1.1" 1001 | }, 1002 | "type": "library", 1003 | "autoload": { 1004 | "psr-0": { 1005 | "HTMLPurifier": "library/" 1006 | }, 1007 | "files": [ 1008 | "library/HTMLPurifier.composer.php" 1009 | ] 1010 | }, 1011 | "notification-url": "https://packagist.org/downloads/", 1012 | "license": [ 1013 | "LGPL" 1014 | ], 1015 | "authors": [ 1016 | { 1017 | "name": "Edward Z. Yang", 1018 | "email": "admin@htmlpurifier.org", 1019 | "homepage": "http://ezyang.com" 1020 | } 1021 | ], 1022 | "description": "Standards compliant HTML filter written in PHP", 1023 | "homepage": "http://htmlpurifier.org/", 1024 | "keywords": [ 1025 | "html" 1026 | ], 1027 | "time": "2017-06-03T02:28:16+00:00" 1028 | }, 1029 | { 1030 | "name": "guzzlehttp/guzzle", 1031 | "version": "6.3.0", 1032 | "source": { 1033 | "type": "git", 1034 | "url": "https://github.com/guzzle/guzzle.git", 1035 | "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699" 1036 | }, 1037 | "dist": { 1038 | "type": "zip", 1039 | "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699", 1040 | "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699", 1041 | "shasum": "" 1042 | }, 1043 | "require": { 1044 | "guzzlehttp/promises": "^1.0", 1045 | "guzzlehttp/psr7": "^1.4", 1046 | "php": ">=5.5" 1047 | }, 1048 | "require-dev": { 1049 | "ext-curl": "*", 1050 | "phpunit/phpunit": "^4.0 || ^5.0", 1051 | "psr/log": "^1.0" 1052 | }, 1053 | "suggest": { 1054 | "psr/log": "Required for using the Log middleware" 1055 | }, 1056 | "type": "library", 1057 | "extra": { 1058 | "branch-alias": { 1059 | "dev-master": "6.2-dev" 1060 | } 1061 | }, 1062 | "autoload": { 1063 | "files": [ 1064 | "src/functions_include.php" 1065 | ], 1066 | "psr-4": { 1067 | "GuzzleHttp\\": "src/" 1068 | } 1069 | }, 1070 | "notification-url": "https://packagist.org/downloads/", 1071 | "license": [ 1072 | "MIT" 1073 | ], 1074 | "authors": [ 1075 | { 1076 | "name": "Michael Dowling", 1077 | "email": "mtdowling@gmail.com", 1078 | "homepage": "https://github.com/mtdowling" 1079 | } 1080 | ], 1081 | "description": "Guzzle is a PHP HTTP client library", 1082 | "homepage": "http://guzzlephp.org/", 1083 | "keywords": [ 1084 | "client", 1085 | "curl", 1086 | "framework", 1087 | "http", 1088 | "http client", 1089 | "rest", 1090 | "web service" 1091 | ], 1092 | "time": "2017-06-22T18:50:49+00:00" 1093 | }, 1094 | { 1095 | "name": "guzzlehttp/promises", 1096 | "version": "v1.3.1", 1097 | "source": { 1098 | "type": "git", 1099 | "url": "https://github.com/guzzle/promises.git", 1100 | "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" 1101 | }, 1102 | "dist": { 1103 | "type": "zip", 1104 | "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", 1105 | "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", 1106 | "shasum": "" 1107 | }, 1108 | "require": { 1109 | "php": ">=5.5.0" 1110 | }, 1111 | "require-dev": { 1112 | "phpunit/phpunit": "^4.0" 1113 | }, 1114 | "type": "library", 1115 | "extra": { 1116 | "branch-alias": { 1117 | "dev-master": "1.4-dev" 1118 | } 1119 | }, 1120 | "autoload": { 1121 | "psr-4": { 1122 | "GuzzleHttp\\Promise\\": "src/" 1123 | }, 1124 | "files": [ 1125 | "src/functions_include.php" 1126 | ] 1127 | }, 1128 | "notification-url": "https://packagist.org/downloads/", 1129 | "license": [ 1130 | "MIT" 1131 | ], 1132 | "authors": [ 1133 | { 1134 | "name": "Michael Dowling", 1135 | "email": "mtdowling@gmail.com", 1136 | "homepage": "https://github.com/mtdowling" 1137 | } 1138 | ], 1139 | "description": "Guzzle promises library", 1140 | "keywords": [ 1141 | "promise" 1142 | ], 1143 | "time": "2016-12-20T10:07:11+00:00" 1144 | }, 1145 | { 1146 | "name": "guzzlehttp/psr7", 1147 | "version": "1.4.2", 1148 | "source": { 1149 | "type": "git", 1150 | "url": "https://github.com/guzzle/psr7.git", 1151 | "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" 1152 | }, 1153 | "dist": { 1154 | "type": "zip", 1155 | "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", 1156 | "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", 1157 | "shasum": "" 1158 | }, 1159 | "require": { 1160 | "php": ">=5.4.0", 1161 | "psr/http-message": "~1.0" 1162 | }, 1163 | "provide": { 1164 | "psr/http-message-implementation": "1.0" 1165 | }, 1166 | "require-dev": { 1167 | "phpunit/phpunit": "~4.0" 1168 | }, 1169 | "type": "library", 1170 | "extra": { 1171 | "branch-alias": { 1172 | "dev-master": "1.4-dev" 1173 | } 1174 | }, 1175 | "autoload": { 1176 | "psr-4": { 1177 | "GuzzleHttp\\Psr7\\": "src/" 1178 | }, 1179 | "files": [ 1180 | "src/functions_include.php" 1181 | ] 1182 | }, 1183 | "notification-url": "https://packagist.org/downloads/", 1184 | "license": [ 1185 | "MIT" 1186 | ], 1187 | "authors": [ 1188 | { 1189 | "name": "Michael Dowling", 1190 | "email": "mtdowling@gmail.com", 1191 | "homepage": "https://github.com/mtdowling" 1192 | }, 1193 | { 1194 | "name": "Tobias Schultze", 1195 | "homepage": "https://github.com/Tobion" 1196 | } 1197 | ], 1198 | "description": "PSR-7 message implementation that also provides common utility methods", 1199 | "keywords": [ 1200 | "http", 1201 | "message", 1202 | "request", 1203 | "response", 1204 | "stream", 1205 | "uri", 1206 | "url" 1207 | ], 1208 | "time": "2017-03-20T17:10:46+00:00" 1209 | }, 1210 | { 1211 | "name": "guzzlehttp/ringphp", 1212 | "version": "1.1.0", 1213 | "source": { 1214 | "type": "git", 1215 | "url": "https://github.com/guzzle/RingPHP.git", 1216 | "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b" 1217 | }, 1218 | "dist": { 1219 | "type": "zip", 1220 | "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/dbbb91d7f6c191e5e405e900e3102ac7f261bc0b", 1221 | "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b", 1222 | "shasum": "" 1223 | }, 1224 | "require": { 1225 | "guzzlehttp/streams": "~3.0", 1226 | "php": ">=5.4.0", 1227 | "react/promise": "~2.0" 1228 | }, 1229 | "require-dev": { 1230 | "ext-curl": "*", 1231 | "phpunit/phpunit": "~4.0" 1232 | }, 1233 | "suggest": { 1234 | "ext-curl": "Guzzle will use specific adapters if cURL is present" 1235 | }, 1236 | "type": "library", 1237 | "extra": { 1238 | "branch-alias": { 1239 | "dev-master": "1.1-dev" 1240 | } 1241 | }, 1242 | "autoload": { 1243 | "psr-4": { 1244 | "GuzzleHttp\\Ring\\": "src/" 1245 | } 1246 | }, 1247 | "notification-url": "https://packagist.org/downloads/", 1248 | "license": [ 1249 | "MIT" 1250 | ], 1251 | "authors": [ 1252 | { 1253 | "name": "Michael Dowling", 1254 | "email": "mtdowling@gmail.com", 1255 | "homepage": "https://github.com/mtdowling" 1256 | } 1257 | ], 1258 | "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.", 1259 | "time": "2015-05-20T03:37:09+00:00" 1260 | }, 1261 | { 1262 | "name": "guzzlehttp/streams", 1263 | "version": "3.0.0", 1264 | "source": { 1265 | "type": "git", 1266 | "url": "https://github.com/guzzle/streams.git", 1267 | "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5" 1268 | }, 1269 | "dist": { 1270 | "type": "zip", 1271 | "url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", 1272 | "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", 1273 | "shasum": "" 1274 | }, 1275 | "require": { 1276 | "php": ">=5.4.0" 1277 | }, 1278 | "require-dev": { 1279 | "phpunit/phpunit": "~4.0" 1280 | }, 1281 | "type": "library", 1282 | "extra": { 1283 | "branch-alias": { 1284 | "dev-master": "3.0-dev" 1285 | } 1286 | }, 1287 | "autoload": { 1288 | "psr-4": { 1289 | "GuzzleHttp\\Stream\\": "src/" 1290 | } 1291 | }, 1292 | "notification-url": "https://packagist.org/downloads/", 1293 | "license": [ 1294 | "MIT" 1295 | ], 1296 | "authors": [ 1297 | { 1298 | "name": "Michael Dowling", 1299 | "email": "mtdowling@gmail.com", 1300 | "homepage": "https://github.com/mtdowling" 1301 | } 1302 | ], 1303 | "description": "Provides a simple abstraction over streams of data", 1304 | "homepage": "http://guzzlephp.org/", 1305 | "keywords": [ 1306 | "Guzzle", 1307 | "stream" 1308 | ], 1309 | "time": "2014-10-12T19:18:40+00:00" 1310 | }, 1311 | { 1312 | "name": "justinrainbow/json-schema", 1313 | "version": "5.2.6", 1314 | "source": { 1315 | "type": "git", 1316 | "url": "https://github.com/justinrainbow/json-schema.git", 1317 | "reference": "d283e11b6e14c6f4664cf080415c4341293e5bbd" 1318 | }, 1319 | "dist": { 1320 | "type": "zip", 1321 | "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/d283e11b6e14c6f4664cf080415c4341293e5bbd", 1322 | "reference": "d283e11b6e14c6f4664cf080415c4341293e5bbd", 1323 | "shasum": "" 1324 | }, 1325 | "require": { 1326 | "php": ">=5.3.3" 1327 | }, 1328 | "require-dev": { 1329 | "friendsofphp/php-cs-fixer": "^2.1", 1330 | "json-schema/json-schema-test-suite": "1.2.0", 1331 | "phpunit/phpunit": "^4.8.22" 1332 | }, 1333 | "bin": [ 1334 | "bin/validate-json" 1335 | ], 1336 | "type": "library", 1337 | "extra": { 1338 | "branch-alias": { 1339 | "dev-master": "5.0.x-dev" 1340 | } 1341 | }, 1342 | "autoload": { 1343 | "psr-4": { 1344 | "JsonSchema\\": "src/JsonSchema/" 1345 | } 1346 | }, 1347 | "notification-url": "https://packagist.org/downloads/", 1348 | "license": [ 1349 | "MIT" 1350 | ], 1351 | "authors": [ 1352 | { 1353 | "name": "Bruno Prieto Reis", 1354 | "email": "bruno.p.reis@gmail.com" 1355 | }, 1356 | { 1357 | "name": "Justin Rainbow", 1358 | "email": "justin.rainbow@gmail.com" 1359 | }, 1360 | { 1361 | "name": "Igor Wiedler", 1362 | "email": "igor@wiedler.ch" 1363 | }, 1364 | { 1365 | "name": "Robert Schönthal", 1366 | "email": "seroscho@googlemail.com" 1367 | } 1368 | ], 1369 | "description": "A library to validate a json schema.", 1370 | "homepage": "https://github.com/justinrainbow/json-schema", 1371 | "keywords": [ 1372 | "json", 1373 | "schema" 1374 | ], 1375 | "time": "2017-10-21T13:15:38+00:00" 1376 | }, 1377 | { 1378 | "name": "league/flysystem", 1379 | "version": "1.0.41", 1380 | "source": { 1381 | "type": "git", 1382 | "url": "https://github.com/thephpleague/flysystem.git", 1383 | "reference": "f400aa98912c561ba625ea4065031b7a41e5a155" 1384 | }, 1385 | "dist": { 1386 | "type": "zip", 1387 | "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/f400aa98912c561ba625ea4065031b7a41e5a155", 1388 | "reference": "f400aa98912c561ba625ea4065031b7a41e5a155", 1389 | "shasum": "" 1390 | }, 1391 | "require": { 1392 | "php": ">=5.5.9" 1393 | }, 1394 | "conflict": { 1395 | "league/flysystem-sftp": "<1.0.6" 1396 | }, 1397 | "require-dev": { 1398 | "ext-fileinfo": "*", 1399 | "mockery/mockery": "~0.9", 1400 | "phpspec/phpspec": "^2.2", 1401 | "phpunit/phpunit": "~4.8" 1402 | }, 1403 | "suggest": { 1404 | "ext-fileinfo": "Required for MimeType", 1405 | "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", 1406 | "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", 1407 | "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", 1408 | "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", 1409 | "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", 1410 | "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", 1411 | "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", 1412 | "league/flysystem-webdav": "Allows you to use WebDAV storage", 1413 | "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", 1414 | "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", 1415 | "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" 1416 | }, 1417 | "type": "library", 1418 | "extra": { 1419 | "branch-alias": { 1420 | "dev-master": "1.1-dev" 1421 | } 1422 | }, 1423 | "autoload": { 1424 | "psr-4": { 1425 | "League\\Flysystem\\": "src/" 1426 | } 1427 | }, 1428 | "notification-url": "https://packagist.org/downloads/", 1429 | "license": [ 1430 | "MIT" 1431 | ], 1432 | "authors": [ 1433 | { 1434 | "name": "Frank de Jonge", 1435 | "email": "info@frenky.net" 1436 | } 1437 | ], 1438 | "description": "Filesystem abstraction: Many filesystems, one API.", 1439 | "keywords": [ 1440 | "Cloud Files", 1441 | "WebDAV", 1442 | "abstraction", 1443 | "aws", 1444 | "cloud", 1445 | "copy.com", 1446 | "dropbox", 1447 | "file systems", 1448 | "files", 1449 | "filesystem", 1450 | "filesystems", 1451 | "ftp", 1452 | "rackspace", 1453 | "remote", 1454 | "s3", 1455 | "sftp", 1456 | "storage" 1457 | ], 1458 | "time": "2017-08-06T17:41:04+00:00" 1459 | }, 1460 | { 1461 | "name": "league/fractal", 1462 | "version": "0.16.0", 1463 | "source": { 1464 | "type": "git", 1465 | "url": "https://github.com/thephpleague/fractal.git", 1466 | "reference": "d0445305e308d9207430680acfd580557b679ddc" 1467 | }, 1468 | "dist": { 1469 | "type": "zip", 1470 | "url": "https://api.github.com/repos/thephpleague/fractal/zipball/d0445305e308d9207430680acfd580557b679ddc", 1471 | "reference": "d0445305e308d9207430680acfd580557b679ddc", 1472 | "shasum": "" 1473 | }, 1474 | "require": { 1475 | "php": ">=5.4" 1476 | }, 1477 | "require-dev": { 1478 | "doctrine/orm": "^2.5", 1479 | "illuminate/contracts": "~5.0", 1480 | "mockery/mockery": "~0.9", 1481 | "pagerfanta/pagerfanta": "~1.0.0", 1482 | "phpunit/phpunit": "~4.0", 1483 | "squizlabs/php_codesniffer": "~1.5", 1484 | "zendframework/zend-paginator": "~2.3" 1485 | }, 1486 | "suggest": { 1487 | "illuminate/pagination": "The Illuminate Pagination component.", 1488 | "pagerfanta/pagerfanta": "Pagerfanta Paginator", 1489 | "zendframework/zend-paginator": "Zend Framework Paginator" 1490 | }, 1491 | "type": "library", 1492 | "extra": { 1493 | "branch-alias": { 1494 | "dev-master": "0.13-dev" 1495 | } 1496 | }, 1497 | "autoload": { 1498 | "psr-4": { 1499 | "League\\Fractal\\": "src" 1500 | } 1501 | }, 1502 | "notification-url": "https://packagist.org/downloads/", 1503 | "license": [ 1504 | "MIT" 1505 | ], 1506 | "authors": [ 1507 | { 1508 | "name": "Phil Sturgeon", 1509 | "email": "me@philsturgeon.uk", 1510 | "homepage": "http://philsturgeon.uk/", 1511 | "role": "Developer" 1512 | } 1513 | ], 1514 | "description": "Handle the output of complex data structures ready for API output.", 1515 | "homepage": "http://fractal.thephpleague.com/", 1516 | "keywords": [ 1517 | "api", 1518 | "json", 1519 | "league", 1520 | "rest" 1521 | ], 1522 | "time": "2017-03-12T01:28:43+00:00" 1523 | }, 1524 | { 1525 | "name": "league/oauth2-client", 1526 | "version": "2.2.1", 1527 | "source": { 1528 | "type": "git", 1529 | "url": "https://github.com/thephpleague/oauth2-client.git", 1530 | "reference": "313250eab923e673a5c0c8f463f443ee79f4383f" 1531 | }, 1532 | "dist": { 1533 | "type": "zip", 1534 | "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/313250eab923e673a5c0c8f463f443ee79f4383f", 1535 | "reference": "313250eab923e673a5c0c8f463f443ee79f4383f", 1536 | "shasum": "" 1537 | }, 1538 | "require": { 1539 | "guzzlehttp/guzzle": "^6.0", 1540 | "paragonie/random_compat": "^1|^2", 1541 | "php": ">=5.6.0" 1542 | }, 1543 | "require-dev": { 1544 | "eloquent/liberator": "^2.0", 1545 | "eloquent/phony": "^0.14.1", 1546 | "jakub-onderka/php-parallel-lint": "~0.9", 1547 | "phpunit/phpunit": "^5.0", 1548 | "squizlabs/php_codesniffer": "^2.0" 1549 | }, 1550 | "type": "library", 1551 | "extra": { 1552 | "branch-alias": { 1553 | "dev-2.x": "2.0.x-dev" 1554 | } 1555 | }, 1556 | "autoload": { 1557 | "psr-4": { 1558 | "League\\OAuth2\\Client\\": "src/" 1559 | } 1560 | }, 1561 | "notification-url": "https://packagist.org/downloads/", 1562 | "license": [ 1563 | "MIT" 1564 | ], 1565 | "authors": [ 1566 | { 1567 | "name": "Alex Bilbie", 1568 | "email": "hello@alexbilbie.com", 1569 | "homepage": "http://www.alexbilbie.com", 1570 | "role": "Developer" 1571 | }, 1572 | { 1573 | "name": "Woody Gilk", 1574 | "homepage": "https://github.com/shadowhand", 1575 | "role": "Contributor" 1576 | } 1577 | ], 1578 | "description": "OAuth 2.0 Client Library", 1579 | "keywords": [ 1580 | "Authentication", 1581 | "SSO", 1582 | "authorization", 1583 | "identity", 1584 | "idp", 1585 | "oauth", 1586 | "oauth2", 1587 | "single sign on" 1588 | ], 1589 | "time": "2017-04-25T14:43:14+00:00" 1590 | }, 1591 | { 1592 | "name": "mikehaertl/php-shellcommand", 1593 | "version": "1.2.5", 1594 | "source": { 1595 | "type": "git", 1596 | "url": "https://github.com/mikehaertl/php-shellcommand.git", 1597 | "reference": "35a81f344bd771b0b1c1ae3f4dc986dddfd234b9" 1598 | }, 1599 | "dist": { 1600 | "type": "zip", 1601 | "url": "https://api.github.com/repos/mikehaertl/php-shellcommand/zipball/35a81f344bd771b0b1c1ae3f4dc986dddfd234b9", 1602 | "reference": "35a81f344bd771b0b1c1ae3f4dc986dddfd234b9", 1603 | "shasum": "" 1604 | }, 1605 | "type": "library", 1606 | "autoload": { 1607 | "psr-4": { 1608 | "mikehaertl\\shellcommand\\": "src/" 1609 | } 1610 | }, 1611 | "notification-url": "https://packagist.org/downloads/", 1612 | "license": [ 1613 | "MIT" 1614 | ], 1615 | "authors": [ 1616 | { 1617 | "name": "Michael Härtl", 1618 | "email": "haertl.mike@gmail.com" 1619 | } 1620 | ], 1621 | "description": "An object oriented interface to shell commands", 1622 | "keywords": [ 1623 | "shell" 1624 | ], 1625 | "time": "2017-06-30T06:21:01+00:00" 1626 | }, 1627 | { 1628 | "name": "paragonie/random_compat", 1629 | "version": "v2.0.11", 1630 | "source": { 1631 | "type": "git", 1632 | "url": "https://github.com/paragonie/random_compat.git", 1633 | "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8" 1634 | }, 1635 | "dist": { 1636 | "type": "zip", 1637 | "url": "https://api.github.com/repos/paragonie/random_compat/zipball/5da4d3c796c275c55f057af5a643ae297d96b4d8", 1638 | "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8", 1639 | "shasum": "" 1640 | }, 1641 | "require": { 1642 | "php": ">=5.2.0" 1643 | }, 1644 | "require-dev": { 1645 | "phpunit/phpunit": "4.*|5.*" 1646 | }, 1647 | "suggest": { 1648 | "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." 1649 | }, 1650 | "type": "library", 1651 | "autoload": { 1652 | "files": [ 1653 | "lib/random.php" 1654 | ] 1655 | }, 1656 | "notification-url": "https://packagist.org/downloads/", 1657 | "license": [ 1658 | "MIT" 1659 | ], 1660 | "authors": [ 1661 | { 1662 | "name": "Paragon Initiative Enterprises", 1663 | "email": "security@paragonie.com", 1664 | "homepage": "https://paragonie.com" 1665 | } 1666 | ], 1667 | "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", 1668 | "keywords": [ 1669 | "csprng", 1670 | "pseudorandom", 1671 | "random" 1672 | ], 1673 | "time": "2017-09-27T21:40:39+00:00" 1674 | }, 1675 | { 1676 | "name": "pixelandtonic/imagine", 1677 | "version": "v0.7.1.3", 1678 | "source": { 1679 | "type": "git", 1680 | "url": "https://github.com/pixelandtonic/Imagine.git", 1681 | "reference": "989656b05410446fde623540bbf83af15087e4ea" 1682 | }, 1683 | "dist": { 1684 | "type": "zip", 1685 | "url": "https://api.github.com/repos/pixelandtonic/Imagine/zipball/989656b05410446fde623540bbf83af15087e4ea", 1686 | "reference": "989656b05410446fde623540bbf83af15087e4ea", 1687 | "shasum": "" 1688 | }, 1689 | "require": { 1690 | "php": ">=5.3.2" 1691 | }, 1692 | "require-dev": { 1693 | "sami/sami": "^3.3", 1694 | "symfony/phpunit-bridge": "^3.2" 1695 | }, 1696 | "suggest": { 1697 | "ext-gd": "to use the GD implementation", 1698 | "ext-gmagick": "to use the Gmagick implementation", 1699 | "ext-imagick": "to use the Imagick implementation" 1700 | }, 1701 | "type": "library", 1702 | "extra": { 1703 | "branch-alias": { 1704 | "dev-develop": "0.7-dev" 1705 | } 1706 | }, 1707 | "autoload": { 1708 | "psr-0": { 1709 | "Imagine": "lib/" 1710 | } 1711 | }, 1712 | "notification-url": "https://packagist.org/downloads/", 1713 | "license": [ 1714 | "MIT" 1715 | ], 1716 | "authors": [ 1717 | { 1718 | "name": "Bulat Shakirzyanov", 1719 | "email": "mallluhuct@gmail.com", 1720 | "homepage": "http://avalanche123.com" 1721 | } 1722 | ], 1723 | "description": "Image processing for PHP 5.3", 1724 | "homepage": "http://imagine.readthedocs.org/", 1725 | "keywords": [ 1726 | "drawing", 1727 | "graphics", 1728 | "image manipulation", 1729 | "image processing" 1730 | ], 1731 | "time": "2017-10-26T13:18:33+00:00" 1732 | }, 1733 | { 1734 | "name": "psr/http-message", 1735 | "version": "1.0.1", 1736 | "source": { 1737 | "type": "git", 1738 | "url": "https://github.com/php-fig/http-message.git", 1739 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" 1740 | }, 1741 | "dist": { 1742 | "type": "zip", 1743 | "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", 1744 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", 1745 | "shasum": "" 1746 | }, 1747 | "require": { 1748 | "php": ">=5.3.0" 1749 | }, 1750 | "type": "library", 1751 | "extra": { 1752 | "branch-alias": { 1753 | "dev-master": "1.0.x-dev" 1754 | } 1755 | }, 1756 | "autoload": { 1757 | "psr-4": { 1758 | "Psr\\Http\\Message\\": "src/" 1759 | } 1760 | }, 1761 | "notification-url": "https://packagist.org/downloads/", 1762 | "license": [ 1763 | "MIT" 1764 | ], 1765 | "authors": [ 1766 | { 1767 | "name": "PHP-FIG", 1768 | "homepage": "http://www.php-fig.org/" 1769 | } 1770 | ], 1771 | "description": "Common interface for HTTP messages", 1772 | "homepage": "https://github.com/php-fig/http-message", 1773 | "keywords": [ 1774 | "http", 1775 | "http-message", 1776 | "psr", 1777 | "psr-7", 1778 | "request", 1779 | "response" 1780 | ], 1781 | "time": "2016-08-06T14:39:51+00:00" 1782 | }, 1783 | { 1784 | "name": "psr/log", 1785 | "version": "1.0.2", 1786 | "source": { 1787 | "type": "git", 1788 | "url": "https://github.com/php-fig/log.git", 1789 | "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" 1790 | }, 1791 | "dist": { 1792 | "type": "zip", 1793 | "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", 1794 | "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", 1795 | "shasum": "" 1796 | }, 1797 | "require": { 1798 | "php": ">=5.3.0" 1799 | }, 1800 | "type": "library", 1801 | "extra": { 1802 | "branch-alias": { 1803 | "dev-master": "1.0.x-dev" 1804 | } 1805 | }, 1806 | "autoload": { 1807 | "psr-4": { 1808 | "Psr\\Log\\": "Psr/Log/" 1809 | } 1810 | }, 1811 | "notification-url": "https://packagist.org/downloads/", 1812 | "license": [ 1813 | "MIT" 1814 | ], 1815 | "authors": [ 1816 | { 1817 | "name": "PHP-FIG", 1818 | "homepage": "http://www.php-fig.org/" 1819 | } 1820 | ], 1821 | "description": "Common interface for logging libraries", 1822 | "homepage": "https://github.com/php-fig/log", 1823 | "keywords": [ 1824 | "log", 1825 | "psr", 1826 | "psr-3" 1827 | ], 1828 | "time": "2016-10-10T12:19:37+00:00" 1829 | }, 1830 | { 1831 | "name": "react/promise", 1832 | "version": "v2.5.1", 1833 | "source": { 1834 | "type": "git", 1835 | "url": "https://github.com/reactphp/promise.git", 1836 | "reference": "62785ae604c8d69725d693eb370e1d67e94c4053" 1837 | }, 1838 | "dist": { 1839 | "type": "zip", 1840 | "url": "https://api.github.com/repos/reactphp/promise/zipball/62785ae604c8d69725d693eb370e1d67e94c4053", 1841 | "reference": "62785ae604c8d69725d693eb370e1d67e94c4053", 1842 | "shasum": "" 1843 | }, 1844 | "require": { 1845 | "php": ">=5.4.0" 1846 | }, 1847 | "require-dev": { 1848 | "phpunit/phpunit": "~4.8" 1849 | }, 1850 | "type": "library", 1851 | "autoload": { 1852 | "psr-4": { 1853 | "React\\Promise\\": "src/" 1854 | }, 1855 | "files": [ 1856 | "src/functions_include.php" 1857 | ] 1858 | }, 1859 | "notification-url": "https://packagist.org/downloads/", 1860 | "license": [ 1861 | "MIT" 1862 | ], 1863 | "authors": [ 1864 | { 1865 | "name": "Jan Sorgalla", 1866 | "email": "jsorgalla@gmail.com" 1867 | } 1868 | ], 1869 | "description": "A lightweight implementation of CommonJS Promises/A for PHP", 1870 | "keywords": [ 1871 | "promise", 1872 | "promises" 1873 | ], 1874 | "time": "2017-03-25T12:08:31+00:00" 1875 | }, 1876 | { 1877 | "name": "seld/cli-prompt", 1878 | "version": "1.0.3", 1879 | "source": { 1880 | "type": "git", 1881 | "url": "https://github.com/Seldaek/cli-prompt.git", 1882 | "reference": "a19a7376a4689d4d94cab66ab4f3c816019ba8dd" 1883 | }, 1884 | "dist": { 1885 | "type": "zip", 1886 | "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/a19a7376a4689d4d94cab66ab4f3c816019ba8dd", 1887 | "reference": "a19a7376a4689d4d94cab66ab4f3c816019ba8dd", 1888 | "shasum": "" 1889 | }, 1890 | "require": { 1891 | "php": ">=5.3" 1892 | }, 1893 | "type": "library", 1894 | "extra": { 1895 | "branch-alias": { 1896 | "dev-master": "1.x-dev" 1897 | } 1898 | }, 1899 | "autoload": { 1900 | "psr-4": { 1901 | "Seld\\CliPrompt\\": "src/" 1902 | } 1903 | }, 1904 | "notification-url": "https://packagist.org/downloads/", 1905 | "license": [ 1906 | "MIT" 1907 | ], 1908 | "authors": [ 1909 | { 1910 | "name": "Jordi Boggiano", 1911 | "email": "j.boggiano@seld.be" 1912 | } 1913 | ], 1914 | "description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type", 1915 | "keywords": [ 1916 | "cli", 1917 | "console", 1918 | "hidden", 1919 | "input", 1920 | "prompt" 1921 | ], 1922 | "time": "2017-03-18T11:32:45+00:00" 1923 | }, 1924 | { 1925 | "name": "seld/jsonlint", 1926 | "version": "1.6.2", 1927 | "source": { 1928 | "type": "git", 1929 | "url": "https://github.com/Seldaek/jsonlint.git", 1930 | "reference": "7a30649c67ee0d19faacfd9fa2cfb6cc032d9b19" 1931 | }, 1932 | "dist": { 1933 | "type": "zip", 1934 | "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/7a30649c67ee0d19faacfd9fa2cfb6cc032d9b19", 1935 | "reference": "7a30649c67ee0d19faacfd9fa2cfb6cc032d9b19", 1936 | "shasum": "" 1937 | }, 1938 | "require": { 1939 | "php": "^5.3 || ^7.0" 1940 | }, 1941 | "require-dev": { 1942 | "phpunit/phpunit": "^4.5" 1943 | }, 1944 | "bin": [ 1945 | "bin/jsonlint" 1946 | ], 1947 | "type": "library", 1948 | "autoload": { 1949 | "psr-4": { 1950 | "Seld\\JsonLint\\": "src/Seld/JsonLint/" 1951 | } 1952 | }, 1953 | "notification-url": "https://packagist.org/downloads/", 1954 | "license": [ 1955 | "MIT" 1956 | ], 1957 | "authors": [ 1958 | { 1959 | "name": "Jordi Boggiano", 1960 | "email": "j.boggiano@seld.be", 1961 | "homepage": "http://seld.be" 1962 | } 1963 | ], 1964 | "description": "JSON Linter", 1965 | "keywords": [ 1966 | "json", 1967 | "linter", 1968 | "parser", 1969 | "validator" 1970 | ], 1971 | "time": "2017-11-30T15:34:22+00:00" 1972 | }, 1973 | { 1974 | "name": "seld/phar-utils", 1975 | "version": "1.0.1", 1976 | "source": { 1977 | "type": "git", 1978 | "url": "https://github.com/Seldaek/phar-utils.git", 1979 | "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a" 1980 | }, 1981 | "dist": { 1982 | "type": "zip", 1983 | "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/7009b5139491975ef6486545a39f3e6dad5ac30a", 1984 | "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a", 1985 | "shasum": "" 1986 | }, 1987 | "require": { 1988 | "php": ">=5.3" 1989 | }, 1990 | "type": "library", 1991 | "extra": { 1992 | "branch-alias": { 1993 | "dev-master": "1.x-dev" 1994 | } 1995 | }, 1996 | "autoload": { 1997 | "psr-4": { 1998 | "Seld\\PharUtils\\": "src/" 1999 | } 2000 | }, 2001 | "notification-url": "https://packagist.org/downloads/", 2002 | "license": [ 2003 | "MIT" 2004 | ], 2005 | "authors": [ 2006 | { 2007 | "name": "Jordi Boggiano", 2008 | "email": "j.boggiano@seld.be" 2009 | } 2010 | ], 2011 | "description": "PHAR file format utilities, for when PHP phars you up", 2012 | "keywords": [ 2013 | "phra" 2014 | ], 2015 | "time": "2015-10-13T18:44:15+00:00" 2016 | }, 2017 | { 2018 | "name": "swiftmailer/swiftmailer", 2019 | "version": "v6.0.2", 2020 | "source": { 2021 | "type": "git", 2022 | "url": "https://github.com/swiftmailer/swiftmailer.git", 2023 | "reference": "412333372fb6c8ffb65496a2bbd7321af75733fc" 2024 | }, 2025 | "dist": { 2026 | "type": "zip", 2027 | "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/412333372fb6c8ffb65496a2bbd7321af75733fc", 2028 | "reference": "412333372fb6c8ffb65496a2bbd7321af75733fc", 2029 | "shasum": "" 2030 | }, 2031 | "require": { 2032 | "egulias/email-validator": "~2.0", 2033 | "php": ">=7.0.0" 2034 | }, 2035 | "require-dev": { 2036 | "mockery/mockery": "~0.9.1", 2037 | "symfony/phpunit-bridge": "~3.3@dev" 2038 | }, 2039 | "type": "library", 2040 | "extra": { 2041 | "branch-alias": { 2042 | "dev-master": "6.0-dev" 2043 | } 2044 | }, 2045 | "autoload": { 2046 | "files": [ 2047 | "lib/swift_required.php" 2048 | ] 2049 | }, 2050 | "notification-url": "https://packagist.org/downloads/", 2051 | "license": [ 2052 | "MIT" 2053 | ], 2054 | "authors": [ 2055 | { 2056 | "name": "Chris Corbyn" 2057 | }, 2058 | { 2059 | "name": "Fabien Potencier", 2060 | "email": "fabien@symfony.com" 2061 | } 2062 | ], 2063 | "description": "Swiftmailer, free feature-rich PHP mailer", 2064 | "homepage": "http://swiftmailer.symfony.com", 2065 | "keywords": [ 2066 | "email", 2067 | "mail", 2068 | "mailer" 2069 | ], 2070 | "time": "2017-09-30T22:39:41+00:00" 2071 | }, 2072 | { 2073 | "name": "symfony/console", 2074 | "version": "v3.4.2", 2075 | "source": { 2076 | "type": "git", 2077 | "url": "https://github.com/symfony/console.git", 2078 | "reference": "9f21adfb92a9315b73ae2ed43138988ee4913d4e" 2079 | }, 2080 | "dist": { 2081 | "type": "zip", 2082 | "url": "https://api.github.com/repos/symfony/console/zipball/9f21adfb92a9315b73ae2ed43138988ee4913d4e", 2083 | "reference": "9f21adfb92a9315b73ae2ed43138988ee4913d4e", 2084 | "shasum": "" 2085 | }, 2086 | "require": { 2087 | "php": "^5.5.9|>=7.0.8", 2088 | "symfony/debug": "~2.8|~3.0|~4.0", 2089 | "symfony/polyfill-mbstring": "~1.0" 2090 | }, 2091 | "conflict": { 2092 | "symfony/dependency-injection": "<3.4", 2093 | "symfony/process": "<3.3" 2094 | }, 2095 | "require-dev": { 2096 | "psr/log": "~1.0", 2097 | "symfony/config": "~3.3|~4.0", 2098 | "symfony/dependency-injection": "~3.4|~4.0", 2099 | "symfony/event-dispatcher": "~2.8|~3.0|~4.0", 2100 | "symfony/lock": "~3.4|~4.0", 2101 | "symfony/process": "~3.3|~4.0" 2102 | }, 2103 | "suggest": { 2104 | "psr/log": "For using the console logger", 2105 | "symfony/event-dispatcher": "", 2106 | "symfony/lock": "", 2107 | "symfony/process": "" 2108 | }, 2109 | "type": "library", 2110 | "extra": { 2111 | "branch-alias": { 2112 | "dev-master": "3.4-dev" 2113 | } 2114 | }, 2115 | "autoload": { 2116 | "psr-4": { 2117 | "Symfony\\Component\\Console\\": "" 2118 | }, 2119 | "exclude-from-classmap": [ 2120 | "/Tests/" 2121 | ] 2122 | }, 2123 | "notification-url": "https://packagist.org/downloads/", 2124 | "license": [ 2125 | "MIT" 2126 | ], 2127 | "authors": [ 2128 | { 2129 | "name": "Fabien Potencier", 2130 | "email": "fabien@symfony.com" 2131 | }, 2132 | { 2133 | "name": "Symfony Community", 2134 | "homepage": "https://symfony.com/contributors" 2135 | } 2136 | ], 2137 | "description": "Symfony Console Component", 2138 | "homepage": "https://symfony.com", 2139 | "time": "2017-12-14T19:40:10+00:00" 2140 | }, 2141 | { 2142 | "name": "symfony/debug", 2143 | "version": "v3.4.2", 2144 | "source": { 2145 | "type": "git", 2146 | "url": "https://github.com/symfony/debug.git", 2147 | "reference": "543deab3ffff94402440b326fc94153bae2dfa7a" 2148 | }, 2149 | "dist": { 2150 | "type": "zip", 2151 | "url": "https://api.github.com/repos/symfony/debug/zipball/543deab3ffff94402440b326fc94153bae2dfa7a", 2152 | "reference": "543deab3ffff94402440b326fc94153bae2dfa7a", 2153 | "shasum": "" 2154 | }, 2155 | "require": { 2156 | "php": "^5.5.9|>=7.0.8", 2157 | "psr/log": "~1.0" 2158 | }, 2159 | "conflict": { 2160 | "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" 2161 | }, 2162 | "require-dev": { 2163 | "symfony/http-kernel": "~2.8|~3.0|~4.0" 2164 | }, 2165 | "type": "library", 2166 | "extra": { 2167 | "branch-alias": { 2168 | "dev-master": "3.4-dev" 2169 | } 2170 | }, 2171 | "autoload": { 2172 | "psr-4": { 2173 | "Symfony\\Component\\Debug\\": "" 2174 | }, 2175 | "exclude-from-classmap": [ 2176 | "/Tests/" 2177 | ] 2178 | }, 2179 | "notification-url": "https://packagist.org/downloads/", 2180 | "license": [ 2181 | "MIT" 2182 | ], 2183 | "authors": [ 2184 | { 2185 | "name": "Fabien Potencier", 2186 | "email": "fabien@symfony.com" 2187 | }, 2188 | { 2189 | "name": "Symfony Community", 2190 | "homepage": "https://symfony.com/contributors" 2191 | } 2192 | ], 2193 | "description": "Symfony Debug Component", 2194 | "homepage": "https://symfony.com", 2195 | "time": "2017-12-12T08:27:14+00:00" 2196 | }, 2197 | { 2198 | "name": "symfony/filesystem", 2199 | "version": "v3.4.2", 2200 | "source": { 2201 | "type": "git", 2202 | "url": "https://github.com/symfony/filesystem.git", 2203 | "reference": "25b135bea251829e3db6a77d773643408b575ed4" 2204 | }, 2205 | "dist": { 2206 | "type": "zip", 2207 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/25b135bea251829e3db6a77d773643408b575ed4", 2208 | "reference": "25b135bea251829e3db6a77d773643408b575ed4", 2209 | "shasum": "" 2210 | }, 2211 | "require": { 2212 | "php": "^5.5.9|>=7.0.8" 2213 | }, 2214 | "type": "library", 2215 | "extra": { 2216 | "branch-alias": { 2217 | "dev-master": "3.4-dev" 2218 | } 2219 | }, 2220 | "autoload": { 2221 | "psr-4": { 2222 | "Symfony\\Component\\Filesystem\\": "" 2223 | }, 2224 | "exclude-from-classmap": [ 2225 | "/Tests/" 2226 | ] 2227 | }, 2228 | "notification-url": "https://packagist.org/downloads/", 2229 | "license": [ 2230 | "MIT" 2231 | ], 2232 | "authors": [ 2233 | { 2234 | "name": "Fabien Potencier", 2235 | "email": "fabien@symfony.com" 2236 | }, 2237 | { 2238 | "name": "Symfony Community", 2239 | "homepage": "https://symfony.com/contributors" 2240 | } 2241 | ], 2242 | "description": "Symfony Filesystem Component", 2243 | "homepage": "https://symfony.com", 2244 | "time": "2017-12-14T19:40:10+00:00" 2245 | }, 2246 | { 2247 | "name": "symfony/finder", 2248 | "version": "v3.4.2", 2249 | "source": { 2250 | "type": "git", 2251 | "url": "https://github.com/symfony/finder.git", 2252 | "reference": "dac8d7db537bac7ad8143eb11360a8c2231f251a" 2253 | }, 2254 | "dist": { 2255 | "type": "zip", 2256 | "url": "https://api.github.com/repos/symfony/finder/zipball/dac8d7db537bac7ad8143eb11360a8c2231f251a", 2257 | "reference": "dac8d7db537bac7ad8143eb11360a8c2231f251a", 2258 | "shasum": "" 2259 | }, 2260 | "require": { 2261 | "php": "^5.5.9|>=7.0.8" 2262 | }, 2263 | "type": "library", 2264 | "extra": { 2265 | "branch-alias": { 2266 | "dev-master": "3.4-dev" 2267 | } 2268 | }, 2269 | "autoload": { 2270 | "psr-4": { 2271 | "Symfony\\Component\\Finder\\": "" 2272 | }, 2273 | "exclude-from-classmap": [ 2274 | "/Tests/" 2275 | ] 2276 | }, 2277 | "notification-url": "https://packagist.org/downloads/", 2278 | "license": [ 2279 | "MIT" 2280 | ], 2281 | "authors": [ 2282 | { 2283 | "name": "Fabien Potencier", 2284 | "email": "fabien@symfony.com" 2285 | }, 2286 | { 2287 | "name": "Symfony Community", 2288 | "homepage": "https://symfony.com/contributors" 2289 | } 2290 | ], 2291 | "description": "Symfony Finder Component", 2292 | "homepage": "https://symfony.com", 2293 | "time": "2017-11-05T16:10:10+00:00" 2294 | }, 2295 | { 2296 | "name": "symfony/polyfill-mbstring", 2297 | "version": "v1.6.0", 2298 | "source": { 2299 | "type": "git", 2300 | "url": "https://github.com/symfony/polyfill-mbstring.git", 2301 | "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296" 2302 | }, 2303 | "dist": { 2304 | "type": "zip", 2305 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", 2306 | "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", 2307 | "shasum": "" 2308 | }, 2309 | "require": { 2310 | "php": ">=5.3.3" 2311 | }, 2312 | "suggest": { 2313 | "ext-mbstring": "For best performance" 2314 | }, 2315 | "type": "library", 2316 | "extra": { 2317 | "branch-alias": { 2318 | "dev-master": "1.6-dev" 2319 | } 2320 | }, 2321 | "autoload": { 2322 | "psr-4": { 2323 | "Symfony\\Polyfill\\Mbstring\\": "" 2324 | }, 2325 | "files": [ 2326 | "bootstrap.php" 2327 | ] 2328 | }, 2329 | "notification-url": "https://packagist.org/downloads/", 2330 | "license": [ 2331 | "MIT" 2332 | ], 2333 | "authors": [ 2334 | { 2335 | "name": "Nicolas Grekas", 2336 | "email": "p@tchwork.com" 2337 | }, 2338 | { 2339 | "name": "Symfony Community", 2340 | "homepage": "https://symfony.com/contributors" 2341 | } 2342 | ], 2343 | "description": "Symfony polyfill for the Mbstring extension", 2344 | "homepage": "https://symfony.com", 2345 | "keywords": [ 2346 | "compatibility", 2347 | "mbstring", 2348 | "polyfill", 2349 | "portable", 2350 | "shim" 2351 | ], 2352 | "time": "2017-10-11T12:05:26+00:00" 2353 | }, 2354 | { 2355 | "name": "symfony/process", 2356 | "version": "v3.4.2", 2357 | "source": { 2358 | "type": "git", 2359 | "url": "https://github.com/symfony/process.git", 2360 | "reference": "bb3ef65d493a6d57297cad6c560ee04e2a8f5098" 2361 | }, 2362 | "dist": { 2363 | "type": "zip", 2364 | "url": "https://api.github.com/repos/symfony/process/zipball/bb3ef65d493a6d57297cad6c560ee04e2a8f5098", 2365 | "reference": "bb3ef65d493a6d57297cad6c560ee04e2a8f5098", 2366 | "shasum": "" 2367 | }, 2368 | "require": { 2369 | "php": "^5.5.9|>=7.0.8" 2370 | }, 2371 | "type": "library", 2372 | "extra": { 2373 | "branch-alias": { 2374 | "dev-master": "3.4-dev" 2375 | } 2376 | }, 2377 | "autoload": { 2378 | "psr-4": { 2379 | "Symfony\\Component\\Process\\": "" 2380 | }, 2381 | "exclude-from-classmap": [ 2382 | "/Tests/" 2383 | ] 2384 | }, 2385 | "notification-url": "https://packagist.org/downloads/", 2386 | "license": [ 2387 | "MIT" 2388 | ], 2389 | "authors": [ 2390 | { 2391 | "name": "Fabien Potencier", 2392 | "email": "fabien@symfony.com" 2393 | }, 2394 | { 2395 | "name": "Symfony Community", 2396 | "homepage": "https://symfony.com/contributors" 2397 | } 2398 | ], 2399 | "description": "Symfony Process Component", 2400 | "homepage": "https://symfony.com", 2401 | "time": "2017-12-14T19:40:10+00:00" 2402 | }, 2403 | { 2404 | "name": "twig/twig", 2405 | "version": "v2.4.4", 2406 | "source": { 2407 | "type": "git", 2408 | "url": "https://github.com/twigphp/Twig.git", 2409 | "reference": "eddb97148ad779f27e670e1e3f19fb323aedafeb" 2410 | }, 2411 | "dist": { 2412 | "type": "zip", 2413 | "url": "https://api.github.com/repos/twigphp/Twig/zipball/eddb97148ad779f27e670e1e3f19fb323aedafeb", 2414 | "reference": "eddb97148ad779f27e670e1e3f19fb323aedafeb", 2415 | "shasum": "" 2416 | }, 2417 | "require": { 2418 | "php": "^7.0", 2419 | "symfony/polyfill-mbstring": "~1.0" 2420 | }, 2421 | "require-dev": { 2422 | "psr/container": "^1.0", 2423 | "symfony/debug": "~2.7", 2424 | "symfony/phpunit-bridge": "~3.3@dev" 2425 | }, 2426 | "type": "library", 2427 | "extra": { 2428 | "branch-alias": { 2429 | "dev-master": "2.4-dev" 2430 | } 2431 | }, 2432 | "autoload": { 2433 | "psr-0": { 2434 | "Twig_": "lib/" 2435 | }, 2436 | "psr-4": { 2437 | "Twig\\": "src/" 2438 | } 2439 | }, 2440 | "notification-url": "https://packagist.org/downloads/", 2441 | "license": [ 2442 | "BSD-3-Clause" 2443 | ], 2444 | "authors": [ 2445 | { 2446 | "name": "Fabien Potencier", 2447 | "email": "fabien@symfony.com", 2448 | "homepage": "http://fabien.potencier.org", 2449 | "role": "Lead Developer" 2450 | }, 2451 | { 2452 | "name": "Armin Ronacher", 2453 | "email": "armin.ronacher@active-4.com", 2454 | "role": "Project Founder" 2455 | }, 2456 | { 2457 | "name": "Twig Team", 2458 | "homepage": "http://twig.sensiolabs.org/contributors", 2459 | "role": "Contributors" 2460 | } 2461 | ], 2462 | "description": "Twig, the flexible, fast, and secure template language for PHP", 2463 | "homepage": "http://twig.sensiolabs.org", 2464 | "keywords": [ 2465 | "templating" 2466 | ], 2467 | "time": "2017-09-27T18:10:31+00:00" 2468 | }, 2469 | { 2470 | "name": "yiisoft/yii2", 2471 | "version": "2.0.13.1", 2472 | "source": { 2473 | "type": "git", 2474 | "url": "https://github.com/yiisoft/yii2-framework.git", 2475 | "reference": "7af96d8da5ea3e9a5dd05d0e734b21c5726a6ddf" 2476 | }, 2477 | "dist": { 2478 | "type": "zip", 2479 | "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/7af96d8da5ea3e9a5dd05d0e734b21c5726a6ddf", 2480 | "reference": "7af96d8da5ea3e9a5dd05d0e734b21c5726a6ddf", 2481 | "shasum": "" 2482 | }, 2483 | "require": { 2484 | "bower-asset/inputmask": "~3.2.2 | ~3.3.5", 2485 | "bower-asset/jquery": "3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable", 2486 | "bower-asset/punycode": "1.3.*", 2487 | "bower-asset/yii2-pjax": "~2.0.1", 2488 | "cebe/markdown": "~1.0.0 | ~1.1.0", 2489 | "ext-ctype": "*", 2490 | "ext-mbstring": "*", 2491 | "ezyang/htmlpurifier": "~4.6", 2492 | "lib-pcre": "*", 2493 | "php": ">=5.4.0", 2494 | "yiisoft/yii2-composer": "~2.0.4" 2495 | }, 2496 | "bin": [ 2497 | "yii" 2498 | ], 2499 | "type": "library", 2500 | "extra": { 2501 | "branch-alias": { 2502 | "dev-master": "2.0.x-dev" 2503 | } 2504 | }, 2505 | "autoload": { 2506 | "psr-4": { 2507 | "yii\\": "" 2508 | } 2509 | }, 2510 | "notification-url": "https://packagist.org/downloads/", 2511 | "license": [ 2512 | "BSD-3-Clause" 2513 | ], 2514 | "authors": [ 2515 | { 2516 | "name": "Qiang Xue", 2517 | "email": "qiang.xue@gmail.com", 2518 | "homepage": "http://www.yiiframework.com/", 2519 | "role": "Founder and project lead" 2520 | }, 2521 | { 2522 | "name": "Alexander Makarov", 2523 | "email": "sam@rmcreative.ru", 2524 | "homepage": "http://rmcreative.ru/", 2525 | "role": "Core framework development" 2526 | }, 2527 | { 2528 | "name": "Maurizio Domba", 2529 | "homepage": "http://mdomba.info/", 2530 | "role": "Core framework development" 2531 | }, 2532 | { 2533 | "name": "Carsten Brandt", 2534 | "email": "mail@cebe.cc", 2535 | "homepage": "http://cebe.cc/", 2536 | "role": "Core framework development" 2537 | }, 2538 | { 2539 | "name": "Timur Ruziev", 2540 | "email": "resurtm@gmail.com", 2541 | "homepage": "http://resurtm.com/", 2542 | "role": "Core framework development" 2543 | }, 2544 | { 2545 | "name": "Paul Klimov", 2546 | "email": "klimov.paul@gmail.com", 2547 | "role": "Core framework development" 2548 | }, 2549 | { 2550 | "name": "Dmitry Naumenko", 2551 | "email": "d.naumenko.a@gmail.com", 2552 | "role": "Core framework development" 2553 | }, 2554 | { 2555 | "name": "Boudewijn Vahrmeijer", 2556 | "email": "info@dynasource.eu", 2557 | "homepage": "http://dynasource.eu", 2558 | "role": "Core framework development" 2559 | } 2560 | ], 2561 | "description": "Yii PHP Framework Version 2", 2562 | "homepage": "http://www.yiiframework.com/", 2563 | "keywords": [ 2564 | "framework", 2565 | "yii2" 2566 | ], 2567 | "time": "2017-11-14T11:08:21+00:00" 2568 | }, 2569 | { 2570 | "name": "yiisoft/yii2-bootstrap", 2571 | "version": "2.0.7", 2572 | "source": { 2573 | "type": "git", 2574 | "url": "https://github.com/yiisoft/yii2-bootstrap.git", 2575 | "reference": "02a54d868343ed11d02f0f0f8cbbecb590e0cb3f" 2576 | }, 2577 | "dist": { 2578 | "type": "zip", 2579 | "url": "https://api.github.com/repos/yiisoft/yii2-bootstrap/zipball/02a54d868343ed11d02f0f0f8cbbecb590e0cb3f", 2580 | "reference": "02a54d868343ed11d02f0f0f8cbbecb590e0cb3f", 2581 | "shasum": "" 2582 | }, 2583 | "require": { 2584 | "bower-asset/bootstrap": "3.3.* | 3.2.* | 3.1.*", 2585 | "yiisoft/yii2": "~2.0.6" 2586 | }, 2587 | "type": "yii2-extension", 2588 | "extra": { 2589 | "branch-alias": { 2590 | "dev-master": "2.0.x-dev" 2591 | } 2592 | }, 2593 | "autoload": { 2594 | "psr-4": { 2595 | "yii\\bootstrap\\": "" 2596 | } 2597 | }, 2598 | "notification-url": "https://packagist.org/downloads/", 2599 | "license": [ 2600 | "BSD-3-Clause" 2601 | ], 2602 | "authors": [ 2603 | { 2604 | "name": "Qiang Xue", 2605 | "email": "qiang.xue@gmail.com" 2606 | } 2607 | ], 2608 | "description": "The Twitter Bootstrap extension for the Yii framework", 2609 | "keywords": [ 2610 | "bootstrap", 2611 | "yii2" 2612 | ], 2613 | "time": "2017-10-09T19:48:22+00:00" 2614 | }, 2615 | { 2616 | "name": "yiisoft/yii2-composer", 2617 | "version": "2.0.5", 2618 | "source": { 2619 | "type": "git", 2620 | "url": "https://github.com/yiisoft/yii2-composer.git", 2621 | "reference": "3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2" 2622 | }, 2623 | "dist": { 2624 | "type": "zip", 2625 | "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2", 2626 | "reference": "3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2", 2627 | "shasum": "" 2628 | }, 2629 | "require": { 2630 | "composer-plugin-api": "^1.0" 2631 | }, 2632 | "require-dev": { 2633 | "composer/composer": "^1.0" 2634 | }, 2635 | "type": "composer-plugin", 2636 | "extra": { 2637 | "class": "yii\\composer\\Plugin", 2638 | "branch-alias": { 2639 | "dev-master": "2.0.x-dev" 2640 | } 2641 | }, 2642 | "autoload": { 2643 | "psr-4": { 2644 | "yii\\composer\\": "" 2645 | } 2646 | }, 2647 | "notification-url": "https://packagist.org/downloads/", 2648 | "license": [ 2649 | "BSD-3-Clause" 2650 | ], 2651 | "authors": [ 2652 | { 2653 | "name": "Qiang Xue", 2654 | "email": "qiang.xue@gmail.com" 2655 | } 2656 | ], 2657 | "description": "The composer plugin for Yii extension installer", 2658 | "keywords": [ 2659 | "composer", 2660 | "extension installer", 2661 | "yii2" 2662 | ], 2663 | "time": "2016-12-20T13:26:02+00:00" 2664 | }, 2665 | { 2666 | "name": "yiisoft/yii2-debug", 2667 | "version": "2.0.13", 2668 | "source": { 2669 | "type": "git", 2670 | "url": "https://github.com/yiisoft/yii2-debug.git", 2671 | "reference": "b37f414959c2fafefb332020b42037cd17c1cb7f" 2672 | }, 2673 | "dist": { 2674 | "type": "zip", 2675 | "url": "https://api.github.com/repos/yiisoft/yii2-debug/zipball/b37f414959c2fafefb332020b42037cd17c1cb7f", 2676 | "reference": "b37f414959c2fafefb332020b42037cd17c1cb7f", 2677 | "shasum": "" 2678 | }, 2679 | "require": { 2680 | "yiisoft/yii2": "~2.0.13", 2681 | "yiisoft/yii2-bootstrap": "~2.0.0" 2682 | }, 2683 | "type": "yii2-extension", 2684 | "extra": { 2685 | "branch-alias": { 2686 | "dev-master": "2.0.x-dev" 2687 | } 2688 | }, 2689 | "autoload": { 2690 | "psr-4": { 2691 | "yii\\debug\\": "" 2692 | } 2693 | }, 2694 | "notification-url": "https://packagist.org/downloads/", 2695 | "license": [ 2696 | "BSD-3-Clause" 2697 | ], 2698 | "authors": [ 2699 | { 2700 | "name": "Qiang Xue", 2701 | "email": "qiang.xue@gmail.com" 2702 | } 2703 | ], 2704 | "description": "The debugger extension for the Yii framework", 2705 | "keywords": [ 2706 | "debug", 2707 | "debugger", 2708 | "yii2" 2709 | ], 2710 | "time": "2017-12-05T07:36:23+00:00" 2711 | }, 2712 | { 2713 | "name": "yiisoft/yii2-queue", 2714 | "version": "2.0.1", 2715 | "source": { 2716 | "type": "git", 2717 | "url": "https://github.com/yiisoft/yii2-queue.git", 2718 | "reference": "5e3bc6c389c4374acaf40dfa1901ba258983f575" 2719 | }, 2720 | "dist": { 2721 | "type": "zip", 2722 | "url": "https://api.github.com/repos/yiisoft/yii2-queue/zipball/5e3bc6c389c4374acaf40dfa1901ba258983f575", 2723 | "reference": "5e3bc6c389c4374acaf40dfa1901ba258983f575", 2724 | "shasum": "" 2725 | }, 2726 | "require": { 2727 | "php": ">=5.5.0", 2728 | "symfony/process": "*", 2729 | "yiisoft/yii2": "~2.0.13" 2730 | }, 2731 | "require-dev": { 2732 | "jeremeamia/superclosure": "*", 2733 | "pda/pheanstalk": "*", 2734 | "php-amqplib/php-amqplib": "*", 2735 | "phpunit/phpunit": "~4.4", 2736 | "yiisoft/yii2-debug": "*", 2737 | "yiisoft/yii2-gii": "*", 2738 | "yiisoft/yii2-redis": "*" 2739 | }, 2740 | "suggest": { 2741 | "ext-gearman": "Need for Gearman queue.", 2742 | "ext-pcntl": "Need for process signals.", 2743 | "pda/pheanstalk": "Need for Beanstalk queue.", 2744 | "php-amqplib/php-amqplib": "Need for AMQP queue.", 2745 | "yiisoft/yii2-redis": "Need for Redis queue." 2746 | }, 2747 | "type": "yii2-extension", 2748 | "extra": { 2749 | "branch-alias": { 2750 | "dev-master": "2.0.x-dev" 2751 | } 2752 | }, 2753 | "autoload": { 2754 | "psr-4": { 2755 | "yii\\queue\\": "src", 2756 | "yii\\queue\\amqp\\": "src/drivers/amqp", 2757 | "yii\\queue\\beanstalk\\": "src/drivers/beanstalk", 2758 | "yii\\queue\\db\\": "src/drivers/db", 2759 | "yii\\queue\\file\\": "src/drivers/file", 2760 | "yii\\queue\\gearman\\": "src/drivers/gearman", 2761 | "yii\\queue\\redis\\": "src/drivers/redis", 2762 | "yii\\queue\\sync\\": "src/drivers/sync" 2763 | } 2764 | }, 2765 | "notification-url": "https://packagist.org/downloads/", 2766 | "license": [ 2767 | "BSD-3-Clause" 2768 | ], 2769 | "authors": [ 2770 | { 2771 | "name": "Roman Zhuravlev", 2772 | "email": "zhuravljov@gmail.com" 2773 | } 2774 | ], 2775 | "description": "Yii2 Queue Extension which supported DB, Redis, RabbitMQ, Beanstalk and Gearman", 2776 | "keywords": [ 2777 | "async", 2778 | "beanstalk", 2779 | "db", 2780 | "gearman", 2781 | "gii", 2782 | "queue", 2783 | "rabbitmq", 2784 | "redis", 2785 | "yii" 2786 | ], 2787 | "time": "2017-11-13T19:49:43+00:00" 2788 | }, 2789 | { 2790 | "name": "yiisoft/yii2-swiftmailer", 2791 | "version": "2.1.0", 2792 | "source": { 2793 | "type": "git", 2794 | "url": "https://github.com/yiisoft/yii2-swiftmailer.git", 2795 | "reference": "563570c9aa19ca47c1b22e3032983229378e9274" 2796 | }, 2797 | "dist": { 2798 | "type": "zip", 2799 | "url": "https://api.github.com/repos/yiisoft/yii2-swiftmailer/zipball/563570c9aa19ca47c1b22e3032983229378e9274", 2800 | "reference": "563570c9aa19ca47c1b22e3032983229378e9274", 2801 | "shasum": "" 2802 | }, 2803 | "require": { 2804 | "swiftmailer/swiftmailer": "~6.0", 2805 | "yiisoft/yii2": "~2.0.4" 2806 | }, 2807 | "type": "yii2-extension", 2808 | "extra": { 2809 | "branch-alias": { 2810 | "dev-master": "2.0.x-dev" 2811 | } 2812 | }, 2813 | "autoload": { 2814 | "psr-4": { 2815 | "yii\\swiftmailer\\": "" 2816 | } 2817 | }, 2818 | "notification-url": "https://packagist.org/downloads/", 2819 | "license": [ 2820 | "BSD-3-Clause" 2821 | ], 2822 | "authors": [ 2823 | { 2824 | "name": "Paul Klimov", 2825 | "email": "klimov.paul@gmail.com" 2826 | } 2827 | ], 2828 | "description": "The SwiftMailer integration for the Yii framework", 2829 | "keywords": [ 2830 | "email", 2831 | "mail", 2832 | "mailer", 2833 | "swift", 2834 | "swiftmailer", 2835 | "yii2" 2836 | ], 2837 | "time": "2017-08-04T10:48:17+00:00" 2838 | }, 2839 | { 2840 | "name": "zendframework/zend-escaper", 2841 | "version": "2.5.2", 2842 | "source": { 2843 | "type": "git", 2844 | "url": "https://github.com/zendframework/zend-escaper.git", 2845 | "reference": "2dcd14b61a72d8b8e27d579c6344e12c26141d4e" 2846 | }, 2847 | "dist": { 2848 | "type": "zip", 2849 | "url": "https://api.github.com/repos/zendframework/zend-escaper/zipball/2dcd14b61a72d8b8e27d579c6344e12c26141d4e", 2850 | "reference": "2dcd14b61a72d8b8e27d579c6344e12c26141d4e", 2851 | "shasum": "" 2852 | }, 2853 | "require": { 2854 | "php": ">=5.5" 2855 | }, 2856 | "require-dev": { 2857 | "fabpot/php-cs-fixer": "1.7.*", 2858 | "phpunit/phpunit": "~4.0" 2859 | }, 2860 | "type": "library", 2861 | "extra": { 2862 | "branch-alias": { 2863 | "dev-master": "2.5-dev", 2864 | "dev-develop": "2.6-dev" 2865 | } 2866 | }, 2867 | "autoload": { 2868 | "psr-4": { 2869 | "Zend\\Escaper\\": "src/" 2870 | } 2871 | }, 2872 | "notification-url": "https://packagist.org/downloads/", 2873 | "license": [ 2874 | "BSD-3-Clause" 2875 | ], 2876 | "homepage": "https://github.com/zendframework/zend-escaper", 2877 | "keywords": [ 2878 | "escaper", 2879 | "zf2" 2880 | ], 2881 | "time": "2016-06-30T19:48:38+00:00" 2882 | }, 2883 | { 2884 | "name": "zendframework/zend-feed", 2885 | "version": "2.8.0", 2886 | "source": { 2887 | "type": "git", 2888 | "url": "https://github.com/zendframework/zend-feed.git", 2889 | "reference": "94579e805dd108683209fe14b3b5d4276de3de6e" 2890 | }, 2891 | "dist": { 2892 | "type": "zip", 2893 | "url": "https://api.github.com/repos/zendframework/zend-feed/zipball/94579e805dd108683209fe14b3b5d4276de3de6e", 2894 | "reference": "94579e805dd108683209fe14b3b5d4276de3de6e", 2895 | "shasum": "" 2896 | }, 2897 | "require": { 2898 | "php": "^5.6 || ^7.0", 2899 | "zendframework/zend-escaper": "^2.5", 2900 | "zendframework/zend-stdlib": "^2.7 || ^3.1" 2901 | }, 2902 | "require-dev": { 2903 | "phpunit/phpunit": "^6.0.8 || ^5.7.15", 2904 | "psr/http-message": "^1.0", 2905 | "zendframework/zend-cache": "^2.6", 2906 | "zendframework/zend-coding-standard": "~1.0.0", 2907 | "zendframework/zend-db": "^2.7", 2908 | "zendframework/zend-http": "^2.5.4", 2909 | "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3", 2910 | "zendframework/zend-validator": "^2.6" 2911 | }, 2912 | "suggest": { 2913 | "psr/http-message": "PSR-7 ^1.0, if you wish to use Zend\\Feed\\Reader\\Http\\Psr7ResponseDecorator", 2914 | "zendframework/zend-cache": "Zend\\Cache component, for optionally caching feeds between requests", 2915 | "zendframework/zend-db": "Zend\\Db component, for use with PubSubHubbub", 2916 | "zendframework/zend-http": "Zend\\Http for PubSubHubbub, and optionally for use with Zend\\Feed\\Reader", 2917 | "zendframework/zend-servicemanager": "Zend\\ServiceManager component, for easily extending ExtensionManager implementations", 2918 | "zendframework/zend-validator": "Zend\\Validator component, for validating email addresses used in Atom feeds and entries ehen using the Writer subcomponent" 2919 | }, 2920 | "type": "library", 2921 | "extra": { 2922 | "branch-alias": { 2923 | "dev-master": "2.8-dev", 2924 | "dev-develop": "2.9-dev" 2925 | } 2926 | }, 2927 | "autoload": { 2928 | "psr-4": { 2929 | "Zend\\Feed\\": "src/" 2930 | } 2931 | }, 2932 | "notification-url": "https://packagist.org/downloads/", 2933 | "license": [ 2934 | "BSD-3-Clause" 2935 | ], 2936 | "description": "provides functionality for consuming RSS and Atom feeds", 2937 | "homepage": "https://github.com/zendframework/zend-feed", 2938 | "keywords": [ 2939 | "feed", 2940 | "zf2" 2941 | ], 2942 | "time": "2017-04-01T15:03:14+00:00" 2943 | }, 2944 | { 2945 | "name": "zendframework/zend-stdlib", 2946 | "version": "3.1.0", 2947 | "source": { 2948 | "type": "git", 2949 | "url": "https://github.com/zendframework/zend-stdlib.git", 2950 | "reference": "debedcfc373a293f9250cc9aa03cf121428c8e78" 2951 | }, 2952 | "dist": { 2953 | "type": "zip", 2954 | "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/debedcfc373a293f9250cc9aa03cf121428c8e78", 2955 | "reference": "debedcfc373a293f9250cc9aa03cf121428c8e78", 2956 | "shasum": "" 2957 | }, 2958 | "require": { 2959 | "php": "^5.6 || ^7.0" 2960 | }, 2961 | "require-dev": { 2962 | "athletic/athletic": "~0.1", 2963 | "phpunit/phpunit": "~4.0", 2964 | "squizlabs/php_codesniffer": "^2.6.2" 2965 | }, 2966 | "type": "library", 2967 | "extra": { 2968 | "branch-alias": { 2969 | "dev-master": "3.1-dev", 2970 | "dev-develop": "3.2-dev" 2971 | } 2972 | }, 2973 | "autoload": { 2974 | "psr-4": { 2975 | "Zend\\Stdlib\\": "src/" 2976 | } 2977 | }, 2978 | "notification-url": "https://packagist.org/downloads/", 2979 | "license": [ 2980 | "BSD-3-Clause" 2981 | ], 2982 | "homepage": "https://github.com/zendframework/zend-stdlib", 2983 | "keywords": [ 2984 | "stdlib", 2985 | "zf2" 2986 | ], 2987 | "time": "2016-09-13T14:38:50+00:00" 2988 | } 2989 | ], 2990 | "packages-dev": [], 2991 | "aliases": [], 2992 | "minimum-stability": "stable", 2993 | "stability-flags": { 2994 | "craftcms/cms": 5 2995 | }, 2996 | "prefer-stable": false, 2997 | "prefer-lowest": false, 2998 | "platform": [], 2999 | "platform-dev": [] 3000 | } 3001 | -------------------------------------------------------------------------------- /resources/img/plugin-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phoob/elasticraft/458fba9f8ec8bd53aff0664f911cf093f638decf/resources/img/plugin-logo.png -------------------------------------------------------------------------------- /src/Elasticraft.php: -------------------------------------------------------------------------------- 1 | controllerNamespace = 'dfo\elasticraft\console\controllers'; 93 | } 94 | 95 | // Add indicator for if user is logged in 96 | if (Craft::$app instanceof craft\web\Application) { 97 | $currentUser = Craft::$app->getUser()->getIdentity(); 98 | $cookie = new \yii\web\Cookie([ 99 | 'name' => 'craft_has_logged_in', 100 | 'value' => 'true', 101 | 'expire' => time() + 86400, 102 | 'httpOnly' => false, 103 | ]); 104 | if ($currentUser) { 105 | Craft::$app->getResponse()->getCookies()->add($cookie); 106 | } else { 107 | Craft::$app->getResponse()->getCookies()->remove($cookie); 108 | } 109 | } 110 | 111 | // Register our site routes 112 | Event::on( 113 | UrlManager::className(), 114 | UrlManager::EVENT_REGISTER_SITE_URL_RULES, 115 | function (RegisterUrlRulesEvent $event) { 116 | // Not needed now. 117 | // $event->rules['siteActionTrigger1'] = 'elasticraft/default'; 118 | } 119 | ); 120 | 121 | // Register our CP routes 122 | Event::on( 123 | UrlManager::className(), 124 | UrlManager::EVENT_REGISTER_CP_URL_RULES, 125 | function (RegisterUrlRulesEvent $event) { 126 | // Not needed now. 127 | // $event->rules['elastic/ping'] = 'elasticraft/default/ping'; 128 | } 129 | ); 130 | 131 | // Register our utilities 132 | Event::on( 133 | Utilities::className(), 134 | Utilities::EVENT_REGISTER_UTILITY_TYPES, 135 | function (RegisterComponentTypesEvent $event) { 136 | $event->types[] = ElasticraftUtilityUtility::class; 137 | } 138 | ); 139 | 140 | // Register our widgets 141 | Event::on( 142 | Dashboard::className(), 143 | Dashboard::EVENT_REGISTER_WIDGET_TYPES, 144 | function (RegisterComponentTypesEvent $event) { 145 | // Not in use now. 146 | // $event->types[] = ElasticraftWidgetWidget::class; 147 | } 148 | ); 149 | 150 | // Register index events 151 | Event::on( 152 | Elements::className(), 153 | Elements::EVENT_AFTER_SAVE_ELEMENT, 154 | function (ElementEvent $event) { 155 | // All matrix blocks in elements fires this event individually. 156 | // Let's not bother with those. 157 | if( !$event->element instanceof craft\elements\MatrixBlock ) { 158 | Elasticraft::$plugin->elasticraftService->processElement($event->element, 'index'); 159 | $this->_indexAncestorsAndDescendants( $event->element, 160 | 'Rendexing ancestors and descendants of saved element' 161 | ); 162 | } 163 | } 164 | ); 165 | 166 | Event::on( 167 | Elements::className(), 168 | Elements::EVENT_BEFORE_DELETE_ELEMENT, 169 | function (ElementEvent $event) { 170 | Elasticraft::$plugin->elasticraftService->processElement($event->element, 'delete'); 171 | $this->_indexAncestorsAndDescendants( $event->element, 172 | 'Reindexing ancestors and descendands of deleted element' 173 | ); 174 | } 175 | ); 176 | 177 | Event::on( 178 | Structures::className(), 179 | Structures::EVENT_BEFORE_MOVE_ELEMENT, 180 | function (MoveElementEvent $event) { 181 | $this->_indexAncestorsAndDescendants( $event->element, 182 | 'Reindexing previous ancestors and descendands of moved element' 183 | ); 184 | } 185 | ); 186 | 187 | Event::on( 188 | Elements::className(), 189 | Elements::EVENT_AFTER_UPDATE_SLUG_AND_URI, 190 | function (ElementEvent $event) { 191 | Elasticraft::$plugin->elasticraftService->processElement($event->element, 'index'); 192 | $this->_indexAncestorsAndDescendants( $event->element, 193 | 'Reindexing new ancestors and descendands of moved element' 194 | ); 195 | } 196 | ); 197 | 198 | Event::on( 199 | EntryRevisions::className(), 200 | EntryRevisions::EVENT_AFTER_SAVE_DRAFT, 201 | function (DraftEvent $event) { 202 | Elasticraft::$plugin->elasticraftService->processEntryDraft($event->draft, 'index'); 203 | } 204 | ); 205 | 206 | Event::on( 207 | EntryRevisions::className(), 208 | EntryRevisions::EVENT_BEFORE_DELETE_DRAFT, 209 | function (DraftEvent $event) { 210 | Elasticraft::$plugin->elasticraftService->processEntryDraft($event->draft, 'delete'); 211 | } 212 | ); 213 | 214 | Event::on( 215 | EntryRevisions::className(), 216 | EntryRevisions::EVENT_AFTER_PUBLISH_DRAFT, 217 | function (DraftEvent $event) { 218 | $entry = Entry::find()->id($event->draft->id)->one(); 219 | Elasticraft::$plugin->elasticraftService->processElement($entry, 'index'); 220 | $this->_indexAncestorsAndDescendants( $entry, 221 | 'Rendexing ancestors and descendants of published draft' 222 | ); 223 | } 224 | ); 225 | 226 | Event::on( 227 | EntryRevisions::className(), 228 | EntryRevisions::EVENT_AFTER_REVERT_ENTRY_TO_VERSION, 229 | function (VersionEvent $event) { 230 | $entry = Entry::find()->id($event->version->id)->one(); 231 | Elasticraft::$plugin->elasticraftService->processElement($entry, 'index'); 232 | $this->_indexAncestorsAndDescendants( $entry, 233 | 'Rendexing ancestors and descendants of restored entry' 234 | ); 235 | } 236 | ); 237 | 238 | // Do something after we're installed 239 | Event::on( 240 | Plugins::className(), 241 | Plugins::EVENT_AFTER_INSTALL_PLUGIN, 242 | function (PluginEvent $event) { 243 | if ($event->plugin === $this) { 244 | // We were just installed 245 | } 246 | } 247 | ); 248 | 249 | // Add widget to edit entries 250 | Craft::$app->getView()->hook('cp.entries.edit.details', function(&$context) { 251 | /** @var EntryModel $entry **/ 252 | $entry = $context['entry']; 253 | $doc = Elasticraft::$plugin->elasticraftService->getDocWithElement($entry); 254 | $params = [ 255 | 'ping' => Elasticraft::$plugin->elasticraftService->ping(), 256 | 'hasTransformer' => ElasticDocument::elementHasTransformer($entry), 257 | 'doc' => $doc, 258 | 'dateIndexed' => $doc ? $doc['_source']['date']['indexed'] : false, 259 | ]; 260 | return Craft::$app->view->renderTemplate( 261 | 'elasticraft/entriesWidget', 262 | $params 263 | ); 264 | }); 265 | 266 | /** 267 | * Logging in Craft involves using one of the following methods: 268 | * 269 | * Craft::trace(): record a message to trace how a piece of code runs. This is mainly for development use. 270 | * Craft::info(): record a message that conveys some useful information. 271 | * Craft::warning(): record a warning message that indicates something unexpected has happened. 272 | * Craft::error(): record a fatal error that should be investigated as soon as possible. 273 | * 274 | * Unless `devMode` is on, only Craft::warning() & Craft::error() will log to `craft/storage/logs/web.log` 275 | * 276 | * It's recommended that you pass in the magic constant `__METHOD__` as the second parameter, which sets 277 | * the category to the method (prefixed with the fully qualified class name) where the constant appears. 278 | * 279 | * To enable the Yii debug toolbar, go to your user account in the AdminCP and check the 280 | * [] Show the debug toolbar on the front end & [] Show the debug toolbar on the Control Panel 281 | * 282 | * http://www.yiiframework.com/doc-2.0/guide-runtime-logging.html 283 | */ 284 | Craft::info( 285 | Craft::t( 286 | 'elasticraft', 287 | '{name} plugin loaded', 288 | ['name' => $this->name] 289 | ), 290 | __METHOD__ 291 | ); 292 | } 293 | 294 | // Protected Methods 295 | // ========================================================================= 296 | 297 | /** 298 | * Creates and returns the model used to store the plugin’s settings. 299 | * 300 | * @return \craft\base\Model|null 301 | */ 302 | 303 | protected function createSettingsModel() 304 | { 305 | return new Settings(); 306 | } 307 | 308 | /** 309 | * Returns the rendered settings HTML, which will be inserted into the content 310 | * block on the settings page. 311 | * 312 | * @return string The rendered settings HTML 313 | */ 314 | protected function settingsHtml(): string 315 | { 316 | return Craft::$app->view->renderTemplate( 317 | 'elasticraft/settings', 318 | [ 319 | 'settings' => $this->getSettings() 320 | ] 321 | ); 322 | } 323 | 324 | protected function _indexAncestorsAndDescendants(Element $element, $description = null) 325 | { 326 | Craft::$app->queue->push(new ElasticJob([ 327 | 'elements' => array_merge( 328 | $element->getAncestors()->all(), 329 | $element->getDescendants()->all() 330 | ), 331 | 'description' => $description, 332 | ])); 333 | } 334 | 335 | } 336 | -------------------------------------------------------------------------------- /src/assetbundles/elasticraft/ElasticraftAsset.php: -------------------------------------------------------------------------------- 1 | sourcePath = "@dfo/elasticraft/assetbundles/elasticraft/dist"; 47 | 48 | // define the dependencies 49 | $this->depends = [ 50 | CpAsset::class, 51 | ]; 52 | 53 | // define the relative path to CSS/JS files that should be registered with the page 54 | // when this asset bundle is registered 55 | $this->js = [ 56 | 'js/Elasticraft.js', 57 | ]; 58 | 59 | $this->css = [ 60 | 'css/Elasticraft.css', 61 | ]; 62 | 63 | parent::init(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/assetbundles/elasticraft/dist/css/Elasticraft.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Elasticraft plugin for Craft CMS 3 | * 4 | * Elasticraft CSS 5 | * 6 | * @author Peter Holme Obrestad 7 | * @copyright Copyright (c) 2017 Peter Holme Obrestad 8 | * @link https://dfo.no 9 | * @package Elasticraft 10 | * @since 1.0.0 11 | */ 12 | -------------------------------------------------------------------------------- /src/assetbundles/elasticraft/dist/img/Elasticraft-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 14 | 17 | 20 | 21 | 22 | 23 | 24 | 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 | -------------------------------------------------------------------------------- /src/assetbundles/elasticraft/dist/js/Elasticraft.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Elasticraft plugin for Craft CMS 3 | * 4 | * Elasticraft JS 5 | * 6 | * @author Peter Holme Obrestad 7 | * @copyright Copyright (c) 2017 Peter Holme Obrestad 8 | * @link https://dfo.no 9 | * @package Elasticraft 10 | * @since 1.0.0 11 | */ 12 | -------------------------------------------------------------------------------- /src/assetbundles/elasticraftutilityutility/ElasticraftUtilityUtilityAsset.php: -------------------------------------------------------------------------------- 1 | sourcePath = "@dfo/elasticraft/assetbundles/elasticraftutilityutility/dist"; 47 | 48 | // define the dependencies 49 | $this->depends = [ 50 | CpAsset::class, 51 | ]; 52 | 53 | // define the relative path to CSS/JS files that should be registered with the page 54 | // when this asset bundle is registered 55 | $this->js = [ 56 | 'js/ElasticraftUtility.js', 57 | ]; 58 | 59 | $this->css = [ 60 | 'css/ElasticraftUtility.css', 61 | ]; 62 | 63 | parent::init(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/assetbundles/elasticraftutilityutility/dist/css/ElasticraftUtility.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Elasticraft plugin for Craft CMS 3 | * 4 | * ElasticraftUtility Utility CSS 5 | * 6 | * @author Peter Holme Obrestad 7 | * @copyright Copyright (c) 2017 Peter Holme Obrestad 8 | * @link https://dfo.no 9 | * @package Elasticraft 10 | * @since 1.0.0 11 | */ 12 | 13 | pre { 14 | border: 1px solid #ccc; 15 | padding: .5rem; 16 | } 17 | 18 | .string { color: green; } 19 | .number { color: darkorange; } 20 | .boolean { color: blue; } 21 | .null { color: magenta; } 22 | .key { color: crimson; } 23 | -------------------------------------------------------------------------------- /src/assetbundles/elasticraftutilityutility/dist/img/ElasticraftUtility-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/assetbundles/elasticraftutilityutility/dist/js/ElasticraftUtility.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Elasticraft plugin for Craft CMS 3 | * 4 | * ElasticraftUtility Utility JS 5 | * 6 | * @author Peter Holme Obrestad 7 | * @copyright Copyright (c) 2017 Peter Holme Obrestad 8 | * @link https://dfo.no 9 | * @package Elasticraft 10 | * @since 1.0.0 11 | */ 12 | 13 | var buttons = $("form.elasticraft input[type='button']"); 14 | var executing = false; 15 | 16 | $(document).ready(function(){ 17 | refreshContent(); 18 | this.$status = $('.utility-status', this.$form); 19 | }); 20 | 21 | function refreshContent() { 22 | Craft.postActionRequest('elasticraft/default/ping', function(connectionWorks) { 23 | if (connectionWorks) { 24 | $('#connectionNotWorking').addClass('hidden'); 25 | Craft.postActionRequest('elasticraft/default/index-exists', function(indexExists) { 26 | if (indexExists) { 27 | $('#indexDoesNotExist').addClass('hidden'); 28 | $('#indexUtilities').removeClass('hidden'); 29 | Craft.postActionRequest('elasticraft/default/get-document-count', function(documentCount) { 30 | $('#numDocsIndexed').html(documentCount['total']); 31 | var tableHtml = ''; 32 | for (var i = 0; i < documentCount['count_by_type'].length; i++) { 33 | tableHtml += '' + documentCount['count_by_type'][i]['key'] + '' + documentCount['count_by_type'][i]['doc_count'] + ''; 34 | } 35 | tableHtml += 'Total' + documentCount['total'] + ''; 36 | $('#documentCountByType tbody').html(tableHtml); 37 | }); 38 | } else { 39 | $('#indexUtilities').addClass('hidden'); 40 | $('#indexDoesNotExist').removeClass('hidden'); 41 | } 42 | }); 43 | } else { 44 | $('#connectionNotWorking').removeClass('hidden'); 45 | } 46 | }); 47 | } 48 | 49 | buttons.on("click", function(ev) { 50 | ev.preventDefault(); 51 | 52 | if (executing) { 53 | return; 54 | } 55 | executing = true; 56 | 57 | var $this = $(this); 58 | var action = $this.attr('name'); 59 | // var spinner = $('#spinner'); 60 | // var results = $('#elasticraft-result'); 61 | 62 | $this.addClass('active'); 63 | // results.html('
'); 64 | 65 | Craft.postActionRequest(action, function(response) { 66 | $this.removeClass('active'); 67 | // spinner.addClass('hidden'); 68 | executing = false; 69 | // results.html(syntaxHighlight(JSON.stringify(response, null, 4)) ); 70 | Craft.cp.runQueue(); 71 | refreshContent(); 72 | }); 73 | 74 | }); 75 | 76 | function syntaxHighlight(json) { 77 | json = json.replace(/&/g, '&').replace(//g, '>'); 78 | return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) { 79 | var cls = 'number'; 80 | if (/^"/.test(match)) { 81 | if (/:$/.test(match)) { 82 | cls = 'key'; 83 | } else { 84 | cls = 'string'; 85 | } 86 | } else if (/true|false/.test(match)) { 87 | cls = 'boolean'; 88 | } else if (/null/.test(match)) { 89 | cls = 'null'; 90 | } 91 | return '' + match + ''; 92 | }); 93 | } 94 | 95 | 96 | -------------------------------------------------------------------------------- /src/assetbundles/elasticraftwidgetwidget/ElasticraftWidgetWidgetAsset.php: -------------------------------------------------------------------------------- 1 | sourcePath = "@dfo/elasticraft/assetbundles/elasticraftwidgetwidget/dist"; 47 | 48 | // define the dependencies 49 | $this->depends = [ 50 | CpAsset::class, 51 | ]; 52 | 53 | // define the relative path to CSS/JS files that should be registered with the page 54 | // when this asset bundle is registered 55 | $this->js = [ 56 | 'js/ElasticraftWidget.js', 57 | ]; 58 | 59 | $this->css = [ 60 | 'css/ElasticraftWidget.css', 61 | ]; 62 | 63 | parent::init(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/assetbundles/elasticraftwidgetwidget/dist/css/ElasticraftWidget.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Elasticraft plugin for Craft CMS 3 | * 4 | * ElasticraftWidget Widget CSS 5 | * 6 | * @author Peter Holme Obrestad 7 | * @copyright Copyright (c) 2017 Peter Holme Obrestad 8 | * @link https://dfo.no 9 | * @package Elasticraft 10 | * @since 1.0.0 11 | */ 12 | -------------------------------------------------------------------------------- /src/assetbundles/elasticraftwidgetwidget/dist/img/ElasticraftWidget-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 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 | -------------------------------------------------------------------------------- /src/assetbundles/elasticraftwidgetwidget/dist/js/ElasticraftWidget.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Elasticraft plugin for Craft CMS 3 | * 4 | * ElasticraftWidget Widget JS 5 | * 6 | * @author Peter Holme Obrestad 7 | * @copyright Copyright (c) 2017 Peter Holme Obrestad 8 | * @link https://dfo.no 9 | * @package Elasticraft 10 | * @since 1.0.0 11 | */ 12 | -------------------------------------------------------------------------------- /src/config.php: -------------------------------------------------------------------------------- 1 | getenv('ELASTIC_HOSTS') ?: 'http://localhost:9200', 31 | 32 | // The name of the Elasticsearch index to be used 33 | 'indexName' => getenv('ELASTIC_INDEX_NAME') ?: 'craft', 34 | 35 | // IndexOptions to pass to Elasticsearch when creating index 36 | 'indexOptions' => [ 37 | 'mappings' => [ 38 | '_default_' => [ 39 | 'properties' => [ 40 | 'date' => [ 41 | 'properties' => [ 42 | 'indexed' => [ 43 | 'type' => 'date', 44 | 'format' => 'epoch_second' 45 | ], 46 | 'created' => [ 47 | 'type' => 'date', 48 | 'format' => 'epoch_second' 49 | ], 50 | 'updated' => [ 51 | 'type' => 'date', 52 | 'format' => 'epoch_second' 53 | ], 54 | ], 55 | ], 56 | ], 57 | ], 58 | ], 59 | ], 60 | 61 | // Mapping of which page transformers should be used for which element types 62 | 'transformers' => [ 63 | // 'page' => new PageTransformer(), 64 | ], 65 | ]; 66 | -------------------------------------------------------------------------------- /src/console/controllers/IndexController.php: -------------------------------------------------------------------------------- 1 | elasticraftService; 57 | 58 | // Create index if it does not exist yet 59 | if( !$service->indexExists() ) 60 | $service->createIndex(); 61 | 62 | $elements = array_merge( 63 | Entry::find()->all(), 64 | GlobalSet::find()->all(), 65 | $service->getCraftDrafts() 66 | ); 67 | $this->stdout(sprintf("Indexing %d entries, globalsets and drafts\n", count($elements)), Console::BOLD); 68 | 69 | // Save time in case we need it after processing 70 | $now = microtime(true); 71 | $slow = []; 72 | Console::startProgress(0,count($elements)); 73 | foreach ($elements as $index => $element) { 74 | $n = microtime(true); 75 | if (is_a($element, 'craft\models\EntryDraft')) { 76 | $service->processEntryDraft( $element ); 77 | } elseif (is_a($element, 'craft\base\Element')) { 78 | $service->processElement( $element ); 79 | } 80 | $d = (microtime(true) - $n); 81 | if ($d > 0.5) $slow[] = [ 82 | 'time' => $d, 83 | 'title' => $element->title, 84 | ]; 85 | Console::updateProgress($index + 1, count($elements)); 86 | } 87 | Console::endProgress(); 88 | 89 | $this->stdout("Done in " . round((microtime(true) - $now),3) . " seconds.\n"); 90 | if ($slow) { 91 | $this->stdout("These elements indexed slowly:\n"); 92 | foreach ($slow as $e) { 93 | $this->stdout(round($e['time'],3) . "\t" . $e['title'] . "\n"); 94 | } 95 | } 96 | } 97 | 98 | /** 99 | * Delete and recreate Elasticsearch index 100 | * 101 | * @return mixed 102 | */ 103 | public function actionRecreate() 104 | { 105 | // Delete old index 106 | Elasticraft::$plugin->elasticraftService->deleteIndex(); 107 | $this->actionIndex(); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/controllers/DefaultController.php: -------------------------------------------------------------------------------- 1 | asJson($result); 72 | } 73 | 74 | /** 75 | * Handle requests going to: 76 | * actions/elasticraft/default/ping 77 | * actions/elasticraft/default/create-index 78 | * etc. 79 | * 80 | * @return mixed 81 | */ 82 | public function actionPing() 83 | { 84 | $result = Elasticraft::$plugin->elasticraftService->ping(); 85 | return $this->asJson($result); 86 | } 87 | 88 | public function actionIndexExists() 89 | { 90 | $result = Elasticraft::$plugin->elasticraftService->indexExists(); 91 | return $this->asJson($result); 92 | } 93 | 94 | public function actionReindex() 95 | { 96 | Craft::$app->queue->push(new ElasticJob([ 97 | 'elements' => [ 98 | Entry::find(), 99 | GlobalSet::find(), 100 | Elasticraft::$plugin->elasticraftService->getCraftDrafts(), 101 | ], 102 | 'deleteStale' => true, 103 | 'description' => 'Reindexing all entries and globals and deleting stale', 104 | ])); 105 | return $this->asJson(true); 106 | } 107 | 108 | public function actionRecreateIndex() 109 | { 110 | Elasticraft::$plugin->elasticraftService->deleteIndex(); 111 | Craft::$app->queue->push(new ElasticJob([ 112 | 'elements' => [ 113 | Entry::find(), 114 | GlobalSet::find(), 115 | Elasticraft::$plugin->elasticraftService->getCraftDrafts() 116 | ], 117 | 'description' => 'Indexing all entries and globals', 118 | ])); 119 | return $this->asJson(true); 120 | } 121 | 122 | public function actionGetDocumentCount() 123 | { 124 | $response = Elasticraft::$plugin->elasticraftService->getDocumentCount(); 125 | return $this->asJson([ 126 | 'total' => $response['hits']['total'], 127 | 'count_by_type' => $response['aggregations']['count_by_type']['buckets'], 128 | ]); 129 | } 130 | 131 | public function actionReleaseStaleJobs() 132 | { 133 | $response = Craft::$app->queue->getJobInfo(); 134 | $jobs = [ 135 | 'kept' => [], 136 | 'released' => [] 137 | ]; 138 | foreach ($response as $job) { 139 | if ($job['status'] > 1) { 140 | Craft::$app->queue->release($job['id']); 141 | $jobs['released'][] = $job; 142 | } else { 143 | $jobs['kept'][] = $job; 144 | } 145 | } 146 | return $this->asJson($jobs); 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /src/icon-mask.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 14 | 17 | 20 | 21 | 22 | 23 | 24 | 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 | -------------------------------------------------------------------------------- /src/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 14 | 17 | 20 | 21 | 22 | 23 | 24 | 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 | -------------------------------------------------------------------------------- /src/jobs/ElasticJob.php: -------------------------------------------------------------------------------- 1 | elasticraftService; 43 | 44 | // Create index if it does not exist yet 45 | if( !$service->indexExists() ) 46 | $service->createIndex(); 47 | 48 | // Harmonize elements array 49 | $elements = []; 50 | foreach ($this->elements as $v) { 51 | if( $v instanceof craft\base\Element ) { 52 | $elements[] = $v; 53 | } else if ( $v instanceof craft\elements\db\ElementQueryInterface ) { 54 | $elements = array_merge( $elements, $v->all() ); 55 | } else if ( is_array( $v ) ) { // Drafts array 56 | $elements = array_merge( $elements, $v ); 57 | } 58 | } 59 | 60 | // Save time in case we need it after processing 61 | $now = time(); 62 | 63 | // Process elements and set progress 64 | $elementCount = count($elements); 65 | for( $i=0; $i < $elementCount; $i++ ) { 66 | // Set progress counter 67 | $this->setProgress($queue, $i / $elementCount); 68 | // Process element 69 | if (is_a($elements[$i], 'craft\models\EntryDraft')) { 70 | $service->processEntryDraft( $elements[$i], $this->action ); 71 | } else if (is_a($elements[$i], 'craft\base\Element')) { 72 | $service->processElement( $elements[$i], $this->action ); 73 | } 74 | } 75 | 76 | // Delete documents in index that weren't indexed in this job 77 | if( $this->deleteStale ) 78 | $service->deleteDocumentsOlderThan($now); 79 | } 80 | 81 | // Protected Methods 82 | // ========================================================================= 83 | 84 | /** 85 | * Returns a default description for [[getDescription()]], if [[description]] isn’t set. 86 | * 87 | * @return string The default task description 88 | */ 89 | protected function defaultDescription(): string 90 | { 91 | return Craft::t('elasticraft', 'Indexing to Elasticsearch'); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/models/ElasticDocument.php: -------------------------------------------------------------------------------- 1 | transformers = Elasticraft::$plugin 61 | ->getInstance() 62 | ->getSettings() 63 | ->transformers; 64 | } 65 | 66 | public static function withElement( Element $element ) 67 | { 68 | $instance = new self(); 69 | if ( $instance->_loadByElement( $element ) ) { 70 | return $instance; 71 | } 72 | return false; 73 | } 74 | 75 | public static function withVersion( craft\models\EntryVersion $element ) 76 | { 77 | $instance = new self(); 78 | if ( $instance->_loadByElement( $element ) ) { 79 | return $instance; 80 | } 81 | return false; 82 | } 83 | 84 | public static function withEntryDraft( craft\models\EntryDraft $element ) 85 | { 86 | $instance = new self(); 87 | if ( $instance->_loadByElement( $element ) ) { 88 | $instance->id = $element->draftId; 89 | $instance->type = self::DRAFT_DOCUMENT_TYPE; 90 | return $instance; 91 | } 92 | return false; 93 | } 94 | 95 | // Helper methods 96 | // ========================================================================= 97 | 98 | public static function elementHasTransformer( Element $element): bool 99 | { 100 | $instance = new self(); 101 | $transformer = $instance->_getTransformerForElement( $element ); 102 | if( isset( $instance->transformers[$transformer] ) ) 103 | return true; 104 | return false; 105 | } 106 | 107 | /** 108 | * Returns the validation rules for attributes. 109 | * 110 | * Validation rules are used by [[validate()]] to check if attribute values are valid. 111 | * Child classes may override this method to declare different validation rules. 112 | * 113 | * More info: http://www.yiiframework.com/doc-2.0/guide-input-validation.html 114 | * 115 | * @return array 116 | */ 117 | public function rules() 118 | { 119 | return [ 120 | [['id', 'type'], 'string'], 121 | [['id', 'type'], 'required'], 122 | ]; 123 | } 124 | 125 | // Private Methods 126 | // ========================================================================= 127 | 128 | private function _loadByElement( Element $element ) 129 | { 130 | $this->type = self::ELEMENT_DOCUMENT_TYPE; 131 | $this->id = $element->id; 132 | $transformer = $this->_getTransformerForElement( $element ); 133 | 134 | // if there is no defined transformer for this element, stop now. 135 | if ( !isset( $this->transformers[$transformer] ) ) { 136 | return false; 137 | } 138 | 139 | // We have a body transformer. 140 | $this->body = $this->transformers[$transformer]->transform($element); 141 | 142 | // set body['type'] if it is not already defined in transformer 143 | if( !isset($this->body['type']) ) 144 | $this->body['type'] = $transformer; 145 | 146 | // set common body dates. date.indexed is needed for pruning stale documents. 147 | $this->body['date']['indexed'] = time(); 148 | $this->body['date']['created'] = isset($element->dateCreated) ? (int)$element->dateCreated->format('U') : null; 149 | $this->body['date']['updated'] = isset($element->dateUpdated) ? (int)$element->dateUpdated->format('U') : null; 150 | $this->body['date']['publish'] = isset($element->postDate) ? (int)$element->postDate->format('U') : null; 151 | $this->body['date']['expire'] = isset($element->expiryDate) ? (int)$element->expiryDate->format('U') : null; 152 | 153 | return true; 154 | } 155 | 156 | private function _getTransformerForElement( Element $element ): string 157 | { 158 | switch (get_class($element)) { 159 | case 'craft\elements\Entry': 160 | case 'craft\models\EntryDraft': 161 | case 'craft\models\EntryVersion': 162 | return $element->section->handle; 163 | case 'craft\elements\GlobalSet': 164 | return self::GLOBALSET_PREFIX . $element->handle; 165 | default: 166 | return get_class($element); 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/models/Settings.php: -------------------------------------------------------------------------------- 1 | client = $this->_getClient(); 47 | $this->indexName = $this->_getIndexName(); 48 | $this->indexOptions = $this->_getIndexOptions(); 49 | } 50 | 51 | // Public Methods 52 | // ========================================================================= 53 | // From any other plugin file, call them like this: 54 | // Elasticraft::$plugin->elasticraftService->method() 55 | 56 | /** 57 | * Tries to contact Elasticsearch server. 58 | * 59 | * @return bool 60 | */ 61 | public function ping(): bool 62 | { 63 | $params = [ ]; 64 | try { 65 | $response = $this->client->ping($params); 66 | } catch (\Exception $e) { 67 | throw $e; 68 | } 69 | return $response; 70 | } 71 | 72 | /** 73 | * Checks if the index exists on the Elasticsearch server. 74 | * 75 | * @return bool 76 | */ 77 | public function indexExists(): bool 78 | { 79 | $params = [ 'index' => $this->indexName ]; 80 | try { 81 | $response = $this->client->indices()->exists($params); 82 | } catch (\Exception $e) { 83 | throw $e; 84 | } 85 | return $response; 86 | } 87 | 88 | /** 89 | * Creates a new index on the Elasticsearch server with a simple mapping. 90 | * 91 | * @return array 92 | */ 93 | public function createIndex(): array 94 | { 95 | $params = [ 96 | 'index' => $this->indexName, 97 | 'body' => $this->indexOptions, 98 | ]; 99 | try { 100 | $response = $this->client->indices()->create($params); 101 | } catch (\Exception $e) { 102 | throw $e; 103 | } 104 | return $response; 105 | } 106 | 107 | /** 108 | * Get basic info about the index. 109 | * 110 | * @return array 111 | */ 112 | public function getIndex(): array 113 | { 114 | $params = ['index' => $this->indexName]; 115 | try { 116 | $response = $this->client->indices()->get($params); 117 | } catch (\Exception $e) { 118 | if ($e instanceof \Elasticsearch\Common\Exceptions\Missing404Exception) 119 | return []; 120 | throw $e; 121 | } 122 | return $response; 123 | } 124 | 125 | /** 126 | * Delete index. 127 | * 128 | * @return bool 129 | */ 130 | public function deleteIndex(): bool 131 | { 132 | $params = ['index' => $this->indexName]; 133 | try { 134 | $response = $this->client->indices()->delete($params); 135 | } catch (\Exception $e) { 136 | if ($e instanceof \Elasticsearch\Common\Exceptions\Missing404Exception) 137 | return false; 138 | throw $e; 139 | } 140 | return true; 141 | } 142 | 143 | /** 144 | * Get number of documents aggregated by document type 145 | * 146 | * @return array 147 | */ 148 | public function getDocumentCount(): array 149 | { 150 | $params = [ 151 | 'index' => $this->indexName, 152 | 'body' => [ 153 | 'size' => 0, 154 | 'aggregations' => [ 155 | 'count_by_type' => [ 156 | 'terms' => [ 157 | 'field' => 'type.keyword' 158 | ] 159 | ] 160 | ] 161 | ] 162 | ]; 163 | try { 164 | $response = $this->client->indices()->refresh(['index' => $this->indexName ]); 165 | $response = $this->client->search($params); 166 | } catch (\Exception $e) { 167 | if ($e instanceof \Elasticsearch\Common\Exceptions\Missing404Exception) 168 | return []; 169 | throw $e; 170 | } 171 | return $response; 172 | } 173 | 174 | /** 175 | * Gets a doc from Elasticsearch based on an entry 176 | * 177 | * @param Entry $entry 178 | * 179 | * @return array 180 | */ 181 | public function getDocWithElement(Element $element): array 182 | { 183 | // Bail if $element is not saved yet 184 | if( !$element->id ) return []; 185 | 186 | $params = [ 187 | 'index' => $this->indexName, 188 | 'type' => ElasticDocument::ELEMENT_DOCUMENT_TYPE, 189 | 'id' => $element->id 190 | ]; 191 | 192 | try { 193 | $response = $this->client->get($params); 194 | } catch (\Exception $e) { 195 | if ($e instanceof \Elasticsearch\Common\Exceptions\Missing404Exception) 196 | return []; 197 | throw $e; 198 | } 199 | return $response; 200 | } 201 | 202 | /** 203 | * Process many documents with the same action. 204 | * 205 | * @param array $docs Array of ElasticDocuments 206 | * @param string $action Name of action 207 | * 208 | * @return array 209 | */ 210 | public function processDocuments(array $docs, string $action='index'): array 211 | { 212 | $params = $this->_createBulkParams(); 213 | $responses = []; 214 | 215 | // send in batches of 1000 docs 216 | foreach ($docs as $i => $doc) { 217 | $params = $this->addDocToBulkParams($params, $doc, $action); 218 | if ($i % 1000 == 0) { 219 | $responses[] = $this->_bulkProcess($params); 220 | $params['body'] = []; 221 | } 222 | } 223 | 224 | // send the rest 225 | if (!empty($params['body'])) { 226 | $responses[] = $this->_bulkProcess($params); 227 | } 228 | 229 | return $responses; 230 | } 231 | 232 | /** 233 | * Process one document. 234 | * 235 | * @param ElasticDocument $doc Document to process 236 | * @param string $action Name of action ('index' or 'delete') 237 | * 238 | * @return array 239 | */ 240 | public function processDocument(ElasticDocument $doc, string $action = 'index'): array 241 | { 242 | $params = [ 243 | 'index' => $this->indexName, 244 | 'type' => $doc->type, 245 | 'id' => $doc->id, 246 | ]; 247 | try { 248 | switch ($action) { 249 | case 'index': 250 | $params['body'] = $doc->body; 251 | $response = $this->client->index($params); 252 | break; 253 | case 'delete': 254 | $response = $this->client->delete($params); 255 | break; 256 | default: 257 | throw new \Exception("Action must be either 'index' or 'delete'.", 1); 258 | break; 259 | } 260 | } catch (\Exception $e) { 261 | if ($e instanceof \Elasticsearch\Common\Exceptions\Missing404Exception) 262 | return []; 263 | throw $e; 264 | } 265 | return $response; 266 | } 267 | 268 | /** 269 | * Process one element. 270 | * 271 | * @param Element $doc Document to process 272 | * @param string $action Name of action 273 | * 274 | * @return array 275 | */ 276 | public function processElement(craft\base\Element $element, string $action = 'index'): array 277 | { 278 | if ( $doc = ElasticDocument::withElement( $element ) ) { 279 | return $this->processDocument($doc, $action); 280 | } 281 | return []; 282 | } 283 | 284 | /** 285 | * Process one draft. 286 | * 287 | * @param EntryDraft $doc Document to process 288 | * @param string $action Name of action 289 | * 290 | * @return array 291 | */ 292 | public function processEntryDraft(craft\models\EntryDraft $draft, string $action = 'index'): array 293 | { 294 | if ( $doc = ElasticDocument::withEntryDraft( $draft ) ) { 295 | return $this->processDocument($doc, $action); 296 | } 297 | return []; 298 | } 299 | 300 | /** 301 | * Process one version. 302 | * 303 | * @param EntryVersion $doc Document to process 304 | * @param string $action Name of action 305 | * 306 | * @return array 307 | */ 308 | public function processVersion(craft\models\EntryVersion $version, string $action = 'index'): array 309 | { 310 | // if ( $doc = ElasticDocument::withElement( Entry::find()->id($version->id)->one() ) ) { 311 | if ( $doc = ElasticDocument::withVersion( $version ) ) { 312 | return $this->processDocument($doc, $action); 313 | } 314 | return []; 315 | } 316 | 317 | /** 318 | * Deletes all elements older than $now (unix epoch seconds) 319 | * 320 | * @param int $now epoch seconds 321 | * 322 | * @return bool 323 | */ 324 | public function deleteDocumentsOlderThan(int $now): bool 325 | { 326 | $params = [ 327 | 'index' => $this->indexName, 328 | 'body' => [ 329 | 'query' => [ 330 | 'range' => [ 331 | 'date.indexed' => [ 332 | 'lt' => $now, 333 | ], 334 | ], 335 | ], 336 | ], 337 | ]; 338 | try { 339 | $response = $this->client->indices()->refresh(['index' => $this->indexName ]); 340 | $response = $this->client->deleteByQuery( $params ); 341 | } catch (\Exception $e) { 342 | throw $e; 343 | } 344 | return true; 345 | } 346 | 347 | public function getCraftDrafts($siteId = null): array 348 | { 349 | // Access private method _getDraftsQuery 350 | $EntryRevisions = new craft\services\EntryRevisions(); 351 | $reflector = new \ReflectionObject($EntryRevisions); 352 | $_getDraftsQuery = $reflector->getMethod('_getDraftsQuery'); 353 | $_getDraftsQuery->setAccessible(true); 354 | $draftsQuery = $_getDraftsQuery->invoke($EntryRevisions); 355 | 356 | $drafts = array_map(function($row){ 357 | return Craft::$app->entryRevisions->getDraftById($row['id']); 358 | }, $draftsQuery->all() ); 359 | 360 | return $drafts; 361 | } 362 | 363 | // Private methods 364 | // ========================================================================= 365 | 366 | private function _getClient(): \Elasticsearch\Client 367 | { 368 | try { 369 | $client = ClientBuilder::create() 370 | ->setHosts( $this->_getElasticHosts() ) 371 | ->build(); 372 | } catch (\Exception $e) { 373 | throw $e; 374 | } 375 | return $client; 376 | } 377 | 378 | private function _getElasticHosts(): array 379 | { 380 | if( is_string( Elasticraft::$plugin->getSettings()->hosts ) ) { 381 | return explode( ',', Elasticraft::$plugin->getSettings()->hosts ); 382 | } else { 383 | throw new \Exception("Elastic hosts must be a string.", 1); 384 | } 385 | } 386 | 387 | private function _getIndexName(): string 388 | { 389 | if( is_string( Elasticraft::$plugin->getSettings()->indexName ) ) { 390 | return Elasticraft::$plugin->getSettings()->indexName; 391 | } else { 392 | throw new \Exception("Elastic indexName must be a string.", 1); 393 | } 394 | } 395 | 396 | private function _getIndexOptions(): array 397 | { 398 | return Elasticraft::$plugin->getSettings()->indexOptions ?: []; 399 | } 400 | 401 | /** 402 | * Create array with params for a bulk request. 403 | * 404 | * @return array 405 | */ 406 | private function _createBulkParams(): array 407 | { 408 | $params = [ 409 | 'index' => $this->indexName, 410 | 'body' => [] 411 | ]; 412 | return $params; 413 | } 414 | 415 | /** 416 | * Add document to process to a params array. 417 | * 418 | * @param array $params Array created using createBulkParams() 419 | * @param ElasticDocument $doc Document to add 420 | * @param string $action Name of action 421 | * 422 | * @return array 423 | */ 424 | private function _addDocToBulkParams(array $params, ElasticDocument $doc, string $action = 'index'): array 425 | { 426 | $params['body'][] = [ 427 | $action => [ 428 | '_type' => $doc->type, 429 | '_id' => $doc->id, 430 | ] 431 | ]; 432 | if($action == 'index') { 433 | $params['body'][] = $doc->body; 434 | } 435 | return $params; 436 | } 437 | 438 | /** 439 | * Perform a bulk request to the Elasticsearch server. 440 | * 441 | * @param array $params Parameters for the bulk request 442 | * 443 | * @return array 444 | */ 445 | private function _bulkProcess(array $params): array 446 | { 447 | if( !$this->indexExists() ) 448 | $this->createIndex(); 449 | try { 450 | $response = $this->client->bulk($params); 451 | } catch (\Exception $e) { 452 | throw $e; 453 | } 454 | return $response; 455 | } 456 | 457 | 458 | } 459 | -------------------------------------------------------------------------------- /src/templates/_components/utilities/ElasticraftUtility_content.twig: -------------------------------------------------------------------------------- 1 | {# 2 | /** 3 | * Elasticraft plugin for Craft CMS 4 | * 5 | * ElasticraftUtility Utility Content 6 | * 7 | * @author Peter Holme Obrestad 8 | * @copyright Copyright (c) 2017 Peter Holme Obrestad 9 | * @link https://dfo.no 10 | * @package Elasticraft 11 | * @since 1.0.0 12 | */ 13 | #} 14 | 15 | {% import "_includes/forms" as forms %} 16 | 17 |
18 | {{ csrfInput() }} 19 | 24 | 32 | 48 |
-------------------------------------------------------------------------------- /src/templates/_components/widgets/ElasticraftWidget_body.twig: -------------------------------------------------------------------------------- 1 | {# 2 | /** 3 | * Elasticraft plugin for Craft CMS 4 | * 5 | * ElasticraftWidget Widget Body 6 | * 7 | * @author Peter Holme Obrestad 8 | * @copyright Copyright (c) 2017 Peter Holme Obrestad 9 | * @link https://dfo.no 10 | * @package Elasticraft 11 | * @since 1.0.0 12 | */ 13 | #} 14 | 15 | {% set iconUrl = view.getAssetManager().getPublishedUrl('@dfo/elasticraft/assetbundles/elasticraftwidgetwidget/dist', true) ~ '/img/ElasticraftWidget-icon.svg' %} 16 | 17 | 18 | 19 |

{{ message }}

20 | -------------------------------------------------------------------------------- /src/templates/_components/widgets/ElasticraftWidget_settings.twig: -------------------------------------------------------------------------------- 1 | {# 2 | /** 3 | * Elasticraft plugin for Craft CMS 4 | * 5 | * ElasticraftWidget Widget Settings 6 | * 7 | * @author Peter Holme Obrestad 8 | * @copyright Copyright (c) 2017 Peter Holme Obrestad 9 | * @link https://dfo.no 10 | * @package Elasticraft 11 | * @since 1.0.0 12 | */ 13 | #} 14 | 15 | {% import "_includes/forms" as forms %} 16 | 17 | {% do view.registerAssetBundle("dfo\\elasticraft\\assetbundles\\elasticraft\\ElasticraftAsset") %} 18 | 19 | {{ forms.textField({ 20 | label: 'Message', 21 | instructions: 'Enter a message here.', 22 | id: 'message', 23 | name: 'message', 24 | value: widget['message']}) 25 | }} 26 | -------------------------------------------------------------------------------- /src/templates/entriesWidget.twig: -------------------------------------------------------------------------------- 1 |
2 |
3 |

{{ "Elasticsearch" | t('elasticraft') }}

4 |
5 |
6 | {% if not ping %} 7 |

{{ "Could not contact Elasticsearch. Check your config" | t('elasticraft') }}

8 | {% elseif not hasTransformer %} 9 |

{{ "This entry type is not set up to be indexed to Elasticsearch." | t('elasticraft') }}

10 | {% elseif not doc %} 11 |

{{ "Entry not indexed yet. Save entry to index it." | t('elasticraft') }}

12 | {% elseif not dateIndexed %} 13 |

{{ "Indexed date not found. Check your config." | t('elasticraft') }}

14 | {% else %} 15 |
{{ "Last indexed" | t('elasticraft') }}
16 |
{{ dateIndexed | datetime('short') }}
17 | {% endif %} 18 |
19 |
20 | -------------------------------------------------------------------------------- /src/templates/settings.twig: -------------------------------------------------------------------------------- 1 | {# 2 | /** 3 | * Elasticraft plugin for Craft CMS 3.x 4 | * 5 | * Elasticraft Settings.twig 6 | * 7 | * @author Peter Holme Obrestad 8 | * @copyright Copyright (c) 2017 Peter Holme Obrestad 9 | * @link https://dfo.no 10 | * @package Elasticraft 11 | * @since 1.0.0 12 | */ 13 | #} 14 | 15 | {% import "_includes/forms" as forms %} 16 | 17 | {% do view.registerAssetBundle("dfo\\elasticraft\\assetbundles\\elasticraft\\ElasticraftAsset") %} 18 | 19 |

Connection settings

20 | 21 | {{ forms.textField({ 22 | label: 'Elastic host', 23 | instructions: 'Enter Elasticsearch hosts here. Comma separated. Must be fully qualified urls.', 24 | id: 'hosts', 25 | name: 'hosts', 26 | value: settings['hosts']}) 27 | }} 28 | 29 | {{ forms.textField({ 30 | label: 'Elastic index name', 31 | instructions: 'Enter Elasticsearch index name here', 32 | id: 'indexName', 33 | name: 'indexName', 34 | value: settings['indexName']}) 35 | }} 36 | 37 | {# Apparently settings not shown here must be emptied out #} 38 | {{ forms.hidden({ 39 | id: 'transformers', 40 | name: 'transformers', 41 | value: null}) 42 | }} 43 | {{ forms.hidden({ 44 | id: 'indexOptions', 45 | name: 'indexOptions', 46 | value: null}) 47 | }} 48 | 49 |

Other settings

50 | 51 |

You should also specify indexOptions and transformers. Copy config.php from the plugin directory to elasticraft.php in the Craft main config directory and fill out as necessary.

52 | -------------------------------------------------------------------------------- /src/transformers/BaseTransformer.php: -------------------------------------------------------------------------------- 1 | getParsedContent()); 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/transformers/ExampleEntryTransformer.php: -------------------------------------------------------------------------------- 1 | versionId = $versionId; 14 | $this->draftId = $draftId; 15 | } 16 | 17 | public function transform(Entry $entry) { 18 | if ($this->draftId) { 19 | // Fetch by draft id 20 | $entry = Craft::$app->getEntryRevisions()->getDraftById($this->draftId); 21 | if (!$entry) { return []; } 22 | } 23 | 24 | // Build the page response 25 | return [ 26 | 'id' => $entry->id, 27 | 'active' => $entry->enabled, 28 | 29 | 'updateNote' => $entry->updateNote, 30 | 31 | 'slug' => $entry->slug, 32 | 'uri' => $entry->uri, 33 | 'type' => $entry->type->handle, 34 | 35 | 'title' => $entry->title, 36 | 37 | 'body' => $this->getBody($entry), 38 | 'bodyText' => $this->getBodyText($entry), 39 | ]; 40 | } 41 | 42 | protected function getBody(Entry $entry) 43 | { 44 | // Build the html body of the document 45 | return '

Hello world.

'; 46 | } 47 | 48 | protected function getBodyText(Entry $entry) 49 | { 50 | // Build raw text body of the document for search 51 | return 'Hello world.'; 52 | } 53 | } -------------------------------------------------------------------------------- /src/translations/en/elasticraft.php: -------------------------------------------------------------------------------- 1 | 'Elasticraft-utvidelsen er innlastet', 25 | 'Last indexed' => 'Last indexed', 26 | 'Indexed date not found. Check your config.' => 'Indexed date not found. Check your config.', 27 | 'Save entry to index it.' => 'Save entry to index it.', 28 | ]; 29 | -------------------------------------------------------------------------------- /src/translations/nb/elasticraft.php: -------------------------------------------------------------------------------- 1 | 'Elasticraft-utvidelsen er innlastet', 25 | 'Last indexed' => 'Sist indeksert', 26 | 'Indexed date not found. Check your config.' => 'Fant ikke indekseringsdato. Sjekk config.', 27 | 'Save entry to index it.' => 'Lagre innlegg for å indeksere det.', 28 | ]; 29 | -------------------------------------------------------------------------------- /src/utilities/ElasticraftUtility.php: -------------------------------------------------------------------------------- 1 | elasticraftService->ping() === false 77 | ||Elasticraft::$plugin->elasticraftService->indexExists() === false 78 | ) return 1; 79 | return 0; 80 | } 81 | 82 | /** 83 | * Returns the utility's content HTML. 84 | * 85 | * @return string 86 | */ 87 | public static function contentHtml(): string 88 | { 89 | Craft::$app->getView()->registerAssetBundle(ElasticraftUtilityUtilityAsset::class); 90 | 91 | return Craft::$app->getView()->renderTemplate( 92 | 'elasticraft/_components/utilities/ElasticraftUtility_content', 93 | [ 94 | 'indexName' => Elasticraft::$plugin->elasticraftService->indexName, 95 | ] 96 | ); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/widgets/ElasticraftWidget.php: -------------------------------------------------------------------------------- 1 | 'Hello, world.'], 96 | ] 97 | ); 98 | return $rules; 99 | } 100 | 101 | /** 102 | * Returns the component’s settings HTML. 103 | * 104 | * An extremely simple implementation would be to directly return some HTML: 105 | * 106 | * ```php 107 | * return ''; 108 | * ``` 109 | * 110 | * For more complex settings, you might prefer to create a template, and render it via 111 | * [[\craft\web\View::renderTemplate()]]. For example, the following code would render a template loacated at 112 | * craft/plugins/myplugin/templates/_settings.html, passing the settings to it: 113 | * 114 | * ```php 115 | * return Craft::$app->getView()->renderTemplate('myplugin/_settings', [ 116 | * 'settings' => $this->getSettings() 117 | * ]); 118 | * ``` 119 | * 120 | * If you need to tie any JavaScript code to your settings, it’s important to know that any `name=` and `id=` 121 | * attributes within the returned HTML will probably get [[\craft\web\View::namespaceInputs() namespaced]], 122 | * however your JavaScript code will be left untouched. 123 | * 124 | * For example, if getSettingsHtml() returns the following HTML: 125 | * 126 | * ```html 127 | * 128 | * 129 | * 132 | * ``` 133 | * 134 | * …then it might actually look like this before getting output to the browser: 135 | * 136 | * ```html 137 | * 138 | * 139 | * 142 | * ``` 143 | * 144 | * As you can see, that JavaScript code will not be able to find the textarea, because the textarea’s `id=` 145 | * attribute was changed from `foo` to `namespace-foo`. 146 | * 147 | * Before you start adding `namespace-` to the beginning of your element ID selectors, keep in mind that the actual 148 | * namespace is going to change depending on the context. Often they are randomly generated. So it’s not quite 149 | * that simple. 150 | * 151 | * Thankfully, [[\craft\web\View]] service provides a couple handy methods that can help you deal 152 | * with this: 153 | * 154 | * - [[\craft\web\View::namespaceInputId()]] will give you the namespaced version of a given ID. 155 | * - [[\craft\web\View::namespaceInputName()]] will give you the namespaced version of a given input name. 156 | * - [[\craft\web\View::formatInputId()]] will format an input name to look more like an ID attribute value. 157 | * 158 | * So here’s what a getSettingsHtml() method that includes field-targeting JavaScript code might look like: 159 | * 160 | * ```php 161 | * public function getSettingsHtml() 162 | * { 163 | * // Come up with an ID value for 'foo' 164 | * $id = Craft::$app->getView()->formatInputId('foo'); 165 | * 166 | * // Figure out what that ID is going to be namespaced into 167 | * $namespacedId = Craft::$app->getView()->namespaceInputId($id); 168 | * 169 | * // Render and return the input template 170 | * return Craft::$app->getView()->renderTemplate('myplugin/_fieldinput', [ 171 | * 'id' => $id, 172 | * 'namespacedId' => $namespacedId, 173 | * 'settings' => $this->getSettings() 174 | * ]); 175 | * } 176 | * ``` 177 | * 178 | * And the _settings.html template might look like this: 179 | * 180 | * ```twig 181 | * 182 | * 183 | * 186 | * ``` 187 | * 188 | * The same principles also apply if you’re including your JavaScript code with 189 | * [[\craft\web\View::registerJs()]]. 190 | * 191 | * @return string|null 192 | */ 193 | public function getSettingsHtml() 194 | { 195 | return Craft::$app->getView()->renderTemplate( 196 | 'elasticraft/_components/widgets/ElasticraftWidget_settings', 197 | [ 198 | 'widget' => $this 199 | ] 200 | ); 201 | } 202 | 203 | /** 204 | * Returns the widget's body HTML. 205 | * 206 | * @return string|false The widget’s body HTML, or `false` if the widget 207 | * should not be visible. (If you don’t want the widget 208 | * to be selectable in the first place, use {@link isSelectable()}.) 209 | */ 210 | public function getBodyHtml() 211 | { 212 | Craft::$app->getView()->registerAssetBundle(ElasticraftWidgetWidgetAsset::class); 213 | 214 | return Craft::$app->getView()->renderTemplate( 215 | 'elasticraft/_components/widgets/ElasticraftWidget_body', 216 | [ 217 | 'message' => $this->message 218 | ] 219 | ); 220 | } 221 | } 222 | --------------------------------------------------------------------------------