From 41685a2409964add5c17b72e90e62615000d1665 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 9 Dec 2013 23:51:49 -0500 Subject: [PATCH] moved extensions under yii. --- extensions/bootstrap/Alert.php | 149 -- extensions/bootstrap/BootstrapAsset.php | 22 - extensions/bootstrap/BootstrapPluginAsset.php | 27 - extensions/bootstrap/BootstrapThemeAsset.php | 27 - extensions/bootstrap/Button.php | 62 - extensions/bootstrap/ButtonDropdown.php | 109 - extensions/bootstrap/ButtonGroup.php | 97 - extensions/bootstrap/Carousel.php | 170 -- extensions/bootstrap/Collapse.php | 133 -- extensions/bootstrap/Dropdown.php | 92 - extensions/bootstrap/Modal.php | 227 -- extensions/bootstrap/Nav.php | 214 -- extensions/bootstrap/NavBar.php | 108 - extensions/bootstrap/Progress.php | 146 -- extensions/bootstrap/README.md | 32 - extensions/bootstrap/Tabs.php | 199 -- extensions/bootstrap/Widget.php | 81 - extensions/bootstrap/composer.json | 28 - extensions/composer/Installer.php | 234 -- extensions/composer/LICENSE.md | 32 - extensions/composer/Plugin.php | 35 - extensions/composer/README.md | 63 - extensions/composer/composer.json | 30 - extensions/debug/DebugAsset.php | 25 - extensions/debug/LogTarget.php | 105 - extensions/debug/Module.php | 124 -- extensions/debug/Panel.php | 91 - extensions/debug/README.md | 46 - extensions/debug/assets/main.css | 153 -- extensions/debug/composer.json | 28 - extensions/debug/controllers/DefaultController.php | 114 - extensions/debug/panels/ConfigPanel.php | 129 -- extensions/debug/panels/DbPanel.php | 123 -- extensions/debug/panels/LogPanel.php | 105 - extensions/debug/panels/ProfilingPanel.php | 107 - extensions/debug/panels/RequestPanel.php | 167 -- extensions/debug/views/default/index.php | 46 - extensions/debug/views/default/toolbar.css | 177 -- extensions/debug/views/default/toolbar.js | 41 - extensions/debug/views/default/toolbar.php | 38 - extensions/debug/views/default/view.php | 78 - extensions/debug/views/layouts/main.php | 23 - extensions/elasticsearch/ActiveQuery.php | 199 -- extensions/elasticsearch/ActiveRecord.php | 485 ----- extensions/elasticsearch/ActiveRelation.php | 61 - extensions/elasticsearch/Command.php | 403 ---- extensions/elasticsearch/Connection.php | 358 ---- extensions/elasticsearch/DebugAction.php | 76 - extensions/elasticsearch/DebugPanel.php | 177 -- extensions/elasticsearch/Exception.php | 25 - extensions/elasticsearch/LICENSE.md | 32 - extensions/elasticsearch/Query.php | 508 ----- extensions/elasticsearch/QueryBuilder.php | 297 --- extensions/elasticsearch/README-debug.png | Bin 107733 -> 0 bytes extensions/elasticsearch/README.md | 176 -- extensions/elasticsearch/composer.json | 28 - extensions/gii/CodeFile.php | 155 -- extensions/gii/Generator.php | 449 ---- extensions/gii/GiiAsset.php | 46 - extensions/gii/Module.php | 146 -- extensions/gii/README.md | 47 - extensions/gii/assets/gii.js | 99 - extensions/gii/assets/logo.png | Bin 6677 -> 0 bytes extensions/gii/assets/main.css | 211 -- extensions/gii/assets/typeahead.js | 1139 ---------- extensions/gii/assets/typeahead.js-bootstrap.css | 51 - extensions/gii/components/ActiveField.php | 66 - extensions/gii/composer.json | 28 - extensions/gii/controllers/DefaultController.php | 152 -- extensions/gii/generators/controller/Generator.php | 236 -- extensions/gii/generators/controller/form.php | 10 - .../generators/controller/templates/controller.php | 28 - .../gii/generators/controller/templates/view.php | 22 - extensions/gii/generators/crud/Generator.php | 436 ---- extensions/gii/generators/crud/form.php | 16 - .../gii/generators/crud/templates/controller.php | 157 -- .../gii/generators/crud/templates/search.php | 83 - .../gii/generators/crud/templates/views/_form.php | 44 - .../generators/crud/templates/views/_search.php | 48 - .../gii/generators/crud/templates/views/create.php | 33 - .../gii/generators/crud/templates/views/index.php | 81 - .../gii/generators/crud/templates/views/update.php | 36 - .../gii/generators/crud/templates/views/view.php | 59 - extensions/gii/generators/form/Generator.php | 152 -- extensions/gii/generators/form/form.php | 10 - .../gii/generators/form/templates/action.php | 28 - extensions/gii/generators/form/templates/form.php | 35 - extensions/gii/generators/model/Generator.php | 555 ----- extensions/gii/generators/model/form.php | 14 - .../gii/generators/model/templates/model.php | 72 - extensions/gii/generators/module/Generator.php | 165 -- extensions/gii/generators/module/form.php | 13 - .../gii/generators/module/templates/controller.php | 21 - .../gii/generators/module/templates/module.php | 29 - .../gii/generators/module/templates/view.php | 18 - extensions/gii/views/default/diff.php | 15 - extensions/gii/views/default/index.php | 33 - extensions/gii/views/default/view.php | 72 - extensions/gii/views/default/view/files.php | 78 - extensions/gii/views/default/view/results.php | 18 - extensions/gii/views/layouts/generator.php | 31 - extensions/gii/views/layouts/main.php | 53 - extensions/jui/Accordion.php | 121 -- extensions/jui/AccordionAsset.php | 26 - extensions/jui/AutoComplete.php | 66 - extensions/jui/AutoCompleteAsset.php | 25 - extensions/jui/ButtonAsset.php | 24 - extensions/jui/CoreAsset.php | 27 - extensions/jui/DatePicker.php | 110 - extensions/jui/DatePickerAsset.php | 25 - extensions/jui/DatePickerRegionalAsset.php | 24 - extensions/jui/Dialog.php | 52 - extensions/jui/DialogAsset.php | 27 - extensions/jui/Draggable.php | 50 - extensions/jui/DraggableAsset.php | 24 - extensions/jui/Droppable.php | 50 - extensions/jui/DroppableAsset.php | 24 - extensions/jui/EffectAsset.php | 24 - extensions/jui/InputWidget.php | 59 - extensions/jui/LICENSE.md | 32 - extensions/jui/Menu.php | 78 - extensions/jui/MenuAsset.php | 24 - extensions/jui/ProgressBar.php | 60 - extensions/jui/ProgressBarAsset.php | 24 - extensions/jui/README.md | 41 - extensions/jui/Resizable.php | 52 - extensions/jui/ResizableAsset.php | 24 - extensions/jui/Selectable.php | 116 - extensions/jui/SelectableAsset.php | 24 - extensions/jui/Slider.php | 45 - extensions/jui/SliderAsset.php | 24 - extensions/jui/SliderInput.php | 79 - extensions/jui/Sortable.php | 106 - extensions/jui/SortableAsset.php | 24 - extensions/jui/Spinner.php | 62 - extensions/jui/SpinnerAsset.php | 25 - extensions/jui/Tabs.php | 145 -- extensions/jui/TabsAsset.php | 25 - extensions/jui/ThemeAsset.php | 21 - extensions/jui/TooltipAsset.php | 25 - extensions/jui/Widget.php | 122 -- extensions/jui/assets/UPGRADE.md | 14 - extensions/jui/assets/jquery.ui.accordion.js | 572 ----- extensions/jui/assets/jquery.ui.autocomplete.js | 610 ------ extensions/jui/assets/jquery.ui.button.js | 419 ---- extensions/jui/assets/jquery.ui.core.js | 320 --- extensions/jui/assets/jquery.ui.datepicker-i18n.js | 1793 ---------------- extensions/jui/assets/jquery.ui.datepicker.js | 2038 ------------------ extensions/jui/assets/jquery.ui.dialog.js | 808 ------- extensions/jui/assets/jquery.ui.draggable.js | 958 --------- extensions/jui/assets/jquery.ui.droppable.js | 372 ---- extensions/jui/assets/jquery.ui.effect-all.js | 2261 -------------------- extensions/jui/assets/jquery.ui.menu.js | 621 ------ extensions/jui/assets/jquery.ui.mouse.js | 169 -- extensions/jui/assets/jquery.ui.position.js | 497 ----- extensions/jui/assets/jquery.ui.progressbar.js | 145 -- extensions/jui/assets/jquery.ui.resizable.js | 968 --------- extensions/jui/assets/jquery.ui.selectable.js | 277 --- extensions/jui/assets/jquery.ui.slider.js | 672 ------ extensions/jui/assets/jquery.ui.sortable.js | 1285 ----------- extensions/jui/assets/jquery.ui.spinner.js | 493 ----- extensions/jui/assets/jquery.ui.tabs.js | 846 -------- extensions/jui/assets/jquery.ui.tooltip.js | 402 ---- extensions/jui/assets/jquery.ui.widget.js | 521 ----- .../jui/assets/theme/images/animated-overlay.gif | Bin 1738 -> 0 bytes .../theme/images/ui-bg_flat_0_aaaaaa_40x100.png | Bin 212 -> 0 bytes .../theme/images/ui-bg_flat_75_ffffff_40x100.png | Bin 208 -> 0 bytes .../theme/images/ui-bg_glass_55_fbf9ee_1x400.png | Bin 335 -> 0 bytes .../theme/images/ui-bg_glass_65_ffffff_1x400.png | Bin 207 -> 0 bytes .../theme/images/ui-bg_glass_75_dadada_1x400.png | Bin 262 -> 0 bytes .../theme/images/ui-bg_glass_75_e6e6e6_1x400.png | Bin 262 -> 0 bytes .../theme/images/ui-bg_glass_95_fef1ec_1x400.png | Bin 332 -> 0 bytes .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin 280 -> 0 bytes .../theme/images/ui-icons_222222_256x240.png | Bin 6922 -> 0 bytes .../theme/images/ui-icons_2e83ff_256x240.png | Bin 4549 -> 0 bytes .../theme/images/ui-icons_454545_256x240.png | Bin 6992 -> 0 bytes .../theme/images/ui-icons_888888_256x240.png | Bin 6999 -> 0 bytes .../theme/images/ui-icons_cd0a0a_256x240.png | Bin 4549 -> 0 bytes extensions/jui/assets/theme/jquery.ui.css | 1177 ---------- extensions/jui/composer.json | 27 - extensions/mongodb/ActiveQuery.php | 107 - extensions/mongodb/ActiveRecord.php | 353 --- extensions/mongodb/ActiveRelation.php | 22 - extensions/mongodb/Collection.php | 893 -------- extensions/mongodb/Connection.php | 254 --- extensions/mongodb/Database.php | 172 -- extensions/mongodb/Exception.php | 25 - extensions/mongodb/LICENSE.md | 32 - extensions/mongodb/Query.php | 344 --- extensions/mongodb/README.md | 104 - extensions/mongodb/composer.json | 28 - extensions/mongodb/file/ActiveQuery.php | 107 - extensions/mongodb/file/ActiveRecord.php | 340 --- extensions/mongodb/file/ActiveRelation.php | 22 - extensions/mongodb/file/Collection.php | 186 -- extensions/mongodb/file/Query.php | 73 - extensions/redis/ActiveQuery.php | 382 ---- extensions/redis/ActiveRecord.php | 305 --- extensions/redis/ActiveRelation.php | 67 - extensions/redis/Cache.php | 204 -- extensions/redis/Connection.php | 406 ---- extensions/redis/LICENSE.md | 32 - extensions/redis/LuaScriptBuilder.php | 365 ---- extensions/redis/README.md | 184 -- extensions/redis/Session.php | 157 -- extensions/redis/composer.json | 27 - extensions/sphinx/ActiveQuery.php | 204 -- extensions/sphinx/ActiveRecord.php | 671 ------ extensions/sphinx/ActiveRelation.php | 22 - extensions/sphinx/ColumnSchema.php | 81 - extensions/sphinx/Command.php | 326 --- extensions/sphinx/Connection.php | 129 -- extensions/sphinx/IndexSchema.php | 63 - extensions/sphinx/LICENSE.md | 32 - extensions/sphinx/Query.php | 703 ------ extensions/sphinx/QueryBuilder.php | 905 -------- extensions/sphinx/README.md | 108 - extensions/sphinx/Schema.php | 489 ----- extensions/sphinx/composer.json | 29 - extensions/swiftmailer/LICENSE.md | 32 - extensions/swiftmailer/Mailer.php | 220 -- extensions/swiftmailer/Message.php | 302 --- extensions/swiftmailer/README.md | 49 - extensions/swiftmailer/composer.json | 28 - extensions/yii/bootstrap/Alert.php | 149 ++ extensions/yii/bootstrap/BootstrapAsset.php | 22 + extensions/yii/bootstrap/BootstrapPluginAsset.php | 27 + extensions/yii/bootstrap/BootstrapThemeAsset.php | 27 + extensions/yii/bootstrap/Button.php | 62 + extensions/yii/bootstrap/ButtonDropdown.php | 109 + extensions/yii/bootstrap/ButtonGroup.php | 97 + extensions/yii/bootstrap/Carousel.php | 170 ++ extensions/yii/bootstrap/Collapse.php | 133 ++ extensions/yii/bootstrap/Dropdown.php | 92 + extensions/yii/bootstrap/Modal.php | 227 ++ extensions/yii/bootstrap/Nav.php | 214 ++ extensions/yii/bootstrap/NavBar.php | 108 + extensions/yii/bootstrap/Progress.php | 146 ++ extensions/yii/bootstrap/README.md | 32 + extensions/yii/bootstrap/Tabs.php | 199 ++ extensions/yii/bootstrap/Widget.php | 81 + extensions/yii/bootstrap/composer.json | 28 + extensions/yii/composer/Installer.php | 234 ++ extensions/yii/composer/LICENSE.md | 32 + extensions/yii/composer/Plugin.php | 35 + extensions/yii/composer/README.md | 63 + extensions/yii/composer/composer.json | 30 + extensions/yii/debug/DebugAsset.php | 25 + extensions/yii/debug/LogTarget.php | 105 + extensions/yii/debug/Module.php | 124 ++ extensions/yii/debug/Panel.php | 91 + extensions/yii/debug/README.md | 46 + extensions/yii/debug/assets/main.css | 153 ++ extensions/yii/debug/composer.json | 28 + .../yii/debug/controllers/DefaultController.php | 114 + extensions/yii/debug/panels/ConfigPanel.php | 129 ++ extensions/yii/debug/panels/DbPanel.php | 123 ++ extensions/yii/debug/panels/LogPanel.php | 105 + extensions/yii/debug/panels/ProfilingPanel.php | 107 + extensions/yii/debug/panels/RequestPanel.php | 167 ++ extensions/yii/debug/views/default/index.php | 46 + extensions/yii/debug/views/default/toolbar.css | 177 ++ extensions/yii/debug/views/default/toolbar.js | 41 + extensions/yii/debug/views/default/toolbar.php | 38 + extensions/yii/debug/views/default/view.php | 78 + extensions/yii/debug/views/layouts/main.php | 23 + extensions/yii/elasticsearch/ActiveQuery.php | 199 ++ extensions/yii/elasticsearch/ActiveRecord.php | 485 +++++ extensions/yii/elasticsearch/ActiveRelation.php | 61 + extensions/yii/elasticsearch/Command.php | 403 ++++ extensions/yii/elasticsearch/Connection.php | 358 ++++ extensions/yii/elasticsearch/DebugAction.php | 76 + extensions/yii/elasticsearch/DebugPanel.php | 177 ++ extensions/yii/elasticsearch/Exception.php | 25 + extensions/yii/elasticsearch/LICENSE.md | 32 + extensions/yii/elasticsearch/Query.php | 508 +++++ extensions/yii/elasticsearch/QueryBuilder.php | 297 +++ extensions/yii/elasticsearch/README-debug.png | Bin 0 -> 107733 bytes extensions/yii/elasticsearch/README.md | 176 ++ extensions/yii/elasticsearch/composer.json | 28 + extensions/yii/gii/CodeFile.php | 155 ++ extensions/yii/gii/Generator.php | 449 ++++ extensions/yii/gii/GiiAsset.php | 46 + extensions/yii/gii/Module.php | 146 ++ extensions/yii/gii/README.md | 47 + extensions/yii/gii/assets/gii.js | 99 + extensions/yii/gii/assets/logo.png | Bin 0 -> 6677 bytes extensions/yii/gii/assets/main.css | 211 ++ extensions/yii/gii/assets/typeahead.js | 1139 ++++++++++ .../yii/gii/assets/typeahead.js-bootstrap.css | 51 + extensions/yii/gii/components/ActiveField.php | 66 + extensions/yii/gii/composer.json | 28 + .../yii/gii/controllers/DefaultController.php | 152 ++ .../yii/gii/generators/controller/Generator.php | 236 ++ extensions/yii/gii/generators/controller/form.php | 10 + .../generators/controller/templates/controller.php | 28 + .../gii/generators/controller/templates/view.php | 22 + extensions/yii/gii/generators/crud/Generator.php | 436 ++++ extensions/yii/gii/generators/crud/form.php | 16 + .../gii/generators/crud/templates/controller.php | 157 ++ .../yii/gii/generators/crud/templates/search.php | 83 + .../gii/generators/crud/templates/views/_form.php | 44 + .../generators/crud/templates/views/_search.php | 48 + .../gii/generators/crud/templates/views/create.php | 33 + .../gii/generators/crud/templates/views/index.php | 81 + .../gii/generators/crud/templates/views/update.php | 36 + .../gii/generators/crud/templates/views/view.php | 59 + extensions/yii/gii/generators/form/Generator.php | 152 ++ extensions/yii/gii/generators/form/form.php | 10 + .../yii/gii/generators/form/templates/action.php | 28 + .../yii/gii/generators/form/templates/form.php | 35 + extensions/yii/gii/generators/model/Generator.php | 555 +++++ extensions/yii/gii/generators/model/form.php | 14 + .../yii/gii/generators/model/templates/model.php | 72 + extensions/yii/gii/generators/module/Generator.php | 165 ++ extensions/yii/gii/generators/module/form.php | 13 + .../gii/generators/module/templates/controller.php | 21 + .../yii/gii/generators/module/templates/module.php | 29 + .../yii/gii/generators/module/templates/view.php | 18 + extensions/yii/gii/views/default/diff.php | 15 + extensions/yii/gii/views/default/index.php | 33 + extensions/yii/gii/views/default/view.php | 72 + extensions/yii/gii/views/default/view/files.php | 78 + extensions/yii/gii/views/default/view/results.php | 18 + extensions/yii/gii/views/layouts/generator.php | 31 + extensions/yii/gii/views/layouts/main.php | 53 + extensions/yii/jui/Accordion.php | 121 ++ extensions/yii/jui/AccordionAsset.php | 26 + extensions/yii/jui/AutoComplete.php | 66 + extensions/yii/jui/AutoCompleteAsset.php | 25 + extensions/yii/jui/ButtonAsset.php | 24 + extensions/yii/jui/CoreAsset.php | 27 + extensions/yii/jui/DatePicker.php | 110 + extensions/yii/jui/DatePickerAsset.php | 25 + extensions/yii/jui/DatePickerRegionalAsset.php | 24 + extensions/yii/jui/Dialog.php | 52 + extensions/yii/jui/DialogAsset.php | 27 + extensions/yii/jui/Draggable.php | 50 + extensions/yii/jui/DraggableAsset.php | 24 + extensions/yii/jui/Droppable.php | 50 + extensions/yii/jui/DroppableAsset.php | 24 + extensions/yii/jui/EffectAsset.php | 24 + extensions/yii/jui/InputWidget.php | 59 + extensions/yii/jui/LICENSE.md | 32 + extensions/yii/jui/Menu.php | 78 + extensions/yii/jui/MenuAsset.php | 24 + extensions/yii/jui/ProgressBar.php | 60 + extensions/yii/jui/ProgressBarAsset.php | 24 + extensions/yii/jui/README.md | 41 + extensions/yii/jui/Resizable.php | 52 + extensions/yii/jui/ResizableAsset.php | 24 + extensions/yii/jui/Selectable.php | 116 + extensions/yii/jui/SelectableAsset.php | 24 + extensions/yii/jui/Slider.php | 45 + extensions/yii/jui/SliderAsset.php | 24 + extensions/yii/jui/SliderInput.php | 79 + extensions/yii/jui/Sortable.php | 106 + extensions/yii/jui/SortableAsset.php | 24 + extensions/yii/jui/Spinner.php | 62 + extensions/yii/jui/SpinnerAsset.php | 25 + extensions/yii/jui/Tabs.php | 145 ++ extensions/yii/jui/TabsAsset.php | 25 + extensions/yii/jui/ThemeAsset.php | 21 + extensions/yii/jui/TooltipAsset.php | 25 + extensions/yii/jui/Widget.php | 122 ++ extensions/yii/jui/assets/UPGRADE.md | 14 + extensions/yii/jui/assets/jquery.ui.accordion.js | 572 +++++ .../yii/jui/assets/jquery.ui.autocomplete.js | 610 ++++++ extensions/yii/jui/assets/jquery.ui.button.js | 419 ++++ extensions/yii/jui/assets/jquery.ui.core.js | 320 +++ .../yii/jui/assets/jquery.ui.datepicker-i18n.js | 1793 ++++++++++++++++ extensions/yii/jui/assets/jquery.ui.datepicker.js | 2038 ++++++++++++++++++ extensions/yii/jui/assets/jquery.ui.dialog.js | 808 +++++++ extensions/yii/jui/assets/jquery.ui.draggable.js | 958 +++++++++ extensions/yii/jui/assets/jquery.ui.droppable.js | 372 ++++ extensions/yii/jui/assets/jquery.ui.effect-all.js | 2261 ++++++++++++++++++++ extensions/yii/jui/assets/jquery.ui.menu.js | 621 ++++++ extensions/yii/jui/assets/jquery.ui.mouse.js | 169 ++ extensions/yii/jui/assets/jquery.ui.position.js | 497 +++++ extensions/yii/jui/assets/jquery.ui.progressbar.js | 145 ++ extensions/yii/jui/assets/jquery.ui.resizable.js | 968 +++++++++ extensions/yii/jui/assets/jquery.ui.selectable.js | 277 +++ extensions/yii/jui/assets/jquery.ui.slider.js | 672 ++++++ extensions/yii/jui/assets/jquery.ui.sortable.js | 1285 +++++++++++ extensions/yii/jui/assets/jquery.ui.spinner.js | 493 +++++ extensions/yii/jui/assets/jquery.ui.tabs.js | 846 ++++++++ extensions/yii/jui/assets/jquery.ui.tooltip.js | 402 ++++ extensions/yii/jui/assets/jquery.ui.widget.js | 521 +++++ .../jui/assets/theme/images/animated-overlay.gif | Bin 0 -> 1738 bytes .../theme/images/ui-bg_flat_0_aaaaaa_40x100.png | Bin 0 -> 212 bytes .../theme/images/ui-bg_flat_75_ffffff_40x100.png | Bin 0 -> 208 bytes .../theme/images/ui-bg_glass_55_fbf9ee_1x400.png | Bin 0 -> 335 bytes .../theme/images/ui-bg_glass_65_ffffff_1x400.png | Bin 0 -> 207 bytes .../theme/images/ui-bg_glass_75_dadada_1x400.png | Bin 0 -> 262 bytes .../theme/images/ui-bg_glass_75_e6e6e6_1x400.png | Bin 0 -> 262 bytes .../theme/images/ui-bg_glass_95_fef1ec_1x400.png | Bin 0 -> 332 bytes .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin 0 -> 280 bytes .../theme/images/ui-icons_222222_256x240.png | Bin 0 -> 6922 bytes .../theme/images/ui-icons_2e83ff_256x240.png | Bin 0 -> 4549 bytes .../theme/images/ui-icons_454545_256x240.png | Bin 0 -> 6992 bytes .../theme/images/ui-icons_888888_256x240.png | Bin 0 -> 6999 bytes .../theme/images/ui-icons_cd0a0a_256x240.png | Bin 0 -> 4549 bytes extensions/yii/jui/assets/theme/jquery.ui.css | 1177 ++++++++++ extensions/yii/jui/composer.json | 27 + extensions/yii/mongodb/ActiveQuery.php | 107 + extensions/yii/mongodb/ActiveRecord.php | 353 +++ extensions/yii/mongodb/ActiveRelation.php | 22 + extensions/yii/mongodb/Collection.php | 893 ++++++++ extensions/yii/mongodb/Connection.php | 254 +++ extensions/yii/mongodb/Database.php | 172 ++ extensions/yii/mongodb/Exception.php | 25 + extensions/yii/mongodb/LICENSE.md | 32 + extensions/yii/mongodb/Query.php | 344 +++ extensions/yii/mongodb/README.md | 104 + extensions/yii/mongodb/composer.json | 28 + extensions/yii/mongodb/file/ActiveQuery.php | 107 + extensions/yii/mongodb/file/ActiveRecord.php | 340 +++ extensions/yii/mongodb/file/ActiveRelation.php | 22 + extensions/yii/mongodb/file/Collection.php | 186 ++ extensions/yii/mongodb/file/Query.php | 73 + extensions/yii/redis/ActiveQuery.php | 382 ++++ extensions/yii/redis/ActiveRecord.php | 305 +++ extensions/yii/redis/ActiveRelation.php | 67 + extensions/yii/redis/Cache.php | 204 ++ extensions/yii/redis/Connection.php | 406 ++++ extensions/yii/redis/LICENSE.md | 32 + extensions/yii/redis/LuaScriptBuilder.php | 365 ++++ extensions/yii/redis/README.md | 184 ++ extensions/yii/redis/Session.php | 157 ++ extensions/yii/redis/composer.json | 27 + extensions/yii/sphinx/ActiveQuery.php | 204 ++ extensions/yii/sphinx/ActiveRecord.php | 671 ++++++ extensions/yii/sphinx/ActiveRelation.php | 22 + extensions/yii/sphinx/ColumnSchema.php | 81 + extensions/yii/sphinx/Command.php | 326 +++ extensions/yii/sphinx/Connection.php | 129 ++ extensions/yii/sphinx/IndexSchema.php | 63 + extensions/yii/sphinx/LICENSE.md | 32 + extensions/yii/sphinx/Query.php | 703 ++++++ extensions/yii/sphinx/QueryBuilder.php | 905 ++++++++ extensions/yii/sphinx/README.md | 108 + extensions/yii/sphinx/Schema.php | 489 +++++ extensions/yii/sphinx/composer.json | 29 + extensions/yii/swiftmailer/LICENSE.md | 32 + extensions/yii/swiftmailer/Mailer.php | 220 ++ extensions/yii/swiftmailer/Message.php | 302 +++ extensions/yii/swiftmailer/README.md | 49 + extensions/yii/swiftmailer/composer.json | 28 + 448 files changed, 41937 insertions(+), 41937 deletions(-) delete mode 100644 extensions/bootstrap/Alert.php delete mode 100644 extensions/bootstrap/BootstrapAsset.php delete mode 100644 extensions/bootstrap/BootstrapPluginAsset.php delete mode 100644 extensions/bootstrap/BootstrapThemeAsset.php delete mode 100644 extensions/bootstrap/Button.php delete mode 100644 extensions/bootstrap/ButtonDropdown.php delete mode 100644 extensions/bootstrap/ButtonGroup.php delete mode 100644 extensions/bootstrap/Carousel.php delete mode 100644 extensions/bootstrap/Collapse.php delete mode 100644 extensions/bootstrap/Dropdown.php delete mode 100644 extensions/bootstrap/Modal.php delete mode 100644 extensions/bootstrap/Nav.php delete mode 100644 extensions/bootstrap/NavBar.php delete mode 100644 extensions/bootstrap/Progress.php delete mode 100644 extensions/bootstrap/README.md delete mode 100644 extensions/bootstrap/Tabs.php delete mode 100644 extensions/bootstrap/Widget.php delete mode 100644 extensions/bootstrap/composer.json delete mode 100644 extensions/composer/Installer.php delete mode 100644 extensions/composer/LICENSE.md delete mode 100644 extensions/composer/Plugin.php delete mode 100644 extensions/composer/README.md delete mode 100644 extensions/composer/composer.json delete mode 100644 extensions/debug/DebugAsset.php delete mode 100644 extensions/debug/LogTarget.php delete mode 100644 extensions/debug/Module.php delete mode 100644 extensions/debug/Panel.php delete mode 100644 extensions/debug/README.md delete mode 100644 extensions/debug/assets/main.css delete mode 100644 extensions/debug/composer.json delete mode 100644 extensions/debug/controllers/DefaultController.php delete mode 100644 extensions/debug/panels/ConfigPanel.php delete mode 100644 extensions/debug/panels/DbPanel.php delete mode 100644 extensions/debug/panels/LogPanel.php delete mode 100644 extensions/debug/panels/ProfilingPanel.php delete mode 100644 extensions/debug/panels/RequestPanel.php delete mode 100644 extensions/debug/views/default/index.php delete mode 100644 extensions/debug/views/default/toolbar.css delete mode 100644 extensions/debug/views/default/toolbar.js delete mode 100644 extensions/debug/views/default/toolbar.php delete mode 100644 extensions/debug/views/default/view.php delete mode 100644 extensions/debug/views/layouts/main.php delete mode 100644 extensions/elasticsearch/ActiveQuery.php delete mode 100644 extensions/elasticsearch/ActiveRecord.php delete mode 100644 extensions/elasticsearch/ActiveRelation.php delete mode 100644 extensions/elasticsearch/Command.php delete mode 100644 extensions/elasticsearch/Connection.php delete mode 100644 extensions/elasticsearch/DebugAction.php delete mode 100644 extensions/elasticsearch/DebugPanel.php delete mode 100644 extensions/elasticsearch/Exception.php delete mode 100644 extensions/elasticsearch/LICENSE.md delete mode 100644 extensions/elasticsearch/Query.php delete mode 100644 extensions/elasticsearch/QueryBuilder.php delete mode 100644 extensions/elasticsearch/README-debug.png delete mode 100644 extensions/elasticsearch/README.md delete mode 100644 extensions/elasticsearch/composer.json delete mode 100644 extensions/gii/CodeFile.php delete mode 100644 extensions/gii/Generator.php delete mode 100644 extensions/gii/GiiAsset.php delete mode 100644 extensions/gii/Module.php delete mode 100644 extensions/gii/README.md delete mode 100644 extensions/gii/assets/gii.js delete mode 100644 extensions/gii/assets/logo.png delete mode 100644 extensions/gii/assets/main.css delete mode 100644 extensions/gii/assets/typeahead.js delete mode 100644 extensions/gii/assets/typeahead.js-bootstrap.css delete mode 100644 extensions/gii/components/ActiveField.php delete mode 100644 extensions/gii/composer.json delete mode 100644 extensions/gii/controllers/DefaultController.php delete mode 100644 extensions/gii/generators/controller/Generator.php delete mode 100644 extensions/gii/generators/controller/form.php delete mode 100644 extensions/gii/generators/controller/templates/controller.php delete mode 100644 extensions/gii/generators/controller/templates/view.php delete mode 100644 extensions/gii/generators/crud/Generator.php delete mode 100644 extensions/gii/generators/crud/form.php delete mode 100644 extensions/gii/generators/crud/templates/controller.php delete mode 100644 extensions/gii/generators/crud/templates/search.php delete mode 100644 extensions/gii/generators/crud/templates/views/_form.php delete mode 100644 extensions/gii/generators/crud/templates/views/_search.php delete mode 100644 extensions/gii/generators/crud/templates/views/create.php delete mode 100644 extensions/gii/generators/crud/templates/views/index.php delete mode 100644 extensions/gii/generators/crud/templates/views/update.php delete mode 100644 extensions/gii/generators/crud/templates/views/view.php delete mode 100644 extensions/gii/generators/form/Generator.php delete mode 100644 extensions/gii/generators/form/form.php delete mode 100644 extensions/gii/generators/form/templates/action.php delete mode 100644 extensions/gii/generators/form/templates/form.php delete mode 100644 extensions/gii/generators/model/Generator.php delete mode 100644 extensions/gii/generators/model/form.php delete mode 100644 extensions/gii/generators/model/templates/model.php delete mode 100644 extensions/gii/generators/module/Generator.php delete mode 100644 extensions/gii/generators/module/form.php delete mode 100644 extensions/gii/generators/module/templates/controller.php delete mode 100644 extensions/gii/generators/module/templates/module.php delete mode 100644 extensions/gii/generators/module/templates/view.php delete mode 100644 extensions/gii/views/default/diff.php delete mode 100644 extensions/gii/views/default/index.php delete mode 100644 extensions/gii/views/default/view.php delete mode 100644 extensions/gii/views/default/view/files.php delete mode 100644 extensions/gii/views/default/view/results.php delete mode 100644 extensions/gii/views/layouts/generator.php delete mode 100644 extensions/gii/views/layouts/main.php delete mode 100644 extensions/jui/Accordion.php delete mode 100644 extensions/jui/AccordionAsset.php delete mode 100644 extensions/jui/AutoComplete.php delete mode 100644 extensions/jui/AutoCompleteAsset.php delete mode 100644 extensions/jui/ButtonAsset.php delete mode 100644 extensions/jui/CoreAsset.php delete mode 100644 extensions/jui/DatePicker.php delete mode 100644 extensions/jui/DatePickerAsset.php delete mode 100644 extensions/jui/DatePickerRegionalAsset.php delete mode 100644 extensions/jui/Dialog.php delete mode 100644 extensions/jui/DialogAsset.php delete mode 100644 extensions/jui/Draggable.php delete mode 100644 extensions/jui/DraggableAsset.php delete mode 100644 extensions/jui/Droppable.php delete mode 100644 extensions/jui/DroppableAsset.php delete mode 100644 extensions/jui/EffectAsset.php delete mode 100644 extensions/jui/InputWidget.php delete mode 100644 extensions/jui/LICENSE.md delete mode 100644 extensions/jui/Menu.php delete mode 100644 extensions/jui/MenuAsset.php delete mode 100644 extensions/jui/ProgressBar.php delete mode 100644 extensions/jui/ProgressBarAsset.php delete mode 100644 extensions/jui/README.md delete mode 100644 extensions/jui/Resizable.php delete mode 100644 extensions/jui/ResizableAsset.php delete mode 100644 extensions/jui/Selectable.php delete mode 100644 extensions/jui/SelectableAsset.php delete mode 100644 extensions/jui/Slider.php delete mode 100644 extensions/jui/SliderAsset.php delete mode 100644 extensions/jui/SliderInput.php delete mode 100644 extensions/jui/Sortable.php delete mode 100644 extensions/jui/SortableAsset.php delete mode 100644 extensions/jui/Spinner.php delete mode 100644 extensions/jui/SpinnerAsset.php delete mode 100644 extensions/jui/Tabs.php delete mode 100644 extensions/jui/TabsAsset.php delete mode 100644 extensions/jui/ThemeAsset.php delete mode 100644 extensions/jui/TooltipAsset.php delete mode 100644 extensions/jui/Widget.php delete mode 100644 extensions/jui/assets/UPGRADE.md delete mode 100644 extensions/jui/assets/jquery.ui.accordion.js delete mode 100644 extensions/jui/assets/jquery.ui.autocomplete.js delete mode 100644 extensions/jui/assets/jquery.ui.button.js delete mode 100644 extensions/jui/assets/jquery.ui.core.js delete mode 100755 extensions/jui/assets/jquery.ui.datepicker-i18n.js delete mode 100644 extensions/jui/assets/jquery.ui.datepicker.js delete mode 100644 extensions/jui/assets/jquery.ui.dialog.js delete mode 100644 extensions/jui/assets/jquery.ui.draggable.js delete mode 100644 extensions/jui/assets/jquery.ui.droppable.js delete mode 100755 extensions/jui/assets/jquery.ui.effect-all.js delete mode 100644 extensions/jui/assets/jquery.ui.menu.js delete mode 100644 extensions/jui/assets/jquery.ui.mouse.js delete mode 100644 extensions/jui/assets/jquery.ui.position.js delete mode 100644 extensions/jui/assets/jquery.ui.progressbar.js delete mode 100644 extensions/jui/assets/jquery.ui.resizable.js delete mode 100644 extensions/jui/assets/jquery.ui.selectable.js delete mode 100644 extensions/jui/assets/jquery.ui.slider.js delete mode 100644 extensions/jui/assets/jquery.ui.sortable.js delete mode 100644 extensions/jui/assets/jquery.ui.spinner.js delete mode 100644 extensions/jui/assets/jquery.ui.tabs.js delete mode 100644 extensions/jui/assets/jquery.ui.tooltip.js delete mode 100644 extensions/jui/assets/jquery.ui.widget.js delete mode 100755 extensions/jui/assets/theme/images/animated-overlay.gif delete mode 100755 extensions/jui/assets/theme/images/ui-bg_flat_0_aaaaaa_40x100.png delete mode 100755 extensions/jui/assets/theme/images/ui-bg_flat_75_ffffff_40x100.png delete mode 100755 extensions/jui/assets/theme/images/ui-bg_glass_55_fbf9ee_1x400.png delete mode 100755 extensions/jui/assets/theme/images/ui-bg_glass_65_ffffff_1x400.png delete mode 100755 extensions/jui/assets/theme/images/ui-bg_glass_75_dadada_1x400.png delete mode 100755 extensions/jui/assets/theme/images/ui-bg_glass_75_e6e6e6_1x400.png delete mode 100755 extensions/jui/assets/theme/images/ui-bg_glass_95_fef1ec_1x400.png delete mode 100755 extensions/jui/assets/theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png delete mode 100755 extensions/jui/assets/theme/images/ui-icons_222222_256x240.png delete mode 100755 extensions/jui/assets/theme/images/ui-icons_2e83ff_256x240.png delete mode 100755 extensions/jui/assets/theme/images/ui-icons_454545_256x240.png delete mode 100755 extensions/jui/assets/theme/images/ui-icons_888888_256x240.png delete mode 100755 extensions/jui/assets/theme/images/ui-icons_cd0a0a_256x240.png delete mode 100755 extensions/jui/assets/theme/jquery.ui.css delete mode 100644 extensions/jui/composer.json delete mode 100644 extensions/mongodb/ActiveQuery.php delete mode 100644 extensions/mongodb/ActiveRecord.php delete mode 100644 extensions/mongodb/ActiveRelation.php delete mode 100644 extensions/mongodb/Collection.php delete mode 100644 extensions/mongodb/Connection.php delete mode 100644 extensions/mongodb/Database.php delete mode 100644 extensions/mongodb/Exception.php delete mode 100644 extensions/mongodb/LICENSE.md delete mode 100644 extensions/mongodb/Query.php delete mode 100644 extensions/mongodb/README.md delete mode 100644 extensions/mongodb/composer.json delete mode 100644 extensions/mongodb/file/ActiveQuery.php delete mode 100644 extensions/mongodb/file/ActiveRecord.php delete mode 100644 extensions/mongodb/file/ActiveRelation.php delete mode 100644 extensions/mongodb/file/Collection.php delete mode 100644 extensions/mongodb/file/Query.php delete mode 100644 extensions/redis/ActiveQuery.php delete mode 100644 extensions/redis/ActiveRecord.php delete mode 100644 extensions/redis/ActiveRelation.php delete mode 100644 extensions/redis/Cache.php delete mode 100644 extensions/redis/Connection.php delete mode 100644 extensions/redis/LICENSE.md delete mode 100644 extensions/redis/LuaScriptBuilder.php delete mode 100644 extensions/redis/README.md delete mode 100644 extensions/redis/Session.php delete mode 100644 extensions/redis/composer.json delete mode 100644 extensions/sphinx/ActiveQuery.php delete mode 100644 extensions/sphinx/ActiveRecord.php delete mode 100644 extensions/sphinx/ActiveRelation.php delete mode 100644 extensions/sphinx/ColumnSchema.php delete mode 100644 extensions/sphinx/Command.php delete mode 100644 extensions/sphinx/Connection.php delete mode 100644 extensions/sphinx/IndexSchema.php delete mode 100644 extensions/sphinx/LICENSE.md delete mode 100644 extensions/sphinx/Query.php delete mode 100644 extensions/sphinx/QueryBuilder.php delete mode 100644 extensions/sphinx/README.md delete mode 100644 extensions/sphinx/Schema.php delete mode 100644 extensions/sphinx/composer.json delete mode 100644 extensions/swiftmailer/LICENSE.md delete mode 100644 extensions/swiftmailer/Mailer.php delete mode 100644 extensions/swiftmailer/Message.php delete mode 100644 extensions/swiftmailer/README.md delete mode 100644 extensions/swiftmailer/composer.json create mode 100644 extensions/yii/bootstrap/Alert.php create mode 100644 extensions/yii/bootstrap/BootstrapAsset.php create mode 100644 extensions/yii/bootstrap/BootstrapPluginAsset.php create mode 100644 extensions/yii/bootstrap/BootstrapThemeAsset.php create mode 100644 extensions/yii/bootstrap/Button.php create mode 100644 extensions/yii/bootstrap/ButtonDropdown.php create mode 100644 extensions/yii/bootstrap/ButtonGroup.php create mode 100644 extensions/yii/bootstrap/Carousel.php create mode 100644 extensions/yii/bootstrap/Collapse.php create mode 100644 extensions/yii/bootstrap/Dropdown.php create mode 100644 extensions/yii/bootstrap/Modal.php create mode 100644 extensions/yii/bootstrap/Nav.php create mode 100644 extensions/yii/bootstrap/NavBar.php create mode 100644 extensions/yii/bootstrap/Progress.php create mode 100644 extensions/yii/bootstrap/README.md create mode 100644 extensions/yii/bootstrap/Tabs.php create mode 100644 extensions/yii/bootstrap/Widget.php create mode 100644 extensions/yii/bootstrap/composer.json create mode 100644 extensions/yii/composer/Installer.php create mode 100644 extensions/yii/composer/LICENSE.md create mode 100644 extensions/yii/composer/Plugin.php create mode 100644 extensions/yii/composer/README.md create mode 100644 extensions/yii/composer/composer.json create mode 100644 extensions/yii/debug/DebugAsset.php create mode 100644 extensions/yii/debug/LogTarget.php create mode 100644 extensions/yii/debug/Module.php create mode 100644 extensions/yii/debug/Panel.php create mode 100644 extensions/yii/debug/README.md create mode 100644 extensions/yii/debug/assets/main.css create mode 100644 extensions/yii/debug/composer.json create mode 100644 extensions/yii/debug/controllers/DefaultController.php create mode 100644 extensions/yii/debug/panels/ConfigPanel.php create mode 100644 extensions/yii/debug/panels/DbPanel.php create mode 100644 extensions/yii/debug/panels/LogPanel.php create mode 100644 extensions/yii/debug/panels/ProfilingPanel.php create mode 100644 extensions/yii/debug/panels/RequestPanel.php create mode 100644 extensions/yii/debug/views/default/index.php create mode 100644 extensions/yii/debug/views/default/toolbar.css create mode 100644 extensions/yii/debug/views/default/toolbar.js create mode 100644 extensions/yii/debug/views/default/toolbar.php create mode 100644 extensions/yii/debug/views/default/view.php create mode 100644 extensions/yii/debug/views/layouts/main.php create mode 100644 extensions/yii/elasticsearch/ActiveQuery.php create mode 100644 extensions/yii/elasticsearch/ActiveRecord.php create mode 100644 extensions/yii/elasticsearch/ActiveRelation.php create mode 100644 extensions/yii/elasticsearch/Command.php create mode 100644 extensions/yii/elasticsearch/Connection.php create mode 100644 extensions/yii/elasticsearch/DebugAction.php create mode 100644 extensions/yii/elasticsearch/DebugPanel.php create mode 100644 extensions/yii/elasticsearch/Exception.php create mode 100644 extensions/yii/elasticsearch/LICENSE.md create mode 100644 extensions/yii/elasticsearch/Query.php create mode 100644 extensions/yii/elasticsearch/QueryBuilder.php create mode 100644 extensions/yii/elasticsearch/README-debug.png create mode 100644 extensions/yii/elasticsearch/README.md create mode 100644 extensions/yii/elasticsearch/composer.json create mode 100644 extensions/yii/gii/CodeFile.php create mode 100644 extensions/yii/gii/Generator.php create mode 100644 extensions/yii/gii/GiiAsset.php create mode 100644 extensions/yii/gii/Module.php create mode 100644 extensions/yii/gii/README.md create mode 100644 extensions/yii/gii/assets/gii.js create mode 100644 extensions/yii/gii/assets/logo.png create mode 100644 extensions/yii/gii/assets/main.css create mode 100644 extensions/yii/gii/assets/typeahead.js create mode 100644 extensions/yii/gii/assets/typeahead.js-bootstrap.css create mode 100644 extensions/yii/gii/components/ActiveField.php create mode 100644 extensions/yii/gii/composer.json create mode 100644 extensions/yii/gii/controllers/DefaultController.php create mode 100644 extensions/yii/gii/generators/controller/Generator.php create mode 100644 extensions/yii/gii/generators/controller/form.php create mode 100644 extensions/yii/gii/generators/controller/templates/controller.php create mode 100644 extensions/yii/gii/generators/controller/templates/view.php create mode 100644 extensions/yii/gii/generators/crud/Generator.php create mode 100644 extensions/yii/gii/generators/crud/form.php create mode 100644 extensions/yii/gii/generators/crud/templates/controller.php create mode 100644 extensions/yii/gii/generators/crud/templates/search.php create mode 100644 extensions/yii/gii/generators/crud/templates/views/_form.php create mode 100644 extensions/yii/gii/generators/crud/templates/views/_search.php create mode 100644 extensions/yii/gii/generators/crud/templates/views/create.php create mode 100644 extensions/yii/gii/generators/crud/templates/views/index.php create mode 100644 extensions/yii/gii/generators/crud/templates/views/update.php create mode 100644 extensions/yii/gii/generators/crud/templates/views/view.php create mode 100644 extensions/yii/gii/generators/form/Generator.php create mode 100644 extensions/yii/gii/generators/form/form.php create mode 100644 extensions/yii/gii/generators/form/templates/action.php create mode 100644 extensions/yii/gii/generators/form/templates/form.php create mode 100644 extensions/yii/gii/generators/model/Generator.php create mode 100644 extensions/yii/gii/generators/model/form.php create mode 100644 extensions/yii/gii/generators/model/templates/model.php create mode 100644 extensions/yii/gii/generators/module/Generator.php create mode 100644 extensions/yii/gii/generators/module/form.php create mode 100644 extensions/yii/gii/generators/module/templates/controller.php create mode 100644 extensions/yii/gii/generators/module/templates/module.php create mode 100644 extensions/yii/gii/generators/module/templates/view.php create mode 100644 extensions/yii/gii/views/default/diff.php create mode 100644 extensions/yii/gii/views/default/index.php create mode 100644 extensions/yii/gii/views/default/view.php create mode 100644 extensions/yii/gii/views/default/view/files.php create mode 100644 extensions/yii/gii/views/default/view/results.php create mode 100644 extensions/yii/gii/views/layouts/generator.php create mode 100644 extensions/yii/gii/views/layouts/main.php create mode 100644 extensions/yii/jui/Accordion.php create mode 100644 extensions/yii/jui/AccordionAsset.php create mode 100644 extensions/yii/jui/AutoComplete.php create mode 100644 extensions/yii/jui/AutoCompleteAsset.php create mode 100644 extensions/yii/jui/ButtonAsset.php create mode 100644 extensions/yii/jui/CoreAsset.php create mode 100644 extensions/yii/jui/DatePicker.php create mode 100644 extensions/yii/jui/DatePickerAsset.php create mode 100644 extensions/yii/jui/DatePickerRegionalAsset.php create mode 100644 extensions/yii/jui/Dialog.php create mode 100644 extensions/yii/jui/DialogAsset.php create mode 100644 extensions/yii/jui/Draggable.php create mode 100644 extensions/yii/jui/DraggableAsset.php create mode 100644 extensions/yii/jui/Droppable.php create mode 100644 extensions/yii/jui/DroppableAsset.php create mode 100644 extensions/yii/jui/EffectAsset.php create mode 100644 extensions/yii/jui/InputWidget.php create mode 100644 extensions/yii/jui/LICENSE.md create mode 100644 extensions/yii/jui/Menu.php create mode 100644 extensions/yii/jui/MenuAsset.php create mode 100644 extensions/yii/jui/ProgressBar.php create mode 100644 extensions/yii/jui/ProgressBarAsset.php create mode 100644 extensions/yii/jui/README.md create mode 100644 extensions/yii/jui/Resizable.php create mode 100644 extensions/yii/jui/ResizableAsset.php create mode 100644 extensions/yii/jui/Selectable.php create mode 100644 extensions/yii/jui/SelectableAsset.php create mode 100644 extensions/yii/jui/Slider.php create mode 100644 extensions/yii/jui/SliderAsset.php create mode 100644 extensions/yii/jui/SliderInput.php create mode 100644 extensions/yii/jui/Sortable.php create mode 100644 extensions/yii/jui/SortableAsset.php create mode 100644 extensions/yii/jui/Spinner.php create mode 100644 extensions/yii/jui/SpinnerAsset.php create mode 100644 extensions/yii/jui/Tabs.php create mode 100644 extensions/yii/jui/TabsAsset.php create mode 100644 extensions/yii/jui/ThemeAsset.php create mode 100644 extensions/yii/jui/TooltipAsset.php create mode 100644 extensions/yii/jui/Widget.php create mode 100644 extensions/yii/jui/assets/UPGRADE.md create mode 100644 extensions/yii/jui/assets/jquery.ui.accordion.js create mode 100644 extensions/yii/jui/assets/jquery.ui.autocomplete.js create mode 100644 extensions/yii/jui/assets/jquery.ui.button.js create mode 100644 extensions/yii/jui/assets/jquery.ui.core.js create mode 100755 extensions/yii/jui/assets/jquery.ui.datepicker-i18n.js create mode 100644 extensions/yii/jui/assets/jquery.ui.datepicker.js create mode 100644 extensions/yii/jui/assets/jquery.ui.dialog.js create mode 100644 extensions/yii/jui/assets/jquery.ui.draggable.js create mode 100644 extensions/yii/jui/assets/jquery.ui.droppable.js create mode 100755 extensions/yii/jui/assets/jquery.ui.effect-all.js create mode 100644 extensions/yii/jui/assets/jquery.ui.menu.js create mode 100644 extensions/yii/jui/assets/jquery.ui.mouse.js create mode 100644 extensions/yii/jui/assets/jquery.ui.position.js create mode 100644 extensions/yii/jui/assets/jquery.ui.progressbar.js create mode 100644 extensions/yii/jui/assets/jquery.ui.resizable.js create mode 100644 extensions/yii/jui/assets/jquery.ui.selectable.js create mode 100644 extensions/yii/jui/assets/jquery.ui.slider.js create mode 100644 extensions/yii/jui/assets/jquery.ui.sortable.js create mode 100644 extensions/yii/jui/assets/jquery.ui.spinner.js create mode 100644 extensions/yii/jui/assets/jquery.ui.tabs.js create mode 100644 extensions/yii/jui/assets/jquery.ui.tooltip.js create mode 100644 extensions/yii/jui/assets/jquery.ui.widget.js create mode 100755 extensions/yii/jui/assets/theme/images/animated-overlay.gif create mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_flat_0_aaaaaa_40x100.png create mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_flat_75_ffffff_40x100.png create mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_glass_55_fbf9ee_1x400.png create mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_glass_65_ffffff_1x400.png create mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_glass_75_dadada_1x400.png create mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_glass_75_e6e6e6_1x400.png create mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_glass_95_fef1ec_1x400.png create mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png create mode 100755 extensions/yii/jui/assets/theme/images/ui-icons_222222_256x240.png create mode 100755 extensions/yii/jui/assets/theme/images/ui-icons_2e83ff_256x240.png create mode 100755 extensions/yii/jui/assets/theme/images/ui-icons_454545_256x240.png create mode 100755 extensions/yii/jui/assets/theme/images/ui-icons_888888_256x240.png create mode 100755 extensions/yii/jui/assets/theme/images/ui-icons_cd0a0a_256x240.png create mode 100755 extensions/yii/jui/assets/theme/jquery.ui.css create mode 100644 extensions/yii/jui/composer.json create mode 100644 extensions/yii/mongodb/ActiveQuery.php create mode 100644 extensions/yii/mongodb/ActiveRecord.php create mode 100644 extensions/yii/mongodb/ActiveRelation.php create mode 100644 extensions/yii/mongodb/Collection.php create mode 100644 extensions/yii/mongodb/Connection.php create mode 100644 extensions/yii/mongodb/Database.php create mode 100644 extensions/yii/mongodb/Exception.php create mode 100644 extensions/yii/mongodb/LICENSE.md create mode 100644 extensions/yii/mongodb/Query.php create mode 100644 extensions/yii/mongodb/README.md create mode 100644 extensions/yii/mongodb/composer.json create mode 100644 extensions/yii/mongodb/file/ActiveQuery.php create mode 100644 extensions/yii/mongodb/file/ActiveRecord.php create mode 100644 extensions/yii/mongodb/file/ActiveRelation.php create mode 100644 extensions/yii/mongodb/file/Collection.php create mode 100644 extensions/yii/mongodb/file/Query.php create mode 100644 extensions/yii/redis/ActiveQuery.php create mode 100644 extensions/yii/redis/ActiveRecord.php create mode 100644 extensions/yii/redis/ActiveRelation.php create mode 100644 extensions/yii/redis/Cache.php create mode 100644 extensions/yii/redis/Connection.php create mode 100644 extensions/yii/redis/LICENSE.md create mode 100644 extensions/yii/redis/LuaScriptBuilder.php create mode 100644 extensions/yii/redis/README.md create mode 100644 extensions/yii/redis/Session.php create mode 100644 extensions/yii/redis/composer.json create mode 100644 extensions/yii/sphinx/ActiveQuery.php create mode 100644 extensions/yii/sphinx/ActiveRecord.php create mode 100644 extensions/yii/sphinx/ActiveRelation.php create mode 100644 extensions/yii/sphinx/ColumnSchema.php create mode 100644 extensions/yii/sphinx/Command.php create mode 100644 extensions/yii/sphinx/Connection.php create mode 100644 extensions/yii/sphinx/IndexSchema.php create mode 100644 extensions/yii/sphinx/LICENSE.md create mode 100644 extensions/yii/sphinx/Query.php create mode 100644 extensions/yii/sphinx/QueryBuilder.php create mode 100644 extensions/yii/sphinx/README.md create mode 100644 extensions/yii/sphinx/Schema.php create mode 100644 extensions/yii/sphinx/composer.json create mode 100644 extensions/yii/swiftmailer/LICENSE.md create mode 100644 extensions/yii/swiftmailer/Mailer.php create mode 100644 extensions/yii/swiftmailer/Message.php create mode 100644 extensions/yii/swiftmailer/README.md create mode 100644 extensions/yii/swiftmailer/composer.json diff --git a/extensions/bootstrap/Alert.php b/extensions/bootstrap/Alert.php deleted file mode 100644 index 29844bd..0000000 --- a/extensions/bootstrap/Alert.php +++ /dev/null @@ -1,149 +0,0 @@ - 'Say hello...', - * 'closeButton' => [ - * 'label' => '×', - * 'tag' => 'a', - * ], - * ]); - * ``` - * - * The following example will show the content enclosed between the [[begin()]] - * and [[end()]] calls within the alert box: - * - * ```php - * Alert::begin([ - * 'closeButton' => ['label' => '×'], - * ]); - * - * echo 'Say hello...'; - * - * Alert::end(); - * ``` - * - * @see http://twitter.github.io/bootstrap/javascript.html#alerts - * @author Antonio Ramirez - * @since 2.0 - */ -class Alert extends Widget -{ - /** - * @var string the body content in the alert component. Note that anything between - * the [[begin()]] and [[end()]] calls of the Alert widget will also be treated - * as the body content, and will be rendered before this. - */ - public $body; - /** - * @var array the options for rendering the close button tag. - * The close button is displayed in the header of the modal window. Clicking - * on the button will hide the modal window. If this is null, no close button will be rendered. - * - * The following special options are supported: - * - * - tag: string, the tag name of the button. Defaults to 'button'. - * - label: string, the label of the button. Defaults to '×'. - * - * The rest of the options will be rendered as the HTML attributes of the button tag. - * Please refer to the [Alert plugin help](http://twitter.github.com/bootstrap/javascript.html#alerts) - * for the supported HTML attributes. - */ - public $closeButton = []; - - - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - - $this->initOptions(); - - echo Html::beginTag('div', $this->options) . "\n"; - echo $this->renderBodyBegin() . "\n"; - } - - /** - * Renders the widget. - */ - public function run() - { - echo "\n" . $this->renderBodyEnd(); - echo "\n" . Html::endTag('div'); - - $this->registerPlugin('alert'); - } - - /** - * Renders the close button if any before rendering the content. - * @return string the rendering result - */ - protected function renderBodyBegin() - { - return $this->renderCloseButton(); - } - - /** - * Renders the alert body (if any). - * @return string the rendering result - */ - protected function renderBodyEnd() - { - return $this->body . "\n"; - } - - /** - * Renders the close button. - * @return string the rendering result - */ - protected function renderCloseButton() - { - if ($this->closeButton !== null) { - $tag = ArrayHelper::remove($this->closeButton, 'tag', 'button'); - $label = ArrayHelper::remove($this->closeButton, 'label', '×'); - if ($tag === 'button' && !isset($this->closeButton['type'])) { - $this->closeButton['type'] = 'button'; - } - return Html::tag($tag, $label, $this->closeButton); - } else { - return null; - } - } - - /** - * Initializes the widget options. - * This method sets the default values for various options. - */ - protected function initOptions() - { - $this->options = array_merge(['class' => 'fade in'], $this->options); - - Html::addCssClass($this->options, 'alert'); - - if ($this->closeButton !== null) { - $this->closeButton = array_merge([ - 'data-dismiss' => 'alert', - 'aria-hidden' => 'true', - 'class' => 'close', - ], $this->closeButton); - } - } -} diff --git a/extensions/bootstrap/BootstrapAsset.php b/extensions/bootstrap/BootstrapAsset.php deleted file mode 100644 index 27dabc0..0000000 --- a/extensions/bootstrap/BootstrapAsset.php +++ /dev/null @@ -1,22 +0,0 @@ - - * @since 2.0 - */ -class BootstrapAsset extends AssetBundle -{ - public $sourcePath = '@vendor/twbs/bootstrap/dist'; - public $css = [ - 'css/bootstrap.css', - ]; -} diff --git a/extensions/bootstrap/BootstrapPluginAsset.php b/extensions/bootstrap/BootstrapPluginAsset.php deleted file mode 100644 index 35bf18a..0000000 --- a/extensions/bootstrap/BootstrapPluginAsset.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @since 2.0 - */ -class BootstrapPluginAsset extends AssetBundle -{ - public $sourcePath = '@vendor/twbs/bootstrap/dist'; - public $js = [ - 'js/bootstrap.js', - ]; - public $depends = [ - 'yii\web\JqueryAsset', - 'yii\bootstrap\BootstrapAsset', - ]; -} diff --git a/extensions/bootstrap/BootstrapThemeAsset.php b/extensions/bootstrap/BootstrapThemeAsset.php deleted file mode 100644 index f15a0fb..0000000 --- a/extensions/bootstrap/BootstrapThemeAsset.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @since 2.0 - */ -class BootstrapThemeAsset extends AssetBundle -{ - public $sourcePath = '@vendor/twbs/bootstrap/dist'; - public $css = [ - 'css/bootstrap-theme.css', - ]; - public $depends = [ - 'yii\bootstrap\BootstrapAsset', - ]; -} diff --git a/extensions/bootstrap/Button.php b/extensions/bootstrap/Button.php deleted file mode 100644 index 88acab7..0000000 --- a/extensions/bootstrap/Button.php +++ /dev/null @@ -1,62 +0,0 @@ - 'Action', - * 'options' => ['class' => 'btn-lg'], - * ]); - * ``` - * @see http://twitter.github.io/bootstrap/javascript.html#buttons - * @author Antonio Ramirez - * @since 2.0 - */ -class Button extends Widget -{ - /** - * @var string the tag to use to render the button - */ - public $tagName = 'button'; - /** - * @var string the button label - */ - public $label = 'Button'; - /** - * @var boolean whether the label should be HTML-encoded. - */ - public $encodeLabel = true; - - - /** - * Initializes the widget. - * If you override this method, make sure you call the parent implementation first. - */ - public function init() - { - parent::init(); - $this->clientOptions = false; - Html::addCssClass($this->options, 'btn'); - } - - /** - * Renders the widget. - */ - public function run() - { - echo Html::tag($this->tagName, $this->encodeLabel ? Html::encode($this->label) : $this->label, $this->options); - $this->registerPlugin('button'); - } -} diff --git a/extensions/bootstrap/ButtonDropdown.php b/extensions/bootstrap/ButtonDropdown.php deleted file mode 100644 index 1ffde7d..0000000 --- a/extensions/bootstrap/ButtonDropdown.php +++ /dev/null @@ -1,109 +0,0 @@ - 'Action', - * 'dropdown' => [ - * 'items' => [ - * ['label' => 'DropdownA', 'url' => '/'], - * ['label' => 'DropdownB', 'url' => '#'], - * ], - * ], - * ]); - * ``` - * @see http://twitter.github.io/bootstrap/javascript.html#buttons - * @see http://twitter.github.io/bootstrap/components.html#buttonDropdowns - * @author Antonio Ramirez - * @since 2.0 - */ -class ButtonDropdown extends Widget -{ - /** - * @var string the button label - */ - public $label = 'Button'; - /** - * @var array the HTML attributes of the button. - */ - public $options = []; - /** - * @var array the configuration array for [[Dropdown]]. - */ - public $dropdown = []; - /** - * @var boolean whether to display a group of split-styled button group. - */ - public $split = false; - - - /** - * Renders the widget. - */ - public function run() - { - echo $this->renderButton() . "\n" . $this->renderDropdown(); - $this->registerPlugin('button'); - } - - /** - * Generates the button dropdown. - * @return string the rendering result. - */ - protected function renderButton() - { - Html::addCssClass($this->options, 'btn'); - if ($this->split) { - $tag = 'button'; - $options = $this->options; - $this->options['data-toggle'] = 'dropdown'; - Html::addCssClass($this->options, 'dropdown-toggle'); - $splitButton = Button::widget([ - 'label' => '', - 'encodeLabel' => false, - 'options' => $this->options, - ]); - } else { - $tag = 'a'; - $this->label .= ' '; - $options = $this->options; - if (!isset($options['href'])) { - $options['href'] = '#'; - } - Html::addCssClass($options, 'dropdown-toggle'); - $options['data-toggle'] = 'dropdown'; - $splitButton = ''; - } - return Button::widget([ - 'tagName' => $tag, - 'label' => $this->label, - 'options' => $options, - 'encodeLabel' => false, - ]) . "\n" . $splitButton; - } - - /** - * Generates the dropdown menu. - * @return string the rendering result. - */ - protected function renderDropdown() - { - $config = $this->dropdown; - $config['clientOptions'] = false; - return Dropdown::widget($config); - } -} diff --git a/extensions/bootstrap/ButtonGroup.php b/extensions/bootstrap/ButtonGroup.php deleted file mode 100644 index 4fc2eb3..0000000 --- a/extensions/bootstrap/ButtonGroup.php +++ /dev/null @@ -1,97 +0,0 @@ - [ - * ['label' => 'A'], - * ['label' => 'B'], - * ] - * ]); - * - * // button group with an item as a string - * echo ButtonGroup::widget([ - * 'buttons' => [ - * Button::widget(['label' => 'A']), - * ['label' => 'B'], - * ] - * ]); - * ``` - * @see http://twitter.github.io/bootstrap/javascript.html#buttons - * @see http://twitter.github.io/bootstrap/components.html#buttonGroups - * @author Antonio Ramirez - * @since 2.0 - */ -class ButtonGroup extends Widget -{ - /** - * @var array list of buttons. Each array element represents a single button - * which can be specified as a string or an array of the following structure: - * - * - label: string, required, the button label. - * - options: array, optional, the HTML attributes of the button. - */ - public $buttons = []; - /** - * @var boolean whether to HTML-encode the button labels. - */ - public $encodeLabels = true; - - - /** - * Initializes the widget. - * If you override this method, make sure you call the parent implementation first. - */ - public function init() - { - parent::init(); - Html::addCssClass($this->options, 'btn-group'); - } - - /** - * Renders the widget. - */ - public function run() - { - echo Html::tag('div', $this->renderButtons(), $this->options); - BootstrapAsset::register($this->getView()); - } - - /** - * Generates the buttons that compound the group as specified on [[items]]. - * @return string the rendering result. - */ - protected function renderButtons() - { - $buttons = []; - foreach ($this->buttons as $button) { - if (is_array($button)) { - $label = ArrayHelper::getValue($button, 'label'); - $options = ArrayHelper::getValue($button, 'options'); - $buttons[] = Button::widget([ - 'label' => $label, - 'options' => $options, - 'encodeLabel' => $this->encodeLabels - ]); - } else { - $buttons[] = $button; - } - } - return implode("\n", $buttons); - } -} diff --git a/extensions/bootstrap/Carousel.php b/extensions/bootstrap/Carousel.php deleted file mode 100644 index 8344929..0000000 --- a/extensions/bootstrap/Carousel.php +++ /dev/null @@ -1,170 +0,0 @@ - [ - * // the item contains only the image - * '', - * // equivalent to the above - * ['content' => ''], - * // the item contains both the image and the caption - * [ - * 'content' => '', - * 'caption' => '

This is title

This is the caption text

', - * 'options' => [...], - * ], - * ] - * ]); - * ``` - * - * @see http://twitter.github.io/bootstrap/javascript.html#carousel - * @author Antonio Ramirez - * @since 2.0 - */ -class Carousel extends Widget -{ - /** - * @var array|boolean the labels for the previous and the next control buttons. - * If false, it means the previous and the next control buttons should not be displayed. - */ - public $controls = ['‹', '›']; - /** - * @var array list of slides in the carousel. Each array element represents a single - * slide with the following structure: - * - * ```php - * [ - * // required, slide content (HTML), such as an image tag - * 'content' => '', - * // optional, the caption (HTML) of the slide - * 'caption' => '

This is title

This is the caption text

', - * // optional the HTML attributes of the slide container - * 'options' => [], - * ] - * ``` - */ - public $items = []; - - - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - Html::addCssClass($this->options, 'carousel'); - } - - /** - * Renders the widget. - */ - public function run() - { - echo Html::beginTag('div', $this->options) . "\n"; - echo $this->renderIndicators() . "\n"; - echo $this->renderItems() . "\n"; - echo $this->renderControls() . "\n"; - echo Html::endTag('div') . "\n"; - $this->registerPlugin('carousel'); - } - - /** - * Renders carousel indicators. - * @return string the rendering result - */ - public function renderIndicators() - { - $indicators = []; - for ($i = 0, $count = count($this->items); $i < $count; $i++) { - $options = ['data-target' => '#' . $this->options['id'], 'data-slide-to' => $i]; - if ($i === 0) { - Html::addCssClass($options, 'active'); - } - $indicators[] = Html::tag('li', '', $options); - } - return Html::tag('ol', implode("\n", $indicators), ['class' => 'carousel-indicators']); - } - - /** - * Renders carousel items as specified on [[items]]. - * @return string the rendering result - */ - public function renderItems() - { - $items = []; - for ($i = 0, $count = count($this->items); $i < $count; $i++) { - $items[] = $this->renderItem($this->items[$i], $i); - } - return Html::tag('div', implode("\n", $items), ['class' => 'carousel-inner']); - } - - /** - * Renders a single carousel item - * @param string|array $item a single item from [[items]] - * @param integer $index the item index as the first item should be set to `active` - * @return string the rendering result - * @throws InvalidConfigException if the item is invalid - */ - public function renderItem($item, $index) - { - if (is_string($item)) { - $content = $item; - $caption = null; - $options = []; - } elseif (isset($item['content'])) { - $content = $item['content']; - $caption = ArrayHelper::getValue($item, 'caption'); - if ($caption !== null) { - $caption = Html::tag('div', $caption, ['class' => 'carousel-caption']); - } - $options = ArrayHelper::getValue($item, 'options', []); - } else { - throw new InvalidConfigException('The "content" option is required.'); - } - - Html::addCssClass($options, 'item'); - if ($index === 0) { - Html::addCssClass($options, 'active'); - } - - return Html::tag('div', $content . "\n" . $caption, $options); - } - - /** - * Renders previous and next control buttons. - * @throws InvalidConfigException if [[controls]] is invalid. - */ - public function renderControls() - { - if (isset($this->controls[0], $this->controls[1])) { - return Html::a($this->controls[0], '#' . $this->options['id'], [ - 'class' => 'left carousel-control', - 'data-slide' => 'prev', - ]) . "\n" - . Html::a($this->controls[1], '#' . $this->options['id'], [ - 'class' => 'right carousel-control', - 'data-slide' => 'next', - ]); - } elseif ($this->controls === false) { - return ''; - } else { - throw new InvalidConfigException('The "controls" property must be either false or an array of two elements.'); - } - } -} diff --git a/extensions/bootstrap/Collapse.php b/extensions/bootstrap/Collapse.php deleted file mode 100644 index 08bde22..0000000 --- a/extensions/bootstrap/Collapse.php +++ /dev/null @@ -1,133 +0,0 @@ - [ - * // equivalent to the above - * 'Collapsible Group Item #1' => [ - * 'content' => 'Anim pariatur cliche...', - * // open its content by default - * 'contentOptions' => ['class' => 'in'] - * ], - * // another group item - * 'Collapsible Group Item #2' => [ - * 'content' => 'Anim pariatur cliche...', - * 'contentOptions' => [...], - * 'options' => [...], - * ], - * ] - * ]); - * ``` - * - * @see http://twitter.github.io/bootstrap/javascript.html#collapse - * @author Antonio Ramirez - * @since 2.0 - */ -class Collapse extends Widget -{ - /** - * @var array list of groups in the collapse widget. Each array element represents a single - * group with the following structure: - * - * ```php - * // item key is the actual group header - * 'Collapsible Group Item #1' => [ - * // required, the content (HTML) of the group - * 'content' => 'Anim pariatur cliche...', - * // optional the HTML attributes of the content group - * 'contentOptions' => [], - * // optional the HTML attributes of the group - * 'options' => [], - * ] - * ``` - */ - public $items = []; - - - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - Html::addCssClass($this->options, 'accordion'); - } - - /** - * Renders the widget. - */ - public function run() - { - echo Html::beginTag('div', $this->options) . "\n"; - echo $this->renderItems() . "\n"; - echo Html::endTag('div') . "\n"; - $this->registerPlugin('collapse'); - } - - /** - * Renders collapsible items as specified on [[items]]. - * @return string the rendering result - */ - public function renderItems() - { - $items = []; - $index = 0; - foreach ($this->items as $header => $item) { - $options = ArrayHelper::getValue($item, 'options', []); - Html::addCssClass($options, 'accordion-group'); - $items[] = Html::tag('div', $this->renderItem($header, $item, ++$index), $options); - } - - return implode("\n", $items); - } - - /** - * Renders a single collapsible item group - * @param string $header a label of the item group [[items]] - * @param array $item a single item from [[items]] - * @param integer $index the item index as each item group content must have an id - * @return string the rendering result - * @throws InvalidConfigException - */ - public function renderItem($header, $item, $index) - { - if (isset($item['content'])) { - $id = $this->options['id'] . '-collapse' . $index; - $options = ArrayHelper::getValue($item, 'contentOptions', []); - $options['id'] = $id; - Html::addCssClass($options, 'accordion-body collapse'); - - $header = Html::a($header, '#' . $id, [ - 'class' => 'accordion-toggle', - 'data-toggle' => 'collapse', - 'data-parent' => '#' . $this->options['id'] - ]) . "\n"; - - $content = Html::tag('div', $item['content'], ['class' => 'accordion-inner']) . "\n"; - } else { - throw new InvalidConfigException('The "content" option is required.'); - } - $group = []; - - $group[] = Html::tag('div', $header, ['class' => 'accordion-heading']); - $group[] = Html::tag('div', $content, $options); - - return implode("\n", $group); - } -} diff --git a/extensions/bootstrap/Dropdown.php b/extensions/bootstrap/Dropdown.php deleted file mode 100644 index fecfb0b..0000000 --- a/extensions/bootstrap/Dropdown.php +++ /dev/null @@ -1,92 +0,0 @@ - - * @since 2.0 - */ -class Dropdown extends Widget -{ - /** - * @var array list of menu items in the dropdown. Each array element can be either an HTML string, - * or an array representing a single menu with the following structure: - * - * - label: string, required, the label of the item link - * - url: string, optional, the url of the item link. Defaults to "#". - * - visible: boolean, optional, whether this menu item is visible. Defaults to true. - * - linkOptions: array, optional, the HTML attributes of the item link. - * - options: array, optional, the HTML attributes of the item. - * - * To insert divider use ``. - */ - public $items = []; - /** - * @var boolean whether the labels for header items should be HTML-encoded. - */ - public $encodeLabels = true; - - - /** - * Initializes the widget. - * If you override this method, make sure you call the parent implementation first. - */ - public function init() - { - parent::init(); - Html::addCssClass($this->options, 'dropdown-menu'); - } - - /** - * Renders the widget. - */ - public function run() - { - echo $this->renderItems($this->items); - $this->registerPlugin('dropdown'); - } - - /** - * Renders menu items. - * @param array $items the menu items to be rendered - * @return string the rendering result. - * @throws InvalidConfigException if the label option is not specified in one of the items. - */ - protected function renderItems($items) - { - $lines = []; - foreach ($items as $i => $item) { - if (isset($item['visible']) && !$item['visible']) { - unset($items[$i]); - continue; - } - if (is_string($item)) { - $lines[] = $item; - continue; - } - if (!isset($item['label'])) { - throw new InvalidConfigException("The 'label' option is required."); - } - $label = $this->encodeLabels ? Html::encode($item['label']) : $item['label']; - $options = ArrayHelper::getValue($item, 'options', []); - $linkOptions = ArrayHelper::getValue($item, 'linkOptions', []); - $linkOptions['tabindex'] = '-1'; - $content = Html::a($label, ArrayHelper::getValue($item, 'url', '#'), $linkOptions); - $lines[] = Html::tag('li', $content, $options); - } - - return Html::tag('ul', implode("\n", $lines), $this->options); - } -} diff --git a/extensions/bootstrap/Modal.php b/extensions/bootstrap/Modal.php deleted file mode 100644 index 94a3997..0000000 --- a/extensions/bootstrap/Modal.php +++ /dev/null @@ -1,227 +0,0 @@ - '

Hello world

', - * 'toggleButton' => ['label' => 'click me'], - * ]); - * - * echo 'Say hello...'; - * - * Modal::end(); - * ~~~ - * - * @see http://twitter.github.io/bootstrap/javascript.html#modals - * @author Antonio Ramirez - * @author Qiang Xue - * @since 2.0 - */ -class Modal extends Widget -{ - /** - * @var string the header content in the modal window. - */ - public $header; - /** - * @var string the footer content in the modal window. - */ - public $footer; - /** - * @var array the options for rendering the close button tag. - * The close button is displayed in the header of the modal window. Clicking - * on the button will hide the modal window. If this is null, no close button will be rendered. - * - * The following special options are supported: - * - * - tag: string, the tag name of the button. Defaults to 'button'. - * - label: string, the label of the button. Defaults to '×'. - * - * The rest of the options will be rendered as the HTML attributes of the button tag. - * Please refer to the [Modal plugin help](http://twitter.github.com/bootstrap/javascript.html#modals) - * for the supported HTML attributes. - */ - public $closeButton = []; - /** - * @var array the options for rendering the toggle button tag. - * The toggle button is used to toggle the visibility of the modal window. - * If this property is null, no toggle button will be rendered. - * - * The following special options are supported: - * - * - tag: string, the tag name of the button. Defaults to 'button'. - * - label: string, the label of the button. Defaults to 'Show'. - * - * The rest of the options will be rendered as the HTML attributes of the button tag. - * Please refer to the [Modal plugin help](http://twitter.github.com/bootstrap/javascript.html#modals) - * for the supported HTML attributes. - */ - public $toggleButton; - - - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - - $this->initOptions(); - - echo $this->renderToggleButton() . "\n"; - echo Html::beginTag('div', $this->options) . "\n"; - echo Html::beginTag('div', ['class' => 'modal-dialog']) . "\n"; - echo Html::beginTag('div', ['class' => 'modal-content']) . "\n"; - echo $this->renderHeader() . "\n"; - echo $this->renderBodyBegin() . "\n"; - } - - /** - * Renders the widget. - */ - public function run() - { - echo "\n" . $this->renderBodyEnd(); - echo "\n" . $this->renderFooter(); - echo "\n" . Html::endTag('div'); // modal-content - echo "\n" . Html::endTag('div'); // modal-dialog - echo "\n" . Html::endTag('div'); - - $this->registerPlugin('modal'); - } - - /** - * Renders the header HTML markup of the modal - * @return string the rendering result - */ - protected function renderHeader() - { - $button = $this->renderCloseButton(); - if ($button !== null) { - $this->header = $button . "\n" . $this->header; - } - if ($this->header !== null) { - return Html::tag('div', "\n" . $this->header . "\n", ['class' => 'modal-header']); - } else { - return null; - } - } - - /** - * Renders the opening tag of the modal body. - * @return string the rendering result - */ - protected function renderBodyBegin() - { - return Html::beginTag('div', ['class' => 'modal-body']); - } - - /** - * Renders the closing tag of the modal body. - * @return string the rendering result - */ - protected function renderBodyEnd() - { - return Html::endTag('div'); - } - - /** - * Renders the HTML markup for the footer of the modal - * @return string the rendering result - */ - protected function renderFooter() - { - if ($this->footer !== null) { - return Html::tag('div', "\n" . $this->footer . "\n", ['class' => 'modal-footer']); - } else { - return null; - } - } - - /** - * Renders the toggle button. - * @return string the rendering result - */ - protected function renderToggleButton() - { - if ($this->toggleButton !== null) { - $tag = ArrayHelper::remove($this->toggleButton, 'tag', 'button'); - $label = ArrayHelper::remove($this->toggleButton, 'label', 'Show'); - if ($tag === 'button' && !isset($this->toggleButton['type'])) { - $this->toggleButton['type'] = 'button'; - } - return Html::tag($tag, $label, $this->toggleButton); - } else { - return null; - } - } - - /** - * Renders the close button. - * @return string the rendering result - */ - protected function renderCloseButton() - { - if ($this->closeButton !== null) { - $tag = ArrayHelper::remove($this->closeButton, 'tag', 'button'); - $label = ArrayHelper::remove($this->closeButton, 'label', '×'); - if ($tag === 'button' && !isset($this->closeButton['type'])) { - $this->closeButton['type'] = 'button'; - } - return Html::tag($tag, $label, $this->closeButton); - } else { - return null; - } - } - - /** - * Initializes the widget options. - * This method sets the default values for various options. - */ - protected function initOptions() - { - $this->options = array_merge([ - 'class' => 'fade', - 'role' => 'dialog', - 'tabindex' => -1, - ], $this->options); - Html::addCssClass($this->options, 'modal'); - - if ($this->clientOptions !== false) { - $this->clientOptions = array_merge(['show' => false], $this->clientOptions); - } - - if ($this->closeButton !== null) { - $this->closeButton = array_merge([ - 'data-dismiss' => 'modal', - 'aria-hidden' => 'true', - 'class' => 'close', - ], $this->closeButton); - } - - if ($this->toggleButton !== null) { - $this->toggleButton = array_merge([ - 'data-toggle' => 'modal', - ], $this->toggleButton); - if (!isset($this->toggleButton['data-target']) && !isset($this->toggleButton['href'])) { - $this->toggleButton['data-target'] = '#' . $this->options['id']; - } - } - } -} diff --git a/extensions/bootstrap/Nav.php b/extensions/bootstrap/Nav.php deleted file mode 100644 index ef45f09..0000000 --- a/extensions/bootstrap/Nav.php +++ /dev/null @@ -1,214 +0,0 @@ - [ - * [ - * 'label' => 'Home', - * 'url' => ['site/index'], - * 'linkOptions' => [...], - * ], - * [ - * 'label' => 'Dropdown', - * 'items' => [ - * ['label' => 'Level 1 - Dropdown A', 'url' => '#'], - * '
  • ', - * '', - * ['label' => 'Level 1 - Dropdown B', 'url' => '#'], - * ], - * ], - * ], - * ]); - * ``` - * - * Note: Multilevel dropdowns beyond Level 1 are not supported in Bootstrap 3. - * - * @see http://getbootstrap.com/components.html#dropdowns - * @see http://getbootstrap.com/components/#nav - * - * @author Antonio Ramirez - * @since 2.0 - */ -class Nav extends Widget -{ - /** - * @var array list of items in the nav widget. Each array element represents a single - * menu item which can be either a string or an array with the following structure: - * - * - label: string, required, the nav item label. - * - url: optional, the item's URL. Defaults to "#". - * - visible: boolean, optional, whether this menu item is visible. Defaults to true. - * - linkOptions: array, optional, the HTML attributes of the item's link. - * - options: array, optional, the HTML attributes of the item container (LI). - * - active: boolean, optional, whether the item should be on active state or not. - * - items: array|string, optional, the configuration array for creating a [[Dropdown]] widget, - * or a string representing the dropdown menu. Note that Bootstrap does not support sub-dropdown menus. - * - * If a menu item is a string, it will be rendered directly without HTML encoding. - */ - public $items = []; - /** - * @var boolean whether the nav items labels should be HTML-encoded. - */ - public $encodeLabels = true; - /** - * @var boolean whether to automatically activate items according to whether their route setting - * matches the currently requested route. - * @see isItemActive - */ - public $activateItems = true; - /** - * @var string the route used to determine if a menu item is active or not. - * If not set, it will use the route of the current request. - * @see params - * @see isItemActive - */ - public $route; - /** - * @var array the parameters used to determine if a menu item is active or not. - * If not set, it will use `$_GET`. - * @see route - * @see isItemActive - */ - public $params; - - - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - if ($this->route === null && Yii::$app->controller !== null) { - $this->route = Yii::$app->controller->getRoute(); - } - if ($this->params === null) { - $this->params = $_GET; - } - Html::addCssClass($this->options, 'nav'); - } - - /** - * Renders the widget. - */ - public function run() - { - echo $this->renderItems(); - BootstrapAsset::register($this->getView()); - } - - /** - * Renders widget items. - */ - public function renderItems() - { - $items = []; - foreach ($this->items as $i => $item) { - if (isset($item['visible']) && !$item['visible']) { - unset($items[$i]); - continue; - } - $items[] = $this->renderItem($item); - } - - return Html::tag('ul', implode("\n", $items), $this->options); - } - - /** - * Renders a widget's item. - * @param string|array $item the item to render. - * @return string the rendering result. - * @throws InvalidConfigException - */ - public function renderItem($item) - { - if (is_string($item)) { - return $item; - } - if (!isset($item['label'])) { - throw new InvalidConfigException("The 'label' option is required."); - } - $label = $this->encodeLabels ? Html::encode($item['label']) : $item['label']; - $options = ArrayHelper::getValue($item, 'options', []); - $items = ArrayHelper::getValue($item, 'items'); - $url = Html::url(ArrayHelper::getValue($item, 'url', '#')); - $linkOptions = ArrayHelper::getValue($item, 'linkOptions', []); - - if (isset($item['active'])) { - $active = ArrayHelper::remove($item, 'active', false); - } else { - $active = $this->isItemActive($item); - } - - if ($active) { - Html::addCssClass($options, 'active'); - } - - if ($items !== null) { - $linkOptions['data-toggle'] = 'dropdown'; - Html::addCssClass($options, 'dropdown'); - Html::addCssClass($urlOptions, 'dropdown-toggle'); - $label .= ' ' . Html::tag('b', '', ['class' => 'caret']); - if (is_array($items)) { - $items = Dropdown::widget([ - 'items' => $items, - 'encodeLabels' => $this->encodeLabels, - 'clientOptions' => false, - ]); - } - } - - return Html::tag('li', Html::a($label, $url, $linkOptions) . $items, $options); - } - - - /** - * Checks whether a menu item is active. - * This is done by checking if [[route]] and [[params]] match that specified in the `url` option of the menu item. - * When the `url` option of a menu item is specified in terms of an array, its first element is treated - * as the route for the item and the rest of the elements are the associated parameters. - * Only when its route and parameters match [[route]] and [[params]], respectively, will a menu item - * be considered active. - * @param array $item the menu item to be checked - * @return boolean whether the menu item is active - */ - protected function isItemActive($item) - { - if (isset($item['url']) && is_array($item['url']) && isset($item['url'][0])) { - $route = $item['url'][0]; - if ($route[0] !== '/' && Yii::$app->controller) { - $route = Yii::$app->controller->module->getUniqueId() . '/' . $route; - } - if (ltrim($route, '/') !== $this->route) { - return false; - } - unset($item['url']['#']); - if (count($item['url']) > 1) { - foreach (array_splice($item['url'], 1) as $name => $value) { - if (!isset($this->params[$name]) || $this->params[$name] != $value) { - return false; - } - } - } - return true; - } - return false; - } -} diff --git a/extensions/bootstrap/NavBar.php b/extensions/bootstrap/NavBar.php deleted file mode 100644 index 620f51e..0000000 --- a/extensions/bootstrap/NavBar.php +++ /dev/null @@ -1,108 +0,0 @@ - 'NavBar Test']); - * echo Nav::widget([ - * 'items' => [ - * ['label' => 'Home', 'url' => ['/site/index']], - * ['label' => 'About', 'url' => ['/site/about']], - * ], - * ]); - * NavBar::end(); - * ``` - * - * @see http://twitter.github.io/bootstrap/components.html#navbar - * @author Antonio Ramirez - * @since 2.0 - */ -class NavBar extends Widget -{ - /** - * @var string the text of the brand. Note that this is not HTML-encoded. - * @see http://twitter.github.io/bootstrap/components.html#navbar - */ - public $brandLabel; - /** - * @param array|string $url the URL for the brand's hyperlink tag. This parameter will be processed by [[Html::url()]] - * and will be used for the "href" attribute of the brand link. Defaults to site root. - */ - public $brandUrl = '/'; - /** - * @var array the HTML attributes of the brand link. - */ - public $brandOptions = []; - - public $screenReaderToggleText = 'Toggle navigation'; - - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - $this->clientOptions = false; - Html::addCssClass($this->options, 'navbar navbar-default'); - Html::addCssClass($this->brandOptions, 'navbar-brand'); - if (empty($this->options['role'])) { - $this->options['role'] = 'navigation'; - } - - echo Html::beginTag('nav', $this->options); - echo Html::beginTag('div', ['class' => 'container']); - - echo Html::beginTag('div', ['class' => 'navbar-header']); - echo $this->renderToggleButton(); - if ($this->brandLabel !== null) { - echo Html::a($this->brandLabel, $this->brandUrl, $this->brandOptions); - } - echo Html::endTag('div'); - - echo Html::beginTag('div', ['class' => 'collapse navbar-collapse navbar-ex1-collapse']); - } - - /** - * Renders the widget. - */ - public function run() - { - - echo Html::endTag('div'); - echo Html::endTag('div'); - echo Html::endTag('nav'); - BootstrapPluginAsset::register($this->getView()); - } - - /** - * Renders collapsible toggle button. - * @return string the rendering toggle button. - */ - protected function renderToggleButton() - { - $bar = Html::tag('span', '', ['class' => 'icon-bar']); - $screenReader = ''.$this->screenReaderToggleText.''; - return Html::button("{$screenReader}\n{$bar}\n{$bar}\n{$bar}", [ - 'class' => 'navbar-toggle', - 'data-toggle' => 'collapse', - 'data-target' => '.navbar-ex1-collapse', - ]); - } -} diff --git a/extensions/bootstrap/Progress.php b/extensions/bootstrap/Progress.php deleted file mode 100644 index 184451c..0000000 --- a/extensions/bootstrap/Progress.php +++ /dev/null @@ -1,146 +0,0 @@ - 60, - * 'label' => 'test', - * ]); - * - * // styled - * echo Progress::widget([ - * 'percent' => 65, - * 'barOptions' => ['class' => 'bar-danger'] - * ]); - * - * // striped - * echo Progress::widget([ - * 'percent' => 70, - * 'barOptions' => ['class' => 'bar-warning'], - * 'options' => ['class' => 'progress-striped'] - * ]); - * - * // striped animated - * echo Progress::widget([ - * 'percent' => 70, - * 'barOptions' => ['class' => 'bar-success'], - * 'options' => ['class' => 'active progress-striped'] - * ]); - * - * // stacked bars - * echo Progress::widget([ - * 'bars' => [ - * ['percent' => 30, 'options' => ['class' => 'bar-danger']], - * ['percent' => 30, 'label' => 'test', 'options' => ['class' => 'bar-success']], - * ['percent' => 35, 'options' => ['class' => 'bar-warning']], - * ] - * ]); - * ``` - * @see http://twitter.github.io/bootstrap/components.html#progress - * @author Antonio Ramirez - * @since 2.0 - */ -class Progress extends Widget -{ - /** - * @var string the button label - */ - public $label; - /** - * @var integer the amount of progress as a percentage. - */ - public $percent = 0; - /** - * @var array the HTML attributes of the - */ - public $barOptions = []; - /** - * @var array a set of bars that are stacked together to form a single progress bar. - * Each bar is an array of the following structure: - * - * ```php - * [ - * // required, the amount of progress as a percentage. - * 'percent' => 30, - * // optional, the label to be displayed on the bar - * 'label' => '30%', - * // optional, array, additional HTML attributes for the bar tag - * 'options' => [], - * ] - */ - public $bars; - - - /** - * Initializes the widget. - * If you override this method, make sure you call the parent implementation first. - */ - public function init() - { - parent::init(); - Html::addCssClass($this->options, 'progress'); - } - - /** - * Renders the widget. - */ - public function run() - { - echo Html::beginTag('div', $this->options) . "\n"; - echo $this->renderProgress() . "\n"; - echo Html::endTag('div') . "\n"; - BootstrapAsset::register($this->getView()); - } - - /** - * Renders the progress. - * @return string the rendering result. - * @throws InvalidConfigException if the "percent" option is not set in a stacked progress bar. - */ - protected function renderProgress() - { - if (empty($this->bars)) { - return $this->renderBar($this->percent, $this->label, $this->barOptions); - } - $bars = []; - foreach ($this->bars as $bar) { - $label = ArrayHelper::getValue($bar, 'label', ''); - if (!isset($bar['percent'])) { - throw new InvalidConfigException("The 'percent' option is required."); - } - $options = ArrayHelper::getValue($bar, 'options', []); - $bars[] = $this->renderBar($bar['percent'], $label, $options); - } - return implode("\n", $bars); - } - - /** - * Generates a bar - * @param int $percent the percentage of the bar - * @param string $label, optional, the label to display at the bar - * @param array $options the HTML attributes of the bar - * @return string the rendering result. - */ - protected function renderBar($percent, $label = '', $options = []) - { - Html::addCssClass($options, 'bar'); - $options['style'] = "width:{$percent}%"; - return Html::tag('div', $label, $options); - } -} diff --git a/extensions/bootstrap/README.md b/extensions/bootstrap/README.md deleted file mode 100644 index e199f64..0000000 --- a/extensions/bootstrap/README.md +++ /dev/null @@ -1,32 +0,0 @@ -Twitter Bootstrap Extension for Yii 2 -===================================== - -This is the Twitter Bootstrap extension for Yii 2. It encapsulates Bootstrap components -and plugins in terms of Yii widgets, and thus makes using Bootstrap components/plugins -in Yii applications extremely easy. For example, the following -single line of code in a view file would render a Bootstrap Progress plugin: - -```php - 60, 'label' => 'test']) ?> -``` - - -Installation ------------- - -The preferred way to install this extension is through [composer](http://getcomposer.org/download/). - -Either run - -``` -php composer.phar require yiisoft/yii2-bootstrap "*" -``` - -or add - -``` -"yiisoft/yii2-bootstrap": "*" -``` - -to the require section of your `composer.json` file. - diff --git a/extensions/bootstrap/Tabs.php b/extensions/bootstrap/Tabs.php deleted file mode 100644 index 2e76398..0000000 --- a/extensions/bootstrap/Tabs.php +++ /dev/null @@ -1,199 +0,0 @@ - [ - * [ - * 'label' => 'One', - * 'content' => 'Anim pariatur cliche...', - * 'active' => true - * ], - * [ - * 'label' => 'Two', - * 'content' => 'Anim pariatur cliche...', - * 'headerOptions' => [...], - * 'options' => ['id' => 'myveryownID'], - * ], - * [ - * 'label' => 'Dropdown', - * 'items' => [ - * [ - * 'label' => 'DropdownA', - * 'content' => 'DropdownA, Anim pariatur cliche...', - * ], - * [ - * 'label' => 'DropdownB', - * 'content' => 'DropdownB, Anim pariatur cliche...', - * ], - * ], - * ], - * ], - * ]); - * ``` - * - * @see http://twitter.github.io/bootstrap/javascript.html#tabs - * @author Antonio Ramirez - * @since 2.0 - */ -class Tabs extends Widget -{ - /** - * @var array list of tabs in the tabs widget. Each array element represents a single - * tab with the following structure: - * - * - label: string, required, the tab header label. - * - headerOptions: array, optional, the HTML attributes of the tab header. - * - content: array, required if `items` is not set. The content (HTML) of the tab pane. - * - options: array, optional, the HTML attributes of the tab pane container. - * - active: boolean, optional, whether the item tab header and pane should be visible or not. - * - items: array, optional, if not set then `content` will be required. The `items` specify a dropdown items - * configuration array. Each item can hold two extra keys, besides the above ones: - * * active: boolean, optional, whether the item tab header and pane should be visible or not. - * * content: string, required if `items` is not set. The content (HTML) of the tab pane. - * * contentOptions: optional, array, the HTML attributes of the tab content container. - */ - public $items = []; - /** - * @var array list of HTML attributes for the item container tags. This will be overwritten - * by the "options" set in individual [[items]]. The following special options are recognized: - * - * - tag: string, defaults to "div", the tag name of the item container tags. - */ - public $itemOptions = []; - /** - * @var array list of HTML attributes for the header container tags. This will be overwritten - * by the "headerOptions" set in individual [[items]]. - */ - public $headerOptions = []; - /** - * @var boolean whether the labels for header items should be HTML-encoded. - */ - public $encodeLabels = true; - /** - * @var string, specifies the Bootstrap tab styling. - */ - public $navType = 'nav-tabs'; - - - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - Html::addCssClass($this->options, 'nav ' . $this->navType); - } - - /** - * Renders the widget. - */ - public function run() - { - echo $this->renderItems(); - $this->registerPlugin('tab'); - } - - /** - * Renders tab items as specified on [[items]]. - * @return string the rendering result. - * @throws InvalidConfigException. - */ - protected function renderItems() - { - $headers = []; - $panes = []; - foreach ($this->items as $n => $item) { - if (!isset($item['label'])) { - throw new InvalidConfigException("The 'label' option is required."); - } - $label = $this->encodeLabels ? Html::encode($item['label']) : $item['label']; - $headerOptions = array_merge($this->headerOptions, ArrayHelper::getValue($item, 'headerOptions', [])); - - if (isset($item['items'])) { - $label .= ' '; - Html::addCssClass($headerOptions, 'dropdown'); - - if ($this->renderDropdown($item['items'], $panes)) { - Html::addCssClass($headerOptions, 'active'); - } - - $header = Html::a($label, "#", ['class' => 'dropdown-toggle', 'data-toggle' => 'dropdown']) . "\n" - . Dropdown::widget(['items' => $item['items'], 'clientOptions' => false]); - } elseif (isset($item['content'])) { - $options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', [])); - $options['id'] = ArrayHelper::getValue($options, 'id', $this->options['id'] . '-tab' . $n); - - Html::addCssClass($options, 'tab-pane'); - if (ArrayHelper::remove($item, 'active')) { - Html::addCssClass($options, 'active'); - Html::addCssClass($headerOptions, 'active'); - } - $header = Html::a($label, '#' . $options['id'], ['data-toggle' => 'tab']); - $panes[] = Html::tag('div', $item['content'], $options); - } else { - throw new InvalidConfigException("Either the 'content' or 'items' option must be set."); - } - - $headers[] = Html::tag('li', $header, $headerOptions); - } - - return Html::tag('ul', implode("\n", $headers), $this->options) . "\n" - . Html::tag('div', implode("\n", $panes), ['class' => 'tab-content']); - } - - /** - * Normalizes dropdown item options by removing tab specific keys `content` and `contentOptions`, and also - * configure `panes` accordingly. - * @param array $items the dropdown items configuration. - * @param array $panes the panes reference array. - * @return boolean whether any of the dropdown items is `active` or not. - * @throws InvalidConfigException - */ - protected function renderDropdown(&$items, &$panes) - { - $itemActive = false; - - foreach ($items as $n => &$item) { - if (is_string($item)) { - continue; - } - if (!isset($item['content'])) { - throw new InvalidConfigException("The 'content' option is required."); - } - - $content = ArrayHelper::remove($item, 'content'); - $options = ArrayHelper::remove($item, 'contentOptions', []); - Html::addCssClass($options, 'tab-pane'); - if (ArrayHelper::remove($item, 'active')) { - Html::addCssClass($options, 'active'); - Html::addCssClass($item['options'], 'active'); - $itemActive = true; - } - - $options['id'] = ArrayHelper::getValue($options, 'id', $this->options['id'] . '-dd-tab' . $n); - $item['url'] = '#' . $options['id']; - $item['linkOptions']['data-toggle'] = 'tab'; - - $panes[] = Html::tag('div', $content, $options); - - unset($item); - } - return $itemActive; - } -} diff --git a/extensions/bootstrap/Widget.php b/extensions/bootstrap/Widget.php deleted file mode 100644 index ff4084d..0000000 --- a/extensions/bootstrap/Widget.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @author Qiang Xue - * @since 2.0 - */ -class Widget extends \yii\base\Widget -{ - /** - * @var array the HTML attributes for the widget container tag. - */ - public $options = []; - /** - * @var array the options for the underlying Bootstrap JS plugin. - * Please refer to the corresponding Bootstrap plugin Web page for possible options. - * For example, [this page](http://twitter.github.io/bootstrap/javascript.html#modals) shows - * how to use the "Modal" plugin and the supported options (e.g. "remote"). - */ - public $clientOptions = []; - /** - * @var array the event handlers for the underlying Bootstrap JS plugin. - * Please refer to the corresponding Bootstrap plugin Web page for possible events. - * For example, [this page](http://twitter.github.io/bootstrap/javascript.html#modals) shows - * how to use the "Modal" plugin and the supported events (e.g. "shown"). - */ - public $clientEvents = []; - - - /** - * Initializes the widget. - * This method will register the bootstrap asset bundle. If you override this method, - * make sure you call the parent implementation first. - */ - public function init() - { - parent::init(); - if (!isset($this->options['id'])) { - $this->options['id'] = $this->getId(); - } - } - - /** - * Registers a specific Bootstrap plugin and the related events - * @param string $name the name of the Bootstrap plugin - */ - protected function registerPlugin($name) - { - $view = $this->getView(); - - BootstrapPluginAsset::register($view); - - $id = $this->options['id']; - - if ($this->clientOptions !== false) { - $options = empty($this->clientOptions) ? '' : Json::encode($this->clientOptions); - $js = "jQuery('#$id').$name($options);"; - $view->registerJs($js); - } - - if (!empty($this->clientEvents)) { - $js = []; - foreach ($this->clientEvents as $event => $handler) { - $js[] = "jQuery('#$id').on('$event', $handler);"; - } - $view->registerJs(implode("\n", $js)); - } - } -} diff --git a/extensions/bootstrap/composer.json b/extensions/bootstrap/composer.json deleted file mode 100644 index 3e6031e..0000000 --- a/extensions/bootstrap/composer.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "yiisoft/yii2-bootstrap", - "description": "The Twitter Bootstrap extension for the Yii framework", - "keywords": ["yii", "bootstrap"], - "type": "yii2-extension", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?labels=ext%3Abootstrap", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "authors": [ - { - "name": "Qiang Xue", - "email": "qiang.xue@gmail.com" - } - ], - "require": { - "yiisoft/yii2": "*", - "twbs/bootstrap": "3.0.*" - }, - "autoload": { - "psr-0": { "yii\\bootstrap\\": "" } - }, - "target-dir": "yii/bootstrap" -} diff --git a/extensions/composer/Installer.php b/extensions/composer/Installer.php deleted file mode 100644 index d8d799f..0000000 --- a/extensions/composer/Installer.php +++ /dev/null @@ -1,234 +0,0 @@ - - * @since 2.0 - */ -class Installer extends LibraryInstaller -{ - const EXTRA_BOOTSTRAP = 'bootstrap'; - const EXTRA_WRITABLE = 'writable'; - const EXTRA_EXECUTABLE = 'executable'; - - const EXTENSION_FILE = 'yiisoft/extensions.php'; - - /** - * @inheritdoc - */ - public function supports($packageType) - { - return $packageType === 'yii2-extension'; - } - - /** - * @inheritdoc - */ - public function install(InstalledRepositoryInterface $repo, PackageInterface $package) - { - // install the package the normal composer way - parent::install($repo, $package); - // add the package to yiisoft/extensions.php - $this->addPackage($package); - // ensure the yii2-dev package also provides Yii.php in the same place as yii2 does - if ($package->getName() == 'yiisoft/yii2-dev') { - $this->linkYiiBaseFiles(); - } - } - - /** - * @inheritdoc - */ - public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) - { - parent::update($repo, $initial, $target); - $this->removePackage($initial); - $this->addPackage($target); - // ensure the yii2-dev package also provides Yii.php in the same place as yii2 does - if ($initial->getName() == 'yiisoft/yii2-dev') { - $this->linkYiiBaseFiles(); - } - } - - /** - * @inheritdoc - */ - public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) - { - // uninstall the package the normal composer way - parent::uninstall($repo, $package); - // remove the package from yiisoft/extensions.php - $this->removePackage($package); - // remove links for Yii.php - if ($package->getName() == 'yiisoft/yii2-dev') { - $this->removeYiiBaseFiles(); - } - } - - protected function addPackage(PackageInterface $package) - { - $extension = [ - 'name' => $package->getName(), - 'version' => $package->getVersion(), - ]; - - $alias = $this->generateDefaultAlias($package); - if (!empty($alias)) { - $extension['alias'] = $alias; - } - $extra = $package->getExtra(); - if (isset($extra[self::EXTRA_BOOTSTRAP]) && is_string($extra[self::EXTRA_BOOTSTRAP])) { - $extension['bootstrap'] = $extra[self::EXTRA_BOOTSTRAP]; - } - - $extensions = $this->loadExtensions(); - $extensions[$package->getName()] = $extension; - $this->saveExtensions($extensions); - } - - protected function generateDefaultAlias(PackageInterface $package) - { - $autoload = $package->getAutoload(); - if (empty($autoload['psr-0'])) { - return false; - } - $fs = new Filesystem; - $vendorDir = $fs->normalizePath($this->vendorDir); - $aliases = []; - foreach ($autoload['psr-0'] as $name => $path) { - $name = str_replace('\\', '/', trim($name, '\\')); - if (!$fs->isAbsolutePath($path)) { - $path = $this->vendorDir . '/' . $package->getName() . '/' . $path; - } - $path = $fs->normalizePath($path); - if (strpos($path . '/', $vendorDir . '/') === 0) { - $aliases["@$name"] = '' . substr($path, strlen($vendorDir)) . '/' . $name; - } else { - $aliases["@$name"] = $path . '/' . $name; - } - } - return $aliases; - } - - protected function removePackage(PackageInterface $package) - { - $packages = $this->loadExtensions(); - unset($packages[$package->getName()]); - $this->saveExtensions($packages); - } - - protected function loadExtensions() - { - $file = $this->vendorDir . '/' . self::EXTENSION_FILE; - if (!is_file($file)) { - return []; - } - $extensions = require($file); - - $vendorDir = str_replace('\\', '/', $this->vendorDir); - $n = strlen($vendorDir); - - foreach ($extensions as &$extension) { - if (isset($extension['alias'])) { - foreach ($extension['alias'] as $alias => $path) { - $path = str_replace('\\', '/', $path); - if (strpos($path . '/', $vendorDir . '/') === 0) { - $extension['alias'][$alias] = '' . substr($path, $n); - } - } - } - } - - return $extensions; - } - - protected function saveExtensions(array $extensions) - { - $file = $this->vendorDir . '/' . self::EXTENSION_FILE; - $array = str_replace("'", '$vendorDir . \'', var_export($extensions, true)); - file_put_contents($file, "vendorDir . '/yiisoft/yii2/yii'; - if (!file_exists($yiiDir)) { - mkdir($yiiDir, 0777, true); - } - foreach(['Yii.php', 'YiiBase.php', 'classes.php'] as $file) { - file_put_contents($yiiDir . '/' . $file, <<vendorDir . '/yiisoft/yii2/yii'; - foreach(['Yii.php', 'YiiBase.php', 'classes.php'] as $file) { - if (file_exists($yiiDir . '/' . $file)) { - unlink($yiiDir . '/' . $file); - } - } - if (file_exists($yiiDir)) { - rmdir($yiiDir); - } - } - - /** - * Sets the correct permission for the files and directories listed in the extra section. - * @param CommandEvent $event - */ - public static function setPermission($event) - { - $options = array_merge([ - self::EXTRA_WRITABLE => [], - self::EXTRA_EXECUTABLE => [], - ], $event->getComposer()->getPackage()->getExtra()); - - foreach ((array)$options[self::EXTRA_WRITABLE] as $path) { - echo "Setting writable: $path ..."; - if (is_dir($path)) { - chmod($path, 0777); - echo "done\n"; - } else { - echo "The directory was not found: " . getcwd() . DIRECTORY_SEPARATOR . $path; - return; - } - } - - foreach ((array)$options[self::EXTRA_EXECUTABLE] as $path) { - echo "Setting executable: $path ..."; - if (is_file($path)) { - chmod($path, 0755); - echo "done\n"; - } else { - echo "\n\tThe file was not found: " . getcwd() . DIRECTORY_SEPARATOR . $path . "\n"; - return; - } - } - } -} diff --git a/extensions/composer/LICENSE.md b/extensions/composer/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/extensions/composer/LICENSE.md +++ /dev/null @@ -1,32 +0,0 @@ -The Yii framework is free software. It is released under the terms of -the following BSD License. - -Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Yii Software LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/extensions/composer/Plugin.php b/extensions/composer/Plugin.php deleted file mode 100644 index 1111738..0000000 --- a/extensions/composer/Plugin.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @since 2.0 - */ -class Plugin implements PluginInterface -{ - /** - * @inheritdoc - */ - public function activate(Composer $composer, IOInterface $io) - { - $installer = new Installer($io, $composer); - $composer->getInstallationManager()->addInstaller($installer); - $file = rtrim($composer->getConfig()->get('vendor-dir'), '/') . '/yiisoft/extensions.php'; - if (!is_file($file)) { - @mkdir(dirname($file)); - file_put_contents($file, " - * @since 2.0 - */ -class DebugAsset extends AssetBundle -{ - public $sourcePath = '@yii/debug/assets'; - public $css = [ - 'main.css', - ]; - public $depends = [ - 'yii\web\YiiAsset', - 'yii\bootstrap\BootstrapAsset', - ]; -} diff --git a/extensions/debug/LogTarget.php b/extensions/debug/LogTarget.php deleted file mode 100644 index 4b75cfa..0000000 --- a/extensions/debug/LogTarget.php +++ /dev/null @@ -1,105 +0,0 @@ - - * @since 2.0 - */ -class LogTarget extends Target -{ - /** - * @var Module - */ - public $module; - public $tag; - - /** - * @param \yii\debug\Module $module - * @param array $config - */ - public function __construct($module, $config = []) - { - parent::__construct($config); - $this->module = $module; - $this->tag = uniqid(); - } - - /** - * Exports log messages to a specific destination. - * Child classes must implement this method. - */ - public function export() - { - $path = $this->module->dataPath; - if (!is_dir($path)) { - mkdir($path); - } - $indexFile = "$path/index.data"; - if (!is_file($indexFile)) { - $manifest = []; - } else { - $manifest = unserialize(file_get_contents($indexFile)); - } - $request = Yii::$app->getRequest(); - $manifest[$this->tag] = $summary = [ - 'tag' => $this->tag, - 'url' => $request->getAbsoluteUrl(), - 'ajax' => $request->getIsAjax(), - 'method' => $request->getMethod(), - 'ip' => $request->getUserIP(), - 'time' => time(), - ]; - $this->gc($manifest); - - $dataFile = "$path/{$this->tag}.data"; - $data = []; - foreach ($this->module->panels as $id => $panel) { - $data[$id] = $panel->save(); - } - $data['summary'] = $summary; - file_put_contents($dataFile, serialize($data)); - file_put_contents($indexFile, serialize($manifest)); - } - - /** - * Processes the given log messages. - * This method will filter the given messages with [[levels]] and [[categories]]. - * And if requested, it will also export the filtering result to specific medium (e.g. email). - * @param array $messages log messages to be processed. See [[Logger::messages]] for the structure - * of each message. - * @param boolean $final whether this method is called at the end of the current application - */ - public function collect($messages, $final) - { - $this->messages = array_merge($this->messages, $messages); - if ($final) { - $this->export($this->messages); - } - } - - protected function gc(&$manifest) - { - if (count($manifest) > $this->module->historySize + 10) { - $n = count($manifest) - $this->module->historySize; - foreach (array_keys($manifest) as $tag) { - $file = $this->module->dataPath . "/$tag.data"; - @unlink($file); - unset($manifest[$tag]); - if (--$n <= 0) { - break; - } - } - } - } -} diff --git a/extensions/debug/Module.php b/extensions/debug/Module.php deleted file mode 100644 index 6c1e6e0..0000000 --- a/extensions/debug/Module.php +++ /dev/null @@ -1,124 +0,0 @@ - - * @since 2.0 - */ -class Module extends \yii\base\Module -{ - /** - * @var array the list of IPs that are allowed to access this module. - * Each array element represents a single IP filter which can be either an IP address - * or an address with wildcard (e.g. 192.168.0.*) to represent a network segment. - * The default value is `['127.0.0.1', '::1']`, which means the module can only be accessed - * by localhost. - */ - public $allowedIPs = ['127.0.0.1', '::1']; - /** - * @var string the namespace that controller classes are in. - */ - public $controllerNamespace = 'yii\debug\controllers'; - /** - * @var LogTarget - */ - public $logTarget; - /** - * @var array|Panel[] - */ - public $panels = []; - /** - * @var string the directory storing the debugger data files. This can be specified using a path alias. - */ - public $dataPath = '@runtime/debug'; - /** - * @var integer the maximum number of debug data files to keep. If there are more files generated, - * the oldest ones will be removed. - */ - public $historySize = 50; - - - public function init() - { - parent::init(); - $this->dataPath = Yii::getAlias($this->dataPath); - $this->logTarget = Yii::$app->getLog()->targets['debug'] = new LogTarget($this); - // do not initialize view component before application is ready (needed when debug in preload) - Yii::$app->on(Application::EVENT_BEFORE_ACTION, function() { - Yii::$app->getView()->on(View::EVENT_END_BODY, [$this, 'renderToolbar']); - }); - - $this->panels = array_merge($this->corePanels(), $this->panels); - foreach ($this->panels as $id => $config) { - $config['module'] = $this; - $config['id'] = $id; - $this->panels[$id] = Yii::createObject($config); - } - } - - public function beforeAction($action) - { - Yii::$app->getView()->off(View::EVENT_END_BODY, [$this, 'renderToolbar']); - unset(Yii::$app->getLog()->targets['debug']); - $this->logTarget = null; - - if ($this->checkAccess($action)) { - return parent::beforeAction($action); - } elseif ($action->id === 'toolbar') { - return false; - } else { - throw new AccessDeniedHttpException('You are not allowed to access this page.'); - } - } - - public function renderToolbar($event) - { - if (!$this->checkAccess() || Yii::$app->getRequest()->getIsAjax()) { - return; - } - $url = Yii::$app->getUrlManager()->createUrl($this->id . '/default/toolbar', [ - 'tag' => $this->logTarget->tag, - ]); - echo ''; - /** @var View $view */ - $view = $event->sender; - echo ''; - echo ''; - } - - protected function checkAccess() - { - $ip = Yii::$app->getRequest()->getUserIP(); - foreach ($this->allowedIPs as $filter) { - if ($filter === '*' || $filter === $ip || (($pos = strpos($filter, '*')) !== false && !strncmp($ip, $filter, $pos))) { - return true; - } - } - Yii::warning('Access to debugger is denied due to IP address restriction. The requested IP is ' . $ip, __METHOD__); - return false; - } - - protected function corePanels() - { - return [ - 'config' => ['class' => 'yii\debug\panels\ConfigPanel'], - 'request' => ['class' => 'yii\debug\panels\RequestPanel'], - 'log' => ['class' => 'yii\debug\panels\LogPanel'], - 'profiling' => ['class' => 'yii\debug\panels\ProfilingPanel'], - 'db' => ['class' => 'yii\debug\panels\DbPanel'], - ]; - } -} diff --git a/extensions/debug/Panel.php b/extensions/debug/Panel.php deleted file mode 100644 index ebfa8b3..0000000 --- a/extensions/debug/Panel.php +++ /dev/null @@ -1,91 +0,0 @@ - - * @since 2.0 - */ -class Panel extends Component -{ - public $id; - public $tag; - /** - * @var Module - */ - public $module; - public $data; - /** - * @var array array of actions to add to the debug modules default controller. - * This array will be merged with all other panels actions property. - * See [[yii\base\Controller::actions()]] for the format. - */ - public $actions = []; - - /** - * @return string name of the panel - */ - public function getName() - { - return ''; - } - - /** - * @return string content that is displayed at debug toolbar - */ - public function getSummary() - { - return ''; - } - - /** - * @return string content that is displayed in debugger detail view - */ - public function getDetail() - { - return ''; - } - - /** - * Saves data to be later used in debugger detail view. - * This method is called on every page where debugger is enabled. - * - * @return mixed data to be saved - */ - public function save() - { - return null; - } - - public function load($data) - { - $this->data = $data; - } - - /** - * @return string URL pointing to panel detail view - */ - public function getUrl() - { - return Yii::$app->getUrlManager()->createUrl($this->module->id . '/default/view', [ - 'panel' => $this->id, - 'tag' => $this->tag, - ]); - } -} diff --git a/extensions/debug/README.md b/extensions/debug/README.md deleted file mode 100644 index e02c76b..0000000 --- a/extensions/debug/README.md +++ /dev/null @@ -1,46 +0,0 @@ -Debug Extension for Yii 2 -========================= - -This extension provides a debugger for Yii 2 applications. When this extension is used, -a debugger toolbar will appear at the bottom of every page. The extension also provides -a set of standalone pages to display more detailed debug information. - - -Installation ------------- - -The preferred way to install this extension is through [composer](http://getcomposer.org/download/). - -Either run - -``` -php composer.phar require yiisoft/yii2-debug "*" -``` - -or add - -``` -"yiisoft/yii2-debug": "*" -``` - -to the require section of your `composer.json` file. - - -Usage ------ - -Once the extension is installed, simply modify your application configuration as follows: - -```php -return [ - 'preload' => ['debug'], - 'modules' => [ - 'debug' => 'yii\debug\Module', - ... - ], - ... -]; -``` - -You will see a debugger toolbar showing at the bottom of every page of your application. -You can click on the toolbar to see more detailed debug information. diff --git a/extensions/debug/assets/main.css b/extensions/debug/assets/main.css deleted file mode 100644 index 7953873..0000000 --- a/extensions/debug/assets/main.css +++ /dev/null @@ -1,153 +0,0 @@ -body { - padding-top: 60px; -} - -#yii-debug-toolbar { - position: fixed; - top: 0; - left: 0; - right: 0; - margin: 0 0 20px 0; - padding: 0; - z-index: 1000000; - font: 11px Verdana, Arial, sans-serif; - text-align: left; - height: 40px; - border-bottom: 1px solid #e4e4e4; - background: rgb(237,237,237); - background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2VkZWRlZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjUzJSIgc3RvcC1jb2xvcj0iI2Y2ZjZmNiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); - background: -moz-linear-gradient(top, rgba(237,237,237,1) 0%, rgba(246,246,246,1) 53%, rgba(255,255,255,1) 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(237,237,237,1)), color-stop(53%,rgba(246,246,246,1)), color-stop(100%,rgba(255,255,255,1))); - background: -webkit-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: -o-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: -ms-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: linear-gradient(to bottom, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ededed', endColorstr='#ffffff',GradientType=0 ); -} - -.yii-debug-toolbar-block { - float: left; - margin: 0; - border-right: 1px solid #e4e4e4; - padding: 4px 8px; - line-height: 32px; -} - -.yii-debug-toolbar-block.title { - font-size: 1.4em; -} - -.yii-debug-toolbar-block a { - text-decoration: none; - color: black; -} - -.yii-debug-toolbar-block span { -} - -.yii-debug-toolbar-block img { - vertical-align: middle; -} - -#yii-debug-toolbar .label { - display: inline-block; - padding: 2px 4px; - font-size: 11.844px; - font-weight: normal; - line-height: 14px; - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - white-space: nowrap; - vertical-align: baseline; - background-color: #999999; -} - -#yii-debug-toolbar .label { - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; -} - -#yii-debug-toolbar .label:empty { - display: none; -} - -#yii-debug-toolbar a.label:hover, -#yii-debug-toolbar a.label:focus { - color: #ffffff; - text-decoration: none; - cursor: pointer; -} - -#yii-debug-toolbar .label-important { - background-color: #b94a48; -} - -#yii-debug-toolbar .label-important[href] { - background-color: #953b39; -} - -#yii-debug-toolbar .label-warning, -#yii-debug-toolbar .badge-warning { - background-color: #f89406; -} - -#yii-debug-toolbar .label-warning[href] { - background-color: #c67605; -} - -#yii-debug-toolbar .label-success { - background-color: #468847; -} - -#yii-debug-toolbar .label-success[href] { - background-color: #356635; -} - -#yii-debug-toolbar .label-info { - background-color: #3a87ad; -} - -#yii-debug-toolbar .label-info[href] { - background-color: #2d6987; -} - -#yii-debug-toolbar .label-inverse, -#yii-debug-toolbar .badge-inverse { - background-color: #333333; -} - -#yii-debug-toolbar .label-inverse[href], -#yii-debug-toolbar .badge-inverse[href] { - background-color: #1a1a1a; -} -span.indent { - color: #ccc; -} - -ul.trace { - font-size: 12px; - color: #999; - margin: 2px 0 0 0; - padding: 0; - list-style: none; - white-space: normal; -} - -.callout-danger { - background-color: #fcf2f2; - border-color: #dFb5b4; -} -.callout { - margin: 0 0 10px 0; - padding: 5px; -} - -.list-group .glyphicon { - float: right; -} - -td, th { - white-space: pre; - word-wrap: break-word; -} diff --git a/extensions/debug/composer.json b/extensions/debug/composer.json deleted file mode 100644 index d8cbc1e..0000000 --- a/extensions/debug/composer.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "yiisoft/yii2-debug", - "description": "The debugger extension for the Yii framework", - "keywords": ["yii", "debug", "debugger"], - "type": "yii2-extension", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?labels=ext%3Adebug", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "authors": [ - { - "name": "Qiang Xue", - "email": "qiang.xue@gmail.com" - } - ], - "require": { - "yiisoft/yii2": "*", - "yiisoft/yii2-bootstrap": "*" - }, - "autoload": { - "psr-0": { "yii\\debug\\": "" } - }, - "target-dir": "yii/debug" -} diff --git a/extensions/debug/controllers/DefaultController.php b/extensions/debug/controllers/DefaultController.php deleted file mode 100644 index 0c8d6e9..0000000 --- a/extensions/debug/controllers/DefaultController.php +++ /dev/null @@ -1,114 +0,0 @@ - - * @since 2.0 - */ -class DefaultController extends Controller -{ - public $layout = 'main'; - /** - * @var \yii\debug\Module - */ - public $module; - /** - * @var array the summary data (e.g. URL, time) - */ - public $summary; - - public function actions() - { - $actions = []; - foreach($this->module->panels as $panel) { - $actions = array_merge($actions, $panel->actions); - } - return $actions; - } - - public function actionIndex() - { - return $this->render('index', ['manifest' => $this->getManifest()]); - } - - public function actionView($tag = null, $panel = null) - { - if ($tag === null) { - $tags = array_keys($this->getManifest()); - $tag = reset($tags); - } - $this->loadData($tag); - if (isset($this->module->panels[$panel])) { - $activePanel = $this->module->panels[$panel]; - } else { - $activePanel = $this->module->panels['request']; - } - return $this->render('view', [ - 'tag' => $tag, - 'summary' => $this->summary, - 'manifest' => $this->getManifest(), - 'panels' => $this->module->panels, - 'activePanel' => $activePanel, - ]); - } - - public function actionToolbar($tag) - { - $this->loadData($tag); - return $this->renderPartial('toolbar', [ - 'tag' => $tag, - 'panels' => $this->module->panels, - ]); - } - - public function actionPhpinfo() - { - phpinfo(); - } - - private $_manifest; - - protected function getManifest() - { - if ($this->_manifest === null) { - $indexFile = $this->module->dataPath . '/index.data'; - if (is_file($indexFile)) { - $this->_manifest = array_reverse(unserialize(file_get_contents($indexFile)), true); - } else { - $this->_manifest = []; - } - } - return $this->_manifest; - } - - public function loadData($tag) - { - $manifest = $this->getManifest(); - if (isset($manifest[$tag])) { - $dataFile = $this->module->dataPath . "/$tag.data"; - $data = unserialize(file_get_contents($dataFile)); - foreach ($this->module->panels as $id => $panel) { - if (isset($data[$id])) { - $panel->tag = $tag; - $panel->load($data[$id]); - } else { - // remove the panel since it has not received any data - unset($this->module->panels[$id]); - } - } - $this->summary = $data['summary']; - } else { - throw new NotFoundHttpException("Unable to find debug data tagged with '$tag'."); - } - } -} diff --git a/extensions/debug/panels/ConfigPanel.php b/extensions/debug/panels/ConfigPanel.php deleted file mode 100644 index 59cabf3..0000000 --- a/extensions/debug/panels/ConfigPanel.php +++ /dev/null @@ -1,129 +0,0 @@ - - * @since 2.0 - */ -class ConfigPanel extends Panel -{ - public function getName() - { - return 'Configuration'; - } - - public static function getYiiLogo() - { - return 'data:image/png;base64,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'; - } - - public function getSummary() - { - $yiiLogo = $this->getYiiLogo(); - $url = $this->getUrl(); - $phpUrl = Yii::$app->getUrlManager()->createUrl($this->module->id . '/default/phpinfo'); - return << - - - {$this->data['application']['yii']} - - - -EOD; - } - - public function getDetail() - { - $app = [ - 'Yii Version' => $this->data['application']['yii'], - 'Application Name' => $this->data['application']['name'], - 'Environment' => $this->data['application']['env'], - 'Debug Mode' => $this->data['application']['debug'] ? 'Yes' : 'No', - ]; - $php = [ - 'PHP Version' => $this->data['php']['version'], - 'Xdebug' => $this->data['php']['xdebug'] ? 'Enabled' : 'Disabled', - 'APC' => $this->data['php']['apc'] ? 'Enabled' : 'Disabled', - 'Memcache' => $this->data['php']['memcache'] ? 'Enabled' : 'Disabled', - ]; - return "

    Configuration

    \n" - . $this->renderData('Application Configuration', $app) . "\n" - . $this->renderExtensions() - . $this->renderData('PHP Configuration', $php) . "\n" - . $this->getPhpInfo(); - } - - protected function getPhpInfo() - { - return '
    ' . Html::a('Show phpinfo »', ['phpinfo'], ['class' => 'btn btn-primary']) . "
    \n"; - } - - protected function renderData($caption, $values) - { - if (empty($values)) { - return "

    $caption

    \n

    Empty.

    "; - } - $rows = []; - foreach ($values as $name => $value) { - $rows[] = '' . Html::encode($name) . '' . Html::encode($value) . ''; - } - $rows = implode("\n", $rows); - return <<$caption - - - -$rows - -
    NameValue
    -EOD; - } - - protected function renderExtensions() - { - if (empty($this->data['extensions'])) { - return ''; - } - $data = []; - foreach ($this->data['extensions'] as $extension) { - $data[$extension['name']] = $extension['version']; - } - return $this->renderData('Installed Extensions', $data) . "\n"; - } - - public function save() - { - return [ - 'phpVersion' => PHP_VERSION, - 'yiiVersion' => Yii::getVersion(), - 'application' => [ - 'yii' => Yii::getVersion(), - 'name' => Yii::$app->name, - 'env' => YII_ENV, - 'debug' => YII_DEBUG, - ], - 'php' => [ - 'version' => PHP_VERSION, - 'xdebug' => extension_loaded('xdebug'), - 'apc' => extension_loaded('apc'), - 'memcache' => extension_loaded('memcache'), - ], - 'extensions' => Yii::$app->extensions, - ]; - } -} diff --git a/extensions/debug/panels/DbPanel.php b/extensions/debug/panels/DbPanel.php deleted file mode 100644 index a487dd4..0000000 --- a/extensions/debug/panels/DbPanel.php +++ /dev/null @@ -1,123 +0,0 @@ - - * @since 2.0 - */ -class DbPanel extends Panel -{ - public function getName() - { - return 'Database'; - } - - public function getSummary() - { - $timings = $this->calculateTimings(); - $queryCount = count($timings); - $queryTime = 0; - foreach ($timings as $timing) { - $queryTime += $timing[3]; - } - $queryTime = number_format($queryTime * 1000) . ' ms'; - $url = $this->getUrl(); - $output = << - - DB $queryCount $queryTime - - -EOD; - return $queryCount > 0 ? $output : ''; - } - - public function getDetail() - { - $timings = $this->calculateTimings(); - ArrayHelper::multisort($timings, 3, SORT_DESC); - $rows = []; - foreach ($timings as $timing) { - $duration = sprintf('%.1f ms', $timing[3] * 1000); - $procedure = Html::encode($timing[1]); - $traces = $timing[4]; - if (!empty($traces)) { - $procedure .= Html::ul($traces, [ - 'class' => 'trace', - 'item' => function ($trace) { - return "
  • {$trace['file']}({$trace['line']})
  • "; - }, - ]); - } - $rows[] = "$duration$procedure"; - } - $rows = implode("\n", $rows); - - return <<Database Queries - - - - - - - - - -$rows - -
    TimeQuery
    -EOD; - } - - private $_timings; - - protected function calculateTimings() - { - if ($this->_timings !== null) { - return $this->_timings; - } - $messages = $this->data['messages']; - $timings = []; - $stack = []; - foreach ($messages as $i => $log) { - list($token, $level, $category, $timestamp) = $log; - $log[5] = $i; - if ($level == Logger::LEVEL_PROFILE_BEGIN) { - $stack[] = $log; - } elseif ($level == Logger::LEVEL_PROFILE_END) { - if (($last = array_pop($stack)) !== null && $last[0] === $token) { - $timings[$last[5]] = [count($stack), $token, $last[3], $timestamp - $last[3], $last[4]]; - } - } - } - - $now = microtime(true); - while (($last = array_pop($stack)) !== null) { - $delta = $now - $last[3]; - $timings[$last[5]] = [count($stack), $last[0], $last[2], $delta, $last[4]]; - } - ksort($timings); - return $this->_timings = $timings; - } - - public function save() - { - $target = $this->module->logTarget; - $messages = $target->filterMessages($target->messages, Logger::LEVEL_PROFILE, ['yii\db\Command::queryInternal']); - return ['messages' => $messages]; - } -} diff --git a/extensions/debug/panels/LogPanel.php b/extensions/debug/panels/LogPanel.php deleted file mode 100644 index ccf4402..0000000 --- a/extensions/debug/panels/LogPanel.php +++ /dev/null @@ -1,105 +0,0 @@ - - * @since 2.0 - */ -class LogPanel extends Panel -{ - public function getName() - { - return 'Logs'; - } - - public function getSummary() - { - $output = ['' . count($this->data['messages']) . '']; - $title = 'Logged ' . count($this->data['messages']) . ' messages'; - $errorCount = count(Target::filterMessages($this->data['messages'], Logger::LEVEL_ERROR)); - if ($errorCount) { - $output[] = '' . $errorCount . ''; - $title .= ", $errorCount errors"; - } - $warningCount = count(Target::filterMessages($this->data['messages'], Logger::LEVEL_WARNING)); - if ($warningCount) { - $output[] = '' . $warningCount . ''; - $title .= ", $warningCount warnings"; - } - $log = implode(' ', $output); - $url = $this->getUrl(); - return << - Log $log - -EOD; - } - - public function getDetail() - { - $rows = []; - foreach ($this->data['messages'] as $log) { - list ($message, $level, $category, $time, $traces) = $log; - $time = date('H:i:s.', $time) . sprintf('%03d', (int)(($time - (int)$time) * 1000)); - $message = nl2br(Html::encode($message)); - if (!empty($traces)) { - $message .= Html::ul($traces, [ - 'class' => 'trace', - 'item' => function ($trace) { - return "
  • {$trace['file']}({$trace['line']})
  • "; - }, - ]); - } - if ($level == Logger::LEVEL_ERROR) { - $class = ' class="danger"'; - } elseif ($level == Logger::LEVEL_WARNING) { - $class = ' class="warning"'; - } elseif ($level == Logger::LEVEL_INFO) { - $class = ' class="success"'; - } else { - $class = ''; - } - $level = Logger::getLevelName($level); - $rows[] = "$time$level$category
    $message
    "; - } - $rows = implode("\n", $rows); - return <<Log Messages - - - - - - - - - - - -$rows - -
    TimeLevelCategoryMessage
    -EOD; - } - - public function save() - { - $target = $this->module->logTarget; - $messages = $target->filterMessages($target->messages, Logger::LEVEL_ERROR | Logger::LEVEL_INFO | Logger::LEVEL_WARNING | Logger::LEVEL_TRACE); - return ['messages' => $messages]; - } -} diff --git a/extensions/debug/panels/ProfilingPanel.php b/extensions/debug/panels/ProfilingPanel.php deleted file mode 100644 index 49cf081..0000000 --- a/extensions/debug/panels/ProfilingPanel.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @since 2.0 - */ -class ProfilingPanel extends Panel -{ - public function getName() - { - return 'Profiling'; - } - - public function getSummary() - { - $memory = sprintf('%.1f MB', $this->data['memory'] / 1048576); - $time = number_format($this->data['time'] * 1000) . ' ms'; - $url = $this->getUrl(); - - return << - Time $time - - -EOD; - } - - public function getDetail() - { - $messages = $this->data['messages']; - $timings = []; - $stack = []; - foreach ($messages as $i => $log) { - list($token, $level, $category, $timestamp, $traces) = $log; - if ($level == Logger::LEVEL_PROFILE_BEGIN) { - $stack[] = $log; - } elseif ($level == Logger::LEVEL_PROFILE_END) { - if (($last = array_pop($stack)) !== null && $last[0] === $token) { - $timings[] = [count($stack), $token, $category, $timestamp - $last[3], $traces]; - } - } - } - - $now = microtime(true); - while (($last = array_pop($stack)) !== null) { - $timings[] = [count($stack), $last[0], $last[2], $now - $last[3], $last[4]]; - } - - $rows = []; - foreach ($timings as $timing) { - $time = sprintf('%.1f ms', $timing[3] * 1000); - $procedure = str_repeat('', $timing[0]) . Html::encode($timing[1]); - $category = Html::encode($timing[2]); - $rows[] = "$time$category$procedure"; - } - $rows = implode("\n", $rows); - - $memory = sprintf('%.1f MB', $this->data['memory'] / 1048576); - $time = number_format($this->data['time'] * 1000) . ' ms'; - - return <<Performance Profiling - -

    Total processing time: $time; Peak memory: $memory.

    - - - - - - - - - - -$rows - -
    TimeCategoryProcedure
    -EOD; - } - - public function save() - { - $target = $this->module->logTarget; - $messages = $target->filterMessages($target->messages, Logger::LEVEL_PROFILE); - return [ - 'memory' => memory_get_peak_usage(), - 'time' => microtime(true) - YII_BEGIN_TIME, - 'messages' => $messages, - ]; - } -} diff --git a/extensions/debug/panels/RequestPanel.php b/extensions/debug/panels/RequestPanel.php deleted file mode 100644 index 9d9cb02..0000000 --- a/extensions/debug/panels/RequestPanel.php +++ /dev/null @@ -1,167 +0,0 @@ - - * @since 2.0 - */ -class RequestPanel extends Panel -{ - public function getName() - { - return 'Request'; - } - - public function getSummary() - { - $url = $this->getUrl(); - $statusCode = $this->data['statusCode']; - if ($statusCode === null) { - $statusCode = 200; - } - if ($statusCode >= 200 && $statusCode < 300) { - $class = 'label-success'; - } elseif ($statusCode >= 100 && $statusCode < 200) { - $class = 'label-info'; - } else { - $class = 'label-important'; - } - $statusText = Html::encode(isset(Response::$httpStatuses[$statusCode]) ? Response::$httpStatuses[$statusCode] : ''); - - return << - Status $statusCode - - -EOD; - } - - public function getDetail() - { - $data = [ - 'Route' => $this->data['route'], - 'Action' => $this->data['action'], - 'Parameters' => $this->data['actionParams'], - ]; - return Tabs::widget([ - 'items' => [ - [ - 'label' => 'Parameters', - 'content' => $this->renderData('Routing', $data) - . $this->renderData('$_GET', $this->data['GET']) - . $this->renderData('$_POST', $this->data['POST']) - . $this->renderData('$_FILES', $this->data['FILES']) - . $this->renderData('$_COOKIE', $this->data['COOKIE']), - 'active' => true, - ], - [ - 'label' => 'Headers', - 'content' => $this->renderData('Request Headers', $this->data['requestHeaders']) - . $this->renderData('Response Headers', $this->data['responseHeaders']), - ], - [ - 'label' => 'Session', - 'content' => $this->renderData('$_SESSION', $this->data['SESSION']) - . $this->renderData('Flashes', $this->data['flashes']), - ], - [ - 'label' => '$_SERVER', - 'content' => $this->renderData('$_SERVER', $this->data['SERVER']), - ], - ], - ]); - } - - public function save() - { - if (function_exists('apache_request_headers')) { - $requestHeaders = apache_request_headers(); - } elseif (function_exists('http_get_request_headers')) { - $requestHeaders = http_get_request_headers(); - } else { - $requestHeaders = []; - } - $responseHeaders = []; - foreach (headers_list() as $header) { - if (($pos = strpos($header, ':')) !== false) { - $name = substr($header, 0, $pos); - $value = trim(substr($header, $pos + 1)); - if (isset($responseHeaders[$name])) { - if (!is_array($responseHeaders[$name])) { - $responseHeaders[$name] = [$responseHeaders[$name], $value]; - } else { - $responseHeaders[$name][] = $value; - } - } else { - $responseHeaders[$name] = $value; - } - } else { - $responseHeaders[] = $header; - } - } - if (Yii::$app->requestedAction) { - if (Yii::$app->requestedAction instanceof InlineAction) { - $action = get_class(Yii::$app->requestedAction->controller) . '::' . Yii::$app->requestedAction->actionMethod . '()'; - } else { - $action = get_class(Yii::$app->requestedAction) . '::run()'; - } - } else { - $action = null; - } - /** @var \yii\web\Session $session */ - $session = Yii::$app->getComponent('session', false); - return [ - 'flashes' => $session ? $session->getAllFlashes() : [], - 'statusCode' => Yii::$app->getResponse()->getStatusCode(), - 'requestHeaders' => $requestHeaders, - 'responseHeaders' => $responseHeaders, - 'route' => Yii::$app->requestedAction ? Yii::$app->requestedAction->getUniqueId() : Yii::$app->requestedRoute, - 'action' => $action, - 'actionParams' => Yii::$app->requestedParams, - 'SERVER' => empty($_SERVER) ? [] : $_SERVER, - 'GET' => empty($_GET) ? [] : $_GET, - 'POST' => empty($_POST) ? [] : $_POST, - 'COOKIE' => empty($_COOKIE) ? [] : $_COOKIE, - 'FILES' => empty($_FILES) ? [] : $_FILES, - 'SESSION' => empty($_SESSION) ? [] : $_SESSION, - ]; - } - - protected function renderData($caption, $values) - { - if (empty($values)) { - return "

    $caption

    \n

    Empty.

    "; - } - $rows = []; - foreach ($values as $name => $value) { - $rows[] = '' . Html::encode($name) . '' . htmlspecialchars(var_export($value, true), ENT_QUOTES|ENT_SUBSTITUTE, \Yii::$app->charset, TRUE) . ''; - } - $rows = implode("\n", $rows); - return <<$caption - - - -$rows - -
    NameValue
    -EOD; - } -} diff --git a/extensions/debug/views/default/index.php b/extensions/debug/views/default/index.php deleted file mode 100644 index 93737e2..0000000 --- a/extensions/debug/views/default/index.php +++ /dev/null @@ -1,46 +0,0 @@ -title = 'Yii Debugger'; -?> -
    -
    -
    - Yii Debugger -
    -
    - -
    -
    -

    Available Debug Data

    - - - - - - - - - - - - $data): ?> - - - - - - - - - -
    TagTimeIPMethodURL
    $tag]) ?>
    -
    -
    -
    diff --git a/extensions/debug/views/default/toolbar.css b/extensions/debug/views/default/toolbar.css deleted file mode 100644 index 72bf3bf..0000000 --- a/extensions/debug/views/default/toolbar.css +++ /dev/null @@ -1,177 +0,0 @@ -#yii-debug-toolbar { - position: fixed; - left: 0; - right: 0; - bottom: 0; - margin: 0; - padding: 0; - z-index: 1000000; - font: 11px Verdana, Arial, sans-serif; - text-align: left; - height: 40px; - border-top: 1px solid #ccc; - background: rgb(237,237,237); - background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2VkZWRlZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjUzJSIgc3RvcC1jb2xvcj0iI2Y2ZjZmNiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); - background: -moz-linear-gradient(top, rgba(237,237,237,1) 0%, rgba(246,246,246,1) 53%, rgba(255,255,255,1) 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(237,237,237,1)), color-stop(53%,rgba(246,246,246,1)), color-stop(100%,rgba(255,255,255,1))); - background: -webkit-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: -o-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: -ms-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: linear-gradient(to bottom, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ededed', endColorstr='#ffffff',GradientType=0 ); -} - -.yii-debug-toolbar-block { - float: left; - margin: 0; - border-right: 1px solid #e4e4e4; - padding: 4px 8px; - line-height: 32px; -} - -.yii-debug-toolbar-block a { - text-decoration: none; - color: black; -} - -.yii-debug-toolbar-block span { -} - -.yii-debug-toolbar-block img { - vertical-align: middle; -} - -#yii-debug-toolbar .label { - display: inline-block; - padding: 2px 4px; - font-size: 11.844px; - font-weight: normal; - line-height: 14px; - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - white-space: nowrap; - vertical-align: baseline; - background-color: #999999; -} - -#yii-debug-toolbar .label { - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; -} - -#yii-debug-toolbar .label:empty { - display: none; -} - -#yii-debug-toolbar a.label:hover, -#yii-debug-toolbar a.label:focus { - color: #ffffff; - text-decoration: none; - cursor: pointer; -} - -#yii-debug-toolbar .label-important { - background-color: #b94a48; -} - -#yii-debug-toolbar .label-important[href] { - background-color: #953b39; -} - -#yii-debug-toolbar .label-warning, -#yii-debug-toolbar .badge-warning { - background-color: #f89406; -} - -#yii-debug-toolbar .label-warning[href] { - background-color: #c67605; -} - -#yii-debug-toolbar .label-success { - background-color: #468847; -} - -#yii-debug-toolbar .label-success[href] { - background-color: #356635; -} - -#yii-debug-toolbar .label-info { - background-color: #3a87ad; -} - -#yii-debug-toolbar .label-info[href] { - background-color: #2d6987; -} - -#yii-debug-toolbar .label-inverse, -#yii-debug-toolbar .badge-inverse { - background-color: #333333; -} - -#yii-debug-toolbar .label-inverse[href], -#yii-debug-toolbar .badge-inverse[href] { - background-color: #1a1a1a; -} - -.yii-debug-toolbar-toggler { - cursor: pointer; - position: absolute; - right: 10px; - bottom: 4px; - width: 15px; - height: 30px; - font-size: 25px; - font-weight: 100; - line-height: 28px; - color: #ffffff; - text-align: center; - background: #666666; - -webkit-border-radius: 12px; - -moz-border-radius: 12px; - border-radius: 12px; - opacity: 0.5; - filter: alpha(opacity=50); -} - -.yii-debug-toolbar-toggler:hover, -.yii-debug-toolbar-toggler:focus { - color: #ffffff; - text-decoration: none; - opacity: 0.9; - filter: alpha(opacity=90); -} - -#yii-debug-toolbar-min { - display: none; - position: fixed; - right: 0; - bottom: 0; - margin: 0; - padding: 0; - z-index: 1000000; - font: 11px Verdana, Arial, sans-serif; - text-align: left; - width: 63px; - height: 38px; - border-top: 1px solid #ccc; - border-left: 1px solid #ccc; - -webkit-border-top-left-radius: 6px; - -moz-border-top-left-radius: 6px; - border-top-left-radius: 6px; - background: rgb(237,237,237); - background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2VkZWRlZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjUzJSIgc3RvcC1jb2xvcj0iI2Y2ZjZmNiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); - background: -moz-linear-gradient(top, rgba(237,237,237,1) 0%, rgba(246,246,246,1) 53%, rgba(255,255,255,1) 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(237,237,237,1)), color-stop(53%,rgba(246,246,246,1)), color-stop(100%,rgba(255,255,255,1))); - background: -webkit-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: -o-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: -ms-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: linear-gradient(to bottom, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ededed', endColorstr='#ffffff',GradientType=0 ); -} - -#yii-debug-toolbar-logo { - position: fixed; - right: 31px; - bottom: 4px; -} diff --git a/extensions/debug/views/default/toolbar.js b/extensions/debug/views/default/toolbar.js deleted file mode 100644 index 0dca1de..0000000 --- a/extensions/debug/views/default/toolbar.js +++ /dev/null @@ -1,41 +0,0 @@ -(function() { - var ajax = function(url, settings) { - var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); - settings = settings || {}; - xhr.open(settings.method || 'GET', url, true); - xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); - xhr.onreadystatechange = function(state) { - if (xhr.readyState == 4) { - if (xhr.status == 200 && settings.success) { - settings.success(xhr); - } else if (xhr.status != 200 && settings.error) { - settings.error(xhr); - } - } - }; - xhr.send(settings.data || ''); - }; - - var e = document.getElementById('yii-debug-toolbar'); - if (e) { - e.style.display = 'block'; - var url = e.getAttribute('data-url'); - ajax(url, { - success: function(xhr) { - var div = document.createElement('div'); - div.innerHTML = xhr.responseText; - e.parentNode.replaceChild(div, e); - if (window.localStorage) { - var pref = localStorage.getItem('yii-debug-toolbar'); - if (pref == 'minimized') { - document.getElementById('yii-debug-toolbar').style.display = 'none'; - document.getElementById('yii-debug-toolbar-min').style.display = 'block'; - } - } - }, - error: function(xhr) { - e.innerHTML = xhr.responseText; - } - }); - } -})(); diff --git a/extensions/debug/views/default/toolbar.php b/extensions/debug/views/default/toolbar.php deleted file mode 100644 index 7d88822..0000000 --- a/extensions/debug/views/default/toolbar.php +++ /dev/null @@ -1,38 +0,0 @@ -getUrl(); -?> -
    - - getSummary() ?> - - -
    -
    - - -
    diff --git a/extensions/debug/views/default/view.php b/extensions/debug/views/default/view.php deleted file mode 100644 index 846653c..0000000 --- a/extensions/debug/views/default/view.php +++ /dev/null @@ -1,78 +0,0 @@ -title = 'Yii Debugger'; -?> -
    -
    -
    - Yii Debugger -
    - - getSummary() ?> - -
    - -
    -
    -
    -
    - $panel) { - $label = '' . Html::encode($panel->getName()); - echo Html::a($label, ['view', 'tag' => $tag, 'panel' => $id], [ - 'class' => $panel === $activePanel ? 'list-group-item active' : 'list-group-item', - ]); - } - ?> -
    -
    -
    -
    - $meta['tag'], 'panel' => $activePanel->id]; - $items[] = [ - 'label' => $label, - 'url' => $url, - ]; - if (++$count >= 10) { - break; - } - } - echo ButtonGroup::widget([ - 'buttons' => [ - Html::a('All', ['index'], ['class' => 'btn btn-default']), - ButtonDropdown::widget([ - 'label' => 'Last 10', - 'options' => ['class' => 'btn-default'], - 'dropdown' => ['items' => $items], - ]), - ], - ]); - echo "\n" . $summary['tag'] . ': ' . $summary['method'] . ' ' . Html::a(Html::encode($summary['url']), $summary['url']); - echo ' at ' . date('Y-m-d h:i:s a', $summary['time']) . ' by ' . $summary['ip']; - ?> -
    - getDetail() ?> -
    -
    -
    -
    diff --git a/extensions/debug/views/layouts/main.php b/extensions/debug/views/layouts/main.php deleted file mode 100644 index 97ef08c..0000000 --- a/extensions/debug/views/layouts/main.php +++ /dev/null @@ -1,23 +0,0 @@ - - - -beginPage() ?> - - <?= Html::encode($this->title) ?> - head() ?> - - -beginBody() ?> - -endBody() ?> - -endPage() ?> - diff --git a/extensions/elasticsearch/ActiveQuery.php b/extensions/elasticsearch/ActiveQuery.php deleted file mode 100644 index 96d6681..0000000 --- a/extensions/elasticsearch/ActiveQuery.php +++ /dev/null @@ -1,199 +0,0 @@ -with('orders')->asArray()->all(); - * ~~~ - * - * @author Carsten Brandt - * @since 2.0 - */ -class ActiveQuery extends Query implements ActiveQueryInterface -{ - use ActiveQueryTrait; - - /** - * Creates a DB command that can be used to execute this query. - * @param Connection $db the DB connection used to create the DB command. - * If null, the DB connection returned by [[modelClass]] will be used. - * @return Command the created DB command instance. - */ - public function createCommand($db = null) - { - /** @var ActiveRecord $modelClass */ - $modelClass = $this->modelClass; - if ($db === null) { - $db = $modelClass::getDb(); - } - - if ($this->type === null) { - $this->type = $modelClass::type(); - } - if ($this->index === null) { - $this->index = $modelClass::index(); - $this->type = $modelClass::type(); - } - $commandConfig = $db->getQueryBuilder()->build($this); - return $db->createCommand($commandConfig); - } - - /** - * Executes query and returns all results as an array. - * @param Connection $db the DB connection used to create the DB command. - * If null, the DB connection returned by [[modelClass]] will be used. - * @return array the query results. If the query results in nothing, an empty array will be returned. - */ - public function all($db = null) - { - $result = $this->createCommand($db)->search(); - if (empty($result['hits']['hits'])) { - return []; - } - if ($this->fields !== null) { - foreach ($result['hits']['hits'] as &$row) { - $row['_source'] = isset($row['fields']) ? $row['fields'] : []; - unset($row['fields']); - } - unset($row); - } - if ($this->asArray && $this->indexBy) { - foreach ($result['hits']['hits'] as &$row) { - $row['_source'][ActiveRecord::PRIMARY_KEY_NAME] = $row['_id']; - $row = $row['_source']; - } - } - $models = $this->createModels($result['hits']['hits']); - if ($this->asArray && !$this->indexBy) { - foreach($models as $key => $model) { - $model['_source'][ActiveRecord::PRIMARY_KEY_NAME] = $model['_id']; - $models[$key] = $model['_source']; - } - } - if (!empty($this->with)) { - $this->findWith($this->with, $models); - } - return $models; - } - - /** - * Executes query and returns a single row of result. - * @param Connection $db the DB connection used to create the DB command. - * If null, the DB connection returned by [[modelClass]] will be used. - * @return ActiveRecord|array|null a single row of query result. Depending on the setting of [[asArray]], - * the query result may be either an array or an ActiveRecord object. Null will be returned - * if the query results in nothing. - */ - public function one($db = null) - { - if (($result = parent::one($db)) === false) { - return null; - } - if ($this->asArray) { - $model = $result['_source']; - $model[ActiveRecord::PRIMARY_KEY_NAME] = $result['_id']; - } else { - /** @var ActiveRecord $class */ - $class = $this->modelClass; - $model = $class::create($result); - } - if (!empty($this->with)) { - $models = [$model]; - $this->findWith($this->with, $models); - $model = $models[0]; - } - return $model; - } - - /** - * @inheritdoc - */ - public function search($db = null, $options = []) - { - $result = $this->createCommand($db)->search($options); - if (!empty($result['hits']['hits'])) { - $models = $this->createModels($result['hits']['hits']); - if ($this->asArray) { - foreach($models as $key => $model) { - $model['_source'][ActiveRecord::PRIMARY_KEY_NAME] = $model['_id']; - $models[$key] = $model['_source']; - } - } - if (!empty($this->with)) { - $this->findWith($this->with, $models); - } - $result['hits']['hits'] = $models; - } - return $result; - } - - /** - * @inheritdoc - */ - public function scalar($field, $db = null) - { - $record = parent::one($db); - if ($record !== false) { - if ($field == ActiveRecord::PRIMARY_KEY_NAME) { - return $record['_id']; - } elseif (isset($record['_source'][$field])) { - return $record['_source'][$field]; - } - } - return null; - } - - /** - * @inheritdoc - */ - public function column($field, $db = null) - { - if ($field == ActiveRecord::PRIMARY_KEY_NAME) { - $command = $this->createCommand($db); - $command->queryParts['fields'] = []; - $result = $command->search(); - if (empty($result['hits']['hits'])) { - return []; - } - $column = []; - foreach ($result['hits']['hits'] as $row) { - $column[] = $row['_id']; - } - return $column; - } - return parent::column($field, $db); - } -} diff --git a/extensions/elasticsearch/ActiveRecord.php b/extensions/elasticsearch/ActiveRecord.php deleted file mode 100644 index 3c8b4a8..0000000 --- a/extensions/elasticsearch/ActiveRecord.php +++ /dev/null @@ -1,485 +0,0 @@ - - * @since 2.0 - */ -class ActiveRecord extends BaseActiveRecord -{ - const PRIMARY_KEY_NAME = 'id'; - - private $_id; - private $_version; - - /** - * Returns the database connection used by this AR class. - * By default, the "elasticsearch" application component is used as the database connection. - * You may override this method if you want to use a different database connection. - * @return Connection the database connection used by this AR class. - */ - public static function getDb() - { - return \Yii::$app->getComponent('elasticsearch'); - } - - /** - * @inheritdoc - */ - public static function find($q = null) - { - $query = static::createQuery(); - if (is_array($q)) { - if (count($q) == 1 && (array_key_exists(ActiveRecord::PRIMARY_KEY_NAME, $q))) { - $pk = $q[ActiveRecord::PRIMARY_KEY_NAME]; - if (is_array($pk)) { - return static::mget($pk); - } else { - return static::get($pk); - } - } - return $query->where($q)->one(); - } elseif ($q !== null) { - return static::get($q); - } - return $query; - } - - /** - * Gets a record by its primary key. - * - * @param mixed $primaryKey the primaryKey value - * @param array $options options given in this parameter are passed to elasticsearch - * as request URI parameters. - * Please refer to the [elasticsearch documentation](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-get.html) - * for more details on these options. - * @return static|null The record instance or null if it was not found. - */ - public static function get($primaryKey, $options = []) - { - if ($primaryKey === null) { - return null; - } - $command = static::getDb()->createCommand(); - $result = $command->get(static::index(), static::type(), $primaryKey, $options); - if ($result['exists']) { - return static::create($result); - } - return null; - } - - /** - * Gets a list of records by its primary keys. - * - * @param array $primaryKeys an array of primaryKey values - * @param array $options options given in this parameter are passed to elasticsearch - * as request URI parameters. - * - * Please refer to the [elasticsearch documentation](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-get.html) - * for more details on these options. - * @return static|null The record instance or null if it was not found. - */ - - public static function mget($primaryKeys, $options = []) - { - if (empty($primaryKeys)) { - return []; - } - $command = static::getDb()->createCommand(); - $result = $command->mget(static::index(), static::type(), $primaryKeys, $options); - $models = []; - foreach($result['docs'] as $doc) { - if ($doc['exists']) { - $models[] = static::create($doc); - } - } - return $models; - } - - // TODO add more like this feature http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-more-like-this.html - - // TODO add percolate functionality http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-percolate.html - - /** - * @inheritdoc - */ - public static function createQuery() - { - return new ActiveQuery(['modelClass' => get_called_class()]); - } - - /** - * @inheritdoc - */ - public static function createActiveRelation($config = []) - { - return new ActiveRelation($config); - } - - // TODO implement copy and move as pk change is not possible - - public function getId() - { - return $this->_id; - } - - /** - * Sets the primary key - * @param mixed $value - * @throws \yii\base\InvalidCallException when record is not new - */ - public function setId($value) - { - if ($this->isNewRecord) { - $this->_id = $value; - } else { - throw new InvalidCallException('Changing the primaryKey of an already saved record is not allowed.'); - } - } - - /** - * @inheritdoc - */ - public function getPrimaryKey($asArray = false) - { - if ($asArray) { - return [ActiveRecord::PRIMARY_KEY_NAME => $this->_id]; - } else { - return $this->_id; - } - } - - /** - * @inheritdoc - */ - public function getOldPrimaryKey($asArray = false) - { - $id = $this->isNewRecord ? null : $this->_id; - if ($asArray) { - return [ActiveRecord::PRIMARY_KEY_NAME => $id]; - } else { - return $this->_id; - } - } - - /** - * This method defines the primary. - * - * The primaryKey for elasticsearch documents is always `primaryKey`. It can not be changed. - * - * @return string[] the primary keys of this record. - */ - public static function primaryKey() - { - return [ActiveRecord::PRIMARY_KEY_NAME]; - } - - /** - * Returns the list of all attribute names of the model. - * This method must be overridden by child classes to define available attributes. - * @return array list of attribute names. - */ - public function attributes() - { - throw new InvalidConfigException('The attributes() method of elasticsearch ActiveRecord has to be implemented by child classes.'); - } - - /** - * @return string the name of the index this record is stored in. - */ - public static function index() - { - return Inflector::pluralize(Inflector::camel2id(StringHelper::basename(get_called_class()), '-')); - } - - /** - * @return string the name of the type of this record. - */ - public static function type() - { - return Inflector::camel2id(StringHelper::basename(get_called_class()), '-'); - } - - /** - * Creates an active record object using a row of data. - * This method is called by [[ActiveQuery]] to populate the query results - * into Active Records. It is not meant to be used to create new records. - * @param array $row attribute values (name => value) - * @return ActiveRecord the newly created active record. - */ - public static function create($row) - { - $row['_source'][ActiveRecord::PRIMARY_KEY_NAME] = $row['_id']; - $record = parent::create($row['_source']); - return $record; - } - - /** - * Inserts a document into the associated index using the attribute values of this record. - * - * This method performs the following steps in order: - * - * 1. call [[beforeValidate()]] when `$runValidation` is true. If validation - * fails, it will skip the rest of the steps; - * 2. call [[afterValidate()]] when `$runValidation` is true. - * 3. call [[beforeSave()]]. If the method returns false, it will skip the - * rest of the steps; - * 4. insert the record into database. If this fails, it will skip the rest of the steps; - * 5. call [[afterSave()]]; - * - * In the above step 1, 2, 3 and 5, events [[EVENT_BEFORE_VALIDATE]], - * [[EVENT_BEFORE_INSERT]], [[EVENT_AFTER_INSERT]] and [[EVENT_AFTER_VALIDATE]] - * will be raised by the corresponding methods. - * - * Only the [[dirtyAttributes|changed attribute values]] will be inserted into database. - * - * If the [[primaryKey|primary key]] is not set (null) during insertion, - * it will be populated with a - * [randomly generated value](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-index_.html#_automatic_id_generation) - * after insertion. - * - * For example, to insert a customer record: - * - * ~~~ - * $customer = new Customer; - * $customer->name = $name; - * $customer->email = $email; - * $customer->insert(); - * ~~~ - * - * @param boolean $runValidation whether to perform validation before saving the record. - * If the validation fails, the record will not be inserted into the database. - * @param array $attributes list of attributes that need to be saved. Defaults to null, - * meaning all attributes will be saved. - * @param array $options options given in this parameter are passed to elasticsearch - * as request URI parameters. These are among others: - * - * - `routing` define shard placement of this record. - * - `parent` by giving the primaryKey of another record this defines a parent-child relation - * - `timestamp` specifies the timestamp to store along with the document. Default is indexing time. - * - * Please refer to the [elasticsearch documentation](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-index_.html) - * for more details on these options. - * - * By default the `op_type` is set to `create`. - * @return boolean whether the attributes are valid and the record is inserted successfully. - */ - public function insert($runValidation = true, $attributes = null, $options = ['op_type' => 'create']) - { - if ($runValidation && !$this->validate($attributes)) { - return false; - } - if ($this->beforeSave(true)) { - $values = $this->getDirtyAttributes($attributes); - - $response = static::getDb()->createCommand()->insert( - static::index(), - static::type(), - $values, - $this->getPrimaryKey(), - $options - ); - - if (!$response['ok']) { - return false; - } - $this->_id = $response['_id']; - $this->_version = $response['_version']; - $this->setOldAttributes($values); - $this->afterSave(true); - return true; - } - return false; - } - - /** - * Updates all records whos primary keys are given. - * For example, to change the status to be 1 for all customers whose status is 2: - * - * ~~~ - * Customer::updateAll(array('status' => 1), array(2, 3, 4)); - * ~~~ - * - * @param array $attributes attribute values (name-value pairs) to be saved into the table - * @param array $condition the conditions that will be put in the WHERE part of the UPDATE SQL. - * Please refer to [[ActiveQuery::where()]] on how to specify this parameter. - * @return integer the number of rows updated - */ - public static function updateAll($attributes, $condition = []) - { - if (count($condition) == 1 && isset($condition[ActiveRecord::PRIMARY_KEY_NAME])) { - $primaryKeys = (array) $condition[ActiveRecord::PRIMARY_KEY_NAME]; - } else { - $primaryKeys = static::find()->where($condition)->column(ActiveRecord::PRIMARY_KEY_NAME); - } - if (empty($primaryKeys)) { - return 0; - } - $bulk = ''; - foreach((array) $primaryKeys as $pk) { - $action = Json::encode([ - "update" => [ - "_id" => $pk, - "_type" => static::type(), - "_index" => static::index(), - ], - ]); - $data = Json::encode([ - "doc" => $attributes - ]); - $bulk .= $action . "\n" . $data . "\n"; - } - - // TODO do this via command - $url = [static::index(), static::type(), '_bulk']; - $response = static::getDb()->post($url, [], $bulk); - $n=0; - foreach($response['items'] as $item) { - if ($item['update']['ok']) { - $n++; - } - } - return $n; - } - - /** - * Updates all matching records using the provided counter changes and conditions. - * For example, to increment all customers' age by 1, - * - * ~~~ - * Customer::updateAllCounters(['age' => 1]); - * ~~~ - * - * @param array $counters the counters to be updated (attribute name => increment value). - * Use negative values if you want to decrement the counters. - * @param string|array $condition the conditions that will be put in the WHERE part of the UPDATE SQL. - * Please refer to [[Query::where()]] on how to specify this parameter. - * @return integer the number of rows updated - */ - public static function updateAllCounters($counters, $condition = []) - { - if (count($condition) == 1 && isset($condition[ActiveRecord::PRIMARY_KEY_NAME])) { - $primaryKeys = (array) $condition[ActiveRecord::PRIMARY_KEY_NAME]; - } else { - $primaryKeys = static::find()->where($condition)->column(ActiveRecord::PRIMARY_KEY_NAME); - } - if (empty($primaryKeys) || empty($counters)) { - return 0; - } - $bulk = ''; - foreach((array) $primaryKeys as $pk) { - $action = Json::encode([ - "update" => [ - "_id" => $pk, - "_type" => static::type(), - "_index" => static::index(), - ], - ]); - $script = ''; - foreach($counters as $counter => $value) { - $script .= "ctx._source.$counter += $counter;\n"; - } - $data = Json::encode([ - "script" => $script, - "params" => $counters - ]); - $bulk .= $action . "\n" . $data . "\n"; - } - - // TODO do this via command - $url = [static::index(), static::type(), '_bulk']; - $response = static::getDb()->post($url, [], $bulk); - - $n=0; - foreach($response['items'] as $item) { - if ($item['update']['ok']) { - $n++; - } - } - return $n; - } - - /** - * Deletes rows in the table using the provided conditions. - * WARNING: If you do not specify any condition, this method will delete ALL rows in the table. - * - * For example, to delete all customers whose status is 3: - * - * ~~~ - * Customer::deleteAll('status = 3'); - * ~~~ - * - * @param array $condition the conditions that will be put in the WHERE part of the DELETE SQL. - * Please refer to [[ActiveQuery::where()]] on how to specify this parameter. - * @return integer the number of rows deleted - */ - public static function deleteAll($condition = []) - { - if (count($condition) == 1 && isset($condition[ActiveRecord::PRIMARY_KEY_NAME])) { - $primaryKeys = (array) $condition[ActiveRecord::PRIMARY_KEY_NAME]; - } else { - $primaryKeys = static::find()->where($condition)->column(ActiveRecord::PRIMARY_KEY_NAME); - } - if (empty($primaryKeys)) { - return 0; - } - $bulk = ''; - foreach((array) $primaryKeys as $pk) { - $bulk .= Json::encode([ - "delete" => [ - "_id" => $pk, - "_type" => static::type(), - "_index" => static::index(), - ], - ]) . "\n"; - } - - // TODO do this via command - $url = [static::index(), static::type(), '_bulk']; - $response = static::getDb()->post($url, [], $bulk); - $n=0; - foreach($response['items'] as $item) { - if ($item['delete']['found'] && $item['delete']['ok']) { - $n++; - } - } - return $n; - } -} diff --git a/extensions/elasticsearch/ActiveRelation.php b/extensions/elasticsearch/ActiveRelation.php deleted file mode 100644 index a102697..0000000 --- a/extensions/elasticsearch/ActiveRelation.php +++ /dev/null @@ -1,61 +0,0 @@ - - * @since 2.0 - */ -class ActiveRelation extends ActiveQuery implements ActiveRelationInterface -{ - use ActiveRelationTrait; - - /** - * Creates a DB command that can be used to execute this query. - * @param Connection $db the DB connection used to create the DB command. - * If null, the DB connection returned by [[modelClass]] will be used. - * @return Command the created DB command instance. - */ - public function createCommand($db = null) - { - if ($this->primaryModel !== null) { - // lazy loading - if (is_array($this->via)) { - // via relation - /** @var ActiveRelation $viaQuery */ - list($viaName, $viaQuery) = $this->via; - if ($viaQuery->multiple) { - $viaModels = $viaQuery->all(); - $this->primaryModel->populateRelation($viaName, $viaModels); - } else { - $model = $viaQuery->one(); - $this->primaryModel->populateRelation($viaName, $model); - $viaModels = $model === null ? [] : [$model]; - } - $this->filterByModels($viaModels); - } else { - $this->filterByModels([$this->primaryModel]); - } - } - return parent::createCommand($db); - } -} diff --git a/extensions/elasticsearch/Command.php b/extensions/elasticsearch/Command.php deleted file mode 100644 index bc4bb2f..0000000 --- a/extensions/elasticsearch/Command.php +++ /dev/null @@ -1,403 +0,0 @@ - - * @since 2.0 - */ -class Command extends Component -{ - /** - * @var Connection - */ - public $db; - /** - * @var string|array the indexes to execute the query on. Defaults to null meaning all indexes - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search.html#search-multi-index - */ - public $index; - /** - * @var string|array the types to execute the query on. Defaults to null meaning all types - */ - public $type; - /** - * @var array list of arrays or json strings that become parts of a query - */ - public $queryParts; - - public $options = []; - - /** - * @param array $options - * @return mixed - */ - public function search($options = []) - { - $query = $this->queryParts; - if (empty($query)) { - $query = '{}'; - } - if (is_array($query)) { - $query = Json::encode($query); - } - $url = [ - $this->index !== null ? $this->index : '_all', - $this->type !== null ? $this->type : '_all', - '_search' - ]; - return $this->db->get($url, array_merge($this->options, $options), $query); - } - - /** - * Inserts a document into an index - * @param string $index - * @param string $type - * @param string|array $data json string or array of data to store - * @param null $id the documents id. If not specified Id will be automatically choosen - * @param array $options - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-index_.html - */ - public function insert($index, $type, $data, $id = null, $options = []) - { - $body = is_array($data) ? Json::encode($data) : $data; - - if ($id !== null) { - return $this->db->put([$index, $type, $id], $options, $body); - } else { - return $this->db->post([$index, $type], $options, $body); - } - } - - /** - * gets a document from the index - * @param $index - * @param $type - * @param $id - * @param array $options - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-get.html - */ - public function get($index, $type, $id, $options = []) - { - return $this->db->get([$index, $type, $id], $options, null); - } - - /** - * gets multiple documents from the index - * - * TODO allow specifying type and index + fields - * @param $index - * @param $type - * @param $ids - * @param array $options - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-multi-get.html - */ - public function mget($index, $type, $ids, $options = []) - { - $body = Json::encode(['ids' => array_values($ids)]); - return $this->db->get([$index, $type, '_mget'], $options, $body); - } - - /** - * gets a documents _source from the index (>=v0.90.1) - * @param $index - * @param $type - * @param $id - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-get.html#_source - */ - public function getSource($index, $type, $id) - { - return $this->db->get([$index, $type, $id]); - } - - /** - * gets a document from the index - * @param $index - * @param $type - * @param $id - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-get.html - */ - public function exists($index, $type, $id) - { - return $this->db->head([$index, $type, $id]); - } - - /** - * deletes a document from the index - * @param $index - * @param $type - * @param $id - * @param array $options - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-delete.html - */ - public function delete($index, $type, $id, $options = []) - { - return $this->db->delete([$index, $type, $id], $options); - } - - /** - * updates a document - * @param $index - * @param $type - * @param $id - * @param array $options - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-update.html - */ -// public function update($index, $type, $id, $data, $options = []) -// { -// // TODO implement -//// return $this->db->delete([$index, $type, $id], $options); -// } - - // TODO bulk http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-bulk.html - - /** - * creates an index - * @param $index - * @param array $configuration - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-create-index.html - */ - public function createIndex($index, $configuration = null) - { - $body = $configuration !== null ? Json::encode($configuration) : null; - return $this->db->put([$index], $body); - } - - /** - * deletes an index - * @param $index - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-delete-index.html - */ - public function deleteIndex($index) - { - return $this->db->delete([$index]); - } - - /** - * deletes all indexes - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-delete-index.html - */ - public function deleteAllIndexes() - { - return $this->db->delete(['_all']); - } - - /** - * checks whether an index exists - * @param $index - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-exists.html - */ - public function indexExists($index) - { - return $this->db->head([$index]); - } - - /** - * @param $index - * @param $type - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-types-exists.html - */ - public function typeExists($index, $type) - { - return $this->db->head([$index, $type]); - } - - // TODO http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-aliases.html - - // TODO http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-update-settings.html - // TODO http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-get-settings.html - - // TODO http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-warmers.html - - /** - * @param $index - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-open-close.html - */ - public function openIndex($index) - { - return $this->db->post([$index, '_open']); - } - - /** - * @param $index - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-open-close.html - */ - public function closeIndex($index) - { - return $this->db->post([$index, '_close']); - } - - /** - * @param $index - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-status.html - */ - public function getIndexStatus($index = '_all') - { - return $this->db->get([$index, '_status']); - } - - // TODO http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-stats.html - // http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-segments.html - - /** - * @param $index - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-clearcache.html - */ - public function clearIndexCache($index) - { - return $this->db->post([$index, '_cache', 'clear']); - } - - /** - * @param $index - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-flush.html - */ - public function flushIndex($index = '_all') - { - return $this->db->post([$index, '_flush']); - } - - /** - * @param $index - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-refresh.html - */ - public function refreshIndex($index) - { - return $this->db->post([$index, '_refresh']); - } - - // TODO http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-optimize.html - - // TODO http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-gateway-snapshot.html - - /** - * @param $index - * @param $type - * @param $mapping - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-put-mapping.html - */ - public function setMapping($index, $type, $mapping, $options = []) - { - $body = $mapping !== null ? (is_string($mapping) ? $mapping : Json::encode($mapping)) : null; - return $this->db->put([$index, $type, '_mapping'], $options, $body); - } - - /** - * @param string $index - * @param string $type - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-get-mapping.html - */ - public function getMapping($index = '_all', $type = '_all') - { - return $this->db->get([$index, $type, '_mapping']); - } - - /** - * @param $index - * @param $type - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-put-mapping.html - */ - public function deleteMapping($index, $type) - { - return $this->db->delete([$index, $type]); - } - - /** - * @param $index - * @param string $type - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-get-field-mapping.html - */ - public function getFieldMapping($index, $type = '_all') - { - return $this->db->put([$index, $type, '_mapping']); - } - - /** - * @param $options - * @param $index - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-analyze.html - */ -// public function analyze($options, $index = null) -// { -// // TODO implement -//// return $this->db->put([$index]); -// } - - /** - * @param $name - * @param $pattern - * @param $settings - * @param $mappings - * @param int $order - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-templates.html - */ - public function createTemplate($name, $pattern, $settings, $mappings, $order = 0) - { - $body = Json::encode([ - 'template' => $pattern, - 'order' => $order, - 'settings' => (object) $settings, - 'mappings' => (object) $mappings, - ]); - return $this->db->put(['_template', $name], $body); - - } - - /** - * @param $name - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-templates.html - */ - public function deleteTemplate($name) - { - return $this->db->delete(['_template', $name]); - - } - - /** - * @param $name - * @return mixed - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-templates.html - */ - public function getTemplate($name) - { - return $this->db->get(['_template', $name]); - } -} \ No newline at end of file diff --git a/extensions/elasticsearch/Connection.php b/extensions/elasticsearch/Connection.php deleted file mode 100644 index 75de7a3..0000000 --- a/extensions/elasticsearch/Connection.php +++ /dev/null @@ -1,358 +0,0 @@ - - * @since 2.0 - */ -class Connection extends Component -{ - /** - * @event Event an event that is triggered after a DB connection is established - */ - const EVENT_AFTER_OPEN = 'afterOpen'; - - /** - * @var bool whether to autodetect available cluster nodes on [[open()]] - */ - public $autodetectCluster = true; - /** - * @var array cluster nodes - * This is populated with the result of a cluster nodes request when [[autodetectCluster]] is true. - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/cluster-nodes-info.html#cluster-nodes-info - */ - public $nodes = [ - ['http_address' => 'inet[/127.0.0.1:9200]'], - ]; - /** - * @var array the active node. key of [[nodes]]. Will be randomly selected on [[open()]]. - */ - public $activeNode; - - // TODO http://www.elasticsearch.org/guide/en/elasticsearch/client/php-api/current/_configuration.html#_example_configuring_http_basic_auth - public $auth = []; - /** - * @var float timeout to use for connecting to an elasticsearch node. - * This value will be used to configure the curl `CURLOPT_CONNECTTIMEOUT` option. - * If not set, no explicit timeout will be set for curl. - */ - public $connectionTimeout = null; - /** - * @var float timeout to use when reading the response from an elasticsearch node. - * This value will be used to configure the curl `CURLOPT_TIMEOUT` option. - * If not set, no explicit timeout will be set for curl. - */ - public $dataTimeout = null; - - - public function init() - { - foreach($this->nodes as $node) { - if (!isset($node['http_address'])) { - throw new InvalidConfigException('Elasticsearch node needs at least a http_address configured.'); - } - } - } - - /** - * Closes the connection when this component is being serialized. - * @return array - */ - public function __sleep() - { - $this->close(); - return array_keys(get_object_vars($this)); - } - - /** - * Returns a value indicating whether the DB connection is established. - * @return boolean whether the DB connection is established - */ - public function getIsActive() - { - return $this->activeNode !== null; - } - - /** - * Establishes a DB connection. - * It does nothing if a DB connection has already been established. - * @throws Exception if connection fails - */ - public function open() - { - if ($this->activeNode !== null) { - return; - } - if (empty($this->nodes)) { - throw new InvalidConfigException('elasticsearch needs at least one node to operate.'); - } - if ($this->autodetectCluster) { - $node = reset($this->nodes); - $host = $node['http_address']; - if (strncmp($host, 'inet[/', 6) == 0) { - $host = substr($host, 6, -1); - } - $response = $this->httpRequest('GET', 'http://' . $host . '/_cluster/nodes'); - $this->nodes = $response['nodes']; - if (empty($this->nodes)) { - throw new Exception('cluster autodetection did not find any active node.'); - } - } - $this->selectActiveNode(); - Yii::trace('Opening connection to elasticsearch. Nodes in cluster: ' . count($this->nodes) - . ', active node: ' . $this->nodes[$this->activeNode]['http_address'], __CLASS__); - $this->initConnection(); - } - - /** - * select active node randomly - */ - protected function selectActiveNode() - { - $keys = array_keys($this->nodes); - $this->activeNode = $keys[rand(0, count($keys) - 1)]; - } - - /** - * Closes the currently active DB connection. - * It does nothing if the connection is already closed. - */ - public function close() - { - Yii::trace('Closing connection to elasticsearch. Active node was: ' - . $this->nodes[$this->activeNode]['http_address'], __CLASS__); - $this->activeNode = null; - } - - /** - * Initializes the DB connection. - * This method is invoked right after the DB connection is established. - * The default implementation triggers an [[EVENT_AFTER_OPEN]] event. - */ - protected function initConnection() - { - $this->trigger(self::EVENT_AFTER_OPEN); - } - - /** - * Returns the name of the DB driver for the current [[dsn]]. - * @return string name of the DB driver - */ - public function getDriverName() - { - return 'elasticsearch'; - } - - /** - * Creates a command for execution. - * @param array $config the configuration for the Command class - * @return Command the DB command - */ - public function createCommand($config = []) - { - $this->open(); - $config['db'] = $this; - $command = new Command($config); - return $command; - } - - public function getQueryBuilder() - { - return new QueryBuilder($this); - } - - public function get($url, $options = [], $body = null, $raw = false) - { - $this->open(); - return $this->httpRequest('GET', $this->createUrl($url, $options), $body, $raw); - } - - public function head($url, $options = [], $body = null) - { - $this->open(); - return $this->httpRequest('HEAD', $this->createUrl($url, $options), $body); - } - - public function post($url, $options = [], $body = null, $raw = false) - { - $this->open(); - return $this->httpRequest('POST', $this->createUrl($url, $options), $body, $raw); - } - - public function put($url, $options = [], $body = null, $raw = false) - { - $this->open(); - return $this->httpRequest('PUT', $this->createUrl($url, $options), $body, $raw); - } - - public function delete($url, $options = [], $body = null, $raw = false) - { - $this->open(); - return $this->httpRequest('DELETE', $this->createUrl($url, $options), $body, $raw); - } - - private function createUrl($path, $options = []) - { - if (!is_string($path)) { - $url = implode('/', array_map(function($a) { - return urlencode(is_array($a) ? implode(',', $a) : $a); - }, $path)); - if (!empty($options)) { - $url .= '?' . http_build_query($options); - } - } else { - $url = $path; - if (!empty($options)) { - $url .= (strpos($url, '?') === false ? '?' : '&') . http_build_query($options); - } - } - return [$this->nodes[$this->activeNode]['http_address'], $url]; - } - - protected function httpRequest($method, $url, $requestBody = null, $raw = false) - { - $method = strtoupper($method); - - // response body and headers - $headers = []; - $body = ''; - - $options = [ - CURLOPT_USERAGENT => 'Yii Framework 2 ' . __CLASS__, - CURLOPT_RETURNTRANSFER => false, - CURLOPT_HEADER => false, - // http://www.php.net/manual/en/function.curl-setopt.php#82418 - CURLOPT_HTTPHEADER => ['Expect:'], - - CURLOPT_WRITEFUNCTION => function($curl, $data) use (&$body) { - $body .= $data; - return mb_strlen($data, '8bit'); - }, - CURLOPT_HEADERFUNCTION => function($curl, $data) use (&$headers) { - foreach(explode("\r\n", $data) as $row) { - if (($pos = strpos($row, ':')) !== false) { - $headers[strtolower(substr($row, 0, $pos))] = trim(substr($row, $pos + 1)); - } - } - return mb_strlen($data, '8bit'); - }, - CURLOPT_CUSTOMREQUEST => $method, - ]; - if ($this->connectionTimeout !== null) { - $options[CURLOPT_CONNECTTIMEOUT] = $this->connectionTimeout; - } - if ($this->dataTimeout !== null) { - $options[CURLOPT_TIMEOUT] = $this->dataTimeout; - } - if ($requestBody !== null) { - $options[CURLOPT_POSTFIELDS] = $requestBody; - } - if ($method == 'HEAD') { - $options[CURLOPT_NOBODY] = true; - unset($options[CURLOPT_WRITEFUNCTION]); - } - - if (is_array($url)) { - list($host, $q) = $url; - if (strncmp($host, 'inet[', 5) == 0) { - $host = substr($host, 5, -1); - if (($pos = strpos($host, '/')) !== false) { - $host = substr($host, $pos + 1); - } - } - $profile = $method . ' ' . $q . '#' . $requestBody; - $url = 'http://' . $host . '/' . $q; - } else { - $profile = false; - } - - Yii::trace("Sending request to elasticsearch node: $url\n$requestBody", __METHOD__); - if ($profile !== false) { - Yii::beginProfile($profile, __METHOD__); - } - - $curl = curl_init($url); - curl_setopt_array($curl, $options); - if (curl_exec($curl) === false) { - throw new Exception('Elasticsearch request failed: ' . curl_errno($curl) . ' - ' . curl_error($curl), [ - 'requestMethod' => $method, - 'requestUrl' => $url, - 'requestBody' => $requestBody, - 'responseHeaders' => $headers, - 'responseBody' => $body, - ]); - } - - $responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); - curl_close($curl); - - if ($profile !== false) { - Yii::endProfile($profile, __METHOD__); - } - - if ($responseCode >= 200 && $responseCode < 300) { - if ($method == 'HEAD') { - return true; - } else { - if (isset($headers['content-length']) && ($len = mb_strlen($body, '8bit')) < $headers['content-length']) { - throw new Exception("Incomplete data received from elasticsearch: $len < {$headers['content-length']}", [ - 'requestMethod' => $method, - 'requestUrl' => $url, - 'requestBody' => $requestBody, - 'responseCode' => $responseCode, - 'responseHeaders' => $headers, - 'responseBody' => $body, - ]); - } - if (isset($headers['content-type']) && !strncmp($headers['content-type'], 'application/json', 16)) { - return $raw ? $body : Json::decode($body); - } - throw new Exception('Unsupported data received from elasticsearch: ' . $headers['content-type'], [ - 'requestMethod' => $method, - 'requestUrl' => $url, - 'requestBody' => $requestBody, - 'responseCode' => $responseCode, - 'responseHeaders' => $headers, - 'responseBody' => $body, - ]); - } - } elseif ($responseCode == 404) { - return false; - } else { - throw new Exception("Elasticsearch request failed with code $responseCode.", [ - 'requestMethod' => $method, - 'requestUrl' => $url, - 'requestBody' => $requestBody, - 'responseCode' => $responseCode, - 'responseHeaders' => $headers, - 'responseBody' => $body, - ]); - } - } - - public function getNodeInfo() - { - return $this->get([]); - } - - public function getClusterState() - { - return $this->get(['_cluster', 'state']); - } -} \ No newline at end of file diff --git a/extensions/elasticsearch/DebugAction.php b/extensions/elasticsearch/DebugAction.php deleted file mode 100644 index d4ddd41..0000000 --- a/extensions/elasticsearch/DebugAction.php +++ /dev/null @@ -1,76 +0,0 @@ - - */ - -namespace yii\elasticsearch; - - -use yii\base\Action; -use yii\base\NotSupportedException; -use yii\debug\Panel; -use yii\helpers\ArrayHelper; -use yii\web\HttpException; -use Yii; -use yii\web\Response; - -class DebugAction extends Action -{ - /** - * @var string the connection id to use - */ - public $db; - /** - * @var Panel - */ - public $panel; - - public function run($logId, $tag) - { - $this->controller->loadData($tag); - - $timings = $this->panel->calculateTimings(); - ArrayHelper::multisort($timings, 3, SORT_DESC); - if (!isset($timings[$logId])) { - throw new HttpException(404, 'Log message not found.'); - } - $message = $timings[$logId][1]; - if (($pos = mb_strpos($message, "#")) !== false) { - $url = mb_substr($message, 0, $pos); - $body = mb_substr($message, $pos + 1); - } else { - $url = $message; - $body = null; - } - $method = mb_substr($url, 0, $pos = mb_strpos($url, ' ')); - $url = mb_substr($url, $pos + 1); - - $options = ['pretty' => true]; - - /** @var Connection $db */ - $db = \Yii::$app->getComponent($this->db); - $time = microtime(true); - switch($method) { - case 'GET': $result = $db->get($url, $options, $body, true); break; - case 'POST': $result = $db->post($url, $options, $body, true); break; - case 'PUT': $result = $db->put($url, $options, $body, true); break; - case 'DELETE': $result = $db->delete($url, $options, $body, true); break; - case 'HEAD': $result = $db->head($url, $options, $body); break; - default: - throw new NotSupportedException("Request method '$method' is not supported by elasticsearch."); - } - $time = microtime(true) - $time; - - if ($result === true) { - $result = 'success'; - } elseif ($result === false) { - $result = 'no success'; - } - - Yii::$app->response->format = Response::FORMAT_JSON; - return [ - 'time' => sprintf('%.1f ms', $time * 1000), - 'result' => $result, - ]; - } -} \ No newline at end of file diff --git a/extensions/elasticsearch/DebugPanel.php b/extensions/elasticsearch/DebugPanel.php deleted file mode 100644 index 1782b8d..0000000 --- a/extensions/elasticsearch/DebugPanel.php +++ /dev/null @@ -1,177 +0,0 @@ - - * @since 2.0 - */ -class DebugPanel extends Panel -{ - public $db = 'elasticsearch'; - - public function init() - { - $this->actions['elasticsearch-query'] = [ - 'class' => 'yii\\elasticsearch\\DebugAction', - 'panel' => $this, - 'db' => $this->db, - ]; - } - - public function getName() - { - return 'Elasticsearch'; - } - - public function getSummary() - { - $timings = $this->calculateTimings(); - $queryCount = count($timings); - $queryTime = 0; - foreach ($timings as $timing) { - $queryTime += $timing[3]; - } - $queryTime = number_format($queryTime * 1000) . ' ms'; - $url = $this->getUrl(); - $output = << - - ES $queryCount $queryTime - - -EOD; - return $queryCount > 0 ? $output : ''; - } - - public function getDetail() - { - $timings = $this->calculateTimings(); - ArrayHelper::multisort($timings, 3, SORT_DESC); - $rows = []; - $i = 0; - foreach ($timings as $logId => $timing) { - $duration = sprintf('%.1f ms', $timing[3] * 1000); - $message = $timing[1]; - $traces = $timing[4]; - if (($pos = mb_strpos($message, "#")) !== false) { - $url = mb_substr($message, 0, $pos); - $body = mb_substr($message, $pos + 1); - } else { - $url = $message; - $body = null; - } - $traceString = ''; - if (!empty($traces)) { - $traceString .= Html::ul($traces, [ - 'class' => 'trace', - 'item' => function ($trace) { - return "
  • {$trace['file']}({$trace['line']})
  • "; - }, - ]); - } - $ajaxUrl = Html::url(['elasticsearch-query', 'logId' => $logId, 'tag' => $this->tag]); - \Yii::$app->view->registerJs(<<Error: ' + errorThrown + ' - ' + textStatus + '
    ' + jqXHR.responseText); - }, - dataType: "json" - }); - - return false; -}); -JS -, View::POS_READY); - $runLink = Html::a('run query', '#', ['id' => "elastic-link-$i"]) . '
    '; - $rows[] = << - $duration -
    $url

    $body

    $traceString
    - $runLink - - -HTML; - $i++; - } - $rows = implode("\n", $rows); - return <<Elasticsearch Queries - - - - - - - - - - -$rows - -
    TimeUrl / QueryRun Query on node
    -HTML; - } - - private $_timings; - - public function calculateTimings() - { - if ($this->_timings !== null) { - return $this->_timings; - } - $messages = $this->data['messages']; - $timings = []; - $stack = []; - foreach ($messages as $i => $log) { - list($token, $level, $category, $timestamp) = $log; - $log[5] = $i; - if ($level == Logger::LEVEL_PROFILE_BEGIN) { - $stack[] = $log; - } elseif ($level == Logger::LEVEL_PROFILE_END) { - if (($last = array_pop($stack)) !== null && $last[0] === $token) { - $timings[$last[5]] = [count($stack), $token, $last[3], $timestamp - $last[3], $last[4]]; - } - } - } - - $now = microtime(true); - while (($last = array_pop($stack)) !== null) { - $delta = $now - $last[3]; - $timings[$last[5]] = [count($stack), $last[0], $last[2], $delta, $last[4]]; - } - ksort($timings); - return $this->_timings = $timings; - } - - public function save() - { - $target = $this->module->logTarget; - $messages = $target->filterMessages($target->messages, Logger::LEVEL_PROFILE, ['yii\elasticsearch\Connection::httpRequest']); - return ['messages' => $messages]; - } -} diff --git a/extensions/elasticsearch/Exception.php b/extensions/elasticsearch/Exception.php deleted file mode 100644 index ade7cd1..0000000 --- a/extensions/elasticsearch/Exception.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class Exception extends \yii\db\Exception -{ - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return \Yii::t('yii', 'Elasticsearch Database Exception'); - } -} \ No newline at end of file diff --git a/extensions/elasticsearch/LICENSE.md b/extensions/elasticsearch/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/extensions/elasticsearch/LICENSE.md +++ /dev/null @@ -1,32 +0,0 @@ -The Yii framework is free software. It is released under the terms of -the following BSD License. - -Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Yii Software LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/extensions/elasticsearch/Query.php b/extensions/elasticsearch/Query.php deleted file mode 100644 index 79e58c3..0000000 --- a/extensions/elasticsearch/Query.php +++ /dev/null @@ -1,508 +0,0 @@ -fields('id, name') - * ->from('myindex', 'users') - * ->limit(10); - * // build and execute the query - * $command = $query->createCommand(); - * $rows = $command->search(); // this way you get the raw output of elasticsearch. - * ~~~ - * - * You would normally call `$query->search()` instead of creating a command as this method - * adds the `indexBy()` feature and also removes some inconsistencies from the response. - * - * Query also provides some methods to easier get some parts of the result only: - * - * - [[one()]]: returns a single record populated with the first row of data. - * - [[all()]]: returns all records based on the query results. - * - [[count()]]: returns the number of records. - * - [[scalar()]]: returns the value of the first column in the first row of the query result. - * - [[column()]]: returns the value of the first column in the query result. - * - [[exists()]]: returns a value indicating whether the query result has data or not. - * - * @author Carsten Brandt - * @since 2.0 - */ -class Query extends Component implements QueryInterface -{ - use QueryTrait; - - /** - * @var array the fields being retrieved from the documents. For example, `['id', 'name']`. - * If not set, it means retrieving all fields. An empty array will result in no fields being - * retrieved. This means that only the primaryKey of a record will be available in the result. - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-fields.html#search-request-fields - * @see fields() - */ - public $fields; - /** - * @var string|array The index to retrieve data from. This can be a string representing a single index - * or a an array of multiple indexes. If this is not set, indexes are being queried. - * @see from() - */ - public $index; - /** - * @var string|array The type to retrieve data from. This can be a string representing a single type - * or a an array of multiple types. If this is not set, all types are being queried. - * @see from() - */ - public $type; - /** - * @var integer A search timeout, bounding the search request to be executed within the specified time value - * and bail with the hits accumulated up to that point when expired. Defaults to no timeout. - * @see timeout() - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-body.html#_parameters_3 - */ - public $timeout; - /** - * @var array|string The query part of this search query. This is an array or json string that follows the format of - * the elasticsearch [Query DSL](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl.html). - */ - public $query; - /** - * @var array|string The filter part of this search query. This is an array or json string that follows the format of - * the elasticsearch [Query DSL](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl.html). - */ - public $filter; - - public $facets = []; - - public function init() - { - parent::init(); - // setting the default limit according to elasticsearch defaults - // http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-body.html#_parameters_3 - if ($this->limit === null) { - $this->limit = 10; - } - } - - /** - * Creates a DB command that can be used to execute this query. - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `elasticsearch` application component will be used. - * @return Command the created DB command instance. - */ - public function createCommand($db = null) - { - if ($db === null) { - $db = Yii::$app->getComponent('elasticsearch'); - } - - $commandConfig = $db->getQueryBuilder()->build($this); - return $db->createCommand($commandConfig); - } - - /** - * Executes the query and returns all results as an array. - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `elasticsearch` application component will be used. - * @return array the query results. If the query results in nothing, an empty array will be returned. - */ - public function all($db = null) - { - $result = $this->createCommand($db)->search(); - if (empty($result['hits']['hits'])) { - return []; - } - $rows = $result['hits']['hits']; - if ($this->indexBy === null && $this->fields === null) { - return $rows; - } - $models = []; - foreach ($rows as $key => $row) { - if ($this->fields !== null) { - $row['_source'] = isset($row['fields']) ? $row['fields'] : []; - unset($row['fields']); - } - if ($this->indexBy !== null) { - if (is_string($this->indexBy)) { - $key = $row['_source'][$this->indexBy]; - } else { - $key = call_user_func($this->indexBy, $row); - } - } - $models[$key] = $row; - } - return $models; - } - - /** - * Executes the query and returns a single row of result. - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `elasticsearch` application component will be used. - * @return array|boolean the first row (in terms of an array) of the query result. False is returned if the query - * results in nothing. - */ - public function one($db = null) - { - $options['size'] = 1; - $result = $this->createCommand($db)->search($options); - if (empty($result['hits']['hits'])) { - return false; - } - $record = reset($result['hits']['hits']); - if ($this->fields !== null) { - $record['_source'] = isset($record['fields']) ? $record['fields'] : []; - unset($record['fields']); - } - return $record; - } - - /** - * Executes the query and returns the complete search result including e.g. hits, facets, totalCount. - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `elasticsearch` application component will be used. - * @param array $options The options given with this query. Possible options are: - * - [routing](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search.html#search-routing) - * - [search_type](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-search-type.html) - * @return array the query results. - */ - public function search($db = null, $options = []) - { - $result = $this->createCommand($db)->search($options); - if (!empty($result['hits']['hits']) && ($this->indexBy === null || $this->fields === null)) { - $rows = []; - foreach ($result['hits']['hits'] as $key => $row) { - if ($this->fields !== null) { - $row['_source'] = isset($row['fields']) ? $row['fields'] : []; - unset($row['fields']); - } - if ($this->indexBy !== null) { - if (is_string($this->indexBy)) { - $key = $row['_source'][$this->indexBy]; - } else { - $key = call_user_func($this->indexBy, $row); - } - } - $rows[$key] = $row; - } - $result['hits']['hits'] = $rows; - } - return $result; - } - - // TODO add query stats http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search.html#stats-groups - - // TODO add scroll/scan http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-search-type.html#scan - - /** - * Executes the query and deletes all matching documents. - * - * This will not run facet queries. - * - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `elasticsearch` application component will be used. - * @return array the query results. If the query results in nothing, an empty array will be returned. - */ - public function delete($db = null) - { - // TODO implement http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-delete-by-query.html - throw new NotSupportedException('Delete by query is not implemented yet.'); - } - - /** - * Returns the query result as a scalar value. - * The value returned will be the specified field in the first document of the query results. - * @param string $field name of the attribute to select - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `elasticsearch` application component will be used. - * @return string the value of the specified attribute in the first record of the query result. - * Null is returned if the query result is empty or the field does not exist. - */ - public function scalar($field, $db = null) - { - $record = self::one($db); // TODO limit fields to the one required - if ($record !== false && isset($record['_source'][$field])) { - return $record['_source'][$field]; - } else { - return null; - } - } - - /** - * Executes the query and returns the first column of the result. - * @param string $field the field to query over - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `elasticsearch` application component will be used. - * @return array the first column of the query result. An empty array is returned if the query results in nothing. - */ - public function column($field, $db = null) - { - $command = $this->createCommand($db); - $command->queryParts['fields'] = [$field]; - $result = $command->search(); - if (empty($result['hits']['hits'])) { - return []; - } - $column = []; - foreach ($result['hits']['hits'] as $row) { - $column[] = isset($row['fields'][$field]) ? $row['fields'][$field] : null; - } - return $column; - } - - /** - * Returns the number of records. - * @param string $q the COUNT expression. This parameter is ignored by this implementation. - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `elasticsearch` application component will be used. - * @return integer number of records - */ - public function count($q = '*', $db = null) - { - // TODO consider sending to _count api instead of _search for performance - // only when no facety are registerted. - // http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-count.html - - $options = []; - $options['search_type'] = 'count'; - $count = $this->createCommand($db)->search($options)['hits']['total']; - if ($this->limit === null && $this->offset === null) { - return $count; - } elseif ($this->offset !== null) { - $count = $this->offset < $count ? $count - $this->offset : 0; - } - return $this->limit === null ? $count : ($this->limit > $count ? $count : $this->limit); - } - - /** - * Returns a value indicating whether the query result contains any row of data. - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `elasticsearch` application component will be used. - * @return boolean whether the query result contains any row of data. - */ - public function exists($db = null) - { - return self::one($db) !== false; - } - - /** - * Adds a facet search to this query. - * @param string $name the name of this facet - * @param string $type the facet type. e.g. `terms`, `range`, `histogram`... - * @param string|array $options the configuration options for this facet. Can be an array or a json string. - * @return static the query object itself - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-query-facet.html - */ - public function addFacet($name, $type, $options) - { - $this->facets[$name] = [$type => $options]; - return $this; - } - - /** - * The `terms facet` allow to specify field facets that return the N most frequent terms. - * @param string $name the name of this facet - * @param array $options additional option. Please refer to the elasticsearch documentation for details. - * @return static the query object itself - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-terms-facet.html - */ - public function addTermFacet($name, $options) - { - return $this->addFacet($name, 'terms', $options); - } - - /** - * Range facet allows to specify a set of ranges and get both the number of docs (count) that fall - * within each range, and aggregated data either based on the field, or using another field. - * @param string $name the name of this facet - * @param array $options additional option. Please refer to the elasticsearch documentation for details. - * @return static the query object itself - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-range-facet.html - */ - public function addRangeFacet($name, $options) - { - return $this->addFacet($name, 'range', $options); - } - - /** - * The histogram facet works with numeric data by building a histogram across intervals of the field values. - * Each value is "rounded" into an interval (or placed in a bucket), and statistics are provided per - * interval/bucket (count and total). - * @param string $name the name of this facet - * @param array $options additional option. Please refer to the elasticsearch documentation for details. - * @return static the query object itself - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-histogram-facet.html - */ - public function addHistogramFacet($name, $options) - { - return $this->addFacet($name, 'histogram', $options); - } - - /** - * A specific histogram facet that can work with date field types enhancing it over the regular histogram facet. - * @param string $name the name of this facet - * @param array $options additional option. Please refer to the elasticsearch documentation for details. - * @return static the query object itself - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-date-histogram-facet.html - */ - public function addDateHistogramFacet($name, $options) - { - return $this->addFacet($name, 'date_histogram', $options); - } - - /** - * A filter facet (not to be confused with a facet filter) allows you to return a count of the hits matching the filter. - * The filter itself can be expressed using the Query DSL. - * @param string $name the name of this facet - * @param string $filter the query in Query DSL - * @return static the query object itself - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-filter-facet.html - */ - public function addFilterFacet($name, $filter) - { - return $this->addFacet($name, 'filter', $filter); - } - - /** - * A facet query allows to return a count of the hits matching the facet query. - * The query itself can be expressed using the Query DSL. - * @param string $name the name of this facet - * @param string $query the query in Query DSL - * @return static the query object itself - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-query-facet.html - */ - public function addQueryFacet($name, $query) - { - return $this->addFacet($name, 'query', $query); - } - - /** - * Statistical facet allows to compute statistical data on a numeric fields. The statistical data include count, - * total, sum of squares, mean (average), minimum, maximum, variance, and standard deviation. - * @param string $name the name of this facet - * @param array $options additional option. Please refer to the elasticsearch documentation for details. - * @return static the query object itself - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-statistical-facet.html - */ - public function addStatisticalFacet($name, $options) - { - return $this->addFacet($name, 'statistical', $options); - } - - /** - * The `terms_stats` facet combines both the terms and statistical allowing to compute stats computed on a field, - * per term value driven by another field. - * @param string $name the name of this facet - * @param array $options additional option. Please refer to the elasticsearch documentation for details. - * @return static the query object itself - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-terms-stats-facet.html - */ - public function addTermsStatsFacet($name, $options) - { - return $this->addFacet($name, 'terms_stats', $options); - } - - /** - * The `geo_distance` facet is a facet providing information for ranges of distances from a provided `geo_point` - * including count of the number of hits that fall within each range, and aggregation information (like `total`). - * @param string $name the name of this facet - * @param array $options additional option. Please refer to the elasticsearch documentation for details. - * @return static the query object itself - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-geo-distance-facet.html - */ - public function addGeoDistanceFacet($name, $options) - { - return $this->addFacet($name, 'geo_distance', $options); - } - - // TODO add suggesters http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-suggesters.html - - // TODO add validate query http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-validate.html - - // TODO support multi query via static method http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-multi-search.html - - /** - * Sets the querypart of this search query. - * @param string $query - * @return static the query object itself - */ - public function query($query) - { - $this->query = $query; - return $this; - } - - /** - * Sets the filter part of this search query. - * @param string $filter - * @return static the query object itself - */ - public function filter($filter) - { - $this->filter = $filter; - return $this; - } - - /** - * Sets the index and type to retrieve documents from. - * @param string|array $index The index to retrieve data from. This can be a string representing a single index - * or a an array of multiple indexes. If this is `null` it means that all indexes are being queried. - * @param string|array $type The type to retrieve data from. This can be a string representing a single type - * or a an array of multiple types. If this is `null` it means that all types are being queried. - * @return static the query object itself - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-search.html#search-multi-index-type - */ - public function from($index, $type = null) - { - $this->index = $index; - $this->type = $type; - return $this; - } - - /** - * Sets the fields to retrieve from the documents. - * @param array $fields the fields to be selected. - * @return static the query object itself - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-fields.html - */ - public function fields($fields) - { - if (is_array($fields) || $fields === null) { - $this->fields = $fields; - } else { - $this->fields = func_get_args(); - } - return $this; - } - - /** - * Sets the search timeout. - * @param integer $timeout A search timeout, bounding the search request to be executed within the specified time value - * and bail with the hits accumulated up to that point when expired. Defaults to no timeout. - * @return static the query object itself - * @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-body.html#_parameters_3 - */ - public function timeout($timeout) - { - $this->timeout = $timeout; - return $this; - } -} \ No newline at end of file diff --git a/extensions/elasticsearch/QueryBuilder.php b/extensions/elasticsearch/QueryBuilder.php deleted file mode 100644 index 9201f9a..0000000 --- a/extensions/elasticsearch/QueryBuilder.php +++ /dev/null @@ -1,297 +0,0 @@ - - * @since 2.0 - */ -class QueryBuilder extends \yii\base\Object -{ - /** - * @var Connection the database connection. - */ - public $db; - - /** - * Constructor. - * @param Connection $connection the database connection. - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($connection, $config = []) - { - $this->db = $connection; - parent::__construct($config); - } - - /** - * Generates query from a [[Query]] object. - * @param Query $query the [[Query]] object from which the query will be generated - * @return array the generated SQL statement (the first array element) and the corresponding - * parameters to be bound to the SQL statement (the second array element). - */ - public function build($query) - { - $parts = []; - - if ($query->fields !== null) { - $parts['fields'] = (array) $query->fields; - } - if ($query->limit !== null && $query->limit >= 0) { - $parts['size'] = $query->limit; - } - if ($query->offset > 0) { - $parts['from'] = (int) $query->offset; - } - - if (empty($parts['query'])) { - $parts['query'] = ["match_all" => (object)[]]; - } - - $whereFilter = $this->buildCondition($query->where); - if (is_string($query->filter)) { - if (empty($whereFilter)) { - $parts['filter'] = $query->filter; - } else { - $parts['filter'] = '{"and": [' . $query->filter . ', ' . Json::encode($whereFilter) . ']}'; - } - } elseif ($query->filter !== null) { - if (empty($whereFilter)) { - $parts['filter'] = $query->filter; - } else { - $parts['filter'] = ['and' => [$query->filter, $whereFilter]]; - } - } elseif (!empty($whereFilter)) { - $parts['filter'] = $whereFilter; - } - - $sort = $this->buildOrderBy($query->orderBy); - if (!empty($sort)) { - $parts['sort'] = $sort; - } - - if (!empty($query->facets)) { - $parts['facets'] = $query->facets; - } - - $options = []; - if ($query->timeout !== null) { - $options['timeout'] = $query->timeout; - } - - return [ - 'queryParts' => $parts, - 'index' => $query->index, - 'type' => $query->type, - 'options' => $options, - ]; - } - - /** - * adds order by condition to the query - */ - public function buildOrderBy($columns) - { - if (empty($columns)) { - return []; - } - $orders = []; - foreach ($columns as $name => $direction) { - if (is_string($direction)) { - $column = $direction; - $direction = SORT_ASC; - } else { - $column = $name; - } - if ($column == ActiveRecord::PRIMARY_KEY_NAME) { - $column = '_uid'; - } - - // allow elasticsearch extended syntax as described in http://www.elasticsearch.org/guide/reference/api/search/sort/ - if (is_array($direction)) { - $orders[] = [$column => $direction]; - } else { - $orders[] = [$column => ($direction === SORT_DESC ? 'desc' : 'asc')]; - } - } - return $orders; - } - - /** - * Parses the condition specification and generates the corresponding SQL expression. - * @param string|array $condition the condition specification. Please refer to [[Query::where()]] - * on how to specify a condition. - * @param array $params the binding parameters to be populated - * @return string the generated SQL expression - * @throws \yii\db\Exception if the condition is in bad format - */ - public function buildCondition($condition) - { - static $builders = array( - 'and' => 'buildAndCondition', - 'or' => 'buildAndCondition', - 'between' => 'buildBetweenCondition', - 'not between' => 'buildBetweenCondition', - 'in' => 'buildInCondition', - 'not in' => 'buildInCondition', - 'like' => 'buildLikeCondition', - 'not like' => 'buildLikeCondition', - 'or like' => 'buildLikeCondition', - 'or not like' => 'buildLikeCondition', - ); - - if (empty($condition)) { - return []; - } - if (!is_array($condition)) { - throw new NotSupportedException('String conditions in where() are not supported by elasticsearch.'); - } - if (isset($condition[0])) { // operator format: operator, operand 1, operand 2, ... - $operator = strtolower($condition[0]); - if (isset($builders[$operator])) { - $method = $builders[$operator]; - array_shift($condition); - return $this->$method($operator, $condition); - } else { - throw new InvalidParamException('Found unknown operator in query: ' . $operator); - } - } else { // hash format: 'column1' => 'value1', 'column2' => 'value2', ... - return $this->buildHashCondition($condition); - } - } - - private function buildHashCondition($condition) - { - $parts = []; - foreach($condition as $attribute => $value) { - if ($attribute == ActiveRecord::PRIMARY_KEY_NAME) { - if ($value == null) { // there is no null pk - $parts[] = ['script' => ['script' => '0==1']]; - } else { - $parts[] = ['ids' => ['values' => is_array($value) ? $value : [$value]]]; - } - } else { - if (is_array($value)) { // IN condition - $parts[] = ['in' => [$attribute => $value]]; - } else { - if ($value === null) { - $parts[] = ['missing' => ['field' => $attribute, 'existence' => true, 'null_value' => true]]; - } else { - $parts[] = ['term' => [$attribute => $value]]; - } - } - } - } - return count($parts) === 1 ? $parts[0] : ['and' => $parts]; - } - - private function buildAndCondition($operator, $operands) - { - $parts = []; - foreach ($operands as $operand) { - if (is_array($operand)) { - $operand = $this->buildCondition($operand); - } - if (!empty($operand)) { - $parts[] = $operand; - } - } - if (!empty($parts)) { - return [$operator => $parts]; - } else { - return []; - } - } - - private function buildBetweenCondition($operator, $operands) - { - if (!isset($operands[0], $operands[1], $operands[2])) { - throw new InvalidParamException("Operator '$operator' requires three operands."); - } - - list($column, $value1, $value2) = $operands; - if ($column == ActiveRecord::PRIMARY_KEY_NAME) { - throw new NotSupportedException('Between condition is not supported for primaryKey.'); - } - $filter = ['range' => [$column => ['gte' => $value1, 'lte' => $value2]]]; - if ($operator == 'not between') { - $filter = ['not' => $filter]; - } - return $filter; - } - - private function buildInCondition($operator, $operands) - { - if (!isset($operands[0], $operands[1])) { - throw new InvalidParamException("Operator '$operator' requires two operands."); - } - - list($column, $values) = $operands; - - $values = (array)$values; - - if (empty($values) || $column === []) { - return $operator === 'in' ? ['script' => ['script' => '0==1']] : []; - } - - if (count($column) > 1) { - return $this->buildCompositeInCondition($operator, $column, $values); - } elseif (is_array($column)) { - $column = reset($column); - } - $canBeNull = false; - foreach ($values as $i => $value) { - if (is_array($value)) { - $values[$i] = $value = isset($value[$column]) ? $value[$column] : null; - } - if ($value === null) { - $canBeNull = true; - unset($values[$i]); - } - } - if ($column == ActiveRecord::PRIMARY_KEY_NAME) { - if (empty($values) && $canBeNull) { // there is no null pk - $filter = ['script' => ['script' => '0==1']]; - } else { - $filter = ['ids' => ['values' => array_values($values)]]; - if ($canBeNull) { - $filter = ['or' => [$filter, ['missing' => ['field' => $column, 'existence' => true, 'null_value' => true]]]]; - } - } - } else { - if (empty($values) && $canBeNull) { - $filter = ['missing' => ['field' => $column, 'existence' => true, 'null_value' => true]]; - } else { - $filter = ['in' => [$column => array_values($values)]]; - if ($canBeNull) { - $filter = ['or' => [$filter, ['missing' => ['field' => $column, 'existence' => true, 'null_value' => true]]]]; - } - } - } - if ($operator == 'not in') { - $filter = ['not' => $filter]; - } - return $filter; - } - - protected function buildCompositeInCondition($operator, $columns, $values) - { - throw new NotSupportedException('composite in is not supported by elasticsearch.'); - } - - private function buildLikeCondition($operator, $operands) - { - throw new NotSupportedException('like conditions is not supported by elasticsearch.'); - } -} diff --git a/extensions/elasticsearch/README-debug.png b/extensions/elasticsearch/README-debug.png deleted file mode 100644 index 8877a604a751df3c702838e3677c41c88207a236..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107733 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 [ - 'elasticsearch' => [ - 'class' => 'yii\elasticsearch\Connection', - 'nodes' => [ - ['http_address' => '127.0.0.1:9200'], - // configure more hosts if you have a cluster - ], - ], - ] -]; -``` - - -Installation ------------- - -The preferred way to install this extension is through [composer](http://getcomposer.org/download/). - -Either run - -``` -php composer.phar require yiisoft/yii2-elasticsearch "*" -``` - -or add - -```json -"yiisoft/yii2-elasticsearch": "*" -``` - -to the require section of your composer.json. - - -Using the Query ---------------- - -TBD - -Using the ActiveRecord ----------------------- - -For general information on how to use yii's ActiveRecord please refer to the [guide](https://github.com/yiisoft/yii2/blob/master/docs/guide/active-record.md). - -For defining an elasticsearch ActiveRecord class your record class needs to extend from `yii\elasticsearch\ActiveRecord` and -implement at least the `attributes()` method to define the attributes of the record. -The primary key (the `_id` field in elasticsearch terms) is represented by `getId()` and `setId()` and can not be changed. -The primary key is not part of the attributes. - - primary key can be defined via [[primaryKey()]] which defaults to `id` if not specified. -The primaryKey needs to be part of the attributes so make sure you have an `id` attribute defined if you do -not specify your own primary key. - -The following is an example model called `Customer`: - -```php -class Customer extends \yii\elasticsearch\ActiveRecord -{ - /** - * @return array the list of attributes for this record - */ - public function attributes() - { - return ['id', 'name', 'address', 'registration_date']; - } - - /** - * @return ActiveRelation defines a relation to the Order record (can be in other database, e.g. redis or sql) - */ - public function getOrders() - { - return $this->hasMany(Order::className(), ['customer_id' => 'id'])->orderBy('id'); - } - - /** - * Defines a scope that modifies the `$query` to return only active(status = 1) customers - */ - public static function active($query) - { - $query->andWhere(array('status' => 1)); - } -} -``` - -You may override [[index()]] and [[type()]] to define the index and type this record represents. - -The general usage of elasticsearch ActiveRecord is very similar to the database ActiveRecord as described in the -[guide](https://github.com/yiisoft/yii2/blob/master/docs/guide/active-record.md). -It supports the same interface and features except the following limitations and additions(*!*): - -- As elasticsearch does not support SQL, the query API does not support `join()`, `groupBy()`, `having()` and `union()`. - Sorting, limit, offset and conditional where are all supported. -- `from()` does not select the tables, but the [index](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/glossary.html#glossary-index) - and [type](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/glossary.html#glossary-type) to query against. -- `select()` has been replaced with `fields()` which basically does the same but `fields` is more elasticsearch terminology. - It defines the fields to retrieve from a document. -- `via`-relations can not be defined via a table as there are not tables in elasticsearch. You can only define relations via other records. -- As elasticsearch is a data storage and search engine there is of course support added for search your records. - There are `query()`, `filter()` and `addFacets()` methods that allows to compose an elasticsearch query. - See the usage example below on how they work and check out the [Query DSL](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl.html) - on how to compose `query` and `filter` parts. -- It is also possible to define relations from elasticsearch ActiveRecords to normal ActiveRecord classes and vice versa. - -Elasticsearch separates primary key from attributes. You need to set the `id` property of the record to set its primary key. - -Usage example: - -```php -$customer = new Customer(); -$customer->id = 1; -$customer->attributes = ['name' => 'test']; -$customer->save(); - -$customer = Customer::get(1); // get a record by pk -$customers = Customer::get([1,2,3]); // get a records multiple by pk -$customer = Customer::find()->where(['name' => 'test'])->one(); // find by query -$customers = Customer::find()->active()->all(); // find all by query (using the `active` scope) - -// http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-field-query.html -$result = Article::find()->query(["field" => ["title" => "yii"]])->all(); // articles whose title contains "yii" - -// http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-flt-query.html -$query = Article::find()->query([ - "fuzzy_like_this" => [ - "fields" => ["title", "description"], - "like_text" => "This query will return articles that are similar to this text :-)", - "max_query_terms" : 12 - ] -]); - -$query->all(); // gives you all the documents -// you can add facets to your search: -$query->addStatisticalFacet('click_stats', ['field' => 'visit_count']); -$query->search(); // gives you all the records + stats about the visit_count field. e.g. mean, sum, min, max etc... -``` - -And there is so much more in it. "it’s endless what you can build"[¹](http://www.elasticsearch.org/) - - -Using the elasticsearch DebugPanel ----------------------------------- - -The yii2 elasticsearch extensions provides a `DebugPanel` that can be integrated with the yii debug module -an shows the executed elasticsearch queries. It also allows to run these queries on different cluster nodes -an view the results. - -Add the following to you application config to enable it: - -```php - // ... - 'preload' => 'debug', - 'modules' => [ - 'debug' => [ - 'class' => 'yii\\debug\\Module', - 'panels' => [ - 'elasticsearch' => [ - 'class' => 'yii\\elasticsearch\\DebugPanel', - ], - ], - ], - ], - // ... -``` - -![elasticsearch DebugPanel](README-debug.png) \ No newline at end of file diff --git a/extensions/elasticsearch/composer.json b/extensions/elasticsearch/composer.json deleted file mode 100644 index c72cd81..0000000 --- a/extensions/elasticsearch/composer.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "yiisoft/yii2-elasticsearch", - "description": "Elasticsearch integration and ActiveRecord for the Yii framework", - "keywords": ["yii", "elasticsearch", "active-record", "search", "fulltext"], - "type": "yii2-extension", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?labels=ext%3Aelasticsearch", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "authors": [ - { - "name": "Carsten Brandt", - "email": "mail@cebe.cc" - } - ], - "require": { - "yiisoft/yii2": "*", - "ext-curl": "*" - }, - "autoload": { - "psr-0": { "yii\\elasticsearch\\": "" } - }, - "target-dir": "yii/elasticsearch" -} diff --git a/extensions/gii/CodeFile.php b/extensions/gii/CodeFile.php deleted file mode 100644 index a5196d9..0000000 --- a/extensions/gii/CodeFile.php +++ /dev/null @@ -1,155 +0,0 @@ - - * @since 2.0 - */ -class CodeFile extends Object -{ - /** - * The code file is new. - */ - const OP_CREATE = 'create'; - /** - * The code file already exists, and the new one may need to overwrite it. - */ - const OP_OVERWRITE = 'overwrite'; - /** - * The new code file and the existing one are identical. - */ - const OP_SKIP = 'skip'; - - /** - * @var string an ID that uniquely identifies this code file. - */ - public $id; - /** - * @var string the file path that the new code should be saved to. - */ - public $path; - /** - * @var string the newly generated code content - */ - public $content; - /** - * @var string the operation to be performed. This can be [[OP_NEW]], [[OP_OVERWRITE]] or [[OP_SKIP]]. - */ - public $operation; - - /** - * Constructor. - * @param string $path the file path that the new code should be saved to. - * @param string $content the newly generated code content. - */ - public function __construct($path, $content) - { - $this->path = strtr($path, ['/' => DIRECTORY_SEPARATOR, '\\' => DIRECTORY_SEPARATOR]); - $this->content = $content; - $this->id = md5($this->path); - if (is_file($path)) { - $this->operation = file_get_contents($path) === $content ? self::OP_SKIP : self::OP_OVERWRITE; - } else { - $this->operation = self::OP_CREATE; - } - } - - /** - * Saves the code into the file specified by [[path]]. - * @return string|boolean the error occurred while saving the code file, or true if no error. - */ - public function save() - { - $module = Yii::$app->controller->module; - if ($this->operation === self::OP_CREATE) { - $dir = dirname($this->path); - if (!is_dir($dir)) { - $mask = @umask(0); - $result = @mkdir($dir, $module->newDirMode, true); - @umask($mask); - if (!$result) { - return "Unable to create the directory '$dir'."; - } - } - } - if (@file_put_contents($this->path, $this->content) === false) { - return "Unable to write the file '{$this->path}'."; - } else { - $mask = @umask(0); - @chmod($this->path, $module->newFileMode); - @umask($mask); - } - return true; - } - - /** - * @return string the code file path relative to the application base path. - */ - public function getRelativePath() - { - if (strpos($this->path, Yii::$app->basePath) === 0) { - return substr($this->path, strlen(Yii::$app->basePath) + 1); - } else { - return $this->path; - } - } - - /** - * @return string the code file extension (e.g. php, txt) - */ - public function getType() - { - if (($pos = strrpos($this->path, '.')) !== false) { - return substr($this->path, $pos + 1); - } else { - return 'unknown'; - } - } - - public function preview() - { - if (($pos = strrpos($this->path, '.')) !== false) { - $type = substr($this->path, $pos + 1); - } else { - $type = 'unknown'; - } - - if ($type === 'php') { - return highlight_string($this->content, true); - } elseif (!in_array($type, ['jpg', 'gif', 'png', 'exe'])) { - return nl2br(Html::encode($this->content)); - } else { - return false; - } - } - - public function diff() - { - $type = strtolower($this->getType()); - if (in_array($type, ['jpg', 'gif', 'png', 'exe'])) { - return false; - } elseif ($this->operation === self::OP_OVERWRITE) { - return StringHelper::diff(file($this->path), $this->content); - } else { - return ''; - } - } -} diff --git a/extensions/gii/Generator.php b/extensions/gii/Generator.php deleted file mode 100644 index 05c45a7..0000000 --- a/extensions/gii/Generator.php +++ /dev/null @@ -1,449 +0,0 @@ - - * @since 2.0 - */ -abstract class Generator extends Model -{ - /** - * @var array a list of available code templates. The array keys are the template names, - * and the array values are the corresponding template paths or path aliases. - */ - public $templates = []; - /** - * @var string the name of the code template that the user has selected. - * The value of this property is internally managed by this class. - */ - public $template; - - /** - * @return string name of the code generator - */ - abstract public function getName(); - /** - * Generates the code based on the current user input and the specified code template files. - * This is the main method that child classes should implement. - * Please refer to [[\yii\gii\generators\controller\Generator::generate()]] as an example - * on how to implement this method. - * @return CodeFile[] a list of code files to be created. - */ - abstract public function generate(); - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if (!isset($this->templates['default'])) { - $this->templates['default'] = $this->defaultTemplate(); - } - foreach ($this->templates as $i => $template) { - $this->templates[$i] = Yii::getAlias($template); - } - } - - /** - * Returns a list of code template files that are required. - * Derived classes usually should override this method if they require the existence of - * certain template files. - * @return array list of code template files that are required. They should be file paths - * relative to [[templatePath]]. - */ - public function requiredTemplates() - { - return []; - } - - /** - * Returns the list of sticky attributes. - * A sticky attribute will remember its value and will initialize the attribute with this value - * when the generator is restarted. - * @return array list of sticky attributes - */ - public function stickyAttributes() - { - return ['template']; - } - - /** - * Returns the list of hint messages. - * The array keys are the attribute names, and the array values are the corresponding hint messages. - * Hint messages will be displayed to end users when they are filling the form for the generator. - * @return array the list of hint messages - */ - public function hints() - { - return []; - } - - /** - * Returns the list of auto complete values. - * The array keys are the attribute names, and the array values are the corresponding auto complete values. - * Auto complete values can also be callable typed in order one want to make postponed data generation. - * @return array the list of auto complete values - */ - public function autoCompleteData() - { - return []; - } - - /** - * Returns the message to be displayed when the newly generated code is saved successfully. - * Child classes may override this method to customize the message. - * @return string the message to be displayed when the newly generated code is saved successfully. - */ - public function successMessage() - { - return 'The code has been generated successfully.'; - } - - /** - * Returns the view file for the input form of the generator. - * The default implementation will return the "form.php" file under the directory - * that contains the generator class file. - * @return string the view file for the input form of the generator. - */ - public function formView() - { - $class = new ReflectionClass($this); - return dirname($class->getFileName()) . '/form.php'; - } - - /** - * Returns the root path to the default code template files. - * The default implementation will return the "templates" subdirectory of the - * directory containing the generator class file. - * @return string the root path to the default code template files. - */ - public function defaultTemplate() - { - $class = new ReflectionClass($this); - return dirname($class->getFileName()) . '/templates'; - } - - /** - * @return string the detailed description of the generator. - */ - public function getDescription() - { - return ''; - } - - /** - * @inheritdoc - * - * Child classes should override this method like the following so that the parent - * rules are included: - * - * ~~~ - * return array_merge(parent::rules(), [ - * ...rules for the child class... - * ]); - * ~~~ - */ - public function rules() - { - return [ - [['template'], 'required', 'message' => 'A code template must be selected.'], - [['template'], 'validateTemplate'], - ]; - } - - /** - * Loads sticky attributes from an internal file and populates them into the generator. - * @internal - */ - public function loadStickyAttributes() - { - $stickyAttributes = $this->stickyAttributes(); - $attributes[] = 'template'; - $path = $this->getStickyDataFile(); - if (is_file($path)) { - $result = json_decode(file_get_contents($path), true); - if (is_array($result)) { - foreach ($stickyAttributes as $name) { - if (isset($result[$name])) { - $this->$name = $result[$name]; - } - } - } - } - } - - /** - * Saves sticky attributes into an internal file. - * @internal - */ - public function saveStickyAttributes() - { - $stickyAttributes = $this->stickyAttributes(); - $stickyAttributes[] = 'template'; - $values = []; - foreach ($stickyAttributes as $name) { - $values[$name] = $this->$name; - } - $path = $this->getStickyDataFile(); - @mkdir(dirname($path), 0755, true); - file_put_contents($path, json_encode($values)); - } - - /** - * @return string the file path that stores the sticky attribute values. - * @internal - */ - public function getStickyDataFile() - { - return Yii::$app->getRuntimePath() . '/gii-' . Yii::getVersion() . '/' . str_replace('\\', '-', get_class($this)) . '.json'; - } - - /** - * Saves the generated code into files. - * @param CodeFile[] $files the code files to be saved - * @param array $answers - * @param string $results this parameter receives a value from this method indicating the log messages - * generated while saving the code files. - * @return boolean whether there is any error while saving the code files. - */ - public function save($files, $answers, &$results) - { - $lines = ['Generating code using template "' . $this->getTemplatePath() . '"...']; - $hasError = false; - foreach ($files as $file) { - $relativePath = $file->getRelativePath(); - if (isset($answers[$file->id]) && $file->operation !== CodeFile::OP_SKIP) { - $error = $file->save(); - if (is_string($error)) { - $hasError = true; - $lines[] = "generating $relativePath\n$error"; - } else { - $lines[] = $file->operation === CodeFile::OP_CREATE ? " generated $relativePath" : " overwrote $relativePath"; - } - } else { - $lines[] = " skipped $relativePath"; - } - } - $lines[] = "done!\n"; - $results = implode("\n", $lines); - - return $hasError; - } - - /** - * @return string the root path of the template files that are currently being used. - * @throws InvalidConfigException if [[template]] is invalid - */ - public function getTemplatePath() - { - if (isset($this->templates[$this->template])) { - return $this->templates[$this->template]; - } else { - throw new InvalidConfigException("Unknown template: {$this->template}"); - } - } - - /** - * Generates code using the specified code template and parameters. - * Note that the code template will be used as a PHP file. - * @param string $template the code template file. This must be specified as a file path - * relative to [[templatePath]]. - * @param array $params list of parameters to be passed to the template file. - * @return string the generated code - */ - public function render($template, $params = []) - { - $view = new View; - $params['generator'] = $this; - return $view->renderFile($this->getTemplatePath() . '/' . $template, $params, $this); - } - - /** - * Validates the template selection. - * This method validates whether the user selects an existing template - * and the template contains all required template files as specified in [[requiredTemplates()]]. - */ - public function validateTemplate() - { - $templates = $this->templates; - if (!isset($templates[$this->template])) { - $this->addError('template', 'Invalid template selection.'); - } else { - $templatePath = $this->templates[$this->template]; - foreach ($this->requiredTemplates() as $template) { - if (!is_file($templatePath . '/' . $template)) { - $this->addError('template', "Unable to find the required code template file '$template'."); - } - } - } - } - - /** - * An inline validator that checks if the attribute value refers to an existing class name. - * If the `extends` option is specified, it will also check if the class is a child class - * of the class represented by the `extends` option. - * @param string $attribute the attribute being validated - * @param array $params the validation options - */ - public function validateClass($attribute, $params) - { - $class = $this->$attribute; - try { - if (class_exists($class)) { - if (isset($params['extends'])) { - if (ltrim($class, '\\') !== ltrim($params['extends'], '\\') && !is_subclass_of($class, $params['extends'])) { - $this->addError($attribute, "'$class' must extend from {$params['extends']} or its child class."); - } - } - } else { - $this->addError($attribute, "Class '$class' does not exist or has syntax error."); - } - } catch (\Exception $e) { - $this->addError($attribute, "Class '$class' does not exist or has syntax error."); - } - } - - /** - * An inline validator that checks if the attribute value refers to a valid namespaced class name. - * The validator will check if the directory containing the new class file exist or not. - * @param string $attribute the attribute being validated - * @param array $params the validation options - */ - public function validateNewClass($attribute, $params) - { - $class = ltrim($this->$attribute, '\\'); - if (($pos = strrpos($class, '\\')) === false) { - $this->addError($attribute, "The class name must contain fully qualified namespace name."); - } else { - $ns = substr($class, 0, $pos); - $path = Yii::getAlias('@' . str_replace('\\', '/', $ns), false); - if ($path === false) { - $this->addError($attribute, "The class namespace is invalid: $ns"); - } elseif (!is_dir($path)) { - $this->addError($attribute, "Please make sure the directory containing this class exists: $path"); - } - } - } - - /** - * @param string $value the attribute to be validated - * @return boolean whether the value is a reserved PHP keyword. - */ - public function isReservedKeyword($value) - { - static $keywords = [ - '__class__', - '__dir__', - '__file__', - '__function__', - '__line__', - '__method__', - '__namespace__', - '__trait__', - 'abstract', - 'and', - 'array', - 'as', - 'break', - 'case', - 'catch', - 'callable', - 'cfunction', - 'class', - 'clone', - 'const', - 'continue', - 'declare', - 'default', - 'die', - 'do', - 'echo', - 'else', - 'elseif', - 'empty', - 'enddeclare', - 'endfor', - 'endforeach', - 'endif', - 'endswitch', - 'endwhile', - 'eval', - 'exception', - 'exit', - 'extends', - 'final', - 'finally', - 'for', - 'foreach', - 'function', - 'global', - 'goto', - 'if', - 'implements', - 'include', - 'include_once', - 'instanceof', - 'insteadof', - 'interface', - 'isset', - 'list', - 'namespace', - 'new', - 'old_function', - 'or', - 'parent', - 'php_user_filter', - 'print', - 'private', - 'protected', - 'public', - 'require', - 'require_once', - 'return', - 'static', - 'switch', - 'this', - 'throw', - 'trait', - 'try', - 'unset', - 'use', - 'var', - 'while', - 'xor', - ]; - return in_array(strtolower($value), $keywords, true); - } -} diff --git a/extensions/gii/GiiAsset.php b/extensions/gii/GiiAsset.php deleted file mode 100644 index b100750..0000000 --- a/extensions/gii/GiiAsset.php +++ /dev/null @@ -1,46 +0,0 @@ - - * @since 2.0 - */ -class GiiAsset extends AssetBundle -{ - /** - * @inheritdoc - */ - public $sourcePath = '@yii/gii/assets'; - /** - * @inheritdoc - */ - public $css = [ - 'main.css', - 'typeahead.js-bootstrap.css', - ]; - /** - * @inheritdoc - */ - public $js = [ - 'gii.js', - 'typeahead.js', - ]; - /** - * @inheritdoc - */ - public $depends = [ - 'yii\web\YiiAsset', - 'yii\bootstrap\BootstrapAsset', - 'yii\bootstrap\BootstrapPluginAsset', - ]; -} diff --git a/extensions/gii/Module.php b/extensions/gii/Module.php deleted file mode 100644 index a7bb3ed..0000000 --- a/extensions/gii/Module.php +++ /dev/null @@ -1,146 +0,0 @@ - [ - * 'gii' => ['class' => 'yii\gii\Module'], - * ], - * ] - * ~~~ - * - * Because Gii generates new code files on the server, you should only use it on your own - * development machine. To prevent other people from using this module, by default, Gii - * can only be accessed by localhost. You may configure its [[allowedIPs]] property if - * you want to make it accessible on other machines. - * - * With the above configuration, you will be able to access GiiModule in your browser using - * the URL `http://localhost/path/to/index.php?r=gii` - * - * If your application enables [[UrlManager::enablePrettyUrl|pretty URLs]] and you have defined - * custom URL rules or enabled [[UrlManager::enableStrictParsing], you may need to add - * the following URL rules at the beginning of your URL rule set in your application configuration - * in order to access Gii: - * - * ~~~ - * 'rules' => [ - * 'gii' => 'gii', - * 'gii/' => 'gii/', - * 'gii//' => 'gii//', - * ... - * ], - * ~~~ - * - * You can then access Gii via URL: `http://localhost/path/to/index.php/gii` - * - * @author Qiang Xue - * @since 2.0 - */ -class Module extends \yii\base\Module -{ - /** - * @inheritdoc - */ - public $controllerNamespace = 'yii\gii\controllers'; - /** - * @var array the list of IPs that are allowed to access this module. - * Each array element represents a single IP filter which can be either an IP address - * or an address with wildcard (e.g. 192.168.0.*) to represent a network segment. - * The default value is `['127.0.0.1', '::1']`, which means the module can only be accessed - * by localhost. - */ - public $allowedIPs = ['127.0.0.1', '::1']; - /** - * @var array|Generator[] a list of generator configurations or instances. The array keys - * are the generator IDs (e.g. "crud"), and the array elements are the corresponding generator - * configurations or the instances. - * - * After the module is initialized, this property will become an array of generator instances - * which are created based on the configurations previously taken by this property. - * - * Newly assigned generators will be merged with the [[coreGenerators()|core ones]], and the former - * takes precedence in case when they have the same generator ID. - */ - public $generators = []; - /** - * @var integer the permission to be set for newly generated code files. - * This value will be used by PHP chmod function. - * Defaults to 0666, meaning the file is read-writable by all users. - */ - public $newFileMode = 0666; - /** - * @var integer the permission to be set for newly generated directories. - * This value will be used by PHP chmod function. - * Defaults to 0777, meaning the directory can be read, written and executed by all users. - */ - public $newDirMode = 0777; - - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - foreach (array_merge($this->coreGenerators(), $this->generators) as $id => $config) { - $this->generators[$id] = Yii::createObject($config); - } - } - - /** - * @inheritdoc - */ - public function beforeAction($action) - { - if ($this->checkAccess()) { - return parent::beforeAction($action); - } else { - throw new AccessDeniedHttpException('You are not allowed to access this page.'); - } - } - - /** - * @return boolean whether the module can be accessed by the current user - */ - protected function checkAccess() - { - $ip = Yii::$app->getRequest()->getUserIP(); - foreach ($this->allowedIPs as $filter) { - if ($filter === '*' || $filter === $ip || (($pos = strpos($filter, '*')) !== false && !strncmp($ip, $filter, $pos))) { - return true; - } - } - Yii::warning('Access to Gii is denied due to IP address restriction. The requested IP is ' . $ip, __METHOD__); - return false; - } - - /** - * Returns the list of the core code generator configurations. - * @return array the list of the core code generator configurations. - */ - protected function coreGenerators() - { - return [ - 'model' => ['class' => 'yii\gii\generators\model\Generator'], - 'crud' => ['class' => 'yii\gii\generators\crud\Generator'], - 'controller' => ['class' => 'yii\gii\generators\controller\Generator'], - 'form' => ['class' => 'yii\gii\generators\form\Generator'], - 'module' => ['class' => 'yii\gii\generators\module\Generator'], - ]; - } -} diff --git a/extensions/gii/README.md b/extensions/gii/README.md deleted file mode 100644 index 60f374b..0000000 --- a/extensions/gii/README.md +++ /dev/null @@ -1,47 +0,0 @@ -Gii Extension for Yii 2 -======================== - -This extension provides a Web-based code generator, called Gii, for Yii 2 applications. -You can use Gii to quickly generate models, forms, modules, CRUD, etc. - - -Installation ------------- - -The preferred way to install this extension is through [composer](http://getcomposer.org/download/). - -Either run - -``` -php composer.phar require yiisoft/yii2-gii "*" -``` - -or add - -``` -"yiisoft/yii2-gii": "*" -``` - -to the require section of your `composer.json` file. - - -Usage ------ - -Once the extension is installed, simply modify your application configuration as follows: - -```php -return [ - 'modules' => [ - 'gii' => 'yii\gii\Module', - ... - ], - ... -]; -``` - -You can then access Gii through the following URL: - -``` -http://localhost/path/to/index.php?r=gii -``` diff --git a/extensions/gii/assets/gii.js b/extensions/gii/assets/gii.js deleted file mode 100644 index a95221e..0000000 --- a/extensions/gii/assets/gii.js +++ /dev/null @@ -1,99 +0,0 @@ -yii.gii = (function ($) { - var isActive = $('.default-view').length > 0; - - var initHintBlocks = function () { - $('.hint-block').each(function () { - var $hint = $(this); - $hint.parent().find('label').addClass('help').popover({ - html: true, - trigger: 'hover', - placement: 'right', - content: $hint.html() - }); - }); - }; - - var initStickyInputs = function () { - $('.sticky:not(.error)').find('input[type="text"],select,textarea').each(function () { - var value; - if (this.tagName === 'SELECT') { - value = this.options[this.selectedIndex].text; - } else if (this.tagName === 'TEXTAREA') { - value = $(this).html(); - } else { - value = $(this).val(); - } - if (value === '') { - value = '[empty]'; - } - $(this).before('
    ' + value + '
    ').hide(); - }); - $('.sticky-value').on('click', function () { - $(this).hide(); - $(this).next().show().get(0).focus(); - }); - }; - - var initPreviewDiffLinks = function () { - $('.preview-code,.diff-code').on('click', function () { - var $modal = $('#preview-modal'); - var $link = $(this); - $modal.find('.modal-title').text($link.data('title')); - $modal.find('.modal-body').html('Loading ...'); - $modal.modal('show'); - $.ajax({ - type: 'POST', - cache: false, - url: $link.prop('href'), - data: $('.default-view form').serializeArray(), - success: function (data) { - $modal.find('.modal-body').html(data); - $modal.find('.content').css('max-height', ($(window).height() - 200) + 'px'); - }, - error: function (XMLHttpRequest, textStatus, errorThrown) { - $modal.find('.modal-body').html('
    ' + XMLHttpRequest.responseText + '
    '); - } - }); - return false; - }); - }; - - var initConfirmationCheckboxes = function () { - var $checkAll = $('#check-all'); - $checkAll.click(function () { - $('.default-view-files table .check input').prop('checked', this.checked); - }); - $('.default-view-files table .check input').click(function () { - $checkAll.prop('checked', !$('.default-view-files table .check input:not(:checked)').length); - }); - $checkAll.prop('checked', !$('.default-view-files table .check input:not(:checked)').length); - }; - - return { - init: function () { - initHintBlocks(); - initStickyInputs(); - initPreviewDiffLinks(); - initConfirmationCheckboxes(); - - // model generator: hide class name input when table name input contains * - $('#model-generator #generator-tablename').on('change', function () { - $('#model-generator .field-generator-modelclass').toggle($(this).val().indexOf('*') == -1); - }).change(); - - // hide Generate button if any input is changed - $('.default-view .form-group input,select,textarea').change(function () { - $('.default-view-results,.default-view-files').hide(); - $('.default-view button[name="generate"]').hide(); - }); - - $('.module-form #generator-moduleclass').change(function () { - var value = $(this).val().match(/(\w+)\\\w+$/); - var $idInput = $('#generator-moduleid'); - if (value && value[1] && $idInput.val() == '') { - $idInput.val(value[1]); - } - }); - } - }; -})(jQuery); diff --git a/extensions/gii/assets/logo.png b/extensions/gii/assets/logo.png deleted file mode 100644 index e48b5aad64109229acee2c02708f1d2ab885936a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6677 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 diff --git a/extensions/gii/assets/main.css b/extensions/gii/assets/main.css deleted file mode 100644 index 1a4f794..0000000 --- a/extensions/gii/assets/main.css +++ /dev/null @@ -1,211 +0,0 @@ -body { - padding-top: 70px; -} - -.footer { - border-top: 1px solid #ddd; - margin-top: 30px; - padding: 15px 0 30px; -} - -.jumbotron { - text-align: center; - background-color: transparent; -} - -.jumbotron .btn { - font-size: 21px; - padding: 14px 24px; -} - -.navbar-brand { - padding: 0; - margin: 0; -} - -.default-index .generator { - min-height: 200px; - margin-bottom: 20px; -} - -.list-group .glyphicon { - float: right; -} - -.popover { - max-width: 400px; - width: 400px; -} - -.hint-block { - display: none; -} - -.default-view .sticky-value { - padding: 6px 12px; - background: lightyellow; - white-space: pre; - word-wrap: break-word; -} - -.default-view .form-group label.help { - border-bottom: 1px dashed #888; - cursor: help; -} - -.default-view .modal-dialog { - width: 800px; -} - -.default-view .modal-dialog .error { - color: #d9534f; -} - -.default-view .modal-dialog .content { - background: #fafafa; - border-left: #eee 5px solid; - padding: 5px 10px; - overflow: auto; -} - -.default-view .modal-dialog code { - background: transparent; -} - -.default-view-files table .action { - width: 100px; -} - -.default-view-files table .check { - width: 25px; - text-align: center; -} - -.default-view-results pre { - overflow: auto; - background-color: #333; - max-height: 300px; - color: white; - padding: 10px; - border-radius: 0; - white-space: nowrap; -} - -.default-view-results pre .error { - background: #FFE0E1; - color: black; - padding: 1px; -} - -.default-view-results .alert pre { - background: white; -} - -.default-diff pre { - padding: 0; - margin: 0; - background: transparent; - border: none; -} - -.default-diff pre del { - background: pink; -} - -.default-diff pre ins { - background: lightgreen; - text-decoration: none; -} - - -.Differences { - width: 100%; - border-collapse: collapse; - border-spacing: 0; - empty-cells: show; -} - -.Differences thead { - display: none; -} - -.Differences tbody th { - text-align: right; - background: #FAFAFA; - padding: 1px 2px; - border-right: 1px solid #eee; - vertical-align: top; - font-size: 13px; - font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; - font-weight: normal; - color: #999; - width: 5px; -} - -.Differences td { - padding: 1px 2px; - font-size: 13px; - font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; -} - -.DifferencesSideBySide .ChangeInsert td.Left { - background: #dfd; -} - -.DifferencesSideBySide .ChangeInsert td.Right { - background: #cfc; -} - -.DifferencesSideBySide .ChangeDelete td.Left { - background: #f88; -} - -.DifferencesSideBySide .ChangeDelete td.Right { - background: #faa; -} - -.DifferencesSideBySide .ChangeReplace .Left { - background: #fe9; -} - -.DifferencesSideBySide .ChangeReplace .Right { - background: #fd8; -} - -.Differences ins, .Differences del { - text-decoration: none; -} - -.DifferencesSideBySide .ChangeReplace ins, .DifferencesSideBySide .ChangeReplace del { - background: #fc0; -} - -.Differences .Skipped { - background: #f7f7f7; -} - -.DifferencesInline .ChangeReplace .Left, -.DifferencesInline .ChangeDelete .Left { - background: #fdd; -} - -.DifferencesInline .ChangeReplace .Right, -.DifferencesInline .ChangeInsert .Right { - background: #dfd; -} - -.DifferencesInline .ChangeReplace ins { - background: #9e9; -} - -.DifferencesInline .ChangeReplace del { - background: #e99; -} - -/* additional styles for typeahead.js-bootstrap.css */ -.twitter-typeahead { - display: block !important; -} -.twitter-typeahead .tt-hint { - padding: 6px 12px !important; -} diff --git a/extensions/gii/assets/typeahead.js b/extensions/gii/assets/typeahead.js deleted file mode 100644 index 9365bd6..0000000 --- a/extensions/gii/assets/typeahead.js +++ /dev/null @@ -1,1139 +0,0 @@ -/*! - * typeahead.js 0.9.3 - * https://github.com/twitter/typeahead - * Copyright 2013 Twitter, Inc. and other contributors; Licensed MIT - */ - -(function($) { - var VERSION = "0.9.3"; - var utils = { - isMsie: function() { - var match = /(msie) ([\w.]+)/i.exec(navigator.userAgent); - return match ? parseInt(match[2], 10) : false; - }, - isBlankString: function(str) { - return !str || /^\s*$/.test(str); - }, - escapeRegExChars: function(str) { - return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); - }, - isString: function(obj) { - return typeof obj === "string"; - }, - isNumber: function(obj) { - return typeof obj === "number"; - }, - isArray: $.isArray, - isFunction: $.isFunction, - isObject: $.isPlainObject, - isUndefined: function(obj) { - return typeof obj === "undefined"; - }, - bind: $.proxy, - bindAll: function(obj) { - var val; - for (var key in obj) { - $.isFunction(val = obj[key]) && (obj[key] = $.proxy(val, obj)); - } - }, - indexOf: function(haystack, needle) { - for (var i = 0; i < haystack.length; i++) { - if (haystack[i] === needle) { - return i; - } - } - return -1; - }, - each: $.each, - map: $.map, - filter: $.grep, - every: function(obj, test) { - var result = true; - if (!obj) { - return result; - } - $.each(obj, function(key, val) { - if (!(result = test.call(null, val, key, obj))) { - return false; - } - }); - return !!result; - }, - some: function(obj, test) { - var result = false; - if (!obj) { - return result; - } - $.each(obj, function(key, val) { - if (result = test.call(null, val, key, obj)) { - return false; - } - }); - return !!result; - }, - mixin: $.extend, - getUniqueId: function() { - var counter = 0; - return function() { - return counter++; - }; - }(), - defer: function(fn) { - setTimeout(fn, 0); - }, - debounce: function(func, wait, immediate) { - var timeout, result; - return function() { - var context = this, args = arguments, later, callNow; - later = function() { - timeout = null; - if (!immediate) { - result = func.apply(context, args); - } - }; - callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) { - result = func.apply(context, args); - } - return result; - }; - }, - throttle: function(func, wait) { - var context, args, timeout, result, previous, later; - previous = 0; - later = function() { - previous = new Date(); - timeout = null; - result = func.apply(context, args); - }; - return function() { - var now = new Date(), remaining = wait - (now - previous); - context = this; - args = arguments; - if (remaining <= 0) { - clearTimeout(timeout); - timeout = null; - previous = now; - result = func.apply(context, args); - } else if (!timeout) { - timeout = setTimeout(later, remaining); - } - return result; - }; - }, - tokenizeQuery: function(str) { - return $.trim(str).toLowerCase().split(/[\s]+/); - }, - tokenizeText: function(str) { - return $.trim(str).toLowerCase().split(/[\s\-_]+/); - }, - getProtocol: function() { - return location.protocol; - }, - noop: function() {} - }; - var EventTarget = function() { - var eventSplitter = /\s+/; - return { - on: function(events, callback) { - var event; - if (!callback) { - return this; - } - this._callbacks = this._callbacks || {}; - events = events.split(eventSplitter); - while (event = events.shift()) { - this._callbacks[event] = this._callbacks[event] || []; - this._callbacks[event].push(callback); - } - return this; - }, - trigger: function(events, data) { - var event, callbacks; - if (!this._callbacks) { - return this; - } - events = events.split(eventSplitter); - while (event = events.shift()) { - if (callbacks = this._callbacks[event]) { - for (var i = 0; i < callbacks.length; i += 1) { - callbacks[i].call(this, { - type: event, - data: data - }); - } - } - } - return this; - } - }; - }(); - var EventBus = function() { - var namespace = "typeahead:"; - function EventBus(o) { - if (!o || !o.el) { - $.error("EventBus initialized without el"); - } - this.$el = $(o.el); - } - utils.mixin(EventBus.prototype, { - trigger: function(type) { - var args = [].slice.call(arguments, 1); - this.$el.trigger(namespace + type, args); - } - }); - return EventBus; - }(); - var PersistentStorage = function() { - var ls, methods; - try { - ls = window.localStorage; - ls.setItem("~~~", "!"); - ls.removeItem("~~~"); - } catch (err) { - ls = null; - } - function PersistentStorage(namespace) { - this.prefix = [ "__", namespace, "__" ].join(""); - this.ttlKey = "__ttl__"; - this.keyMatcher = new RegExp("^" + this.prefix); - } - if (ls && window.JSON) { - methods = { - _prefix: function(key) { - return this.prefix + key; - }, - _ttlKey: function(key) { - return this._prefix(key) + this.ttlKey; - }, - get: function(key) { - if (this.isExpired(key)) { - this.remove(key); - } - return decode(ls.getItem(this._prefix(key))); - }, - set: function(key, val, ttl) { - if (utils.isNumber(ttl)) { - ls.setItem(this._ttlKey(key), encode(now() + ttl)); - } else { - ls.removeItem(this._ttlKey(key)); - } - return ls.setItem(this._prefix(key), encode(val)); - }, - remove: function(key) { - ls.removeItem(this._ttlKey(key)); - ls.removeItem(this._prefix(key)); - return this; - }, - clear: function() { - var i, key, keys = [], len = ls.length; - for (i = 0; i < len; i++) { - if ((key = ls.key(i)).match(this.keyMatcher)) { - keys.push(key.replace(this.keyMatcher, "")); - } - } - for (i = keys.length; i--; ) { - this.remove(keys[i]); - } - return this; - }, - isExpired: function(key) { - var ttl = decode(ls.getItem(this._ttlKey(key))); - return utils.isNumber(ttl) && now() > ttl ? true : false; - } - }; - } else { - methods = { - get: utils.noop, - set: utils.noop, - remove: utils.noop, - clear: utils.noop, - isExpired: utils.noop - }; - } - utils.mixin(PersistentStorage.prototype, methods); - return PersistentStorage; - function now() { - return new Date().getTime(); - } - function encode(val) { - return JSON.stringify(utils.isUndefined(val) ? null : val); - } - function decode(val) { - return JSON.parse(val); - } - }(); - var RequestCache = function() { - function RequestCache(o) { - utils.bindAll(this); - o = o || {}; - this.sizeLimit = o.sizeLimit || 10; - this.cache = {}; - this.cachedKeysByAge = []; - } - utils.mixin(RequestCache.prototype, { - get: function(url) { - return this.cache[url]; - }, - set: function(url, resp) { - var requestToEvict; - if (this.cachedKeysByAge.length === this.sizeLimit) { - requestToEvict = this.cachedKeysByAge.shift(); - delete this.cache[requestToEvict]; - } - this.cache[url] = resp; - this.cachedKeysByAge.push(url); - } - }); - return RequestCache; - }(); - var Transport = function() { - var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests, requestCache; - function Transport(o) { - utils.bindAll(this); - o = utils.isString(o) ? { - url: o - } : o; - requestCache = requestCache || new RequestCache(); - maxPendingRequests = utils.isNumber(o.maxParallelRequests) ? o.maxParallelRequests : maxPendingRequests || 6; - this.url = o.url; - this.wildcard = o.wildcard || "%QUERY"; - this.filter = o.filter; - this.replace = o.replace; - this.ajaxSettings = { - type: "get", - cache: o.cache, - timeout: o.timeout, - dataType: o.dataType || "json", - beforeSend: o.beforeSend - }; - this._get = (/^throttle$/i.test(o.rateLimitFn) ? utils.throttle : utils.debounce)(this._get, o.rateLimitWait || 300); - } - utils.mixin(Transport.prototype, { - _get: function(url, cb) { - var that = this; - if (belowPendingRequestsThreshold()) { - this._sendRequest(url).done(done); - } else { - this.onDeckRequestArgs = [].slice.call(arguments, 0); - } - function done(resp) { - var data = that.filter ? that.filter(resp) : resp; - cb && cb(data); - requestCache.set(url, resp); - } - }, - _sendRequest: function(url) { - var that = this, jqXhr = pendingRequests[url]; - if (!jqXhr) { - incrementPendingRequests(); - jqXhr = pendingRequests[url] = $.ajax(url, this.ajaxSettings).always(always); - } - return jqXhr; - function always() { - decrementPendingRequests(); - pendingRequests[url] = null; - if (that.onDeckRequestArgs) { - that._get.apply(that, that.onDeckRequestArgs); - that.onDeckRequestArgs = null; - } - } - }, - get: function(query, cb) { - var that = this, encodedQuery = encodeURIComponent(query || ""), url, resp; - cb = cb || utils.noop; - url = this.replace ? this.replace(this.url, encodedQuery) : this.url.replace(this.wildcard, encodedQuery); - if (resp = requestCache.get(url)) { - utils.defer(function() { - cb(that.filter ? that.filter(resp) : resp); - }); - } else { - this._get(url, cb); - } - return !!resp; - } - }); - return Transport; - function incrementPendingRequests() { - pendingRequestsCount++; - } - function decrementPendingRequests() { - pendingRequestsCount--; - } - function belowPendingRequestsThreshold() { - return pendingRequestsCount < maxPendingRequests; - } - }(); - var Dataset = function() { - var keys = { - thumbprint: "thumbprint", - protocol: "protocol", - itemHash: "itemHash", - adjacencyList: "adjacencyList" - }; - function Dataset(o) { - utils.bindAll(this); - if (utils.isString(o.template) && !o.engine) { - $.error("no template engine specified"); - } - if (!o.local && !o.prefetch && !o.remote) { - $.error("one of local, prefetch, or remote is required"); - } - this.name = o.name || utils.getUniqueId(); - this.limit = o.limit || 5; - this.minLength = o.minLength || 1; - this.header = o.header; - this.footer = o.footer; - this.valueKey = o.valueKey || "value"; - this.template = compileTemplate(o.template, o.engine, this.valueKey); - this.local = o.local; - this.prefetch = o.prefetch; - this.remote = o.remote; - this.itemHash = {}; - this.adjacencyList = {}; - this.storage = o.name ? new PersistentStorage(o.name) : null; - } - utils.mixin(Dataset.prototype, { - _processLocalData: function(data) { - this._mergeProcessedData(this._processData(data)); - }, - _loadPrefetchData: function(o) { - var that = this, thumbprint = VERSION + (o.thumbprint || ""), storedThumbprint, storedProtocol, storedItemHash, storedAdjacencyList, isExpired, deferred; - if (this.storage) { - storedThumbprint = this.storage.get(keys.thumbprint); - storedProtocol = this.storage.get(keys.protocol); - storedItemHash = this.storage.get(keys.itemHash); - storedAdjacencyList = this.storage.get(keys.adjacencyList); - } - isExpired = storedThumbprint !== thumbprint || storedProtocol !== utils.getProtocol(); - o = utils.isString(o) ? { - url: o - } : o; - o.ttl = utils.isNumber(o.ttl) ? o.ttl : 24 * 60 * 60 * 1e3; - if (storedItemHash && storedAdjacencyList && !isExpired) { - this._mergeProcessedData({ - itemHash: storedItemHash, - adjacencyList: storedAdjacencyList - }); - deferred = $.Deferred().resolve(); - } else { - deferred = $.getJSON(o.url).done(processPrefetchData); - } - return deferred; - function processPrefetchData(data) { - var filteredData = o.filter ? o.filter(data) : data, processedData = that._processData(filteredData), itemHash = processedData.itemHash, adjacencyList = processedData.adjacencyList; - if (that.storage) { - that.storage.set(keys.itemHash, itemHash, o.ttl); - that.storage.set(keys.adjacencyList, adjacencyList, o.ttl); - that.storage.set(keys.thumbprint, thumbprint, o.ttl); - that.storage.set(keys.protocol, utils.getProtocol(), o.ttl); - } - that._mergeProcessedData(processedData); - } - }, - _transformDatum: function(datum) { - var value = utils.isString(datum) ? datum : datum[this.valueKey], tokens = datum.tokens || utils.tokenizeText(value), item = { - value: value, - tokens: tokens - }; - if (utils.isString(datum)) { - item.datum = {}; - item.datum[this.valueKey] = datum; - } else { - item.datum = datum; - } - item.tokens = utils.filter(item.tokens, function(token) { - return !utils.isBlankString(token); - }); - item.tokens = utils.map(item.tokens, function(token) { - return token.toLowerCase(); - }); - return item; - }, - _processData: function(data) { - var that = this, itemHash = {}, adjacencyList = {}; - utils.each(data, function(i, datum) { - var item = that._transformDatum(datum), id = utils.getUniqueId(item.value); - itemHash[id] = item; - utils.each(item.tokens, function(i, token) { - var character = token.charAt(0), adjacency = adjacencyList[character] || (adjacencyList[character] = [ id ]); - !~utils.indexOf(adjacency, id) && adjacency.push(id); - }); - }); - return { - itemHash: itemHash, - adjacencyList: adjacencyList - }; - }, - _mergeProcessedData: function(processedData) { - var that = this; - utils.mixin(this.itemHash, processedData.itemHash); - utils.each(processedData.adjacencyList, function(character, adjacency) { - var masterAdjacency = that.adjacencyList[character]; - that.adjacencyList[character] = masterAdjacency ? masterAdjacency.concat(adjacency) : adjacency; - }); - }, - _getLocalSuggestions: function(terms) { - var that = this, firstChars = [], lists = [], shortestList, suggestions = []; - utils.each(terms, function(i, term) { - var firstChar = term.charAt(0); - !~utils.indexOf(firstChars, firstChar) && firstChars.push(firstChar); - }); - utils.each(firstChars, function(i, firstChar) { - var list = that.adjacencyList[firstChar]; - if (!list) { - return false; - } - lists.push(list); - if (!shortestList || list.length < shortestList.length) { - shortestList = list; - } - }); - if (lists.length < firstChars.length) { - return []; - } - utils.each(shortestList, function(i, id) { - var item = that.itemHash[id], isCandidate, isMatch; - isCandidate = utils.every(lists, function(list) { - return ~utils.indexOf(list, id); - }); - isMatch = isCandidate && utils.every(terms, function(term) { - return utils.some(item.tokens, function(token) { - return token.indexOf(term) === 0; - }); - }); - isMatch && suggestions.push(item); - }); - return suggestions; - }, - initialize: function() { - var deferred; - this.local && this._processLocalData(this.local); - this.transport = this.remote ? new Transport(this.remote) : null; - deferred = this.prefetch ? this._loadPrefetchData(this.prefetch) : $.Deferred().resolve(); - this.local = this.prefetch = this.remote = null; - this.initialize = function() { - return deferred; - }; - return deferred; - }, - getSuggestions: function(query, cb) { - var that = this, terms, suggestions, cacheHit = false; - if (query.length < this.minLength) { - return; - } - terms = utils.tokenizeQuery(query); - suggestions = this._getLocalSuggestions(terms).slice(0, this.limit); - if (suggestions.length < this.limit && this.transport) { - cacheHit = this.transport.get(query, processRemoteData); - } - !cacheHit && cb && cb(suggestions); - function processRemoteData(data) { - suggestions = suggestions.slice(0); - utils.each(data, function(i, datum) { - var item = that._transformDatum(datum), isDuplicate; - isDuplicate = utils.some(suggestions, function(suggestion) { - return item.value === suggestion.value; - }); - !isDuplicate && suggestions.push(item); - return suggestions.length < that.limit; - }); - cb && cb(suggestions); - } - } - }); - return Dataset; - function compileTemplate(template, engine, valueKey) { - var renderFn, compiledTemplate; - if (utils.isFunction(template)) { - renderFn = template; - } else if (utils.isString(template)) { - compiledTemplate = engine.compile(template); - renderFn = utils.bind(compiledTemplate.render, compiledTemplate); - } else { - renderFn = function(context) { - return "

    " + context[valueKey] + "

    "; - }; - } - return renderFn; - } - }(); - var InputView = function() { - function InputView(o) { - var that = this; - utils.bindAll(this); - this.specialKeyCodeMap = { - 9: "tab", - 27: "esc", - 37: "left", - 39: "right", - 13: "enter", - 38: "up", - 40: "down" - }; - this.$hint = $(o.hint); - this.$input = $(o.input).on("blur.tt", this._handleBlur).on("focus.tt", this._handleFocus).on("keydown.tt", this._handleSpecialKeyEvent); - if (!utils.isMsie()) { - this.$input.on("input.tt", this._compareQueryToInputValue); - } else { - this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) { - if (that.specialKeyCodeMap[$e.which || $e.keyCode]) { - return; - } - utils.defer(that._compareQueryToInputValue); - }); - } - this.query = this.$input.val(); - this.$overflowHelper = buildOverflowHelper(this.$input); - } - utils.mixin(InputView.prototype, EventTarget, { - _handleFocus: function() { - this.trigger("focused"); - }, - _handleBlur: function() { - this.trigger("blured"); - }, - _handleSpecialKeyEvent: function($e) { - var keyName = this.specialKeyCodeMap[$e.which || $e.keyCode]; - keyName && this.trigger(keyName + "Keyed", $e); - }, - _compareQueryToInputValue: function() { - var inputValue = this.getInputValue(), isSameQuery = compareQueries(this.query, inputValue), isSameQueryExceptWhitespace = isSameQuery ? this.query.length !== inputValue.length : false; - if (isSameQueryExceptWhitespace) { - this.trigger("whitespaceChanged", { - value: this.query - }); - } else if (!isSameQuery) { - this.trigger("queryChanged", { - value: this.query = inputValue - }); - } - }, - destroy: function() { - this.$hint.off(".tt"); - this.$input.off(".tt"); - this.$hint = this.$input = this.$overflowHelper = null; - }, - focus: function() { - this.$input.focus(); - }, - blur: function() { - this.$input.blur(); - }, - getQuery: function() { - return this.query; - }, - setQuery: function(query) { - this.query = query; - }, - getInputValue: function() { - return this.$input.val(); - }, - setInputValue: function(value, silent) { - this.$input.val(value); - !silent && this._compareQueryToInputValue(); - }, - getHintValue: function() { - return this.$hint.val(); - }, - setHintValue: function(value) { - this.$hint.val(value); - }, - getLanguageDirection: function() { - return (this.$input.css("direction") || "ltr").toLowerCase(); - }, - isOverflow: function() { - this.$overflowHelper.text(this.getInputValue()); - return this.$overflowHelper.width() > this.$input.width(); - }, - isCursorAtEnd: function() { - var valueLength = this.$input.val().length, selectionStart = this.$input[0].selectionStart, range; - if (utils.isNumber(selectionStart)) { - return selectionStart === valueLength; - } else if (document.selection) { - range = document.selection.createRange(); - range.moveStart("character", -valueLength); - return valueLength === range.text.length; - } - return true; - } - }); - return InputView; - function buildOverflowHelper($input) { - return $("").css({ - position: "absolute", - left: "-9999px", - visibility: "hidden", - whiteSpace: "nowrap", - fontFamily: $input.css("font-family"), - fontSize: $input.css("font-size"), - fontStyle: $input.css("font-style"), - fontVariant: $input.css("font-variant"), - fontWeight: $input.css("font-weight"), - wordSpacing: $input.css("word-spacing"), - letterSpacing: $input.css("letter-spacing"), - textIndent: $input.css("text-indent"), - textRendering: $input.css("text-rendering"), - textTransform: $input.css("text-transform") - }).insertAfter($input); - } - function compareQueries(a, b) { - a = (a || "").replace(/^\s*/g, "").replace(/\s{2,}/g, " "); - b = (b || "").replace(/^\s*/g, "").replace(/\s{2,}/g, " "); - return a === b; - } - }(); - var DropdownView = function() { - var html = { - suggestionsList: '' - }, css = { - suggestionsList: { - display: "block" - }, - suggestion: { - whiteSpace: "nowrap", - cursor: "pointer" - }, - suggestionChild: { - whiteSpace: "normal" - } - }; - function DropdownView(o) { - utils.bindAll(this); - this.isOpen = false; - this.isEmpty = true; - this.isMouseOverDropdown = false; - this.$menu = $(o.menu).on("mouseenter.tt", this._handleMouseenter).on("mouseleave.tt", this._handleMouseleave).on("click.tt", ".tt-suggestion", this._handleSelection).on("mouseover.tt", ".tt-suggestion", this._handleMouseover); - } - utils.mixin(DropdownView.prototype, EventTarget, { - _handleMouseenter: function() { - this.isMouseOverDropdown = true; - }, - _handleMouseleave: function() { - this.isMouseOverDropdown = false; - }, - _handleMouseover: function($e) { - var $suggestion = $($e.currentTarget); - this._getSuggestions().removeClass("tt-is-under-cursor"); - $suggestion.addClass("tt-is-under-cursor"); - }, - _handleSelection: function($e) { - var $suggestion = $($e.currentTarget); - this.trigger("suggestionSelected", extractSuggestion($suggestion)); - }, - _show: function() { - this.$menu.css("display", "block"); - }, - _hide: function() { - this.$menu.hide(); - }, - _moveCursor: function(increment) { - var $suggestions, $cur, nextIndex, $underCursor; - if (!this.isVisible()) { - return; - } - $suggestions = this._getSuggestions(); - $cur = $suggestions.filter(".tt-is-under-cursor"); - $cur.removeClass("tt-is-under-cursor"); - nextIndex = $suggestions.index($cur) + increment; - nextIndex = (nextIndex + 1) % ($suggestions.length + 1) - 1; - if (nextIndex === -1) { - this.trigger("cursorRemoved"); - return; - } else if (nextIndex < -1) { - nextIndex = $suggestions.length - 1; - } - $underCursor = $suggestions.eq(nextIndex).addClass("tt-is-under-cursor"); - this._ensureVisibility($underCursor); - this.trigger("cursorMoved", extractSuggestion($underCursor)); - }, - _getSuggestions: function() { - return this.$menu.find(".tt-suggestions > .tt-suggestion"); - }, - _ensureVisibility: function($el) { - var menuHeight = this.$menu.height() + parseInt(this.$menu.css("paddingTop"), 10) + parseInt(this.$menu.css("paddingBottom"), 10), menuScrollTop = this.$menu.scrollTop(), elTop = $el.position().top, elBottom = elTop + $el.outerHeight(true); - if (elTop < 0) { - this.$menu.scrollTop(menuScrollTop + elTop); - } else if (menuHeight < elBottom) { - this.$menu.scrollTop(menuScrollTop + (elBottom - menuHeight)); - } - }, - destroy: function() { - this.$menu.off(".tt"); - this.$menu = null; - }, - isVisible: function() { - return this.isOpen && !this.isEmpty; - }, - closeUnlessMouseIsOverDropdown: function() { - if (!this.isMouseOverDropdown) { - this.close(); - } - }, - close: function() { - if (this.isOpen) { - this.isOpen = false; - this.isMouseOverDropdown = false; - this._hide(); - this.$menu.find(".tt-suggestions > .tt-suggestion").removeClass("tt-is-under-cursor"); - this.trigger("closed"); - } - }, - open: function() { - if (!this.isOpen) { - this.isOpen = true; - !this.isEmpty && this._show(); - this.trigger("opened"); - } - }, - setLanguageDirection: function(dir) { - var ltrCss = { - left: "0", - right: "auto" - }, rtlCss = { - left: "auto", - right: " 0" - }; - dir === "ltr" ? this.$menu.css(ltrCss) : this.$menu.css(rtlCss); - }, - moveCursorUp: function() { - this._moveCursor(-1); - }, - moveCursorDown: function() { - this._moveCursor(+1); - }, - getSuggestionUnderCursor: function() { - var $suggestion = this._getSuggestions().filter(".tt-is-under-cursor").first(); - return $suggestion.length > 0 ? extractSuggestion($suggestion) : null; - }, - getFirstSuggestion: function() { - var $suggestion = this._getSuggestions().first(); - return $suggestion.length > 0 ? extractSuggestion($suggestion) : null; - }, - renderSuggestions: function(dataset, suggestions) { - var datasetClassName = "tt-dataset-" + dataset.name, wrapper = '
    %body
    ', compiledHtml, $suggestionsList, $dataset = this.$menu.find("." + datasetClassName), elBuilder, fragment, $el; - if ($dataset.length === 0) { - $suggestionsList = $(html.suggestionsList).css(css.suggestionsList); - $dataset = $("
    ").addClass(datasetClassName).append(dataset.header).append($suggestionsList).append(dataset.footer).appendTo(this.$menu); - } - if (suggestions.length > 0) { - this.isEmpty = false; - this.isOpen && this._show(); - elBuilder = document.createElement("div"); - fragment = document.createDocumentFragment(); - utils.each(suggestions, function(i, suggestion) { - suggestion.dataset = dataset.name; - compiledHtml = dataset.template(suggestion.datum); - elBuilder.innerHTML = wrapper.replace("%body", compiledHtml); - $el = $(elBuilder.firstChild).css(css.suggestion).data("suggestion", suggestion); - $el.children().each(function() { - $(this).css(css.suggestionChild); - }); - fragment.appendChild($el[0]); - }); - $dataset.show().find(".tt-suggestions").html(fragment); - } else { - this.clearSuggestions(dataset.name); - } - this.trigger("suggestionsRendered"); - }, - clearSuggestions: function(datasetName) { - var $datasets = datasetName ? this.$menu.find(".tt-dataset-" + datasetName) : this.$menu.find('[class^="tt-dataset-"]'), $suggestions = $datasets.find(".tt-suggestions"); - $datasets.hide(); - $suggestions.empty(); - if (this._getSuggestions().length === 0) { - this.isEmpty = true; - this._hide(); - } - } - }); - return DropdownView; - function extractSuggestion($el) { - return $el.data("suggestion"); - } - }(); - var TypeaheadView = function() { - var html = { - wrapper: '', - hint: '', - dropdown: '' - }, css = { - wrapper: { - position: "relative", - display: "inline-block" - }, - hint: { - position: "absolute", - top: "0", - left: "0", - borderColor: "transparent", - boxShadow: "none" - }, - query: { - position: "relative", - verticalAlign: "top", - backgroundColor: "transparent" - }, - dropdown: { - position: "absolute", - top: "100%", - left: "0", - zIndex: "100", - display: "none" - } - }; - if (utils.isMsie()) { - utils.mixin(css.query, { - backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)" - }); - } - if (utils.isMsie() && utils.isMsie() <= 7) { - utils.mixin(css.wrapper, { - display: "inline", - zoom: "1" - }); - utils.mixin(css.query, { - marginTop: "-1px" - }); - } - function TypeaheadView(o) { - var $menu, $input, $hint; - utils.bindAll(this); - this.$node = buildDomStructure(o.input); - this.datasets = o.datasets; - this.dir = null; - this.eventBus = o.eventBus; - $menu = this.$node.find(".tt-dropdown-menu"); - $input = this.$node.find(".tt-query"); - $hint = this.$node.find(".tt-hint"); - this.dropdownView = new DropdownView({ - menu: $menu - }).on("suggestionSelected", this._handleSelection).on("cursorMoved", this._clearHint).on("cursorMoved", this._setInputValueToSuggestionUnderCursor).on("cursorRemoved", this._setInputValueToQuery).on("cursorRemoved", this._updateHint).on("suggestionsRendered", this._updateHint).on("opened", this._updateHint).on("closed", this._clearHint).on("opened closed", this._propagateEvent); - this.inputView = new InputView({ - input: $input, - hint: $hint - }).on("focused", this._openDropdown).on("blured", this._closeDropdown).on("blured", this._setInputValueToQuery).on("enterKeyed tabKeyed", this._handleSelection).on("queryChanged", this._clearHint).on("queryChanged", this._clearSuggestions).on("queryChanged", this._getSuggestions).on("whitespaceChanged", this._updateHint).on("queryChanged whitespaceChanged", this._openDropdown).on("queryChanged whitespaceChanged", this._setLanguageDirection).on("escKeyed", this._closeDropdown).on("escKeyed", this._setInputValueToQuery).on("tabKeyed upKeyed downKeyed", this._managePreventDefault).on("upKeyed downKeyed", this._moveDropdownCursor).on("upKeyed downKeyed", this._openDropdown).on("tabKeyed leftKeyed rightKeyed", this._autocomplete); - } - utils.mixin(TypeaheadView.prototype, EventTarget, { - _managePreventDefault: function(e) { - var $e = e.data, hint, inputValue, preventDefault = false; - switch (e.type) { - case "tabKeyed": - hint = this.inputView.getHintValue(); - inputValue = this.inputView.getInputValue(); - preventDefault = hint && hint !== inputValue; - break; - - case "upKeyed": - case "downKeyed": - preventDefault = !$e.shiftKey && !$e.ctrlKey && !$e.metaKey; - break; - } - preventDefault && $e.preventDefault(); - }, - _setLanguageDirection: function() { - var dir = this.inputView.getLanguageDirection(); - if (dir !== this.dir) { - this.dir = dir; - this.$node.css("direction", dir); - this.dropdownView.setLanguageDirection(dir); - } - }, - _updateHint: function() { - var suggestion = this.dropdownView.getFirstSuggestion(), hint = suggestion ? suggestion.value : null, dropdownIsVisible = this.dropdownView.isVisible(), inputHasOverflow = this.inputView.isOverflow(), inputValue, query, escapedQuery, beginsWithQuery, match; - if (hint && dropdownIsVisible && !inputHasOverflow) { - inputValue = this.inputView.getInputValue(); - query = inputValue.replace(/\s{2,}/g, " ").replace(/^\s+/g, ""); - escapedQuery = utils.escapeRegExChars(query); - beginsWithQuery = new RegExp("^(?:" + escapedQuery + ")(.*$)", "i"); - match = beginsWithQuery.exec(hint); - this.inputView.setHintValue(inputValue + (match ? match[1] : "")); - } - }, - _clearHint: function() { - this.inputView.setHintValue(""); - }, - _clearSuggestions: function() { - this.dropdownView.clearSuggestions(); - }, - _setInputValueToQuery: function() { - this.inputView.setInputValue(this.inputView.getQuery()); - }, - _setInputValueToSuggestionUnderCursor: function(e) { - var suggestion = e.data; - this.inputView.setInputValue(suggestion.value, true); - }, - _openDropdown: function() { - this.dropdownView.open(); - }, - _closeDropdown: function(e) { - this.dropdownView[e.type === "blured" ? "closeUnlessMouseIsOverDropdown" : "close"](); - }, - _moveDropdownCursor: function(e) { - var $e = e.data; - if (!$e.shiftKey && !$e.ctrlKey && !$e.metaKey) { - this.dropdownView[e.type === "upKeyed" ? "moveCursorUp" : "moveCursorDown"](); - } - }, - _handleSelection: function(e) { - var byClick = e.type === "suggestionSelected", suggestion = byClick ? e.data : this.dropdownView.getSuggestionUnderCursor(); - if (suggestion) { - this.inputView.setInputValue(suggestion.value); - byClick ? this.inputView.focus() : e.data.preventDefault(); - byClick && utils.isMsie() ? utils.defer(this.dropdownView.close) : this.dropdownView.close(); - this.eventBus.trigger("selected", suggestion.datum, suggestion.dataset); - } - }, - _getSuggestions: function() { - var that = this, query = this.inputView.getQuery(); - if (utils.isBlankString(query)) { - return; - } - utils.each(this.datasets, function(i, dataset) { - dataset.getSuggestions(query, function(suggestions) { - if (query === that.inputView.getQuery()) { - that.dropdownView.renderSuggestions(dataset, suggestions); - } - }); - }); - }, - _autocomplete: function(e) { - var isCursorAtEnd, ignoreEvent, query, hint, suggestion; - if (e.type === "rightKeyed" || e.type === "leftKeyed") { - isCursorAtEnd = this.inputView.isCursorAtEnd(); - ignoreEvent = this.inputView.getLanguageDirection() === "ltr" ? e.type === "leftKeyed" : e.type === "rightKeyed"; - if (!isCursorAtEnd || ignoreEvent) { - return; - } - } - query = this.inputView.getQuery(); - hint = this.inputView.getHintValue(); - if (hint !== "" && query !== hint) { - suggestion = this.dropdownView.getFirstSuggestion(); - this.inputView.setInputValue(suggestion.value); - this.eventBus.trigger("autocompleted", suggestion.datum, suggestion.dataset); - } - }, - _propagateEvent: function(e) { - this.eventBus.trigger(e.type); - }, - destroy: function() { - this.inputView.destroy(); - this.dropdownView.destroy(); - destroyDomStructure(this.$node); - this.$node = null; - }, - setQuery: function(query) { - this.inputView.setQuery(query); - this.inputView.setInputValue(query); - this._clearHint(); - this._clearSuggestions(); - this._getSuggestions(); - } - }); - return TypeaheadView; - function buildDomStructure(input) { - var $wrapper = $(html.wrapper), $dropdown = $(html.dropdown), $input = $(input), $hint = $(html.hint); - $wrapper = $wrapper.css(css.wrapper); - $dropdown = $dropdown.css(css.dropdown); - $hint.css(css.hint).css({ - backgroundAttachment: $input.css("background-attachment"), - backgroundClip: $input.css("background-clip"), - backgroundColor: $input.css("background-color"), - backgroundImage: $input.css("background-image"), - backgroundOrigin: $input.css("background-origin"), - backgroundPosition: $input.css("background-position"), - backgroundRepeat: $input.css("background-repeat"), - backgroundSize: $input.css("background-size") - }); - $input.data("ttAttrs", { - dir: $input.attr("dir"), - autocomplete: $input.attr("autocomplete"), - spellcheck: $input.attr("spellcheck"), - style: $input.attr("style") - }); - $input.addClass("tt-query").attr({ - autocomplete: "off", - spellcheck: false - }).css(css.query); - try { - !$input.attr("dir") && $input.attr("dir", "auto"); - } catch (e) {} - return $input.wrap($wrapper).parent().prepend($hint).append($dropdown); - } - function destroyDomStructure($node) { - var $input = $node.find(".tt-query"); - utils.each($input.data("ttAttrs"), function(key, val) { - utils.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val); - }); - $input.detach().removeData("ttAttrs").removeClass("tt-query").insertAfter($node); - $node.remove(); - } - }(); - (function() { - var cache = {}, viewKey = "ttView", methods; - methods = { - initialize: function(datasetDefs) { - var datasets; - datasetDefs = utils.isArray(datasetDefs) ? datasetDefs : [ datasetDefs ]; - if (datasetDefs.length === 0) { - $.error("no datasets provided"); - } - datasets = utils.map(datasetDefs, function(o) { - var dataset = cache[o.name] ? cache[o.name] : new Dataset(o); - if (o.name) { - cache[o.name] = dataset; - } - return dataset; - }); - return this.each(initialize); - function initialize() { - var $input = $(this), deferreds, eventBus = new EventBus({ - el: $input - }); - deferreds = utils.map(datasets, function(dataset) { - return dataset.initialize(); - }); - $input.data(viewKey, new TypeaheadView({ - input: $input, - eventBus: eventBus = new EventBus({ - el: $input - }), - datasets: datasets - })); - $.when.apply($, deferreds).always(function() { - utils.defer(function() { - eventBus.trigger("initialized"); - }); - }); - } - }, - destroy: function() { - return this.each(destroy); - function destroy() { - var $this = $(this), view = $this.data(viewKey); - if (view) { - view.destroy(); - $this.removeData(viewKey); - } - } - }, - setQuery: function(query) { - return this.each(setQuery); - function setQuery() { - var view = $(this).data(viewKey); - view && view.setQuery(query); - } - } - }; - jQuery.fn.typeahead = function(method) { - if (methods[method]) { - return methods[method].apply(this, [].slice.call(arguments, 1)); - } else { - return methods.initialize.apply(this, arguments); - } - }; - })(); -})(window.jQuery); \ No newline at end of file diff --git a/extensions/gii/assets/typeahead.js-bootstrap.css b/extensions/gii/assets/typeahead.js-bootstrap.css deleted file mode 100644 index 987aaf5..0000000 --- a/extensions/gii/assets/typeahead.js-bootstrap.css +++ /dev/null @@ -1,51 +0,0 @@ -/* always keep this link here when updating this file: https://github.com/jharding/typeahead.js-bootstrap.css */ - -.twitter-typeahead .tt-query, -.twitter-typeahead .tt-hint { - margin-bottom: 0; -} - -.tt-dropdown-menu { - min-width: 160px; - margin-top: 2px; - padding: 5px 0; - background-color: #fff; - border: 1px solid #ccc; - border: 1px solid rgba(0,0,0,.2); - *border-right-width: 2px; - *border-bottom-width: 2px; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; - -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); - -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); - box-shadow: 0 5px 10px rgba(0,0,0,.2); - -webkit-background-clip: padding-box; - -moz-background-clip: padding; - background-clip: padding-box; -} - -.tt-suggestion { - display: block; - padding: 3px 20px; -} - -.tt-suggestion.tt-is-under-cursor { - color: #fff; - background-color: #0081c2; - background-image: -moz-linear-gradient(top, #0088cc, #0077b3); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); - background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); - background-image: -o-linear-gradient(top, #0088cc, #0077b3); - background-image: linear-gradient(to bottom, #0088cc, #0077b3); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0) -} - -.tt-suggestion.tt-is-under-cursor a { - color: #fff; -} - -.tt-suggestion p { - margin: 0; -} diff --git a/extensions/gii/components/ActiveField.php b/extensions/gii/components/ActiveField.php deleted file mode 100644 index ae6f144..0000000 --- a/extensions/gii/components/ActiveField.php +++ /dev/null @@ -1,66 +0,0 @@ - - * @since 2.0 - */ -class ActiveField extends \yii\widgets\ActiveField -{ - /** - * @var Generator - */ - public $model; - - public function init() - { - $stickyAttributes = $this->model->stickyAttributes(); - if (in_array($this->attribute, $stickyAttributes)) { - $this->sticky(); - } - $hints = $this->model->hints(); - if (isset($hints[$this->attribute])) { - $this->hint($hints[$this->attribute]); - } - $autoCompleteData = $this->model->autoCompleteData(); - if (isset($autoCompleteData[$this->attribute])) { - if (is_callable($autoCompleteData[$this->attribute])) { - $this->autoComplete(call_user_func($autoCompleteData[$this->attribute])); - } else { - $this->autoComplete($autoCompleteData[$this->attribute]); - } - } - } - - /** - * Makes field remember its value between page reloads - * @return static the field object itself - */ - public function sticky() - { - $this->options['class'] .= ' sticky'; - return $this; - } - - /** - * Makes field auto completable - * @param array $data auto complete data (array of callables or scalars) - * @return static the field object itself - */ - public function autoComplete($data) - { - static $counter = 0; - $this->inputOptions['class'] .= ' typeahead-' . (++$counter); - $this->form->getView()->registerJs("jQuery('.typeahead-{$counter}').typeahead({local: " . Json::encode($data) . "});"); - return $this; - } -} diff --git a/extensions/gii/composer.json b/extensions/gii/composer.json deleted file mode 100644 index 4e17844..0000000 --- a/extensions/gii/composer.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "yiisoft/yii2-gii", - "description": "The Gii extension for the Yii framework", - "keywords": ["yii", "gii", "code generator"], - "type": "yii2-extension", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?labels=ext%3Agii", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "authors": [ - { - "name": "Qiang Xue", - "email": "qiang.xue@gmail.com" - } - ], - "require": { - "yiisoft/yii2": "*", - "yiisoft/yii2-bootstrap": "*" - }, - "autoload": { - "psr-0": { "yii\\gii\\": "" } - }, - "target-dir": "yii/gii" -} diff --git a/extensions/gii/controllers/DefaultController.php b/extensions/gii/controllers/DefaultController.php deleted file mode 100644 index 2b3bf00..0000000 --- a/extensions/gii/controllers/DefaultController.php +++ /dev/null @@ -1,152 +0,0 @@ - - * @since 2.0 - */ -class DefaultController extends Controller -{ - public $layout = 'generator'; - /** - * @var \yii\gii\Module - */ - public $module; - /** - * @var \yii\gii\Generator - */ - public $generator; - - public function actionIndex() - { - $this->layout = 'main'; - return $this->render('index'); - } - - public function actionView($id) - { - $generator = $this->loadGenerator($id); - $params = ['generator' => $generator, 'id' => $id]; - if (isset($_POST['preview']) || isset($_POST['generate'])) { - if ($generator->validate()) { - $generator->saveStickyAttributes(); - $files = $generator->generate(); - if (isset($_POST['generate']) && !empty($_POST['answers'])) { - $params['hasError'] = $generator->save($files, (array)$_POST['answers'], $results); - $params['results'] = $results; - } else { - $params['files'] = $files; - $params['answers'] = isset($_POST['answers']) ? $_POST['answers'] : null; - } - } - } - - return $this->render('view', $params); - } - - public function actionPreview($id, $file) - { - $generator = $this->loadGenerator($id); - if ($generator->validate()) { - foreach ($generator->generate() as $f) { - if ($f->id === $file) { - $content = $f->preview(); - if ($content !== false) { - return '
    ' . $content . ''; - } else { - return '
    Preview is not available for this file type.
    '; - } - } - } - } - throw new NotFoundHttpException("Code file not found: $file"); - } - - public function actionDiff($id, $file) - { - $generator = $this->loadGenerator($id); - if ($generator->validate()) { - foreach ($generator->generate() as $f) { - if ($f->id === $file) { - return $this->renderPartial('diff', [ - 'diff' => $f->diff(), - ]); - } - } - } - throw new NotFoundHttpException("Code file not found: $file"); - } - - /** - * Runs an action defined in the generator. - * Given an action named "xyz", the method "actionXyz()" in the generator will be called. - * If the method does not exist, a 400 HTTP exception will be thrown. - * @param string $id the ID of the generator - * @param string $name the action name - * @return mixed the result of the action. - * @throws NotFoundHttpException if the action method does not exist. - */ - public function actionAction($id, $name) - { - $generator = $this->loadGenerator($id); - $method = 'action' . $name; - if (method_exists($generator, $method)) { - return $generator->$method(); - } else { - throw new NotFoundHttpException("Unknown generator action: $name"); - } - } - - public function createUrl($route, $params = []) - { - if (!isset($params['id']) && $this->generator !== null) { - foreach ($this->module->generators as $id => $generator) { - if ($generator === $this->generator) { - $params['id'] = $id; - break; - } - } - } - return parent::createUrl($route, $params); - } - - public function createActionUrl($name, $params = []) - { - foreach ($this->module->generators as $id => $generator) { - if ($generator === $this->generator) { - $params['id'] = $id; - break; - } - } - $params['name'] = $name; - return parent::createUrl('action', $params); - } - - /** - * Loads the generator with the specified ID. - * @param string $id the ID of the generator to be loaded. - * @return \yii\gii\Generator the loaded generator - * @throws NotFoundHttpException - */ - protected function loadGenerator($id) - { - if (isset($this->module->generators[$id])) { - $this->generator = $this->module->generators[$id]; - $this->generator->loadStickyAttributes(); - $this->generator->load($_POST); - return $this->generator; - } else { - throw new NotFoundHttpException("Code generator not found: $id"); - } - } -} diff --git a/extensions/gii/generators/controller/Generator.php b/extensions/gii/generators/controller/Generator.php deleted file mode 100644 index 08b29d5..0000000 --- a/extensions/gii/generators/controller/Generator.php +++ /dev/null @@ -1,236 +0,0 @@ - - * @since 2.0 - */ -class Generator extends \yii\gii\Generator -{ - /** - * @var string the controller ID - */ - public $controller; - /** - * @var string the base class of the controller - */ - public $baseClass = 'yii\web\Controller'; - /** - * @var string the namespace of the controller class - */ - public $ns; - /** - * @var string list of action IDs separated by commas or spaces - */ - public $actions = 'index'; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - $this->ns = \Yii::$app->controllerNamespace; - } - - /** - * @inheritdoc - */ - public function getName() - { - return 'Controller Generator'; - } - - /** - * @inheritdoc - */ - public function getDescription() - { - return 'This generator helps you to quickly generate a new controller class, - one or several controller actions and their corresponding views.'; - } - - /** - * @inheritdoc - */ - public function rules() - { - return array_merge(parent::rules(), [ - [['controller', 'actions', 'baseClass', 'ns'], 'filter', 'filter' => 'trim'], - [['controller', 'baseClass'], 'required'], - [['controller'], 'match', 'pattern' => '/^[a-z\\-\\/]*$/', 'message' => 'Only a-z, dashes (-) and slashes (/) are allowed.'], - [['actions'], 'match', 'pattern' => '/^[a-z\\-,\\s]*$/', 'message' => 'Only a-z, dashes (-), spaces and commas are allowed.'], - [['baseClass'], 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], - [['ns'], 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], - ]); - } - - /** - * @inheritdoc - */ - public function attributeLabels() - { - return [ - 'baseClass' => 'Base Class', - 'controller' => 'Controller ID', - 'actions' => 'Action IDs', - 'ns' => 'Controller Namespace', - ]; - } - - /** - * @inheritdoc - */ - public function requiredTemplates() - { - return [ - 'controller.php', - 'view.php', - ]; - } - - /** - * @inheritdoc - */ - public function stickyAttributes() - { - return ['ns', 'baseClass']; - } - - /** - * @inheritdoc - */ - public function hints() - { - return [ - 'controller' => 'Controller ID should be in lower case and may contain module ID(s) separated by slashes. For example: -
      -
    • order generates OrderController.php
    • -
    • order-item generates OrderItemController.php
    • -
    • admin/user generates UserController.php within the admin module.
    • -
    ', - 'actions' => 'Provide one or multiple action IDs to generate empty action method(s) in the controller. Separate multiple action IDs with commas or spaces. - Action IDs should be in lower case. For example: -
      -
    • index generates actionIndex()
    • -
    • create-order generates actionCreateOrder()
    • -
    ', - 'ns' => 'This is the namespace that the new controller class will use.', - 'baseClass' => 'This is the class that the new controller class will extend from. Please make sure the class exists and can be autoloaded.', - ]; - } - - /** - * @inheritdoc - */ - public function successMessage() - { - $actions = $this->getActionIDs(); - if (in_array('index', $actions)) { - $route = $this->controller . '/index'; - } else { - $route = $this->controller . '/' . reset($actions); - } - $link = Html::a('try it now', Yii::$app->getUrlManager()->createUrl($route), ['target' => '_blank']); - return "The controller has been generated successfully. You may $link."; - } - - /** - * @inheritdoc - */ - public function generate() - { - $files = []; - - $files[] = new CodeFile( - $this->getControllerFile(), - $this->render('controller.php') - ); - - foreach ($this->getActionIDs() as $action) { - $files[] = new CodeFile( - $this->getViewFile($action), - $this->render('view.php', ['action' => $action]) - ); - } - - return $files; - } - - /** - * Normalizes [[actions]] into an array of action IDs. - * @return array an array of action IDs entered by the user - */ - public function getActionIDs() - { - $actions = array_unique(preg_split('/[\s,]+/', $this->actions, -1, PREG_SPLIT_NO_EMPTY)); - sort($actions); - return $actions; - } - - /** - * @return string the controller class name without the namespace part. - */ - public function getControllerClass() - { - return Inflector::id2camel($this->getControllerID()) . 'Controller'; - } - - /** - * @return string the controller ID (without the module ID prefix) - */ - public function getControllerID() - { - if (($pos = strrpos($this->controller, '/')) !== false) { - return substr($this->controller, $pos + 1); - } else { - return $this->controller; - } - } - - /** - * @return \yii\base\Module the module that the new controller belongs to - */ - public function getModule() - { - if (($pos = strrpos($this->controller, '/')) !== false) { - $id = substr($this->controller, 0, $pos); - if (($module = Yii::$app->getModule($id)) !== null) { - return $module; - } - } - return Yii::$app; - } - - /** - * @return string the controller class file path - */ - public function getControllerFile() - { - $module = $this->getModule(); - return $module->getControllerPath() . '/' . $this->getControllerClass() . '.php'; - } - - /** - * @param string $action the action ID - * @return string the action view file path - */ - public function getViewFile($action) - { - $module = $this->getModule(); - return $module->getViewPath() . '/' . $this->getControllerID() . '/' . $action . '.php'; - } -} diff --git a/extensions/gii/generators/controller/form.php b/extensions/gii/generators/controller/form.php deleted file mode 100644 index 4fba36f..0000000 --- a/extensions/gii/generators/controller/form.php +++ /dev/null @@ -1,10 +0,0 @@ -field($generator, 'controller'); -echo $form->field($generator, 'actions'); -echo $form->field($generator, 'ns'); -echo $form->field($generator, 'baseClass'); diff --git a/extensions/gii/generators/controller/templates/controller.php b/extensions/gii/generators/controller/templates/controller.php deleted file mode 100644 index b62edc3..0000000 --- a/extensions/gii/generators/controller/templates/controller.php +++ /dev/null @@ -1,28 +0,0 @@ - - -ns)): ?> -namespace ns ?>; - - -class getControllerClass() ?> extends baseClass, '\\') . "\n" ?> -{ -getActionIDs() as $action): ?> - public function action() - { - return $this->render(''); - } - - -} diff --git a/extensions/gii/generators/controller/templates/view.php b/extensions/gii/generators/controller/templates/view.php deleted file mode 100644 index 6ef2a87..0000000 --- a/extensions/gii/generators/controller/templates/view.php +++ /dev/null @@ -1,22 +0,0 @@ - -/** - * @var yii\web\View $this - */ -" ?> - -

    getControllerID() . '/' . $action ?>

    - -

    - You may change the content of this page by modifying - the file echo __FILE__; ?>. -

    diff --git a/extensions/gii/generators/crud/Generator.php b/extensions/gii/generators/crud/Generator.php deleted file mode 100644 index b126c7b..0000000 --- a/extensions/gii/generators/crud/Generator.php +++ /dev/null @@ -1,436 +0,0 @@ - - * @since 2.0 - */ -class Generator extends \yii\gii\Generator -{ - public $modelClass; - public $moduleID; - public $controllerClass; - public $baseControllerClass = 'yii\web\Controller'; - public $indexWidgetType = 'grid'; - public $searchModelClass; - - public function getName() - { - return 'CRUD Generator'; - } - - public function getDescription() - { - return 'This generator generates a controller and views that implement CRUD (Create, Read, Update, Delete) - operations for the specified data model.'; - } - - public function rules() - { - return array_merge(parent::rules(), [ - [['moduleID', 'controllerClass', 'modelClass', 'searchModelClass', 'baseControllerClass'], 'filter', 'filter' => 'trim'], - [['modelClass', 'searchModelClass', 'controllerClass', 'baseControllerClass', 'indexWidgetType'], 'required'], - [['searchModelClass'], 'compare', 'compareAttribute' => 'modelClass', 'operator' => '!==', 'message' => 'Search Model Class must not be equal to Model Class.'], - [['modelClass', 'controllerClass', 'baseControllerClass', 'searchModelClass'], 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], - [['modelClass'], 'validateClass', 'params' => ['extends' => BaseActiveRecord::className()]], - [['baseControllerClass'], 'validateClass', 'params' => ['extends' => Controller::className()]], - [['controllerClass'], 'match', 'pattern' => '/Controller$/', 'message' => 'Controller class name must be suffixed with "Controller".'], - [['controllerClass', 'searchModelClass'], 'validateNewClass'], - [['indexWidgetType'], 'in', 'range' => ['grid', 'list']], - [['modelClass'], 'validateModelClass'], - [['moduleID'], 'validateModuleID'], - ]); - } - - public function attributeLabels() - { - return array_merge(parent::attributeLabels(), [ - 'modelClass' => 'Model Class', - 'moduleID' => 'Module ID', - 'controllerClass' => 'Controller Class', - 'baseControllerClass' => 'Base Controller Class', - 'indexWidgetType' => 'Widget Used in Index Page', - 'searchModelClass' => 'Search Model Class', - ]); - } - - /** - * @inheritdoc - */ - public function hints() - { - return [ - 'modelClass' => 'This is the ActiveRecord class associated with the table that CRUD will be built upon. - You should provide a fully qualified class name, e.g., app\models\Post.', - 'controllerClass' => 'This is the name of the controller class to be generated. You should - provide a fully qualified namespaced class, .e.g, app\controllers\PostController.', - 'baseControllerClass' => 'This is the class that the new CRUD controller class will extend from. - You should provide a fully qualified class name, e.g., yii\web\Controller.', - 'moduleID' => 'This is the ID of the module that the generated controller will belong to. - If not set, it means the controller will belong to the application.', - 'indexWidgetType' => 'This is the widget type to be used in the index page to display list of the models. - You may choose either GridView or ListView', - 'searchModelClass' => 'This is the class representing the data being collected in the search form. - A fully qualified namespaced class name is required, e.g., app\models\search\PostSearch.', - ]; - } - - public function requiredTemplates() - { - return ['controller.php']; - } - - /** - * @inheritdoc - */ - public function stickyAttributes() - { - return ['baseControllerClass', 'moduleID', 'indexWidgetType']; - } - - public function validateModelClass() - { - /** @var ActiveRecord $class */ - $class = $this->modelClass; - $pk = $class::primaryKey(); - if (empty($pk)) { - $this->addError('modelClass', "The table associated with $class must have primary key(s)."); - } - } - - public function validateModuleID() - { - if (!empty($this->moduleID)) { - $module = Yii::$app->getModule($this->moduleID); - if ($module === null) { - $this->addError('moduleID', "Module '{$this->moduleID}' does not exist."); - } - } - } - - /** - * @inheritdoc - */ - public function generate() - { - $controllerFile = Yii::getAlias('@' . str_replace('\\', '/', ltrim($this->controllerClass, '\\')) . '.php'); - $searchModel = Yii::getAlias('@' . str_replace('\\', '/', ltrim($this->searchModelClass, '\\') . '.php')); - $files = [ - new CodeFile($controllerFile, $this->render('controller.php')), - new CodeFile($searchModel, $this->render('search.php')), - ]; - - $viewPath = $this->getViewPath(); - $templatePath = $this->getTemplatePath() . '/views'; - foreach (scandir($templatePath) as $file) { - if (is_file($templatePath . '/' . $file) && pathinfo($file, PATHINFO_EXTENSION) === 'php') { - $files[] = new CodeFile("$viewPath/$file", $this->render("views/$file")); - } - } - - - return $files; - } - - /** - * @return string the controller ID (without the module ID prefix) - */ - public function getControllerID() - { - $pos = strrpos($this->controllerClass, '\\'); - $class = substr(substr($this->controllerClass, $pos + 1), 0, -10); - return Inflector::camel2id($class); - } - - /** - * @return string the action view file path - */ - public function getViewPath() - { - $module = empty($this->moduleID) ? Yii::$app : Yii::$app->getModule($this->moduleID); - return $module->getViewPath() . '/' . $this->getControllerID() ; - } - - public function getNameAttribute() - { - foreach ($this->getColumnNames() as $name) { - if (!strcasecmp($name, 'name') || !strcasecmp($name, 'title')) { - return $name; - } - } - /** @var \yii\db\ActiveRecord $class */ - $class = $this->modelClass; - $pk = $class::primaryKey(); - return $pk[0]; - } - - /** - * @param string $attribute - * @return string - */ - public function generateActiveField($attribute) - { - $tableSchema = $this->getTableSchema(); - if ($tableSchema === false || !isset($tableSchema->columns[$attribute])) { - if (preg_match('/^(password|pass|passwd|passcode)$/i', $attribute)) { - return "\$form->field(\$model, '$attribute')->passwordInput();"; - } else { - return "\$form->field(\$model, '$attribute');"; - } - } - $column = $tableSchema->columns[$attribute]; - if ($column->phpType === 'boolean') { - return "\$form->field(\$model, '$attribute')->checkbox()"; - } elseif ($column->type === 'text') { - return "\$form->field(\$model, '$attribute')->textarea(['rows' => 6])"; - } else { - if (preg_match('/^(password|pass|passwd|passcode)$/i', $column->name)) { - $input = 'passwordInput'; - } else { - $input = 'textInput'; - } - if ($column->phpType !== 'string' || $column->size === null) { - return "\$form->field(\$model, '$attribute')->$input()"; - } else { - return "\$form->field(\$model, '$attribute')->$input(['maxlength' => $column->size])"; - } - } - } - - /** - * @param string $attribute - * @return string - */ - public function generateActiveSearchField($attribute) - { - $tableSchema = $this->getTableSchema(); - if ($tableSchema === false) { - return "\$form->field(\$model, '$attribute')"; - } - $column = $tableSchema->columns[$attribute]; - if ($column->phpType === 'boolean') { - return "\$form->field(\$model, '$attribute')->checkbox()"; - } else { - return "\$form->field(\$model, '$attribute')"; - } - } - - /** - * @param \yii\db\ColumnSchema $column - * @return string - */ - public function generateColumnFormat($column) - { - if ($column->phpType === 'boolean') { - return 'boolean'; - } elseif ($column->type === 'text') { - return 'ntext'; - } elseif (stripos($column->name, 'time') !== false && $column->phpType === 'integer') { - return 'datetime'; - } elseif (stripos($column->name, 'email') !== false) { - return 'email'; - } elseif (stripos($column->name, 'url') !== false) { - return 'url'; - } else { - return 'text'; - } - } - - /** - * Generates validation rules for the search model. - * @return array the generated validation rules - */ - public function generateSearchRules() - { - if (($table = $this->getTableSchema()) === false) { - return ["[['" . implode("', '", $this->getColumnNames()) . "'], 'safe']"]; - } - $types = []; - foreach ($table->columns as $column) { - switch ($column->type) { - case Schema::TYPE_SMALLINT: - case Schema::TYPE_INTEGER: - case Schema::TYPE_BIGINT: - $types['integer'][] = $column->name; - break; - case Schema::TYPE_BOOLEAN: - $types['boolean'][] = $column->name; - break; - case Schema::TYPE_FLOAT: - case Schema::TYPE_DECIMAL: - case Schema::TYPE_MONEY: - $types['number'][] = $column->name; - break; - case Schema::TYPE_DATE: - case Schema::TYPE_TIME: - case Schema::TYPE_DATETIME: - case Schema::TYPE_TIMESTAMP: - default: - $types['safe'][] = $column->name; - break; - } - } - - $rules = []; - foreach ($types as $type => $columns) { - $rules[] = "[['" . implode("', '", $columns) . "'], '$type']"; - } - - return $rules; - } - - public function getSearchAttributes() - { - return $this->getColumnNames(); - } - - /** - * Generates the attribute labels for the search model. - * @return array the generated attribute labels (name => label) - */ - public function generateSearchLabels() - { - $labels = []; - foreach ($this->getColumnNames() as $name) { - if (!strcasecmp($name, 'id')) { - $labels[$name] = 'ID'; - } else { - $label = Inflector::camel2words($name); - if (strcasecmp(substr($label, -3), ' id') === 0) { - $label = substr($label, 0, -3) . ' ID'; - } - $labels[$name] = $label; - } - } - return $labels; - } - - public function generateSearchConditions() - { - $columns = []; - if (($table = $this->getTableSchema()) === false) { - $class = $this->modelClass; - $model = new $class(); - foreach ($model->attributes() as $attribute) { - $columns[$attribute] = 'unknown'; - } - } else { - foreach ($table->columns as $column) { - $columns[$column->name] = $column->type; - } - } - $conditions = []; - foreach ($columns as $column => $type) { - switch ($type) { - case Schema::TYPE_SMALLINT: - case Schema::TYPE_INTEGER: - case Schema::TYPE_BIGINT: - case Schema::TYPE_BOOLEAN: - case Schema::TYPE_FLOAT: - case Schema::TYPE_DECIMAL: - case Schema::TYPE_MONEY: - case Schema::TYPE_DATE: - case Schema::TYPE_TIME: - case Schema::TYPE_DATETIME: - case Schema::TYPE_TIMESTAMP: - $conditions[] = "\$this->addCondition(\$query, '{$column}');"; - break; - default: - $conditions[] = "\$this->addCondition(\$query, '{$column}', true);"; - break; - } - } - - return $conditions; - } - - public function generateUrlParams() - { - /** @var ActiveRecord $class */ - $class = $this->modelClass; - $pks = $class::primaryKey(); - if (count($pks) === 1) { - return "'id' => \$model->{$pks[0]}"; - } else { - $params = []; - foreach ($pks as $pk) { - $params[] = "'$pk' => \$model->$pk"; - } - return implode(', ', $params); - } - } - - public function generateActionParams() - { - /** @var ActiveRecord $class */ - $class = $this->modelClass; - $pks = $class::primaryKey(); - if (count($pks) === 1) { - return '$id'; - } else { - return '$' . implode(', $', $pks); - } - } - - public function generateActionParamComments() - { - /** @var ActiveRecord $class */ - $class = $this->modelClass; - $pks = $class::primaryKey(); - if (($table = $this->getTableSchema()) === false) { - $params = []; - foreach ($pks as $pk) { - $params[] = '@param ' . (substr(strtolower($pk), -2) == 'id' ? 'integer' : 'string') . ' $' . $pk; - } - return $params; - } - if (count($pks) === 1) { - return ['@param ' . $table->columns[$pks[0]]->phpType . ' $id']; - } else { - $params = []; - foreach ($pks as $pk) { - $params[] = '@param ' . $table->columns[$pk]->phpType . ' $' . $pk; - } - return $params; - } - } - - public function getTableSchema() - { - /** @var ActiveRecord $class */ - $class = $this->modelClass; - if (is_subclass_of($class, 'yii\db\ActiveRecord')) { - return $class::getTableSchema(); - } else { - return false; - } - } - - public function getColumnNames() - { - /** @var ActiveRecord $class */ - $class = $this->modelClass; - if (is_subclass_of($class, 'yii\db\ActiveRecord')) { - return $class::getTableSchema()->getColumnNames(); - } else { - $model = new $class(); - return $model->attributes(); - } - } - -} diff --git a/extensions/gii/generators/crud/form.php b/extensions/gii/generators/crud/form.php deleted file mode 100644 index 1b101c2..0000000 --- a/extensions/gii/generators/crud/form.php +++ /dev/null @@ -1,16 +0,0 @@ -field($generator, 'modelClass'); -echo $form->field($generator, 'searchModelClass'); -echo $form->field($generator, 'controllerClass'); -echo $form->field($generator, 'baseControllerClass'); -echo $form->field($generator, 'moduleID'); -echo $form->field($generator, 'indexWidgetType')->dropDownList([ - 'grid' => 'GridView', - 'list' => 'ListView', -]); diff --git a/extensions/gii/generators/crud/templates/controller.php b/extensions/gii/generators/crud/templates/controller.php deleted file mode 100644 index bb5d3f4..0000000 --- a/extensions/gii/generators/crud/templates/controller.php +++ /dev/null @@ -1,157 +0,0 @@ -controllerClass); -$modelClass = StringHelper::basename($generator->modelClass); -$searchModelClass = StringHelper::basename($generator->searchModelClass); -if ($modelClass === $searchModelClass) { - $searchModelAlias = $searchModelClass.'Search'; -} - -/** @var ActiveRecordInterface $class */ -$class = $generator->modelClass; -$pks = $class::primaryKey(); -$urlParams = $generator->generateUrlParams(); -$actionParams = $generator->generateActionParams(); -$actionParamComments = $generator->generateActionParamComments(); - -echo " - -namespace controllerClass, '\\')) ?>; - -use modelClass, '\\') ?>; -use searchModelClass, '\\') ?> as ; -use baseControllerClass, '\\') ?>; -use yii\web\NotFoundHttpException; -use yii\web\VerbFilter; - -/** - * implements the CRUD actions for model. - */ -class extends baseControllerClass) . "\n" ?> -{ - public function behaviors() - { - return [ - 'verbs' => [ - 'class' => VerbFilter::className(), - 'actions' => [ - 'delete' => ['post'], - ], - ], - ]; - } - - /** - * Lists all models. - * @return mixed - */ - public function actionIndex() - { - $searchModel = new ; - $dataProvider = $searchModel->search($_GET); - - return $this->render('index', [ - 'dataProvider' => $dataProvider, - 'searchModel' => $searchModel, - ]); - } - - /** - * Displays a single model. - * - * @return mixed - */ - public function actionView() - { - return $this->render('view', [ - 'model' => $this->findModel(), - ]); - } - - /** - * Creates a new model. - * If creation is successful, the browser will be redirected to the 'view' page. - * @return mixed - */ - public function actionCreate() - { - $model = new ; - - if ($model->load($_POST) && $model->save()) { - return $this->redirect(['view', ]); - } else { - return $this->render('create', [ - 'model' => $model, - ]); - } - } - - /** - * Updates an existing model. - * If update is successful, the browser will be redirected to the 'view' page. - * - * @return mixed - */ - public function actionUpdate() - { - $model = $this->findModel(); - - if ($model->load($_POST) && $model->save()) { - return $this->redirect(['view', ]); - } else { - return $this->render('update', [ - 'model' => $model, - ]); - } - } - - /** - * Deletes an existing model. - * If deletion is successful, the browser will be redirected to the 'index' page. - * - * @return mixed - */ - public function actionDelete() - { - $this->findModel()->delete(); - return $this->redirect(['index']); - } - - /** - * Finds the model based on its primary key value. - * If the model is not found, a 404 HTTP exception will be thrown. - * - * @return the loaded model - * @throws NotFoundHttpException if the model cannot be found - */ - protected function findModel() - { - \$$pk"; - } - $condition = '[' . implode(', ', $condition) . ']'; -} -?> - if (($model = ::find()) !== null) { - return $model; - } else { - throw new NotFoundHttpException('The requested page does not exist.'); - } - } -} diff --git a/extensions/gii/generators/crud/templates/search.php b/extensions/gii/generators/crud/templates/search.php deleted file mode 100644 index 1411896..0000000 --- a/extensions/gii/generators/crud/templates/search.php +++ /dev/null @@ -1,83 +0,0 @@ -modelClass); -$searchModelClass = StringHelper::basename($generator->searchModelClass); -$rules = $generator->generateSearchRules(); -$labels = $generator->generateSearchLabels(); -$searchAttributes = $generator->getSearchAttributes(); -$searchConditions = $generator->generateSearchConditions(); - -echo " - -namespace searchModelClass, '\\')) ?>; - -use yii\base\Model; -use yii\data\ActiveDataProvider; -use modelClass, '\\') ?>; - -/** - * represents the model behind the search form about . - */ -class extends Model -{ - public $; - - public function rules() - { - return [ - , - ]; - } - - /** - * @inheritdoc - */ - public function attributeLabels() - { - return [ - $label): ?> - '" . addslashes($label) . "',\n" ?> - - ]; - } - - public function search($params) - { - $query = ::find(); - $dataProvider = new ActiveDataProvider([ - 'query' => $query, - ]); - - if (!($this->load($params) && $this->validate())) { - return $dataProvider; - } - - - - return $dataProvider; - } - - protected function addCondition($query, $attribute, $partialMatch = false) - { - $value = $this->$attribute; - if (trim($value) === '') { - return; - } - if ($partialMatch) { - $value = '%' . strtr($value, ['%'=>'\%', '_'=>'\_', '\\'=>'\\\\']) . '%'; - $query->andWhere(['like', $attribute, $value]); - } else { - $query->andWhere([$attribute => $value]); - } - } -} diff --git a/extensions/gii/generators/crud/templates/views/_form.php b/extensions/gii/generators/crud/templates/views/_form.php deleted file mode 100644 index 52538d5..0000000 --- a/extensions/gii/generators/crud/templates/views/_form.php +++ /dev/null @@ -1,44 +0,0 @@ -modelClass; -$safeAttributes = $model->safeAttributes(); -if (empty($safeAttributes)) { - $safeAttributes = $model->attributes(); -} - -echo " - -use yii\helpers\Html; -use yii\widgets\ActiveForm; - -/** - * @var yii\web\View $this - * @var modelClass, '\\') ?> $model - * @var yii\widgets\ActiveForm $form - */ -?> - -
    - - $form = ActiveForm::begin(); ?> - -generateActiveField($attribute) . " ?>\n\n"; -} ?> -
    - Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> -
    - - ActiveForm::end(); ?> - -
    diff --git a/extensions/gii/generators/crud/templates/views/_search.php b/extensions/gii/generators/crud/templates/views/_search.php deleted file mode 100644 index af2f948..0000000 --- a/extensions/gii/generators/crud/templates/views/_search.php +++ /dev/null @@ -1,48 +0,0 @@ - - -use yii\helpers\Html; -use yii\widgets\ActiveForm; - -/** - * @var yii\web\View $this - * @var searchModelClass, '\\') ?> $model - * @var yii\widgets\ActiveForm $form - */ -?> - - diff --git a/extensions/gii/generators/crud/templates/views/create.php b/extensions/gii/generators/crud/templates/views/create.php deleted file mode 100644 index 68d08ba..0000000 --- a/extensions/gii/generators/crud/templates/views/create.php +++ /dev/null @@ -1,33 +0,0 @@ - - -use yii\helpers\Html; - -/** - * @var yii\web\View $this - * @var modelClass, '\\') ?> $model - */ - -$this->title = 'Create modelClass)) ?>'; -$this->params['breadcrumbs'][] = ['label' => 'modelClass))) ?>', 'url' => ['index']]; -$this->params['breadcrumbs'][] = $this->title; -?> -
    - -

    Html::encode($this->title) ?>

    - - echo $this->render('_form', [ - 'model' => $model, - ]); ?> - -
    diff --git a/extensions/gii/generators/crud/templates/views/index.php b/extensions/gii/generators/crud/templates/views/index.php deleted file mode 100644 index 3ad2138..0000000 --- a/extensions/gii/generators/crud/templates/views/index.php +++ /dev/null @@ -1,81 +0,0 @@ -generateUrlParams(); -$nameAttribute = $generator->getNameAttribute(); - -echo " - -use yii\helpers\Html; -use indexWidgetType === 'grid' ? "yii\\grid\\GridView" : "yii\\widgets\\ListView" ?>; - -/** - * @var yii\web\View $this - * @var yii\data\ActiveDataProvider $dataProvider - * @var searchModelClass, '\\') ?> $searchModel - */ - -$this->title = 'modelClass))) ?>'; -$this->params['breadcrumbs'][] = $this->title; -?> -
    - -

    Html::encode($this->title) ?>

    - - indexWidgetType === 'grid' ? "// " : "") ?>echo $this->render('_search', ['model' => $searchModel]); ?> - -

    - Html::a('Create modelClass) ?>', ['create'], ['class' => 'btn btn-success']) ?> -

    - -indexWidgetType === 'grid'): ?> - echo GridView::widget([ - 'dataProvider' => $dataProvider, - 'filterModel' => $searchModel, - 'columns' => [ - ['class' => 'yii\grid\SerialColumn'], - -getTableSchema()) === false) { - foreach ($generator->getColumnNames() as $name) { - if (++$count < 6) { - echo "\t\t\t'" . $name . "',\n"; - } else { - echo "\t\t\t// '" . $name . "',\n"; - } - } -} else { - foreach ($tableSchema->columns as $column) { - $format = $generator->generateColumnFormat($column); - if (++$count < 6) { - echo "\t\t\t'" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n"; - } else { - echo "\t\t\t// '" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n"; - } - } -} -?> - - ['class' => 'yii\grid\ActionColumn'], - ], - ]); ?> - - echo ListView::widget([ - 'dataProvider' => $dataProvider, - 'itemOptions' => ['class' => 'item'], - 'itemView' => function ($model, $key, $index, $widget) { - return Html::a(Html::encode($model->), ['view', ]); - }, - ]); ?> - - -
    diff --git a/extensions/gii/generators/crud/templates/views/update.php b/extensions/gii/generators/crud/templates/views/update.php deleted file mode 100644 index 2fbbecf..0000000 --- a/extensions/gii/generators/crud/templates/views/update.php +++ /dev/null @@ -1,36 +0,0 @@ -generateUrlParams(); - -echo " - -use yii\helpers\Html; - -/** - * @var yii\web\View $this - * @var modelClass, '\\') ?> $model - */ - -$this->title = 'Update modelClass)) ?>: ' . $model->getNameAttribute() ?>; -$this->params['breadcrumbs'][] = ['label' => 'modelClass))) ?>', 'url' => ['index']]; -$this->params['breadcrumbs'][] = ['label' => $model->getNameAttribute() ?>, 'url' => ['view', ]]; -$this->params['breadcrumbs'][] = 'Update'; -?> -
    - -

    Html::encode($this->title) ?>

    - - echo $this->render('_form', [ - 'model' => $model, - ]); ?> - -
    diff --git a/extensions/gii/generators/crud/templates/views/view.php b/extensions/gii/generators/crud/templates/views/view.php deleted file mode 100644 index 9e74aff..0000000 --- a/extensions/gii/generators/crud/templates/views/view.php +++ /dev/null @@ -1,59 +0,0 @@ -generateUrlParams(); - -echo " - -use yii\helpers\Html; -use yii\widgets\DetailView; - -/** - * @var yii\web\View $this - * @var modelClass, '\\') ?> $model - */ - -$this->title = $model->getNameAttribute() ?>; -$this->params['breadcrumbs'][] = ['label' => 'modelClass))) ?>', 'url' => ['index']]; -$this->params['breadcrumbs'][] = $this->title; -?> -
    - -

    Html::encode($this->title) ?>

    - -

    - Html::a('Update', ['update', ], ['class' => 'btn btn-primary']) ?> - echo Html::a('Delete', ['delete', ], [ - 'class' => 'btn btn-danger', - 'data-confirm' => Yii::t('app', 'Are you sure to delete this item?'), - 'data-method' => 'post', - ]); ?> -

    - - echo DetailView::widget([ - 'model' => $model, - 'attributes' => [ -getTableSchema()) === false) { - foreach ($generator->getColumnNames() as $name) { - echo "\t\t\t'" . $name . "',\n"; - } -} else { - foreach ($generator->getTableSchema()->columns as $column) { - $format = $generator->generateColumnFormat($column); - echo "\t\t\t'" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n"; - } -} -?> - ], - ]); ?> - -
    diff --git a/extensions/gii/generators/form/Generator.php b/extensions/gii/generators/form/Generator.php deleted file mode 100644 index 3bc0be6..0000000 --- a/extensions/gii/generators/form/Generator.php +++ /dev/null @@ -1,152 +0,0 @@ - - * @since 2.0 - */ -class Generator extends \yii\gii\Generator -{ - public $modelClass; - public $viewPath = '@app/views'; - public $viewName; - public $scenarioName; - - - /** - * @inheritdoc - */ - public function getName() - { - return 'Form Generator'; - } - - /** - * @inheritdoc - */ - public function getDescription() - { - return 'This generator generates a view script file that displays a form to collect input for the specified model class.'; - } - - /** - * @inheritdoc - */ - public function generate() - { - $files = []; - $files[] = new CodeFile( - Yii::getAlias($this->viewPath) . '/' . $this->viewName . '.php', - $this->render('form.php') - ); - return $files; - } - - /** - * @inheritdoc - */ - public function rules() - { - return array_merge(parent::rules(), [ - [['modelClass', 'viewName', 'scenarioName', 'viewPath'], 'filter', 'filter' => 'trim'], - [['modelClass', 'viewName', 'viewPath'], 'required'], - [['modelClass'], 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], - [['modelClass'], 'validateClass', 'params' => ['extends' => Model::className()]], - [['viewName'], 'match', 'pattern' => '/^\w+[\\-\\/\w]*$/', 'message' => 'Only word characters, dashes and slashes are allowed.'], - [['viewPath'], 'match', 'pattern' => '/^@?\w+[\\-\\/\w]*$/', 'message' => 'Only word characters, dashes, slashes and @ are allowed.'], - [['viewPath'], 'validateViewPath'], - [['scenarioName'], 'match', 'pattern' => '/^[\w\\-]+$/', 'message' => 'Only word characters and dashes are allowed.'], - ]); - } - - /** - * @inheritdoc - */ - public function attributeLabels() - { - return [ - 'modelClass' => 'Model Class', - 'viewName' => 'View Name', - 'viewPath' => 'View Path', - 'scenarioName' => 'Scenario', - ]; - } - - /** - * @inheritdoc - */ - public function requiredTemplates() - { - return ['form.php', 'action.php']; - } - - /** - * @inheritdoc - */ - public function stickyAttributes() - { - return ['viewPath', 'scenarioName']; - } - - /** - * @inheritdoc - */ - public function hints() - { - return [ - 'modelClass' => 'This is the model class for collecting the form input. You should provide a fully qualified class name, e.g., app\models\Post.', - 'viewName' => 'This is the view name with respect to the view path. For example, site/index would generate a site/index.php view file under the view path.', - 'viewPath' => 'This is the root view path to keep the generated view files. You may provide either a directory or a path alias, e.g., @app/views.', - 'scenarioName' => 'This is the scenario to be used by the model when collecting the form input. If empty, the default scenario will be used.', - ]; - } - - /** - * @inheritdoc - */ - public function successMessage() - { - $code = highlight_string($this->render('action.php'), true); - return <<The form has been generated successfully.

    -

    You may add the following code in an appropriate controller class to invoke the view:

    -
    $code
    -EOD; - } - - /** - * Validates [[viewPath]] to make sure it is a valid path or path alias and exists. - */ - public function validateViewPath() - { - $path = Yii::getAlias($this->viewPath, false); - if ($path === false || !is_dir($path)) { - $this->addError('viewPath', 'View path does not exist.'); - } - } - - /** - * @return array list of safe attributes of [[modelClass]] - */ - public function getModelAttributes() - { - /** @var Model $model */ - $model = new $this->modelClass; - if (!empty($this->scenarioName)) { - $model->setScenario($this->scenarioName); - } - return $model->safeAttributes(); - } -} diff --git a/extensions/gii/generators/form/form.php b/extensions/gii/generators/form/form.php deleted file mode 100644 index 3d46777..0000000 --- a/extensions/gii/generators/form/form.php +++ /dev/null @@ -1,10 +0,0 @@ -field($generator, 'viewName'); -echo $form->field($generator, 'modelClass'); -echo $form->field($generator, 'scenarioName'); -echo $form->field($generator, 'viewPath'); diff --git a/extensions/gii/generators/form/templates/action.php b/extensions/gii/generators/form/templates/action.php deleted file mode 100644 index 9e6840d..0000000 --- a/extensions/gii/generators/form/templates/action.php +++ /dev/null @@ -1,28 +0,0 @@ - - -public function actionviewName), '_')) ?>() -{ - $model = new modelClass ?>scenarioName) ? "" : "(['scenario' => '{$generator->scenarioName}'])" ?>; - - if ($model->load($_POST)) { - if ($model->validate()) { - // form inputs are valid, do something here - return; - } - } - return $this->render('viewName ?>', [ - 'model' => $model, - ]); -} diff --git a/extensions/gii/generators/form/templates/form.php b/extensions/gii/generators/form/templates/form.php deleted file mode 100644 index b30570c..0000000 --- a/extensions/gii/generators/form/templates/form.php +++ /dev/null @@ -1,35 +0,0 @@ - - -use yii\helpers\Html; -use yii\widgets\ActiveForm; - -/** - * @var yii\web\View $this - * @var modelClass ?> $model - * @var ActiveForm $form - */ -" ?> - -
    - - $form = ActiveForm::begin(); ?> - - getModelAttributes() as $attribute): ?> - $form->field($model, '') ?> - - -
    - Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?> -
    - ActiveForm::end(); ?> - -
    diff --git a/extensions/gii/generators/model/Generator.php b/extensions/gii/generators/model/Generator.php deleted file mode 100644 index 591cb3b..0000000 --- a/extensions/gii/generators/model/Generator.php +++ /dev/null @@ -1,555 +0,0 @@ - - * @since 2.0 - */ -class Generator extends \yii\gii\Generator -{ - public $db = 'db'; - public $ns = 'app\models'; - public $tableName; - public $modelClass; - public $baseClass = 'yii\db\ActiveRecord'; - public $generateRelations = true; - public $generateLabelsFromComments = false; - - - /** - * @inheritdoc - */ - public function getName() - { - return 'Model Generator'; - } - - /** - * @inheritdoc - */ - public function getDescription() - { - return 'This generator generates an ActiveRecord class for the specified database table.'; - } - - /** - * @inheritdoc - */ - public function rules() - { - return array_merge(parent::rules(), [ - [['db', 'ns', 'tableName', 'modelClass', 'baseClass'], 'filter', 'filter' => 'trim'], - [['db', 'ns', 'tableName', 'baseClass'], 'required'], - [['db', 'modelClass'], 'match', 'pattern' => '/^\w+$/', 'message' => 'Only word characters are allowed.'], - [['ns', 'baseClass'], 'match', 'pattern' => '/^[\w\\\\]+$/', 'message' => 'Only word characters and backslashes are allowed.'], - [['tableName'], 'match', 'pattern' => '/^(\w+\.)?([\w\*]+)$/', 'message' => 'Only word characters, and optionally an asterisk and/or a dot are allowed.'], - [['db'], 'validateDb'], - [['ns'], 'validateNamespace'], - [['tableName'], 'validateTableName'], - [['modelClass'], 'validateModelClass', 'skipOnEmpty' => false], - [['baseClass'], 'validateClass', 'params' => ['extends' => ActiveRecord::className()]], - [['generateRelations', 'generateLabelsFromComments'], 'boolean'], - ]); - } - - /** - * @inheritdoc - */ - public function attributeLabels() - { - return [ - 'ns' => 'Namespace', - 'db' => 'Database Connection ID', - 'tableName' => 'Table Name', - 'modelClass' => 'Model Class', - 'baseClass' => 'Base Class', - 'generateRelations' => 'Generate Relations', - 'generateLabelsFromComments' => 'Generate Labels from DB Comments', - ]; - } - - /** - * @inheritdoc - */ - public function hints() - { - return [ - 'ns' => 'This is the namespace of the ActiveRecord class to be generated, e.g., app\models', - 'db' => 'This is the ID of the DB application component.', - 'tableName' => 'This is the name of the DB table that the new ActiveRecord class is associated with, e.g. tbl_post. - The table name may consist of the DB schema part if needed, e.g. public.tbl_post. - The table name may end with asterisk to match multiple table names, e.g. tbl_* - will match tables who name starts with tbl_. In this case, multiple ActiveRecord classes - will be generated, one for each matching table name; and the class names will be generated from - the matching characters. For example, table tbl_post will generate Post - class.', - 'modelClass' => 'This is the name of the ActiveRecord class to be generated. The class name should not contain - the namespace part as it is specified in "Namespace". You do not need to specify the class name - if "Table Name" ends with asterisk, in which case multiple ActiveRecord classes will be generated.', - 'baseClass' => 'This is the base class of the new ActiveRecord class. It should be a fully qualified namespaced class name.', - 'generateRelations' => 'This indicates whether the generator should generate relations based on - foreign key constraints it detects in the database. Note that if your database contains too many tables, - you may want to uncheck this option to accelerate the code generation process.', - 'generateLabelsFromComments' => 'This indicates whether the generator should generate attribute labels - by using the comments of the corresponding DB columns.', - ]; - } - - /** - * @inheritdoc - */ - public function autoCompleteData() - { - $db = $this->getDbConnection(); - if ($db !== null) { - return [ - 'tableName' => function () use ($db) { - return $db->getSchema()->getTableNames(); - }, - ]; - } else { - return []; - } - } - - /** - * @inheritdoc - */ - public function requiredTemplates() - { - return ['model.php']; - } - - /** - * @inheritdoc - */ - public function stickyAttributes() - { - return ['ns', 'db', 'baseClass', 'generateRelations', 'generateLabelsFromComments']; - } - - /** - * @inheritdoc - */ - public function generate() - { - $files = []; - $relations = $this->generateRelations(); - $db = $this->getDbConnection(); - foreach ($this->getTableNames() as $tableName) { - $className = $this->generateClassName($tableName); - $tableSchema = $db->getTableSchema($tableName); - $params = [ - 'tableName' => $tableName, - 'className' => $className, - 'tableSchema' => $tableSchema, - 'labels' => $this->generateLabels($tableSchema), - 'rules' => $this->generateRules($tableSchema), - 'relations' => isset($relations[$className]) ? $relations[$className] : [], - ]; - $files[] = new CodeFile( - Yii::getAlias('@' . str_replace('\\', '/', $this->ns)) . '/' . $className . '.php', - $this->render('model.php', $params) - ); - } - - return $files; - } - - /** - * Generates the attribute labels for the specified table. - * @param \yii\db\TableSchema $table the table schema - * @return array the generated attribute labels (name => label) - */ - public function generateLabels($table) - { - $labels = []; - foreach ($table->columns as $column) { - if ($this->generateLabelsFromComments && !empty($column->comment)) { - $labels[$column->name] = $column->comment; - } elseif (!strcasecmp($column->name, 'id')) { - $labels[$column->name] = 'ID'; - } else { - $label = Inflector::camel2words($column->name); - if (strcasecmp(substr($label, -3), ' id') === 0) { - $label = substr($label, 0, -3) . ' ID'; - } - $labels[$column->name] = $label; - } - } - return $labels; - } - - /** - * Generates validation rules for the specified table. - * @param \yii\db\TableSchema $table the table schema - * @return array the generated validation rules - */ - public function generateRules($table) - { - $types = []; - $lengths = []; - foreach ($table->columns as $column) { - if ($column->autoIncrement) { - continue; - } - if (!$column->allowNull && $column->defaultValue === null) { - $types['required'][] = $column->name; - } - switch ($column->type) { - case Schema::TYPE_SMALLINT: - case Schema::TYPE_INTEGER: - case Schema::TYPE_BIGINT: - $types['integer'][] = $column->name; - break; - case Schema::TYPE_BOOLEAN: - $types['boolean'][] = $column->name; - break; - case Schema::TYPE_FLOAT: - case Schema::TYPE_DECIMAL: - case Schema::TYPE_MONEY: - $types['number'][] = $column->name; - break; - case Schema::TYPE_DATE: - case Schema::TYPE_TIME: - case Schema::TYPE_DATETIME: - case Schema::TYPE_TIMESTAMP: - $types['safe'][] = $column->name; - break; - default: // strings - if ($column->size > 0) { - $lengths[$column->size][] = $column->name; - } else { - $types['string'][] = $column->name; - } - } - } - - $rules = []; - foreach ($types as $type => $columns) { - $rules[] = "[['" . implode("', '", $columns) . "'], '$type']"; - } - foreach ($lengths as $length => $columns) { - $rules[] = "[['" . implode("', '", $columns) . "'], 'string', 'max' => $length]"; - } - - return $rules; - } - - /** - * @return array the generated relation declarations - */ - protected function generateRelations() - { - if (!$this->generateRelations) { - return []; - } - - $db = $this->getDbConnection(); - - if (($pos = strpos($this->tableName, '.')) !== false) { - $schemaName = substr($this->tableName, 0, $pos); - } else { - $schemaName = ''; - } - - $relations = []; - foreach ($db->getSchema()->getTableSchemas($schemaName) as $table) { - $tableName = $table->name; - $className = $this->generateClassName($tableName); - foreach ($table->foreignKeys as $refs) { - $refTable = $refs[0]; - unset($refs[0]); - $fks = array_keys($refs); - $refClassName = $this->generateClassName($refTable); - - // Add relation for this table - $link = $this->generateRelationLink(array_flip($refs)); - $relationName = $this->generateRelationName($relations, $className, $table, $fks[0], false); - $relations[$className][$relationName] = [ - "return \$this->hasOne($refClassName::className(), $link);", - $refClassName, - false, - ]; - - // Add relation for the referenced table - $hasMany = false; - foreach ($fks as $key) { - if (!in_array($key, $table->primaryKey, true)) { - $hasMany = true; - break; - } - } - $link = $this->generateRelationLink($refs); - $relationName = $this->generateRelationName($relations, $refClassName, $refTable, $className, $hasMany); - $relations[$refClassName][$relationName] = [ - "return \$this->" . ($hasMany ? 'hasMany' : 'hasOne') . "($className::className(), $link);", - $className, - $hasMany, - ]; - } - - if (($fks = $this->checkPivotTable($table)) === false) { - continue; - } - $table0 = $fks[$table->primaryKey[0]][0]; - $table1 = $fks[$table->primaryKey[1]][0]; - $className0 = $this->generateClassName($table0); - $className1 = $this->generateClassName($table1); - - $link = $this->generateRelationLink([$fks[$table->primaryKey[1]][1] => $table->primaryKey[1]]); - $viaLink = $this->generateRelationLink([$table->primaryKey[0] => $fks[$table->primaryKey[0]][1]]); - $relationName = $this->generateRelationName($relations, $className0, $db->getTableSchema($table0), $table->primaryKey[1], true); - $relations[$className0][$relationName] = [ - "return \$this->hasMany($className1::className(), $link)->viaTable('{$table->name}', $viaLink);", - $className0, - true, - ]; - - $link = $this->generateRelationLink([$fks[$table->primaryKey[0]][1] => $table->primaryKey[0]]); - $viaLink = $this->generateRelationLink([$table->primaryKey[1] => $fks[$table->primaryKey[1]][1]]); - $relationName = $this->generateRelationName($relations, $className1, $db->getTableSchema($table1), $table->primaryKey[0], true); - $relations[$className1][$relationName] = [ - "return \$this->hasMany($className0::className(), $link)->viaTable('{$table->name}', $viaLink);", - $className1, - true, - ]; - } - return $relations; - } - - /** - * Generates the link parameter to be used in generating the relation declaration. - * @param array $refs reference constraint - * @return string the generated link parameter. - */ - protected function generateRelationLink($refs) - { - $pairs = []; - foreach ($refs as $a => $b) { - $pairs[] = "'$a' => '$b'"; - } - return '[' . implode(', ', $pairs) . ']'; - } - - /** - * Checks if the given table is a pivot table. - * For simplicity, this method only deals with the case where the pivot contains two PK columns, - * each referencing a column in a different table. - * @param \yii\db\TableSchema the table being checked - * @return array|boolean the relevant foreign key constraint information if the table is a pivot table, - * or false if the table is not a pivot table. - */ - protected function checkPivotTable($table) - { - $pk = $table->primaryKey; - if (count($pk) !== 2) { - return false; - } - $fks = []; - foreach ($table->foreignKeys as $refs) { - if (count($refs) === 2) { - if (isset($refs[$pk[0]])) { - $fks[$pk[0]] = [$refs[0], $refs[$pk[0]]]; - } elseif (isset($refs[$pk[1]])) { - $fks[$pk[1]] = [$refs[0], $refs[$pk[1]]]; - } - } - } - if (count($fks) === 2 && $fks[$pk[0]][0] !== $fks[$pk[1]][0]) { - return $fks; - } else { - return false; - } - } - - /** - * Generate a relation name for the specified table and a base name. - * @param array $relations the relations being generated currently. - * @param string $className the class name that will contain the relation declarations - * @param \yii\db\TableSchema $table the table schema - * @param string $key a base name that the relation name may be generated from - * @param boolean $multiple whether this is a has-many relation - * @return string the relation name - */ - protected function generateRelationName($relations, $className, $table, $key, $multiple) - { - if (strcasecmp(substr($key, -2), 'id') === 0 && strcasecmp($key, 'id')) { - $key = rtrim(substr($key, 0, -2), '_'); - } - if ($multiple) { - $key = Inflector::pluralize($key); - } - $name = $rawName = Inflector::id2camel($key, '_'); - $i = 0; - while (isset($table->columns[lcfirst($name)])) { - $name = $rawName . ($i++); - } - while (isset($relations[$className][lcfirst($name)])) { - $name = $rawName . ($i++); - } - - return $name; - } - - /** - * Validates the [[db]] attribute. - */ - public function validateDb() - { - if (Yii::$app->hasComponent($this->db) === false) { - $this->addError('db', 'There is no application component named "db".'); - } elseif (!Yii::$app->getComponent($this->db) instanceof Connection) { - $this->addError('db', 'The "db" application component must be a DB connection instance.'); - } - } - - /** - * Validates the [[ns]] attribute. - */ - public function validateNamespace() - { - $this->ns = ltrim($this->ns, '\\'); - $path = Yii::getAlias('@' . str_replace('\\', '/', $this->ns), false); - if ($path === false) { - $this->addError('ns', 'Namespace must be associated with an existing directory.'); - } - } - - /** - * Validates the [[modelClass]] attribute. - */ - public function validateModelClass() - { - if ($this->isReservedKeyword($this->modelClass)) { - $this->addError('modelClass', 'Class name cannot be a reserved PHP keyword.'); - } - if (substr($this->tableName, -1) !== '*' && $this->modelClass == '') { - $this->addError('modelClass', 'Model Class cannot be blank if table name does not end with asterisk.'); - } - } - - /** - * Validates the [[tableName]] attribute. - */ - public function validateTableName() - { - if (($pos = strpos($this->tableName, '*')) !== false && substr($this->tableName, -1) !== '*') { - $this->addError('tableName', 'Asterisk is only allowed as the last character.'); - return; - } - $tables = $this->getTableNames(); - if (empty($tables)) { - $this->addError('tableName', "Table '{$this->tableName}' does not exist."); - } else { - foreach ($tables as $table) { - $class = $this->generateClassName($table); - if ($this->isReservedKeyword($class)) { - $this->addError('tableName', "Table '$table' will generate a class which is a reserved PHP keyword."); - break; - } - } - } - } - - private $_tableNames; - private $_classNames; - - /** - * @return array the table names that match the pattern specified by [[tableName]]. - */ - protected function getTableNames() - { - if ($this->_tableNames !== null) { - return $this->_tableNames; - } - $db = $this->getDbConnection(); - if ($db === null) { - return []; - } - $tableNames = []; - if (strpos($this->tableName, '*') !== false) { - if (($pos = strrpos($this->tableName, '.')) !== false) { - $schema = substr($this->tableName, 0, $pos); - $pattern = '/^' . str_replace('*', '\w+', substr($this->tableName, $pos + 1)) . '$/'; - } else { - $schema = ''; - $pattern = '/^' . str_replace('*', '\w+', $this->tableName) . '$/'; - } - - foreach ($db->schema->getTableNames($schema) as $table) { - if (preg_match($pattern, $table)) { - $tableNames[] = $schema === '' ? $table : ($schema . '.' . $table); - } - } - } elseif (($table = $db->getTableSchema($this->tableName, true)) !== null) { - $tableNames[] = $this->tableName; - $this->_classNames[$this->tableName] = $this->modelClass; - } - return $this->_tableNames = $tableNames; - } - - /** - * Generates a class name from the specified table name. - * @param string $tableName the table name (which may contain schema prefix) - * @return string the generated class name - */ - protected function generateClassName($tableName) - { - if (isset($this->_classNames[$tableName])) { - return $this->_classNames[$tableName]; - } - - if (($pos = strrpos($tableName, '.')) !== false) { - $tableName = substr($tableName, $pos + 1); - } - - $db = $this->getDbConnection(); - $patterns = []; - if (strpos($this->tableName, '*') !== false) { - $pattern = $this->tableName; - if (($pos = strrpos($pattern, '.')) !== false) { - $pattern = substr($pattern, $pos + 1); - } - $patterns[] = '/^' . str_replace('*', '(\w+)', $pattern) . '$/'; - } - if (!empty($db->tablePrefix)) { - $patterns[] = "/^{$db->tablePrefix}(.*?)$/"; - $patterns[] = "/^(.*?){$db->tablePrefix}$/"; - } else { - $patterns[] = "/^tbl_(.*?)$/"; - } - - $className = $tableName; - foreach ($patterns as $pattern) { - if (preg_match($pattern, $tableName, $matches)) { - $className = $matches[1]; - break; - } - } - return $this->_classNames[$tableName] = Inflector::id2camel($className, '_'); - } - - /** - * @return Connection the DB connection as specified by [[db]]. - */ - protected function getDbConnection() - { - return Yii::$app->{$this->db}; - } -} diff --git a/extensions/gii/generators/model/form.php b/extensions/gii/generators/model/form.php deleted file mode 100644 index ddc40f8..0000000 --- a/extensions/gii/generators/model/form.php +++ /dev/null @@ -1,14 +0,0 @@ -field($generator, 'tableName'); -echo $form->field($generator, 'modelClass'); -echo $form->field($generator, 'ns'); -echo $form->field($generator, 'baseClass'); -echo $form->field($generator, 'db'); -echo $form->field($generator, 'generateRelations')->checkbox(); -echo $form->field($generator, 'generateLabelsFromComments')->checkbox(); diff --git a/extensions/gii/generators/model/templates/model.php b/extensions/gii/generators/model/templates/model.php deleted file mode 100644 index dcd1461..0000000 --- a/extensions/gii/generators/model/templates/model.php +++ /dev/null @@ -1,72 +0,0 @@ -label) - * @var string[] $rules list of validation rules - * @var array $relations list of relations (name=>relation declaration) - */ - -echo " - -namespace ns ?>; - -/** - * This is the model class for table "". - * -columns as $column): ?> - * @property phpType} \${$column->name}\n" ?> - - - * - $relation): ?> - * @property - - - */ -class extends baseClass, '\\') . "\n" ?> -{ - /** - * @inheritdoc - */ - public static function tableName() - { - return ''; - } - - /** - * @inheritdoc - */ - public function rules() - { - return []; - } - - /** - * @inheritdoc - */ - public function attributeLabels() - { - return [ - $label): ?> - '" . addslashes($label) . "',\n" ?> - - ]; - } - $relation): ?> - - /** - * @return \yii\db\ActiveRelation - */ - public function get() - { - - } - -} diff --git a/extensions/gii/generators/module/Generator.php b/extensions/gii/generators/module/Generator.php deleted file mode 100644 index a97aa20..0000000 --- a/extensions/gii/generators/module/Generator.php +++ /dev/null @@ -1,165 +0,0 @@ - - * @since 2.0 - */ -class Generator extends \yii\gii\Generator -{ - public $moduleClass; - public $moduleID; - - /** - * @inheritdoc - */ - public function getName() - { - return 'Module Generator'; - } - - /** - * @inheritdoc - */ - public function getDescription() - { - return 'This generator helps you to generate the skeleton code needed by a Yii module.'; - } - - /** - * @inheritdoc - */ - public function rules() - { - return array_merge(parent::rules(), [ - [['moduleID', 'moduleClass'], 'filter', 'filter' => 'trim'], - [['moduleID', 'moduleClass'], 'required'], - [['moduleID'], 'match', 'pattern' => '/^[\w\\-]+$/', 'message' => 'Only word characters and dashes are allowed.'], - [['moduleClass'], 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'], - [['moduleClass'], 'validateModuleClass'], - ]); - } - - /** - * @inheritdoc - */ - public function attributeLabels() - { - return [ - 'moduleID' => 'Module ID', - 'moduleClass' => 'Module Class', - ]; - } - - /** - * @inheritdoc - */ - public function hints() - { - return [ - 'moduleID' => 'This refers to the ID of the module, e.g., admin.', - 'moduleClass' => 'This is the fully qualified class name of the module, e.g., app\modules\admin\Module.', - ]; - } - - /** - * @inheritdoc - */ - public function successMessage() - { - if (Yii::$app->hasModule($this->moduleID)) { - $link = Html::a('try it now', Yii::$app->getUrlManager()->createUrl($this->moduleID), ['target' => '_blank']); - return "The module has been generated successfully. You may $link."; - } - - $output = <<The module has been generated successfully.

    -

    To access the module, you need to add this to your application configuration:

    -EOD; - $code = << [ - '{$this->moduleID}' => [ - 'class' => '{$this->moduleClass}', - ], - ], - ...... -EOD; - - return $output . '
    ' . highlight_string($code, true) . '
    '; - } - - /** - * @inheritdoc - */ - public function requiredTemplates() - { - return ['module.php', 'controller.php', 'view.php']; - } - - /** - * @inheritdoc - */ - public function generate() - { - $files = []; - $modulePath = $this->getModulePath(); - $files[] = new CodeFile( - $modulePath . '/' . StringHelper::basename($this->moduleClass) . '.php', - $this->render("module.php") - ); - $files[] = new CodeFile( - $modulePath . '/controllers/DefaultController.php', - $this->render("controller.php") - ); - $files[] = new CodeFile( - $modulePath . '/views/default/index.php', - $this->render("view.php") - ); - - return $files; - } - - /** - * Validates [[moduleClass]] to make sure it is a fully qualified class name. - */ - public function validateModuleClass() - { - if (strpos($this->moduleClass, '\\') === false || Yii::getAlias('@' . str_replace('\\', '/', $this->moduleClass), false) === false) { - $this->addError('moduleClass', 'Module class must be properly namespaced.'); - } - if (substr($this->moduleClass, -1, 1) == '\\') { - $this->addError('moduleClass', 'Module class name must not be empty. Please enter a fully qualified class name. e.g. "app\\modules\\admin\\Module".'); - } - } - - /** - * @return boolean the directory that contains the module class - */ - public function getModulePath() - { - return Yii::getAlias('@' . str_replace('\\', '/', substr($this->moduleClass, 0, strrpos($this->moduleClass, '\\')))); - } - - /** - * @return string the controller namespace of the module. - */ - public function getControllerNamespace() - { - return substr($this->moduleClass, 0, strrpos($this->moduleClass, '\\')) . '\controllers'; - } -} diff --git a/extensions/gii/generators/module/form.php b/extensions/gii/generators/module/form.php deleted file mode 100644 index 2874d90..0000000 --- a/extensions/gii/generators/module/form.php +++ /dev/null @@ -1,13 +0,0 @@ - -
    -field($generator, 'moduleClass'); - echo $form->field($generator, 'moduleID'); -?> -
    diff --git a/extensions/gii/generators/module/templates/controller.php b/extensions/gii/generators/module/templates/controller.php deleted file mode 100644 index 018450c..0000000 --- a/extensions/gii/generators/module/templates/controller.php +++ /dev/null @@ -1,21 +0,0 @@ - - -namespace getControllerNamespace() ?>; - -use yii\web\Controller; - -class DefaultController extends Controller -{ - public function actionIndex() - { - return $this->render('index'); - } -} diff --git a/extensions/gii/generators/module/templates/module.php b/extensions/gii/generators/module/templates/module.php deleted file mode 100644 index 72b32be..0000000 --- a/extensions/gii/generators/module/templates/module.php +++ /dev/null @@ -1,29 +0,0 @@ -moduleClass; -$pos = strrpos($className, '\\'); -$ns = ltrim(substr($className, 0, $pos), '\\'); -$className = substr($className, $pos + 1); - -echo " - -namespace ; - - -class extends \yii\base\Module -{ - public $controllerNamespace = 'getControllerNamespace() ?>'; - - public function init() - { - parent::init(); - - // custom initialization code goes here - } -} diff --git a/extensions/gii/generators/module/templates/view.php b/extensions/gii/generators/module/templates/view.php deleted file mode 100644 index f5f4248..0000000 --- a/extensions/gii/generators/module/templates/view.php +++ /dev/null @@ -1,18 +0,0 @@ - -
    -

    $this->context->action->uniqueId ?>

    -

    - This is the view content for action "$this->context->action->id ?>". - The action belongs to the controller "get_class($this->context) ?>" - in the "$this->context->module->id ?>" module. -

    -

    - You may customize this page by editing the following file:
    - __FILE__ ?> -

    -
    diff --git a/extensions/gii/views/default/diff.php b/extensions/gii/views/default/diff.php deleted file mode 100644 index 6ee91a1..0000000 --- a/extensions/gii/views/default/diff.php +++ /dev/null @@ -1,15 +0,0 @@ - -
    - -
    Diff is not supported for this file type.
    - -
    Identical.
    - -
    - -
    diff --git a/extensions/gii/views/default/index.php b/extensions/gii/views/default/index.php deleted file mode 100644 index 2e48816..0000000 --- a/extensions/gii/views/default/index.php +++ /dev/null @@ -1,33 +0,0 @@ -controller->module->generators; -$activeGenerator = Yii::$app->controller->generator; -$this->title = 'Welcome to Gii'; -?> -
    - - -

    Start the fun with the following code generators:

    - -
    - $generator): ?> -
    -

    getName()) ?>

    -

    getDescription() ?>

    -

    $id], ['class' => 'btn btn-default']) ?>

    -
    - -
    - -

    Get More Generators

    - -
    diff --git a/extensions/gii/views/default/view.php b/extensions/gii/views/default/view.php deleted file mode 100644 index dabcf39..0000000 --- a/extensions/gii/views/default/view.php +++ /dev/null @@ -1,72 +0,0 @@ -title = $generator->getName(); -$templates = []; -foreach ($generator->templates as $name => $path) { - $templates[$name] = "$name ($path)"; -} -?> -
    -

    title) ?>

    - -

    getDescription() ?>

    - - "$id-generator", - 'successCssClass' => '', - 'fieldConfig' => ['class' => ActiveField::className()], - ]); ?> -
    -
    - renderFile($generator->formView(), [ - 'generator' => $generator, - 'form' => $form, - ]) ?> - field($generator, 'template')->sticky() - ->label('Code Template') - ->dropDownList($templates)->hint(' - Please select which set of the templates should be used to generated the code. - ') ?> -
    - 'preview', 'class' => 'btn btn-primary']) ?> - - - 'generate', 'class' => 'btn btn-success']) ?> - -
    -
    -
    - - render('view/results', [ - 'generator' => $generator, - 'results' => $results, - 'hasError' => $hasError, - ]); - } elseif (isset($files)) { - echo $this->render('view/files', [ - 'generator' => $generator, - 'files' => $files, - 'answers' => $answers, - ]); - } - ?> - -
    diff --git a/extensions/gii/views/default/view/files.php b/extensions/gii/views/default/view/files.php deleted file mode 100644 index d8d5f0f..0000000 --- a/extensions/gii/views/default/view/files.php +++ /dev/null @@ -1,78 +0,0 @@ - -
    -

    Click on the above Generate button to generate the files selected below:

    - - - - - - - - - - - - - - - - - - -
    Code FileAction - operation !== CodeFile::OP_SKIP) { - echo ''; - break; - } - } - ?> -
    - getRelativePath()), ['preview', 'file' => $file->id], ['class' => 'preview-code', 'data-title' => $file->getRelativePath()]) ?> - operation === CodeFile::OP_OVERWRITE): ?> - $file->id], ['class' => 'diff-code label label-warning', 'data-title' => $file->getRelativePath()]) ?> - - - operation === CodeFile::OP_SKIP) { - echo 'unchanged'; - } else { - echo $file->operation; - } - ?> - - operation === CodeFile::OP_SKIP) { - echo ' '; - } else { - echo Html::checkBox("answers[{$file->id}]", isset($answers) ? isset($answers[$file->id]) : ($file->operation === CodeFile::OP_CREATE)); - } - ?> -
    - - -
    diff --git a/extensions/gii/views/default/view/results.php b/extensions/gii/views/default/view/results.php deleted file mode 100644 index 0e9b7d9..0000000 --- a/extensions/gii/views/default/view/results.php +++ /dev/null @@ -1,18 +0,0 @@ - -
    - There was something wrong when generating the code. Please check the following messages.
    '; - } else { - echo '
    ' . $generator->successMessage() . '
    '; - } - ?> -
    -
    diff --git a/extensions/gii/views/layouts/generator.php b/extensions/gii/views/layouts/generator.php deleted file mode 100644 index 245cd29..0000000 --- a/extensions/gii/views/layouts/generator.php +++ /dev/null @@ -1,31 +0,0 @@ -controller->module->generators; -$activeGenerator = Yii::$app->controller->generator; -?> -beginContent('@yii/gii/views/layouts/main.php'); ?> -
    -
    -
    - $generator) { - $label = '' . Html::encode($generator->getName()); - echo Html::a($label, ['default/view', 'id' => $id], [ - 'class' => $generator === $activeGenerator ? 'list-group-item active' : 'list-group-item', - ]); - } - ?> -
    -
    -
    - -
    -
    -endContent(); ?> diff --git a/extensions/gii/views/layouts/main.php b/extensions/gii/views/layouts/main.php deleted file mode 100644 index 788b10c..0000000 --- a/extensions/gii/views/layouts/main.php +++ /dev/null @@ -1,53 +0,0 @@ - -beginPage() ?> - - - - - <?= Html::encode($this->title) ?> - head() ?> - - -beginBody() ?> - Html::img($asset->baseUrl . '/logo.png'), - 'brandUrl' => ['default/index'], - 'options' => ['class' => 'navbar-inverse navbar-fixed-top'], -]); -echo Nav::widget([ - 'options' => ['class' => 'nav navbar-nav navbar-right'], - 'items' => [ - ['label' => 'Home', 'url' => ['default/index']], - ['label' => 'Help', 'url' => 'http://www.yiiframework.com/doc/guide/topics.gii'], - ['label' => 'Application', 'url' => Yii::$app->homeUrl], - ], -]); -NavBar::end(); -?> - -
    - -
    - - - -endBody() ?> - - -endPage() ?> diff --git a/extensions/jui/Accordion.php b/extensions/jui/Accordion.php deleted file mode 100644 index 42897a9..0000000 --- a/extensions/jui/Accordion.php +++ /dev/null @@ -1,121 +0,0 @@ - [ - * [ - * 'header' => 'Section 1', - * 'content' => 'Mauris mauris ante, blandit et, ultrices a, suscipit eget...', - * ], - * [ - * 'header' => 'Section 2', - * 'headerOptions' => ['tag' => 'h3'], - * 'content' => 'Sed non urna. Phasellus eu ligula. Vestibulum sit amet purus...', - * 'options' => ['tag' => 'div'], - * ], - * ], - * 'options' => ['tag' => 'div'], - * 'itemOptions' => ['tag' => 'div'], - * 'headerOptions' => ['tag' => 'h3'], - * 'clientOptions' => ['collapsible' => false], - * ]); - * ``` - * - * @see http://api.jqueryui.com/accordion/ - * @author Alexander Kochetov - * @since 2.0 - */ -class Accordion extends Widget -{ - /** - * @var array the HTML attributes for the widget container tag. The following special options are recognized: - * - * - tag: string, defaults to "div", the tag name of the container tag of this widget - */ - public $options = []; - /** - * @var array list of collapsible items. Each item can be an array of the following structure: - * - * ~~~ - * [ - * 'header' => 'Item header', - * 'content' => 'Item content', - * // the HTML attributes of the item header container tag. This will overwrite "headerOptions". - * 'headerOptions' => [], - * // the HTML attributes of the item container tag. This will overwrite "itemOptions". - * 'options' => [], - * ] - * ~~~ - */ - public $items = []; - /** - * @var array list of HTML attributes for the item container tags. This will be overwritten - * by the "options" set in individual [[items]]. The following special options are recognized: - * - * - tag: string, defaults to "div", the tag name of the item container tags. - */ - public $itemOptions = []; - /** - * @var array list of HTML attributes for the item header container tags. This will be overwritten - * by the "headerOptions" set in individual [[items]]. The following special options are recognized: - * - * - tag: string, defaults to "h3", the tag name of the item container tags. - */ - public $headerOptions = []; - - - /** - * Renders the widget. - */ - public function run() - { - $options = $this->options; - $tag = ArrayHelper::remove($options, 'tag', 'div'); - echo Html::beginTag($tag, $options) . "\n"; - echo $this->renderItems() . "\n"; - echo Html::endTag($tag) . "\n"; - $this->registerWidget('accordion', AccordionAsset::className()); - } - - /** - * Renders collapsible items as specified on [[items]]. - * @return string the rendering result. - * @throws InvalidConfigException. - */ - protected function renderItems() - { - $items = []; - foreach ($this->items as $item) { - if (!isset($item['header'])) { - throw new InvalidConfigException("The 'header' option is required."); - } - if (!isset($item['content'])) { - throw new InvalidConfigException("The 'content' option is required."); - } - $headerOptions = array_merge($this->headerOptions, ArrayHelper::getValue($item, 'headerOptions', [])); - $headerTag = ArrayHelper::remove($headerOptions, 'tag', 'h3'); - $items[] = Html::tag($headerTag, $item['header'], $headerOptions); - $options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', [])); - $tag = ArrayHelper::remove($options, 'tag', 'div'); - $items[] = Html::tag($tag, $item['content'], $options); - } - - return implode("\n", $items); - } -} diff --git a/extensions/jui/AccordionAsset.php b/extensions/jui/AccordionAsset.php deleted file mode 100644 index 05c1e20..0000000 --- a/extensions/jui/AccordionAsset.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @since 2.0 - */ -class AccordionAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.accordion.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - 'yii\jui\EffectAsset', - ]; -} diff --git a/extensions/jui/AutoComplete.php b/extensions/jui/AutoComplete.php deleted file mode 100644 index ac0c997..0000000 --- a/extensions/jui/AutoComplete.php +++ /dev/null @@ -1,66 +0,0 @@ - $model, - * 'attribute' => 'country', - * 'clientOptions' => [ - * 'source' => ['USA', 'RUS'], - * ], - * ]); - * ``` - * - * The following example will use the name property instead: - * - * ```php - * echo AutoComplete::widget([ - * 'name' => 'country', - * 'clientOptions' => [ - * 'source' => ['USA', 'RUS'], - * ], - * ]); - *``` - * - * @see http://api.jqueryui.com/autocomplete/ - * @author Alexander Kochetov - * @since 2.0 - */ -class AutoComplete extends InputWidget -{ - /** - * Renders the widget. - */ - public function run() - { - echo $this->renderWidget(); - $this->registerWidget('autocomplete', AutoCompleteAsset::className()); - } - - /** - * Renders the AutoComplete widget. - * @return string the rendering result. - */ - public function renderWidget() - { - if ($this->hasModel()) { - return Html::activeTextInput($this->model, $this->attribute, $this->options); - } else { - return Html::textInput($this->name, $this->value, $this->options); - } - } -} diff --git a/extensions/jui/AutoCompleteAsset.php b/extensions/jui/AutoCompleteAsset.php deleted file mode 100644 index f48e064..0000000 --- a/extensions/jui/AutoCompleteAsset.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class AutoCompleteAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.autocomplete.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - 'yii\jui\MenuAsset', - ]; -} diff --git a/extensions/jui/ButtonAsset.php b/extensions/jui/ButtonAsset.php deleted file mode 100644 index 6616b34..0000000 --- a/extensions/jui/ButtonAsset.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class ButtonAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.button.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - ]; -} diff --git a/extensions/jui/CoreAsset.php b/extensions/jui/CoreAsset.php deleted file mode 100644 index d77a25f..0000000 --- a/extensions/jui/CoreAsset.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @since 2.0 - */ -class CoreAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.core.js', - 'jquery.ui.widget.js', - 'jquery.ui.position.js', - 'jquery.ui.mouse.js', - ]; - public $depends = [ - 'yii\web\JqueryAsset', - ]; -} diff --git a/extensions/jui/DatePicker.php b/extensions/jui/DatePicker.php deleted file mode 100644 index 06ca356..0000000 --- a/extensions/jui/DatePicker.php +++ /dev/null @@ -1,110 +0,0 @@ - 'ru', - * 'model' => $model, - * 'attribute' => 'country', - * 'clientOptions' => [ - * 'dateFormat' => 'yy-mm-dd', - * ], - * ]); - * ``` - * - * The following example will use the name property instead: - * - * ```php - * echo DatePicker::widget([ - * 'language' => 'ru', - * 'name' => 'country', - * 'clientOptions' => [ - * 'dateFormat' => 'yy-mm-dd', - * ], - * ]); - *``` - * - * @see http://api.jqueryui.com/datepicker/ - * @author Alexander Kochetov - * @since 2.0 - */ -class DatePicker extends InputWidget -{ - /** - * @var string the locale ID (eg 'fr', 'de') for the language to be used by the date picker. - * If this property set to false, I18N will not be involved. That is, the date picker will show in English. - */ - public $language = false; - /** - * @var boolean If true, shows the widget as an inline calendar and the input as a hidden field. - */ - public $inline = false; - - - /** - * Renders the widget. - */ - public function run() - { - echo $this->renderWidget() . "\n"; - if ($this->language !== false) { - $view = $this->getView(); - DatePickerRegionalAsset::register($view); - - $options = Json::encode($this->clientOptions); - $view->registerJs("$('#{$this->options['id']}').datepicker($.extend({}, $.datepicker.regional['{$this->language}'], $options));"); - - $options = $this->clientOptions; - $this->clientOptions = false; // the datepicker js widget is already registered - $this->registerWidget('datepicker', DatePickerAsset::className()); - $this->clientOptions = $options; - } else { - $this->registerWidget('datepicker', DatePickerAsset::className()); - } - } - - /** - * Renders the DatePicker widget. - * @return string the rendering result. - */ - protected function renderWidget() - { - $contents = []; - - if ($this->inline === false) { - if ($this->hasModel()) { - $contents[] = Html::activeTextInput($this->model, $this->attribute, $this->options); - } else { - $contents[] = Html::textInput($this->name, $this->value, $this->options); - } - } else { - if ($this->hasModel()) { - $contents[] = Html::activeHiddenInput($this->model, $this->attribute, $this->options); - $this->clientOptions['defaultDate'] = $this->model->{$this->attribute}; - } else { - $contents[] = Html::hiddenInput($this->name, $this->value, $this->options); - $this->clientOptions['defaultDate'] = $this->value; - } - $this->clientOptions['altField'] = '#' . $this->options['id']; - $this->options['id'] .= '-container'; - $contents[] = Html::tag('div', null, $this->options); - } - - return implode("\n", $contents); - } -} diff --git a/extensions/jui/DatePickerAsset.php b/extensions/jui/DatePickerAsset.php deleted file mode 100644 index fddd8df..0000000 --- a/extensions/jui/DatePickerAsset.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class DatePickerAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.datepicker.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - 'yii\jui\EffectAsset', - ]; -} diff --git a/extensions/jui/DatePickerRegionalAsset.php b/extensions/jui/DatePickerRegionalAsset.php deleted file mode 100644 index 249373a..0000000 --- a/extensions/jui/DatePickerRegionalAsset.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class DatePickerRegionalAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.datepicker-i18n.js', - ]; - public $depends = [ - 'yii\jui\DatePickerAsset', - ]; -} diff --git a/extensions/jui/Dialog.php b/extensions/jui/Dialog.php deleted file mode 100644 index a5cbaf2..0000000 --- a/extensions/jui/Dialog.php +++ /dev/null @@ -1,52 +0,0 @@ - [ - * 'modal' => true, - * ], - * ]); - * - * echo 'Dialog contents here...'; - * - * Dialog::end(); - * ``` - * - * @see http://api.jqueryui.com/dialog/ - * @author Alexander Kochetov - * @since 2.0 - */ -class Dialog extends Widget -{ - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - echo Html::beginTag('div', $this->options) . "\n"; - } - - /** - * Renders the widget. - */ - public function run() - { - echo Html::endTag('div') . "\n"; - $this->registerWidget('dialog', DialogAsset::className()); - } -} diff --git a/extensions/jui/DialogAsset.php b/extensions/jui/DialogAsset.php deleted file mode 100644 index 109243e..0000000 --- a/extensions/jui/DialogAsset.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @since 2.0 - */ -class DialogAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.dialog.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - 'yii\jui\ButtonAsset', - 'yii\jui\DraggableAsset', - 'yii\jui\ResizableAsset', - ]; -} diff --git a/extensions/jui/Draggable.php b/extensions/jui/Draggable.php deleted file mode 100644 index 02e4973..0000000 --- a/extensions/jui/Draggable.php +++ /dev/null @@ -1,50 +0,0 @@ - ['grid' => [50, 20]], - * ]); - * - * echo 'Draggable contents here...'; - * - * Draggable::end(); - * ``` - * - * @see http://api.jqueryui.com/draggable/ - * @author Alexander Kochetov - * @since 2.0 - */ -class Draggable extends Widget -{ - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - echo Html::beginTag('div', $this->options) . "\n"; - } - - /** - * Renders the widget. - */ - public function run() - { - echo Html::endTag('div') . "\n"; - $this->registerWidget('draggable', DraggableAsset::className()); - } -} diff --git a/extensions/jui/DraggableAsset.php b/extensions/jui/DraggableAsset.php deleted file mode 100644 index f3286a5..0000000 --- a/extensions/jui/DraggableAsset.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class DraggableAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.draggable.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - ]; -} diff --git a/extensions/jui/Droppable.php b/extensions/jui/Droppable.php deleted file mode 100644 index 530e736..0000000 --- a/extensions/jui/Droppable.php +++ /dev/null @@ -1,50 +0,0 @@ - ['accept' => '.special'], - * ]); - * - * echo 'Droppable body here...'; - * - * Droppable::end(); - * ``` - * - * @see http://api.jqueryui.com/droppable/ - * @author Alexander Kochetov - * @since 2.0 - */ -class Droppable extends Widget -{ - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - echo Html::beginTag('div', $this->options) . "\n"; - } - - /** - * Renders the widget. - */ - public function run() - { - echo Html::endTag('div') . "\n"; - $this->registerWidget('droppable', DroppableAsset::className()); - } -} diff --git a/extensions/jui/DroppableAsset.php b/extensions/jui/DroppableAsset.php deleted file mode 100644 index 84b64b8..0000000 --- a/extensions/jui/DroppableAsset.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class DroppableAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.droppable.js', - ]; - public $depends = [ - 'yii\jui\DraggableAsset', - ]; -} diff --git a/extensions/jui/EffectAsset.php b/extensions/jui/EffectAsset.php deleted file mode 100644 index 79c5aaa..0000000 --- a/extensions/jui/EffectAsset.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class EffectAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.effect-all.js', - ]; - public $depends = [ - 'yii\web\JqueryAsset', - ]; -} diff --git a/extensions/jui/InputWidget.php b/extensions/jui/InputWidget.php deleted file mode 100644 index e100d6c..0000000 --- a/extensions/jui/InputWidget.php +++ /dev/null @@ -1,59 +0,0 @@ - - * @since 2.0 - */ -class InputWidget extends Widget -{ - /** - * @var Model the data model that this widget is associated with. - */ - public $model; - /** - * @var string the model attribute that this widget is associated with. - */ - public $attribute; - /** - * @var string the input name. This must be set if [[model]] and [[attribute]] are not set. - */ - public $name; - /** - * @var string the input value. - */ - public $value; - - - /** - * Initializes the widget. - * If you override this method, make sure you call the parent implementation first. - */ - public function init() - { - if (!$this->hasModel() && $this->name === null) { - throw new InvalidConfigException("Either 'name' or 'model' and 'attribute' properties must be specified."); - } - parent::init(); - } - - /** - * @return boolean whether this widget is associated with a data model. - */ - protected function hasModel() - { - return $this->model instanceof Model && $this->attribute !== null; - } -} diff --git a/extensions/jui/LICENSE.md b/extensions/jui/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/extensions/jui/LICENSE.md +++ /dev/null @@ -1,32 +0,0 @@ -The Yii framework is free software. It is released under the terms of -the following BSD License. - -Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Yii Software LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/extensions/jui/Menu.php b/extensions/jui/Menu.php deleted file mode 100644 index 46c7ee0..0000000 --- a/extensions/jui/Menu.php +++ /dev/null @@ -1,78 +0,0 @@ - - * @since 2.0 - */ -class Menu extends \yii\widgets\Menu -{ - /** - * @var array the options for the underlying jQuery UI widget. - * Please refer to the corresponding jQuery UI widget Web page for possible options. - * For example, [this page](http://api.jqueryui.com/accordion/) shows - * how to use the "Accordion" widget and the supported options (e.g. "header"). - */ - public $clientOptions = []; - /** - * @var array the event handlers for the underlying jQuery UI widget. - * Please refer to the corresponding jQuery UI widget Web page for possible events. - * For example, [this page](http://api.jqueryui.com/accordion/) shows - * how to use the "Accordion" widget and the supported events (e.g. "create"). - */ - public $clientEvents = []; - - - /** - * Initializes the widget. - * If you override this method, make sure you call the parent implementation first. - */ - public function init() - { - parent::init(); - if (!isset($this->options['id'])) { - $this->options['id'] = $this->getId(); - } - } - - /** - * Renders the widget. - */ - public function run() - { - parent::run(); - - $view = $this->getView(); - MenuAsset::register($view); - /** @var \yii\web\AssetBundle $themeAsset */ - $themeAsset = Widget::$theme; - $themeAsset::register($view); - - $id = $this->options['id']; - if ($this->clientOptions !== false) { - $options = empty($this->clientOptions) ? '' : Json::encode($this->clientOptions); - $js = "jQuery('#$id').menu($options);"; - $view->registerJs($js); - } - - if (!empty($this->clientEvents)) { - $js = []; - foreach ($this->clientEvents as $event => $handler) { - $js[] = "jQuery('#$id').on('menu$event', $handler);"; - } - $view->registerJs(implode("\n", $js)); - } - } -} diff --git a/extensions/jui/MenuAsset.php b/extensions/jui/MenuAsset.php deleted file mode 100644 index 8b840a8..0000000 --- a/extensions/jui/MenuAsset.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class MenuAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.menu.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - ]; -} diff --git a/extensions/jui/ProgressBar.php b/extensions/jui/ProgressBar.php deleted file mode 100644 index 1c555f1..0000000 --- a/extensions/jui/ProgressBar.php +++ /dev/null @@ -1,60 +0,0 @@ - [ - * 'value' => 75, - * ], - * ]); - * ``` - * - * The following example will show the content enclosed between the [[begin()]] - * and [[end()]] calls within the widget container: - * - * ~~~php - * ProgressBar::widget([ - * 'clientOptions' => ['value' => 75], - * ]); - * - * echo '
    Loading...
    '; - * - * ProgressBar::end(); - * ~~~ - * @see http://api.jqueryui.com/progressbar/ - * @author Alexander Kochetov - * @since 2.0 - */ -class ProgressBar extends Widget -{ - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - echo Html::beginTag('div', $this->options) . "\n"; - } - - /** - * Renders the widget. - */ - public function run() - { - echo Html::endTag('div') . "\n"; - $this->registerWidget('progressbar', ProgressBarAsset::className()); - } -} diff --git a/extensions/jui/ProgressBarAsset.php b/extensions/jui/ProgressBarAsset.php deleted file mode 100644 index d485fbd..0000000 --- a/extensions/jui/ProgressBarAsset.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class ProgressBarAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.progressbar.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - ]; -} diff --git a/extensions/jui/README.md b/extensions/jui/README.md deleted file mode 100644 index f197c8c..0000000 --- a/extensions/jui/README.md +++ /dev/null @@ -1,41 +0,0 @@ -JUI Extension for Yii 2 -======================= - -This is the JQuery UI extension for Yii 2. It encapsulates JQuery UI widgets as Yii widgets, -and makes using JQuery UI widgets in Yii applications extremely easy. For example, the following -single line of code in a view file would render a JQuery UI DatePicker widget: - -```php - 'attributeName']) ?> -``` - -Configuring the Jquery UI options should be done using the clientOptions attribute: -```php - 'attributeName', 'clientOptions' => ['dateFormat' => 'yy-mm-dd']]) ?> -``` - -If you want to use the JUI widget in an ActiveRecord form, it can be done like this: -```php -field($model,'attributeName')->widget(DatePicker::className(),['clientOptions' => ['dateFormat' => 'yy-mm-dd']]) ?> -``` - - -Installation ------------- - -The preferred way to install this extension is through [composer](http://getcomposer.org/download/). - -Either run - -``` -php composer.phar require yiisoft/yii2-jui "*" -``` - -or add - -``` -"yiisoft/yii2-jui": "*" -``` - -to the require section of your `composer.json` file. - diff --git a/extensions/jui/Resizable.php b/extensions/jui/Resizable.php deleted file mode 100644 index bcff9a8..0000000 --- a/extensions/jui/Resizable.php +++ /dev/null @@ -1,52 +0,0 @@ - [ - * 'grid' => [20, 10], - * ], - * ]); - * - * echo 'Resizable contents here...'; - * - * Resizable::end(); - * ``` - * - * @see http://api.jqueryui.com/resizable/ - * @author Alexander Kochetov - * @since 2.0 - */ -class Resizable extends Widget -{ - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - echo Html::beginTag('div', $this->options) . "\n"; - } - - /** - * Renders the widget. - */ - public function run() - { - echo Html::endTag('div') . "\n"; - $this->registerWidget('resizable', ResizableAsset::className()); - } -} diff --git a/extensions/jui/ResizableAsset.php b/extensions/jui/ResizableAsset.php deleted file mode 100644 index acf4c73..0000000 --- a/extensions/jui/ResizableAsset.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class ResizableAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.resizable.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - ]; -} diff --git a/extensions/jui/Selectable.php b/extensions/jui/Selectable.php deleted file mode 100644 index 94e4faf..0000000 --- a/extensions/jui/Selectable.php +++ /dev/null @@ -1,116 +0,0 @@ - [ - * 'Item 1', - * [ - * 'content' => 'Item2', - * ], - * [ - * 'content' => 'Item3', - * 'options' => [ - * 'tag' => 'li', - * ], - * ], - * ), - * 'options' => [ - * 'tag' => 'ul', - * ], - * 'itemOptions' => [ - * 'tag' => 'li', - * ], - * 'clientOptions' => [ - * 'tolerance' => 'fit', - * ], - * ]); - * ``` - * - * @see http://api.jqueryui.com/selectable/ - * @author Alexander Kochetov - * @since 2.0 - */ -class Selectable extends Widget -{ - /** - * @var array the HTML attributes for the widget container tag. The following special options are recognized: - * - * - tag: string, defaults to "ul", the tag name of the container tag of this widget - */ - public $options = []; - /** - * @var array list of selectable items. Each item can be a string representing the item content - * or an array of the following structure: - * - * ~~~ - * [ - * 'content' => 'item content', - * // the HTML attributes of the item container tag. This will overwrite "itemOptions". - * 'options' => [], - * ] - * ~~~ - */ - public $items = []; - /** - * @var array list of HTML attributes for the item container tags. This will be overwritten - * by the "options" set in individual [[items]]. The following special options are recognized: - * - * - tag: string, defaults to "li", the tag name of the item container tags. - */ - public $itemOptions = []; - - - /** - * Renders the widget. - */ - public function run() - { - $options = $this->options; - $tag = ArrayHelper::remove($options, 'tag', 'ul'); - echo Html::beginTag($tag, $options) . "\n"; - echo $this->renderItems() . "\n"; - echo Html::endTag($tag) . "\n"; - $this->registerWidget('selectable', SelectableAsset::className()); - } - - /** - * Renders selectable items as specified on [[items]]. - * @return string the rendering result. - * @throws InvalidConfigException. - */ - public function renderItems() - { - $items = []; - foreach ($this->items as $item) { - $options = $this->itemOptions; - $tag = ArrayHelper::remove($options, 'tag', 'li'); - if (is_array($item)) { - if (!isset($item['content'])) { - throw new InvalidConfigException("The 'content' option is required."); - } - $options = array_merge($options, ArrayHelper::getValue($item, 'options', [])); - $tag = ArrayHelper::remove($options, 'tag', $tag); - $items[] = Html::tag($tag, $item['content'], $options); - } else { - $items[] = Html::tag($tag, $item, $options); - } - } - return implode("\n", $items); - } -} diff --git a/extensions/jui/SelectableAsset.php b/extensions/jui/SelectableAsset.php deleted file mode 100644 index 61f405f..0000000 --- a/extensions/jui/SelectableAsset.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class SelectableAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.selectable.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - ]; -} diff --git a/extensions/jui/Slider.php b/extensions/jui/Slider.php deleted file mode 100644 index f051b9e..0000000 --- a/extensions/jui/Slider.php +++ /dev/null @@ -1,45 +0,0 @@ - [ - * 'min' => 1, - * 'max' => 10, - * ], - * ]); - * ``` - * - * @see http://api.jqueryui.com/slider/ - * @author Alexander Makarov - * @since 2.0 - */ -class Slider extends Widget -{ - protected $clientEventsMap = [ - 'change' => 'slidechange', - 'create' => 'slidecreate', - 'slide' => 'slide', - 'start' => 'slidestart', - 'stop' => 'slidestop', - ]; - - /** - * Executes the widget. - */ - public function run() - { - echo Html::tag('div', '', $this->options); - $this->registerWidget('slider', SliderAsset::className()); - } -} \ No newline at end of file diff --git a/extensions/jui/SliderAsset.php b/extensions/jui/SliderAsset.php deleted file mode 100644 index 56c2451..0000000 --- a/extensions/jui/SliderAsset.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class SliderAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.slider.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - ]; -} diff --git a/extensions/jui/SliderInput.php b/extensions/jui/SliderInput.php deleted file mode 100644 index cc77103..0000000 --- a/extensions/jui/SliderInput.php +++ /dev/null @@ -1,79 +0,0 @@ - $model, - * 'attribute' => 'amount', - * 'clientOptions' => [ - * 'min' => 1, - * 'max' => 10, - * ], - * ]); - * ``` - * - * The following example will use the name property instead: - * - * ``` - * echo Slider::widget([ - * 'name' => 'amount', - * 'clientOptions' => [ - * 'min' => 1, - * 'max' => 10, - * ], - * ]); - * ``` - * - * @see http://api.jqueryui.com/slider/ - * @author Alexander Makarov - * @since 2.0 - */ -class SliderInput extends InputWidget -{ - protected $clientEventsMap = [ - 'change' => 'slidechange', - 'create' => 'slidecreate', - 'slide' => 'slide', - 'start' => 'slidestart', - 'stop' => 'slidestop', - ]; - - /** - * Executes the widget. - */ - public function run() - { - echo Html::tag('div', '', $this->options); - - $inputId = $this->id.'-input'; - $inputOptions = $this->options; - $inputOptions['id'] = $inputId; - if ($this->hasModel()) { - echo Html::activeHiddenInput($this->model, $this->attribute, $inputOptions); - } else { - echo Html::hiddenInput($this->name, $this->value, $inputOptions); - } - - if (!isset($this->clientEvents['slide'])) { - $this->clientEvents['slide'] = 'function(event, ui) { - $("#'.$inputId.'").val(ui.value); - }'; - } - - $this->registerWidget('slider', SliderAsset::className()); - $this->getView()->registerJs('$("#'.$inputId.'").val($("#'.$this->id.'").slider("value"));'); - } -} \ No newline at end of file diff --git a/extensions/jui/Sortable.php b/extensions/jui/Sortable.php deleted file mode 100644 index 6209cb6..0000000 --- a/extensions/jui/Sortable.php +++ /dev/null @@ -1,106 +0,0 @@ - [ - * 'Item 1', - * ['content' => 'Item2'], - * [ - * 'content' => 'Item3', - * 'options' => ['tag' => 'li'], - * ], - * ], - * 'options' => ['tag' => 'ul'], - * 'itemOptions' => ['tag' => 'li'], - * 'clientOptions' => ['cursor' => 'move'], - * )); - * ``` - * - * @see http://api.jqueryui.com/sortable/ - * @author Alexander Kochetov - * @since 2.0 - */ -class Sortable extends Widget -{ - /** - * @var array the HTML attributes for the widget container tag. The following special options are recognized: - * - * - tag: string, defaults to "ul", the tag name of the container tag of this widget - */ - public $options = []; - /** - * @var array list of sortable items. Each item can be a string representing the item content - * or an array of the following structure: - * - * ~~~ - * [ - * 'content' => 'item content', - * // the HTML attributes of the item container tag. This will overwrite "itemOptions". - * 'options' => [], - * ] - * ~~~ - */ - public $items = []; - /** - * @var array list of HTML attributes for the item container tags. This will be overwritten - * by the "options" set in individual [[items]]. The following special options are recognized: - * - * - tag: string, defaults to "li", the tag name of the item container tags. - */ - public $itemOptions = []; - - - /** - * Renders the widget. - */ - public function run() - { - $options = $this->options; - $tag = ArrayHelper::remove($options, 'tag', 'ul'); - echo Html::beginTag($tag, $options) . "\n"; - echo $this->renderItems() . "\n"; - echo Html::endTag($tag) . "\n"; - $this->registerWidget('sortable', SortableAsset::className()); - } - - /** - * Renders sortable items as specified on [[items]]. - * @return string the rendering result. - * @throws InvalidConfigException. - */ - public function renderItems() - { - $items = []; - foreach ($this->items as $item) { - $options = $this->itemOptions; - $tag = ArrayHelper::remove($options, 'tag', 'li'); - if (is_array($item)) { - if (!isset($item['content'])) { - throw new InvalidConfigException("The 'content' option is required."); - } - $options = array_merge($options, ArrayHelper::getValue($item, 'options', [])); - $tag = ArrayHelper::remove($options, 'tag', $tag); - $items[] = Html::tag($tag, $item['content'], $options); - } else { - $items[] = Html::tag($tag, $item, $options); - } - } - return implode("\n", $items); - } -} diff --git a/extensions/jui/SortableAsset.php b/extensions/jui/SortableAsset.php deleted file mode 100644 index 69c9ba3..0000000 --- a/extensions/jui/SortableAsset.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class SortableAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.sortable.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - ]; -} diff --git a/extensions/jui/Spinner.php b/extensions/jui/Spinner.php deleted file mode 100644 index caf73f3..0000000 --- a/extensions/jui/Spinner.php +++ /dev/null @@ -1,62 +0,0 @@ - $model, - * 'attribute' => 'country', - * 'clientOptions' => ['step' => 2], - * ]); - * ``` - * - * The following example will use the name property instead: - * - * ```php - * echo Spinner::widget([ - * 'name' => 'country', - * 'clientOptions' => ['step' => 2], - * ]); - *``` - * - * @see http://api.jqueryui.com/spinner/ - * @author Alexander Kochetov - * @since 2.0 - */ -class Spinner extends InputWidget -{ - /** - * Renders the widget. - */ - public function run() - { - echo $this->renderWidget(); - $this->registerWidget('spinner', SpinnerAsset::className()); - } - - /** - * Renders the Spinner widget. - * @return string the rendering result. - */ - public function renderWidget() - { - if ($this->hasModel()) { - return Html::activeTextInput($this->model, $this->attribute, $this->options); - } else { - return Html::textInput($this->name, $this->value, $this->options); - } - } -} diff --git a/extensions/jui/SpinnerAsset.php b/extensions/jui/SpinnerAsset.php deleted file mode 100644 index 89a8c59..0000000 --- a/extensions/jui/SpinnerAsset.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class SpinnerAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.spinner.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - 'yii\jui\ButtonAsset', - ]; -} diff --git a/extensions/jui/Tabs.php b/extensions/jui/Tabs.php deleted file mode 100644 index 9d2a2be..0000000 --- a/extensions/jui/Tabs.php +++ /dev/null @@ -1,145 +0,0 @@ - [ - * [ - * 'label' => 'Tab one', - * 'content' => 'Mauris mauris ante, blandit et, ultrices a, suscipit eget...', - * ], - * [ - * 'label' => 'Tab two', - * 'content' => 'Sed non urna. Phasellus eu ligula. Vestibulum sit amet purus...', - * 'options' => ['tag' => 'div'], - * 'headerOptions' => ['class' => 'my-class'], - * ], - * [ - * 'label' => 'Tab with custom id', - * 'content' => 'Morbi tincidunt, dui sit amet facilisis feugiat...', - * 'options' => ['id' => 'my-tab'], - * ], - * [ - * 'label' => 'Ajax tab', - * 'url' => ['ajax/content'], - * ], - * ), - * 'options' => ['tag' => 'div'], - * 'itemOptions' => ['tag' => 'div'], - * 'headerOptions' => ['class' => 'my-class'], - * 'clientOptions' => ['collapsible' => false], - * ]); - * ``` - * - * @see http://api.jqueryui.com/tabs/ - * @author Alexander Kochetov - * @since 2.0 - */ -class Tabs extends Widget -{ - /** - * @var array the HTML attributes for the widget container tag. The following special options are recognized: - * - * - tag: string, defaults to "div", the tag name of the container tag of this widget - */ - public $options = []; - /** - * @var array list of tab items. Each item can be an array of the following structure: - * - * - label: string, required, specifies the header link label. When [[encodeLabels]] is true, the label - * will be HTML-encoded. - * - content: string, the content to show when corresponding tab is clicked. Can be omitted if url is specified. - * - url: mixed, mixed, optional, the url to load tab contents via AJAX. It is required if no content is specified. - * - template: string, optional, the header link template to render the header link. If none specified - * [[linkTemplate]] will be used instead. - * - options: array, optional, the HTML attributes of the header. - * - headerOptions: array, optional, the HTML attributes for the header container tag. - */ - public $items = []; - /** - * @var array list of HTML attributes for the item container tags. This will be overwritten - * by the "options" set in individual [[items]]. The following special options are recognized: - * - * - tag: string, defaults to "div", the tag name of the item container tags. - */ - public $itemOptions = []; - /** - * @var array list of HTML attributes for the header container tags. This will be overwritten - * by the "headerOptions" set in individual [[items]]. - */ - public $headerOptions = []; - /** - * @var string the default header template to render the link. - */ - public $linkTemplate = '{label}'; - /** - * @var boolean whether the labels for header items should be HTML-encoded. - */ - public $encodeLabels = true; - - - /** - * Renders the widget. - */ - public function run() - { - $options = $this->options; - $tag = ArrayHelper::remove($options, 'tag', 'div'); - echo Html::beginTag($tag, $options) . "\n"; - echo $this->renderItems() . "\n"; - echo Html::endTag($tag) . "\n"; - $this->registerWidget('tabs', TabsAsset::className()); - } - - /** - * Renders tab items as specified on [[items]]. - * @return string the rendering result. - * @throws InvalidConfigException. - */ - protected function renderItems() - { - $headers = []; - $items = []; - foreach ($this->items as $n => $item) { - if (!isset($item['label'])) { - throw new InvalidConfigException("The 'label' option is required."); - } - if (isset($item['url'])) { - $url = Html::url($item['url']); - } else { - if (!isset($item['content'])) { - throw new InvalidConfigException("The 'content' or 'url' option is required."); - } - $options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', [])); - $tag = ArrayHelper::remove($options, 'tag', 'div'); - if (!isset($options['id'])) { - $options['id'] = $this->options['id'] . '-tab' . $n; - } - $url = '#' . $options['id']; - $items[] = Html::tag($tag, $item['content'], $options); - } - $headerOptions = array_merge($this->headerOptions, ArrayHelper::getValue($item, 'headerOptions', [])); - $template = ArrayHelper::getValue($item, 'template', $this->linkTemplate); - $headers[] = Html::tag('li', strtr($template, [ - '{label}' => $this->encodeLabels ? Html::encode($item['label']) : $item['label'], - '{url}' => $url, - ]), $headerOptions); - } - return Html::tag('ul', implode("\n", $headers)) . "\n" . implode("\n", $items); - } -} diff --git a/extensions/jui/TabsAsset.php b/extensions/jui/TabsAsset.php deleted file mode 100644 index 5bef4c0..0000000 --- a/extensions/jui/TabsAsset.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class TabsAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.tabs.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - 'yii\jui\EffectAsset', - ]; -} diff --git a/extensions/jui/ThemeAsset.php b/extensions/jui/ThemeAsset.php deleted file mode 100644 index dedcb00..0000000 --- a/extensions/jui/ThemeAsset.php +++ /dev/null @@ -1,21 +0,0 @@ - - * @since 2.0 - */ -class ThemeAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $css = [ - 'theme/jquery.ui.css', - ]; -} diff --git a/extensions/jui/TooltipAsset.php b/extensions/jui/TooltipAsset.php deleted file mode 100644 index 1fa4490..0000000 --- a/extensions/jui/TooltipAsset.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class TooltipAsset extends AssetBundle -{ - public $sourcePath = '@yii/jui/assets'; - public $js = [ - 'jquery.ui.tooltip.js', - ]; - public $depends = [ - 'yii\jui\CoreAsset', - 'yii\jui\EffectAsset', - ]; -} diff --git a/extensions/jui/Widget.php b/extensions/jui/Widget.php deleted file mode 100644 index ced00fb..0000000 --- a/extensions/jui/Widget.php +++ /dev/null @@ -1,122 +0,0 @@ - - * @since 2.0 - */ -class Widget extends \yii\base\Widget -{ - /** - * @var string the jQuery UI theme. This refers to an asset bundle class - * representing the JUI theme. The default theme is the official "Smoothness" theme. - */ - public static $theme = 'yii\jui\ThemeAsset'; - /** - * @var array the HTML attributes for the widget container tag. - */ - public $options = []; - /** - * @var array the options for the underlying jQuery UI widget. - * Please refer to the corresponding jQuery UI widget Web page for possible options. - * For example, [this page](http://api.jqueryui.com/accordion/) shows - * how to use the "Accordion" widget and the supported options (e.g. "header"). - */ - public $clientOptions = []; - /** - * @var array the event handlers for the underlying jQuery UI widget. - * Please refer to the corresponding jQuery UI widget Web page for possible events. - * For example, [this page](http://api.jqueryui.com/accordion/) shows - * how to use the "Accordion" widget and the supported events (e.g. "create"). - */ - public $clientEvents = []; - - /** - * @var array event names mapped to what should be specified in .on( - * If empty, it is assumed that event passed to clientEvents is prefixed with widget name. - */ - protected $clientEventsMap = []; - - /** - * Initializes the widget. - * If you override this method, make sure you call the parent implementation first. - */ - public function init() - { - parent::init(); - if (!isset($this->options['id'])) { - $this->options['id'] = $this->getId(); - } - } - - /** - * Registers a specific jQuery UI widget assets - * @param string $assetBundle the asset bundle for the widget - */ - protected function registerAssets($assetBundle) - { - /** @var \yii\web\AssetBundle $assetBundle */ - $assetBundle::register($this->getView()); - /** @var \yii\web\AssetBundle $themeAsset */ - $themeAsset = static::$theme; - $themeAsset::register($this->getView()); - } - - /** - * Registers a specific jQuery UI widget options - * @param string $name the name of the jQuery UI widget - */ - protected function registerClientOptions($name) - { - if ($this->clientOptions !== false) { - $id = $this->options['id']; - $options = empty($this->clientOptions) ? '' : Json::encode($this->clientOptions); - $js = "jQuery('#$id').$name($options);"; - $this->getView()->registerJs($js); - } - } - - /** - * Registers a specific jQuery UI widget events - * @param string $name the name of the jQuery UI widget - */ - protected function registerClientEvents($name) - { - if (!empty($this->clientEvents)) { - $id = $this->options['id']; - $js = []; - foreach ($this->clientEvents as $event => $handler) { - if (isset($this->clientEventsMap[$event])) { - $eventName = $this->clientEventsMap[$event]; - } else { - $eventName = $name.$event; - } - $js[] = "jQuery('#$id').on('$eventName', $handler);"; - } - $this->getView()->registerJs(implode("\n", $js)); - } - } - - /** - * Registers a specific jQuery UI widget asset bundle, initializes it with client options and registers related events - * @param string $name the name of the jQuery UI widget - * @param string $assetBundle the asset bundle for the widget - */ - protected function registerWidget($name, $assetBundle) - { - $this->registerAssets($assetBundle); - $this->registerClientOptions($name); - $this->registerClientEvents($name); - } -} diff --git a/extensions/jui/assets/UPGRADE.md b/extensions/jui/assets/UPGRADE.md deleted file mode 100644 index 5cd32d2..0000000 --- a/extensions/jui/assets/UPGRADE.md +++ /dev/null @@ -1,14 +0,0 @@ -How to Upgrade JQuery UI -======================== - -To upgrade JQuery UI, use [JUI Download Builder](http://jqueryui.com/download/) and toggle all options. -Choose the `Smoothness` theme, download and unpack. - -The following files are needed: - -* UI Core: all JS files -* Interactions: all JS files -* Widgets: all JS files -* DatePicker I18N: only the combined file is needed, and it should be renamed as `jquery.ui.datepicker-i18n.js` -* Effects: only the combined file is needed, and it should be renamed as `jquery.ui.effect-all.js` -* Theme: Only the combined CSS file and the image files are needed. Rename the CSS file as `jquery.ui.css`. diff --git a/extensions/jui/assets/jquery.ui.accordion.js b/extensions/jui/assets/jquery.ui.accordion.js deleted file mode 100644 index bdd2d53..0000000 --- a/extensions/jui/assets/jquery.ui.accordion.js +++ /dev/null @@ -1,572 +0,0 @@ -/*! - * jQuery UI Accordion 1.10.3 - * http://jqueryui.com - * - * Copyright 2013 jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * http://api.jqueryui.com/accordion/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -var uid = 0, - hideProps = {}, - showProps = {}; - -hideProps.height = hideProps.paddingTop = hideProps.paddingBottom = - hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide"; -showProps.height = showProps.paddingTop = showProps.paddingBottom = - showProps.borderTopWidth = showProps.borderBottomWidth = "show"; - -$.widget( "ui.accordion", { - version: "1.10.3", - options: { - active: 0, - animate: {}, - collapsible: false, - event: "click", - header: "> li > :first-child,> :not(li):even", - heightStyle: "auto", - icons: { - activeHeader: "ui-icon-triangle-1-s", - header: "ui-icon-triangle-1-e" - }, - - // callbacks - activate: null, - beforeActivate: null - }, - - _create: function() { - var options = this.options; - this.prevShow = this.prevHide = $(); - this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ) - // ARIA - .attr( "role", "tablist" ); - - // don't allow collapsible: false and active: false / null - if ( !options.collapsible && (options.active === false || options.active == null) ) { - options.active = 0; - } - - this._processPanels(); - // handle negative values - if ( options.active < 0 ) { - options.active += this.headers.length; - } - this._refresh(); - }, - - _getCreateEventData: function() { - return { - header: this.active, - panel: !this.active.length ? $() : this.active.next(), - content: !this.active.length ? $() : this.active.next() - }; - }, - - _createIcons: function() { - var icons = this.options.icons; - if ( icons ) { - $( "" ) - .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) - .prependTo( this.headers ); - this.active.children( ".ui-accordion-header-icon" ) - .removeClass( icons.header ) - .addClass( icons.activeHeader ); - this.headers.addClass( "ui-accordion-icons" ); - } - }, - - _destroyIcons: function() { - this.headers - .removeClass( "ui-accordion-icons" ) - .children( ".ui-accordion-header-icon" ) - .remove(); - }, - - _destroy: function() { - var contents; - - // clean up main element - this.element - .removeClass( "ui-accordion ui-widget ui-helper-reset" ) - .removeAttr( "role" ); - - // clean up headers - this.headers - .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) - .removeAttr( "role" ) - .removeAttr( "aria-selected" ) - .removeAttr( "aria-controls" ) - .removeAttr( "tabIndex" ) - .each(function() { - if ( /^ui-accordion/.test( this.id ) ) { - this.removeAttribute( "id" ); - } - }); - this._destroyIcons(); - - // clean up content panels - contents = this.headers.next() - .css( "display", "" ) - .removeAttr( "role" ) - .removeAttr( "aria-expanded" ) - .removeAttr( "aria-hidden" ) - .removeAttr( "aria-labelledby" ) - .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" ) - .each(function() { - if ( /^ui-accordion/.test( this.id ) ) { - this.removeAttribute( "id" ); - } - }); - if ( this.options.heightStyle !== "content" ) { - contents.css( "height", "" ); - } - }, - - _setOption: function( key, value ) { - if ( key === "active" ) { - // _activate() will handle invalid values and update this.options - this._activate( value ); - return; - } - - if ( key === "event" ) { - if ( this.options.event ) { - this._off( this.headers, this.options.event ); - } - this._setupEvents( value ); - } - - this._super( key, value ); - - // setting collapsible: false while collapsed; open first panel - if ( key === "collapsible" && !value && this.options.active === false ) { - this._activate( 0 ); - } - - if ( key === "icons" ) { - this._destroyIcons(); - if ( value ) { - this._createIcons(); - } - } - - // #5332 - opacity doesn't cascade to positioned elements in IE - // so we need to add the disabled class to the headers and panels - if ( key === "disabled" ) { - this.headers.add( this.headers.next() ) - .toggleClass( "ui-state-disabled", !!value ); - } - }, - - _keydown: function( event ) { - /*jshint maxcomplexity:15*/ - if ( event.altKey || event.ctrlKey ) { - return; - } - - var keyCode = $.ui.keyCode, - length = this.headers.length, - currentIndex = this.headers.index( event.target ), - toFocus = false; - - switch ( event.keyCode ) { - case keyCode.RIGHT: - case keyCode.DOWN: - toFocus = this.headers[ ( currentIndex + 1 ) % length ]; - break; - case keyCode.LEFT: - case keyCode.UP: - toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; - break; - case keyCode.SPACE: - case keyCode.ENTER: - this._eventHandler( event ); - break; - case keyCode.HOME: - toFocus = this.headers[ 0 ]; - break; - case keyCode.END: - toFocus = this.headers[ length - 1 ]; - break; - } - - if ( toFocus ) { - $( event.target ).attr( "tabIndex", -1 ); - $( toFocus ).attr( "tabIndex", 0 ); - toFocus.focus(); - event.preventDefault(); - } - }, - - _panelKeyDown : function( event ) { - if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { - $( event.currentTarget ).prev().focus(); - } - }, - - refresh: function() { - var options = this.options; - this._processPanels(); - - // was collapsed or no panel - if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { - options.active = false; - this.active = $(); - // active false only when collapsible is true - } else if ( options.active === false ) { - this._activate( 0 ); - // was active, but active panel is gone - } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { - // all remaining panel are disabled - if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) { - options.active = false; - this.active = $(); - // activate previous panel - } else { - this._activate( Math.max( 0, options.active - 1 ) ); - } - // was active, active panel still exists - } else { - // make sure active index is correct - options.active = this.headers.index( this.active ); - } - - this._destroyIcons(); - - this._refresh(); - }, - - _processPanels: function() { - this.headers = this.element.find( this.options.header ) - .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ); - - this.headers.next() - .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) - .filter(":not(.ui-accordion-content-active)") - .hide(); - }, - - _refresh: function() { - var maxHeight, - options = this.options, - heightStyle = options.heightStyle, - parent = this.element.parent(), - accordionId = this.accordionId = "ui-accordion-" + - (this.element.attr( "id" ) || ++uid); - - this.active = this._findActive( options.active ) - .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ) - .removeClass( "ui-corner-all" ); - this.active.next() - .addClass( "ui-accordion-content-active" ) - .show(); - - this.headers - .attr( "role", "tab" ) - .each(function( i ) { - var header = $( this ), - headerId = header.attr( "id" ), - panel = header.next(), - panelId = panel.attr( "id" ); - if ( !headerId ) { - headerId = accordionId + "-header-" + i; - header.attr( "id", headerId ); - } - if ( !panelId ) { - panelId = accordionId + "-panel-" + i; - panel.attr( "id", panelId ); - } - header.attr( "aria-controls", panelId ); - panel.attr( "aria-labelledby", headerId ); - }) - .next() - .attr( "role", "tabpanel" ); - - this.headers - .not( this.active ) - .attr({ - "aria-selected": "false", - tabIndex: -1 - }) - .next() - .attr({ - "aria-expanded": "false", - "aria-hidden": "true" - }) - .hide(); - - // make sure at least one header is in the tab order - if ( !this.active.length ) { - this.headers.eq( 0 ).attr( "tabIndex", 0 ); - } else { - this.active.attr({ - "aria-selected": "true", - tabIndex: 0 - }) - .next() - .attr({ - "aria-expanded": "true", - "aria-hidden": "false" - }); - } - - this._createIcons(); - - this._setupEvents( options.event ); - - if ( heightStyle === "fill" ) { - maxHeight = parent.height(); - this.element.siblings( ":visible" ).each(function() { - var elem = $( this ), - position = elem.css( "position" ); - - if ( position === "absolute" || position === "fixed" ) { - return; - } - maxHeight -= elem.outerHeight( true ); - }); - - this.headers.each(function() { - maxHeight -= $( this ).outerHeight( true ); - }); - - this.headers.next() - .each(function() { - $( this ).height( Math.max( 0, maxHeight - - $( this ).innerHeight() + $( this ).height() ) ); - }) - .css( "overflow", "auto" ); - } else if ( heightStyle === "auto" ) { - maxHeight = 0; - this.headers.next() - .each(function() { - maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); - }) - .height( maxHeight ); - } - }, - - _activate: function( index ) { - var active = this._findActive( index )[ 0 ]; - - // trying to activate the already active panel - if ( active === this.active[ 0 ] ) { - return; - } - - // trying to collapse, simulate a click on the currently active header - active = active || this.active[ 0 ]; - - this._eventHandler({ - target: active, - currentTarget: active, - preventDefault: $.noop - }); - }, - - _findActive: function( selector ) { - return typeof selector === "number" ? this.headers.eq( selector ) : $(); - }, - - _setupEvents: function( event ) { - var events = { - keydown: "_keydown" - }; - if ( event ) { - $.each( event.split(" "), function( index, eventName ) { - events[ eventName ] = "_eventHandler"; - }); - } - - this._off( this.headers.add( this.headers.next() ) ); - this._on( this.headers, events ); - this._on( this.headers.next(), { keydown: "_panelKeyDown" }); - this._hoverable( this.headers ); - this._focusable( this.headers ); - }, - - _eventHandler: function( event ) { - var options = this.options, - active = this.active, - clicked = $( event.currentTarget ), - clickedIsActive = clicked[ 0 ] === active[ 0 ], - collapsing = clickedIsActive && options.collapsible, - toShow = collapsing ? $() : clicked.next(), - toHide = active.next(), - eventData = { - oldHeader: active, - oldPanel: toHide, - newHeader: collapsing ? $() : clicked, - newPanel: toShow - }; - - event.preventDefault(); - - if ( - // click on active header, but not collapsible - ( clickedIsActive && !options.collapsible ) || - // allow canceling activation - ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { - return; - } - - options.active = collapsing ? false : this.headers.index( clicked ); - - // when the call to ._toggle() comes after the class changes - // it causes a very odd bug in IE 8 (see #6720) - this.active = clickedIsActive ? $() : clicked; - this._toggle( eventData ); - - // switch classes - // corner classes on the previously active header stay after the animation - active.removeClass( "ui-accordion-header-active ui-state-active" ); - if ( options.icons ) { - active.children( ".ui-accordion-header-icon" ) - .removeClass( options.icons.activeHeader ) - .addClass( options.icons.header ); - } - - if ( !clickedIsActive ) { - clicked - .removeClass( "ui-corner-all" ) - .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); - if ( options.icons ) { - clicked.children( ".ui-accordion-header-icon" ) - .removeClass( options.icons.header ) - .addClass( options.icons.activeHeader ); - } - - clicked - .next() - .addClass( "ui-accordion-content-active" ); - } - }, - - _toggle: function( data ) { - var toShow = data.newPanel, - toHide = this.prevShow.length ? this.prevShow : data.oldPanel; - - // handle activating a panel during the animation for another activation - this.prevShow.add( this.prevHide ).stop( true, true ); - this.prevShow = toShow; - this.prevHide = toHide; - - if ( this.options.animate ) { - this._animate( toShow, toHide, data ); - } else { - toHide.hide(); - toShow.show(); - this._toggleComplete( data ); - } - - toHide.attr({ - "aria-expanded": "false", - "aria-hidden": "true" - }); - toHide.prev().attr( "aria-selected", "false" ); - // if we're switching panels, remove the old header from the tab order - // if we're opening from collapsed state, remove the previous header from the tab order - // if we're collapsing, then keep the collapsing header in the tab order - if ( toShow.length && toHide.length ) { - toHide.prev().attr( "tabIndex", -1 ); - } else if ( toShow.length ) { - this.headers.filter(function() { - return $( this ).attr( "tabIndex" ) === 0; - }) - .attr( "tabIndex", -1 ); - } - - toShow - .attr({ - "aria-expanded": "true", - "aria-hidden": "false" - }) - .prev() - .attr({ - "aria-selected": "true", - tabIndex: 0 - }); - }, - - _animate: function( toShow, toHide, data ) { - var total, easing, duration, - that = this, - adjust = 0, - down = toShow.length && - ( !toHide.length || ( toShow.index() < toHide.index() ) ), - animate = this.options.animate || {}, - options = down && animate.down || animate, - complete = function() { - that._toggleComplete( data ); - }; - - if ( typeof options === "number" ) { - duration = options; - } - if ( typeof options === "string" ) { - easing = options; - } - // fall back from options to animation in case of partial down settings - easing = easing || options.easing || animate.easing; - duration = duration || options.duration || animate.duration; - - if ( !toHide.length ) { - return toShow.animate( showProps, duration, easing, complete ); - } - if ( !toShow.length ) { - return toHide.animate( hideProps, duration, easing, complete ); - } - - total = toShow.show().outerHeight(); - toHide.animate( hideProps, { - duration: duration, - easing: easing, - step: function( now, fx ) { - fx.now = Math.round( now ); - } - }); - toShow - .hide() - .animate( showProps, { - duration: duration, - easing: easing, - complete: complete, - step: function( now, fx ) { - fx.now = Math.round( now ); - if ( fx.prop !== "height" ) { - adjust += fx.now; - } else if ( that.options.heightStyle !== "content" ) { - fx.now = Math.round( total - toHide.outerHeight() - adjust ); - adjust = 0; - } - } - }); - }, - - _toggleComplete: function( data ) { - var toHide = data.oldPanel; - - toHide - .removeClass( "ui-accordion-content-active" ) - .prev() - .removeClass( "ui-corner-top" ) - .addClass( "ui-corner-all" ); - - // Work around for rendering bug in IE (#5421) - if ( toHide.length ) { - toHide.parent()[0].className = toHide.parent()[0].className; - } - - this._trigger( "activate", null, data ); - } -}); - -})( jQuery ); diff --git a/extensions/jui/assets/jquery.ui.autocomplete.js b/extensions/jui/assets/jquery.ui.autocomplete.js deleted file mode 100644 index ca53d2c..0000000 --- a/extensions/jui/assets/jquery.ui.autocomplete.js +++ /dev/null @@ -1,610 +0,0 @@ -/*! - * jQuery UI Autocomplete 1.10.3 - * http://jqueryui.com - * - * Copyright 2013 jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * http://api.jqueryui.com/autocomplete/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.position.js - * jquery.ui.menu.js - */ -(function( $, undefined ) { - -// used to prevent race conditions with remote data sources -var requestIndex = 0; - -$.widget( "ui.autocomplete", { - version: "1.10.3", - defaultElement: "", - options: { - appendTo: null, - autoFocus: false, - delay: 300, - minLength: 1, - position: { - my: "left top", - at: "left bottom", - collision: "none" - }, - source: null, - - // callbacks - change: null, - close: null, - focus: null, - open: null, - response: null, - search: null, - select: null - }, - - pending: 0, - - _create: function() { - // Some browsers only repeat keydown events, not keypress events, - // so we use the suppressKeyPress flag to determine if we've already - // handled the keydown event. #7269 - // Unfortunately the code for & in keypress is the same as the up arrow, - // so we use the suppressKeyPressRepeat flag to avoid handling keypress - // events when we know the keydown event was used to modify the - // search term. #7799 - var suppressKeyPress, suppressKeyPressRepeat, suppressInput, - nodeName = this.element[0].nodeName.toLowerCase(), - isTextarea = nodeName === "textarea", - isInput = nodeName === "input"; - - this.isMultiLine = - // Textareas are always multi-line - isTextarea ? true : - // Inputs are always single-line, even if inside a contentEditable element - // IE also treats inputs as contentEditable - isInput ? false : - // All other element types are determined by whether or not they're contentEditable - this.element.prop( "isContentEditable" ); - - this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; - this.isNewMenu = true; - - this.element - .addClass( "ui-autocomplete-input" ) - .attr( "autocomplete", "off" ); - - this._on( this.element, { - keydown: function( event ) { - /*jshint maxcomplexity:15*/ - if ( this.element.prop( "readOnly" ) ) { - suppressKeyPress = true; - suppressInput = true; - suppressKeyPressRepeat = true; - return; - } - - suppressKeyPress = false; - suppressInput = false; - suppressKeyPressRepeat = false; - var keyCode = $.ui.keyCode; - switch( event.keyCode ) { - case keyCode.PAGE_UP: - suppressKeyPress = true; - this._move( "previousPage", event ); - break; - case keyCode.PAGE_DOWN: - suppressKeyPress = true; - this._move( "nextPage", event ); - break; - case keyCode.UP: - suppressKeyPress = true; - this._keyEvent( "previous", event ); - break; - case keyCode.DOWN: - suppressKeyPress = true; - this._keyEvent( "next", event ); - break; - case keyCode.ENTER: - case keyCode.NUMPAD_ENTER: - // when menu is open and has focus - if ( this.menu.active ) { - // #6055 - Opera still allows the keypress to occur - // which causes forms to submit - suppressKeyPress = true; - event.preventDefault(); - this.menu.select( event ); - } - break; - case keyCode.TAB: - if ( this.menu.active ) { - this.menu.select( event ); - } - break; - case keyCode.ESCAPE: - if ( this.menu.element.is( ":visible" ) ) { - this._value( this.term ); - this.close( event ); - // Different browsers have different default behavior for escape - // Single press can mean undo or clear - // Double press in IE means clear the whole form - event.preventDefault(); - } - break; - default: - suppressKeyPressRepeat = true; - // search timeout should be triggered before the input value is changed - this._searchTimeout( event ); - break; - } - }, - keypress: function( event ) { - if ( suppressKeyPress ) { - suppressKeyPress = false; - if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { - event.preventDefault(); - } - return; - } - if ( suppressKeyPressRepeat ) { - return; - } - - // replicate some key handlers to allow them to repeat in Firefox and Opera - var keyCode = $.ui.keyCode; - switch( event.keyCode ) { - case keyCode.PAGE_UP: - this._move( "previousPage", event ); - break; - case keyCode.PAGE_DOWN: - this._move( "nextPage", event ); - break; - case keyCode.UP: - this._keyEvent( "previous", event ); - break; - case keyCode.DOWN: - this._keyEvent( "next", event ); - break; - } - }, - input: function( event ) { - if ( suppressInput ) { - suppressInput = false; - event.preventDefault(); - return; - } - this._searchTimeout( event ); - }, - focus: function() { - this.selectedItem = null; - this.previous = this._value(); - }, - blur: function( event ) { - if ( this.cancelBlur ) { - delete this.cancelBlur; - return; - } - - clearTimeout( this.searching ); - this.close( event ); - this._change( event ); - } - }); - - this._initSource(); - this.menu = $( "