From d0d1e79c041618488cc8c003cc95c99cac382888 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Fri, 10 Jan 2014 21:06:25 -0500 Subject: [PATCH] psr-4 change. --- .coveralls.yml | 4 - .gitattributes | 23 - .gitignore | 29 - .travis.yml | 41 - Alert.php | 149 + BootstrapAsset.php | 22 + BootstrapPluginAsset.php | 27 + BootstrapThemeAsset.php | 27 + Button.php | 62 + ButtonDropdown.php | 119 + ButtonGroup.php | 97 + CHANGELOG.md | 16 + Carousel.php | 170 + Collapse.php | 135 + Dropdown.php | 92 + LICENSE.md | 32 - Modal.php | 227 + Nav.php | 214 + NavBar.php | 122 + Progress.php | 161 + README.md | 78 +- Tabs.php | 199 + Widget.php | 81 + apps/advanced/.gitignore | 1 - apps/advanced/LICENSE.md | 32 - apps/advanced/README.md | 89 - apps/advanced/backend/assets/AppAsset.php | 26 - apps/advanced/backend/config/.gitignore | 2 - apps/advanced/backend/config/main.php | 41 - apps/advanced/backend/config/params.php | 4 - .../backend/controllers/SiteController.php | 66 - apps/advanced/backend/models/.gitkeep | 1 - apps/advanced/backend/runtime/.gitignore | 2 - apps/advanced/backend/views/layouts/main.php | 65 - apps/advanced/backend/views/site/error.php | 29 - apps/advanced/backend/views/site/index.php | 53 - apps/advanced/backend/views/site/login.php | 30 - apps/advanced/backend/web/.gitignore | 1 - apps/advanced/backend/web/assets/.gitignore | 2 - apps/advanced/backend/web/css/site.css | 79 - apps/advanced/backend/web/favicon.ico | Bin 1150 -> 0 bytes apps/advanced/backend/web/robots.txt | 2 - apps/advanced/common/config/.gitignore | 1 - apps/advanced/common/config/params.php | 20 - apps/advanced/common/mails/layouts/html.php | 24 - apps/advanced/common/mails/passwordResetToken.php | 16 - apps/advanced/common/models/LoginForm.php | 71 - apps/advanced/common/models/User.php | 150 - apps/advanced/composer.json | 46 - apps/advanced/console/config/.gitignore | 2 - apps/advanced/console/config/main.php | 33 - apps/advanced/console/config/params.php | 4 - apps/advanced/console/controllers/.gitkeep | 0 .../console/migrations/m130524_201442_init.php | 33 - apps/advanced/console/models/.gitkeep | 1 - apps/advanced/console/runtime/.gitignore | 2 - .../environments/dev/backend/config/main-local.php | 10 - .../dev/backend/config/params-local.php | 3 - .../environments/dev/backend/web/index.php | 14 - .../dev/common/config/params-local.php | 10 - .../environments/dev/console/config/main-local.php | 3 - .../dev/console/config/params-local.php | 3 - .../dev/frontend/config/main-local.php | 10 - .../dev/frontend/config/params-local.php | 3 - .../environments/dev/frontend/web/index.php | 14 - apps/advanced/environments/dev/yii | 27 - apps/advanced/environments/index.php | 38 - .../prod/backend/config/main-local.php | 3 - .../prod/backend/config/params-local.php | 3 - .../environments/prod/backend/web/index.php | 14 - .../prod/common/config/params-local.php | 10 - .../prod/console/config/main-local.php | 3 - .../prod/console/config/params-local.php | 3 - .../prod/frontend/config/main-local.php | 3 - .../prod/frontend/config/params-local.php | 3 - .../environments/prod/frontend/web/index.php | 14 - apps/advanced/environments/prod/yii | 27 - apps/advanced/frontend/assets/AppAsset.php | 29 - apps/advanced/frontend/config/.gitignore | 2 - apps/advanced/frontend/config/main.php | 39 - apps/advanced/frontend/config/params.php | 4 - .../frontend/controllers/SiteController.php | 171 - apps/advanced/frontend/models/ContactForm.php | 63 - apps/advanced/frontend/runtime/.gitignore | 2 - apps/advanced/frontend/views/layouts/main.php | 70 - apps/advanced/frontend/views/site/about.php | 16 - apps/advanced/frontend/views/site/contact.php | 38 - apps/advanced/frontend/views/site/error.php | 29 - apps/advanced/frontend/views/site/index.php | 53 - apps/advanced/frontend/views/site/login.php | 33 - .../views/site/requestPasswordResetToken.php | 28 - .../advanced/frontend/views/site/resetPassword.php | 28 - apps/advanced/frontend/views/site/signup.php | 30 - apps/advanced/frontend/web/.gitignore | 1 - apps/advanced/frontend/web/assets/.gitignore | 2 - apps/advanced/frontend/web/css/site.css | 79 - apps/advanced/frontend/web/favicon.ico | Bin 1150 -> 0 bytes apps/advanced/frontend/web/robots.txt | 2 - apps/advanced/frontend/widgets/Alert.php | 66 - apps/advanced/init | 154 - apps/advanced/init.bat | 20 - apps/advanced/requirements.php | 110 - apps/advanced/vendor/.gitignore | 2 - apps/advanced/yii.bat | 20 - apps/basic/LICENSE.md | 32 - apps/basic/README.md | 64 - apps/basic/assets/AppAsset.php | 29 - apps/basic/codeception.yml | 18 - apps/basic/commands/HelloController.php | 30 - apps/basic/composer.json | 46 - apps/basic/config/console.php | 34 - apps/basic/config/db.php | 9 - apps/basic/config/params.php | 5 - apps/basic/config/web.php | 45 - apps/basic/controllers/SiteController.php | 94 - apps/basic/mails/layouts/html.php | 24 - apps/basic/models/ContactForm.php | 63 - apps/basic/models/LoginForm.php | 72 - apps/basic/models/User.php | 61 - apps/basic/requirements.php | 110 - apps/basic/runtime/.gitignore | 2 - apps/basic/tests/.gitignore | 4 - apps/basic/tests/README.md | 28 - apps/basic/tests/_bootstrap.php | 22 - apps/basic/tests/_config.php | 14 - apps/basic/tests/_data/dump.sql | 1 - apps/basic/tests/_helpers/CodeHelper.php | 7 - apps/basic/tests/_helpers/TestHelper.php | 7 - apps/basic/tests/_helpers/WebHelper.php | 7 - apps/basic/tests/_log/.gitignore | 2 - apps/basic/tests/_pages/AboutPage.php | 10 - apps/basic/tests/_pages/ContactPage.php | 22 - apps/basic/tests/_pages/LoginPage.php | 22 - apps/basic/tests/acceptance.suite.yml | 24 - apps/basic/tests/acceptance/AboutCept.php | 8 - apps/basic/tests/acceptance/ContactCept.php | 49 - apps/basic/tests/acceptance/HomeCept.php | 9 - apps/basic/tests/acceptance/LoginCept.php | 29 - apps/basic/tests/acceptance/_bootstrap.php | 3 - apps/basic/tests/acceptance/_config.php | 13 - apps/basic/tests/functional.suite.yml | 17 - apps/basic/tests/functional/AboutCept.php | 8 - apps/basic/tests/functional/ContactCept.php | 46 - apps/basic/tests/functional/HomeCept.php | 9 - apps/basic/tests/functional/LoginCept.php | 26 - apps/basic/tests/functional/_bootstrap.php | 3 - apps/basic/tests/functional/_config.php | 17 - apps/basic/tests/unit.suite.yml | 9 - apps/basic/tests/unit/_bootstrap.php | 3 - apps/basic/tests/unit/_config.php | 17 - apps/basic/tests/unit/fixtures/.gitkeep | 0 apps/basic/tests/unit/models/ContactFormTest.php | 59 - apps/basic/tests/unit/models/LoginFormTest.php | 62 - apps/basic/tests/unit/models/UserTest.php | 20 - apps/basic/tests/unit/templates/fixtures/.gitkeep | 0 apps/basic/vendor/.gitignore | 2 - apps/basic/views/layouts/main.php | 66 - apps/basic/views/site/about.php | 18 - apps/basic/views/site/contact.php | 47 - apps/basic/views/site/error.php | 29 - apps/basic/views/site/index.php | 53 - apps/basic/views/site/login.php | 47 - apps/basic/web/assets/.gitignore | 2 - apps/basic/web/css/site.css | 79 - apps/basic/web/favicon.ico | Bin 1150 -> 0 bytes apps/basic/web/index-test.php | 16 - apps/basic/web/index.php | 12 - apps/basic/web/robots.txt | 2 - apps/basic/yii | 23 - apps/basic/yii.bat | 20 - apps/benchmark/LICENSE.md | 32 - apps/benchmark/README.md | 58 - apps/benchmark/composer.json | 23 - apps/benchmark/index.php | 18 - apps/benchmark/protected/.htaccess | 1 - .../protected/controllers/SiteController.php | 15 - apps/benchmark/protected/vendor/.gitignore | 2 - build/.htaccess | 1 - build/build | 23 - build/build.bat | 23 - build/build.xml | 276 - build/controllers/ClassmapController.php | 88 - build/controllers/PhpDocController.php | 374 -- composer.json | 120 +- docs/api/base/Component.md | 80 - docs/api/base/Object.md | 61 - docs/api/db/ActiveRecord-find.md | 26 - docs/api/db/ActiveRecord.md | 451 -- docs/guide/README.md | 8 - docs/guide/active-record.md | 769 --- docs/guide/apps-advanced.md | 174 - docs/guide/apps-basic.md | 163 - docs/guide/apps-own.md | 4 - docs/guide/assets.md | 270 - docs/guide/authentication.md | 68 - docs/guide/authorization.md | 257 - docs/guide/basics.md | 120 - docs/guide/behaviors.md | 90 - docs/guide/bootstrap-widgets.md | 66 - docs/guide/caching.md | 216 - docs/guide/composer.md | 81 - docs/guide/configuration.md | 113 - docs/guide/console-fixture.md | 115 - docs/guide/console-migrate.md | 333 - docs/guide/console.md | 123 - docs/guide/controller.md | 276 - docs/guide/database-basics.md | 266 - docs/guide/error.md | 56 - docs/guide/events.md | 43 - docs/guide/extensions.md | 123 - docs/guide/form.md | 106 - docs/guide/gii.md | 143 - docs/guide/i18n.md | 281 - docs/guide/images/flow.png | Bin 27851 -> 0 bytes docs/guide/images/flow.vsd | Bin 87552 -> 0 bytes docs/guide/images/gii-entry.png | Bin 70592 -> 0 bytes docs/guide/images/gii-preview.png | Bin 41620 -> 0 bytes docs/guide/images/structure.png | Bin 6048 -> 0 bytes docs/guide/images/structure.vsd | Bin 80896 -> 0 bytes docs/guide/index.md | 86 - docs/guide/installation.md | 162 - docs/guide/logging.md | 90 - docs/guide/model.md | 289 - docs/guide/module-debug.md | 38 - docs/guide/mvc.md | 46 - docs/guide/overview.md | 43 - docs/guide/performance.md | 216 - docs/guide/query-builder.md | 255 - docs/guide/security.md | 87 - docs/guide/template.md | 132 - docs/guide/testing.md | 4 - docs/guide/theming.md | 4 - docs/guide/title.md | 8 - docs/guide/upgrade-from-v1.md | 525 -- docs/guide/url.md | 197 - docs/guide/validation.md | 204 - docs/guide/view.md | 385 -- docs/internals/ar.md | 32 - docs/internals/autoloader.md | 19 - docs/internals/base.md | 44 - docs/internals/database.md | 27 - docs/internals/errors_and_exceptions.md | 9 - docs/internals/exception_hierarchy.png | Bin 64306 -> 0 bytes docs/internals/exception_hierarchy.vsd | Bin 151040 -> 0 bytes docs/internals/getting-started.md | 32 - docs/internals/git-workflow.md | 175 - docs/internals/translations.md | 26 - docs/internals/versions.md | 35 - extensions/README.md | 12 - extensions/faker/CHANGELOG.md | 7 - extensions/faker/FixtureController.php | 368 -- extensions/faker/LICENSE.md | 32 - extensions/faker/README.md | 162 - extensions/faker/composer.json | 26 - extensions/twig/CHANGELOG.md | 12 - extensions/twig/LICENSE.md | 32 - extensions/twig/README.md | 44 - extensions/twig/TwigSimpleFileLoader.php | 74 - extensions/twig/ViewRenderer.php | 232 - extensions/twig/ViewRendererStaticClassProxy.php | 43 - extensions/twig/composer.json | 27 - extensions/yii/apidoc/.gitignore | 2 - extensions/yii/apidoc/CHANGELOG.md | 7 - extensions/yii/apidoc/LICENSE.md | 32 - extensions/yii/apidoc/README.md | 48 - extensions/yii/apidoc/apidoc | 49 - extensions/yii/apidoc/apidoc.bat | 20 - .../yii/apidoc/commands/RenderController.php | 144 - extensions/yii/apidoc/composer.json | 30 - extensions/yii/apidoc/helpers/Markdown.php | 80 - extensions/yii/apidoc/helpers/PrettyPrinter.php | 41 - extensions/yii/apidoc/models/BaseDoc.php | 105 - extensions/yii/apidoc/models/ClassDoc.php | 109 - extensions/yii/apidoc/models/ConstDoc.php | 35 - extensions/yii/apidoc/models/Context.php | 258 - extensions/yii/apidoc/models/EventDoc.php | 51 - extensions/yii/apidoc/models/FunctionDoc.php | 77 - extensions/yii/apidoc/models/InterfaceDoc.php | 42 - extensions/yii/apidoc/models/MethodDoc.php | 46 - extensions/yii/apidoc/models/ParamDoc.php | 54 - extensions/yii/apidoc/models/PropertyDoc.php | 78 - extensions/yii/apidoc/models/TraitDoc.php | 40 - extensions/yii/apidoc/models/TypeDoc.php | 186 - extensions/yii/apidoc/templates/BaseRenderer.php | 59 - extensions/yii/apidoc/templates/html/README.md | 4 - extensions/yii/apidoc/templates/html/Renderer.php | 353 - .../apidoc/templates/html/views/constSummary.php | 36 - .../apidoc/templates/html/views/eventDetails.php | 35 - .../apidoc/templates/html/views/eventSummary.php | 41 - .../apidoc/templates/html/views/methodDetails.php | 67 - .../apidoc/templates/html/views/methodSummary.php | 41 - .../templates/html/views/propertyDetails.php | 39 - .../templates/html/views/propertySummary.php | 42 - .../yii/apidoc/templates/html/views/seeAlso.php | 31 - .../yii/apidoc/templates/html/views/type.php | 102 - .../yii/apidoc/templates/offline/Renderer.php | 26 - .../templates/offline/assets/AssetBundle.php | 31 - .../apidoc/templates/offline/assets/css/api.css | 111 - .../apidoc/templates/offline/assets/css/style.css | 32 - .../yii/apidoc/templates/offline/views/index.php | 30 - .../yii/apidoc/templates/offline/views/offline.php | 71 - extensions/yii/authclient/AuthAction.php | 362 -- extensions/yii/authclient/BaseClient.php | 236 - extensions/yii/authclient/BaseOAuth.php | 510 -- extensions/yii/authclient/CHANGELOG.md | 7 - extensions/yii/authclient/ClientInterface.php | 57 - extensions/yii/authclient/Collection.php | 107 - extensions/yii/authclient/LICENSE.md | 32 - extensions/yii/authclient/OAuth1.php | 354 - extensions/yii/authclient/OAuth2.php | 184 - extensions/yii/authclient/OAuthToken.php | 191 - extensions/yii/authclient/OpenId.php | 928 --- extensions/yii/authclient/README.md | 298 - extensions/yii/authclient/clients/Facebook.php | 83 - extensions/yii/authclient/clients/GitHub.php | 93 - extensions/yii/authclient/clients/GoogleOAuth.php | 93 - extensions/yii/authclient/clients/GoogleOpenId.php | 90 - extensions/yii/authclient/clients/LinkedIn.php | 168 - extensions/yii/authclient/clients/Twitter.php | 91 - extensions/yii/authclient/clients/YandexOAuth.php | 91 - extensions/yii/authclient/clients/YandexOpenId.php | 86 - extensions/yii/authclient/composer.json | 28 - extensions/yii/authclient/signature/BaseMethod.php | 49 - extensions/yii/authclient/signature/HmacSha1.php | 47 - extensions/yii/authclient/signature/PlainText.php | 33 - extensions/yii/authclient/signature/RsaSha1.php | 168 - extensions/yii/authclient/views/redirect.php | 38 - extensions/yii/authclient/widgets/Choice.php | 239 - extensions/yii/authclient/widgets/ChoiceAsset.php | 30 - .../yii/authclient/widgets/assets/authchoice.css | 82 - .../yii/authclient/widgets/assets/authchoice.js | 68 - .../yii/authclient/widgets/assets/authchoice.png | Bin 14959 -> 0 bytes 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 | 119 - extensions/yii/bootstrap/ButtonGroup.php | 97 - extensions/yii/bootstrap/CHANGELOG.md | 16 - extensions/yii/bootstrap/Carousel.php | 170 - extensions/yii/bootstrap/Collapse.php | 135 - extensions/yii/bootstrap/Dropdown.php | 92 - extensions/yii/bootstrap/Modal.php | 227 - extensions/yii/bootstrap/Nav.php | 214 - extensions/yii/bootstrap/NavBar.php | 122 - extensions/yii/bootstrap/Progress.php | 161 - 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/codeception/BasePage.php | 73 - extensions/yii/codeception/CHANGELOG.md | 7 - extensions/yii/codeception/LICENSE.md | 32 - extensions/yii/codeception/README.md | 199 - extensions/yii/codeception/TestCase.php | 77 - extensions/yii/codeception/composer.json | 26 - extensions/yii/composer/CHANGELOG.md | 14 - extensions/yii/composer/Installer.php | 259 - 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/CHANGELOG.md | 14 - extensions/yii/debug/DebugAsset.php | 26 - extensions/yii/debug/LogTarget.php | 125 - extensions/yii/debug/Module.php | 124 - extensions/yii/debug/Panel.php | 91 - extensions/yii/debug/README.md | 46 - extensions/yii/debug/assets/bg.png | Bin 163 -> 0 bytes extensions/yii/debug/assets/main.css | 70 - extensions/yii/debug/assets/toolbar.css | 188 - extensions/yii/debug/assets/toolbar.js | 41 - extensions/yii/debug/components/search/Filter.php | 72 - .../yii/debug/components/search/matches/Base.php | 26 - .../yii/debug/components/search/matches/Exact.php | 36 - .../debug/components/search/matches/Greater.php | 27 - .../yii/debug/components/search/matches/Lower.php | 27 - .../components/search/matches/MatcherInterface.php | 25 - extensions/yii/debug/composer.json | 28 - .../yii/debug/controllers/DefaultController.php | 132 - extensions/yii/debug/models/search/Base.php | 37 - extensions/yii/debug/models/search/Db.php | 75 - extensions/yii/debug/models/search/Debug.php | 122 - extensions/yii/debug/models/search/Log.php | 79 - extensions/yii/debug/models/search/Profile.php | 75 - extensions/yii/debug/panels/ConfigPanel.php | 70 - extensions/yii/debug/panels/DbPanel.php | 138 - extensions/yii/debug/panels/LogPanel.php | 82 - extensions/yii/debug/panels/ProfilingPanel.php | 91 - extensions/yii/debug/panels/RequestPanel.php | 92 - extensions/yii/debug/views/default/index.php | 85 - .../debug/views/default/panels/config/detail.php | 38 - .../debug/views/default/panels/config/summary.php | 17 - .../debug/views/default/panels/config/table.php | 35 - .../yii/debug/views/default/panels/db/detail.php | 69 - .../yii/debug/views/default/panels/db/summary.php | 7 - .../yii/debug/views/default/panels/log/detail.php | 73 - .../yii/debug/views/default/panels/log/summary.php | 28 - .../debug/views/default/panels/profile/detail.php | 53 - .../debug/views/default/panels/profile/summary.php | 6 - .../debug/views/default/panels/request/detail.php | 35 - .../debug/views/default/panels/request/summary.php | 27 - .../debug/views/default/panels/request/table.php | 34 - extensions/yii/debug/views/default/toolbar.php | 39 - extensions/yii/debug/views/default/view.php | 78 - extensions/yii/debug/views/layouts/main.php | 25 - extensions/yii/elasticsearch/ActiveQuery.php | 221 - extensions/yii/elasticsearch/ActiveRecord.php | 532 -- extensions/yii/elasticsearch/ActiveRelation.php | 61 - extensions/yii/elasticsearch/CHANGELOG.md | 14 - 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 | 502 -- extensions/yii/elasticsearch/QueryBuilder.php | 311 - extensions/yii/elasticsearch/README-debug.png | Bin 107733 -> 0 bytes extensions/yii/elasticsearch/README.md | 190 - extensions/yii/elasticsearch/composer.json | 28 - extensions/yii/gii/CHANGELOG.md | 13 - 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 6677 -> 0 bytes extensions/yii/gii/assets/main.css | 219 - 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 | 82 - .../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 | 588 -- 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 | 54 - extensions/yii/imagine/BaseImage.php | 255 - extensions/yii/imagine/CHANGELOG.md | 7 - extensions/yii/imagine/Image.php | 29 - extensions/yii/imagine/LICENSE.md | 32 - extensions/yii/imagine/README.md | 45 - extensions/yii/imagine/composer.json | 30 - extensions/yii/jui/Accordion.php | 121 - extensions/yii/jui/AccordionAsset.php | 26 - extensions/yii/jui/AutoComplete.php | 65 - extensions/yii/jui/AutoCompleteAsset.php | 25 - extensions/yii/jui/ButtonAsset.php | 24 - extensions/yii/jui/CHANGELOG.md | 12 - extensions/yii/jui/CoreAsset.php | 27 - extensions/yii/jui/DatePicker.php | 124 - 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 | 62 - extensions/yii/jui/LICENSE.md | 32 - extensions/yii/jui/Menu.php | 77 - 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 | 92 - extensions/yii/jui/Sortable.php | 106 - extensions/yii/jui/SortableAsset.php | 24 - extensions/yii/jui/Spinner.php | 65 - 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 | 125 - 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 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/yii/jui/assets/theme/jquery.ui.css | 1177 ---- extensions/yii/jui/composer.json | 27 - extensions/yii/mongodb/ActiveQuery.php | 109 - extensions/yii/mongodb/ActiveRecord.php | 353 - extensions/yii/mongodb/ActiveRelation.php | 53 - extensions/yii/mongodb/CHANGELOG.md | 7 - extensions/yii/mongodb/Collection.php | 894 --- extensions/yii/mongodb/Connection.php | 256 - extensions/yii/mongodb/Database.php | 173 - extensions/yii/mongodb/Exception.php | 25 - extensions/yii/mongodb/LICENSE.md | 32 - extensions/yii/mongodb/Query.php | 346 - extensions/yii/mongodb/README.md | 111 - extensions/yii/mongodb/composer.json | 28 - extensions/yii/mongodb/file/ActiveQuery.php | 109 - extensions/yii/mongodb/file/ActiveRecord.php | 334 - extensions/yii/mongodb/file/ActiveRelation.php | 22 - extensions/yii/mongodb/file/Collection.php | 185 - extensions/yii/mongodb/file/Query.php | 75 - extensions/yii/redis/ActiveQuery.php | 388 -- extensions/yii/redis/ActiveRecord.php | 305 - extensions/yii/redis/ActiveRelation.php | 67 - extensions/yii/redis/CHANGELOG.md | 12 - extensions/yii/redis/Cache.php | 204 - extensions/yii/redis/Connection.php | 406 -- extensions/yii/redis/LICENSE.md | 32 - extensions/yii/redis/LuaScriptBuilder.php | 379 -- extensions/yii/redis/README.md | 184 - extensions/yii/redis/Session.php | 153 - extensions/yii/redis/composer.json | 27 - extensions/yii/smarty/CHANGELOG.md | 12 - extensions/yii/smarty/LICENSE.md | 32 - extensions/yii/smarty/README.md | 41 - extensions/yii/smarty/ViewRenderer.php | 98 - extensions/yii/smarty/composer.json | 28 - extensions/yii/sphinx/ActiveQuery.php | 204 - extensions/yii/sphinx/ActiveRecord.php | 659 -- extensions/yii/sphinx/ActiveRelation.php | 53 - extensions/yii/sphinx/CHANGELOG.md | 12 - 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 | 705 -- extensions/yii/sphinx/QueryBuilder.php | 916 --- extensions/yii/sphinx/README.md | 108 - extensions/yii/sphinx/Schema.php | 489 -- extensions/yii/sphinx/composer.json | 29 - extensions/yii/swiftmailer/CHANGELOG.md | 12 - extensions/yii/swiftmailer/LICENSE.md | 32 - extensions/yii/swiftmailer/Mailer.php | 220 - extensions/yii/swiftmailer/Message.php | 304 - extensions/yii/swiftmailer/README.md | 49 - extensions/yii/swiftmailer/composer.json | 28 - framework/CHANGELOG.md | 107 - framework/LICENSE.md | 32 - framework/README.md | 24 - framework/UPGRADE.md | 9 - framework/composer.json | 64 - framework/yii/.gitignore | 3 - framework/yii/.htaccess | 1 - framework/yii/BaseYii.php | 533 -- framework/yii/Yii.php | 26 - framework/yii/assets/jquery.maskedinput.js | 338 - framework/yii/assets/punycode/LICENSE-GPL.txt | 278 - framework/yii/assets/punycode/LICENSE-MIT.txt | 20 - framework/yii/assets/punycode/punycode.js | 502 -- framework/yii/assets/punycode/punycode.min.js | 2 - framework/yii/assets/yii.activeForm.js | 400 -- framework/yii/assets/yii.captcha.js | 72 - framework/yii/assets/yii.gridView.js | 139 - framework/yii/assets/yii.js | 245 - framework/yii/assets/yii.validation.js | 227 - framework/yii/base/Action.php | 89 - framework/yii/base/ActionEvent.php | 45 - framework/yii/base/ActionFilter.php | 99 - framework/yii/base/Application.php | 646 -- framework/yii/base/Arrayable.php | 23 - framework/yii/base/Behavior.php | 91 - framework/yii/base/Component.php | 581 -- framework/yii/base/Controller.php | 417 -- framework/yii/base/ErrorException.php | 108 - framework/yii/base/ErrorHandler.php | 331 - framework/yii/base/Event.php | 185 - framework/yii/base/Exception.php | 53 - framework/yii/base/Extension.php | 29 - framework/yii/base/Formatter.php | 384 -- framework/yii/base/InlineAction.php | 55 - framework/yii/base/InvalidCallException.php | 25 - framework/yii/base/InvalidConfigException.php | 25 - framework/yii/base/InvalidParamException.php | 25 - framework/yii/base/InvalidRouteException.php | 25 - framework/yii/base/MailEvent.php | 35 - framework/yii/base/Model.php | 858 --- framework/yii/base/ModelEvent.php | 25 - framework/yii/base/Module.php | 667 -- framework/yii/base/NotSupportedException.php | 25 - framework/yii/base/Object.php | 240 - framework/yii/base/Request.php | 82 - framework/yii/base/Response.php | 30 - framework/yii/base/Theme.php | 152 - framework/yii/base/UnknownClassException.php | 25 - framework/yii/base/UnknownMethodException.php | 25 - framework/yii/base/UnknownPropertyException.php | 25 - framework/yii/base/UserException.php | 19 - framework/yii/base/View.php | 461 -- framework/yii/base/ViewContextInterface.php | 26 - framework/yii/base/ViewEvent.php | 46 - framework/yii/base/ViewRenderer.php | 30 - framework/yii/base/Widget.php | 214 - framework/yii/behaviors/AutoTimestamp.php | 116 - framework/yii/caching/ApcCache.php | 133 - framework/yii/caching/Cache.php | 474 -- framework/yii/caching/ChainedDependency.php | 75 - framework/yii/caching/DbCache.php | 274 - framework/yii/caching/DbDependency.php | 66 - framework/yii/caching/Dependency.php | 99 - framework/yii/caching/DummyCache.php | 81 - framework/yii/caching/ExpressionDependency.php | 47 - framework/yii/caching/FileCache.php | 240 - framework/yii/caching/FileDependency.php | 42 - framework/yii/caching/GroupDependency.php | 73 - framework/yii/caching/MemCache.php | 265 - framework/yii/caching/MemCacheServer.php | 58 - framework/yii/caching/WinCache.php | 132 - framework/yii/caching/XCache.php | 104 - framework/yii/caching/ZendDataCache.php | 83 - framework/yii/captcha/Captcha.php | 138 - framework/yii/captcha/CaptchaAction.php | 341 - framework/yii/captcha/CaptchaAsset.php | 27 - framework/yii/captcha/CaptchaValidator.php | 107 - framework/yii/captcha/SpicyRice.md | 11 - framework/yii/captcha/SpicyRice.ttf | Bin 67244 -> 0 bytes framework/yii/classes.php | 253 - framework/yii/console/Application.php | 165 - framework/yii/console/Controller.php | 276 - framework/yii/console/Exception.php | 27 - framework/yii/console/Request.php | 77 - framework/yii/console/Response.php | 18 - .../yii/console/controllers/AssetController.php | 611 -- .../yii/console/controllers/CacheController.php | 67 - .../yii/console/controllers/FixtureController.php | 321 - .../yii/console/controllers/HelpController.php | 434 -- .../yii/console/controllers/MessageController.php | 241 - .../yii/console/controllers/MigrateController.php | 633 -- framework/yii/console/runtime/.gitignore | 1 - framework/yii/data/ActiveDataProvider.php | 182 - framework/yii/data/ArrayDataProvider.php | 131 - framework/yii/data/BaseDataProvider.php | 249 - framework/yii/data/DataProviderInterface.php | 70 - framework/yii/data/Pagination.php | 218 - framework/yii/data/Sort.php | 398 -- framework/yii/data/SqlDataProvider.php | 159 - framework/yii/db/ActiveQuery.php | 427 -- framework/yii/db/ActiveQueryInterface.php | 77 - framework/yii/db/ActiveQueryTrait.php | 228 - framework/yii/db/ActiveRecord.php | 534 -- framework/yii/db/ActiveRecordInterface.php | 310 - framework/yii/db/ActiveRelation.php | 135 - framework/yii/db/ActiveRelationInterface.php | 29 - framework/yii/db/ActiveRelationTrait.php | 257 - framework/yii/db/BaseActiveRecord.php | 1282 ---- framework/yii/db/ColumnSchema.php | 106 - framework/yii/db/Command.php | 756 --- framework/yii/db/Connection.php | 538 -- framework/yii/db/DataReader.php | 264 - framework/yii/db/Exception.php | 44 - framework/yii/db/Expression.php | 60 - framework/yii/db/Migration.php | 416 -- framework/yii/db/Query.php | 678 -- framework/yii/db/QueryBuilder.php | 1074 --- framework/yii/db/QueryInterface.php | 208 - framework/yii/db/QueryTrait.php | 211 - framework/yii/db/Schema.php | 424 -- framework/yii/db/StaleObjectException.php | 23 - framework/yii/db/TableSchema.php | 98 - framework/yii/db/Transaction.php | 106 - framework/yii/db/cubrid/QueryBuilder.php | 90 - framework/yii/db/cubrid/Schema.php | 265 - framework/yii/db/mssql/PDO.php | 61 - framework/yii/db/mssql/QueryBuilder.php | 123 - framework/yii/db/mssql/Schema.php | 353 - framework/yii/db/mssql/SqlsrvPDO.php | 33 - framework/yii/db/mssql/TableSchema.php | 23 - framework/yii/db/mysql/QueryBuilder.php | 163 - framework/yii/db/mysql/Schema.php | 291 - framework/yii/db/oci/QueryBuilder.php | 137 - framework/yii/db/oci/Schema.php | 275 - framework/yii/db/pgsql/QueryBuilder.php | 141 - framework/yii/db/pgsql/Schema.php | 407 -- framework/yii/db/sqlite/QueryBuilder.php | 275 - framework/yii/db/sqlite/Schema.php | 245 - framework/yii/grid/ActionColumn.php | 135 - framework/yii/grid/CheckboxColumn.php | 84 - framework/yii/grid/Column.php | 144 - framework/yii/grid/DataColumn.php | 151 - framework/yii/grid/GridView.php | 442 -- framework/yii/grid/GridViewAsset.php | 27 - framework/yii/grid/SerialColumn.php | 32 - framework/yii/helpers/ArrayHelper.php | 19 - framework/yii/helpers/BaseArrayHelper.php | 475 -- framework/yii/helpers/BaseConsole.php | 922 --- framework/yii/helpers/BaseFileHelper.php | 341 - framework/yii/helpers/BaseHtml.php | 1640 ----- framework/yii/helpers/BaseHtmlPurifier.php | 34 - framework/yii/helpers/BaseInflector.php | 491 -- framework/yii/helpers/BaseJson.php | 110 - framework/yii/helpers/BaseMarkdown.php | 44 - framework/yii/helpers/BaseSecurity.php | 354 - framework/yii/helpers/BaseStringHelper.php | 140 - framework/yii/helpers/BaseVarDumper.php | 126 - framework/yii/helpers/Console.php | 19 - framework/yii/helpers/FileHelper.php | 21 - framework/yii/helpers/Html.php | 18 - framework/yii/helpers/HtmlPurifier.php | 37 - framework/yii/helpers/Inflector.php | 18 - framework/yii/helpers/Json.php | 19 - framework/yii/helpers/Markdown.php | 35 - framework/yii/helpers/Security.php | 29 - framework/yii/helpers/StringHelper.php | 19 - framework/yii/helpers/VarDumper.php | 28 - framework/yii/helpers/mimeTypes.php | 187 - framework/yii/i18n/DbMessageSource.php | 158 - framework/yii/i18n/Formatter.php | 330 - framework/yii/i18n/GettextFile.php | 37 - framework/yii/i18n/GettextMessageSource.php | 85 - framework/yii/i18n/GettextMoFile.php | 271 - framework/yii/i18n/GettextPoFile.php | 97 - framework/yii/i18n/I18N.php | 185 - framework/yii/i18n/MessageFormatter.php | 396 -- framework/yii/i18n/MessageSource.php | 120 - framework/yii/i18n/MissingTranslationEvent.php | 33 - framework/yii/i18n/PhpMessageSource.php | 79 - framework/yii/log/DbTarget.php | 91 - framework/yii/log/EmailTarget.php | 81 - framework/yii/log/FileTarget.php | 127 - framework/yii/log/Logger.php | 355 - framework/yii/log/Target.php | 238 - framework/yii/mail/BaseMailer.php | 344 - framework/yii/mail/BaseMessage.php | 52 - framework/yii/mail/MailerInterface.php | 64 - framework/yii/mail/MessageInterface.php | 218 - framework/yii/messages/config.php | 45 - framework/yii/messages/da/yii.php | 81 - framework/yii/messages/de/yii.php | 81 - framework/yii/messages/es/yii.php | 81 - framework/yii/messages/it/yii.php | 105 - framework/yii/messages/ja/yii.php | 81 - framework/yii/messages/pl/yii.php | 81 - framework/yii/messages/pt-BR/yii.php | 81 - framework/yii/messages/ro/yii.php | 81 - framework/yii/messages/ru/yii.php | 81 - framework/yii/messages/zh_cn/yii.php | 81 - framework/yii/mutex/DbMutex.php | 41 - framework/yii/mutex/FileMutex.php | 104 - framework/yii/mutex/Mutex.php | 95 - framework/yii/mutex/MysqlMutex.php | 57 - framework/yii/rbac/Assignment.php | 55 - framework/yii/rbac/DbManager.php | 598 -- framework/yii/rbac/Item.php | 204 - framework/yii/rbac/Manager.php | 318 - framework/yii/rbac/PhpManager.php | 554 -- framework/yii/rbac/schema-mssql.sql | 44 - framework/yii/rbac/schema-mysql.sql | 44 - framework/yii/rbac/schema-oci.sql | 44 - framework/yii/rbac/schema-pgsql.sql | 45 - framework/yii/rbac/schema-sqlite.sql | 44 - .../yii/requirements/YiiRequirementChecker.php | 398 -- framework/yii/requirements/requirements.php | 50 - framework/yii/requirements/views/console/index.php | 36 - framework/yii/requirements/views/web/css.php | 6807 -------------------- framework/yii/requirements/views/web/index.php | 82 - framework/yii/test/DbFixtureManager.php | 218 - framework/yii/test/DbTestTrait.php | 113 - framework/yii/validators/BooleanValidator.php | 91 - framework/yii/validators/CompareValidator.php | 207 - framework/yii/validators/DateValidator.php | 73 - framework/yii/validators/DefaultValueValidator.php | 40 - framework/yii/validators/EmailValidator.php | 116 - framework/yii/validators/ExistValidator.php | 122 - framework/yii/validators/FileValidator.php | 249 - framework/yii/validators/FilterValidator.php | 66 - framework/yii/validators/ImageValidator.php | 190 - framework/yii/validators/InlineValidator.php | 84 - framework/yii/validators/NumberValidator.php | 153 - framework/yii/validators/PunycodeAsset.php | 23 - framework/yii/validators/RangeValidator.php | 87 - .../yii/validators/RegularExpressionValidator.php | 94 - framework/yii/validators/RequiredValidator.php | 111 - framework/yii/validators/SafeValidator.php | 24 - framework/yii/validators/StringValidator.php | 187 - framework/yii/validators/UniqueValidator.php | 123 - framework/yii/validators/UrlValidator.php | 142 - framework/yii/validators/ValidationAsset.php | 26 - framework/yii/validators/Validator.php | 312 - framework/yii/views/errorHandler/callStackItem.php | 45 - framework/yii/views/errorHandler/error.php | 86 - framework/yii/views/errorHandler/exception.php | 483 -- .../yii/views/errorHandler/previousException.php | 21 - framework/yii/views/messageConfig.php | 45 - framework/yii/views/migration.php | 25 - framework/yii/web/AccessControl.php | 144 - framework/yii/web/AccessDeniedHttpException.php | 28 - framework/yii/web/AccessRule.php | 186 - framework/yii/web/Application.php | 178 - framework/yii/web/AssetBundle.php | 194 - framework/yii/web/AssetConverter.php | 99 - framework/yii/web/AssetConverterInterface.php | 25 - framework/yii/web/AssetManager.php | 343 - framework/yii/web/BadRequestHttpException.php | 28 - framework/yii/web/CacheSession.php | 118 - framework/yii/web/Controller.php | 282 - framework/yii/web/Cookie.php | 65 - framework/yii/web/CookieCollection.php | 228 - framework/yii/web/DbSession.php | 224 - framework/yii/web/ErrorAction.php | 106 - framework/yii/web/HeaderCollection.php | 221 - framework/yii/web/HttpCache.php | 160 - framework/yii/web/HttpException.php | 72 - framework/yii/web/IdentityInterface.php | 81 - framework/yii/web/JqueryAsset.php | 22 - framework/yii/web/JsExpression.php | 47 - .../yii/web/MethodNotAllowedHttpException.php | 28 - framework/yii/web/NotFoundHttpException.php | 28 - framework/yii/web/PageCache.php | 150 - framework/yii/web/Request.php | 1141 ---- framework/yii/web/Response.php | 878 --- framework/yii/web/ResponseFormatterInterface.php | 23 - framework/yii/web/Session.php | 719 --- framework/yii/web/SessionIterator.php | 84 - framework/yii/web/UploadedFile.php | 234 - framework/yii/web/UrlManager.php | 338 - framework/yii/web/UrlRule.php | 326 - framework/yii/web/User.php | 533 -- framework/yii/web/UserEvent.php | 35 - framework/yii/web/VerbFilter.php | 108 - framework/yii/web/View.php | 467 -- framework/yii/web/XmlResponseFormatter.php | 98 - framework/yii/web/YiiAsset.php | 25 - framework/yii/widgets/ActiveField.php | 657 -- framework/yii/widgets/ActiveForm.php | 357 - framework/yii/widgets/ActiveFormAsset.php | 24 - framework/yii/widgets/BaseListView.php | 215 - framework/yii/widgets/Block.php | 49 - framework/yii/widgets/Breadcrumbs.php | 141 - framework/yii/widgets/ContentDecorator.php | 52 - framework/yii/widgets/DetailView.php | 211 - framework/yii/widgets/FragmentCache.php | 178 - framework/yii/widgets/InputWidget.php | 72 - framework/yii/widgets/LinkPager.php | 193 - framework/yii/widgets/LinkSorter.php | 74 - framework/yii/widgets/ListView.php | 107 - framework/yii/widgets/MaskedInput.php | 129 - framework/yii/widgets/MaskedInputAsset.php | 24 - framework/yii/widgets/Menu.php | 307 - framework/yii/widgets/Spaceless.php | 69 - framework/yii/yii | 24 - framework/yii/yii.bat | 20 - phpunit.xml.dist | 30 - tests/README.md | 41 - tests/unit/.gitignore | 1 - tests/unit/TestCase.php | 60 - tests/unit/VendorTestCase.php | 34 - tests/unit/bootstrap.php | 20 - tests/unit/data/ar/ActiveRecord.php | 24 - tests/unit/data/ar/Category.php | 27 - tests/unit/data/ar/Customer.php | 43 - tests/unit/data/ar/Item.php | 23 - tests/unit/data/ar/NullValues.php | 20 - tests/unit/data/ar/Order.php | 77 - tests/unit/data/ar/OrderItem.php | 29 - tests/unit/data/ar/elasticsearch/ActiveRecord.php | 32 - tests/unit/data/ar/elasticsearch/Customer.php | 70 - tests/unit/data/ar/elasticsearch/Item.php | 43 - tests/unit/data/ar/elasticsearch/Order.php | 94 - tests/unit/data/ar/elasticsearch/OrderItem.php | 50 - tests/unit/data/ar/mongodb/ActiveRecord.php | 16 - tests/unit/data/ar/mongodb/Customer.php | 32 - tests/unit/data/ar/mongodb/CustomerOrder.php | 27 - tests/unit/data/ar/mongodb/file/ActiveRecord.php | 16 - tests/unit/data/ar/mongodb/file/CustomerFile.php | 27 - tests/unit/data/ar/redis/ActiveRecord.php | 26 - tests/unit/data/ar/redis/Customer.php | 38 - tests/unit/data/ar/redis/Item.php | 11 - tests/unit/data/ar/redis/Order.php | 62 - tests/unit/data/ar/redis/OrderItem.php | 26 - tests/unit/data/ar/sphinx/ActiveRecord.php | 16 - tests/unit/data/ar/sphinx/ArticleDb.php | 25 - tests/unit/data/ar/sphinx/ArticleIndex.php | 35 - tests/unit/data/ar/sphinx/ItemDb.php | 13 - tests/unit/data/ar/sphinx/ItemIndex.php | 11 - tests/unit/data/ar/sphinx/RuntimeIndex.php | 11 - tests/unit/data/ar/sphinx/TagDb.php | 12 - tests/unit/data/base/InvalidRulesModel.php | 17 - tests/unit/data/base/Singer.php | 22 - tests/unit/data/base/Speaker.php | 45 - tests/unit/data/config.php | 60 - tests/unit/data/cubrid.sql | 119 - tests/unit/data/i18n/messages/de-DE/test.php | 9 - tests/unit/data/i18n/messages/en-US/test.php | 7 - tests/unit/data/i18n/test.mo | Bin 1426 -> 0 bytes tests/unit/data/i18n/test.po | 64 - tests/unit/data/imagine/GothamRnd-Light.otf | Bin 131844 -> 0 bytes tests/unit/data/imagine/large.jpg | Bin 26019 -> 0 bytes tests/unit/data/imagine/xparent.gif | Bin 16449 -> 0 bytes tests/unit/data/mssql.sql | 104 - tests/unit/data/mysql.sql | 153 - tests/unit/data/postgres.sql | 133 - tests/unit/data/sphinx/source.sql | 59 - tests/unit/data/sphinx/sphinx.conf | 125 - tests/unit/data/sqlite.sql | 135 - tests/unit/data/travis/README.md | 14 - tests/unit/data/travis/apc-setup.sh | 8 - tests/unit/data/travis/cubrid-setup.sh | 25 - tests/unit/data/travis/cubrid-solo.rb | 5 - tests/unit/data/travis/memcache-setup.sh | 4 - tests/unit/data/travis/mongodb-setup.sh | 11 - tests/unit/data/travis/sphinx-setup.sh | 32 - tests/unit/data/validators/TestValidator.php | 44 - .../validators/models/FakedValidationModel.php | 63 - .../validators/models/ValidatorTestMainModel.php | 21 - .../validators/models/ValidatorTestRefModel.php | 23 - tests/unit/data/views/layout.php | 22 - tests/unit/data/views/rawlayout.php | 5 - tests/unit/data/views/simple.php | 1 - tests/unit/data/web/assets/.gitignore | 2 - tests/unit/data/web/data.txt | 1 - .../unit/extensions/authclient/AuthActionTest.php | 68 - .../unit/extensions/authclient/BaseClientTest.php | 82 - tests/unit/extensions/authclient/BaseOAuthTest.php | 251 - .../unit/extensions/authclient/CollectionTest.php | 85 - tests/unit/extensions/authclient/OAuth1Test.php | 109 - tests/unit/extensions/authclient/OAuth2Test.php | 33 - tests/unit/extensions/authclient/OpenIdTest.php | 61 - tests/unit/extensions/authclient/TestCase.php | 30 - tests/unit/extensions/authclient/TokenTest.php | 133 - .../authclient/signature/BaseMethodTest.php | 50 - .../authclient/signature/HmacSha1Test.php | 20 - .../authclient/signature/PlainTextTest.php | 20 - .../authclient/signature/RsaSha1Test.php | 110 - .../extensions/elasticsearch/ActiveRecordTest.php | 499 -- .../elasticsearch/ElasticSearchConnectionTest.php | 28 - .../elasticsearch/ElasticSearchTestCase.php | 51 - tests/unit/extensions/elasticsearch/QueryTest.php | 188 - .../unit/extensions/imagine/AbstractImageTest.php | 98 - tests/unit/extensions/imagine/ImageGdTest.php | 30 - tests/unit/extensions/imagine/ImageGmagickTest.php | 30 - tests/unit/extensions/imagine/ImageImagickTest.php | 30 - .../extensions/mongodb/ActiveDataProviderTest.php | 91 - tests/unit/extensions/mongodb/ActiveRecordTest.php | 246 - .../unit/extensions/mongodb/ActiveRelationTest.php | 86 - tests/unit/extensions/mongodb/CollectionTest.php | 319 - tests/unit/extensions/mongodb/ConnectionTest.php | 119 - tests/unit/extensions/mongodb/DatabaseTest.php | 70 - tests/unit/extensions/mongodb/MongoDbTestCase.php | 149 - tests/unit/extensions/mongodb/QueryRunTest.php | 144 - tests/unit/extensions/mongodb/QueryTest.php | 97 - .../extensions/mongodb/file/ActiveRecordTest.php | 323 - .../extensions/mongodb/file/CollectionTest.php | 98 - tests/unit/extensions/mongodb/file/QueryTest.php | 70 - tests/unit/extensions/redis/ActiveRecordTest.php | 231 - tests/unit/extensions/redis/RedisCacheTest.php | 101 - .../unit/extensions/redis/RedisConnectionTest.php | 58 - tests/unit/extensions/redis/RedisTestCase.php | 48 - .../extensions/sphinx/ActiveDataProviderTest.php | 66 - tests/unit/extensions/sphinx/ActiveRecordTest.php | 237 - .../unit/extensions/sphinx/ActiveRelationTest.php | 45 - tests/unit/extensions/sphinx/ColumnSchemaTest.php | 55 - tests/unit/extensions/sphinx/CommandTest.php | 409 -- tests/unit/extensions/sphinx/ConnectionTest.php | 42 - .../sphinx/ExternalActiveRelationTest.php | 74 - tests/unit/extensions/sphinx/QueryTest.php | 187 - tests/unit/extensions/sphinx/SchemaTest.php | 84 - tests/unit/extensions/sphinx/SphinxTestCase.php | 154 - tests/unit/extensions/swiftmailer/MailerTest.php | 124 - tests/unit/extensions/swiftmailer/MessageTest.php | 363 -- tests/unit/extensions/twig/ViewRendererTest.php | 74 - tests/unit/extensions/twig/views/layout.twig | 14 - tests/unit/framework/BaseYiiTest.php | 63 - tests/unit/framework/ar/ActiveRecordTestTrait.php | 838 --- tests/unit/framework/base/BehaviorTest.php | 106 - tests/unit/framework/base/ComponentTest.php | 395 -- tests/unit/framework/base/EventTest.php | 93 - tests/unit/framework/base/ExceptionTest.php | 23 - tests/unit/framework/base/FormatterTest.php | 200 - tests/unit/framework/base/ModelTest.php | 274 - tests/unit/framework/base/ObjectTest.php | 182 - .../unit/framework/behaviors/AutoTimestampTest.php | 116 - tests/unit/framework/caching/ApcCacheTest.php | 45 - tests/unit/framework/caching/CacheTestCase.php | 239 - tests/unit/framework/caching/DbCacheTest.php | 98 - tests/unit/framework/caching/FileCacheTest.php | 48 - tests/unit/framework/caching/MemCacheTest.php | 45 - tests/unit/framework/caching/MemCachedTest.php | 45 - tests/unit/framework/caching/WinCacheTest.php | 33 - tests/unit/framework/caching/XCacheTest.php | 29 - tests/unit/framework/caching/ZendDataCacheTest.php | 29 - .../console/controllers/AssetControllerTest.php | 319 - .../console/controllers/MessageControllerTest.php | 369 -- .../unit/framework/data/ActiveDataProviderTest.php | 180 - tests/unit/framework/data/SortTest.php | 178 - tests/unit/framework/db/ActiveRecordTest.php | 328 - tests/unit/framework/db/CommandTest.php | 278 - tests/unit/framework/db/ConnectionTest.php | 80 - tests/unit/framework/db/DatabaseTestCase.php | 68 - tests/unit/framework/db/QueryBuilderTest.php | 133 - tests/unit/framework/db/QueryTest.php | 126 - tests/unit/framework/db/SchemaTest.php | 93 - .../db/cubrid/CubridActiveDataProviderTest.php | 14 - .../framework/db/cubrid/CubridActiveRecordTest.php | 14 - .../unit/framework/db/cubrid/CubridCommandTest.php | 79 - .../framework/db/cubrid/CubridConnectionTest.php | 44 - .../framework/db/cubrid/CubridQueryBuilderTest.php | 83 - tests/unit/framework/db/cubrid/CubridQueryTest.php | 13 - .../unit/framework/db/cubrid/CubridSchemaTest.php | 36 - .../db/mssql/MssqlActiveDataProviderTest.php | 14 - .../framework/db/mssql/MssqlActiveRecordTest.php | 14 - tests/unit/framework/db/mssql/MssqlCommandTest.php | 84 - .../framework/db/mssql/MssqlConnectionTest.php | 45 - tests/unit/framework/db/mssql/MssqlQueryTest.php | 14 - .../db/pgsql/PostgreSQLActiveDataProviderTest.php | 14 - .../db/pgsql/PostgreSQLActiveRecordTest.php | 14 - .../db/pgsql/PostgreSQLConnectionTest.php | 51 - .../db/pgsql/PostgreSQLQueryBuilderTest.php | 77 - .../db/sqlite/SqliteActiveDataProviderTest.php | 14 - .../framework/db/sqlite/SqliteActiveRecordTest.php | 14 - .../unit/framework/db/sqlite/SqliteCommandTest.php | 22 - .../framework/db/sqlite/SqliteConnectionTest.php | 48 - .../framework/db/sqlite/SqliteQueryBuilderTest.php | 90 - tests/unit/framework/db/sqlite/SqliteQueryTest.php | 13 - .../unit/framework/db/sqlite/SqliteSchemaTest.php | 13 - tests/unit/framework/helpers/ArrayHelperTest.php | 381 -- tests/unit/framework/helpers/ConsoleTest.php | 82 - tests/unit/framework/helpers/FileHelperTest.php | 341 - tests/unit/framework/helpers/HtmlTest.php | 554 -- tests/unit/framework/helpers/InflectorTest.php | 147 - tests/unit/framework/helpers/JsonTest.php | 69 - tests/unit/framework/helpers/SecurityTest.php | 43 - tests/unit/framework/helpers/StringHelperTest.php | 68 - tests/unit/framework/helpers/VarDumperTest.php | 20 - .../i18n/FallbackMessageFormatterTest.php | 171 - tests/unit/framework/i18n/FormatterTest.php | 96 - .../framework/i18n/GettextMessageSourceTest.php | 16 - tests/unit/framework/i18n/GettextMoFileTest.php | 98 - tests/unit/framework/i18n/GettextPoFileTest.php | 98 - tests/unit/framework/i18n/I18NTest.php | 88 - tests/unit/framework/i18n/MessageFormatterTest.php | 337 - tests/unit/framework/log/LoggerTest.php | 33 - tests/unit/framework/log/TargetTest.php | 90 - tests/unit/framework/mail/BaseMailerTest.php | 379 -- tests/unit/framework/mail/BaseMessageTest.php | 129 - tests/unit/framework/rbac/ManagerTestCase.php | 263 - tests/unit/framework/rbac/PhpManagerTest.php | 38 - .../requirements/YiiRequirementCheckerTest.php | 197 - .../framework/validators/BooleanValidatorTest.php | 59 - .../framework/validators/CompareValidatorTest.php | 175 - .../framework/validators/DateValidatorTest.php | 71 - .../validators/DefaultValueValidatorTest.php | 38 - .../framework/validators/EmailValidatorTest.php | 108 - .../ExistValidatorPostgresTest.php | 10 - .../ExistValidatorSQliteTest.php | 10 - .../framework/validators/ExistValidatorTest.php | 137 - .../framework/validators/FileValidatorTest.php | 274 - .../framework/validators/FilterValidatorTest.php | 52 - .../framework/validators/NumberValidatorTest.php | 166 - .../framework/validators/RangeValidatorTest.php | 76 - .../validators/RegularExpressionValidatorTest.php | 54 - .../framework/validators/RequiredValidatorTest.php | 60 - .../framework/validators/StringValidatorTest.php | 116 - .../UniqueValidatorPostgresTest.php | 11 - .../UniqueValidatorSQliteTest.php | 11 - .../framework/validators/UniqueValidatorTest.php | 137 - .../unit/framework/validators/UrlValidatorTest.php | 100 - tests/unit/framework/validators/ValidatorTest.php | 232 - tests/unit/framework/web/AssetBundleTest.php | 256 - tests/unit/framework/web/AssetConverterTest.php | 42 - tests/unit/framework/web/CacheSessionTest.php | 36 - tests/unit/framework/web/ResponseTest.php | 80 - tests/unit/framework/web/UrlManagerTest.php | 310 - tests/unit/framework/web/UrlRuleTest.php | 658 -- .../framework/web/XmlResponseFormatterTest.php | 138 - tests/unit/framework/widgets/SpacelessTest.php | 41 - tests/unit/runtime/.gitignore | 1 - tests/unit/runtime/coveralls/.gitkeep | 0 tests/web/app/assets/.gitignore | 1 - tests/web/app/index.php | 6 - tests/web/app/protected/config/main.php | 3 - .../app/protected/controllers/SiteController.php | 30 - tests/web/app/protected/runtime/.gitignore | 1 - tests/web/app/protected/views/site/index.php | 8 - 1143 files changed, 1953 insertions(+), 150347 deletions(-) delete mode 100644 .coveralls.yml delete mode 100644 .gitattributes delete mode 100644 .gitignore delete mode 100644 .travis.yml create mode 100644 Alert.php create mode 100644 BootstrapAsset.php create mode 100644 BootstrapPluginAsset.php create mode 100644 BootstrapThemeAsset.php create mode 100644 Button.php create mode 100644 ButtonDropdown.php create mode 100644 ButtonGroup.php create mode 100644 CHANGELOG.md create mode 100644 Carousel.php create mode 100644 Collapse.php create mode 100644 Dropdown.php delete mode 100644 LICENSE.md create mode 100644 Modal.php create mode 100644 Nav.php create mode 100644 NavBar.php create mode 100644 Progress.php create mode 100644 Tabs.php create mode 100644 Widget.php delete mode 100644 apps/advanced/.gitignore delete mode 100644 apps/advanced/LICENSE.md delete mode 100644 apps/advanced/README.md delete mode 100644 apps/advanced/backend/assets/AppAsset.php delete mode 100644 apps/advanced/backend/config/.gitignore delete mode 100644 apps/advanced/backend/config/main.php delete mode 100644 apps/advanced/backend/config/params.php delete mode 100644 apps/advanced/backend/controllers/SiteController.php delete mode 100644 apps/advanced/backend/models/.gitkeep delete mode 100644 apps/advanced/backend/runtime/.gitignore delete mode 100644 apps/advanced/backend/views/layouts/main.php delete mode 100644 apps/advanced/backend/views/site/error.php delete mode 100644 apps/advanced/backend/views/site/index.php delete mode 100644 apps/advanced/backend/views/site/login.php delete mode 100644 apps/advanced/backend/web/.gitignore delete mode 100644 apps/advanced/backend/web/assets/.gitignore delete mode 100644 apps/advanced/backend/web/css/site.css delete mode 100644 apps/advanced/backend/web/favicon.ico delete mode 100644 apps/advanced/backend/web/robots.txt delete mode 100644 apps/advanced/common/config/.gitignore delete mode 100644 apps/advanced/common/config/params.php delete mode 100644 apps/advanced/common/mails/layouts/html.php delete mode 100644 apps/advanced/common/mails/passwordResetToken.php delete mode 100644 apps/advanced/common/models/LoginForm.php delete mode 100644 apps/advanced/common/models/User.php delete mode 100644 apps/advanced/composer.json delete mode 100644 apps/advanced/console/config/.gitignore delete mode 100644 apps/advanced/console/config/main.php delete mode 100644 apps/advanced/console/config/params.php delete mode 100644 apps/advanced/console/controllers/.gitkeep delete mode 100644 apps/advanced/console/migrations/m130524_201442_init.php delete mode 100644 apps/advanced/console/models/.gitkeep delete mode 100644 apps/advanced/console/runtime/.gitignore delete mode 100644 apps/advanced/environments/dev/backend/config/main-local.php delete mode 100644 apps/advanced/environments/dev/backend/config/params-local.php delete mode 100644 apps/advanced/environments/dev/backend/web/index.php delete mode 100644 apps/advanced/environments/dev/common/config/params-local.php delete mode 100644 apps/advanced/environments/dev/console/config/main-local.php delete mode 100644 apps/advanced/environments/dev/console/config/params-local.php delete mode 100644 apps/advanced/environments/dev/frontend/config/main-local.php delete mode 100644 apps/advanced/environments/dev/frontend/config/params-local.php delete mode 100644 apps/advanced/environments/dev/frontend/web/index.php delete mode 100644 apps/advanced/environments/dev/yii delete mode 100644 apps/advanced/environments/index.php delete mode 100644 apps/advanced/environments/prod/backend/config/main-local.php delete mode 100644 apps/advanced/environments/prod/backend/config/params-local.php delete mode 100644 apps/advanced/environments/prod/backend/web/index.php delete mode 100644 apps/advanced/environments/prod/common/config/params-local.php delete mode 100644 apps/advanced/environments/prod/console/config/main-local.php delete mode 100644 apps/advanced/environments/prod/console/config/params-local.php delete mode 100644 apps/advanced/environments/prod/frontend/config/main-local.php delete mode 100644 apps/advanced/environments/prod/frontend/config/params-local.php delete mode 100644 apps/advanced/environments/prod/frontend/web/index.php delete mode 100644 apps/advanced/environments/prod/yii delete mode 100644 apps/advanced/frontend/assets/AppAsset.php delete mode 100644 apps/advanced/frontend/config/.gitignore delete mode 100644 apps/advanced/frontend/config/main.php delete mode 100644 apps/advanced/frontend/config/params.php delete mode 100644 apps/advanced/frontend/controllers/SiteController.php delete mode 100644 apps/advanced/frontend/models/ContactForm.php delete mode 100644 apps/advanced/frontend/runtime/.gitignore delete mode 100644 apps/advanced/frontend/views/layouts/main.php delete mode 100644 apps/advanced/frontend/views/site/about.php delete mode 100644 apps/advanced/frontend/views/site/contact.php delete mode 100644 apps/advanced/frontend/views/site/error.php delete mode 100644 apps/advanced/frontend/views/site/index.php delete mode 100644 apps/advanced/frontend/views/site/login.php delete mode 100644 apps/advanced/frontend/views/site/requestPasswordResetToken.php delete mode 100644 apps/advanced/frontend/views/site/resetPassword.php delete mode 100644 apps/advanced/frontend/views/site/signup.php delete mode 100644 apps/advanced/frontend/web/.gitignore delete mode 100644 apps/advanced/frontend/web/assets/.gitignore delete mode 100644 apps/advanced/frontend/web/css/site.css delete mode 100644 apps/advanced/frontend/web/favicon.ico delete mode 100644 apps/advanced/frontend/web/robots.txt delete mode 100644 apps/advanced/frontend/widgets/Alert.php delete mode 100755 apps/advanced/init delete mode 100644 apps/advanced/init.bat delete mode 100644 apps/advanced/requirements.php delete mode 100644 apps/advanced/vendor/.gitignore delete mode 100644 apps/advanced/yii.bat delete mode 100644 apps/basic/LICENSE.md delete mode 100644 apps/basic/README.md delete mode 100644 apps/basic/assets/AppAsset.php delete mode 100644 apps/basic/codeception.yml delete mode 100644 apps/basic/commands/HelloController.php delete mode 100644 apps/basic/composer.json delete mode 100644 apps/basic/config/console.php delete mode 100644 apps/basic/config/db.php delete mode 100644 apps/basic/config/params.php delete mode 100644 apps/basic/config/web.php delete mode 100644 apps/basic/controllers/SiteController.php delete mode 100644 apps/basic/mails/layouts/html.php delete mode 100644 apps/basic/models/ContactForm.php delete mode 100644 apps/basic/models/LoginForm.php delete mode 100644 apps/basic/models/User.php delete mode 100644 apps/basic/requirements.php delete mode 100644 apps/basic/runtime/.gitignore delete mode 100644 apps/basic/tests/.gitignore delete mode 100644 apps/basic/tests/README.md delete mode 100644 apps/basic/tests/_bootstrap.php delete mode 100644 apps/basic/tests/_config.php delete mode 100644 apps/basic/tests/_data/dump.sql delete mode 100644 apps/basic/tests/_helpers/CodeHelper.php delete mode 100644 apps/basic/tests/_helpers/TestHelper.php delete mode 100644 apps/basic/tests/_helpers/WebHelper.php delete mode 100644 apps/basic/tests/_log/.gitignore delete mode 100644 apps/basic/tests/_pages/AboutPage.php delete mode 100644 apps/basic/tests/_pages/ContactPage.php delete mode 100644 apps/basic/tests/_pages/LoginPage.php delete mode 100644 apps/basic/tests/acceptance.suite.yml delete mode 100644 apps/basic/tests/acceptance/AboutCept.php delete mode 100644 apps/basic/tests/acceptance/ContactCept.php delete mode 100644 apps/basic/tests/acceptance/HomeCept.php delete mode 100644 apps/basic/tests/acceptance/LoginCept.php delete mode 100644 apps/basic/tests/acceptance/_bootstrap.php delete mode 100644 apps/basic/tests/acceptance/_config.php delete mode 100644 apps/basic/tests/functional.suite.yml delete mode 100644 apps/basic/tests/functional/AboutCept.php delete mode 100644 apps/basic/tests/functional/ContactCept.php delete mode 100644 apps/basic/tests/functional/HomeCept.php delete mode 100644 apps/basic/tests/functional/LoginCept.php delete mode 100644 apps/basic/tests/functional/_bootstrap.php delete mode 100644 apps/basic/tests/functional/_config.php delete mode 100644 apps/basic/tests/unit.suite.yml delete mode 100644 apps/basic/tests/unit/_bootstrap.php delete mode 100644 apps/basic/tests/unit/_config.php delete mode 100644 apps/basic/tests/unit/fixtures/.gitkeep delete mode 100644 apps/basic/tests/unit/models/ContactFormTest.php delete mode 100644 apps/basic/tests/unit/models/LoginFormTest.php delete mode 100644 apps/basic/tests/unit/models/UserTest.php delete mode 100644 apps/basic/tests/unit/templates/fixtures/.gitkeep delete mode 100644 apps/basic/vendor/.gitignore delete mode 100644 apps/basic/views/layouts/main.php delete mode 100644 apps/basic/views/site/about.php delete mode 100644 apps/basic/views/site/contact.php delete mode 100644 apps/basic/views/site/error.php delete mode 100644 apps/basic/views/site/index.php delete mode 100644 apps/basic/views/site/login.php delete mode 100644 apps/basic/web/assets/.gitignore delete mode 100644 apps/basic/web/css/site.css delete mode 100644 apps/basic/web/favicon.ico delete mode 100644 apps/basic/web/index-test.php delete mode 100644 apps/basic/web/index.php delete mode 100644 apps/basic/web/robots.txt delete mode 100755 apps/basic/yii delete mode 100644 apps/basic/yii.bat delete mode 100644 apps/benchmark/LICENSE.md delete mode 100644 apps/benchmark/README.md delete mode 100644 apps/benchmark/composer.json delete mode 100644 apps/benchmark/index.php delete mode 100644 apps/benchmark/protected/.htaccess delete mode 100644 apps/benchmark/protected/controllers/SiteController.php delete mode 100644 apps/benchmark/protected/vendor/.gitignore delete mode 100644 build/.htaccess delete mode 100755 build/build delete mode 100644 build/build.bat delete mode 100644 build/build.xml delete mode 100644 build/controllers/ClassmapController.php delete mode 100644 build/controllers/PhpDocController.php delete mode 100644 docs/api/base/Component.md delete mode 100644 docs/api/base/Object.md delete mode 100644 docs/api/db/ActiveRecord-find.md delete mode 100644 docs/api/db/ActiveRecord.md delete mode 100644 docs/guide/README.md delete mode 100644 docs/guide/active-record.md delete mode 100644 docs/guide/apps-advanced.md delete mode 100644 docs/guide/apps-basic.md delete mode 100644 docs/guide/apps-own.md delete mode 100644 docs/guide/assets.md delete mode 100644 docs/guide/authentication.md delete mode 100644 docs/guide/authorization.md delete mode 100644 docs/guide/basics.md delete mode 100644 docs/guide/behaviors.md delete mode 100644 docs/guide/bootstrap-widgets.md delete mode 100644 docs/guide/caching.md delete mode 100644 docs/guide/composer.md delete mode 100644 docs/guide/configuration.md delete mode 100644 docs/guide/console-fixture.md delete mode 100644 docs/guide/console-migrate.md delete mode 100644 docs/guide/console.md delete mode 100644 docs/guide/controller.md delete mode 100644 docs/guide/database-basics.md delete mode 100644 docs/guide/error.md delete mode 100644 docs/guide/events.md delete mode 100644 docs/guide/extensions.md delete mode 100644 docs/guide/form.md delete mode 100644 docs/guide/gii.md delete mode 100644 docs/guide/i18n.md delete mode 100644 docs/guide/images/flow.png delete mode 100644 docs/guide/images/flow.vsd delete mode 100644 docs/guide/images/gii-entry.png delete mode 100644 docs/guide/images/gii-preview.png delete mode 100644 docs/guide/images/structure.png delete mode 100644 docs/guide/images/structure.vsd delete mode 100644 docs/guide/index.md delete mode 100644 docs/guide/installation.md delete mode 100644 docs/guide/logging.md delete mode 100644 docs/guide/model.md delete mode 100644 docs/guide/module-debug.md delete mode 100644 docs/guide/mvc.md delete mode 100644 docs/guide/overview.md delete mode 100644 docs/guide/performance.md delete mode 100644 docs/guide/query-builder.md delete mode 100644 docs/guide/security.md delete mode 100644 docs/guide/template.md delete mode 100644 docs/guide/testing.md delete mode 100644 docs/guide/theming.md delete mode 100644 docs/guide/title.md delete mode 100644 docs/guide/upgrade-from-v1.md delete mode 100644 docs/guide/url.md delete mode 100644 docs/guide/validation.md delete mode 100644 docs/guide/view.md delete mode 100644 docs/internals/ar.md delete mode 100644 docs/internals/autoloader.md delete mode 100644 docs/internals/base.md delete mode 100644 docs/internals/database.md delete mode 100644 docs/internals/errors_and_exceptions.md delete mode 100644 docs/internals/exception_hierarchy.png delete mode 100644 docs/internals/exception_hierarchy.vsd delete mode 100644 docs/internals/getting-started.md delete mode 100644 docs/internals/git-workflow.md delete mode 100644 docs/internals/translations.md delete mode 100644 docs/internals/versions.md delete mode 100644 extensions/README.md delete mode 100644 extensions/faker/CHANGELOG.md delete mode 100644 extensions/faker/FixtureController.php delete mode 100644 extensions/faker/LICENSE.md delete mode 100644 extensions/faker/README.md delete mode 100644 extensions/faker/composer.json delete mode 100644 extensions/twig/CHANGELOG.md delete mode 100644 extensions/twig/LICENSE.md delete mode 100644 extensions/twig/README.md delete mode 100644 extensions/twig/TwigSimpleFileLoader.php delete mode 100644 extensions/twig/ViewRenderer.php delete mode 100644 extensions/twig/ViewRendererStaticClassProxy.php delete mode 100644 extensions/twig/composer.json delete mode 100644 extensions/yii/apidoc/.gitignore delete mode 100644 extensions/yii/apidoc/CHANGELOG.md delete mode 100644 extensions/yii/apidoc/LICENSE.md delete mode 100644 extensions/yii/apidoc/README.md delete mode 100755 extensions/yii/apidoc/apidoc delete mode 100644 extensions/yii/apidoc/apidoc.bat delete mode 100644 extensions/yii/apidoc/commands/RenderController.php delete mode 100644 extensions/yii/apidoc/composer.json delete mode 100644 extensions/yii/apidoc/helpers/Markdown.php delete mode 100644 extensions/yii/apidoc/helpers/PrettyPrinter.php delete mode 100644 extensions/yii/apidoc/models/BaseDoc.php delete mode 100644 extensions/yii/apidoc/models/ClassDoc.php delete mode 100644 extensions/yii/apidoc/models/ConstDoc.php delete mode 100644 extensions/yii/apidoc/models/Context.php delete mode 100644 extensions/yii/apidoc/models/EventDoc.php delete mode 100644 extensions/yii/apidoc/models/FunctionDoc.php delete mode 100644 extensions/yii/apidoc/models/InterfaceDoc.php delete mode 100644 extensions/yii/apidoc/models/MethodDoc.php delete mode 100644 extensions/yii/apidoc/models/ParamDoc.php delete mode 100644 extensions/yii/apidoc/models/PropertyDoc.php delete mode 100644 extensions/yii/apidoc/models/TraitDoc.php delete mode 100644 extensions/yii/apidoc/models/TypeDoc.php delete mode 100644 extensions/yii/apidoc/templates/BaseRenderer.php delete mode 100644 extensions/yii/apidoc/templates/html/README.md delete mode 100644 extensions/yii/apidoc/templates/html/Renderer.php delete mode 100644 extensions/yii/apidoc/templates/html/views/constSummary.php delete mode 100644 extensions/yii/apidoc/templates/html/views/eventDetails.php delete mode 100644 extensions/yii/apidoc/templates/html/views/eventSummary.php delete mode 100644 extensions/yii/apidoc/templates/html/views/methodDetails.php delete mode 100644 extensions/yii/apidoc/templates/html/views/methodSummary.php delete mode 100644 extensions/yii/apidoc/templates/html/views/propertyDetails.php delete mode 100644 extensions/yii/apidoc/templates/html/views/propertySummary.php delete mode 100644 extensions/yii/apidoc/templates/html/views/seeAlso.php delete mode 100644 extensions/yii/apidoc/templates/html/views/type.php delete mode 100644 extensions/yii/apidoc/templates/offline/Renderer.php delete mode 100644 extensions/yii/apidoc/templates/offline/assets/AssetBundle.php delete mode 100644 extensions/yii/apidoc/templates/offline/assets/css/api.css delete mode 100644 extensions/yii/apidoc/templates/offline/assets/css/style.css delete mode 100644 extensions/yii/apidoc/templates/offline/views/index.php delete mode 100644 extensions/yii/apidoc/templates/offline/views/offline.php delete mode 100644 extensions/yii/authclient/AuthAction.php delete mode 100644 extensions/yii/authclient/BaseClient.php delete mode 100644 extensions/yii/authclient/BaseOAuth.php delete mode 100644 extensions/yii/authclient/CHANGELOG.md delete mode 100644 extensions/yii/authclient/ClientInterface.php delete mode 100644 extensions/yii/authclient/Collection.php delete mode 100644 extensions/yii/authclient/LICENSE.md delete mode 100644 extensions/yii/authclient/OAuth1.php delete mode 100644 extensions/yii/authclient/OAuth2.php delete mode 100644 extensions/yii/authclient/OAuthToken.php delete mode 100644 extensions/yii/authclient/OpenId.php delete mode 100644 extensions/yii/authclient/README.md delete mode 100644 extensions/yii/authclient/clients/Facebook.php delete mode 100644 extensions/yii/authclient/clients/GitHub.php delete mode 100644 extensions/yii/authclient/clients/GoogleOAuth.php delete mode 100644 extensions/yii/authclient/clients/GoogleOpenId.php delete mode 100644 extensions/yii/authclient/clients/LinkedIn.php delete mode 100644 extensions/yii/authclient/clients/Twitter.php delete mode 100644 extensions/yii/authclient/clients/YandexOAuth.php delete mode 100644 extensions/yii/authclient/clients/YandexOpenId.php delete mode 100644 extensions/yii/authclient/composer.json delete mode 100644 extensions/yii/authclient/signature/BaseMethod.php delete mode 100644 extensions/yii/authclient/signature/HmacSha1.php delete mode 100644 extensions/yii/authclient/signature/PlainText.php delete mode 100644 extensions/yii/authclient/signature/RsaSha1.php delete mode 100644 extensions/yii/authclient/views/redirect.php delete mode 100644 extensions/yii/authclient/widgets/Choice.php delete mode 100644 extensions/yii/authclient/widgets/ChoiceAsset.php delete mode 100644 extensions/yii/authclient/widgets/assets/authchoice.css delete mode 100644 extensions/yii/authclient/widgets/assets/authchoice.js delete mode 100644 extensions/yii/authclient/widgets/assets/authchoice.png delete mode 100644 extensions/yii/bootstrap/Alert.php delete mode 100644 extensions/yii/bootstrap/BootstrapAsset.php delete mode 100644 extensions/yii/bootstrap/BootstrapPluginAsset.php delete mode 100644 extensions/yii/bootstrap/BootstrapThemeAsset.php delete mode 100644 extensions/yii/bootstrap/Button.php delete mode 100644 extensions/yii/bootstrap/ButtonDropdown.php delete mode 100644 extensions/yii/bootstrap/ButtonGroup.php delete mode 100644 extensions/yii/bootstrap/CHANGELOG.md delete mode 100644 extensions/yii/bootstrap/Carousel.php delete mode 100644 extensions/yii/bootstrap/Collapse.php delete mode 100644 extensions/yii/bootstrap/Dropdown.php delete mode 100644 extensions/yii/bootstrap/Modal.php delete mode 100644 extensions/yii/bootstrap/Nav.php delete mode 100644 extensions/yii/bootstrap/NavBar.php delete mode 100644 extensions/yii/bootstrap/Progress.php delete mode 100644 extensions/yii/bootstrap/README.md delete mode 100644 extensions/yii/bootstrap/Tabs.php delete mode 100644 extensions/yii/bootstrap/Widget.php delete mode 100644 extensions/yii/bootstrap/composer.json delete mode 100644 extensions/yii/codeception/BasePage.php delete mode 100644 extensions/yii/codeception/CHANGELOG.md delete mode 100644 extensions/yii/codeception/LICENSE.md delete mode 100644 extensions/yii/codeception/README.md delete mode 100644 extensions/yii/codeception/TestCase.php delete mode 100644 extensions/yii/codeception/composer.json delete mode 100644 extensions/yii/composer/CHANGELOG.md delete mode 100644 extensions/yii/composer/Installer.php delete mode 100644 extensions/yii/composer/LICENSE.md delete mode 100644 extensions/yii/composer/Plugin.php delete mode 100644 extensions/yii/composer/README.md delete mode 100644 extensions/yii/composer/composer.json delete mode 100644 extensions/yii/debug/CHANGELOG.md delete mode 100644 extensions/yii/debug/DebugAsset.php delete mode 100644 extensions/yii/debug/LogTarget.php delete mode 100644 extensions/yii/debug/Module.php delete mode 100644 extensions/yii/debug/Panel.php delete mode 100644 extensions/yii/debug/README.md delete mode 100644 extensions/yii/debug/assets/bg.png delete mode 100644 extensions/yii/debug/assets/main.css delete mode 100644 extensions/yii/debug/assets/toolbar.css delete mode 100644 extensions/yii/debug/assets/toolbar.js delete mode 100644 extensions/yii/debug/components/search/Filter.php delete mode 100644 extensions/yii/debug/components/search/matches/Base.php delete mode 100644 extensions/yii/debug/components/search/matches/Exact.php delete mode 100644 extensions/yii/debug/components/search/matches/Greater.php delete mode 100644 extensions/yii/debug/components/search/matches/Lower.php delete mode 100644 extensions/yii/debug/components/search/matches/MatcherInterface.php delete mode 100644 extensions/yii/debug/composer.json delete mode 100644 extensions/yii/debug/controllers/DefaultController.php delete mode 100644 extensions/yii/debug/models/search/Base.php delete mode 100644 extensions/yii/debug/models/search/Db.php delete mode 100644 extensions/yii/debug/models/search/Debug.php delete mode 100644 extensions/yii/debug/models/search/Log.php delete mode 100644 extensions/yii/debug/models/search/Profile.php delete mode 100644 extensions/yii/debug/panels/ConfigPanel.php delete mode 100644 extensions/yii/debug/panels/DbPanel.php delete mode 100644 extensions/yii/debug/panels/LogPanel.php delete mode 100644 extensions/yii/debug/panels/ProfilingPanel.php delete mode 100644 extensions/yii/debug/panels/RequestPanel.php delete mode 100644 extensions/yii/debug/views/default/index.php delete mode 100644 extensions/yii/debug/views/default/panels/config/detail.php delete mode 100644 extensions/yii/debug/views/default/panels/config/summary.php delete mode 100644 extensions/yii/debug/views/default/panels/config/table.php delete mode 100644 extensions/yii/debug/views/default/panels/db/detail.php delete mode 100644 extensions/yii/debug/views/default/panels/db/summary.php delete mode 100644 extensions/yii/debug/views/default/panels/log/detail.php delete mode 100644 extensions/yii/debug/views/default/panels/log/summary.php delete mode 100644 extensions/yii/debug/views/default/panels/profile/detail.php delete mode 100644 extensions/yii/debug/views/default/panels/profile/summary.php delete mode 100644 extensions/yii/debug/views/default/panels/request/detail.php delete mode 100644 extensions/yii/debug/views/default/panels/request/summary.php delete mode 100644 extensions/yii/debug/views/default/panels/request/table.php delete mode 100644 extensions/yii/debug/views/default/toolbar.php delete mode 100644 extensions/yii/debug/views/default/view.php delete mode 100644 extensions/yii/debug/views/layouts/main.php delete mode 100644 extensions/yii/elasticsearch/ActiveQuery.php delete mode 100644 extensions/yii/elasticsearch/ActiveRecord.php delete mode 100644 extensions/yii/elasticsearch/ActiveRelation.php delete mode 100644 extensions/yii/elasticsearch/CHANGELOG.md delete mode 100644 extensions/yii/elasticsearch/Command.php delete mode 100644 extensions/yii/elasticsearch/Connection.php delete mode 100644 extensions/yii/elasticsearch/DebugAction.php delete mode 100644 extensions/yii/elasticsearch/DebugPanel.php delete mode 100644 extensions/yii/elasticsearch/Exception.php delete mode 100644 extensions/yii/elasticsearch/LICENSE.md delete mode 100644 extensions/yii/elasticsearch/Query.php delete mode 100644 extensions/yii/elasticsearch/QueryBuilder.php delete mode 100644 extensions/yii/elasticsearch/README-debug.png delete mode 100644 extensions/yii/elasticsearch/README.md delete mode 100644 extensions/yii/elasticsearch/composer.json delete mode 100644 extensions/yii/gii/CHANGELOG.md delete mode 100644 extensions/yii/gii/CodeFile.php delete mode 100644 extensions/yii/gii/Generator.php delete mode 100644 extensions/yii/gii/GiiAsset.php delete mode 100644 extensions/yii/gii/Module.php delete mode 100644 extensions/yii/gii/README.md delete mode 100644 extensions/yii/gii/assets/gii.js delete mode 100644 extensions/yii/gii/assets/logo.png delete mode 100644 extensions/yii/gii/assets/main.css delete mode 100644 extensions/yii/gii/assets/typeahead.js delete mode 100644 extensions/yii/gii/assets/typeahead.js-bootstrap.css delete mode 100644 extensions/yii/gii/components/ActiveField.php delete mode 100644 extensions/yii/gii/composer.json delete mode 100644 extensions/yii/gii/controllers/DefaultController.php delete mode 100644 extensions/yii/gii/generators/controller/Generator.php delete mode 100644 extensions/yii/gii/generators/controller/form.php delete mode 100644 extensions/yii/gii/generators/controller/templates/controller.php delete mode 100644 extensions/yii/gii/generators/controller/templates/view.php delete mode 100644 extensions/yii/gii/generators/crud/Generator.php delete mode 100644 extensions/yii/gii/generators/crud/form.php delete mode 100644 extensions/yii/gii/generators/crud/templates/controller.php delete mode 100644 extensions/yii/gii/generators/crud/templates/search.php delete mode 100644 extensions/yii/gii/generators/crud/templates/views/_form.php delete mode 100644 extensions/yii/gii/generators/crud/templates/views/_search.php delete mode 100644 extensions/yii/gii/generators/crud/templates/views/create.php delete mode 100644 extensions/yii/gii/generators/crud/templates/views/index.php delete mode 100644 extensions/yii/gii/generators/crud/templates/views/update.php delete mode 100644 extensions/yii/gii/generators/crud/templates/views/view.php delete mode 100644 extensions/yii/gii/generators/form/Generator.php delete mode 100644 extensions/yii/gii/generators/form/form.php delete mode 100644 extensions/yii/gii/generators/form/templates/action.php delete mode 100644 extensions/yii/gii/generators/form/templates/form.php delete mode 100644 extensions/yii/gii/generators/model/Generator.php delete mode 100644 extensions/yii/gii/generators/model/form.php delete mode 100644 extensions/yii/gii/generators/model/templates/model.php delete mode 100644 extensions/yii/gii/generators/module/Generator.php delete mode 100644 extensions/yii/gii/generators/module/form.php delete mode 100644 extensions/yii/gii/generators/module/templates/controller.php delete mode 100644 extensions/yii/gii/generators/module/templates/module.php delete mode 100644 extensions/yii/gii/generators/module/templates/view.php delete mode 100644 extensions/yii/gii/views/default/diff.php delete mode 100644 extensions/yii/gii/views/default/index.php delete mode 100644 extensions/yii/gii/views/default/view.php delete mode 100644 extensions/yii/gii/views/default/view/files.php delete mode 100644 extensions/yii/gii/views/default/view/results.php delete mode 100644 extensions/yii/gii/views/layouts/generator.php delete mode 100644 extensions/yii/gii/views/layouts/main.php delete mode 100644 extensions/yii/imagine/BaseImage.php delete mode 100644 extensions/yii/imagine/CHANGELOG.md delete mode 100644 extensions/yii/imagine/Image.php delete mode 100644 extensions/yii/imagine/LICENSE.md delete mode 100644 extensions/yii/imagine/README.md delete mode 100644 extensions/yii/imagine/composer.json delete mode 100644 extensions/yii/jui/Accordion.php delete mode 100644 extensions/yii/jui/AccordionAsset.php delete mode 100644 extensions/yii/jui/AutoComplete.php delete mode 100644 extensions/yii/jui/AutoCompleteAsset.php delete mode 100644 extensions/yii/jui/ButtonAsset.php delete mode 100644 extensions/yii/jui/CHANGELOG.md delete mode 100644 extensions/yii/jui/CoreAsset.php delete mode 100644 extensions/yii/jui/DatePicker.php delete mode 100644 extensions/yii/jui/DatePickerAsset.php delete mode 100644 extensions/yii/jui/DatePickerRegionalAsset.php delete mode 100644 extensions/yii/jui/Dialog.php delete mode 100644 extensions/yii/jui/DialogAsset.php delete mode 100644 extensions/yii/jui/Draggable.php delete mode 100644 extensions/yii/jui/DraggableAsset.php delete mode 100644 extensions/yii/jui/Droppable.php delete mode 100644 extensions/yii/jui/DroppableAsset.php delete mode 100644 extensions/yii/jui/EffectAsset.php delete mode 100644 extensions/yii/jui/InputWidget.php delete mode 100644 extensions/yii/jui/LICENSE.md delete mode 100644 extensions/yii/jui/Menu.php delete mode 100644 extensions/yii/jui/MenuAsset.php delete mode 100644 extensions/yii/jui/ProgressBar.php delete mode 100644 extensions/yii/jui/ProgressBarAsset.php delete mode 100644 extensions/yii/jui/README.md delete mode 100644 extensions/yii/jui/Resizable.php delete mode 100644 extensions/yii/jui/ResizableAsset.php delete mode 100644 extensions/yii/jui/Selectable.php delete mode 100644 extensions/yii/jui/SelectableAsset.php delete mode 100644 extensions/yii/jui/Slider.php delete mode 100644 extensions/yii/jui/SliderAsset.php delete mode 100644 extensions/yii/jui/SliderInput.php delete mode 100644 extensions/yii/jui/Sortable.php delete mode 100644 extensions/yii/jui/SortableAsset.php delete mode 100644 extensions/yii/jui/Spinner.php delete mode 100644 extensions/yii/jui/SpinnerAsset.php delete mode 100644 extensions/yii/jui/Tabs.php delete mode 100644 extensions/yii/jui/TabsAsset.php delete mode 100644 extensions/yii/jui/ThemeAsset.php delete mode 100644 extensions/yii/jui/TooltipAsset.php delete mode 100644 extensions/yii/jui/Widget.php delete mode 100644 extensions/yii/jui/assets/UPGRADE.md delete mode 100644 extensions/yii/jui/assets/jquery.ui.accordion.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.autocomplete.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.button.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.core.js delete mode 100755 extensions/yii/jui/assets/jquery.ui.datepicker-i18n.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.datepicker.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.dialog.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.draggable.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.droppable.js delete mode 100755 extensions/yii/jui/assets/jquery.ui.effect-all.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.menu.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.mouse.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.position.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.progressbar.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.resizable.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.selectable.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.slider.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.sortable.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.spinner.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.tabs.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.tooltip.js delete mode 100644 extensions/yii/jui/assets/jquery.ui.widget.js delete mode 100755 extensions/yii/jui/assets/theme/images/animated-overlay.gif delete mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_flat_0_aaaaaa_40x100.png delete mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_flat_75_ffffff_40x100.png delete mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_glass_55_fbf9ee_1x400.png delete mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_glass_65_ffffff_1x400.png delete mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_glass_75_dadada_1x400.png delete mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_glass_75_e6e6e6_1x400.png delete mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_glass_95_fef1ec_1x400.png delete mode 100755 extensions/yii/jui/assets/theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png delete mode 100755 extensions/yii/jui/assets/theme/images/ui-icons_222222_256x240.png delete mode 100755 extensions/yii/jui/assets/theme/images/ui-icons_2e83ff_256x240.png delete mode 100755 extensions/yii/jui/assets/theme/images/ui-icons_454545_256x240.png delete mode 100755 extensions/yii/jui/assets/theme/images/ui-icons_888888_256x240.png delete mode 100755 extensions/yii/jui/assets/theme/images/ui-icons_cd0a0a_256x240.png delete mode 100755 extensions/yii/jui/assets/theme/jquery.ui.css delete mode 100644 extensions/yii/jui/composer.json delete mode 100644 extensions/yii/mongodb/ActiveQuery.php delete mode 100644 extensions/yii/mongodb/ActiveRecord.php delete mode 100644 extensions/yii/mongodb/ActiveRelation.php delete mode 100644 extensions/yii/mongodb/CHANGELOG.md delete mode 100644 extensions/yii/mongodb/Collection.php delete mode 100644 extensions/yii/mongodb/Connection.php delete mode 100644 extensions/yii/mongodb/Database.php delete mode 100644 extensions/yii/mongodb/Exception.php delete mode 100644 extensions/yii/mongodb/LICENSE.md delete mode 100644 extensions/yii/mongodb/Query.php delete mode 100644 extensions/yii/mongodb/README.md delete mode 100644 extensions/yii/mongodb/composer.json delete mode 100644 extensions/yii/mongodb/file/ActiveQuery.php delete mode 100644 extensions/yii/mongodb/file/ActiveRecord.php delete mode 100644 extensions/yii/mongodb/file/ActiveRelation.php delete mode 100644 extensions/yii/mongodb/file/Collection.php delete mode 100644 extensions/yii/mongodb/file/Query.php delete mode 100644 extensions/yii/redis/ActiveQuery.php delete mode 100644 extensions/yii/redis/ActiveRecord.php delete mode 100644 extensions/yii/redis/ActiveRelation.php delete mode 100644 extensions/yii/redis/CHANGELOG.md delete mode 100644 extensions/yii/redis/Cache.php delete mode 100644 extensions/yii/redis/Connection.php delete mode 100644 extensions/yii/redis/LICENSE.md delete mode 100644 extensions/yii/redis/LuaScriptBuilder.php delete mode 100644 extensions/yii/redis/README.md delete mode 100644 extensions/yii/redis/Session.php delete mode 100644 extensions/yii/redis/composer.json delete mode 100644 extensions/yii/smarty/CHANGELOG.md delete mode 100644 extensions/yii/smarty/LICENSE.md delete mode 100644 extensions/yii/smarty/README.md delete mode 100644 extensions/yii/smarty/ViewRenderer.php delete mode 100644 extensions/yii/smarty/composer.json delete mode 100644 extensions/yii/sphinx/ActiveQuery.php delete mode 100644 extensions/yii/sphinx/ActiveRecord.php delete mode 100644 extensions/yii/sphinx/ActiveRelation.php delete mode 100644 extensions/yii/sphinx/CHANGELOG.md delete mode 100644 extensions/yii/sphinx/ColumnSchema.php delete mode 100644 extensions/yii/sphinx/Command.php delete mode 100644 extensions/yii/sphinx/Connection.php delete mode 100644 extensions/yii/sphinx/IndexSchema.php delete mode 100644 extensions/yii/sphinx/LICENSE.md delete mode 100644 extensions/yii/sphinx/Query.php delete mode 100644 extensions/yii/sphinx/QueryBuilder.php delete mode 100644 extensions/yii/sphinx/README.md delete mode 100644 extensions/yii/sphinx/Schema.php delete mode 100644 extensions/yii/sphinx/composer.json delete mode 100644 extensions/yii/swiftmailer/CHANGELOG.md delete mode 100644 extensions/yii/swiftmailer/LICENSE.md delete mode 100644 extensions/yii/swiftmailer/Mailer.php delete mode 100644 extensions/yii/swiftmailer/Message.php delete mode 100644 extensions/yii/swiftmailer/README.md delete mode 100644 extensions/yii/swiftmailer/composer.json delete mode 100644 framework/CHANGELOG.md delete mode 100644 framework/LICENSE.md delete mode 100644 framework/README.md delete mode 100644 framework/UPGRADE.md delete mode 100644 framework/composer.json delete mode 100644 framework/yii/.gitignore delete mode 100644 framework/yii/.htaccess delete mode 100644 framework/yii/BaseYii.php delete mode 100644 framework/yii/Yii.php delete mode 100644 framework/yii/assets/jquery.maskedinput.js delete mode 100644 framework/yii/assets/punycode/LICENSE-GPL.txt delete mode 100644 framework/yii/assets/punycode/LICENSE-MIT.txt delete mode 100644 framework/yii/assets/punycode/punycode.js delete mode 100644 framework/yii/assets/punycode/punycode.min.js delete mode 100644 framework/yii/assets/yii.activeForm.js delete mode 100644 framework/yii/assets/yii.captcha.js delete mode 100644 framework/yii/assets/yii.gridView.js delete mode 100644 framework/yii/assets/yii.js delete mode 100644 framework/yii/assets/yii.validation.js delete mode 100644 framework/yii/base/Action.php delete mode 100644 framework/yii/base/ActionEvent.php delete mode 100644 framework/yii/base/ActionFilter.php delete mode 100644 framework/yii/base/Application.php delete mode 100644 framework/yii/base/Arrayable.php delete mode 100644 framework/yii/base/Behavior.php delete mode 100644 framework/yii/base/Component.php delete mode 100644 framework/yii/base/Controller.php delete mode 100644 framework/yii/base/ErrorException.php delete mode 100644 framework/yii/base/ErrorHandler.php delete mode 100644 framework/yii/base/Event.php delete mode 100644 framework/yii/base/Exception.php delete mode 100644 framework/yii/base/Extension.php delete mode 100644 framework/yii/base/Formatter.php delete mode 100644 framework/yii/base/InlineAction.php delete mode 100644 framework/yii/base/InvalidCallException.php delete mode 100644 framework/yii/base/InvalidConfigException.php delete mode 100644 framework/yii/base/InvalidParamException.php delete mode 100644 framework/yii/base/InvalidRouteException.php delete mode 100644 framework/yii/base/MailEvent.php delete mode 100644 framework/yii/base/Model.php delete mode 100644 framework/yii/base/ModelEvent.php delete mode 100644 framework/yii/base/Module.php delete mode 100644 framework/yii/base/NotSupportedException.php delete mode 100644 framework/yii/base/Object.php delete mode 100644 framework/yii/base/Request.php delete mode 100644 framework/yii/base/Response.php delete mode 100644 framework/yii/base/Theme.php delete mode 100644 framework/yii/base/UnknownClassException.php delete mode 100644 framework/yii/base/UnknownMethodException.php delete mode 100644 framework/yii/base/UnknownPropertyException.php delete mode 100644 framework/yii/base/UserException.php delete mode 100644 framework/yii/base/View.php delete mode 100644 framework/yii/base/ViewContextInterface.php delete mode 100644 framework/yii/base/ViewEvent.php delete mode 100644 framework/yii/base/ViewRenderer.php delete mode 100644 framework/yii/base/Widget.php delete mode 100644 framework/yii/behaviors/AutoTimestamp.php delete mode 100644 framework/yii/caching/ApcCache.php delete mode 100644 framework/yii/caching/Cache.php delete mode 100644 framework/yii/caching/ChainedDependency.php delete mode 100644 framework/yii/caching/DbCache.php delete mode 100644 framework/yii/caching/DbDependency.php delete mode 100644 framework/yii/caching/Dependency.php delete mode 100644 framework/yii/caching/DummyCache.php delete mode 100644 framework/yii/caching/ExpressionDependency.php delete mode 100644 framework/yii/caching/FileCache.php delete mode 100644 framework/yii/caching/FileDependency.php delete mode 100644 framework/yii/caching/GroupDependency.php delete mode 100644 framework/yii/caching/MemCache.php delete mode 100644 framework/yii/caching/MemCacheServer.php delete mode 100644 framework/yii/caching/WinCache.php delete mode 100644 framework/yii/caching/XCache.php delete mode 100644 framework/yii/caching/ZendDataCache.php delete mode 100644 framework/yii/captcha/Captcha.php delete mode 100644 framework/yii/captcha/CaptchaAction.php delete mode 100644 framework/yii/captcha/CaptchaAsset.php delete mode 100644 framework/yii/captcha/CaptchaValidator.php delete mode 100644 framework/yii/captcha/SpicyRice.md delete mode 100644 framework/yii/captcha/SpicyRice.ttf delete mode 100644 framework/yii/classes.php delete mode 100644 framework/yii/console/Application.php delete mode 100644 framework/yii/console/Controller.php delete mode 100644 framework/yii/console/Exception.php delete mode 100644 framework/yii/console/Request.php delete mode 100644 framework/yii/console/Response.php delete mode 100644 framework/yii/console/controllers/AssetController.php delete mode 100644 framework/yii/console/controllers/CacheController.php delete mode 100644 framework/yii/console/controllers/FixtureController.php delete mode 100644 framework/yii/console/controllers/HelpController.php delete mode 100644 framework/yii/console/controllers/MessageController.php delete mode 100644 framework/yii/console/controllers/MigrateController.php delete mode 100644 framework/yii/console/runtime/.gitignore delete mode 100644 framework/yii/data/ActiveDataProvider.php delete mode 100644 framework/yii/data/ArrayDataProvider.php delete mode 100644 framework/yii/data/BaseDataProvider.php delete mode 100644 framework/yii/data/DataProviderInterface.php delete mode 100644 framework/yii/data/Pagination.php delete mode 100644 framework/yii/data/Sort.php delete mode 100644 framework/yii/data/SqlDataProvider.php delete mode 100644 framework/yii/db/ActiveQuery.php delete mode 100644 framework/yii/db/ActiveQueryInterface.php delete mode 100644 framework/yii/db/ActiveQueryTrait.php delete mode 100644 framework/yii/db/ActiveRecord.php delete mode 100644 framework/yii/db/ActiveRecordInterface.php delete mode 100644 framework/yii/db/ActiveRelation.php delete mode 100644 framework/yii/db/ActiveRelationInterface.php delete mode 100644 framework/yii/db/ActiveRelationTrait.php delete mode 100644 framework/yii/db/BaseActiveRecord.php delete mode 100644 framework/yii/db/ColumnSchema.php delete mode 100644 framework/yii/db/Command.php delete mode 100644 framework/yii/db/Connection.php delete mode 100644 framework/yii/db/DataReader.php delete mode 100644 framework/yii/db/Exception.php delete mode 100644 framework/yii/db/Expression.php delete mode 100644 framework/yii/db/Migration.php delete mode 100644 framework/yii/db/Query.php delete mode 100644 framework/yii/db/QueryBuilder.php delete mode 100644 framework/yii/db/QueryInterface.php delete mode 100644 framework/yii/db/QueryTrait.php delete mode 100644 framework/yii/db/Schema.php delete mode 100644 framework/yii/db/StaleObjectException.php delete mode 100644 framework/yii/db/TableSchema.php delete mode 100644 framework/yii/db/Transaction.php delete mode 100644 framework/yii/db/cubrid/QueryBuilder.php delete mode 100644 framework/yii/db/cubrid/Schema.php delete mode 100644 framework/yii/db/mssql/PDO.php delete mode 100644 framework/yii/db/mssql/QueryBuilder.php delete mode 100644 framework/yii/db/mssql/Schema.php delete mode 100644 framework/yii/db/mssql/SqlsrvPDO.php delete mode 100644 framework/yii/db/mssql/TableSchema.php delete mode 100644 framework/yii/db/mysql/QueryBuilder.php delete mode 100644 framework/yii/db/mysql/Schema.php delete mode 100644 framework/yii/db/oci/QueryBuilder.php delete mode 100644 framework/yii/db/oci/Schema.php delete mode 100644 framework/yii/db/pgsql/QueryBuilder.php delete mode 100644 framework/yii/db/pgsql/Schema.php delete mode 100644 framework/yii/db/sqlite/QueryBuilder.php delete mode 100644 framework/yii/db/sqlite/Schema.php delete mode 100644 framework/yii/grid/ActionColumn.php delete mode 100644 framework/yii/grid/CheckboxColumn.php delete mode 100644 framework/yii/grid/Column.php delete mode 100644 framework/yii/grid/DataColumn.php delete mode 100644 framework/yii/grid/GridView.php delete mode 100644 framework/yii/grid/GridViewAsset.php delete mode 100644 framework/yii/grid/SerialColumn.php delete mode 100644 framework/yii/helpers/ArrayHelper.php delete mode 100644 framework/yii/helpers/BaseArrayHelper.php delete mode 100644 framework/yii/helpers/BaseConsole.php delete mode 100644 framework/yii/helpers/BaseFileHelper.php delete mode 100644 framework/yii/helpers/BaseHtml.php delete mode 100644 framework/yii/helpers/BaseHtmlPurifier.php delete mode 100644 framework/yii/helpers/BaseInflector.php delete mode 100644 framework/yii/helpers/BaseJson.php delete mode 100644 framework/yii/helpers/BaseMarkdown.php delete mode 100644 framework/yii/helpers/BaseSecurity.php delete mode 100644 framework/yii/helpers/BaseStringHelper.php delete mode 100644 framework/yii/helpers/BaseVarDumper.php delete mode 100644 framework/yii/helpers/Console.php delete mode 100644 framework/yii/helpers/FileHelper.php delete mode 100644 framework/yii/helpers/Html.php delete mode 100644 framework/yii/helpers/HtmlPurifier.php delete mode 100644 framework/yii/helpers/Inflector.php delete mode 100644 framework/yii/helpers/Json.php delete mode 100644 framework/yii/helpers/Markdown.php delete mode 100644 framework/yii/helpers/Security.php delete mode 100644 framework/yii/helpers/StringHelper.php delete mode 100644 framework/yii/helpers/VarDumper.php delete mode 100644 framework/yii/helpers/mimeTypes.php delete mode 100644 framework/yii/i18n/DbMessageSource.php delete mode 100644 framework/yii/i18n/Formatter.php delete mode 100644 framework/yii/i18n/GettextFile.php delete mode 100644 framework/yii/i18n/GettextMessageSource.php delete mode 100644 framework/yii/i18n/GettextMoFile.php delete mode 100644 framework/yii/i18n/GettextPoFile.php delete mode 100644 framework/yii/i18n/I18N.php delete mode 100644 framework/yii/i18n/MessageFormatter.php delete mode 100644 framework/yii/i18n/MessageSource.php delete mode 100644 framework/yii/i18n/MissingTranslationEvent.php delete mode 100644 framework/yii/i18n/PhpMessageSource.php delete mode 100644 framework/yii/log/DbTarget.php delete mode 100644 framework/yii/log/EmailTarget.php delete mode 100644 framework/yii/log/FileTarget.php delete mode 100644 framework/yii/log/Logger.php delete mode 100644 framework/yii/log/Target.php delete mode 100644 framework/yii/mail/BaseMailer.php delete mode 100644 framework/yii/mail/BaseMessage.php delete mode 100644 framework/yii/mail/MailerInterface.php delete mode 100644 framework/yii/mail/MessageInterface.php delete mode 100644 framework/yii/messages/config.php delete mode 100644 framework/yii/messages/da/yii.php delete mode 100644 framework/yii/messages/de/yii.php delete mode 100644 framework/yii/messages/es/yii.php delete mode 100644 framework/yii/messages/it/yii.php delete mode 100644 framework/yii/messages/ja/yii.php delete mode 100644 framework/yii/messages/pl/yii.php delete mode 100644 framework/yii/messages/pt-BR/yii.php delete mode 100644 framework/yii/messages/ro/yii.php delete mode 100644 framework/yii/messages/ru/yii.php delete mode 100644 framework/yii/messages/zh_cn/yii.php delete mode 100644 framework/yii/mutex/DbMutex.php delete mode 100644 framework/yii/mutex/FileMutex.php delete mode 100644 framework/yii/mutex/Mutex.php delete mode 100644 framework/yii/mutex/MysqlMutex.php delete mode 100644 framework/yii/rbac/Assignment.php delete mode 100644 framework/yii/rbac/DbManager.php delete mode 100644 framework/yii/rbac/Item.php delete mode 100644 framework/yii/rbac/Manager.php delete mode 100644 framework/yii/rbac/PhpManager.php delete mode 100644 framework/yii/rbac/schema-mssql.sql delete mode 100644 framework/yii/rbac/schema-mysql.sql delete mode 100644 framework/yii/rbac/schema-oci.sql delete mode 100644 framework/yii/rbac/schema-pgsql.sql delete mode 100644 framework/yii/rbac/schema-sqlite.sql delete mode 100644 framework/yii/requirements/YiiRequirementChecker.php delete mode 100644 framework/yii/requirements/requirements.php delete mode 100644 framework/yii/requirements/views/console/index.php delete mode 100644 framework/yii/requirements/views/web/css.php delete mode 100644 framework/yii/requirements/views/web/index.php delete mode 100644 framework/yii/test/DbFixtureManager.php delete mode 100644 framework/yii/test/DbTestTrait.php delete mode 100644 framework/yii/validators/BooleanValidator.php delete mode 100644 framework/yii/validators/CompareValidator.php delete mode 100644 framework/yii/validators/DateValidator.php delete mode 100644 framework/yii/validators/DefaultValueValidator.php delete mode 100644 framework/yii/validators/EmailValidator.php delete mode 100644 framework/yii/validators/ExistValidator.php delete mode 100644 framework/yii/validators/FileValidator.php delete mode 100644 framework/yii/validators/FilterValidator.php delete mode 100644 framework/yii/validators/ImageValidator.php delete mode 100644 framework/yii/validators/InlineValidator.php delete mode 100644 framework/yii/validators/NumberValidator.php delete mode 100644 framework/yii/validators/PunycodeAsset.php delete mode 100644 framework/yii/validators/RangeValidator.php delete mode 100644 framework/yii/validators/RegularExpressionValidator.php delete mode 100644 framework/yii/validators/RequiredValidator.php delete mode 100644 framework/yii/validators/SafeValidator.php delete mode 100644 framework/yii/validators/StringValidator.php delete mode 100644 framework/yii/validators/UniqueValidator.php delete mode 100644 framework/yii/validators/UrlValidator.php delete mode 100644 framework/yii/validators/ValidationAsset.php delete mode 100644 framework/yii/validators/Validator.php delete mode 100644 framework/yii/views/errorHandler/callStackItem.php delete mode 100644 framework/yii/views/errorHandler/error.php delete mode 100644 framework/yii/views/errorHandler/exception.php delete mode 100644 framework/yii/views/errorHandler/previousException.php delete mode 100644 framework/yii/views/messageConfig.php delete mode 100644 framework/yii/views/migration.php delete mode 100644 framework/yii/web/AccessControl.php delete mode 100644 framework/yii/web/AccessDeniedHttpException.php delete mode 100644 framework/yii/web/AccessRule.php delete mode 100644 framework/yii/web/Application.php delete mode 100644 framework/yii/web/AssetBundle.php delete mode 100644 framework/yii/web/AssetConverter.php delete mode 100644 framework/yii/web/AssetConverterInterface.php delete mode 100644 framework/yii/web/AssetManager.php delete mode 100644 framework/yii/web/BadRequestHttpException.php delete mode 100644 framework/yii/web/CacheSession.php delete mode 100644 framework/yii/web/Controller.php delete mode 100644 framework/yii/web/Cookie.php delete mode 100644 framework/yii/web/CookieCollection.php delete mode 100644 framework/yii/web/DbSession.php delete mode 100644 framework/yii/web/ErrorAction.php delete mode 100644 framework/yii/web/HeaderCollection.php delete mode 100644 framework/yii/web/HttpCache.php delete mode 100644 framework/yii/web/HttpException.php delete mode 100644 framework/yii/web/IdentityInterface.php delete mode 100644 framework/yii/web/JqueryAsset.php delete mode 100644 framework/yii/web/JsExpression.php delete mode 100644 framework/yii/web/MethodNotAllowedHttpException.php delete mode 100644 framework/yii/web/NotFoundHttpException.php delete mode 100644 framework/yii/web/PageCache.php delete mode 100644 framework/yii/web/Request.php delete mode 100644 framework/yii/web/Response.php delete mode 100644 framework/yii/web/ResponseFormatterInterface.php delete mode 100644 framework/yii/web/Session.php delete mode 100644 framework/yii/web/SessionIterator.php delete mode 100644 framework/yii/web/UploadedFile.php delete mode 100644 framework/yii/web/UrlManager.php delete mode 100644 framework/yii/web/UrlRule.php delete mode 100644 framework/yii/web/User.php delete mode 100644 framework/yii/web/UserEvent.php delete mode 100644 framework/yii/web/VerbFilter.php delete mode 100644 framework/yii/web/View.php delete mode 100644 framework/yii/web/XmlResponseFormatter.php delete mode 100644 framework/yii/web/YiiAsset.php delete mode 100644 framework/yii/widgets/ActiveField.php delete mode 100644 framework/yii/widgets/ActiveForm.php delete mode 100644 framework/yii/widgets/ActiveFormAsset.php delete mode 100644 framework/yii/widgets/BaseListView.php delete mode 100644 framework/yii/widgets/Block.php delete mode 100644 framework/yii/widgets/Breadcrumbs.php delete mode 100644 framework/yii/widgets/ContentDecorator.php delete mode 100644 framework/yii/widgets/DetailView.php delete mode 100644 framework/yii/widgets/FragmentCache.php delete mode 100644 framework/yii/widgets/InputWidget.php delete mode 100644 framework/yii/widgets/LinkPager.php delete mode 100644 framework/yii/widgets/LinkSorter.php delete mode 100644 framework/yii/widgets/ListView.php delete mode 100644 framework/yii/widgets/MaskedInput.php delete mode 100644 framework/yii/widgets/MaskedInputAsset.php delete mode 100644 framework/yii/widgets/Menu.php delete mode 100644 framework/yii/widgets/Spaceless.php delete mode 100755 framework/yii/yii delete mode 100644 framework/yii/yii.bat delete mode 100644 phpunit.xml.dist delete mode 100644 tests/README.md delete mode 100644 tests/unit/.gitignore delete mode 100644 tests/unit/TestCase.php delete mode 100644 tests/unit/VendorTestCase.php delete mode 100644 tests/unit/bootstrap.php delete mode 100644 tests/unit/data/ar/ActiveRecord.php delete mode 100644 tests/unit/data/ar/Category.php delete mode 100644 tests/unit/data/ar/Customer.php delete mode 100644 tests/unit/data/ar/Item.php delete mode 100644 tests/unit/data/ar/NullValues.php delete mode 100644 tests/unit/data/ar/Order.php delete mode 100644 tests/unit/data/ar/OrderItem.php delete mode 100644 tests/unit/data/ar/elasticsearch/ActiveRecord.php delete mode 100644 tests/unit/data/ar/elasticsearch/Customer.php delete mode 100644 tests/unit/data/ar/elasticsearch/Item.php delete mode 100644 tests/unit/data/ar/elasticsearch/Order.php delete mode 100644 tests/unit/data/ar/elasticsearch/OrderItem.php delete mode 100644 tests/unit/data/ar/mongodb/ActiveRecord.php delete mode 100644 tests/unit/data/ar/mongodb/Customer.php delete mode 100644 tests/unit/data/ar/mongodb/CustomerOrder.php delete mode 100644 tests/unit/data/ar/mongodb/file/ActiveRecord.php delete mode 100644 tests/unit/data/ar/mongodb/file/CustomerFile.php delete mode 100644 tests/unit/data/ar/redis/ActiveRecord.php delete mode 100644 tests/unit/data/ar/redis/Customer.php delete mode 100644 tests/unit/data/ar/redis/Item.php delete mode 100644 tests/unit/data/ar/redis/Order.php delete mode 100644 tests/unit/data/ar/redis/OrderItem.php delete mode 100644 tests/unit/data/ar/sphinx/ActiveRecord.php delete mode 100644 tests/unit/data/ar/sphinx/ArticleDb.php delete mode 100644 tests/unit/data/ar/sphinx/ArticleIndex.php delete mode 100644 tests/unit/data/ar/sphinx/ItemDb.php delete mode 100644 tests/unit/data/ar/sphinx/ItemIndex.php delete mode 100644 tests/unit/data/ar/sphinx/RuntimeIndex.php delete mode 100644 tests/unit/data/ar/sphinx/TagDb.php delete mode 100644 tests/unit/data/base/InvalidRulesModel.php delete mode 100644 tests/unit/data/base/Singer.php delete mode 100644 tests/unit/data/base/Speaker.php delete mode 100644 tests/unit/data/config.php delete mode 100644 tests/unit/data/cubrid.sql delete mode 100644 tests/unit/data/i18n/messages/de-DE/test.php delete mode 100644 tests/unit/data/i18n/messages/en-US/test.php delete mode 100644 tests/unit/data/i18n/test.mo delete mode 100644 tests/unit/data/i18n/test.po delete mode 100644 tests/unit/data/imagine/GothamRnd-Light.otf delete mode 100644 tests/unit/data/imagine/large.jpg delete mode 100644 tests/unit/data/imagine/xparent.gif delete mode 100644 tests/unit/data/mssql.sql delete mode 100644 tests/unit/data/mysql.sql delete mode 100644 tests/unit/data/postgres.sql delete mode 100644 tests/unit/data/sphinx/source.sql delete mode 100644 tests/unit/data/sphinx/sphinx.conf delete mode 100644 tests/unit/data/sqlite.sql delete mode 100644 tests/unit/data/travis/README.md delete mode 100755 tests/unit/data/travis/apc-setup.sh delete mode 100755 tests/unit/data/travis/cubrid-setup.sh delete mode 100644 tests/unit/data/travis/cubrid-solo.rb delete mode 100755 tests/unit/data/travis/memcache-setup.sh delete mode 100755 tests/unit/data/travis/mongodb-setup.sh delete mode 100755 tests/unit/data/travis/sphinx-setup.sh delete mode 100644 tests/unit/data/validators/TestValidator.php delete mode 100644 tests/unit/data/validators/models/FakedValidationModel.php delete mode 100644 tests/unit/data/validators/models/ValidatorTestMainModel.php delete mode 100644 tests/unit/data/validators/models/ValidatorTestRefModel.php delete mode 100644 tests/unit/data/views/layout.php delete mode 100644 tests/unit/data/views/rawlayout.php delete mode 100644 tests/unit/data/views/simple.php delete mode 100644 tests/unit/data/web/assets/.gitignore delete mode 100644 tests/unit/data/web/data.txt delete mode 100644 tests/unit/extensions/authclient/AuthActionTest.php delete mode 100644 tests/unit/extensions/authclient/BaseClientTest.php delete mode 100644 tests/unit/extensions/authclient/BaseOAuthTest.php delete mode 100644 tests/unit/extensions/authclient/CollectionTest.php delete mode 100644 tests/unit/extensions/authclient/OAuth1Test.php delete mode 100644 tests/unit/extensions/authclient/OAuth2Test.php delete mode 100644 tests/unit/extensions/authclient/OpenIdTest.php delete mode 100644 tests/unit/extensions/authclient/TestCase.php delete mode 100644 tests/unit/extensions/authclient/TokenTest.php delete mode 100644 tests/unit/extensions/authclient/signature/BaseMethodTest.php delete mode 100644 tests/unit/extensions/authclient/signature/HmacSha1Test.php delete mode 100644 tests/unit/extensions/authclient/signature/PlainTextTest.php delete mode 100644 tests/unit/extensions/authclient/signature/RsaSha1Test.php delete mode 100644 tests/unit/extensions/elasticsearch/ActiveRecordTest.php delete mode 100644 tests/unit/extensions/elasticsearch/ElasticSearchConnectionTest.php delete mode 100644 tests/unit/extensions/elasticsearch/ElasticSearchTestCase.php delete mode 100644 tests/unit/extensions/elasticsearch/QueryTest.php delete mode 100644 tests/unit/extensions/imagine/AbstractImageTest.php delete mode 100644 tests/unit/extensions/imagine/ImageGdTest.php delete mode 100644 tests/unit/extensions/imagine/ImageGmagickTest.php delete mode 100644 tests/unit/extensions/imagine/ImageImagickTest.php delete mode 100644 tests/unit/extensions/mongodb/ActiveDataProviderTest.php delete mode 100644 tests/unit/extensions/mongodb/ActiveRecordTest.php delete mode 100644 tests/unit/extensions/mongodb/ActiveRelationTest.php delete mode 100644 tests/unit/extensions/mongodb/CollectionTest.php delete mode 100644 tests/unit/extensions/mongodb/ConnectionTest.php delete mode 100644 tests/unit/extensions/mongodb/DatabaseTest.php delete mode 100644 tests/unit/extensions/mongodb/MongoDbTestCase.php delete mode 100644 tests/unit/extensions/mongodb/QueryRunTest.php delete mode 100644 tests/unit/extensions/mongodb/QueryTest.php delete mode 100644 tests/unit/extensions/mongodb/file/ActiveRecordTest.php delete mode 100644 tests/unit/extensions/mongodb/file/CollectionTest.php delete mode 100644 tests/unit/extensions/mongodb/file/QueryTest.php delete mode 100644 tests/unit/extensions/redis/ActiveRecordTest.php delete mode 100644 tests/unit/extensions/redis/RedisCacheTest.php delete mode 100644 tests/unit/extensions/redis/RedisConnectionTest.php delete mode 100644 tests/unit/extensions/redis/RedisTestCase.php delete mode 100644 tests/unit/extensions/sphinx/ActiveDataProviderTest.php delete mode 100644 tests/unit/extensions/sphinx/ActiveRecordTest.php delete mode 100644 tests/unit/extensions/sphinx/ActiveRelationTest.php delete mode 100644 tests/unit/extensions/sphinx/ColumnSchemaTest.php delete mode 100644 tests/unit/extensions/sphinx/CommandTest.php delete mode 100644 tests/unit/extensions/sphinx/ConnectionTest.php delete mode 100644 tests/unit/extensions/sphinx/ExternalActiveRelationTest.php delete mode 100644 tests/unit/extensions/sphinx/QueryTest.php delete mode 100644 tests/unit/extensions/sphinx/SchemaTest.php delete mode 100644 tests/unit/extensions/sphinx/SphinxTestCase.php delete mode 100644 tests/unit/extensions/swiftmailer/MailerTest.php delete mode 100644 tests/unit/extensions/swiftmailer/MessageTest.php delete mode 100644 tests/unit/extensions/twig/ViewRendererTest.php delete mode 100644 tests/unit/extensions/twig/views/layout.twig delete mode 100644 tests/unit/framework/BaseYiiTest.php delete mode 100644 tests/unit/framework/ar/ActiveRecordTestTrait.php delete mode 100644 tests/unit/framework/base/BehaviorTest.php delete mode 100644 tests/unit/framework/base/ComponentTest.php delete mode 100644 tests/unit/framework/base/EventTest.php delete mode 100644 tests/unit/framework/base/ExceptionTest.php delete mode 100644 tests/unit/framework/base/FormatterTest.php delete mode 100644 tests/unit/framework/base/ModelTest.php delete mode 100644 tests/unit/framework/base/ObjectTest.php delete mode 100644 tests/unit/framework/behaviors/AutoTimestampTest.php delete mode 100644 tests/unit/framework/caching/ApcCacheTest.php delete mode 100644 tests/unit/framework/caching/CacheTestCase.php delete mode 100644 tests/unit/framework/caching/DbCacheTest.php delete mode 100644 tests/unit/framework/caching/FileCacheTest.php delete mode 100644 tests/unit/framework/caching/MemCacheTest.php delete mode 100644 tests/unit/framework/caching/MemCachedTest.php delete mode 100644 tests/unit/framework/caching/WinCacheTest.php delete mode 100644 tests/unit/framework/caching/XCacheTest.php delete mode 100644 tests/unit/framework/caching/ZendDataCacheTest.php delete mode 100644 tests/unit/framework/console/controllers/AssetControllerTest.php delete mode 100644 tests/unit/framework/console/controllers/MessageControllerTest.php delete mode 100644 tests/unit/framework/data/ActiveDataProviderTest.php delete mode 100644 tests/unit/framework/data/SortTest.php delete mode 100644 tests/unit/framework/db/ActiveRecordTest.php delete mode 100644 tests/unit/framework/db/CommandTest.php delete mode 100644 tests/unit/framework/db/ConnectionTest.php delete mode 100644 tests/unit/framework/db/DatabaseTestCase.php delete mode 100644 tests/unit/framework/db/QueryBuilderTest.php delete mode 100644 tests/unit/framework/db/QueryTest.php delete mode 100644 tests/unit/framework/db/SchemaTest.php delete mode 100644 tests/unit/framework/db/cubrid/CubridActiveDataProviderTest.php delete mode 100644 tests/unit/framework/db/cubrid/CubridActiveRecordTest.php delete mode 100644 tests/unit/framework/db/cubrid/CubridCommandTest.php delete mode 100644 tests/unit/framework/db/cubrid/CubridConnectionTest.php delete mode 100644 tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php delete mode 100644 tests/unit/framework/db/cubrid/CubridQueryTest.php delete mode 100644 tests/unit/framework/db/cubrid/CubridSchemaTest.php delete mode 100644 tests/unit/framework/db/mssql/MssqlActiveDataProviderTest.php delete mode 100644 tests/unit/framework/db/mssql/MssqlActiveRecordTest.php delete mode 100644 tests/unit/framework/db/mssql/MssqlCommandTest.php delete mode 100644 tests/unit/framework/db/mssql/MssqlConnectionTest.php delete mode 100644 tests/unit/framework/db/mssql/MssqlQueryTest.php delete mode 100644 tests/unit/framework/db/pgsql/PostgreSQLActiveDataProviderTest.php delete mode 100644 tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php delete mode 100644 tests/unit/framework/db/pgsql/PostgreSQLConnectionTest.php delete mode 100644 tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php delete mode 100644 tests/unit/framework/db/sqlite/SqliteActiveDataProviderTest.php delete mode 100644 tests/unit/framework/db/sqlite/SqliteActiveRecordTest.php delete mode 100644 tests/unit/framework/db/sqlite/SqliteCommandTest.php delete mode 100644 tests/unit/framework/db/sqlite/SqliteConnectionTest.php delete mode 100644 tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php delete mode 100644 tests/unit/framework/db/sqlite/SqliteQueryTest.php delete mode 100644 tests/unit/framework/db/sqlite/SqliteSchemaTest.php delete mode 100644 tests/unit/framework/helpers/ArrayHelperTest.php delete mode 100644 tests/unit/framework/helpers/ConsoleTest.php delete mode 100644 tests/unit/framework/helpers/FileHelperTest.php delete mode 100644 tests/unit/framework/helpers/HtmlTest.php delete mode 100644 tests/unit/framework/helpers/InflectorTest.php delete mode 100644 tests/unit/framework/helpers/JsonTest.php delete mode 100644 tests/unit/framework/helpers/SecurityTest.php delete mode 100644 tests/unit/framework/helpers/StringHelperTest.php delete mode 100644 tests/unit/framework/helpers/VarDumperTest.php delete mode 100644 tests/unit/framework/i18n/FallbackMessageFormatterTest.php delete mode 100644 tests/unit/framework/i18n/FormatterTest.php delete mode 100644 tests/unit/framework/i18n/GettextMessageSourceTest.php delete mode 100644 tests/unit/framework/i18n/GettextMoFileTest.php delete mode 100644 tests/unit/framework/i18n/GettextPoFileTest.php delete mode 100644 tests/unit/framework/i18n/I18NTest.php delete mode 100644 tests/unit/framework/i18n/MessageFormatterTest.php delete mode 100644 tests/unit/framework/log/LoggerTest.php delete mode 100644 tests/unit/framework/log/TargetTest.php delete mode 100644 tests/unit/framework/mail/BaseMailerTest.php delete mode 100644 tests/unit/framework/mail/BaseMessageTest.php delete mode 100644 tests/unit/framework/rbac/ManagerTestCase.php delete mode 100644 tests/unit/framework/rbac/PhpManagerTest.php delete mode 100644 tests/unit/framework/requirements/YiiRequirementCheckerTest.php delete mode 100644 tests/unit/framework/validators/BooleanValidatorTest.php delete mode 100644 tests/unit/framework/validators/CompareValidatorTest.php delete mode 100644 tests/unit/framework/validators/DateValidatorTest.php delete mode 100644 tests/unit/framework/validators/DefaultValueValidatorTest.php delete mode 100644 tests/unit/framework/validators/EmailValidatorTest.php delete mode 100644 tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php delete mode 100644 tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorSQliteTest.php delete mode 100644 tests/unit/framework/validators/ExistValidatorTest.php delete mode 100644 tests/unit/framework/validators/FileValidatorTest.php delete mode 100644 tests/unit/framework/validators/FilterValidatorTest.php delete mode 100644 tests/unit/framework/validators/NumberValidatorTest.php delete mode 100644 tests/unit/framework/validators/RangeValidatorTest.php delete mode 100644 tests/unit/framework/validators/RegularExpressionValidatorTest.php delete mode 100644 tests/unit/framework/validators/RequiredValidatorTest.php delete mode 100644 tests/unit/framework/validators/StringValidatorTest.php delete mode 100644 tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php delete mode 100644 tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorSQliteTest.php delete mode 100644 tests/unit/framework/validators/UniqueValidatorTest.php delete mode 100644 tests/unit/framework/validators/UrlValidatorTest.php delete mode 100644 tests/unit/framework/validators/ValidatorTest.php delete mode 100644 tests/unit/framework/web/AssetBundleTest.php delete mode 100644 tests/unit/framework/web/AssetConverterTest.php delete mode 100644 tests/unit/framework/web/CacheSessionTest.php delete mode 100644 tests/unit/framework/web/ResponseTest.php delete mode 100644 tests/unit/framework/web/UrlManagerTest.php delete mode 100644 tests/unit/framework/web/UrlRuleTest.php delete mode 100644 tests/unit/framework/web/XmlResponseFormatterTest.php delete mode 100644 tests/unit/framework/widgets/SpacelessTest.php delete mode 100644 tests/unit/runtime/.gitignore delete mode 100644 tests/unit/runtime/coveralls/.gitkeep delete mode 100644 tests/web/app/assets/.gitignore delete mode 100644 tests/web/app/index.php delete mode 100644 tests/web/app/protected/config/main.php delete mode 100644 tests/web/app/protected/controllers/SiteController.php delete mode 100644 tests/web/app/protected/runtime/.gitignore delete mode 100644 tests/web/app/protected/views/site/index.php diff --git a/.coveralls.yml b/.coveralls.yml deleted file mode 100644 index c0564c2..0000000 --- a/.coveralls.yml +++ /dev/null @@ -1,4 +0,0 @@ -service_name: travis-ci -src_dir: framework/yii -coverage_clover: tests/unit/runtime/coveralls/clover.xml -json_path: tests/unit/runtime/coveralls/coveralls-upload.json \ No newline at end of file diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 818cb6a..0000000 --- a/.gitattributes +++ /dev/null @@ -1,23 +0,0 @@ -# Autodetect text files -* text=auto - -# ...Unless the name matches the following overriding patterns - -# Definitively text files -*.php text -*.css text -*.js text -*.txt text -*.md text -*.xml text -*.json text -*.bat text -*.sql text -*.xml text -*.yml text - -# Ensure those won't be messed up with -*.png binary -*.jpg binary -*.gif binary -*.ttf binary diff --git a/.gitignore b/.gitignore deleted file mode 100644 index e3fdcbf..0000000 --- a/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -# phpstorm project files -.idea - -# netbeans project files -nbproject - -# zend studio for eclipse project files -.buildpath -.project -.settings - -# windows thumbnail cache -Thumbs.db - -# composer vendor dir -/vendor - -# composer itself is not needed -composer.phar -# composer.lock should not be committed as we always want the latest versions -/composer.lock - -# Mac DS_Store Files -.DS_Store - -# phpunit itself is not needed -phpunit.phar -# local phpunit config -/phpunit.xml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8134e21..0000000 --- a/.travis.yml +++ /dev/null @@ -1,41 +0,0 @@ -language: php - -php: - - 5.4 - - 5.5 -# - hhvm # commented until composer or hhvm get fixed: https://github.com/facebook/hhvm/issues/1347 - -services: - - redis-server - - memcached - - elasticsearch - - mongodb - -install: - - composer self-update && composer --version -# core framework: -# - composer require satooshi/php-coveralls 0.6.* --dev --prefer-dist - - composer install --prefer-dist - - tests/unit/data/travis/mongodb-setup.sh - - tests/unit/data/travis/apc-setup.sh - - tests/unit/data/travis/memcache-setup.sh - - tests/unit/data/travis/cubrid-setup.sh -# basic application: - - composer install --dev --prefer-dist -d apps/basic - - cd apps/basic && php vendor/bin/codecept build && cd ../.. - - cd apps && php -S localhost:8080 & - -before_script: - - echo 'elasticsearch version ' && curl http://localhost:9200/ - - mysql -e 'CREATE DATABASE yiitest;'; - - psql -U postgres -c 'CREATE DATABASE yiitest;'; - - tests/unit/data/travis/sphinx-setup.sh - - mongo yii2test --eval 'db.addUser("travis", "test");' - -script: -# - vendor/bin/phpunit --coverage-clover tests/unit/runtime/coveralls/clover.xml --verbose --exclude-group mssql,oci,wincache,xcache,zenddata,vendor - - vendor/bin/phpunit --verbose --exclude-group mssql,oci,wincache,xcache,zenddata,vendor - - cd apps/basic && php vendor/bin/codecept run - -#after_script: -# - php vendor/bin/coveralls diff --git a/Alert.php b/Alert.php new file mode 100644 index 0000000..29844bd --- /dev/null +++ b/Alert.php @@ -0,0 +1,149 @@ + '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/BootstrapAsset.php b/BootstrapAsset.php new file mode 100644 index 0000000..27dabc0 --- /dev/null +++ b/BootstrapAsset.php @@ -0,0 +1,22 @@ + + * @since 2.0 + */ +class BootstrapAsset extends AssetBundle +{ + public $sourcePath = '@vendor/twbs/bootstrap/dist'; + public $css = [ + 'css/bootstrap.css', + ]; +} diff --git a/BootstrapPluginAsset.php b/BootstrapPluginAsset.php new file mode 100644 index 0000000..35bf18a --- /dev/null +++ b/BootstrapPluginAsset.php @@ -0,0 +1,27 @@ + + * @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/BootstrapThemeAsset.php b/BootstrapThemeAsset.php new file mode 100644 index 0000000..f15a0fb --- /dev/null +++ b/BootstrapThemeAsset.php @@ -0,0 +1,27 @@ + + * @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/Button.php b/Button.php new file mode 100644 index 0000000..88acab7 --- /dev/null +++ b/Button.php @@ -0,0 +1,62 @@ + '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/ButtonDropdown.php b/ButtonDropdown.php new file mode 100644 index 0000000..34d3ae2 --- /dev/null +++ b/ButtonDropdown.php @@ -0,0 +1,119 @@ + '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; + /** + * @var string the tag to use to render the button + */ + public $tagName = 'button'; + /** + * @var boolean whether the label should be HTML-encoded. + */ + public $encodeLabel = true; + + + /** + * 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'); + $label = $this->label; + if ($this->encodeLabel) { + $label = Html::encode($label); + } + if ($this->split) { + $options = $this->options; + $this->options['data-toggle'] = 'dropdown'; + Html::addCssClass($this->options, 'dropdown-toggle'); + $splitButton = Button::widget([ + 'label' => '', + 'encodeLabel' => false, + 'options' => $this->options, + ]); + } else { + $label .= ' '; + $options = $this->options; + if (!isset($options['href'])) { + $options['href'] = '#'; + } + Html::addCssClass($options, 'dropdown-toggle'); + $options['data-toggle'] = 'dropdown'; + $splitButton = ''; + } + return Button::widget([ + 'tagName' => $this->tagName, + 'label' => $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/ButtonGroup.php b/ButtonGroup.php new file mode 100644 index 0000000..4fc2eb3 --- /dev/null +++ b/ButtonGroup.php @@ -0,0 +1,97 @@ + [ + * ['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/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..58fc73d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,16 @@ +Yii Framework 2 bootstrap extension Change Log +============================================== + +2.0.0 beta under development +---------------------------- + +- Enh #1474: Added option to make NavBar 100% width (cebe) +- Enh #1553: Only add navbar-default class to NavBar when no other class is specified (cebe) +- Enh #1601: Added support for tagName and encodeLabel parameters in ButtonDropdown (omnilight) +- Chg #1459: Update Collapse to use bootstrap 3 classes (tonydspaniard) +- Chg #1820: Update Progress to use bootstrap 3 markup (samdark) + +2.0.0 alpha, December 1, 2013 +----------------------------- + +- Initial release. diff --git a/Carousel.php b/Carousel.php new file mode 100644 index 0000000..8344929 --- /dev/null +++ b/Carousel.php @@ -0,0 +1,170 @@ + [ + * // 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/Collapse.php b/Collapse.php new file mode 100644 index 0000000..794c5e8 --- /dev/null +++ b/Collapse.php @@ -0,0 +1,135 @@ + [ + * // 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, 'panel-group'); + } + + /** + * 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, 'panel panel-default'); + $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, 'panel-collapse collapse'); + + $headerToggle = Html::a($header, '#' . $id, [ + 'class' => 'collapse-toggle', + 'data-toggle' => 'collapse', + 'data-parent' => '#' . $this->options['id'] + ]) . "\n"; + + $header = Html::tag('h4', $headerToggle, ['class' => 'panel-title']); + + $content = Html::tag('div', $item['content'], ['class' => 'panel-body']) . "\n"; + } else { + throw new InvalidConfigException('The "content" option is required.'); + } + $group = []; + + $group[] = Html::tag('div', $header, ['class' => 'panel-heading']); + $group[] = Html::tag('div', $content, $options); + + return implode("\n", $group); + } +} diff --git a/Dropdown.php b/Dropdown.php new file mode 100644 index 0000000..fecfb0b --- /dev/null +++ b/Dropdown.php @@ -0,0 +1,92 @@ + + * @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/LICENSE.md b/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/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/Modal.php b/Modal.php new file mode 100644 index 0000000..94a3997 --- /dev/null +++ b/Modal.php @@ -0,0 +1,227 @@ + '

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/Nav.php b/Nav.php new file mode 100644 index 0000000..42e6346 --- /dev/null +++ b/Nav.php @@ -0,0 +1,214 @@ + [ + * [ + * '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($linkOptions, '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/NavBar.php b/NavBar.php new file mode 100644 index 0000000..4a15481 --- /dev/null +++ b/NavBar.php @@ -0,0 +1,122 @@ + '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 = []; + /** + * @var string text to show for screen readers for the button to toggle the navbar. + */ + public $screenReaderToggleText = 'Toggle navigation'; + /** + * @var bool whether the navbar content should be included in a `container` div which adds left and right padding. + * Set this to false for a 100% width navbar. + */ + public $padded = true; + + /** + * Initializes the widget. + */ + public function init() + { + parent::init(); + $this->clientOptions = false; + Html::addCssClass($this->options, 'navbar'); + if ($this->options['class'] == 'navbar') { + Html::addCssClass($this->options, 'navbar-default'); + } + Html::addCssClass($this->brandOptions, 'navbar-brand'); + if (empty($this->options['role'])) { + $this->options['role'] = 'navigation'; + } + + echo Html::beginTag('nav', $this->options); + if ($this->padded) { + 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-{$this->options['id']}-collapse"]); + } + + /** + * Renders the widget. + */ + public function run() + { + + echo Html::endTag('div'); + if ($this->padded) { + 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-{$this->options['id']}-collapse", + ]); + } +} diff --git a/Progress.php b/Progress.php new file mode 100644 index 0000000..8f23a58 --- /dev/null +++ b/Progress.php @@ -0,0 +1,161 @@ + 60, + * 'label' => 'test', + * ]); + * + * // styled + * echo Progress::widget([ + * 'percent' => 65, + * 'barOptions' => ['class' => 'progress-bar-danger'] + * ]); + * + * // striped + * echo Progress::widget([ + * 'percent' => 70, + * 'barOptions' => ['class' => 'progress-bar-warning'], + * 'options' => ['class' => 'progress-striped'] + * ]); + * + * // striped animated + * echo Progress::widget([ + * 'percent' => 70, + * 'barOptions' => ['class' => 'progress-bar-success'], + * 'options' => ['class' => 'active progress-striped'] + * ]); + * + * // stacked bars + * echo Progress::widget([ + * 'bars' => [ + * ['percent' => 30, 'options' => ['class' => 'progress-bar-danger']], + * ['percent' => 30, 'label' => 'test', 'options' => ['class' => 'progress-bar-success']], + * ['percent' => 35, 'options' => ['class' => 'progress-bar-warning']], + * ] + * ]); + * ``` + * @see http://getbootstrap.com/components/#progress + * @author Antonio Ramirez + * @author Alexander Makarov + * @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 bar + */ + 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 = []) + { + $defaultOptions = [ + 'role' => 'progressbar', + 'aria-valuenow' => $percent, + 'aria-valuemin' => 0, + 'aria-valuemax' => 100, + 'style' => "width:{$percent}%", + ]; + $options = array_merge($defaultOptions, $options); + Html::addCssClass($options, 'progress-bar'); + + $out = Html::beginTag('div', $options); + $out .= $label; + $out .= Html::tag('span', \Yii::t('yii', '{percent}% Complete', ['percent' => $percent]), [ + 'class' => 'sr-only' + ]); + $out .= Html::endTag('div'); + return $out; + } +} diff --git a/README.md b/README.md index d7020d9..bffc715 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,32 @@ -Yii PHP Framework Version 2 -=========================== +Twitter Bootstrap Extension for Yii 2 +===================================== -Thank you for choosing Yii 2 - a modern PHP framework designed for professional Web development. +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: -Yii 2 is a complete rewrite of its previous version Yii 1.1 which is one of the most popular PHP frameworks. -Yii 2 inherits the main spirit behind Yii for being simple, fast and highly extensible. -Yii 2 requires PHP 5.4 and embraces best practices and protocols found in modern Web application development. +```php + 60, 'label' => 'test']) ?> +``` -**Yii 2 is not ready for production use yet.** We may make significant changes without prior notices. -We expect to make the first stable release of Yii 2 in early 2014. - -If you mainly want to learn Yii with no real project development requirement, we highly recommend -you start with Yii 2 as it will be our main focus for the next few years. - -If you have a real project with tight schedule, you should stick to [Yii 1.1](https://github.com/yiisoft/yii) -which is the latest stable release of Yii. - - -[![Latest Stable Version](https://poser.pugx.org/yiisoft/yii2/v/stable.png)](https://packagist.org/packages/yiisoft/yii2) -[![Total Downloads](https://poser.pugx.org/yiisoft/yii2/downloads.png)](https://packagist.org/packages/yiisoft/yii2) -[![Build Status](https://secure.travis-ci.org/yiisoft/yii2.png)](http://travis-ci.org/yiisoft/yii2) -[![Dependency Status](https://www.versioneye.com/php/yiisoft:yii2/dev-master/badge.png)](https://www.versioneye.com/php/yiisoft:yii2/dev-master) - - -DIRECTORY STRUCTURE -------------------- - - apps/ ready-to-use application templates - advanced/ a template suitable for building sophisticated Web applications - basic/ a template suitable for building simple Web applications - benchmark/ an application demonstrating the performance of Yii - build/ internally used build tools - docs/ documentation - extensions/ extensions - framework/ core framework code - tests/ tests of the core framework code - - -REQUIREMENTS +Installation ------------ -The minimum requirement by Yii is that your Web server supports PHP 5.4. - - -DOCUMENTATION -------------- - -A draft of the [Definitive Guide](docs/guide/index.md) is available. - -For 1.1 users, you may refer to [Upgrading from Yii 1.1](docs/guide/upgrade-from-v1.md) -to have a general idea of what has changed in 2.0. - +The preferred way to install this extension is through [composer](http://getcomposer.org/download/). -HOW TO PARTICIPATE ------------------- +Either run -**Your participation to Yii 2 development is very welcome!** +``` +php composer.phar require --prefer-dist yiisoft/yii2-bootstrap "*" +``` -You may participate in the following ways: +or add -* [Report issues](https://github.com/yiisoft/yii2/issues) -* [Give us feedback or start a design discussion](http://www.yiiframework.com/forum/index.php/forum/42-design-discussions-for-yii-20/) -* Fix issues, develop features, write/polish documentation - - Before you start, please adopt an existing issue (labelled with "ready for adoption") or start a new one to avoid duplicated efforts. - - Please submit a merge request after you finish development. +``` +"yiisoft/yii2-bootstrap": "*" +``` -In order to make it easier we've prepared [special `yii2-dev` Composer package](https://github.com/yiisoft/yii2/blob/master/docs/internals/getting-started.md). +to the require section of your `composer.json` file. diff --git a/Tabs.php b/Tabs.php new file mode 100644 index 0000000..2e76398 --- /dev/null +++ b/Tabs.php @@ -0,0 +1,199 @@ + [ + * [ + * '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/Widget.php b/Widget.php new file mode 100644 index 0000000..ff4084d --- /dev/null +++ b/Widget.php @@ -0,0 +1,81 @@ + + * @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/apps/advanced/.gitignore b/apps/advanced/.gitignore deleted file mode 100644 index 447bcd3..0000000 --- a/apps/advanced/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/yii diff --git a/apps/advanced/LICENSE.md b/apps/advanced/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/apps/advanced/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/apps/advanced/README.md b/apps/advanced/README.md deleted file mode 100644 index a1f79aa..0000000 --- a/apps/advanced/README.md +++ /dev/null @@ -1,89 +0,0 @@ -Yii 2 Advanced Application Template -=================================== - -Yii 2 Advanced Application Template is a skeleton Yii 2 application best for -developing complex Web applications with multiple tiers. - -The template includes three tiers: front end, back end, and console, each of which -is a separate Yii application. - -The template is designed to work in a team development environment. It supports -deploying the application in different environments. - - -DIRECTORY STRUCTURE -------------------- - -``` -common - config/ contains shared configurations - models/ contains model classes used in both backend and frontend -console - config/ contains console configurations - controllers/ contains console controllers (commands) - migrations/ contains database migrations - models/ contains console-specific model classes - runtime/ contains files generated during runtime -backend - assets/ contains application assets such as JavaScript and CSS - config/ contains backend configurations - controllers/ contains Web controller classes - models/ contains backend-specific model classes - runtime/ contains files generated during runtime - views/ contains view files for the Web application - web/ contains the entry script and Web resources -frontend - assets/ contains application assets such as JavaScript and CSS - config/ contains frontend configurations - controllers/ contains Web controller classes - models/ contains frontend-specific model classes - runtime/ contains files generated during runtime - views/ contains view files for the Web application - web/ contains the entry script and Web resources -vendor/ contains dependent 3rd-party packages -environments/ contains environment-based overrides -``` - - -REQUIREMENTS ------------- - -The minimum requirement by this application template that your Web server supports PHP 5.4.0. - - -INSTALLATION ------------- - -### Install from an Archive File - -Extract the archive file downloaded from [yiiframework.com](http://www.yiiframework.com/download/) to -a directory named `advanced` that is directly under the Web root. - -Then follow the instructions given in "GETTING STARTED". - - -### Install via Composer - -If you do not have [Composer](http://getcomposer.org/), you may install it by following the instructions -at [getcomposer.org](http://getcomposer.org/doc/00-intro.md#installation-nix). - -You can then install the application using the following command: - -~~~ -php composer.phar create-project --prefer-dist --stability=dev yiisoft/yii2-app-advanced advanced -~~~ - - -GETTING STARTED ---------------- - -After you install the application, you have to conduct the following steps to initialize -the installed application. You only need to do these once for all. - -1. Run command `init` to initialize the application with a specific environment. -2. Create a new database and adjust the `components.db` configuration in `common/config/params-local.php` accordingly. -3. Apply migrations with console command `yii migrate`. -4. Set document roots of your Web server: - -- for frontend `/path/to/yii-application/frontend/web/` and using the URL `http://frontend/` -- for backend `/path/to/yii-application/backend/web/` and using the URL `http://backend/` diff --git a/apps/advanced/backend/assets/AppAsset.php b/apps/advanced/backend/assets/AppAsset.php deleted file mode 100644 index bd5c3a0..0000000 --- a/apps/advanced/backend/assets/AppAsset.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @since 2.0 - */ -class AppAsset extends AssetBundle -{ - public $basePath = '@webroot'; - public $baseUrl = '@web'; - public $css = ['css/site.css']; - public $js = []; - public $depends = [ - 'yii\web\YiiAsset', - 'yii\bootstrap\BootstrapAsset', - ]; -} diff --git a/apps/advanced/backend/config/.gitignore b/apps/advanced/backend/config/.gitignore deleted file mode 100644 index 20da318..0000000 --- a/apps/advanced/backend/config/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -main-local.php -params-local.php \ No newline at end of file diff --git a/apps/advanced/backend/config/main.php b/apps/advanced/backend/config/main.php deleted file mode 100644 index d1a45a7..0000000 --- a/apps/advanced/backend/config/main.php +++ /dev/null @@ -1,41 +0,0 @@ - 'app-backend', - 'basePath' => dirname(__DIR__), - 'vendorPath' => $rootDir . '/vendor', - 'preload' => ['log'], - 'controllerNamespace' => 'backend\controllers', - 'modules' => [], - 'extensions' => require($rootDir . '/vendor/yiisoft/extensions.php'), - 'components' => [ - 'db' => $params['components.db'], - 'cache' => $params['components.cache'], - 'mail' => $params['components.mail'], - 'user' => [ - 'identityClass' => 'common\models\User', - 'enableAutoLogin' => true, - ], - 'log' => [ - 'traceLevel' => YII_DEBUG ? 3 : 0, - 'targets' => [ - [ - 'class' => 'yii\log\FileTarget', - 'levels' => ['error', 'warning'], - ], - ], - ], - 'errorHandler' => [ - 'errorAction' => 'site/error', - ], - ], - 'params' => $params, -]; diff --git a/apps/advanced/backend/config/params.php b/apps/advanced/backend/config/params.php deleted file mode 100644 index 0e625dc..0000000 --- a/apps/advanced/backend/config/params.php +++ /dev/null @@ -1,4 +0,0 @@ - 'admin@example.com', -]; diff --git a/apps/advanced/backend/controllers/SiteController.php b/apps/advanced/backend/controllers/SiteController.php deleted file mode 100644 index ecf684c..0000000 --- a/apps/advanced/backend/controllers/SiteController.php +++ /dev/null @@ -1,66 +0,0 @@ - [ - 'class' => \yii\web\AccessControl::className(), - 'rules' => [ - [ - 'actions' => ['login', 'error'], - 'allow' => true, - ], - [ - 'actions' => ['logout', 'index'], - 'allow' => true, - 'roles' => ['@'], - ], - ], - ], - ]; - } - - public function actions() - { - return [ - 'error' => [ - 'class' => 'yii\web\ErrorAction', - ], - ]; - } - - public function actionIndex() - { - return $this->render('index'); - } - - public function actionLogin() - { - if (!\Yii::$app->user->isGuest) { - $this->goHome(); - } - - $model = new LoginForm(); - if ($model->load($_POST) && $model->login()) { - return $this->goBack(); - } else { - return $this->render('login', [ - 'model' => $model, - ]); - } - } - - public function actionLogout() - { - Yii::$app->user->logout(); - return $this->goHome(); - } -} diff --git a/apps/advanced/backend/models/.gitkeep b/apps/advanced/backend/models/.gitkeep deleted file mode 100644 index 72e8ffc..0000000 --- a/apps/advanced/backend/models/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/apps/advanced/backend/runtime/.gitignore b/apps/advanced/backend/runtime/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/advanced/backend/runtime/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/advanced/backend/views/layouts/main.php b/apps/advanced/backend/views/layouts/main.php deleted file mode 100644 index d1ede45..0000000 --- a/apps/advanced/backend/views/layouts/main.php +++ /dev/null @@ -1,65 +0,0 @@ - -beginPage() ?> - - - - - - <?= Html::encode($this->title) ?> - head() ?> - - - beginBody() ?> - 'My Company', - 'brandUrl' => Yii::$app->homeUrl, - 'options' => [ - 'class' => 'navbar-inverse navbar-fixed-top', - ], - ]); - $menuItems = [ - ['label' => 'Home', 'url' => ['/site/index']], - ]; - if (Yii::$app->user->isGuest) { - $menuItems[] = ['label' => 'Login', 'url' => ['/site/login']]; - } else { - $menuItems[] = ['label' => 'Logout (' . Yii::$app->user->identity->username .')' , 'url' => ['/site/logout']]; - } - echo Nav::widget([ - 'options' => ['class' => 'navbar-nav navbar-right'], - 'items' => $menuItems, - ]); - NavBar::end(); - ?> - -
    - isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], - ]) ?> - -
    - -
    -
    -

    © My Company

    -

    -
    -
    - - endBody() ?> - - -endPage() ?> diff --git a/apps/advanced/backend/views/site/error.php b/apps/advanced/backend/views/site/error.php deleted file mode 100644 index 1b7ce04..0000000 --- a/apps/advanced/backend/views/site/error.php +++ /dev/null @@ -1,29 +0,0 @@ -title = $name; -?> -
    - -

    title) ?>

    - -
    - -
    - -

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

    -

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

    - -
    diff --git a/apps/advanced/backend/views/site/index.php b/apps/advanced/backend/views/site/index.php deleted file mode 100644 index bcb2278..0000000 --- a/apps/advanced/backend/views/site/index.php +++ /dev/null @@ -1,53 +0,0 @@ -title = 'My Yii Application'; -?> -
    - -
    -

    Congratulations!

    - -

    You have successfully created your Yii-powered application.

    - -

    Get started with Yii

    -
    - -
    - -
    -
    -

    Heading

    - -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

    - -

    Yii Documentation »

    -
    -
    -

    Heading

    - -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

    - -

    Yii Forum »

    -
    -
    -

    Heading

    - -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

    - -

    Yii Extensions »

    -
    -
    - -
    -
    diff --git a/apps/advanced/backend/views/site/login.php b/apps/advanced/backend/views/site/login.php deleted file mode 100644 index 41973e5..0000000 --- a/apps/advanced/backend/views/site/login.php +++ /dev/null @@ -1,30 +0,0 @@ -title = 'Login'; -$this->params['breadcrumbs'][] = $this->title; -?> - diff --git a/apps/advanced/backend/web/.gitignore b/apps/advanced/backend/web/.gitignore deleted file mode 100644 index 148f2b0..0000000 --- a/apps/advanced/backend/web/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/index.php \ No newline at end of file diff --git a/apps/advanced/backend/web/assets/.gitignore b/apps/advanced/backend/web/assets/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/advanced/backend/web/assets/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/advanced/backend/web/css/site.css b/apps/advanced/backend/web/css/site.css deleted file mode 100644 index a8508c4..0000000 --- a/apps/advanced/backend/web/css/site.css +++ /dev/null @@ -1,79 +0,0 @@ -body { - padding-top: 70px; -} - -.footer { - border-top: 1px solid #ddd; - margin-top: 30px; - padding-top: 15px; - padding-bottom: 30px; -} - -.jumbotron { - text-align: center; - background-color: transparent; -} - -.jumbotron .btn { - font-size: 21px; - padding: 14px 24px; -} - -.not-set { - color: #c55; - font-style: italic; -} - -/* add sorting icons to gridview sort links */ -a.asc:after, a.desc:after { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: normal; - line-height: 1; - padding-left: 5px; -} - -a.asc:after { - content: /*"\e113"*/ "\e151"; -} - -a.desc:after { - content: /*"\e114"*/ "\e152"; -} - -.sort-numerical a.asc:after { - content: "\e153"; -} - -.sort-numerical a.desc:after { - content: "\e154"; -} - -.sort-ordinal a.asc:after { - content: "\e155"; -} - -.sort-ordinal a.desc:after { - content: "\e156"; -} - -.grid-view th { - white-space: nowrap; -} - -.hint-block { - display: block; - margin-top: 5px; - color: #999; -} - -.error-summary { - color: #a94442; - background: #fdf7f7; - border-left: 3px solid #eed3d7; - padding: 10px 20px; - margin: 0 0 15px 0; -} diff --git a/apps/advanced/backend/web/favicon.ico b/apps/advanced/backend/web/favicon.ico deleted file mode 100644 index 49e61e33ca94362545346cb218c62dc7807e9c66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcma)6XH1hp7(Rmu{|GtU+!^sFa8rsCv}Jk%uOI+4N{Oj%&Pr>HDfEM$SlXWB1Hz(U z=q`_hetCNkh4Fv)y`0bdjM_j#e<+ev-v&l=4iw2c-UG{xrn23ZP6ZdY2&U;sgmB!MCG& zPViGpf_QK&ieQ-2k5Nuv5z%G|~6pzA1+W5r4)V$G60fX<= z_5nON#o*SQ2hNQdkSS&*ggllP?sgTy0Y3?thD*ULrXP+a5|6ZDaLgIev<}Qz&tpo@ zi(NG3){+k{P1)eYN(Vc}b4V4|ys-2Xb?vn8f;|^RU>vyM5#0~onF@Z_(5$icj 'admin@example.com', - 'supportEmail' => 'support@example.com', - - 'components.cache' => [ - 'class' => 'yii\caching\FileCache', - ], - - 'components.mail' => [ - 'class' => 'yii\swiftmailer\Mailer', - 'viewPath' => '@common/mails', - ], -]; diff --git a/apps/advanced/common/mails/layouts/html.php b/apps/advanced/common/mails/layouts/html.php deleted file mode 100644 index 2e6b615..0000000 --- a/apps/advanced/common/mails/layouts/html.php +++ /dev/null @@ -1,24 +0,0 @@ - -beginPage() ?> - - - - - <?= Html::encode($this->title) ?> - head() ?> - - - beginBody() ?> - - endBody() ?> - - -endPage() ?> \ No newline at end of file diff --git a/apps/advanced/common/mails/passwordResetToken.php b/apps/advanced/common/mails/passwordResetToken.php deleted file mode 100644 index b617bd9..0000000 --- a/apps/advanced/common/mails/passwordResetToken.php +++ /dev/null @@ -1,16 +0,0 @@ -urlManager->createAbsoluteUrl('site/reset-password', ['token' => $user->password_reset_token]); -?> - -Hello username) ?>, - -Follow the link below to reset your password: - - diff --git a/apps/advanced/common/models/LoginForm.php b/apps/advanced/common/models/LoginForm.php deleted file mode 100644 index 38888d9..0000000 --- a/apps/advanced/common/models/LoginForm.php +++ /dev/null @@ -1,71 +0,0 @@ -getUser(); - if (!$user || !$user->validatePassword($this->password)) { - $this->addError('password', 'Incorrect username or password.'); - } - } - - /** - * Logs in a user using the provided username and password. - * @return boolean whether the user is logged in successfully - */ - public function login() - { - if ($this->validate()) { - return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0); - } else { - return false; - } - } - - /** - * Finds user by [[username]] - * - * @return User|null - */ - private function getUser() - { - if ($this->_user === false) { - $this->_user = User::findByUsername($this->username); - } - return $this->_user; - } -} diff --git a/apps/advanced/common/models/User.php b/apps/advanced/common/models/User.php deleted file mode 100644 index 9642b8c..0000000 --- a/apps/advanced/common/models/User.php +++ /dev/null @@ -1,150 +0,0 @@ - [ - 'class' => 'yii\behaviors\AutoTimestamp', - 'attributes' => [ - ActiveRecord::EVENT_BEFORE_INSERT => ['create_time', 'update_time'], - ActiveRecord::EVENT_BEFORE_UPDATE => 'update_time', - ], - ], - ]; - } - - /** - * Finds an identity by the given ID. - * - * @param string|integer $id the ID to be looked for - * @return IdentityInterface|null the identity object that matches the given ID. - */ - public static function findIdentity($id) - { - return static::find($id); - } - - /** - * Finds user by username - * - * @param string $username - * @return null|User - */ - public static function findByUsername($username) - { - return static::find(['username' => $username, 'status' => static::STATUS_ACTIVE]); - } - - /** - * @return int|string|array current user ID - */ - public function getId() - { - return $this->getPrimaryKey(); - } - - /** - * @return string current user auth key - */ - public function getAuthKey() - { - return $this->auth_key; - } - - /** - * @param string $authKey - * @return boolean if auth key is valid for current user - */ - public function validateAuthKey($authKey) - { - return $this->getAuthKey() === $authKey; - } - - /** - * @param string $password password to validate - * @return bool if password provided is valid for current user - */ - public function validatePassword($password) - { - return Security::validatePassword($password, $this->password_hash); - } - - public function rules() - { - return [ - ['status', 'default', 'value' => self::STATUS_ACTIVE], - ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]], - - ['role', 'default', 'value' => self::ROLE_USER], - ['role', 'in', 'range' => [self::ROLE_USER]], - - ['username', 'filter', 'filter' => 'trim'], - ['username', 'required'], - ['username', 'string', 'min' => 2, 'max' => 255], - - ['email', 'filter', 'filter' => 'trim'], - ['email', 'required'], - ['email', 'email'], - ['email', 'unique', 'message' => 'This email address has already been taken.', 'on' => 'signup'], - ['email', 'exist', 'message' => 'There is no user with such email.', 'on' => 'requestPasswordResetToken'], - - ['password', 'required'], - ['password', 'string', 'min' => 6], - ]; - } - - public function scenarios() - { - return [ - 'signup' => ['username', 'email', 'password', '!status', '!role'], - 'resetPassword' => ['password'], - 'requestPasswordResetToken' => ['email'], - ]; - } - - public function beforeSave($insert) - { - if (parent::beforeSave($insert)) { - if (($this->isNewRecord || $this->getScenario() === 'resetPassword') && !empty($this->password)) { - $this->password_hash = Security::generatePasswordHash($this->password); - } - if ($this->isNewRecord) { - $this->auth_key = Security::generateRandomKey(); - } - return true; - } - return false; - } -} diff --git a/apps/advanced/composer.json b/apps/advanced/composer.json deleted file mode 100644 index b44cd7f..0000000 --- a/apps/advanced/composer.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "yiisoft/yii2-app-advanced", - "description": "Yii 2 Advanced Application Template", - "keywords": ["yii", "framework", "advanced", "application template"], - "homepage": "http://www.yiiframework.com/", - "type": "project", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?state=open", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "minimum-stability": "dev", - "require": { - "php": ">=5.4.0", - "yiisoft/yii2": "*", - "yiisoft/yii2-bootstrap": "*", - "yiisoft/yii2-swiftmailer": "*" - }, - "require-dev": { - "yiisoft/yii2-debug": "*", - "yiisoft/yii2-gii": "*" - }, - "scripts": { - "post-create-project-cmd": [ - "yii\\composer\\Installer::setPermission" - ] - }, - "config": { - "process-timeout": 1800 - }, - "extra": { - "writable": [ - "backend/runtime", - "backend/web/assets", - - "console/runtime", - "console/migrations", - - "frontend/runtime", - "frontend/web/assets" - ] - } -} diff --git a/apps/advanced/console/config/.gitignore b/apps/advanced/console/config/.gitignore deleted file mode 100644 index 20da318..0000000 --- a/apps/advanced/console/config/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -main-local.php -params-local.php \ No newline at end of file diff --git a/apps/advanced/console/config/main.php b/apps/advanced/console/config/main.php deleted file mode 100644 index 0142e32..0000000 --- a/apps/advanced/console/config/main.php +++ /dev/null @@ -1,33 +0,0 @@ - 'app-console', - 'basePath' => dirname(__DIR__), - 'vendorPath' => dirname(dirname(__DIR__)) . '/vendor', - 'controllerNamespace' => 'console\controllers', - 'modules' => [ - ], - 'extensions' => require(__DIR__ . '/../../vendor/yiisoft/extensions.php'), - 'components' => [ - 'db' => $params['components.db'], - 'cache' => $params['components.cache'], - 'mail' => $params['components.mail'], - 'log' => [ - 'targets' => [ - [ - 'class' => 'yii\log\FileTarget', - 'levels' => ['error', 'warning'], - ], - ], - ], - ], - 'params' => $params, -]; diff --git a/apps/advanced/console/config/params.php b/apps/advanced/console/config/params.php deleted file mode 100644 index 0e625dc..0000000 --- a/apps/advanced/console/config/params.php +++ /dev/null @@ -1,4 +0,0 @@ - 'admin@example.com', -]; diff --git a/apps/advanced/console/controllers/.gitkeep b/apps/advanced/console/controllers/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/apps/advanced/console/migrations/m130524_201442_init.php b/apps/advanced/console/migrations/m130524_201442_init.php deleted file mode 100644 index a5935be..0000000 --- a/apps/advanced/console/migrations/m130524_201442_init.php +++ /dev/null @@ -1,33 +0,0 @@ -db->driverName === 'mysql') { - $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; - } - - $this->createTable('tbl_user', [ - 'id' => Schema::TYPE_PK, - 'username' => Schema::TYPE_STRING . ' NOT NULL', - 'auth_key' => Schema::TYPE_STRING . '(32) NOT NULL', - 'password_hash' => Schema::TYPE_STRING . ' NOT NULL', - 'password_reset_token' => Schema::TYPE_STRING . '(32)', - 'email' => Schema::TYPE_STRING . ' NOT NULL', - 'role' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10', - - 'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10', - 'create_time' => Schema::TYPE_INTEGER.' NOT NULL', - 'update_time' => Schema::TYPE_INTEGER.' NOT NULL', - ], $tableOptions); - } - - public function down() - { - $this->dropTable('tbl_user'); - } -} diff --git a/apps/advanced/console/models/.gitkeep b/apps/advanced/console/models/.gitkeep deleted file mode 100644 index 72e8ffc..0000000 --- a/apps/advanced/console/models/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/apps/advanced/console/runtime/.gitignore b/apps/advanced/console/runtime/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/advanced/console/runtime/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/advanced/environments/dev/backend/config/main-local.php b/apps/advanced/environments/dev/backend/config/main-local.php deleted file mode 100644 index c04d713..0000000 --- a/apps/advanced/environments/dev/backend/config/main-local.php +++ /dev/null @@ -1,10 +0,0 @@ - [ - //'debug', - ], - 'modules' => [ -// 'debug' => 'yii\debug\Module', -// 'gii' => 'yii\gii\Module', - ], -]; diff --git a/apps/advanced/environments/dev/backend/config/params-local.php b/apps/advanced/environments/dev/backend/config/params-local.php deleted file mode 100644 index d0b9c34..0000000 --- a/apps/advanced/environments/dev/backend/config/params-local.php +++ /dev/null @@ -1,3 +0,0 @@ -run(); diff --git a/apps/advanced/environments/dev/common/config/params-local.php b/apps/advanced/environments/dev/common/config/params-local.php deleted file mode 100644 index b6a9496..0000000 --- a/apps/advanced/environments/dev/common/config/params-local.php +++ /dev/null @@ -1,10 +0,0 @@ - [ - 'class' => 'yii\db\Connection', - 'dsn' => 'mysql:host=localhost;dbname=yii2advanced', - 'username' => 'root', - 'password' => '', - 'charset' => 'utf8', - ], -]; diff --git a/apps/advanced/environments/dev/console/config/main-local.php b/apps/advanced/environments/dev/console/config/main-local.php deleted file mode 100644 index d0b9c34..0000000 --- a/apps/advanced/environments/dev/console/config/main-local.php +++ /dev/null @@ -1,3 +0,0 @@ - [ - //'debug', - ], - 'modules' => [ -// 'debug' => 'yii\debug\Module', -// 'gii' => 'yii\gii\Module', - ], -]; diff --git a/apps/advanced/environments/dev/frontend/config/params-local.php b/apps/advanced/environments/dev/frontend/config/params-local.php deleted file mode 100644 index d0b9c34..0000000 --- a/apps/advanced/environments/dev/frontend/config/params-local.php +++ /dev/null @@ -1,3 +0,0 @@ -run(); diff --git a/apps/advanced/environments/dev/yii b/apps/advanced/environments/dev/yii deleted file mode 100644 index 5d1cd90..0000000 --- a/apps/advanced/environments/dev/yii +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/advanced/environments/index.php b/apps/advanced/environments/index.php deleted file mode 100644 index a2097bf..0000000 --- a/apps/advanced/environments/index.php +++ /dev/null @@ -1,38 +0,0 @@ - [ - * 'path' => 'directory storing the local files', - * 'writable' => [ - * // list of directories that should be set writable - * ], - * ], - * ]; - * ``` - */ -return [ - 'Development' => [ - 'path' => 'dev', - 'writable' => [ - // handled by composer.json already - ], - 'executable' => [ - 'yii', - ], - ], - 'Production' => [ - 'path' => 'prod', - 'writable' => [ - // handled by composer.json already - ], - 'executable' => [ - 'yii', - ], - ], -]; diff --git a/apps/advanced/environments/prod/backend/config/main-local.php b/apps/advanced/environments/prod/backend/config/main-local.php deleted file mode 100644 index d0b9c34..0000000 --- a/apps/advanced/environments/prod/backend/config/main-local.php +++ /dev/null @@ -1,3 +0,0 @@ -run(); diff --git a/apps/advanced/environments/prod/common/config/params-local.php b/apps/advanced/environments/prod/common/config/params-local.php deleted file mode 100644 index b6a9496..0000000 --- a/apps/advanced/environments/prod/common/config/params-local.php +++ /dev/null @@ -1,10 +0,0 @@ - [ - 'class' => 'yii\db\Connection', - 'dsn' => 'mysql:host=localhost;dbname=yii2advanced', - 'username' => 'root', - 'password' => '', - 'charset' => 'utf8', - ], -]; diff --git a/apps/advanced/environments/prod/console/config/main-local.php b/apps/advanced/environments/prod/console/config/main-local.php deleted file mode 100644 index d0b9c34..0000000 --- a/apps/advanced/environments/prod/console/config/main-local.php +++ /dev/null @@ -1,3 +0,0 @@ -run(); diff --git a/apps/advanced/environments/prod/yii b/apps/advanced/environments/prod/yii deleted file mode 100644 index b17d9a7..0000000 --- a/apps/advanced/environments/prod/yii +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/advanced/frontend/assets/AppAsset.php b/apps/advanced/frontend/assets/AppAsset.php deleted file mode 100644 index 03c5382..0000000 --- a/apps/advanced/frontend/assets/AppAsset.php +++ /dev/null @@ -1,29 +0,0 @@ - - * @since 2.0 - */ -class AppAsset extends AssetBundle -{ - public $basePath = '@webroot'; - public $baseUrl = '@web'; - public $css = [ - 'css/site.css', - ]; - public $js = [ - ]; - public $depends = [ - 'yii\web\YiiAsset', - 'yii\bootstrap\BootstrapAsset', - ]; -} diff --git a/apps/advanced/frontend/config/.gitignore b/apps/advanced/frontend/config/.gitignore deleted file mode 100644 index 20da318..0000000 --- a/apps/advanced/frontend/config/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -main-local.php -params-local.php \ No newline at end of file diff --git a/apps/advanced/frontend/config/main.php b/apps/advanced/frontend/config/main.php deleted file mode 100644 index 60fb4c2..0000000 --- a/apps/advanced/frontend/config/main.php +++ /dev/null @@ -1,39 +0,0 @@ - 'app-frontend', - 'basePath' => dirname(__DIR__), - 'vendorPath' => $rootDir . '/vendor', - 'controllerNamespace' => 'frontend\controllers', - 'extensions' => require($rootDir . '/vendor/yiisoft/extensions.php'), - 'components' => [ - 'db' => $params['components.db'], - 'cache' => $params['components.cache'], - 'mail' => $params['components.mail'], - 'user' => [ - 'identityClass' => 'common\models\User', - 'enableAutoLogin' => true, - ], - 'log' => [ - 'traceLevel' => YII_DEBUG ? 3 : 0, - 'targets' => [ - [ - 'class' => 'yii\log\FileTarget', - 'levels' => ['error', 'warning'], - ], - ], - ], - 'errorHandler' => [ - 'errorAction' => 'site/error', - ], - ], - 'params' => $params, -]; diff --git a/apps/advanced/frontend/config/params.php b/apps/advanced/frontend/config/params.php deleted file mode 100644 index 0e625dc..0000000 --- a/apps/advanced/frontend/config/params.php +++ /dev/null @@ -1,4 +0,0 @@ - 'admin@example.com', -]; diff --git a/apps/advanced/frontend/controllers/SiteController.php b/apps/advanced/frontend/controllers/SiteController.php deleted file mode 100644 index db6dbe6..0000000 --- a/apps/advanced/frontend/controllers/SiteController.php +++ /dev/null @@ -1,171 +0,0 @@ - [ - 'class' => \yii\web\AccessControl::className(), - 'only' => ['logout', 'signup'], - 'rules' => [ - [ - 'actions' => ['signup'], - 'allow' => true, - 'roles' => ['?'], - ], - [ - 'actions' => ['logout'], - 'allow' => true, - 'roles' => ['@'], - ], - ], - ], - ]; - } - - public function actions() - { - return [ - 'error' => [ - 'class' => 'yii\web\ErrorAction', - ], - 'captcha' => [ - 'class' => 'yii\captcha\CaptchaAction', - 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null, - ], - ]; - } - - public function actionIndex() - { - return $this->render('index'); - } - - public function actionLogin() - { - if (!\Yii::$app->user->isGuest) { - $this->goHome(); - } - - $model = new LoginForm(); - if ($model->load($_POST) && $model->login()) { - return $this->goBack(); - } else { - return $this->render('login', [ - 'model' => $model, - ]); - } - } - - public function actionLogout() - { - Yii::$app->user->logout(); - return $this->goHome(); - } - - public function actionContact() - { - $model = new ContactForm; - if ($model->load($_POST) && $model->contact(Yii::$app->params['adminEmail'])) { - Yii::$app->session->setFlash('success', 'Thank you for contacting us. We will respond to you as soon as possible.'); - return $this->refresh(); - } else { - return $this->render('contact', [ - 'model' => $model, - ]); - } - } - - public function actionAbout() - { - return $this->render('about'); - } - - public function actionSignup() - { - $model = new User(); - $model->setScenario('signup'); - if ($model->load($_POST) && $model->save()) { - if (Yii::$app->getUser()->login($model)) { - return $this->goHome(); - } - } - - return $this->render('signup', [ - 'model' => $model, - ]); - } - - public function actionRequestPasswordReset() - { - $model = new User(); - $model->scenario = 'requestPasswordResetToken'; - if ($model->load($_POST) && $model->validate()) { - if ($this->sendPasswordResetEmail($model->email)) { - Yii::$app->getSession()->setFlash('success', 'Check your email for further instructions.'); - return $this->goHome(); - } else { - Yii::$app->getSession()->setFlash('error', 'There was an error sending email.'); - } - } - return $this->render('requestPasswordResetToken', [ - 'model' => $model, - ]); - } - - public function actionResetPassword($token) - { - $model = User::find([ - 'password_reset_token' => $token, - 'status' => User::STATUS_ACTIVE, - ]); - - if (!$model) { - throw new BadRequestHttpException('Wrong password reset token.'); - } - - $model->scenario = 'resetPassword'; - if ($model->load($_POST) && $model->save()) { - Yii::$app->getSession()->setFlash('success', 'New password was saved.'); - return $this->goHome(); - } - - return $this->render('resetPassword', [ - 'model' => $model, - ]); - } - - private function sendPasswordResetEmail($email) - { - $user = User::find([ - 'status' => User::STATUS_ACTIVE, - 'email' => $email, - ]); - - if (!$user) { - return false; - } - - $user->password_reset_token = Security::generateRandomKey(); - if ($user->save(false)) { - return \Yii::$app->mail->compose('passwordResetToken', ['user' => $user]) - ->setFrom([\Yii::$app->params['supportEmail'] => \Yii::$app->name . ' robot']) - ->setTo($email) - ->setSubject('Password reset for ' . \Yii::$app->name) - ->send(); - } - - return false; - } -} diff --git a/apps/advanced/frontend/models/ContactForm.php b/apps/advanced/frontend/models/ContactForm.php deleted file mode 100644 index 0a664ad..0000000 --- a/apps/advanced/frontend/models/ContactForm.php +++ /dev/null @@ -1,63 +0,0 @@ - 'Verification Code', - ]; - } - - /** - * Sends an email to the specified email address using the information collected by this model. - * @param string $email the target email address - * @return boolean whether the model passes validation - */ - public function contact($email) - { - if ($this->validate()) { - Yii::$app->mail->compose() - ->setTo($email) - ->setFrom([$this->email => $this->name]) - ->setSubject($this->subject) - ->setTextBody($this->body) - ->send(); - return true; - } else { - return false; - } - } -} diff --git a/apps/advanced/frontend/runtime/.gitignore b/apps/advanced/frontend/runtime/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/advanced/frontend/runtime/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/advanced/frontend/views/layouts/main.php b/apps/advanced/frontend/views/layouts/main.php deleted file mode 100644 index 2bfa9b0..0000000 --- a/apps/advanced/frontend/views/layouts/main.php +++ /dev/null @@ -1,70 +0,0 @@ - -beginPage() ?> - - - - - - <?= Html::encode($this->title) ?> - head() ?> - - - beginBody() ?> - 'My Company', - 'brandUrl' => Yii::$app->homeUrl, - 'options' => [ - 'class' => 'navbar-inverse navbar-fixed-top', - ], - ]); - $menuItems = [ - ['label' => 'Home', 'url' => ['/site/index']], - ['label' => 'About', 'url' => ['/site/about']], - ['label' => 'Contact', 'url' => ['/site/contact']], - ]; - if (Yii::$app->user->isGuest) { - $menuItems[] = ['label' => 'Signup', 'url' => ['/site/signup']]; - $menuItems[] = ['label' => 'Login', 'url' => ['/site/login']]; - } else { - $menuItems[] = ['label' => 'Logout (' . Yii::$app->user->identity->username .')' , 'url' => ['/site/logout']]; - } - echo Nav::widget([ - 'options' => ['class' => 'navbar-nav navbar-right'], - 'items' => $menuItems, - ]); - NavBar::end(); - ?> - -
    - isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], - ]) ?> - - -
    - -
    -
    -

    © My Company

    -

    -
    -
    - - endBody() ?> - - -endPage() ?> diff --git a/apps/advanced/frontend/views/site/about.php b/apps/advanced/frontend/views/site/about.php deleted file mode 100644 index ac4ab24..0000000 --- a/apps/advanced/frontend/views/site/about.php +++ /dev/null @@ -1,16 +0,0 @@ -title = 'About'; -$this->params['breadcrumbs'][] = $this->title; -?> -
    -

    title) ?>

    - -

    This is the About page. You may modify the following file to customize its content:

    - - -
    diff --git a/apps/advanced/frontend/views/site/contact.php b/apps/advanced/frontend/views/site/contact.php deleted file mode 100644 index 9aa98e6..0000000 --- a/apps/advanced/frontend/views/site/contact.php +++ /dev/null @@ -1,38 +0,0 @@ -title = 'Contact'; -$this->params['breadcrumbs'][] = $this->title; -?> -
    -

    title) ?>

    - -

    - If you have business inquiries or other questions, please fill out the following form to contact us. Thank you. -

    - -
    -
    - 'contact-form']); ?> - field($model, 'name') ?> - field($model, 'email') ?> - field($model, 'subject') ?> - field($model, 'body')->textArea(['rows' => 6]) ?> - field($model, 'verifyCode')->widget(Captcha::className(), [ - 'template' => '
    {image}
    {input}
    ', - ]) ?> -
    - 'btn btn-primary']) ?> -
    - -
    -
    - -
    diff --git a/apps/advanced/frontend/views/site/error.php b/apps/advanced/frontend/views/site/error.php deleted file mode 100644 index 1b7ce04..0000000 --- a/apps/advanced/frontend/views/site/error.php +++ /dev/null @@ -1,29 +0,0 @@ -title = $name; -?> -
    - -

    title) ?>

    - -
    - -
    - -

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

    -

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

    - -
    diff --git a/apps/advanced/frontend/views/site/index.php b/apps/advanced/frontend/views/site/index.php deleted file mode 100644 index bcb2278..0000000 --- a/apps/advanced/frontend/views/site/index.php +++ /dev/null @@ -1,53 +0,0 @@ -title = 'My Yii Application'; -?> -
    - -
    -

    Congratulations!

    - -

    You have successfully created your Yii-powered application.

    - -

    Get started with Yii

    -
    - -
    - -
    -
    -

    Heading

    - -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

    - -

    Yii Documentation »

    -
    -
    -

    Heading

    - -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

    - -

    Yii Forum »

    -
    -
    -

    Heading

    - -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

    - -

    Yii Extensions »

    -
    -
    - -
    -
    diff --git a/apps/advanced/frontend/views/site/login.php b/apps/advanced/frontend/views/site/login.php deleted file mode 100644 index 75dd4ca..0000000 --- a/apps/advanced/frontend/views/site/login.php +++ /dev/null @@ -1,33 +0,0 @@ -title = 'Login'; -$this->params['breadcrumbs'][] = $this->title; -?> - diff --git a/apps/advanced/frontend/views/site/requestPasswordResetToken.php b/apps/advanced/frontend/views/site/requestPasswordResetToken.php deleted file mode 100644 index bb13a5f..0000000 --- a/apps/advanced/frontend/views/site/requestPasswordResetToken.php +++ /dev/null @@ -1,28 +0,0 @@ -title = 'Request password reset'; -$this->params['breadcrumbs'][] = $this->title; -?> -
    -

    title) ?>

    - -

    Please fill out your email. A link to reset password will be sent there.

    - -
    -
    - 'request-password-reset-form']); ?> - field($model, 'email') ?> -
    - 'btn btn-primary']) ?> -
    - -
    -
    -
    diff --git a/apps/advanced/frontend/views/site/resetPassword.php b/apps/advanced/frontend/views/site/resetPassword.php deleted file mode 100644 index ec9f949..0000000 --- a/apps/advanced/frontend/views/site/resetPassword.php +++ /dev/null @@ -1,28 +0,0 @@ -title = 'Reset password'; -$this->params['breadcrumbs'][] = $this->title; -?> -
    -

    title) ?>

    - -

    Please choose your new password:

    - -
    -
    - 'reset-password-form']); ?> - field($model, 'password')->passwordInput() ?> -
    - 'btn btn-primary']) ?> -
    - -
    -
    -
    diff --git a/apps/advanced/frontend/views/site/signup.php b/apps/advanced/frontend/views/site/signup.php deleted file mode 100644 index 3bb57fc..0000000 --- a/apps/advanced/frontend/views/site/signup.php +++ /dev/null @@ -1,30 +0,0 @@ -title = 'Signup'; -$this->params['breadcrumbs'][] = $this->title; -?> - diff --git a/apps/advanced/frontend/web/.gitignore b/apps/advanced/frontend/web/.gitignore deleted file mode 100644 index 148f2b0..0000000 --- a/apps/advanced/frontend/web/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/index.php \ No newline at end of file diff --git a/apps/advanced/frontend/web/assets/.gitignore b/apps/advanced/frontend/web/assets/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/advanced/frontend/web/assets/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/advanced/frontend/web/css/site.css b/apps/advanced/frontend/web/css/site.css deleted file mode 100644 index a8508c4..0000000 --- a/apps/advanced/frontend/web/css/site.css +++ /dev/null @@ -1,79 +0,0 @@ -body { - padding-top: 70px; -} - -.footer { - border-top: 1px solid #ddd; - margin-top: 30px; - padding-top: 15px; - padding-bottom: 30px; -} - -.jumbotron { - text-align: center; - background-color: transparent; -} - -.jumbotron .btn { - font-size: 21px; - padding: 14px 24px; -} - -.not-set { - color: #c55; - font-style: italic; -} - -/* add sorting icons to gridview sort links */ -a.asc:after, a.desc:after { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: normal; - line-height: 1; - padding-left: 5px; -} - -a.asc:after { - content: /*"\e113"*/ "\e151"; -} - -a.desc:after { - content: /*"\e114"*/ "\e152"; -} - -.sort-numerical a.asc:after { - content: "\e153"; -} - -.sort-numerical a.desc:after { - content: "\e154"; -} - -.sort-ordinal a.asc:after { - content: "\e155"; -} - -.sort-ordinal a.desc:after { - content: "\e156"; -} - -.grid-view th { - white-space: nowrap; -} - -.hint-block { - display: block; - margin-top: 5px; - color: #999; -} - -.error-summary { - color: #a94442; - background: #fdf7f7; - border-left: 3px solid #eed3d7; - padding: 10px 20px; - margin: 0 0 15px 0; -} diff --git a/apps/advanced/frontend/web/favicon.ico b/apps/advanced/frontend/web/favicon.ico deleted file mode 100644 index 49e61e33ca94362545346cb218c62dc7807e9c66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcma)6XH1hp7(Rmu{|GtU+!^sFa8rsCv}Jk%uOI+4N{Oj%&Pr>HDfEM$SlXWB1Hz(U z=q`_hetCNkh4Fv)y`0bdjM_j#e<+ev-v&l=4iw2c-UG{xrn23ZP6ZdY2&U;sgmB!MCG& zPViGpf_QK&ieQ-2k5Nuv5z%G|~6pzA1+W5r4)V$G60fX<= z_5nON#o*SQ2hNQdkSS&*ggllP?sgTy0Y3?thD*ULrXP+a5|6ZDaLgIev<}Qz&tpo@ zi(NG3){+k{P1)eYN(Vc}b4V4|ys-2Xb?vn8f;|^RU>vyM5#0~onF@Z_(5$icjgetSession()->setFlash('error', 'This is the message'); - * - \Yii::$app->getSession()->setFlash('success', 'This is the message'); - * - \Yii::$app->getSession()->setFlash('info', 'This is the message'); - * - * @author Kartik Visweswaran - * @author Alexander Makarov - */ -class Alert extends \yii\bootstrap\Widget -{ - /** - * @var array the alert types configuration for the flash messages. - * This array is setup as $key => $value, where: - * - $key is the name of the session flash variable - * - $value is the bootstrap alert type (i.e. danger, success, info, warning) - */ - public $alertTypes = [ - 'error' => 'danger', - 'danger' => 'danger', - 'success' => 'success', - 'info' => 'info', - 'warning' => 'warning' - ]; - - /** - * @var array the options for rendering the close button tag. - */ - public $closeButton = []; - - public function init() - { - parent::init(); - - $session = \Yii::$app->getSession(); - $flashes = $session->getAllFlashes(); - $appendCss = isset($this->options['class']) ? ' ' . $this->options['class'] : ''; - - foreach ($flashes as $type => $message) { - /* initialize css class for each alert box */ - $this->options['class'] = 'alert-' . $this->alertTypes[$type] . $appendCss; - - /* assign unique id to each alert box */ - $this->options['id'] = $this->getId() . '-' . $type; - - echo \yii\bootstrap\Alert::widget([ - 'body' => $message, - 'closeButton' => $this->closeButton, - 'options' => $this->options - ]); - - $session->removeFlash($type); - } - } -} diff --git a/apps/advanced/init b/apps/advanced/init deleted file mode 100755 index 4015748..0000000 --- a/apps/advanced/init +++ /dev/null @@ -1,154 +0,0 @@ -#!/usr/bin/env php - $name) { - echo " [$i] $name\n"; - } - echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] '; - $answer = trim(fgets(STDIN)); - - if (!ctype_digit($answer) || !in_array($answer, range(0, count($envs) - 1))) { - echo "\n Quit initialization.\n"; - exit(0); - } - - if (isset($envNames[$answer])) { - $envName = $envNames[$answer]; - } -} -else { - $envName = $params['env']; -} - -if (!in_array($envName, $envNames)) { - $envsList = implode(', ', $envNames); - echo "\n $envName is not a valid environment. Try one of the following: $envsList. \n"; - exit(2); -} - -$env = $envs[$envName]; - -if (empty($params['env'])) { - echo "\n Initialize the application under '{$envNames[$answer]}' environment? [yes|no] "; - $answer = trim(fgets(STDIN)); - if (strncasecmp($answer, 'y', 1)) { - echo "\n Quit initialization.\n"; - exit(0); - } -} - -echo "\n Start initialization ...\n\n"; -$files = getFileList("$root/environments/{$env['path']}"); -$all = false; -foreach ($files as $file) { - if (!copyFile($root, "environments/{$env['path']}/$file", $file, $all)) { - break; - } -} - -if (isset($env['writable'])) { - foreach ($env['writable'] as $writable) { - echo " chmod 0777 $writable\n"; - @chmod("$root/$writable", 0777); - } -} - -if (isset($env['executable'])) { - foreach ($env['executable'] as $executable) { - echo " chmod 0755 $executable\n"; - @chmod("$root/$executable", 0755); - } -} - -echo "\n ... initialization completed.\n\n"; - -function getFileList($root, $basePath = '') -{ - $files = []; - $handle = opendir($root); - while (($path = readdir($handle)) !== false) { - if ($path === '.svn' || $path === '.' || $path === '..') { - continue; - } - $fullPath = "$root/$path"; - $relativePath = $basePath === '' ? $path : "$basePath/$path"; - if (is_dir($fullPath)) { - $files = array_merge($files, getFileList($fullPath, $relativePath)); - } else { - $files[] = $relativePath; - } - } - closedir($handle); - return $files; -} - -function copyFile($root, $source, $target, &$all) -{ - if (!is_file($root . '/' . $source)) { - echo " skip $target ($source not exist)\n"; - return true; - } - if (is_file($root . '/' . $target)) { - if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) { - echo " unchanged $target\n"; - return true; - } - if ($all) { - echo " overwrite $target\n"; - } else { - echo " exist $target\n"; - echo " ...overwrite? [Yes|No|All|Quit] "; - $answer = trim(fgets(STDIN)); - if (!strncasecmp($answer, 'q', 1)) { - return false; - } else { - if (!strncasecmp($answer, 'y', 1)) { - echo " overwrite $target\n"; - } else { - if (!strncasecmp($answer, 'a', 1)) { - echo " overwrite $target\n"; - $all = true; - } else { - echo " skip $target\n"; - return true; - } - } - } - } - file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source)); - return true; - } - echo " generate $target\n"; - @mkdir(dirname($root . '/' . $target), 0777, true); - file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source)); - return true; -} - -function getParams() -{ - $rawParams = []; - if (isset($_SERVER['argv'])) { - $rawParams = $_SERVER['argv']; - array_shift($rawParams); - } - - $params = []; - foreach ($rawParams as $param) { - if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) { - $name = $matches[1]; - $params[$name] = isset($matches[3]) ? $matches[3] : true; - } else { - $params[] = $param; - } - } - return $params; -} diff --git a/apps/advanced/init.bat b/apps/advanced/init.bat deleted file mode 100644 index 4fc52f7..0000000 --- a/apps/advanced/init.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line init script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%init" %* - -@endlocal diff --git a/apps/advanced/requirements.php b/apps/advanced/requirements.php deleted file mode 100644 index 5c6495c..0000000 --- a/apps/advanced/requirements.php +++ /dev/null @@ -1,110 +0,0 @@ -Error'; - echo '

    The path to yii framework seems to be incorrect.

    '; - echo '

    You need to install Yii framework via composer or adjust the framework path in file ' . basename(__FILE__) .'.

    '; - echo '

    Please refer to the README on how to install Yii.

    '; -} - -require_once($frameworkPath . '/requirements/YiiRequirementChecker.php'); -$requirementsChecker = new YiiRequirementChecker(); - -/** - * Adjust requirements according to your application specifics. - */ -$requirements = array( - // Database : - array( - 'name' => 'PDO extension', - 'mandatory' => true, - 'condition' => extension_loaded('pdo'), - 'by' => 'All DB-related classes', - ), - array( - 'name' => 'PDO SQLite extension', - 'mandatory' => false, - 'condition' => extension_loaded('pdo_sqlite'), - 'by' => 'All DB-related classes', - 'memo' => 'Required for SQLite database.', - ), - array( - 'name' => 'PDO MySQL extension', - 'mandatory' => false, - 'condition' => extension_loaded('pdo_mysql'), - 'by' => 'All DB-related classes', - 'memo' => 'Required for MySQL database.', - ), - array( - 'name' => 'PDO PostgreSQL extension', - 'mandatory' => false, - 'condition' => extension_loaded('pdo_pgsql'), - 'by' => 'All DB-related classes', - 'memo' => 'Required for PostgreSQL database.', - ), - // Cache : - array( - 'name' => 'Memcache extension', - 'mandatory' => false, - 'condition' => extension_loaded('memcache') || extension_loaded('memcached'), - 'by' => 'CMemCache', - 'memo' => extension_loaded('memcached') ? 'To use memcached set CMemCache::useMemcached to true.' : '' - ), - array( - 'name' => 'APC extension', - 'mandatory' => false, - 'condition' => extension_loaded('apc'), - 'by' => 'CApcCache', - ), - // Additional PHP extensions : - array( - 'name' => 'Mcrypt extension', - 'mandatory' => false, - 'condition' => extension_loaded('mcrypt'), - 'by' => 'CSecurityManager', - 'memo' => 'Required by encrypt and decrypt methods.' - ), - // PHP ini : - 'phpSafeMode' => array( - 'name' => 'PHP safe mode', - 'mandatory' => false, - 'condition' => $requirementsChecker->checkPhpIniOff("safe_mode"), - 'by' => 'File uploading and console command execution', - 'memo' => '"safe_mode" should be disabled at php.ini', - ), - 'phpExposePhp' => array( - 'name' => 'Expose PHP', - 'mandatory' => false, - 'condition' => $requirementsChecker->checkPhpIniOff("expose_php"), - 'by' => 'Security reasons', - 'memo' => '"expose_php" should be disabled at php.ini', - ), - 'phpAllowUrlInclude' => array( - 'name' => 'PHP allow url include', - 'mandatory' => false, - 'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"), - 'by' => 'Security reasons', - 'memo' => '"allow_url_include" should be disabled at php.ini', - ), - 'phpSmtp' => array( - 'name' => 'PHP mail SMTP', - 'mandatory' => false, - 'condition' => strlen(ini_get('SMTP'))>0, - 'by' => 'Email sending', - 'memo' => 'PHP mail SMTP server required', - ), -); -$requirementsChecker->checkYii()->check($requirements)->render(); diff --git a/apps/advanced/vendor/.gitignore b/apps/advanced/vendor/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/advanced/vendor/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/advanced/yii.bat b/apps/advanced/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/advanced/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/basic/LICENSE.md b/apps/basic/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/apps/basic/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/apps/basic/README.md b/apps/basic/README.md deleted file mode 100644 index b233770..0000000 --- a/apps/basic/README.md +++ /dev/null @@ -1,64 +0,0 @@ -Yii 2 Basic Application Template -================================ - -Yii 2 Basic Application Template is a skeleton Yii 2 application best for -rapidly developing small Websites containing mainly informational pages. - -The template contains the basic features including user login/logout and a contact page. -It includes all commonly used configurations that would allow you to focus on adding new -features to your application. - - -DIRECTORY STRUCTURE -------------------- - - commands/ contains console commands (controllers) - config/ contains application configurations - controllers/ contains Web controller classes - models/ contains model classes - runtime/ contains files generated during runtime - vendor/ contains dependent 3rd-party packages - views/ contains view files for the Web application - web/ contains the entry script and Web resources - - - -REQUIREMENTS ------------- - -The minimum requirement by this application template that your Web server supports PHP 5.4.0. - - -INSTALLATION ------------- - -### Install from an Archive File - -Extract the archive file downloaded from [yiiframework.com](http://www.yiiframework.com/download/) to -a directory named `basic` that is directly under the Web root. - -You can then access the application through the following URL: - -~~~ -http://localhost/basic/web/ -~~~ - - -### Install via Composer - -If you do not have [Composer](http://getcomposer.org/), you may install it by following the instructions -at [getcomposer.org](http://getcomposer.org/doc/00-intro.md#installation-nix). - -You can then install this application template using the following command: - -~~~ -php composer.phar create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic -~~~ - -Now you should be able to access the application through the following URL, assuming `basic` is the directory -directly under the Web root. - -~~~ -http://localhost/basic/web/ -~~~ - diff --git a/apps/basic/assets/AppAsset.php b/apps/basic/assets/AppAsset.php deleted file mode 100644 index c964d36..0000000 --- a/apps/basic/assets/AppAsset.php +++ /dev/null @@ -1,29 +0,0 @@ - - * @since 2.0 - */ -class AppAsset extends AssetBundle -{ - public $basePath = '@webroot'; - public $baseUrl = '@web'; - public $css = [ - 'css/site.css', - ]; - public $js = [ - ]; - public $depends = [ - 'yii\web\YiiAsset', - 'yii\bootstrap\BootstrapAsset', - ]; -} diff --git a/apps/basic/codeception.yml b/apps/basic/codeception.yml deleted file mode 100644 index 864fba0..0000000 --- a/apps/basic/codeception.yml +++ /dev/null @@ -1,18 +0,0 @@ -paths: - tests: tests - log: tests/_log - data: tests/_data - helpers: tests/_helpers -settings: - bootstrap: _bootstrap.php - suite_class: \PHPUnit_Framework_TestSuite - memory_limit: 1024M - log: true - colors: true -modules: - config: - Db: - dsn: '' - user: '' - password: '' - dump: tests/_data/dump.sql diff --git a/apps/basic/commands/HelloController.php b/apps/basic/commands/HelloController.php deleted file mode 100644 index ce567dd..0000000 --- a/apps/basic/commands/HelloController.php +++ /dev/null @@ -1,30 +0,0 @@ - - * @since 2.0 - */ -class HelloController extends Controller -{ - /** - * This command echoes what you have entered as the message. - * @param string $message the message to be echoed. - */ - public function actionIndex($message = 'hello world') - { - echo $message . "\n"; - } -} diff --git a/apps/basic/composer.json b/apps/basic/composer.json deleted file mode 100644 index e45c994..0000000 --- a/apps/basic/composer.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "yiisoft/yii2-app-basic", - "description": "Yii 2 Basic Application Template", - "keywords": ["yii", "framework", "basic", "application template"], - "homepage": "http://www.yiiframework.com/", - "type": "project", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?state=open", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "minimum-stability": "dev", - "require": { - "php": ">=5.4.0", - "yiisoft/yii2": "*", - "yiisoft/yii2-bootstrap": "*", - "yiisoft/yii2-swiftmailer": "*" - }, - "require-dev": { - "yiisoft/yii2-codeception": "*", - "yiisoft/yii2-debug": "*", - "yiisoft/yii2-gii": "*", - "codeception/codeception": "*", - "codeception/specify": "*" - }, - "scripts": { - "post-create-project-cmd": [ - "yii\\composer\\Installer::setPermission" - ] - }, - "config": { - "process-timeout": 1800 - }, - "extra": { - "writable": [ - "runtime", - "web/assets" - ], - "executable": [ - "yii" - ] - } -} diff --git a/apps/basic/config/console.php b/apps/basic/config/console.php deleted file mode 100644 index 6b245c4..0000000 --- a/apps/basic/config/console.php +++ /dev/null @@ -1,34 +0,0 @@ - 'basic-console', - 'basePath' => dirname(__DIR__), - 'preload' => ['log'], - 'controllerPath' => dirname(__DIR__) . '/commands', - 'controllerNamespace' => 'app\commands', - 'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'), - 'components' => [ - 'cache' => [ - 'class' => 'yii\caching\FileCache', - ], - 'log' => [ - 'targets' => [ - [ - 'class' => 'yii\log\FileTarget', - 'levels' => ['error', 'warning'], - ], - ], - ], - 'db' => $db, - 'fixture' => [ - 'class' => 'yii\test\DbFixtureManager', - 'basePath' => '@tests/unit/fixtures', - ], - ], - 'params' => $params, -]; diff --git a/apps/basic/config/db.php b/apps/basic/config/db.php deleted file mode 100644 index b14e77e..0000000 --- a/apps/basic/config/db.php +++ /dev/null @@ -1,9 +0,0 @@ - 'yii\db\Connection', - 'dsn' => 'mysql:host=localhost;dbname=yii2basic', - 'username' => 'root', - 'password' => '', - 'charset' => 'utf8', -]; diff --git a/apps/basic/config/params.php b/apps/basic/config/params.php deleted file mode 100644 index 93cb368..0000000 --- a/apps/basic/config/params.php +++ /dev/null @@ -1,5 +0,0 @@ - 'admin@example.com', -]; diff --git a/apps/basic/config/web.php b/apps/basic/config/web.php deleted file mode 100644 index 56ec9f8..0000000 --- a/apps/basic/config/web.php +++ /dev/null @@ -1,45 +0,0 @@ - 'basic', - 'basePath' => dirname(__DIR__), - 'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'), - 'components' => [ - 'cache' => [ - 'class' => 'yii\caching\FileCache', - ], - 'user' => [ - 'identityClass' => 'app\models\User', - 'enableAutoLogin' => true, - ], - 'errorHandler' => [ - 'errorAction' => 'site/error', - ], - 'mail' => [ - 'class' => 'yii\swiftmailer\Mailer', - ], - 'log' => [ - 'traceLevel' => YII_DEBUG ? 3 : 0, - 'targets' => [ - [ - 'class' => 'yii\log\FileTarget', - 'levels' => ['error', 'warning'], - ], - ], - ], - 'db' => $db, - ], - 'params' => $params, -]; - -if (YII_ENV_DEV) { - // configuration adjustments for 'dev' environment - $config['preload'][] = 'debug'; - $config['modules']['debug'] = 'yii\debug\Module'; - $config['modules']['gii'] = 'yii\gii\Module'; -} - -return $config; diff --git a/apps/basic/controllers/SiteController.php b/apps/basic/controllers/SiteController.php deleted file mode 100644 index e3ca29b..0000000 --- a/apps/basic/controllers/SiteController.php +++ /dev/null @@ -1,94 +0,0 @@ - [ - 'class' => AccessControl::className(), - 'only' => ['logout'], - 'rules' => [ - [ - 'actions' => ['logout'], - 'allow' => true, - 'roles' => ['@'], - ], - ], - ], - 'verbs' => [ - 'class' => VerbFilter::className(), - 'actions' => [ - 'logout' => ['post'], - ], - ], - ]; - } - - public function actions() - { - return [ - 'error' => [ - 'class' => 'yii\web\ErrorAction', - ], - 'captcha' => [ - 'class' => 'yii\captcha\CaptchaAction', - 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null, - ], - ]; - } - - public function actionIndex() - { - return $this->render('index'); - } - - public function actionLogin() - { - if (!\Yii::$app->user->isGuest) { - $this->goHome(); - } - - $model = new LoginForm(); - if ($model->load($_POST) && $model->login()) { - return $this->goBack(); - } else { - return $this->render('login', [ - 'model' => $model, - ]); - } - } - - public function actionLogout() - { - Yii::$app->user->logout(); - return $this->goHome(); - } - - public function actionContact() - { - $model = new ContactForm; - if ($model->load($_POST) && $model->contact(Yii::$app->params['adminEmail'])) { - Yii::$app->session->setFlash('contactFormSubmitted'); - return $this->refresh(); - } else { - return $this->render('contact', [ - 'model' => $model, - ]); - } - } - - public function actionAbout() - { - return $this->render('about'); - } -} diff --git a/apps/basic/mails/layouts/html.php b/apps/basic/mails/layouts/html.php deleted file mode 100644 index 2e6b615..0000000 --- a/apps/basic/mails/layouts/html.php +++ /dev/null @@ -1,24 +0,0 @@ - -beginPage() ?> - - - - - <?= Html::encode($this->title) ?> - head() ?> - - - beginBody() ?> - - endBody() ?> - - -endPage() ?> \ No newline at end of file diff --git a/apps/basic/models/ContactForm.php b/apps/basic/models/ContactForm.php deleted file mode 100644 index 1344562..0000000 --- a/apps/basic/models/ContactForm.php +++ /dev/null @@ -1,63 +0,0 @@ - 'Verification Code', - ]; - } - - /** - * Sends an email to the specified email address using the information collected by this model. - * @param string $email the target email address - * @return boolean whether the model passes validation - */ - public function contact($email) - { - if ($this->validate()) { - Yii::$app->mail->compose() - ->setTo($email) - ->setFrom([$this->email => $this->name]) - ->setSubject($this->subject) - ->setTextBody($this->body) - ->send(); - return true; - } else { - return false; - } - } -} diff --git a/apps/basic/models/LoginForm.php b/apps/basic/models/LoginForm.php deleted file mode 100644 index d536443..0000000 --- a/apps/basic/models/LoginForm.php +++ /dev/null @@ -1,72 +0,0 @@ -getUser(); - - if (!$user || !$user->validatePassword($this->password)) { - $this->addError('password', 'Incorrect username or password.'); - } - } - - /** - * Logs in a user using the provided username and password. - * @return boolean whether the user is logged in successfully - */ - public function login() - { - if ($this->validate()) { - return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0); - } else { - return false; - } - } - - /** - * Finds user by [[username]] - * - * @return User|null - */ - public function getUser() - { - if ($this->_user === false) { - $this->_user = User::findByUsername($this->username); - } - return $this->_user; - } -} diff --git a/apps/basic/models/User.php b/apps/basic/models/User.php deleted file mode 100644 index af4c42e..0000000 --- a/apps/basic/models/User.php +++ /dev/null @@ -1,61 +0,0 @@ - [ - 'id' => '100', - 'username' => 'admin', - 'password' => 'admin', - 'authKey' => 'test100key', - ], - '101' => [ - 'id' => '101', - 'username' => 'demo', - 'password' => 'demo', - 'authKey' => 'test101key', - ], - ]; - - public static function findIdentity($id) - { - return isset(self::$users[$id]) ? new static(self::$users[$id]) : null; - } - - public static function findByUsername($username) - { - foreach (self::$users as $user) { - if (strcasecmp($user['username'], $username) === 0) { - return new static($user); - } - } - return null; - } - - public function getId() - { - return $this->id; - } - - public function getAuthKey() - { - return $this->authKey; - } - - public function validateAuthKey($authKey) - { - return $this->authKey === $authKey; - } - - public function validatePassword($password) - { - return $this->password === $password; - } -} diff --git a/apps/basic/requirements.php b/apps/basic/requirements.php deleted file mode 100644 index 5c6495c..0000000 --- a/apps/basic/requirements.php +++ /dev/null @@ -1,110 +0,0 @@ -Error'; - echo '

    The path to yii framework seems to be incorrect.

    '; - echo '

    You need to install Yii framework via composer or adjust the framework path in file ' . basename(__FILE__) .'.

    '; - echo '

    Please refer to the README on how to install Yii.

    '; -} - -require_once($frameworkPath . '/requirements/YiiRequirementChecker.php'); -$requirementsChecker = new YiiRequirementChecker(); - -/** - * Adjust requirements according to your application specifics. - */ -$requirements = array( - // Database : - array( - 'name' => 'PDO extension', - 'mandatory' => true, - 'condition' => extension_loaded('pdo'), - 'by' => 'All DB-related classes', - ), - array( - 'name' => 'PDO SQLite extension', - 'mandatory' => false, - 'condition' => extension_loaded('pdo_sqlite'), - 'by' => 'All DB-related classes', - 'memo' => 'Required for SQLite database.', - ), - array( - 'name' => 'PDO MySQL extension', - 'mandatory' => false, - 'condition' => extension_loaded('pdo_mysql'), - 'by' => 'All DB-related classes', - 'memo' => 'Required for MySQL database.', - ), - array( - 'name' => 'PDO PostgreSQL extension', - 'mandatory' => false, - 'condition' => extension_loaded('pdo_pgsql'), - 'by' => 'All DB-related classes', - 'memo' => 'Required for PostgreSQL database.', - ), - // Cache : - array( - 'name' => 'Memcache extension', - 'mandatory' => false, - 'condition' => extension_loaded('memcache') || extension_loaded('memcached'), - 'by' => 'CMemCache', - 'memo' => extension_loaded('memcached') ? 'To use memcached set CMemCache::useMemcached to true.' : '' - ), - array( - 'name' => 'APC extension', - 'mandatory' => false, - 'condition' => extension_loaded('apc'), - 'by' => 'CApcCache', - ), - // Additional PHP extensions : - array( - 'name' => 'Mcrypt extension', - 'mandatory' => false, - 'condition' => extension_loaded('mcrypt'), - 'by' => 'CSecurityManager', - 'memo' => 'Required by encrypt and decrypt methods.' - ), - // PHP ini : - 'phpSafeMode' => array( - 'name' => 'PHP safe mode', - 'mandatory' => false, - 'condition' => $requirementsChecker->checkPhpIniOff("safe_mode"), - 'by' => 'File uploading and console command execution', - 'memo' => '"safe_mode" should be disabled at php.ini', - ), - 'phpExposePhp' => array( - 'name' => 'Expose PHP', - 'mandatory' => false, - 'condition' => $requirementsChecker->checkPhpIniOff("expose_php"), - 'by' => 'Security reasons', - 'memo' => '"expose_php" should be disabled at php.ini', - ), - 'phpAllowUrlInclude' => array( - 'name' => 'PHP allow url include', - 'mandatory' => false, - 'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"), - 'by' => 'Security reasons', - 'memo' => '"allow_url_include" should be disabled at php.ini', - ), - 'phpSmtp' => array( - 'name' => 'PHP mail SMTP', - 'mandatory' => false, - 'condition' => strlen(ini_get('SMTP'))>0, - 'by' => 'Email sending', - 'memo' => 'PHP mail SMTP server required', - ), -); -$requirementsChecker->checkYii()->check($requirements)->render(); diff --git a/apps/basic/runtime/.gitignore b/apps/basic/runtime/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/basic/runtime/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/basic/tests/.gitignore b/apps/basic/tests/.gitignore deleted file mode 100644 index c5aa074..0000000 --- a/apps/basic/tests/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# these files are auto generated by codeception build -/unit/CodeGuy.php -/functional/TestGuy.php -/acceptance/WebGuy.php diff --git a/apps/basic/tests/README.md b/apps/basic/tests/README.md deleted file mode 100644 index 83b0511..0000000 --- a/apps/basic/tests/README.md +++ /dev/null @@ -1,28 +0,0 @@ -This folder contains various tests for the basic application. -These tests are developed with [Codeception PHP Testing Framework](http://codeception.com/). - -After creating the basic application, follow these steps to prepare for the tests: - -1. In the file `_bootstrap.php`, modify the definition of the constant `TEST_ENTRY_URL` so - that it points to the correct entry script URL. -2. Go to the application base directory and build the test suites: - - ``` - vendor/bin/codecept build - ``` - -Now you can run the tests with the following commands: - -``` -# run all available tests -vendor/bin/codecept run -# run acceptance tests -vendor/bin/codecept run acceptance -# run functional tests -vendor/bin/codecept run functional -# run unit tests -vendor/bin/codecept run unit -``` - -Please refer to [Codeception tutorial](http://codeception.com/docs/01-Introduction) for -more details about writing and running acceptance, functional and unit tests. diff --git a/apps/basic/tests/_bootstrap.php b/apps/basic/tests/_bootstrap.php deleted file mode 100644 index 07e86c7..0000000 --- a/apps/basic/tests/_bootstrap.php +++ /dev/null @@ -1,22 +0,0 @@ - [ - 'mail' => [ - 'useFileTransport' => true, - ], - 'urlManager' => [ - 'showScriptName' => true, - ], - ], -]; diff --git a/apps/basic/tests/_data/dump.sql b/apps/basic/tests/_data/dump.sql deleted file mode 100644 index 4bc742c..0000000 --- a/apps/basic/tests/_data/dump.sql +++ /dev/null @@ -1 +0,0 @@ -/* Replace this file with actual dump of your database */ \ No newline at end of file diff --git a/apps/basic/tests/_helpers/CodeHelper.php b/apps/basic/tests/_helpers/CodeHelper.php deleted file mode 100644 index 6448486..0000000 --- a/apps/basic/tests/_helpers/CodeHelper.php +++ /dev/null @@ -1,7 +0,0 @@ - $value) { - $data["ContactForm[$name]"] = $value; - } - $this->guy->submitForm('#contact-form', $data); - } -} diff --git a/apps/basic/tests/_pages/LoginPage.php b/apps/basic/tests/_pages/LoginPage.php deleted file mode 100644 index aae5e0f..0000000 --- a/apps/basic/tests/_pages/LoginPage.php +++ /dev/null @@ -1,22 +0,0 @@ -guy->submitForm('#login-form', [ - 'LoginForm[username]' => $username, - 'LoginForm[password]' => $password, - ]); - } -} diff --git a/apps/basic/tests/acceptance.suite.yml b/apps/basic/tests/acceptance.suite.yml deleted file mode 100644 index 34e4397..0000000 --- a/apps/basic/tests/acceptance.suite.yml +++ /dev/null @@ -1,24 +0,0 @@ -# Codeception Test Suite Configuration - -# suite for acceptance tests. -# perform tests in browser using the Selenium-like tools. -# powered by Mink (http://mink.behat.org). -# (tip: that's what your customer will see). -# (tip: test your ajax and javascript by one of Mink drivers). - -# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. - -class_name: WebGuy -modules: - enabled: - - WebHelper - - PhpBrowser -# you can use WebDriver instead of PhpBrowser to test javascript and ajax. -# This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium -# - WebDriver - config: - PhpBrowser: - url: 'http://localhost:8080' -# WebDriver: -# url: 'http://localhost' -# browser: firefox diff --git a/apps/basic/tests/acceptance/AboutCept.php b/apps/basic/tests/acceptance/AboutCept.php deleted file mode 100644 index deecee7..0000000 --- a/apps/basic/tests/acceptance/AboutCept.php +++ /dev/null @@ -1,8 +0,0 @@ -wantTo('ensure that about works'); -AboutPage::openBy($I); -$I->see('About', 'h1'); diff --git a/apps/basic/tests/acceptance/ContactCept.php b/apps/basic/tests/acceptance/ContactCept.php deleted file mode 100644 index 25f5735..0000000 --- a/apps/basic/tests/acceptance/ContactCept.php +++ /dev/null @@ -1,49 +0,0 @@ -wantTo('ensure that contact works'); - -$contactPage = ContactPage::openBy($I); - -$I->see('Contact', 'h1'); - -$I->amGoingTo('submit contact form with no data'); -$contactPage->submit([]); -$I->expectTo('see validations errors'); -$I->see('Contact', 'h1'); -$I->see('Name cannot be blank'); -$I->see('Email cannot be blank'); -$I->see('Subject cannot be blank'); -$I->see('Body cannot be blank'); -$I->see('The verification code is incorrect'); - -$I->amGoingTo('submit contact form with not correct email'); -$contactPage->submit([ - 'name' => 'tester', - 'email' => 'tester.email', - 'subject' => 'test subject', - 'body' => 'test content', - 'verifyCode' => 'testme', -]); -$I->expectTo('see that email adress is wrong'); -$I->dontSee('Name cannot be blank', '.help-inline'); -$I->see('Email is not a valid email address.'); -$I->dontSee('Subject cannot be blank', '.help-inline'); -$I->dontSee('Body cannot be blank', '.help-inline'); -$I->dontSee('The verification code is incorrect', '.help-inline'); - -$I->amGoingTo('submit contact form with correct data'); -$contactPage->submit([ - 'name' => 'tester', - 'email' => 'tester@example.com', - 'subject' => 'test subject', - 'body' => 'test content', - 'verifyCode' => 'testme', -]); -if (method_exists($I, 'wait')) { - $I->wait(3); // only for selenium -} -$I->dontSeeElement('#contact-form'); -$I->see('Thank you for contacting us. We will respond to you as soon as possible.'); diff --git a/apps/basic/tests/acceptance/HomeCept.php b/apps/basic/tests/acceptance/HomeCept.php deleted file mode 100644 index 62456f9..0000000 --- a/apps/basic/tests/acceptance/HomeCept.php +++ /dev/null @@ -1,9 +0,0 @@ -wantTo('ensure that home page works'); -$I->amOnPage(Yii::$app->homeUrl); -$I->see('My Company'); -$I->seeLink('About'); -$I->click('About'); -$I->see('This is the About page.'); diff --git a/apps/basic/tests/acceptance/LoginCept.php b/apps/basic/tests/acceptance/LoginCept.php deleted file mode 100644 index 5d6a387..0000000 --- a/apps/basic/tests/acceptance/LoginCept.php +++ /dev/null @@ -1,29 +0,0 @@ -wantTo('ensure that login works'); - -$loginPage = LoginPage::openBy($I); - -$I->see('Login', 'h1'); - -$I->amGoingTo('try to login with empty credentials'); -$loginPage->login('', ''); -$I->expectTo('see validations errors'); -$I->see('Username cannot be blank.'); -$I->see('Password cannot be blank.'); - -$I->amGoingTo('try to login with wrong credentials'); -$loginPage->login('admin', 'wrong'); -$I->expectTo('see validations errors'); -$I->see('Incorrect username or password.'); - -$I->amGoingTo('try to login with correct credentials'); -$loginPage->login('admin', 'admin'); -if (method_exists($I, 'wait')) { - $I->wait(3); // only for selenium -} -$I->expectTo('see user info'); -$I->see('Logout (admin)'); diff --git a/apps/basic/tests/acceptance/_bootstrap.php b/apps/basic/tests/acceptance/_bootstrap.php deleted file mode 100644 index 6ce3d17..0000000 --- a/apps/basic/tests/acceptance/_bootstrap.php +++ /dev/null @@ -1,3 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_basic_acceptance', - ], - ], - ] -); diff --git a/apps/basic/tests/functional.suite.yml b/apps/basic/tests/functional.suite.yml deleted file mode 100644 index 0d400af..0000000 --- a/apps/basic/tests/functional.suite.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Codeception Test Suite Configuration - -# suite for functional (integration) tests. -# emulate web requests and make application process them. -# (tip: better to use with frameworks). - -# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. -#basic/web/index.php -class_name: TestGuy -modules: - enabled: - - Filesystem - - TestHelper - - Yii2 - config: - Yii2: - configFile: 'tests/functional/_config.php' diff --git a/apps/basic/tests/functional/AboutCept.php b/apps/basic/tests/functional/AboutCept.php deleted file mode 100644 index 1875c2e..0000000 --- a/apps/basic/tests/functional/AboutCept.php +++ /dev/null @@ -1,8 +0,0 @@ -wantTo('ensure that about works'); -AboutPage::openBy($I); -$I->see('About', 'h1'); diff --git a/apps/basic/tests/functional/ContactCept.php b/apps/basic/tests/functional/ContactCept.php deleted file mode 100644 index 14e6197..0000000 --- a/apps/basic/tests/functional/ContactCept.php +++ /dev/null @@ -1,46 +0,0 @@ -wantTo('ensure that contact works'); - -$contactPage = ContactPage::openBy($I); - -$I->see('Contact', 'h1'); - -$I->amGoingTo('submit contact form with no data'); -$contactPage->submit([]); -$I->expectTo('see validations errors'); -$I->see('Contact', 'h1'); -$I->see('Name cannot be blank'); -$I->see('Email cannot be blank'); -$I->see('Subject cannot be blank'); -$I->see('Body cannot be blank'); -$I->see('The verification code is incorrect'); - -$I->amGoingTo('submit contact form with not correct email'); -$contactPage->submit([ - 'name' => 'tester', - 'email' => 'tester.email', - 'subject' => 'test subject', - 'body' => 'test content', - 'verifyCode' => 'testme', -]); -$I->expectTo('see that email adress is wrong'); -$I->dontSee('Name cannot be blank', '.help-inline'); -$I->see('Email is not a valid email address.'); -$I->dontSee('Subject cannot be blank', '.help-inline'); -$I->dontSee('Body cannot be blank', '.help-inline'); -$I->dontSee('The verification code is incorrect', '.help-inline'); - -$I->amGoingTo('submit contact form with correct data'); -$contactPage->submit([ - 'name' => 'tester', - 'email' => 'tester@example.com', - 'subject' => 'test subject', - 'body' => 'test content', - 'verifyCode' => 'testme', -]); -$I->dontSeeElement('#contact-form'); -$I->see('Thank you for contacting us. We will respond to you as soon as possible.'); diff --git a/apps/basic/tests/functional/HomeCept.php b/apps/basic/tests/functional/HomeCept.php deleted file mode 100644 index 3258ba3..0000000 --- a/apps/basic/tests/functional/HomeCept.php +++ /dev/null @@ -1,9 +0,0 @@ -wantTo('ensure that home page works'); -$I->amOnPage(Yii::$app->homeUrl); -$I->see('My Company'); -$I->seeLink('About'); -$I->click('About'); -$I->see('This is the About page.'); diff --git a/apps/basic/tests/functional/LoginCept.php b/apps/basic/tests/functional/LoginCept.php deleted file mode 100644 index e5285cd..0000000 --- a/apps/basic/tests/functional/LoginCept.php +++ /dev/null @@ -1,26 +0,0 @@ -wantTo('ensure that login works'); - -$loginPage = LoginPage::openBy($I); - -$I->see('Login', 'h1'); - -$I->amGoingTo('try to login with empty credentials'); -$loginPage->login('', ''); -$I->expectTo('see validations errors'); -$I->see('Username cannot be blank.'); -$I->see('Password cannot be blank.'); - -$I->amGoingTo('try to login with wrong credentials'); -$loginPage->login('admin', 'wrong'); -$I->expectTo('see validations errors'); -$I->see('Incorrect username or password.'); - -$I->amGoingTo('try to login with correct credentials'); -$loginPage->login('admin', 'admin'); -$I->expectTo('see user info'); -$I->see('Logout (admin)'); diff --git a/apps/basic/tests/functional/_bootstrap.php b/apps/basic/tests/functional/_bootstrap.php deleted file mode 100644 index 6ce3d17..0000000 --- a/apps/basic/tests/functional/_bootstrap.php +++ /dev/null @@ -1,3 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_basic_functional', - ], - ], - ] -); diff --git a/apps/basic/tests/unit.suite.yml b/apps/basic/tests/unit.suite.yml deleted file mode 100644 index be2874d..0000000 --- a/apps/basic/tests/unit.suite.yml +++ /dev/null @@ -1,9 +0,0 @@ -# Codeception Test Suite Configuration - -# suite for unit (internal) tests. -# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. - -class_name: CodeGuy -modules: - enabled: - - CodeHelper diff --git a/apps/basic/tests/unit/_bootstrap.php b/apps/basic/tests/unit/_bootstrap.php deleted file mode 100644 index 80cc72a..0000000 --- a/apps/basic/tests/unit/_bootstrap.php +++ /dev/null @@ -1,3 +0,0 @@ - [ - 'fixture' => [ - 'class' => 'yii\test\DbFixtureManager', - 'basePath' => '@tests/unit/fixtures', - ], - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_basic_unit', - ], - ], - ] -); diff --git a/apps/basic/tests/unit/fixtures/.gitkeep b/apps/basic/tests/unit/fixtures/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/apps/basic/tests/unit/models/ContactFormTest.php b/apps/basic/tests/unit/models/ContactFormTest.php deleted file mode 100644 index 8c67567..0000000 --- a/apps/basic/tests/unit/models/ContactFormTest.php +++ /dev/null @@ -1,59 +0,0 @@ -mail->fileTransportCallback = function ($mailer, $message) { - return 'testing_message.eml'; - }; - } - - protected function tearDown() - { - unlink($this->getMessageFile()); - parent::tearDown(); - } - - public function testContact() - { - $model = $this->getMock('app\models\ContactForm', ['validate']); - $model->expects($this->once())->method('validate')->will($this->returnValue(true)); - - $model->attributes = [ - 'name' => 'Tester', - 'email' => 'tester@example.com', - 'subject' => 'very important letter subject', - 'body' => 'body of current message', - ]; - - $model->contact('admin@example.com'); - - $this->specify('email should be send', function () { - $this->assertFileExists($this->getMessageFile(), 'email file should exist'); - }); - - $this->specify('message should contain correct data', function () use($model) { - $emailMessage = file_get_contents($this->getMessageFile()); - $this->assertContains($model->name, $emailMessage, 'email should contain user name'); - $this->assertContains($model->email, $emailMessage, 'email should contain sender email'); - $this->assertContains($model->subject, $emailMessage, 'email should contain subject'); - $this->assertContains($model->body, $emailMessage, 'email should contain body'); - }); - } - - private function getMessageFile() - { - return Yii::getAlias(Yii::$app->mail->fileTransportPath) . '/testing_message.eml'; - } - -} diff --git a/apps/basic/tests/unit/models/LoginFormTest.php b/apps/basic/tests/unit/models/LoginFormTest.php deleted file mode 100644 index f232a47..0000000 --- a/apps/basic/tests/unit/models/LoginFormTest.php +++ /dev/null @@ -1,62 +0,0 @@ -mockUser(null); - - $model->username = 'some_username'; - $model->password = 'some_password'; - - $this->specify('user should not be able to login, when there is no identity' , function () use ($model) { - $this->assertFalse($model->login()); - $this->assertTrue(Yii::$app->user->isGuest,'user should not be logged in'); - }); - } - - public function testLoginWrongPassword() - { - $model = $this->mockUser(new User); - - $model->username = 'demo'; - $model->password = 'wrong-password'; - - $this->specify('user should not be able to login with wrong password', function () use ($model) { - $this->assertFalse($model->login()); - $this->assertArrayHasKey('password',$model->errors); - $this->assertTrue(Yii::$app->user->isGuest,'user should not be logged in'); - }); - } - - public function testLoginCorrect() - { - $model = $this->mockUser(new User(['password' => 'demo'])); - - $model->username = 'demo'; - $model->password = 'demo'; - - $this->specify('user should be able to login with correct credentials', function() use ($model) { - $this->assertTrue($model->login()); - $this->assertArrayNotHasKey('password',$model->errors); - $this->assertFalse(Yii::$app->user->isGuest,'user should be logged in'); - }); - } - - private function mockUser($user) - { - $loginForm = $this->getMock('app\models\LoginForm',['getUser']); - $loginForm->expects($this->any())->method('getUser')->will($this->returnValue($user)); - return $loginForm; - } - -} \ No newline at end of file diff --git a/apps/basic/tests/unit/models/UserTest.php b/apps/basic/tests/unit/models/UserTest.php deleted file mode 100644 index 3ff3c83..0000000 --- a/apps/basic/tests/unit/models/UserTest.php +++ /dev/null @@ -1,20 +0,0 @@ -loadFixtures(['tbl_user']); - } - - // TODO add test methods here -} diff --git a/apps/basic/tests/unit/templates/fixtures/.gitkeep b/apps/basic/tests/unit/templates/fixtures/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/apps/basic/vendor/.gitignore b/apps/basic/vendor/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/basic/vendor/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/basic/views/layouts/main.php b/apps/basic/views/layouts/main.php deleted file mode 100644 index d1af295..0000000 --- a/apps/basic/views/layouts/main.php +++ /dev/null @@ -1,66 +0,0 @@ - -beginPage() ?> - - - - - - <?= Html::encode($this->title) ?> - head() ?> - - -beginBody() ?> - 'My Company', - 'brandUrl' => Yii::$app->homeUrl, - 'options' => [ - 'class' => 'navbar-inverse navbar-fixed-top', - ], - ]); - echo Nav::widget([ - 'options' => ['class' => 'navbar-nav navbar-right'], - 'items' => [ - ['label' => 'Home', 'url' => ['/site/index']], - ['label' => 'About', 'url' => ['/site/about']], - ['label' => 'Contact', 'url' => ['/site/contact']], - Yii::$app->user->isGuest ? - ['label' => 'Login', 'url' => ['/site/login']] : - ['label' => 'Logout (' . Yii::$app->user->identity->username . ')' , - 'url' => ['/site/logout'], - 'linkOptions' => ['data-method' => 'post']], - ], - ]); - NavBar::end(); - ?> - -
    - isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], - ]) ?> - -
    - -
    -
    -

    © My Company

    -

    -
    -
    - -endBody() ?> - - -endPage() ?> diff --git a/apps/basic/views/site/about.php b/apps/basic/views/site/about.php deleted file mode 100644 index 0608dd2..0000000 --- a/apps/basic/views/site/about.php +++ /dev/null @@ -1,18 +0,0 @@ -title = 'About'; -$this->params['breadcrumbs'][] = $this->title; -?> -
    -

    title) ?>

    - -

    - This is the About page. You may modify the following file to customize its content: -

    - - -
    diff --git a/apps/basic/views/site/contact.php b/apps/basic/views/site/contact.php deleted file mode 100644 index ebd148e..0000000 --- a/apps/basic/views/site/contact.php +++ /dev/null @@ -1,47 +0,0 @@ -title = 'Contact'; -$this->params['breadcrumbs'][] = $this->title; -?> -
    -

    title) ?>

    - - session->hasFlash('contactFormSubmitted')): ?> - -
    - Thank you for contacting us. We will respond to you as soon as possible. -
    - - - -

    - If you have business inquiries or other questions, please fill out the following form to contact us. Thank you. -

    - -
    -
    - 'contact-form']); ?> - field($model, 'name') ?> - field($model, 'email') ?> - field($model, 'subject') ?> - field($model, 'body')->textArea(['rows' => 6]) ?> - field($model, 'verifyCode')->widget(Captcha::className(), [ - 'template' => '
    {image}
    {input}
    ', - ]) ?> -
    - 'btn btn-primary']) ?> -
    - -
    -
    - - -
    diff --git a/apps/basic/views/site/error.php b/apps/basic/views/site/error.php deleted file mode 100644 index 1b7ce04..0000000 --- a/apps/basic/views/site/error.php +++ /dev/null @@ -1,29 +0,0 @@ -title = $name; -?> -
    - -

    title) ?>

    - -
    - -
    - -

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

    -

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

    - -
    diff --git a/apps/basic/views/site/index.php b/apps/basic/views/site/index.php deleted file mode 100644 index bcb2278..0000000 --- a/apps/basic/views/site/index.php +++ /dev/null @@ -1,53 +0,0 @@ -title = 'My Yii Application'; -?> -
    - -
    -

    Congratulations!

    - -

    You have successfully created your Yii-powered application.

    - -

    Get started with Yii

    -
    - -
    - -
    -
    -

    Heading

    - -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

    - -

    Yii Documentation »

    -
    -
    -

    Heading

    - -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

    - -

    Yii Forum »

    -
    -
    -

    Heading

    - -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

    - -

    Yii Extensions »

    -
    -
    - -
    -
    diff --git a/apps/basic/views/site/login.php b/apps/basic/views/site/login.php deleted file mode 100644 index da022d6..0000000 --- a/apps/basic/views/site/login.php +++ /dev/null @@ -1,47 +0,0 @@ -title = 'Login'; -$this->params['breadcrumbs'][] = $this->title; -?> - diff --git a/apps/basic/web/assets/.gitignore b/apps/basic/web/assets/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/basic/web/assets/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/basic/web/css/site.css b/apps/basic/web/css/site.css deleted file mode 100644 index a8508c4..0000000 --- a/apps/basic/web/css/site.css +++ /dev/null @@ -1,79 +0,0 @@ -body { - padding-top: 70px; -} - -.footer { - border-top: 1px solid #ddd; - margin-top: 30px; - padding-top: 15px; - padding-bottom: 30px; -} - -.jumbotron { - text-align: center; - background-color: transparent; -} - -.jumbotron .btn { - font-size: 21px; - padding: 14px 24px; -} - -.not-set { - color: #c55; - font-style: italic; -} - -/* add sorting icons to gridview sort links */ -a.asc:after, a.desc:after { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: normal; - line-height: 1; - padding-left: 5px; -} - -a.asc:after { - content: /*"\e113"*/ "\e151"; -} - -a.desc:after { - content: /*"\e114"*/ "\e152"; -} - -.sort-numerical a.asc:after { - content: "\e153"; -} - -.sort-numerical a.desc:after { - content: "\e154"; -} - -.sort-ordinal a.asc:after { - content: "\e155"; -} - -.sort-ordinal a.desc:after { - content: "\e156"; -} - -.grid-view th { - white-space: nowrap; -} - -.hint-block { - display: block; - margin-top: 5px; - color: #999; -} - -.error-summary { - color: #a94442; - background: #fdf7f7; - border-left: 3px solid #eed3d7; - padding: 10px 20px; - margin: 0 0 15px 0; -} diff --git a/apps/basic/web/favicon.ico b/apps/basic/web/favicon.ico deleted file mode 100644 index 49e61e33ca94362545346cb218c62dc7807e9c66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcma)6XH1hp7(Rmu{|GtU+!^sFa8rsCv}Jk%uOI+4N{Oj%&Pr>HDfEM$SlXWB1Hz(U z=q`_hetCNkh4Fv)y`0bdjM_j#e<+ev-v&l=4iw2c-UG{xrn23ZP6ZdY2&U;sgmB!MCG& zPViGpf_QK&ieQ-2k5Nuv5z%G|~6pzA1+W5r4)V$G60fX<= z_5nON#o*SQ2hNQdkSS&*ggllP?sgTy0Y3?thD*ULrXP+a5|6ZDaLgIev<}Qz&tpo@ zi(NG3){+k{P1)eYN(Vc}b4V4|ys-2Xb?vn8f;|^RU>vyM5#0~onF@Z_(5$icjrun(); diff --git a/apps/basic/web/index.php b/apps/basic/web/index.php deleted file mode 100644 index 006e28f..0000000 --- a/apps/basic/web/index.php +++ /dev/null @@ -1,12 +0,0 @@ -run(); diff --git a/apps/basic/web/robots.txt b/apps/basic/web/robots.txt deleted file mode 100644 index 6f27bb6..0000000 --- a/apps/basic/web/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: \ No newline at end of file diff --git a/apps/basic/yii b/apps/basic/yii deleted file mode 100755 index 9188f85..0000000 --- a/apps/basic/yii +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/basic/yii.bat b/apps/basic/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/basic/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/benchmark/LICENSE.md b/apps/benchmark/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/apps/benchmark/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/apps/benchmark/README.md b/apps/benchmark/README.md deleted file mode 100644 index 27f598a..0000000 --- a/apps/benchmark/README.md +++ /dev/null @@ -1,58 +0,0 @@ -Yii 2 Benchmark Application -=========================== - -**NOTE** Yii 2 and the relevant applications and extensions are still under heavy -development. We may make significant changes without prior notices. Please do not -use them for production. Please consider using [Yii v1.1](https://github.com/yiisoft/yii) -if you have a project to be deployed for production soon. - - -Yii 2 Benchmark Application is an application built to demonstrate the minimal overhead -introduced by the Yii framework. The application contains a single page which only renders -the "hello world" string. - -The application attempts to simulate the scenario in which you can achieve the best performance -when using Yii. It does so by assuming that both of the main application configuration and the page -content are cached in memory, and the application enables pretty URLs. - - -DIRECTORY STRUCTURE -------------------- - - protected/ contains application source code - controllers/ contains Web controller classes - index.php the entry script - - -REQUIREMENTS ------------- - -The minimum requirement by Yii is that your Web server supports PHP 5.4.0. - - -INSTALLATION ------------- - -If you do not have [Composer](http://getcomposer.org/), you may download it from -[http://getcomposer.org/](http://getcomposer.org/) or run the following command on Linux/Unix/MacOS: - -~~~ -curl -s http://getcomposer.org/installer | php -~~~ - -You can then install the Bootstrap Application using the following command: - -~~~ -php composer.phar create-project --prefer-dist --stability=dev yiisoft/yii2-app-benchmark yii-benchmark -~~~ - -Now you should be able to access the benchmark page using the URL - -~~~ -http://localhost/yii-benchmark/index.php/site/hello -~~~ - -In the above, we assume `yii-benchmark` is directly under the document root of your Web server. - -Note that in order to install some dependencies you must have `php_openssl` extension enabled. - diff --git a/apps/benchmark/composer.json b/apps/benchmark/composer.json deleted file mode 100644 index d980f9a..0000000 --- a/apps/benchmark/composer.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "yiisoft/yii2-app-benchmark", - "description": "Yii 2 Benchmark Application", - "keywords": ["yii", "framework", "benchmark", "application"], - "homepage": "http://www.yiiframework.com/", - "type": "project", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?state=open", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "config": { - "vendor-dir": "protected/vendor" - }, - "minimum-stability": "dev", - "require": { - "php": ">=5.4.0", - "yiisoft/yii2": "*" - } -} diff --git a/apps/benchmark/index.php b/apps/benchmark/index.php deleted file mode 100644 index 984beb2..0000000 --- a/apps/benchmark/index.php +++ /dev/null @@ -1,18 +0,0 @@ - 'benchmark', - 'basePath' => __DIR__ . '/protected', - 'components' => [ - 'urlManager' => [ - 'enablePrettyUrl' => true, - ], - ], -]; - -$application = new yii\web\Application($config); -$application->run(); diff --git a/apps/benchmark/protected/.htaccess b/apps/benchmark/protected/.htaccess deleted file mode 100644 index 8d2f256..0000000 --- a/apps/benchmark/protected/.htaccess +++ /dev/null @@ -1 +0,0 @@ -deny from all diff --git a/apps/benchmark/protected/controllers/SiteController.php b/apps/benchmark/protected/controllers/SiteController.php deleted file mode 100644 index 9abc164..0000000 --- a/apps/benchmark/protected/controllers/SiteController.php +++ /dev/null @@ -1,15 +0,0 @@ - 'yii-build', - 'basePath' => __DIR__, - 'controllerNamespace' => 'yii\build\controllers', -]); -$application->run(); diff --git a/build/build.bat b/build/build.bat deleted file mode 100644 index e659199..0000000 --- a/build/build.bat +++ /dev/null @@ -1,23 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem build script for Windows. -rem -rem This is the bootstrap script for running build on Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright 2008 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem @version $Id$ -rem ------------------------------------------------------------- - -@setlocal - -set BUILD_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -%PHP_COMMAND% "%BUILD_PATH%build" %* - -@endlocal \ No newline at end of file diff --git a/build/build.xml b/build/build.xml deleted file mode 100644 index 846e4cf..0000000 --- a/build/build.xml +++ /dev/null @@ -1,276 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Building package ${pkgname}... - Copying files to build directory... - - - - - Changing file permissions... - - - - - - - - Generating source release file... - - - - - - - - - - - - - - - - - - - - - - - - Building documentation... - - Building Guide PDF... - - - - - - - Building Blog PDF... - - - - - - - Building API... - - - - - Generating doc release file... - - - - - - - - - - - - - - - - Building online API... - - - - Copying tutorials... - - - - - - - - Copying release text files... - - - - - - -Finished building Web files. -Please update yiisite/common/data/versions.php file with the following code: - - '1.1'=>array( - 'version'=>'${yii.version}', - 'revision'=>'${yii.revision}', - 'date'=>'${yii.date}', - 'latest'=>true, - ), - - - - - - Synchronizing code changes for ${pkgname}... - - Building autoload map... - - - Building yiilite.php... - - - - - Extracting i18n messages... - - - - - - - Cleaning up the build... - - - - - - - Welcome to use Yii build script! - -------------------------------- - You may use the following command format to build a target: - - phing <target name> - - where <target name> can be one of the following: - - - sync : synchronize yiilite.php and BaseYii.php - - message : extract i18n messages of the framework - - src : build source release - - doc : build documentation release (Windows only) - - clean : clean up the build - - - - diff --git a/build/controllers/ClassmapController.php b/build/controllers/ClassmapController.php deleted file mode 100644 index a0ba886..0000000 --- a/build/controllers/ClassmapController.php +++ /dev/null @@ -1,88 +0,0 @@ - - * @since 2.0 - */ -class ClassmapController extends Controller -{ - public $defaultAction = 'create'; - - /** - * Creates a class map for the core Yii classes. - * @param string $root the root path of Yii framework. Defaults to YII_PATH. - * @param string $mapFile the file to contain the class map. Defaults to YII_PATH . '/classes.php'. - */ - public function actionCreate($root = null, $mapFile = null) - { - if ($root === null) { - $root = YII_PATH; - } - $root = FileHelper::normalizePath($root); - if ($mapFile === null) { - $mapFile = YII_PATH . '/classes.php'; - } - $options = [ - 'filter' => function ($path) { - if (is_file($path)) { - $file = basename($path); - if ($file[0] < 'A' || $file[0] > 'Z') { - return false; - } - } - return null; - }, - 'only' => ['.php'], - 'except' => [ - 'Yii.php', - 'BaseYii.php', - '/console/', - ], - ]; - $files = FileHelper::findFiles($root, $options); - $map = []; - foreach ($files as $file) { - if (($pos = strpos($file, $root)) !== 0) { - die("Something wrong: $file\n"); - } - $path = str_replace('\\', '/', substr($file, strlen($root))); - $map[$path] = "\t'yii" . substr(str_replace('/', '\\', $path), 0, -4) . "' => YII_PATH . '$path',"; - } - ksort($map); - $map = implode("\n", $map); - $output = << - * @author Alexander Makarov - * @since 2.0 - */ -class PhpDocController extends Controller -{ - public $defaultAction = 'property'; - - /** - * @var bool whether to update class docs directly. Setting this to false will just output docs - * for copy and paste. - */ - public $updateFiles = true; - - /** - * Generates @property annotations in class files from getters and setters - * - * Property description will be taken from getter or setter or from an @property annotation - * in the getters docblock if there is one defined. - * - * See https://github.com/yiisoft/yii2/wiki/Core-framework-code-style#documentation for details. - * - * @param null $root the directory to parse files from. Defaults to YII_PATH. - */ - public function actionProperty($root = null) - { - $except = []; - if ($root === null) { - $root = dirname(dirname(YII_PATH)); - $extensionPath = "$root/extensions/yii"; - foreach (scandir($extensionPath) as $extension) { - if (ctype_alpha($extension) && is_dir($extensionPath . '/' . $extension)) { - Yii::setAlias("@yii/$extension", "$extensionPath/$extension"); - } - } - - $except = [ - '/apps/', - '/build/', - '/docs/', - '/extensions/yii/composer/', - '/tests/', - '/vendor/', - ]; - } - $root = FileHelper::normalizePath($root); - $options = [ - 'filter' => function ($path) { - if (is_file($path)) { - $file = basename($path); - if ($file[0] < 'A' || $file[0] > 'Z') { - return false; - } - } - return null; - }, - 'only' => ['.php'], - 'except' => array_merge($except, [ - 'BaseYii.php', - 'Yii.php', - '/views/', - '/requirements/', - '/gii/generators/', - ]), - ]; - $files = FileHelper::findFiles($root, $options); - $nFilesTotal = 0; - $nFilesUpdated = 0; - foreach ($files as $file) { - $result = $this->generateClassPropertyDocs($file); - if ($result !== false) { - list($className, $phpdoc) = $result; - if ($this->updateFiles) { - if ($this->updateClassPropertyDocs($file, $className, $phpdoc)) { - $nFilesUpdated++; - } - } elseif (!empty($phpdoc)) { - $this->stdout("\n[ " . $file . " ]\n\n", Console::BOLD); - $this->stdout($phpdoc); - } - } - $nFilesTotal++; - } - - $this->stdout("\nParsed $nFilesTotal files.\n"); - $this->stdout("Updated $nFilesUpdated files.\n"); - } - - public function globalOptions() - { - return array_merge(parent::globalOptions(), ['updateFiles']); - } - - protected function updateClassPropertyDocs($file, $className, $propertyDoc) - { - $ref = new \ReflectionClass($className); - if ($ref->getFileName() != $file) { - $this->stderr("[ERR] Unable to create ReflectionClass for class: $className loaded class is not from file: $file\n", Console::FG_RED); - } - - if (!$ref->isSubclassOf('yii\base\Object') && $className != 'yii\base\Object') { - $this->stderr("[INFO] Skipping class $className as it is not a subclass of yii\\base\\Object.\n", Console::FG_BLUE, Console::BOLD); - return false; - } - - $oldDoc = $ref->getDocComment(); - $newDoc = $this->cleanDocComment($this->updateDocComment($oldDoc, $propertyDoc)); - - $seenSince = false; - $seenAuthor = false; - - // TODO move these checks to different action - $lines = explode("\n", $newDoc); - if (trim($lines[1]) == '*' || substr(trim($lines[1]), 0, 3) == '* @') { - $this->stderr("[WARN] Class $className has no short description.\n", Console::FG_YELLOW, Console::BOLD); - } - foreach ($lines as $line) { - if (substr(trim($line), 0, 9) == '* @since ') { - $seenSince = true; - } elseif (substr(trim($line), 0, 10) == '* @author ') { - $seenAuthor = true; - } - } - - if (!$seenSince) { - $this->stderr("[ERR] No @since found in class doc in file: $file\n", Console::FG_RED); - } - if (!$seenAuthor) { - $this->stderr("[ERR] No @author found in class doc in file: $file\n", Console::FG_RED); - } - - if (trim($oldDoc) != trim($newDoc)) { - - $fileContent = explode("\n", file_get_contents($file)); - $start = $ref->getStartLine() - 2; - $docStart = $start - count(explode("\n", $oldDoc)) + 1; - - $newFileContent = []; - $n = count($fileContent); - for ($i = 0; $i < $n; $i++) { - if ($i > $start || $i < $docStart) { - $newFileContent[] = $fileContent[$i]; - } else { - $newFileContent[] = trim($newDoc); - $i = $start; - } - } - - file_put_contents($file, implode("\n", $newFileContent)); - - return true; - } - return false; - } - - /** - * remove multi empty lines and trim trailing whitespace - * - * @param $doc - * @return string - */ - protected function cleanDocComment($doc) - { - $lines = explode("\n", $doc); - $n = count($lines); - for ($i = 0; $i < $n; $i++) { - $lines[$i] = rtrim($lines[$i]); - if (trim($lines[$i]) == '*' && trim($lines[$i + 1]) == '*') { - unset($lines[$i]); - } - } - return implode("\n", $lines); - } - - /** - * replace property annotations in doc comment - * @param $doc - * @param $properties - * @return string - */ - protected function updateDocComment($doc, $properties) - { - $lines = explode("\n", $doc); - $propertyPart = false; - $propertyPosition = false; - foreach ($lines as $i => $line) { - if (substr(trim($line), 0, 12) == '* @property ') { - $propertyPart = true; - } elseif ($propertyPart && trim($line) == '*') { - $propertyPosition = $i; - $propertyPart = false; - } - if (substr(trim($line), 0, 10) == '* @author ' && $propertyPosition === false) { - $propertyPosition = $i - 1; - $propertyPart = false; - } - if ($propertyPart) { - unset($lines[$i]); - } - } - $finalDoc = ''; - foreach ($lines as $i => $line) { - $finalDoc .= $line . "\n"; - if ($i == $propertyPosition) { - $finalDoc .= $properties; - } - } - return $finalDoc; - } - - protected function generateClassPropertyDocs($fileName) - { - $phpdoc = ""; - $file = str_replace("\r", "", str_replace("\t", " ", file_get_contents($fileName, true))); - $ns = $this->match('#\nnamespace (?[\w\\\\]+);\n#', $file); - $namespace = reset($ns); - $namespace = $namespace['name']; - $classes = $this->match('#\n(?:abstract )?class (?\w+)( extends .+)?( implements .+)?\n\{(?.*)\n\}(\n|$)#', $file); - - if (count($classes) > 1) { - $this->stderr("[ERR] There should be only one class in a file: $fileName\n", Console::FG_RED); - return false; - } - if (count($classes) < 1) { - $interfaces = $this->match('#\ninterface (?\w+)( extends .+)?\n\{(?.+)\n\}(\n|$)#', $file); - if (count($interfaces) == 1) { - return false; - } elseif (count($interfaces) > 1) { - $this->stderr("[ERR] There should be only one interface in a file: $fileName\n", Console::FG_RED); - } else { - $traits = $this->match('#\ntrait (?\w+)\n\{(?.+)\n\}(\n|$)#', $file); - if (count($traits) == 1) { - return false; - } elseif (count($traits) > 1) { - $this->stderr("[ERR] There should be only one class/trait/interface in a file: $fileName\n", Console::FG_RED); - } else { - $this->stderr("[ERR] No class in file: $fileName\n", Console::FG_RED); - } - } - return false; - } - - $className = null; - foreach ($classes as &$class) { - - $className = $namespace . '\\' . $class['name']; - - $gets = $this->match( - '#\* @return (?[\w\\|\\\\\\[\\]]+)(?: (?(?:(?!\*/|\* @).)+?)(?:(?!\*/).)+|[\s\n]*)\*/' . - '[\s\n]{2,}public function (?get)(?\w+)\((?:,? ?\$\w+ ?= ?[^,]+)*\)#', - $class['content']); - $sets = $this->match( - '#\* @param (?[\w\\|\\\\\\[\\]]+) \$\w+(?: (?(?:(?!\*/|\* @).)+?)(?:(?!\*/).)+|[\s\n]*)\*/' . - '[\s\n]{2,}public function (?set)(?\w+)\(\$\w+(?:, ?\$\w+ ?= ?[^,]+)*\)#', - $class['content']); - // check for @property annotations in getter and setter - $properties = $this->match( - '#\* @(?property) (?[\w\\|\\\\\\[\\]]+)(?: (?(?:(?!\*/|\* @).)+?)(?:(?!\*/).)+|[\s\n]*)\*/' . - '[\s\n]{2,}public function [g|s]et(?\w+)\(((?:,? ?\$\w+ ?= ?[^,]+)*|\$\w+(?:, ?\$\w+ ?= ?[^,]+)*)\)#', - $class['content']); - $acrs = array_merge($properties, $gets, $sets); - - $props = []; - foreach ($acrs as &$acr) { - $acr['name'] = lcfirst($acr['name']); - $acr['comment'] = trim(preg_replace('#(^|\n)\s+\*\s?#', '$1 * ', $acr['comment'])); - $props[$acr['name']][$acr['kind']] = [ - 'type' => $acr['type'], - 'comment' => $this->fixSentence($acr['comment']), - ]; - } - - ksort($props); - - if (count($props) > 0) { - $phpdoc .= " *\n"; - foreach ($props as $propName => &$prop) { - $docline = ' * @'; - $docline .= 'property'; // Do not use property-read and property-write as few IDEs support complex syntax. - $note = ''; - if (isset($prop['get']) && isset($prop['set'])) { - if ($prop['get']['type'] != $prop['set']['type']) { - $note = ' Note that the type of this property differs in getter and setter.' - . ' See [[get'.ucfirst($propName).'()]] and [[set'.ucfirst($propName).'()]] for details.'; - } - } elseif (isset($prop['get'])) { - // check if parent class has setter defined - $c = $className; - $parentSetter = false; - while($parent = get_parent_class($c)) { - if (method_exists($parent, 'set' . ucfirst($propName))) { - $parentSetter = true; - break; - } - $c = $parent; - } - if (!$parentSetter) { - $note = ' This property is read-only.'; -// $docline .= '-read'; - } - } elseif (isset($prop['set'])) { - // check if parent class has getter defined - $c = $className; - $parentGetter = false; - while($parent = get_parent_class($c)) { - if (method_exists($parent, 'set' . ucfirst($propName))) { - $parentGetter = true; - break; - } - $c = $parent; - } - if (!$parentGetter) { - $note = ' This property is write-only.'; -// $docline .= '-write'; - } - } else { - continue; - } - $docline .= ' ' . $this->getPropParam($prop, 'type') . " $$propName "; - $comment = explode("\n", $this->getPropParam($prop, 'comment') . $note); - foreach ($comment as &$cline) { - $cline = ltrim($cline, '* '); - } - $docline = wordwrap($docline . implode(' ', $comment), 110, "\n * ") . "\n"; - - $phpdoc .= $docline; - } - $phpdoc .= " *\n"; - } - } - return [$className, $phpdoc]; - } - - protected function match($pattern, $subject) - { - $sets = []; - preg_match_all($pattern . 'suU', $subject, $sets, PREG_SET_ORDER); - foreach ($sets as &$set) - foreach ($set as $i => $match) - if (is_numeric($i) /*&& $i != 0*/) - unset($set[$i]); - return $sets; - } - - protected function fixSentence($str) - { - // TODO fix word wrap - if ($str == '') - return ''; - return strtoupper(substr($str, 0, 1)) . substr($str, 1) . ($str[strlen($str) - 1] != '.' ? '.' : ''); - } - - protected function getPropParam($prop, $param) - { - return isset($prop['property']) ? $prop['property'][$param] : (isset($prop['get']) ? $prop['get'][$param] : $prop['set'][$param]); - } -} diff --git a/composer.json b/composer.json index 368c817..e2a99df 100644 --- a/composer.json +++ b/composer.json @@ -1,121 +1,27 @@ { - "name": "yiisoft/yii2-dev", - "description": "Yii PHP Framework Version 2 - Development Package", - "keywords": ["yii", "framework"], - "homepage": "http://www.yiiframework.com/", + "name": "yiisoft/yii2-bootstrap", + "description": "The Twitter Bootstrap extension for the Yii framework", + "keywords": ["yii", "bootstrap"], "type": "yii2-extension", "license": "BSD-3-Clause", - "authors": [ - { - "name": "Qiang Xue", - "email": "qiang.xue@gmail.com", - "homepage": "http://www.yiiframework.com/", - "role": "Founder and project lead" - }, - { - "name": "Alexander Makarov", - "email": "sam@rmcreative.ru", - "homepage": "http://rmcreative.ru/", - "role": "Core framework development" - }, - { - "name": "Maurizio Domba", - "homepage": "http://mdomba.info/", - "role": "Core framework development" - }, - { - "name": "Carsten Brandt", - "email": "mail@cebe.cc", - "homepage": "http://cebe.cc/", - "role": "Core framework development" - }, - { - "name": "Timur Ruziev", - "email": "resurtm@gmail.com", - "homepage": "http://resurtm.com/", - "role": "Core framework development" - }, - { - "name": "Paul Klimov", - "email": "klimov.paul@gmail.com", - "role": "Core framework development" - } - ], "support": { - "issues": "https://github.com/yiisoft/yii2/issues?state=open", + "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" }, - "minimum-stability": "dev", - "replace": { - "yiisoft/yii2-apidoc": "self.version", - "yiisoft/yii2-authclient": "self.version", - "yiisoft/yii2-bootstrap": "self.version", - "yiisoft/yii2-codeception": "self.version", - "yiisoft/yii2-debug": "self.version", - "yiisoft/yii2-elasticsearch": "self.version", - "yiisoft/yii2-faker": "self.version", - "yiisoft/yii2-imagine": "self.version", - "yiisoft/yii2-gii": "self.version", - "yiisoft/yii2-jui": "self.version", - "yiisoft/yii2-mongodb": "self.version", - "yiisoft/yii2-redis": "self.version", - "yiisoft/yii2-smarty": "self.version", - "yiisoft/yii2-swiftmailer": "self.version", - "yiisoft/yii2-sphinx": "self.version", - "yiisoft/yii2-twig": "self.version", - "yiisoft/yii2": "self.version" - }, + "authors": [ + { + "name": "Qiang Xue", + "email": "qiang.xue@gmail.com" + } + ], "require": { - "php": ">=5.4.0", - "ext-mbstring": "*", - "lib-pcre": "*", - "yiisoft/yii2-composer": "*", - "yiisoft/jquery": "1.10.*", - "phpspec/php-diff": ">=1.0.2", - "ezyang/htmlpurifier": "4.6.*", - "michelf/php-markdown": "1.3.*" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*", - "twig/twig": "*" - }, - "suggest": { - "phpdocumentor/reflection": "required by yii2-apidoc extension", - "twbs/bootstrap": "required by yii2-bootstrap, yii2-debug, yii2-gii extension", - "ext-curl": "required by yii2-elasticsearch extension", - "ext-mongo": "required by yii2-mongo extension", - "ext-pdo": "required by yii2-sphinx extension", - "ext-pdo_mysql": "required by yii2-sphinx extension", - "fzaninotto/faker": "required by yii2-faker extension", - "imagine/imagine": "required by yii2-imagine extension", - "smarty/smarty": "required by yii2-smarty extension", - "swiftmailer/swiftmailer": "required by yii2-swiftmailer extension", - "twig/twig": "required by yii2-twig extension" + "yiisoft/yii2": "*", + "twbs/bootstrap": "3.0.*" }, "autoload": { - "psr-4": { - "yii\\faker\\": "extensions/faker/", - "yii\\twig\\": "extensions/twig/" - }, - "psr-0": { - "yii\\apidoc\\": "extensions/", - "yii\\authclient\\": "extensions/", - "yii\\bootstrap\\": "extensions/", - "yii\\codeception\\": "extensions/", - "yii\\debug\\": "extensions/", - "yii\\elasticsearch\\": "extensions/", - "yii\\gii\\": "extensions/", - "yii\\imagine\\" : "extensions/", - "yii\\jui\\": "extensions/", - "yii\\mongodb\\": "extensions/", - "yii\\redis\\": "extensions/", - "yii\\smarty\\": "extensions/", - "yii\\swiftmailer\\": "extensions/", - "yii\\sphinx\\": "extensions/", - "yii\\": "framework/" - } + "psr-4": { "yii\\bootstrap\\": "" } } } diff --git a/docs/api/base/Component.md b/docs/api/base/Component.md deleted file mode 100644 index f198798..0000000 --- a/docs/api/base/Component.md +++ /dev/null @@ -1,80 +0,0 @@ -Component is the base class that implements the *property*, *event* and *behavior* features. - -Component provides the *event* and *behavior* features, in addition to the *property* feature which is implemented in -its parent class [[Object]]. - -Event is a way to "inject" custom code into existing code at certain places. For example, a comment object can trigger -an "add" event when the user adds a comment. We can write custom code and attach it to this event so that when the event -is triggered (i.e. comment will be added), our custom code will be executed. - -An event is identified by a name that should be unique within the class it is defined at. Event names are *case-sensitive*. - -One or multiple PHP callbacks, called *event handlers*, can be attached to an event. You can call [[trigger()]] to -raise an event. When an event is raised, the event handlers will be invoked automatically in the order they were -attached. - -To attach an event handler to an event, call [[on()]]: - -~~~ -$post->on('update', function($event) { - // send email notification -}); -~~~ - -In the above, an anonymous function is attached to the "update" event of the post. You may attach -the following types of event handlers: - -- anonymous function: `function($event) { ... }` -- object method: `[$object, 'handleAdd']` -- static class method: `['Page', 'handleAdd']` -- global function: `'handleAdd'` - -The signature of an event handler should be like the following: - -~~~ -function foo($event) -~~~ - -where `$event` is an [[Event]] object which includes parameters associated with the event. - -You can also attach a handler to an event when configuring a component with a configuration array. -The syntax is like the following: - -~~~ -[ - 'on add' => function($event) { ... } -] -~~~ - -where `on add` stands for attaching an event to the `add` event. - -Sometimes, you may want to associate extra data with an event handler when you attach it to an event -and then access it when the handler is invoked. You may do so by - -~~~ -$post->on('update', function($event) { - // the data can be accessed via $event->data -}, $data); -~~~ - - -A behavior is an instance of [[Behavior]] or its child class. A component can be attached with one or multiple -behaviors. When a behavior is attached to a component, its public properties and methods can be accessed via the -component directly, as if the component owns those properties and methods. - -To attach a behavior to a component, declare it in [[behaviors()]], or explicitly call [[attachBehavior]]. Behaviors -declared in [[behaviors()]] are automatically attached to the corresponding component. - -One can also attach a behavior to a component when configuring it with a configuration array. The syntax is like the -following: - -~~~ -[ - 'as tree' => [ - 'class' => 'Tree', - ], -] -~~~ - -where `as tree` stands for attaching a behavior named `tree`, and the array will be passed to [[\Yii::createObject()]] -to create the behavior object. \ No newline at end of file diff --git a/docs/api/base/Object.md b/docs/api/base/Object.md deleted file mode 100644 index a6ab2c1..0000000 --- a/docs/api/base/Object.md +++ /dev/null @@ -1,61 +0,0 @@ -Object is the base class that implements the *property* feature. - -A property is defined by a getter method (e.g. `getLabel`), and/or a setter method (e.g. `setLabel`). For example, -the following getter and setter methods define a property named `label`: - -~~~ -private $_label; - -public function getLabel() -{ - return $this->_label; -} - -public function setLabel($value) -{ - $this->_label = $value; -} -~~~ - -Property names are *case-insensitive*. - -A property can be accessed like a member variable of an object. Reading or writing a property will cause the invocation -of the corresponding getter or setter method. For example, - -~~~ -// equivalent to $label = $object->getLabel(); -$label = $object->label; -// equivalent to $object->setLabel('abc'); -$object->label = 'abc'; -~~~ - -If a property has only a getter method and has no setter method, it is considered as *read-only*. In this case, trying -to modify the property value will cause an exception. - -One can call [[hasProperty()]], [[canGetProperty()]] and/or [[canSetProperty()]] to check the existence of a property. - - -Besides the property feature, Object also introduces an important object initialization life cycle. In particular, -creating an new instance of Object or its derived class will involve the following life cycles sequentially: - -1. the class constructor is invoked; -2. object properties are initialized according to the given configuration; -3. the `init()` method is invoked. - -In the above, both Step 2 and 3 occur at the end of the class constructor. It is recommended that -you perform object initialization in the `init()` method because at that stage, the object configuration -is already applied. - -In order to ensure the above life cycles, if a child class of Object needs to override the constructor, -it should be done like the following: - -~~~ -public function __construct($param1, $param2, ..., $config = []) -{ - ... - parent::__construct($config); -} -~~~ - -That is, a `$config` parameter (defaults to `[]`) should be declared as the last parameter -of the constructor, and the parent implementation should be called at the end of the constructor. diff --git a/docs/api/db/ActiveRecord-find.md b/docs/api/db/ActiveRecord-find.md deleted file mode 100644 index 8653853..0000000 --- a/docs/api/db/ActiveRecord-find.md +++ /dev/null @@ -1,26 +0,0 @@ -The returned [[ActiveQuery]] instance can be further customized by calling -methods defined in [[ActiveQuery]] before `one()`, `all()` or `value()` is -called to return the populated active records: - -~~~ -// find all customers -$customers = Customer::find()->all(); - -// find all active customers and order them by their age: -$customers = Customer::find() - ->where(['status' => 1]) - ->orderBy('age') - ->all(); - -// find a single customer whose primary key value is 10 -$customer = Customer::find(10); - -// the above is equivalent to: -$customer = Customer::find()->where(['id' => 10])->one(); - -// find a single customer whose age is 30 and whose status is 1 -$customer = Customer::find(['age' => 30, 'status' => 1]); - -// the above is equivalent to: -$customer = Customer::find()->where(['age' => 30, 'status' => 1])->one(); -~~~ \ No newline at end of file diff --git a/docs/api/db/ActiveRecord.md b/docs/api/db/ActiveRecord.md deleted file mode 100644 index ef050d0..0000000 --- a/docs/api/db/ActiveRecord.md +++ /dev/null @@ -1,451 +0,0 @@ -ActiveRecord implements the [Active Record design pattern](http://en.wikipedia.org/wiki/Active_record). -The idea is that an ActiveRecord object is associated with a row in a database table -so object properties are mapped to columns of the corresponding database row. -For example, a `Customer` object is associated with a row in the `tbl_customer` -table. Instead of writing raw SQL statements to access the data in the table, -you can call intuitive methods available in the corresponding ActiveRecord class -to achieve the same goals. For example, calling [[save()]] would insert or update a row -in the underlying table: - -~~~ -$customer = new Customer(); -$customer->name = 'Qiang'; -$customer->save(); -~~~ - - -### Declaring ActiveRecord Classes - -To declare an ActiveRecord class you need to extend [[\yii\db\ActiveRecord]] and -implement `tableName` method like the following: - -~~~ -class Customer extends \yii\db\ActiveRecord -{ - /** - * @return string the name of the table associated with this ActiveRecord class. - */ - public static function tableName() - { - return 'tbl_customer'; - } -} -~~~ - -### Connecting to Database - -ActiveRecord relies on a [[Connection|DB connection]]. By default, it assumes that -there is an application component named `db` that gives the needed [[Connection]] -instance which serves as the DB connection. Usually this component is configured -via application configuration like the following: - -~~~ -return [ - 'components' => [ - 'db' => [ - 'class' => 'yii\db\Connection', - 'dsn' => 'mysql:host=localhost;dbname=testdb', - 'username' => 'demo', - 'password' => 'demo', - // turn on schema caching to improve performance - // 'schemaCacheDuration' => 3600, - ], - ], -]; -~~~ - - -### Getting Data from Database - -There are two ActiveRecord methods for getting data: - -- [[find()]] -- [[findBySql()]] - -They both return an [[ActiveQuery]] instance. Coupled with the various customization and query methods -provided by [[ActiveQuery]], ActiveRecord supports very flexible and powerful data retrieval approaches. - -The followings are some examples, - -~~~ -// to retrieve all *active* customers and order them by their ID: -$customers = Customer::find() - ->where(['status' => $active]) - ->orderBy('id') - ->all(); - -// to return a single customer whose ID is 1: -$customer = Customer::find() - ->where(['id' => 1]) - ->one(); - -// or use the following shortcut approach: -$customer = Customer::find(1); - -// to retrieve customers using a raw SQL statement: -$sql = 'SELECT * FROM tbl_customer'; -$customers = Customer::findBySql($sql)->all(); - -// to return the number of *active* customers: -$count = Customer::find() - ->where(['status' => $active]) - ->count(); - -// to return customers in terms of arrays rather than `Customer` objects: -$customers = Customer::find()->asArray()->all(); -// each $customers element is an array of name-value pairs - -// to index the result by customer IDs: -$customers = Customer::find()->indexBy('id')->all(); -// $customers array is indexed by customer IDs -~~~ - - -### Accessing Column Data - -ActiveRecord maps each column of the corresponding database table row to an *attribute* in the ActiveRecord -object. An attribute is like a regular object property whose name is the same as the corresponding column -name and is case sensitive. - -To read the value of a column, we can use the following expression: - -~~~ -// "id" is the name of a column in the table associated with $customer ActiveRecord object -$id = $customer->id; -// or alternatively, -$id = $customer->getAttribute('id'); -~~~ - -We can get all column values through the [[attributes]] property: - -~~~ -$values = $customer->attributes; -~~~ - - -### Persisting Data to Database - -ActiveRecord provides the following methods to insert, update and delete data: - -- [[save()]] -- [[insert()]] -- [[update()]] -- [[delete()]] -- [[updateCounters()]] -- [[updateAll()]] -- [[updateAllCounters()]] -- [[deleteAll()]] - -Note that [[updateAll()]], [[updateAllCounters()]] and [[deleteAll()]] apply to the whole database -table, while the rest of the methods only apply to the row associated with the ActiveRecord object. - -The followings are some examples: - -~~~ -// to insert a new customer record -$customer = new Customer; -$customer->name = 'James'; -$customer->email = 'james@example.com'; -$customer->save(); // equivalent to $customer->insert(); - -// to update an existing customer record -$customer = Customer::find($id); -$customer->email = 'james@example.com'; -$customer->save(); // equivalent to $customer->update(); - -// to delete an existing customer record -$customer = Customer::find($id); -$customer->delete(); - -// to increment the age of all customers by 1 -Customer::updateAllCounters(['age' => 1]); -~~~ - - -### Getting Relational Data - -Using ActiveRecord you can expose relationships as properties. For example, -with an appropriate declaration, `$customer->orders` can return an array of `Order` objects -which represent the orders placed by the specified customer. - -To declare a relationship, define a getter method which returns an [[ActiveRelation]] object. For example, - -~~~ -class Customer extends \yii\db\ActiveRecord -{ - public function getOrders() - { - return $this->hasMany(Order::className(), ['customer_id' => 'id']); - } -} - -class Order extends \yii\db\ActiveRecord -{ - public function getCustomer() - { - return $this->hasOne(Customer::className(), ['id' => 'customer_id']); - } -} -~~~ - -Within the getter methods above, we call [[hasMany()]] or [[hasOne()]] methods to -create a new [[ActiveRelation]] object. The [[hasMany()]] method declares -a one-many relationship. For example, a customer has many orders. And the [[hasOne()]] -method declares a many-one or one-one relationship. For example, an order has one customer. -Both methods take two parameters: - -- `$class`: the name of the class that the related models should use. -- `$link`: the association between columns from two tables. This should be given as an array. - The keys of the array are the names of the columns from the table associated with `$class`, - while the values of the array are the names of the columns from the declaring class. - It is a good practice to define relationships based on table foreign keys. - -After declaring relationships getting relational data is as easy as accessing -a component property that is defined by the getter method: - -~~~ -// the orders of a customer -$customer = Customer::find($id); -$orders = $customer->orders; // $orders is an array of Order objects - -// the customer of the first order -$customer2 = $orders[0]->customer; // $customer == $customer2 -~~~ - -Because [[ActiveRelation]] extends from [[ActiveQuery]], it has the same query building methods, -which allows us to customize the query for retrieving the related objects. -For example, we may declare a `bigOrders` relationship which returns orders whose -subtotal exceeds certain amount: - -~~~ -class Customer extends \yii\db\ActiveRecord -{ - public function getBigOrders($threshold = 100) - { - return $this->hasMany(Order::className(), ['customer_id' => 'id']) - ->where('subtotal > :threshold', [':threshold' => $threshold]) - ->orderBy('id'); - } -} -~~~ - - -Sometimes, two tables are related together via an intermediary table called -[pivot table](http://en.wikipedia.org/wiki/Pivot_table). To declare such relationships, we can customize -the [[ActiveRelation]] object by calling its [[ActiveRelation::via()]] or [[ActiveRelation::viaTable()]] -method. - -For example, if table `tbl_order` and table `tbl_item` are related via pivot table `tbl_order_item`, -we can declare the `items` relation in the `Order` class like the following: - -~~~ -class Order extends \yii\db\ActiveRecord -{ - public function getItems() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->viaTable('tbl_order_item', ['order_id' => 'id']); - } -} -~~~ - -[[ActiveRelation::via()]] method is similar to [[ActiveRelation::viaTable()]] except that -the first parameter of [[ActiveRelation::via()]] takes a relation name declared in the ActiveRecord class. -For example, the above `items` relation can be equivalently declared as follows: - -~~~ -class Order extends \yii\db\ActiveRecord -{ - public function getOrderItems() - { - return $this->hasMany(OrderItem::className(), ['order_id' => 'id']); - } - - public function getItems() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems'); - } -} -~~~ - - -When you access the related objects the first time, behind the scene ActiveRecord performs a DB query -to retrieve the corresponding data and populate it into the related objects. No query will be performed -if you access the same related objects again. We call this *lazy loading*. For example, - -~~~ -// SQL executed: SELECT * FROM tbl_customer WHERE id=1 -$customer = Customer::find(1); -// SQL executed: SELECT * FROM tbl_order WHERE customer_id=1 -$orders = $customer->orders; -// no SQL executed -$orders2 = $customer->orders; -~~~ - - -Lazy loading is very convenient to use. However, it may suffer from performance -issue in the following scenario: - -~~~ -// SQL executed: SELECT * FROM tbl_customer LIMIT 100 -$customers = Customer::find()->limit(100)->all(); - -foreach ($customers as $customer) { - // SQL executed: SELECT * FROM tbl_order WHERE customer_id=... - $orders = $customer->orders; - // ...handle $orders... -} -~~~ - -How many SQL queries will be performed in the above code, assuming there are more than 100 customers in -the database? 101! The first SQL query brings back 100 customers. Then for each customer, a SQL query -is performed to bring back the customer's orders. - -To solve the above performance problem, you can use the so-called *eager loading* by calling [[ActiveQuery::with()]]: - -~~~ -// SQL executed: SELECT * FROM tbl_customer LIMIT 100 -// SELECT * FROM tbl_orders WHERE customer_id IN (1,2,...) -$customers = Customer::find()->limit(100) - ->with('orders')->all(); - -foreach ($customers as $customer) { - // no SQL executed - $orders = $customer->orders; - // ...handle $orders... -} -~~~ - -As you can see, only two SQL queries are needed for the same task. - - -Sometimes, you may want to customize the relational queries on the fly. It can be -done for both lazy loading and eager loading. For example, - -~~~ -$customer = Customer::find(1); -// lazy loading: SELECT * FROM tbl_order WHERE customer_id=1 AND subtotal>100 -$orders = $customer->getOrders()->where('subtotal>100')->all(); - -// eager loading: SELECT * FROM tbl_customer LIMIT 10 - SELECT * FROM tbl_order WHERE customer_id IN (1,2,...) AND subtotal>100 -$customers = Customer::find()->limit(100)->with([ - 'orders' => function($query) { - $query->andWhere('subtotal>100'); - }, -])->all(); -~~~ - - -### Working with Relationships - -ActiveRecord provides the following two methods for establishing and breaking a -relationship between two ActiveRecord objects: - -- [[link()]] -- [[unlink()]] - -For example, given a customer and a new order, we can use the following code to make the -order owned by the customer: - -~~~ -$customer = Customer::find(1); -$order = new Order; -$order->subtotal = 100; -$customer->link('orders', $order); -~~~ - -The [[link()]] call above will set the `customer_id` of the order to be the primary key -value of `$customer` and then call [[save()]] to save the order into database. - - -### Data Input and Validation - -TBD - - -### Life Cycles of an ActiveRecord Object - -An ActiveRecord object undergoes different life cycles when it is used in different cases. -Subclasses or ActiveRecord behaviors may "inject" custom code in these life cycles through -method overriding and event handling mechanisms. - -When instantiating a new ActiveRecord instance, we will have the following life cycles: - -1. constructor -2. [[init()]]: will trigger an [[EVENT_INIT]] event - -When getting an ActiveRecord instance through the [[find()]] method, we will have the following life cycles: - -1. constructor -2. [[init()]]: will trigger an [[EVENT_INIT]] event -3. [[afterFind()]]: will trigger an [[EVENT_AFTER_FIND]] event - -When calling [[save()]] to insert or update an ActiveRecord, we will have the following life cycles: - -1. [[beforeValidate()]]: will trigger an [[EVENT_BEFORE_VALIDATE]] event -2. [[afterValidate()]]: will trigger an [[EVENT_AFTER_VALIDATE]] event -3. [[beforeSave()]]: will trigger an [[EVENT_BEFORE_INSERT]] or [[EVENT_BEFORE_UPDATE]] event -4. perform the actual data insertion or updating -5. [[afterSave()]]: will trigger an [[EVENT_AFTER_INSERT]] or [[EVENT_AFTER_UPDATE]] event - -Finally when calling [[delete()]] to delete an ActiveRecord, we will have the following life cycles: - -1. [[beforeDelete()]]: will trigger an [[EVENT_BEFORE_DELETE]] event -2. perform the actual data deletion -3. [[afterDelete()]]: will trigger an [[EVENT_AFTER_DELETE]] event - - -### Scopes - -A scope is a method that customizes a given [[ActiveQuery]] object. Scope methods are defined -in the ActiveRecord classes. They can be invoked through the [[ActiveQuery]] object that is created -via [[find()]] or [[findBySql()]]. The following is an example: - -~~~ -class Customer extends \yii\db\ActiveRecord -{ - // ... - - /** - * @param ActiveQuery $query - */ - public static function active($query) - { - $query->andWhere('status = 1'); - } -} - -$customers = Customer::find()->active()->all(); -~~~ - -In the above, the `active()` method is defined in `Customer` while we are calling it -through `ActiveQuery` returned by `Customer::find()`. - -Scopes can be parameterized. For example, we can define and use the following `olderThan` scope: - -~~~ -class Customer extends \yii\db\ActiveRecord -{ - // ... - - /** - * @param ActiveQuery $query - * @param integer $age - */ - public static function olderThan($query, $age = 30) - { - $query->andWhere('age > :age', [':age' => $age]); - } -} - -$customers = Customer::find()->olderThan(50)->all(); -~~~ - -The parameters should follow after the `$query` parameter when defining the scope method, and they -can take default values like shown above. - -### Atomic operations and scenarios - -TBD diff --git a/docs/guide/README.md b/docs/guide/README.md deleted file mode 100644 index 60ee8fb..0000000 --- a/docs/guide/README.md +++ /dev/null @@ -1,8 +0,0 @@ -This folder contains official Yii 2 guides documentation. - -To add new guide, take the following steps: - -1. Create `guide-name` and put there relevant documentation; -2. If guide has more then one word in name, then it should be with dashes, like: `console-fixture.md`, `module-debug.md`; -3. If your guide is for console commands, than its name should follow convention: `console-{command}.md`; -4. If your guide is for custom modules, than its name should follow convention: `module-{moduleName}.md`. diff --git a/docs/guide/active-record.md b/docs/guide/active-record.md deleted file mode 100644 index 02d5c85..0000000 --- a/docs/guide/active-record.md +++ /dev/null @@ -1,769 +0,0 @@ -Active Record -============= - -Active Record implements the [Active Record design pattern](http://en.wikipedia.org/wiki/Active_record). -The premise behind Active Record is that an individual [[ActiveRecord]] object is associated with a specific row in a database table. The object's attributes are mapped to the columns of the corresponding table. Referencing an Active Record attribute is equivalent to accessing -the corresponding table column for that record. - -As an example, say that the `Customer` ActiveRecord class is associated with the -`tbl_customer` table. This would mean that the class's `name` attribute is automatically mapped to the `name` column in `tbl_customer`. -Thanks to Active Record, assuming the variable `$customer` is an object of type `Customer`, to get the value of the `name` column for the table row, you can use the expression `$customer->name`. In this example, Active Record is providing an object-oriented interface for accessing data stored in the database. But Active Record provides much more functionality than this. - -With Active Record, instead of writing raw SQL statements to perform database queries, you can call intuitive methods to achieve the same goals. For example, calling [[ActiveRecord::save()|save()]] would perform an INSERT or UPDATE query, creating or updating a row in the associated table of the ActiveRecord class: - -```php -$customer = new Customer(); -$customer->name = 'Qiang'; -$customer->save(); // a new row is inserted into tbl_customer -``` - - -Declaring ActiveRecord Classes ------------------------------- - -To declare an ActiveRecord class you need to extend [[\yii\db\ActiveRecord]] and -implement the `tableName` method: - -```php -use yii\db\ActiveRecord; - -class Customer extends ActiveRecord -{ - /** - * @return string the name of the table associated with this ActiveRecord class. - */ - public static function tableName() - { - return 'tbl_customer'; - } -} -``` - -The `tableName` method only has to return the name of the database table associated with the class. - -Class instances are obtained in one of two ways: - -* Using the `new` operator to create a new, empty object -* Using a method to fetch an existing record (or records) from the database - -Connecting to the Database ----------------------- - -ActiveRecord relies on a [[Connection|DB connection]] to perform the underlying DB operations. -By default, ActiveRecord assumes that there is an application component named `db` which provides the needed -[[Connection]] instance. Usually this component is configured in application configuration file: - -```php -return [ - 'components' => [ - 'db' => [ - 'class' => 'yii\db\Connection', - 'dsn' => 'mysql:host=localhost;dbname=testdb', - 'username' => 'demo', - 'password' => 'demo', - ], - ], -]; -``` - -Please read the [Database basics](database-basics.md) section to learn more on how to configure and use database connections. - -Querying Data from the Database ---------------------------- - -There are two ActiveRecord methods for querying data from database: - - - [[ActiveRecord::find()]] - - [[ActiveRecord::findBySql()]] - -Both methods return an [[ActiveQuery]] instance, which extends [[Query]], and thus supports -the same set of flexible and powerful DB query methods. The following examples demonstrate some of the possibilities. - -```php -// to retrieve all *active* customers and order them by their ID: -$customers = Customer::find() - ->where(['status' => $active]) - ->orderBy('id') - ->all(); - -// to return a single customer whose ID is 1: -$customer = Customer::find(1); - -// the above code is equivalent to the following: -$customer = Customer::find() - ->where(['id' => 1]) - ->one(); - -// to retrieve customers using a raw SQL statement: -$sql = 'SELECT * FROM tbl_customer'; -$customers = Customer::findBySql($sql)->all(); - -// to return the number of *active* customers: -$count = Customer::find() - ->where(['status' => $active]) - ->count(); - -// to return customers in terms of arrays rather than `Customer` objects: -$customers = Customer::find() - ->asArray() - ->all(); -// each element of $customers is an array of name-value pairs - -// to index the result by customer IDs: -$customers = Customer::find()->indexBy('id')->all(); -// $customers array is indexed by customer IDs -``` - - -Accessing Column Data ---------------------- - -ActiveRecord maps each column of the corresponding database table row to an attribute in the ActiveRecord -object. The attribute behaves like any regular object public property. The attribute's name will be the same as the corresponding column -name, and is case-sensitive. - -To read the value of a column, you can use the following syntax: - -```php -// "id" and "email" are the names of columns in the table associated with $customer ActiveRecord object -$id = $customer->id; -$email = $customer->email; -``` - -To change the value of a column, assign a new value to the associated property and save the object: - -``` -$customer->email = 'jane@example.com'; -$customer->save(); -``` - -Manipulating Data in the Database ------------------------------ - -ActiveRecord provides the following methods to insert, update and delete data in the database: - -- [[ActiveRecord::save()|save()]] -- [[ActiveRecord::insert()|insert()]] -- [[ActiveRecord::update()|update()]] -- [[ActiveRecord::delete()|delete()]] -- [[ActiveRecord::updateCounters()|updateCounters()]] -- [[ActiveRecord::updateAll()|updateAll()]] -- [[ActiveRecord::updateAllCounters()|updateAllCounters()]] -- [[ActiveRecord::deleteAll()|deleteAll()]] - -Note that [[ActiveRecord::updateAll()|updateAll()]], [[ActiveRecord::updateAllCounters()|updateAllCounters()]] -and [[ActiveRecord::deleteAll()|deleteAll()]] are static methods that apply to the whole database -table. The other methods only apply to the row associated with the ActiveRecord object through which the method is being called. - -```php -// to insert a new customer record -$customer = new Customer; -$customer->name = 'James'; -$customer->email = 'james@example.com'; -$customer->save(); // equivalent to $customer->insert(); - -// to update an existing customer record -$customer = Customer::find($id); -$customer->email = 'james@example.com'; -$customer->save(); // equivalent to $customer->update(); - -// to delete an existing customer record -$customer = Customer::find($id); -$customer->delete(); - -// to increment the age of ALL customers by 1 -Customer::updateAllCounters(['age' => 1]); -``` - -> Info: The `save()` method will either perform an `INSERT` or `UPDATE` SQL statement, depending - on whether the ActiveRecord being saved is new or not by checking `ActiveRecord::isNewRecord`. - - -Data Input and Validation -------------------------- - -ActiveRecord inherits data validation and data input features from [[\yii\base\Model]]. Data validation is called -automatically when `save()` is performed. If data validation fails, the saving operation will be cancelled. - -For more details refer to the [Model](model.md) section of this guide. - -Querying Relational Data ------------------------- - -You can use ActiveRecord to also query a table's relational data (i.e., selection of data from Table A can also pull in related data from Table B). Thanks to ActiveRecord, the relational data returned can be accessed like a property of the ActiveRecord object associated with the primary table. - -For example, with an appropriate relation declaration, by accessing `$customer->orders` you may obtain -an array of `Order` objects which represent the orders placed by the specified customer. - -To declare a relation, define a getter method which returns an [[ActiveRelation]] object. For example, - -```php -class Customer extends \yii\db\ActiveRecord -{ - public function getOrders() - { - return $this->hasMany(Order::className(), ['customer_id' => 'id']); - } -} - -class Order extends \yii\db\ActiveRecord -{ - public function getCustomer() - { - return $this->hasOne(Customer::className(), ['id' => 'customer_id']); - } -} -``` - -The methods [[ActiveRecord::hasMany()]] and [[ActiveRecord::hasOne()]] used in the above -are used to model the many-one relationship and one-one relationship in a relational database. -For example, a customer has many orders, and an order has one customer. -Both methods take two parameters and return an [[ActiveRelation]] object: - - - `$class`: the name of the class of the related model(s). This should be a fully qualified class name. - - `$link`: the association between columns from the two tables. This should be given as an array. - The keys of the array are the names of the columns from the table associated with `$class`, - while the values of the array are the names of the columns from the declaring class. - It is a good practice to define relationships based on table foreign keys. - -After declaring relations, getting relational data is as easy as accessing a component property -that is defined by the corresponding getter method: - -```php -// get the orders of a customer -$customer = Customer::find(1); -$orders = $customer->orders; // $orders is an array of Order objects -``` - -Behind the scene, the above code executes the following two SQL queries, one for each line of code: - -```sql -SELECT * FROM tbl_customer WHERE id=1; -SELECT * FROM tbl_order WHERE customer_id=1; -``` - -> Tip: If you access the expression `$customer->orders` again, will it perform the second SQL query again? -Nope. The SQL query is only performed the first time when this expression is accessed. Any further -accesses will only return the previously fetched results that are cached internally. If you want to re-query -the relational data, simply unset the existing one first: `unset($customer->orders);`. - -Sometimes, you may want to pass parameters to a relational query. For example, instead of returning -all orders of a customer, you may want to return only big orders whose subtotal exceeds a specified amount. -To do so, declare a `bigOrders` relation with the following getter method: - -```php -class Customer extends \yii\db\ActiveRecord -{ - public function getBigOrders($threshold = 100) - { - return $this->hasMany(Order::className(), ['customer_id' => 'id']) - ->where('subtotal > :threshold', [':threshold' => $threshold]) - ->orderBy('id'); - } -} -``` - -Remember that `hasMany()` returns an [[ActiveRelation]] object which extends from [[ActiveQuery]] -and thus supports the same set of querying methods as [[ActiveQuery]]. - -With the above declaration, if you access `$customer->bigOrders`, it will only return the orders -whose subtotal is greater than 100. To specify a different threshold value, use the following code: - -```php -$orders = $customer->getBigOrders(200)->all(); -``` - - -Relations with Pivot Table --------------------------- - -Sometimes, two tables are related together via an intermediary table called -[pivot table](http://en.wikipedia.org/wiki/Pivot_table). To declare such relations, we can customize -the [[ActiveRelation]] object by calling its [[ActiveRelation::via()]] or [[ActiveRelation::viaTable()]] -method. - -For example, if table `tbl_order` and table `tbl_item` are related via pivot table `tbl_order_item`, -we can declare the `items` relation in the `Order` class like the following: - -```php -class Order extends \yii\db\ActiveRecord -{ - public function getItems() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->viaTable('tbl_order_item', ['order_id' => 'id']); - } -} -``` - -[[ActiveRelation::via()]] method is similar to [[ActiveRelation::viaTable()]] except that -the first parameter of [[ActiveRelation::via()]] takes a relation name declared in the ActiveRecord class -instead of the pivot table name. For example, the above `items` relation can be equivalently declared as follows: - -```php -class Order extends \yii\db\ActiveRecord -{ - public function getOrderItems() - { - return $this->hasMany(OrderItem::className(), ['order_id' => 'id']); - } - - public function getItems() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems'); - } -} -``` - - -Lazy and Eager Loading ----------------------- - -As described earlier, when you access the related objects the first time, ActiveRecord will perform a DB query -to retrieve the corresponding data and populate it into the related objects. No query will be performed -if you access the same related objects again. We call this *lazy loading*. For example, - -```php -// SQL executed: SELECT * FROM tbl_customer WHERE id=1 -$customer = Customer::find(1); -// SQL executed: SELECT * FROM tbl_order WHERE customer_id=1 -$orders = $customer->orders; -// no SQL executed -$orders2 = $customer->orders; -``` - -Lazy loading is very convenient to use. However, it may suffer from a performance issue in the following scenario: - -```php -// SQL executed: SELECT * FROM tbl_customer LIMIT 100 -$customers = Customer::find()->limit(100)->all(); - -foreach ($customers as $customer) { - // SQL executed: SELECT * FROM tbl_order WHERE customer_id=... - $orders = $customer->orders; - // ...handle $orders... -} -``` - -How many SQL queries will be performed in the above code, assuming there are more than 100 customers in -the database? 101! The first SQL query brings back 100 customers. Then for each customer, a SQL query -is performed to bring back the orders of that customer. - -To solve the above performance problem, you can use the so-called *eager loading* approach by calling [[ActiveQuery::with()]]: - -```php -// SQL executed: SELECT * FROM tbl_customer LIMIT 100; -// SELECT * FROM tbl_orders WHERE customer_id IN (1,2,...) -$customers = Customer::find()->limit(100) - ->with('orders')->all(); - -foreach ($customers as $customer) { - // no SQL executed - $orders = $customer->orders; - // ...handle $orders... -} -``` - -As you can see, only two SQL queries are needed for the same task. - - -Sometimes, you may want to customize the relational queries on the fly. This can be -done for both lazy loading and eager loading. For example, - -```php -$customer = Customer::find(1); -// lazy loading: SELECT * FROM tbl_order WHERE customer_id=1 AND subtotal>100 -$orders = $customer->getOrders()->where('subtotal>100')->all(); - -// eager loading: SELECT * FROM tbl_customer LIMIT 100 -// SELECT * FROM tbl_order WHERE customer_id IN (1,2,...) AND subtotal>100 -$customers = Customer::find()->limit(100)->with([ - 'orders' => function($query) { - $query->andWhere('subtotal>100'); - }, -])->all(); -``` - - -Joining with Relations ----------------------- - -When working with relational databases, a common task is to join multiple tables and apply various -query conditions and parameters to the JOIN SQL statement. Instead of calling [[ActiveQuery::join()]] -explicitly to build up the JOIN query, you may reuse the existing relation definitions and call -[[ActiveQuery::joinWith()]] to achieve this goal. For example, - -```php -// find all orders and sort the orders by the customer id and the order id. also eager loading "customer" -$orders = Order::find()->joinWith('customer')->orderBy('tbl_customer.id, tbl_order.id')->all(); -// find all orders that contain books, and eager loading "books" -$orders = Order::find()->innerJoinWith('books')->all(); -``` - -In the above, the method [[ActiveQuery::innerJoinWith()|innerJoinWith()]] is a shortcut to [[ActiveQuery::joinWith()|joinWith()]] -with the join type set as `INNER JOIN`. - -You may join with one or multiple relations; you may apply query conditions to the relations on-the-fly; -and you may also join with sub-relations. For example, - -```php -// join with multiple relations -// find out the orders that contain books and are placed by customers who registered within the past 24 hours -$orders = Order::find()->innerJoinWith([ - 'books', - 'customer' => function ($query) { - $query->where('tbl_customer.create_time > ' . (time() - 24 * 3600)); - } -])->all(); -// join with sub-relations: join with books and books' authors -$orders = Order::find()->joinWith('books.author')->all(); -``` - -Behind the scene, Yii will first execute a JOIN SQL statement to bring back the primary models -satisfying the conditions applied to the JOIN SQL. It will then execute a query for each relation -and populate the corresponding related records. - -The difference between [[ActiveQuery::joinWith()|joinWith()]] and [[ActiveQuery::with()|with()]] is that -the former joins the tables for the primary model class and the related model classes to retrieve -the primary models, while the latter just queries against the table for the primary model class to -retrieve the primary models. - -Because of this difference, you may apply query conditions that are only available to a JOIN SQL statement. -For example, you may filter the primary models by the conditions on the related models, like the example -above. You may also sort the primary models using columns from the related tables. - -When using [[ActiveQuery::joinWith()|joinWith()]], you are responsible to disambiguate column names. -In the above examples, we use `tbl_item.id` and `tbl_order.id` to disambiguate the `id` column references -because both of the order table and the item table contain a column named `id`. - -By default, when you join with a relation, the relation will also be eagerly loaded. You may change this behavior -by passing the `$eagerLoading` parameter which specifies whether to eager load the specified relations. - -And also by default, [[ActiveQuery::joinWith()|joinWith()]] uses `LEFT JOIN` to join the related tables. -You may pass it with the `$joinType` parameter to customize the join type. As a shortcut to the `INNER JOIN` type, -you may use [[ActiveQuery::innerJoinWith()|innerJoinWith()]]. - -Below are some more examples, - -```php -// find all orders that contain books, but do not eager loading "books". -$orders = Order::find()->innerJoinWith('books', false)->all(); -// which is equivalent to the above -$orders = Order::find()->joinWith('books', false, 'INNER JOIN')->all(); -``` - -Sometimes when joining two tables, you may need to specify some extra condition in the ON part of the JOIN query. -This can be done by calling the [[\yii\db\ActiveRelation::onCondition()]] method like the following: - -```php -class User extends ActiveRecord -{ - public function getBooks() - { - return $this->hasMany(Item::className(), ['owner_id' => 'id'])->onCondition(['category_id' => 1]); - } -} -``` - -In the above, the `hasMany()` method returns an `ActiveRelation` instance, upon which `onCondition()` is called -to specify that only items whose `category_id` is 1 should be returned. - -When you perform query using [[ActiveQuery::joinWith()|joinWith()]], the on-condition will be put in the ON part -of the corresponding JOIN query. For example, - -```php -// SELECT tbl_user.* FROM tbl_user LEFT JOIN tbl_item ON tbl_item.owner_id=tbl_user.id AND category_id=1 -// SELECT * FROM tbl_item WHERE owner_id IN (...) AND category_id=1 -$users = User::model()->joinWith('books')->all(); -``` - -Note that if you use eager loading via [[ActiveQuery::with()]] or lazy loading, the on-condition will be put -in the WHERE part of the corresponding SQL statement, because there is no JOIN query involved. For example, - -```php -// SELECT * FROM tbl_user WHERE id=10 -$user = User::model(10); -// SELECT * FROM tbl_item WHERE owner_id=10 AND category_id=1 -$books = $user->books; -``` - - -Working with Relationships --------------------------- - -ActiveRecord provides the following two methods for establishing and breaking a -relationship between two ActiveRecord objects: - -- [[ActiveRecord::link()|link()]] -- [[ActiveRecord::unlink()|unlink()]] - -For example, given a customer and a new order, we can use the following code to make the -order owned by the customer: - -```php -$customer = Customer::find(1); -$order = new Order; -$order->subtotal = 100; -$customer->link('orders', $order); -``` - -The [[link()]] call above will set the `customer_id` of the order to be the primary key -value of `$customer` and then call [[save()]] to save the order into database. - - -Life Cycles of an ActiveRecord Object -------------------------------------- - -An ActiveRecord object undergoes different life cycles when it is used in different cases. -Subclasses or ActiveRecord behaviors may "inject" custom code in these life cycles through -method overriding and event handling mechanisms. - -When instantiating a new ActiveRecord instance, we will have the following life cycles: - -1. constructor -2. [[init()]]: will trigger an [[EVENT_INIT]] event - -When getting an ActiveRecord instance through the [[find()]] method, we will have the following life cycles: - -1. constructor -2. [[init()]]: will trigger an [[EVENT_INIT]] event -3. [[afterFind()]]: will trigger an [[EVENT_AFTER_FIND]] event - -When calling [[save()]] to insert or update an ActiveRecord, we will have the following life cycles: - -1. [[beforeValidate()]]: will trigger an [[EVENT_BEFORE_VALIDATE]] event -2. [[afterValidate()]]: will trigger an [[EVENT_AFTER_VALIDATE]] event -3. [[beforeSave()]]: will trigger an [[EVENT_BEFORE_INSERT]] or [[EVENT_BEFORE_UPDATE]] event -4. perform the actual data insertion or updating -5. [[afterSave()]]: will trigger an [[EVENT_AFTER_INSERT]] or [[EVENT_AFTER_UPDATE]] event - -Finally when calling [[delete()]] to delete an ActiveRecord, we will have the following life cycles: - -1. [[beforeDelete()]]: will trigger an [[EVENT_BEFORE_DELETE]] event -2. perform the actual data deletion -3. [[afterDelete()]]: will trigger an [[EVENT_AFTER_DELETE]] event - - -Scopes ------- - -A scope is a method that customizes a given [[ActiveQuery]] object. Scope methods are static and are defined -in the ActiveRecord classes. They can be invoked through the [[ActiveQuery]] object that is created -via [[find()]] or [[findBySql()]]. The following is an example: - -```php -class Comment extends \yii\db\ActiveRecord -{ - // ... - - /** - * @param ActiveQuery $query - */ - public static function active($query) - { - $query->andWhere('status = 1'); - } -} - -$comments = Comment::find()->active()->all(); -``` - -In the above, the `active()` method is defined in `Comment` while we are calling it -through `ActiveQuery` returned by `Comment::find()`. - -You can also use scopes when defining relations. For example, - -```php -class Post extends \yii\db\ActiveRecord -{ - public function getComments() - { - return $this->hasMany(Comment::className(), ['post_id' => 'id'])->active(); - - } -} -``` - -Or use the scopes on-the-fly when performing relational query: - -```php -$posts = Post::find()->with([ - 'comments' => function($q) { - $q->active(); - } -])->all(); -``` - -Scopes can be parameterized. For example, we can define and use the following `olderThan` scope: - -```php -class Customer extends \yii\db\ActiveRecord -{ - // ... - - /** - * @param ActiveQuery $query - * @param integer $age - */ - public static function olderThan($query, $age = 30) - { - $query->andWhere('age > :age', [':age' => $age]); - } -} - -$customers = Customer::find()->olderThan(50)->all(); -``` - -The parameters should follow after the `$query` parameter when defining the scope method, and they -can take default values like shown above. - - -Transactional operations ------------------------- - - -When a few DB operations are related and are executed - -TODO: FIXME: WIP, TBD, https://github.com/yiisoft/yii2/issues/226 - -, -[[afterSave()]], [[beforeDelete()]] and/or [[afterDelete()]] life cycle methods. Developer may come -to the solution of overriding ActiveRecord [[save()]] method with database transaction wrapping or -even using transaction in controller action, which is strictly speaking doesn't seems to be a good -practice (recall skinny-controller fat-model fundamental rule). - -Here these ways are (**DO NOT** use them unless you're sure what are you actually doing). Models: - -```php -class Feature extends \yii\db\ActiveRecord -{ - // ... - - public function getProduct() - { - return $this->hasOne(Product::className(), ['product_id' => 'id']); - } -} - -class Product extends \yii\db\ActiveRecord -{ - // ... - - public function getFeatures() - { - return $this->hasMany(Feature::className(), ['id' => 'product_id']); - } -} -``` - -Overriding [[save()]] method: - -```php - -class ProductController extends \yii\web\Controller -{ - public function actionCreate() - { - // FIXME: TODO: WIP, TBD - } -} -``` - -Using transactions within controller layer: - -```php -class ProductController extends \yii\web\Controller -{ - public function actionCreate() - { - // FIXME: TODO: WIP, TBD - } -} -``` - -Instead of using these fragile methods you should consider using atomic scenarios and operations feature. - -```php -class Feature extends \yii\db\ActiveRecord -{ - // ... - - public function getProduct() - { - return $this->hasOne(Product::className(), ['product_id' => 'id']); - } - - public function scenarios() - { - return [ - 'userCreates' => [ - 'attributes' => ['name', 'value'], - 'atomic' => [self::OP_INSERT], - ], - ]; - } -} - -class Product extends \yii\db\ActiveRecord -{ - // ... - - public function getFeatures() - { - return $this->hasMany(Feature::className(), ['id' => 'product_id']); - } - - public function scenarios() - { - return [ - 'userCreates' => [ - 'attributes' => ['title', 'price'], - 'atomic' => [self::OP_INSERT], - ], - ]; - } - - public function afterValidate() - { - parent::afterValidate(); - // FIXME: TODO: WIP, TBD - } - - public function afterSave($insert) - { - parent::afterSave($insert); - if ($this->getScenario() === 'userCreates') { - // FIXME: TODO: WIP, TBD - } - } -} -``` - -Controller is very thin and neat: - -```php -class ProductController extends \yii\web\Controller -{ - public function actionCreate() - { - // FIXME: TODO: WIP, TBD - } -} -``` - -Optimistic Locks ----------------- - -TODO - -Dirty Attributes ----------------- - -TODO - -See also --------- - -- [Model](model.md) -- [[\yii\db\ActiveRecord]] diff --git a/docs/guide/apps-advanced.md b/docs/guide/apps-advanced.md deleted file mode 100644 index bf1d323..0000000 --- a/docs/guide/apps-advanced.md +++ /dev/null @@ -1,174 +0,0 @@ -Advanced application template -============================= - -This template is for large projects developed in teams where backend is divided from frontend, application is deployed -to multiple servers etc. This application template also goes a bit further regarding features and provides essential -database, signup and password restore out of the box. - -Installation ------------- - -### Install via Composer - -If you do not have [Composer](http://getcomposer.org/), you may download it from -[http://getcomposer.org/](http://getcomposer.org/) or run the following command on Linux/Unix/MacOS: - -~~~ -curl -s http://getcomposer.org/installer | php -~~~ - -You can then install the application using the following command: - -~~~ -php composer.phar create-project --prefer-dist --stability=dev yiisoft/yii2-app-advanced /path/to/yii-application -~~~ - -Getting started ---------------- - -After you install the application, you have to conduct the following steps to initialize -the installed application. You only need to do these once for all. - -1. Execute the `init` command and select `dev` as environment. ---- -php /path/to/yii-application/init ---- -2. Create a new database and adjust the `components.db` configuration in `common/config/params-local.php` accordingly. -3. Apply migrations with console command `yii migrate`. -4. Set document roots of your Web server: - -- for frontend `/path/to/yii-application/frontend/web/` and using the URL `http://frontend/` -- for backend `/path/to/yii-application/backend/web/` and using the URL `http://backend/` - -Directory structure -------------------- - -The root directory contains the following subdirectories: - -- `backend` - backend web application. -- `common` - files common to all applications. -- `console` - console application. -- `environments` - environment configs. -- `frontend` - frontend web application. - -Root directory contains a set of files. - -- `.gitignore` contains a list of directories ignored by git version system. If you need something never get to your source - code repository, add it there. -- `composer.json` - Composer config described in detail below. -- `init` - initialization script described in "Composer config described in detail below". -- `init.bat` - same for Windows. -- `LICENSE.md` - license info. Put your project license there. Especially when opensourcing. -- `README.md` - basic info about installing template. Consider replacing it with information about your project and its - installation. -- `requirements.php` - Yii requirements checker. -- `yii` - console application bootstrap. -- `yii.bat` - same for Windows. - -Applications ------------- - -There are three applications in advanced template: frontend, backend and console. Frontend is typically what is presented -to end user, the project itself. Backend is admin panel, analytics and such functionality. Console is typically used for -cron jobs and low-level server management. Also it's used during application deployment and handles migrations and assets. - -There's also a `common` directory that contains files used by more than one application. For example, `User` model. - -frontend and backend are both web applications and both contain `web` directory. That's the webroot you should point your -webserver to. - -Each application has its own namespace and alias corresponding to its name. Same applies to common directory. - -Configuration and environments ------------------------------- - -There are multiple problems with straightforward approach to configuration: - -- Each team member has its own configuration options. Committing such config will affect other team members. -- Production database password and API keys should not end up in repository. -- There are multiple servers: development, testing, production. Each should have its own configuration. -- Defining all configuration options for each case is very repetitive and takes too much time to maintain. - -In order to solve these issues Yii introduces environments concept that is very simple. Each environment is represented -by a set of files under `environments` directory. `init` command is used to switch between these. What is really does is -just copying everything from environment directory over the root directory where all applications are. - -Typically environment contains application bootstrap files such as `index.php` and config files suffixed with -`-local.php`. These are added to `.gitignore` and never added to source code repository. - -In order to avoid duplication configurations are overriding each other. For example, frontend reads configuration in the -following order: - -- `frontend/config/main.php` -- `frontend/config/main-local.php` - -Parameters are read in the following order: - -- `common/config/params.php` -- `common/config/params-local.php` -- `frontend/config/params.php` -- `frontend/config/params-local.php` - -The later config file overrides the former. - -Another difference is that most application component configurations are moved to params. Since params are read from -`common` as well it allows you to specify database connection in one file and it will be then used for all applications. - -Configuring Composer --------------------- - -After application template is installed it's a good idea to adjust default `composer.json` that can be found in the root -directory: - -```json -{ - "name": "yiisoft/yii2-app-advanced", - "description": "Yii 2 Advanced Application Template", - "keywords": ["yii", "framework", "advanced", "application template"], - "homepage": "http://www.yiiframework.com/", - "type": "project", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?state=open", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "minimum-stability": "dev", - "require": { - "php": ">=5.4.0", - "yiisoft/yii2": "*", - "yiisoft/yii2-swiftmailer": "*", - "yiisoft/yii2-bootstrap": "*", - "yiisoft/yii2-debug": "*", - "yiisoft/yii2-gii": "*" - }, - "scripts": { - "post-create-project-cmd": [ - "yii\\composer\\Installer::setPermission" - ] - }, - "extra": { - "writable": [ - "backend/runtime", - "backend/web/assets", - - "console/runtime", - "console/migrations", - - "frontend/runtime", - "frontend/web/assets" - ] - } -} -``` - -First we're updating basic information. Change `name`, `description`, `keywords`, `homepage` and `support` to match -your project. - -Now the interesting part. You can add more packages your application needs to `require` section. -All these packages are coming from [packagist.org](https://packagist.org/) so feel free to browse the website for useful code. - -After your `composer.json` is changed you can run `php composer.phar update --prefer-dist`, wait till packages are downloaded and -installed and then just use them. Autoloading of classes will be handled automatically. diff --git a/docs/guide/apps-basic.md b/docs/guide/apps-basic.md deleted file mode 100644 index 873125c..0000000 --- a/docs/guide/apps-basic.md +++ /dev/null @@ -1,163 +0,0 @@ -Basic application template -========================== - -This template is a perfect fit for small projects or learning Yii2. - -The application has four pages: the homepage, the about page, the contact page and the login page. -The contact page displays a contact form that users can fill in to submit their inquiries to the webmaster, -and the login page allows users to be authenticated before accessing privileged contents. - -Installation ------------- - -If you do not have [Composer](http://getcomposer.org/), you may download it from -[http://getcomposer.org/](http://getcomposer.org/) or run the following command on Linux/Unix/MacOS: - -~~~ -curl -s http://getcomposer.org/installer | php -~~~ - -You can then install the Bootstrap Application using the following command: - -~~~ -php composer.phar create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic /path/to/yii-application -~~~ - -Now set document root directory of your Web server to /path/to/yii-application/web and you should be able to access the application using the URL `http://localhost/`. - -Directory structure -------------------- - -The basic application does not divide application directories much. Here's the basic structure: - -- `assets` - application asset files. - - `AppAsset.php` - definition of application assets such as CSS, JavaScript etc. Check [Managing assets](assets.md) for - details. -- `commands` - console controllers. -- `config` - configuration. -- `controllers` - web controllers. -- `models` - application models. -- `runtime` - logs, states, file cache. -- `views` - view templates. -- `web` - webroot. - -Root directory contains a set of files. - -- `.gitignore` contains a list of directories ignored by git version system. If you need something never get to your source -code repository, add it there. -- `codeception.yml` - Codeception config. -- `composer.json` - Composer config described in detail below. -- `LICENSE.md` - license info. Put your project license there. Especially when opensourcing. -- `README.md` - basic info about installing template. Consider replacing it with information about your project and its - installation. -- `requirements.php` - Yii requirements checker. -- `yii` - console application bootstrap. -- `yii.bat` - same for Windows. - - -### config - -This directory contains configuration files: - -- `console.php` - console application configuration. -- `params.php` - common application parameters. -- `web.php` - web application configuration. -- `web-test.php` - web application configuration used when running functional tests. - -All these files are returning arrays used to configure corresponding application properties. Check -[Configuration](configuration.md) guide section for details. - -### views - -Views directory contains templates your application is using. In the basic template there are: - -``` -layouts - main.php -site - about.php - contact.php - error.php - index.php - login.php -``` - -`layouts` contains HTML layouts i.e. page markup except content: doctype, head section, main menu, footer etc. -The rest are typically controller views. By convention these are located in subdirectories matching controller id. For -`SiteController` views are under `site`. Names of the views themselves are typically match controller action names. -Partials are often named starting with underscore. - -### web - -Directory is a webroot. Typically a webserver is pointed into it. - -``` -assets -css -index.php -index-test.php -``` - -`assets` contains published asset files such as CSS, JavaScript etc. Publishing process is automatic so you don't need -to do anything with this directory other than making sure Yii has enough permissions to write to it. - -`css` contains plain CSS files and is useful for global CSS that isn't going to be compressed or merged by assets manager. - -`index.php` is the main web application bootstrap and is the central entry point for it. `index-test.php` is the entry -point for functional testing. - -Configuring Composer --------------------- - -After application template is installed it's a good idea to adjust default `composer.json` that can be found in the root -directory: - -```json -{ - "name": "yiisoft/yii2-app-basic", - "description": "Yii 2 Basic Application Template", - "keywords": ["yii", "framework", "basic", "application template"], - "homepage": "http://www.yiiframework.com/", - "type": "project", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?state=open", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "minimum-stability": "dev", - "require": { - "php": ">=5.4.0", - "yiisoft/yii2": "*", - "yiisoft/yii2-swiftmailer": "*", - "yiisoft/yii2-bootstrap": "*", - "yiisoft/yii2-debug": "*", - "yiisoft/yii2-gii": "*" - }, - "scripts": { - "post-create-project-cmd": [ - "yii\\composer\\Installer::setPermission" - ] - }, - "extra": { - "writable": [ - "runtime", - "web/assets" - ], - "executable": [ - "yii" - ] - } -} -``` - -First we're updating basic information. Change `name`, `description`, `keywords`, `homepage` and `support` to match -your project. - -Now the interesting part. You can add more packages your application needs to `require` section. -All these packages are coming from [packagist.org](https://packagist.org/) so feel free to browse the website for useful code. - -After your `composer.json` is changed you can run `php composer.phar update --prefer-dist`, wait till packages are downloaded and -installed and then just use them. Autoloading of classes will be handled automatically. diff --git a/docs/guide/apps-own.md b/docs/guide/apps-own.md deleted file mode 100644 index 3ebf83f..0000000 --- a/docs/guide/apps-own.md +++ /dev/null @@ -1,4 +0,0 @@ -Creating your own Application structure -======================================= - -TBD \ No newline at end of file diff --git a/docs/guide/assets.md b/docs/guide/assets.md deleted file mode 100644 index 467d7f8..0000000 --- a/docs/guide/assets.md +++ /dev/null @@ -1,270 +0,0 @@ -Managing assets -=============== - -An asset in Yii is a file that is included into the page. It could be CSS, JavaScript or -any other file. Framework provides many ways to work with assets from basics such as adding ` - - -endBody(); ?> - - -endPage(); ?> \ No newline at end of file diff --git a/extensions/yii/authclient/AuthAction.php b/extensions/yii/authclient/AuthAction.php deleted file mode 100644 index 0edf0a5..0000000 --- a/extensions/yii/authclient/AuthAction.php +++ /dev/null @@ -1,362 +0,0 @@ - [ - * 'class' => 'yii\authclient\AuthAction', - * 'successCallback' => [$this, 'successCallback'], - * ], - * ] - * } - * - * public function successCallback($client) - * { - * $attributes = $client->getUserAttributes(); - * // user login or signup comes here - * } - * } - * ~~~ - * - * Usually authentication via external services is performed inside the popup window. - * This action handles the redirection and closing of popup window correctly. - * - * @see Collection - * @see \yii\authclient\widgets\Choice - * - * @property string $cancelUrl Cancel URL. - * @property string $successUrl Successful URL. - * - * @author Paul Klimov - * @since 2.0 - */ -class AuthAction extends Action -{ - /** - * @var string name of the auth client collection application component. - * It should point to [[Collection]] instance. - */ - public $clientCollection = 'authClientCollection'; - /** - * @var string name of the GET param, which is used to passed auth client id to this action. - * Note: watch for the naming, make sure you do not choose name used in some auth protocol. - */ - public $clientIdGetParamName = 'authclient'; - /** - * @var callable PHP callback, which should be triggered in case of successful authentication. - * This callback should accept [[ClientInterface]] instance as an argument. - * For example: - * - * ~~~ - * public function onAuthSuccess($client) - * { - * $attributes = $client->getUserAttributes(); - * // user login or signup comes here - * } - * ~~~ - * - * If this callback returns [[Response]] instance, it will be used as action response, - * otherwise redirection to [[successUrl]] will be performed. - * - */ - public $successCallback; - /** - * @var string the redirect url after successful authorization. - */ - private $_successUrl = ''; - /** - * @var string the redirect url after unsuccessful authorization (e.g. user canceled). - */ - private $_cancelUrl = ''; - /** - * @var string name or alias of the view file, which should be rendered in order to perform redirection. - * If not set default one will be used. - */ - public $redirectView; - - /** - * @param string $url successful URL. - */ - public function setSuccessUrl($url) - { - $this->_successUrl = $url; - } - - /** - * @return string successful URL. - */ - public function getSuccessUrl() - { - if (empty($this->_successUrl)) { - $this->_successUrl = $this->defaultSuccessUrl(); - } - return $this->_successUrl; - } - - /** - * @param string $url cancel URL. - */ - public function setCancelUrl($url) - { - $this->_cancelUrl = $url; - } - - /** - * @return string cancel URL. - */ - public function getCancelUrl() - { - if (empty($this->_cancelUrl)) { - $this->_cancelUrl = $this->defaultCancelUrl(); - } - return $this->_cancelUrl; - } - - /** - * Creates default {@link successUrl} value. - * @return string success URL value. - */ - protected function defaultSuccessUrl() - { - return Yii::$app->getUser()->getReturnUrl(); - } - - /** - * Creates default {@link cancelUrl} value. - * @return string cancel URL value. - */ - protected function defaultCancelUrl() - { - return Yii::$app->getRequest()->getAbsoluteUrl(); - } - - /** - * Runs the action. - */ - public function run() - { - if (!empty($_GET[$this->clientIdGetParamName])) { - $clientId = $_GET[$this->clientIdGetParamName]; - /** @var \yii\authclient\Collection $collection */ - $collection = Yii::$app->getComponent($this->clientCollection); - if (!$collection->hasClient($clientId)) { - throw new NotFoundHttpException("Unknown auth client '{$clientId}'"); - } - $client = $collection->getClient($clientId); - return $this->auth($client); - } else { - throw new NotFoundHttpException(); - } - } - - /** - * @param mixed $client auth client instance. - * @return Response response instance. - * @throws \yii\base\NotSupportedException on invalid client. - */ - protected function auth($client) - { - if ($client instanceof OpenId) { - return $this->authOpenId($client); - } elseif ($client instanceof OAuth2) { - return $this->authOAuth2($client); - } elseif ($client instanceof OAuth1) { - return $this->authOAuth1($client); - } else { - throw new NotSupportedException('Provider "' . get_class($client) . '" is not supported.'); - } - } - - /** - * This method is invoked in case of successful authentication via auth client. - * @param ClientInterface $client auth client instance. - * @throws InvalidConfigException on invalid success callback. - * @return Response response instance. - */ - protected function authSuccess($client) - { - if (!is_callable($this->successCallback)) { - throw new InvalidConfigException('"' . get_class($this) . '::successCallback" should be a valid callback.'); - } - $response = call_user_func($this->successCallback, $client); - if ($response instanceof Response) { - return $response; - } - return $this->redirectSuccess(); - } - - /** - * Redirect to the given URL or simply close the popup window. - * @param mixed $url URL to redirect, could be a string or array config to generate a valid URL. - * @param boolean $enforceRedirect indicates if redirect should be performed even in case of popup window. - * @return \yii\web\Response response instance. - */ - public function redirect($url, $enforceRedirect = true) - { - $viewFile = $this->redirectView; - if ($viewFile === null) { - $viewFile = __DIR__ . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'redirect.php'; - } else { - $viewFile = Yii::getAlias($viewFile); - } - $viewData = [ - 'url' => $url, - 'enforceRedirect' => $enforceRedirect, - ]; - $response = Yii::$app->getResponse(); - $response->content = Yii::$app->getView()->renderFile($viewFile, $viewData); - return $response; - } - - /** - * Redirect to the URL. If URL is null, {@link successUrl} will be used. - * @param string $url URL to redirect. - * @return \yii\web\Response response instance. - */ - public function redirectSuccess($url = null) - { - if ($url === null) { - $url = $this->getSuccessUrl(); - } - return $this->redirect($url); - } - - /** - * Redirect to the {@link cancelUrl} or simply close the popup window. - * @param string $url URL to redirect. - * @return \yii\web\Response response instance. - */ - public function redirectCancel($url = null) - { - if ($url === null) { - $url = $this->getCancelUrl(); - } - return $this->redirect($url, false); - } - - /** - * Performs OpenID auth flow. - * @param OpenId $client auth client instance. - * @return Response action response. - * @throws Exception on failure. - * @throws HttpException on failure. - */ - protected function authOpenId($client) - { - if (!empty($_REQUEST['openid_mode'])) { - switch ($_REQUEST['openid_mode']) { - case 'id_res': - if ($client->validate()) { - return $this->authSuccess($client); - } else { - throw new HttpException(400, 'Unable to complete the authentication because the required data was not received.'); - } - break; - case 'cancel': - $this->redirectCancel(); - break; - default: - throw new HttpException(400); - break; - } - } else { - $url = $client->buildAuthUrl(); - return Yii::$app->getResponse()->redirect($url); - } - return $this->redirectCancel(); - } - - /** - * Performs OAuth1 auth flow. - * @param OAuth1 $client auth client instance. - * @return Response action response. - */ - protected function authOAuth1($client) - { - // user denied error - if (isset($_GET['denied'])) { - return $this->redirectCancel(); - } - - if (isset($_REQUEST['oauth_token'])) { - $oauthToken = $_REQUEST['oauth_token']; - } - - if (!isset($oauthToken)) { - // Get request token. - $requestToken = $client->fetchRequestToken(); - // Get authorization URL. - $url = $client->buildAuthUrl($requestToken); - // Redirect to authorization URL. - return Yii::$app->getResponse()->redirect($url); - } else { - // Upgrade to access token. - $accessToken = $client->fetchAccessToken(); - return $this->authSuccess($client); - } - } - - /** - * Performs OAuth2 auth flow. - * @param OAuth2 $client auth client instance. - * @return Response action response. - * @throws \yii\base\Exception on failure. - */ - protected function authOAuth2($client) - { - if (isset($_GET['error'])) { - if ($_GET['error'] == 'access_denied') { - // user denied error - return $this->redirectCancel(); - } else { - // request error - if (isset($_GET['error_description'])) { - $errorMessage = $_GET['error_description']; - } elseif (isset($_GET['error_message'])) { - $errorMessage = $_GET['error_message']; - } else { - $errorMessage = http_build_query($_GET); - } - throw new Exception('Auth error: ' . $errorMessage); - } - } - - // Get the access_token and save them to the session. - if (isset($_GET['code'])) { - $code = $_GET['code']; - $token = $client->fetchAccessToken($code); - if (!empty($token)) { - return $this->authSuccess($client); - } else { - return $this->redirectCancel(); - } - } else { - $url = $client->buildAuthUrl(); - return Yii::$app->getResponse()->redirect($url); - } - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/BaseClient.php b/extensions/yii/authclient/BaseClient.php deleted file mode 100644 index 9868d48..0000000 --- a/extensions/yii/authclient/BaseClient.php +++ /dev/null @@ -1,236 +0,0 @@ - optionValue. - * - * @author Paul Klimov - * @since 2.0 - */ -abstract class BaseClient extends Component implements ClientInterface -{ - /** - * @var string auth service id. - * This value mainly used as HTTP request parameter. - */ - private $_id; - /** - * @var string auth service name. - * This value may be used in database records, CSS files and so on. - */ - private $_name; - /** - * @var string auth service title to display in views. - */ - private $_title; - /** - * @var array authenticated user attributes. - */ - private $_userAttributes; - /** - * @var array map used to normalize user attributes fetched from external auth service - * in format: rawAttributeName => normalizedAttributeName - */ - private $_normalizeUserAttributeMap; - /** - * @var array view options in format: optionName => optionValue - */ - private $_viewOptions; - - /** - * @param string $id service id. - */ - public function setId($id) - { - $this->_id = $id; - } - - /** - * @return string service id - */ - public function getId() - { - if (empty($this->_id)) { - $this->_id = $this->getName(); - } - return $this->_id; - } - - /** - * @param string $name service name. - */ - public function setName($name) - { - $this->_name = $name; - } - - /** - * @return string service name. - */ - public function getName() - { - if ($this->_name === null) { - $this->_name = $this->defaultName(); - } - return $this->_name; - } - - /** - * @param string $title service title. - */ - public function setTitle($title) - { - $this->_title = $title; - } - - /** - * @return string service title. - */ - public function getTitle() - { - if ($this->_title === null) { - $this->_title = $this->defaultTitle(); - } - return $this->_title; - } - - /** - * @param array $userAttributes list of user attributes - */ - public function setUserAttributes($userAttributes) - { - $this->_userAttributes = $this->normalizeUserAttributes($userAttributes); - } - - /** - * @return array list of user attributes - */ - public function getUserAttributes() - { - if ($this->_userAttributes === null) { - $this->_userAttributes = $this->normalizeUserAttributes($this->initUserAttributes()); - } - return $this->_userAttributes; - } - - /** - * @param array $normalizeUserAttributeMap normalize user attribute map. - */ - public function setNormalizeUserAttributeMap($normalizeUserAttributeMap) - { - $this->_normalizeUserAttributeMap = $normalizeUserAttributeMap; - } - - /** - * @return array normalize user attribute map. - */ - public function getNormalizeUserAttributeMap() - { - if ($this->_normalizeUserAttributeMap === null) { - $this->_normalizeUserAttributeMap = $this->defaultNormalizeUserAttributeMap(); - } - return $this->_normalizeUserAttributeMap; - } - - /** - * @param array $viewOptions view options in format: optionName => optionValue - */ - public function setViewOptions($viewOptions) - { - $this->_viewOptions = $viewOptions; - } - - /** - * @return array view options in format: optionName => optionValue - */ - public function getViewOptions() - { - if ($this->_viewOptions === null) { - $this->_viewOptions = $this->defaultViewOptions(); - } - return $this->_viewOptions; - } - - /** - * Generates service name. - * @return string service name. - */ - protected function defaultName() - { - return Inflector::camel2id(StringHelper::basename(get_class($this))); - } - - /** - * Generates service title. - * @return string service title. - */ - protected function defaultTitle() - { - return StringHelper::basename(get_class($this)); - } - - /** - * Initializes authenticated user attributes. - * @return array auth user attributes. - */ - protected function initUserAttributes() - { - throw new NotSupportedException('Method "' . get_class($this) . '::' . __FUNCTION__ . '" not implemented.'); - } - - /** - * Returns the default [[normalizeUserAttributeMap]] value. - * Particular client may override this method in order to provide specific default map. - * @return array normalize attribute map. - */ - protected function defaultNormalizeUserAttributeMap() - { - return []; - } - - /** - * Returns the default [[viewOptions]] value. - * Particular client may override this method in order to provide specific default view options. - * @return array list of default [[viewOptions]] - */ - protected function defaultViewOptions() - { - return []; - } - - /** - * Normalize given user attributes according to {@link normalizeUserAttributeMap}. - * @param array $attributes raw attributes. - * @return array normalized attributes. - */ - protected function normalizeUserAttributes($attributes) - { - foreach ($this->getNormalizeUserAttributeMap() as $normalizedName => $actualName) { - if (array_key_exists($actualName, $attributes)) { - $attributes[$normalizedName] = $attributes[$actualName]; - } - } - return $attributes; - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/BaseOAuth.php b/extensions/yii/authclient/BaseOAuth.php deleted file mode 100644 index 314f2e7..0000000 --- a/extensions/yii/authclient/BaseOAuth.php +++ /dev/null @@ -1,510 +0,0 @@ - - * @since 2.0 - */ -abstract class BaseOAuth extends BaseClient implements ClientInterface -{ - const CONTENT_TYPE_JSON = 'json'; // JSON format - const CONTENT_TYPE_URLENCODED = 'urlencoded'; // urlencoded query string, like name1=value1&name2=value2 - const CONTENT_TYPE_XML = 'xml'; // XML format - const CONTENT_TYPE_AUTO = 'auto'; // attempts to determine format automatically - - /** - * @var string protocol version. - */ - public $version = '1.0'; - /** - * @var string URL, which user will be redirected after authentication at the OAuth provider web site. - * Note: this should be absolute URL (with http:// or https:// leading). - * By default current URL will be used. - */ - private $_returnUrl; - /** - * @var string API base URL. - */ - public $apiBaseUrl; - /** - * @var string authorize URL. - */ - public $authUrl; - /** - * @var string auth request scope. - */ - public $scope; - /** - * @var array cURL request options. Option values from this field will overwrite corresponding - * values from {@link defaultCurlOptions()}. - */ - private $_curlOptions = []; - /** - * @var OAuthToken|array access token instance or its array configuration. - */ - private $_accessToken; - /** - * @var signature\BaseMethod|array signature method instance or its array configuration. - */ - private $_signatureMethod = []; - - /** - * @param string $returnUrl return URL - */ - public function setReturnUrl($returnUrl) - { - $this->_returnUrl = $returnUrl; - } - - /** - * @return string return URL. - */ - public function getReturnUrl() - { - if ($this->_returnUrl === null) { - $this->_returnUrl = $this->defaultReturnUrl(); - } - return $this->_returnUrl; - } - - /** - * @param array $curlOptions cURL options. - */ - public function setCurlOptions(array $curlOptions) - { - $this->_curlOptions = $curlOptions; - } - - /** - * @return array cURL options. - */ - public function getCurlOptions() - { - return $this->_curlOptions; - } - - /** - * @param array|OAuthToken $token - */ - public function setAccessToken($token) - { - if (!is_object($token)) { - $token = $this->createToken($token); - } - $this->_accessToken = $token; - $this->saveAccessToken($token); - } - - /** - * @return OAuthToken auth token instance. - */ - public function getAccessToken() - { - if (!is_object($this->_accessToken)) { - $this->_accessToken = $this->restoreAccessToken(); - } - return $this->_accessToken; - } - - /** - * @param array|signature\BaseMethod $signatureMethod signature method instance or its array configuration. - * @throws InvalidParamException on wrong argument. - */ - public function setSignatureMethod($signatureMethod) - { - if (!is_object($signatureMethod) && !is_array($signatureMethod)) { - throw new InvalidParamException('"' . get_class($this) . '::signatureMethod" should be instance of "\yii\autclient\signature\BaseMethod" or its array configuration. "' . gettype($signatureMethod) . '" has been given.'); - } - $this->_signatureMethod = $signatureMethod; - } - - /** - * @return signature\BaseMethod signature method instance. - */ - public function getSignatureMethod() - { - if (!is_object($this->_signatureMethod)) { - $this->_signatureMethod = $this->createSignatureMethod($this->_signatureMethod); - } - return $this->_signatureMethod; - } - - /** - * Composes default {@link returnUrl} value. - * @return string return URL. - */ - protected function defaultReturnUrl() - { - return Yii::$app->getRequest()->getAbsoluteUrl(); - } - - /** - * Sends HTTP request. - * @param string $method request type. - * @param string $url request URL. - * @param array $params request params. - * @return array response. - * @throws Exception on failure. - */ - protected function sendRequest($method, $url, array $params = []) - { - $curlOptions = $this->mergeCurlOptions( - $this->defaultCurlOptions(), - $this->getCurlOptions(), - array( - CURLOPT_RETURNTRANSFER => true, - CURLOPT_URL => $url, - ), - $this->composeRequestCurlOptions(strtoupper($method), $url, $params) - ); - $curlResource = curl_init(); - foreach ($curlOptions as $option => $value) { - curl_setopt($curlResource, $option, $value); - } - $response = curl_exec($curlResource); - $responseHeaders = curl_getinfo($curlResource); - - // check cURL error - $errorNumber = curl_errno($curlResource); - $errorMessage = curl_error($curlResource); - - curl_close($curlResource); - - if ($errorNumber > 0) { - throw new Exception('Curl error requesting "' . $url . '": #' . $errorNumber . ' - ' . $errorMessage); - } - if ($responseHeaders['http_code'] != 200) { - throw new Exception('Request failed with code: ' . $responseHeaders['http_code'] . ', message: ' . $response); - } - return $this->processResponse($response, $this->determineContentTypeByHeaders($responseHeaders)); - } - - /** - * Merge CUrl options. - * If each options array has an element with the same key value, the latter - * will overwrite the former. - * @param array $options1 options to be merged to. - * @param array $options2 options to be merged from. You can specify additional - * arrays via third argument, fourth argument etc. - * @return array merged options (the original options are not changed.) - */ - protected function mergeCurlOptions($options1, $options2) - { - $args = func_get_args(); - $res = array_shift($args); - while (!empty($args)) { - $next = array_shift($args); - foreach ($next as $k => $v) { - $res[$k]=$v; - } - } - return $res; - } - - /** - * Returns default cURL options. - * @return array cURL options. - */ - protected function defaultCurlOptions() - { - return [ - CURLOPT_USERAGENT => Yii::$app->name . ' OAuth ' . $this->version . ' Client', - CURLOPT_CONNECTTIMEOUT => 30, - CURLOPT_TIMEOUT => 30, - CURLOPT_SSL_VERIFYPEER => false, - ]; - } - - /** - * Processes raw response converting it to actual data. - * @param string $rawResponse raw response. - * @param string $contentType response content type. - * @throws Exception on failure. - * @return array actual response. - */ - protected function processResponse($rawResponse, $contentType = self::CONTENT_TYPE_AUTO) - { - if (empty($rawResponse)) { - return []; - } - switch ($contentType) { - case self::CONTENT_TYPE_AUTO: { - $contentType = $this->determineContentTypeByRaw($rawResponse); - if ($contentType == self::CONTENT_TYPE_AUTO) { - throw new Exception('Unable to determine response content type automatically.'); - } - $response = $this->processResponse($rawResponse, $contentType); - break; - } - case self::CONTENT_TYPE_JSON: { - $response = Json::decode($rawResponse, true); - if (isset($response['error'])) { - throw new Exception('Response error: ' . $response['error']); - } - break; - } - case self::CONTENT_TYPE_URLENCODED: { - $response = []; - parse_str($rawResponse, $response); - break; - } - case self::CONTENT_TYPE_XML: { - $response = $this->convertXmlToArray($rawResponse); - break; - } - default: { - throw new Exception('Unknown response type "' . $contentType . '".'); - } - } - return $response; - } - - /** - * Converts XML document to array. - * @param string|\SimpleXMLElement $xml xml to process. - * @return array XML array representation. - */ - protected function convertXmlToArray($xml) - { - if (!is_object($xml)) { - $xml = simplexml_load_string($xml); - } - $result = (array)$xml; - foreach ($result as $key => $value) { - if (is_object($value)) { - $result[$key] = $this->convertXmlToArray($value); - } - } - return $result; - } - - /** - * Attempts to determine HTTP request content type by headers. - * @param array $headers request headers. - * @return string content type. - */ - protected function determineContentTypeByHeaders(array $headers) - { - if (isset($headers['content_type'])) { - if (stripos($headers['content_type'], 'json') !== false) { - return self::CONTENT_TYPE_JSON; - } - if (stripos($headers['content_type'], 'urlencoded') !== false) { - return self::CONTENT_TYPE_URLENCODED; - } - if (stripos($headers['content_type'], 'xml') !== false) { - return self::CONTENT_TYPE_XML; - } - } - return self::CONTENT_TYPE_AUTO; - } - - /** - * Attempts to determine the content type from raw content. - * @param string $rawContent raw response content. - * @return string response type. - */ - protected function determineContentTypeByRaw($rawContent) - { - if (preg_match('/^\\{.*\\}$/is', $rawContent)) { - return self::CONTENT_TYPE_JSON; - } - if (preg_match('/^[^=|^&]+=[^=|^&]+(&[^=|^&]+=[^=|^&]+)*$/is', $rawContent)) { - return self::CONTENT_TYPE_URLENCODED; - } - if (preg_match('/^<.*>$/is', $rawContent)) { - return self::CONTENT_TYPE_XML; - } - return self::CONTENT_TYPE_AUTO; - } - - /** - * Creates signature method instance from its configuration. - * @param array $signatureMethodConfig signature method configuration. - * @return signature\BaseMethod signature method instance. - */ - protected function createSignatureMethod(array $signatureMethodConfig) - { - if (!array_key_exists('class', $signatureMethodConfig)) { - $signatureMethodConfig['class'] = signature\HmacSha1::className(); - } - return Yii::createObject($signatureMethodConfig); - } - - /** - * Creates token from its configuration. - * @param array $tokenConfig token configuration. - * @return OAuthToken token instance. - */ - protected function createToken(array $tokenConfig = []) - { - if (!array_key_exists('class', $tokenConfig)) { - $tokenConfig['class'] = OAuthToken::className(); - } - return Yii::createObject($tokenConfig); - } - - /** - * Composes URL from base URL and GET params. - * @param string $url base URL. - * @param array $params GET params. - * @return string composed URL. - */ - protected function composeUrl($url, array $params = []) - { - if (strpos($url, '?') === false) { - $url .= '?'; - } else { - $url .= '&'; - } - $url .= http_build_query($params, '', '&', PHP_QUERY_RFC3986); - return $url; - } - - /** - * Saves token as persistent state. - * @param OAuthToken $token auth token - * @return static self reference. - */ - protected function saveAccessToken(OAuthToken $token) - { - return $this->setState('token', $token); - } - - /** - * Restores access token. - * @return OAuthToken auth token. - */ - protected function restoreAccessToken() - { - $token = $this->getState('token'); - if (is_object($token)) { - /* @var $token OAuthToken */ - if ($token->getIsExpired()) { - $token = $this->refreshAccessToken($token); - } - } - return $token; - } - - /** - * Sets persistent state. - * @param string $key state key. - * @param mixed $value state value - * @return static self reference. - */ - protected function setState($key, $value) - { - $session = Yii::$app->getSession(); - $key = $this->getStateKeyPrefix() . $key; - $session->set($key, $value); - return $this; - } - - /** - * Returns persistent state value. - * @param string $key state key. - * @return mixed state value. - */ - protected function getState($key) - { - $session = Yii::$app->getSession(); - $key = $this->getStateKeyPrefix() . $key; - $value = $session->get($key); - return $value; - } - - /** - * Removes persistent state value. - * @param string $key state key. - * @return boolean success. - */ - protected function removeState($key) - { - $session = Yii::$app->getSession(); - $key = $this->getStateKeyPrefix() . $key; - $session->remove($key); - return true; - } - - /** - * Returns session key prefix, which is used to store internal states. - * @return string session key prefix. - */ - protected function getStateKeyPrefix() - { - return get_class($this) . '_' . sha1($this->authUrl) . '_'; - } - - /** - * Performs request to the OAuth API. - * @param string $apiSubUrl API sub URL, which will be append to [[apiBaseUrl]], or absolute API URL. - * @param string $method request method. - * @param array $params request parameters. - * @return array API response - * @throws Exception on failure. - */ - public function api($apiSubUrl, $method = 'GET', array $params = []) - { - if (preg_match('/^https?:\\/\\//is', $apiSubUrl)) { - $url = $apiSubUrl; - } else { - $url = $this->apiBaseUrl . '/' . $apiSubUrl; - } - $accessToken = $this->getAccessToken(); - if (!is_object($accessToken) || !$accessToken->getIsValid()) { - throw new Exception('Invalid access token.'); - } - return $this->apiInternal($accessToken, $url, $method, $params); - } - - /** - * Composes HTTP request CUrl options, which will be merged with the default ones. - * @param string $method request type. - * @param string $url request URL. - * @param array $params request params. - * @return array CUrl options. - * @throws Exception on failure. - */ - abstract protected function composeRequestCurlOptions($method, $url, array $params); - - /** - * Gets new auth token to replace expired one. - * @param OAuthToken $token expired auth token. - * @return OAuthToken new auth token. - */ - abstract public function refreshAccessToken(OAuthToken $token); - - /** - * Performs request to the OAuth API. - * @param OAuthToken $accessToken actual access token. - * @param string $url absolute API URL. - * @param string $method request method. - * @param array $params request parameters. - * @return array API response. - * @throws Exception on failure. - */ - abstract protected function apiInternal($accessToken, $url, $method, array $params); -} \ No newline at end of file diff --git a/extensions/yii/authclient/CHANGELOG.md b/extensions/yii/authclient/CHANGELOG.md deleted file mode 100644 index 975a6e9..0000000 --- a/extensions/yii/authclient/CHANGELOG.md +++ /dev/null @@ -1,7 +0,0 @@ -Yii Framework 2 authclient extension Change Log -=============================================== - -2.0.0 beta under development ----------------------------- - -- Initial release. \ No newline at end of file diff --git a/extensions/yii/authclient/ClientInterface.php b/extensions/yii/authclient/ClientInterface.php deleted file mode 100644 index c9ea0f6..0000000 --- a/extensions/yii/authclient/ClientInterface.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @since 2.0 - */ -interface ClientInterface -{ - /** - * @param string $id service id. - */ - public function setId($id); - - /** - * @return string service id - */ - public function getId(); - - /** - * @return string service name. - */ - public function getName(); - - /** - * @param string $name service name. - */ - public function setName($name); - - /** - * @return string service title. - */ - public function getTitle(); - - /** - * @param string $title service title. - */ - public function setTitle($title); - - /** - * @return array list of user attributes - */ - public function getUserAttributes(); - - /** - * @return array view options in format: optionName => optionValue - */ - public function getViewOptions(); -} \ No newline at end of file diff --git a/extensions/yii/authclient/Collection.php b/extensions/yii/authclient/Collection.php deleted file mode 100644 index 69b4c9a..0000000 --- a/extensions/yii/authclient/Collection.php +++ /dev/null @@ -1,107 +0,0 @@ - [ - * 'authClientCollection' => [ - * 'class' => 'yii\authclient\Collection', - * 'clients' => [ - * 'google' => [ - * 'class' => 'yii\authclient\clients\GoogleOpenId' - * ], - * 'facebook' => [ - * 'class' => 'yii\authclient\clients\Facebook', - * 'clientId' => 'facebook_client_id', - * 'clientSecret' => 'facebook_client_secret', - * ], - * ], - * ] - * ... - * ] - * ~~~ - * - * @property ClientInterface[] $clients List of auth clients. This property is read-only. - * - * @author Paul Klimov - * @since 2.0 - */ -class Collection extends Component -{ - /** - * @var array list of Auth clients with their configuration in format: 'clientId' => [...] - */ - private $_clients = []; - - /** - * @param array $clients list of auth clients - */ - public function setClients(array $clients) - { - $this->_clients = $clients; - } - - /** - * @return ClientInterface[] list of auth clients. - */ - public function getClients() - { - $clients = []; - foreach ($this->_clients as $id => $client) { - $clients[$id] = $this->getClient($id); - } - return $clients; - } - - /** - * @param string $id service id. - * @return ClientInterface auth client instance. - * @throws InvalidParamException on non existing client request. - */ - public function getClient($id) - { - if (!array_key_exists($id, $this->_clients)) { - throw new InvalidParamException("Unknown auth client '{$id}'."); - } - if (!is_object($this->_clients[$id])) { - $this->_clients[$id] = $this->createClient($id, $this->_clients[$id]); - } - return $this->_clients[$id]; - } - - /** - * Checks if client exists in the hub. - * @param string $id client id. - * @return boolean whether client exist. - */ - public function hasClient($id) - { - return array_key_exists($id, $this->_clients); - } - - /** - * Creates auth client instance from its array configuration. - * @param string $id auth client id. - * @param array $config auth client instance configuration. - * @return ClientInterface auth client instance. - */ - protected function createClient($id, $config) - { - $config['id'] = $id; - return Yii::createObject($config); - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/LICENSE.md b/extensions/yii/authclient/LICENSE.md deleted file mode 100644 index 0bb1a8d..0000000 --- a/extensions/yii/authclient/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-2013 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/yii/authclient/OAuth1.php b/extensions/yii/authclient/OAuth1.php deleted file mode 100644 index 35bb74c..0000000 --- a/extensions/yii/authclient/OAuth1.php +++ /dev/null @@ -1,354 +0,0 @@ -fetchRequestToken(); // Get request token - * $url = $oauthClient->buildAuthUrl($requestToken); // Get authorization URL - * return Yii::$app->getResponse()->redirect($url); // Redirect to authorization URL - * // After user returns at our site: - * $accessToken = $oauthClient->fetchAccessToken($requestToken); // Upgrade to access token - * ~~~ - * - * @see http://oauth.net/ - * - * @author Paul Klimov - * @since 2.0 - */ -class OAuth1 extends BaseOAuth -{ - /** - * @var string protocol version. - */ - public $version = '1.0'; - /** - * @var string OAuth consumer key. - */ - public $consumerKey; - /** - * @var string OAuth consumer secret. - */ - public $consumerSecret; - /** - * @var string OAuth request token URL. - */ - public $requestTokenUrl; - /** - * @var string request token HTTP method. - */ - public $requestTokenMethod = 'GET'; - /** - * @var string OAuth access token URL. - */ - public $accessTokenUrl; - /** - * @var string access token HTTP method. - */ - public $accessTokenMethod = 'GET'; - - /** - * Fetches the OAuth request token. - * @param array $params additional request params. - * @return OAuthToken request token. - */ - public function fetchRequestToken(array $params = []) - { - $this->removeState('token'); - $defaultParams = [ - 'oauth_consumer_key' => $this->consumerKey, - 'oauth_callback' => $this->getReturnUrl(), - //'xoauth_displayname' => Yii::$app->name, - ]; - if (!empty($this->scope)) { - $defaultParams['scope'] = $this->scope; - } - $response = $this->sendSignedRequest($this->requestTokenMethod, $this->requestTokenUrl, array_merge($defaultParams, $params)); - $token = $this->createToken([ - 'params' => $response - ]); - $this->setState('requestToken', $token); - return $token; - } - - /** - * Composes user authorization URL. - * @param OAuthToken $requestToken OAuth request token. - * @param array $params additional request params. - * @return string authorize URL - * @throws Exception on failure. - */ - public function buildAuthUrl(OAuthToken $requestToken = null, array $params = []) - { - if (!is_object($requestToken)) { - $requestToken = $this->getState('requestToken'); - if (!is_object($requestToken)) { - throw new Exception('Request token is required to build authorize URL!'); - } - } - $params['oauth_token'] = $requestToken->getToken(); - return $this->composeUrl($this->authUrl, $params); - } - - /** - * Fetches OAuth access token. - * @param OAuthToken $requestToken OAuth request token. - * @param string $oauthVerifier OAuth verifier. - * @param array $params additional request params. - * @return OAuthToken OAuth access token. - * @throws Exception on failure. - */ - public function fetchAccessToken(OAuthToken $requestToken = null, $oauthVerifier = null, array $params = []) - { - if (!is_object($requestToken)) { - $requestToken = $this->getState('requestToken'); - if (!is_object($requestToken)) { - throw new Exception('Request token is required to fetch access token!'); - } - } - $this->removeState('requestToken'); - $defaultParams = [ - 'oauth_consumer_key' => $this->consumerKey, - 'oauth_token' => $requestToken->getToken() - ]; - if ($oauthVerifier === null) { - if (isset($_REQUEST['oauth_verifier'])) { - $oauthVerifier = $_REQUEST['oauth_verifier']; - } - } - if (!empty($oauthVerifier)) { - $defaultParams['oauth_verifier'] = $oauthVerifier; - } - $response = $this->sendSignedRequest($this->accessTokenMethod, $this->accessTokenUrl, array_merge($defaultParams, $params)); - - $token = $this->createToken([ - 'params' => $response - ]); - $this->setAccessToken($token); - return $token; - } - - /** - * Sends HTTP request, signed by {@link signatureMethod}. - * @param string $method request type. - * @param string $url request URL. - * @param array $params request params. - * @return array response. - */ - protected function sendSignedRequest($method, $url, array $params = []) - { - $params = array_merge($params, $this->generateCommonRequestParams()); - $params = $this->signRequest($method, $url, $params); - return $this->sendRequest($method, $url, $params); - } - - /** - * Composes HTTP request CUrl options, which will be merged with the default ones. - * @param string $method request type. - * @param string $url request URL. - * @param array $params request params. - * @return array CUrl options. - * @throws Exception on failure. - */ - protected function composeRequestCurlOptions($method, $url, array $params) - { - $curlOptions = []; - switch ($method) { - case 'GET': { - $curlOptions[CURLOPT_URL] = $this->composeUrl($url, $params); - break; - } - case 'POST': { - $curlOptions[CURLOPT_POST] = true; - if (!empty($params)){ - $curlOptions[CURLOPT_POSTFIELDS] = $params; - } - $authorizationHeader = $this->composeAuthorizationHeader($params); - if (!empty($authorizationHeader)) { - $curlOptions[CURLOPT_HTTPHEADER] = ['Content-Type: application/atom+xml', $authorizationHeader]; - } - break; - } - case 'HEAD': - case 'PUT': - case 'DELETE': { - $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; - if (!empty($params)) { - $curlOptions[CURLOPT_URL] = $this->composeUrl($url, $params); - } - break; - } - default: { - throw new Exception("Unknown request method '{$method}'."); - } - } - return $curlOptions; - } - - /** - * Performs request to the OAuth API. - * @param OAuthToken $accessToken actual access token. - * @param string $url absolute API URL. - * @param string $method request method. - * @param array $params request parameters. - * @return array API response. - * @throws Exception on failure. - */ - protected function apiInternal($accessToken, $url, $method, array $params) - { - $params['oauth_consumer_key'] = $this->consumerKey; - $params['oauth_token'] = $accessToken->getToken(); - $response = $this->sendSignedRequest($method, $url, $params); - return $response; - } - - /** - * Gets new auth token to replace expired one. - * @param OAuthToken $token expired auth token. - * @return OAuthToken new auth token. - */ - public function refreshAccessToken(OAuthToken $token) - { - // @todo - return null; - } - - /** - * Composes default {@link returnUrl} value. - * @return string return URL. - */ - protected function defaultReturnUrl() - { - $params = $_GET; - unset($params['oauth_token']); - return Yii::$app->getUrlManager()->createAbsoluteUrl(Yii::$app->controller->getRoute(), $params); - } - - /** - * Generates nonce value. - * @return string nonce value. - */ - protected function generateNonce() - { - return md5(microtime() . mt_rand()); - } - - /** - * Generates timestamp. - * @return integer timestamp. - */ - protected function generateTimestamp() - { - return time(); - } - - /** - * Generate common request params like version, timestamp etc. - * @return array common request params. - */ - protected function generateCommonRequestParams() - { - $params = [ - 'oauth_version' => $this->version, - 'oauth_nonce' => $this->generateNonce(), - 'oauth_timestamp' => $this->generateTimestamp(), - ]; - return $params; - } - - /** - * Sign request with {@link signatureMethod}. - * @param string $method request method. - * @param string $url request URL. - * @param array $params request params. - * @return array signed request params. - */ - protected function signRequest($method, $url, array $params) - { - $signatureMethod = $this->getSignatureMethod(); - $params['oauth_signature_method'] = $signatureMethod->getName(); - $signatureBaseString = $this->composeSignatureBaseString($method, $url, $params); - $signatureKey = $this->composeSignatureKey(); - $params['oauth_signature'] = $signatureMethod->generateSignature($signatureBaseString, $signatureKey); - return $params; - } - - /** - * Creates signature base string, which will be signed by {@link signatureMethod}. - * @param string $method request method. - * @param string $url request URL. - * @param array $params request params. - * @return string base signature string. - */ - protected function composeSignatureBaseString($method, $url, array $params) - { - unset($params['oauth_signature']); - uksort($params, 'strcmp'); // Parameters are sorted by name, using lexicographical byte value ordering. Ref: Spec: 9.1.1 - $parts = [ - strtoupper($method), - $url, - http_build_query($params, '', '&', PHP_QUERY_RFC3986) - ]; - $parts = array_map('rawurlencode', $parts); - return implode('&', $parts); - } - - /** - * Composes request signature key. - * @return string signature key. - */ - protected function composeSignatureKey() - { - $signatureKeyParts = [ - $this->consumerSecret - ]; - $accessToken = $this->getAccessToken(); - if (is_object($accessToken)) { - $signatureKeyParts[] = $accessToken->getTokenSecret(); - } else { - $signatureKeyParts[] = ''; - } - $signatureKeyParts = array_map('rawurlencode', $signatureKeyParts); - return implode('&', $signatureKeyParts); - } - - /** - * Composes authorization header content. - * @param array $params request params. - * @param string $realm authorization realm. - * @return string authorization header content. - */ - protected function composeAuthorizationHeader(array $params, $realm = '') - { - $header = 'Authorization: OAuth'; - $headerParams = []; - if (!empty($realm)) { - $headerParams[] = 'realm="' . rawurlencode($realm) . '"'; - } - foreach ($params as $key => $value) { - if (substr($key, 0, 5) != 'oauth') { - continue; - } - $headerParams[] = rawurlencode($key) . '="' . rawurlencode($value) . '"'; - } - if (!empty($headerParams)) { - $header .= ' ' . implode(', ', $headerParams); - } - return $header; - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/OAuth2.php b/extensions/yii/authclient/OAuth2.php deleted file mode 100644 index 09146b8..0000000 --- a/extensions/yii/authclient/OAuth2.php +++ /dev/null @@ -1,184 +0,0 @@ -buildAuthUrl(); // Build authorization URL - * Yii::$app->getResponse()->redirect($url); // Redirect to authorization URL. - * // After user returns at our site: - * $code = $_GET['code']; - * $accessToken = $oauthClient->fetchAccessToken($code); // Get access token - * ~~~ - * - * @see http://oauth.net/2/ - * - * @author Paul Klimov - * @since 2.0 - */ -class OAuth2 extends BaseOAuth -{ - /** - * @var string protocol version. - */ - public $version = '2.0'; - /** - * @var string OAuth client ID. - */ - public $clientId; - /** - * @var string OAuth client secret. - */ - public $clientSecret; - /** - * @var string token request URL endpoint. - */ - public $tokenUrl; - - /** - * Composes user authorization URL. - * @param array $params additional auth GET params. - * @return string authorization URL. - */ - public function buildAuthUrl(array $params = []) - { - $defaultParams = [ - 'client_id' => $this->clientId, - 'response_type' => 'code', - 'redirect_uri' => $this->getReturnUrl(), - 'xoauth_displayname' => Yii::$app->name, - ]; - if (!empty($this->scope)) { - $defaultParams['scope'] = $this->scope; - } - return $this->composeUrl($this->authUrl, array_merge($defaultParams, $params)); - } - - /** - * Fetches access token from authorization code. - * @param string $authCode authorization code, usually comes at $_GET['code']. - * @param array $params additional request params. - * @return OAuthToken access token. - */ - public function fetchAccessToken($authCode, array $params = []) - { - $defaultParams = [ - 'client_id' => $this->clientId, - 'client_secret' => $this->clientSecret, - 'code' => $authCode, - 'grant_type' => 'authorization_code', - 'redirect_uri' => $this->getReturnUrl(), - ]; - $response = $this->sendRequest('POST', $this->tokenUrl, array_merge($defaultParams, $params)); - $token = $this->createToken(['params' => $response]); - $this->setAccessToken($token); - return $token; - } - - /** - * Composes HTTP request CUrl options, which will be merged with the default ones. - * @param string $method request type. - * @param string $url request URL. - * @param array $params request params. - * @return array CUrl options. - * @throws Exception on failure. - */ - protected function composeRequestCurlOptions($method, $url, array $params) - { - $curlOptions = []; - switch ($method) { - case 'GET': { - $curlOptions[CURLOPT_URL] = $this->composeUrl($url, $params); - break; - } - case 'POST': { - $curlOptions[CURLOPT_POST] = true; - $curlOptions[CURLOPT_HTTPHEADER] = ['Content-type: application/x-www-form-urlencoded']; - $curlOptions[CURLOPT_POSTFIELDS] = http_build_query($params, '', '&', PHP_QUERY_RFC3986); - break; - } - case 'HEAD': - case 'PUT': - case 'DELETE': { - $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; - if (!empty($params)) { - $curlOptions[CURLOPT_URL] = $this->composeUrl($url, $params); - } - break; - } - default: { - throw new Exception("Unknown request method '{$method}'."); - } - } - return $curlOptions; - } - - /** - * Performs request to the OAuth API. - * @param OAuthToken $accessToken actual access token. - * @param string $url absolute API URL. - * @param string $method request method. - * @param array $params request parameters. - * @return array API response. - * @throws Exception on failure. - */ - protected function apiInternal($accessToken, $url, $method, array $params) - { - $params['access_token'] = $accessToken->getToken(); - return $this->sendRequest($method, $url, $params); - } - - /** - * Gets new auth token to replace expired one. - * @param OAuthToken $token expired auth token. - * @return OAuthToken new auth token. - */ - public function refreshAccessToken(OAuthToken $token) - { - $params = [ - 'client_id' => $this->clientId, - 'client_secret' => $this->clientSecret, - 'grant_type' => 'refresh_token' - ]; - $params = array_merge($token->getParams(), $params); - $response = $this->sendRequest('POST', $this->tokenUrl, $params); - return $response; - } - - /** - * Composes default {@link returnUrl} value. - * @return string return URL. - */ - protected function defaultReturnUrl() - { - $params = $_GET; - unset($params['code']); - return Yii::$app->getUrlManager()->createAbsoluteUrl(Yii::$app->controller->getRoute(), $params); - } - - /** - * Creates token from its configuration. - * @param array $tokenConfig token configuration. - * @return OAuthToken token instance. - */ - protected function createToken(array $tokenConfig = []) - { - $tokenConfig['tokenParamKey'] = 'access_token'; - return parent::createToken($tokenConfig); - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/OAuthToken.php b/extensions/yii/authclient/OAuthToken.php deleted file mode 100644 index 88881b0..0000000 --- a/extensions/yii/authclient/OAuthToken.php +++ /dev/null @@ -1,191 +0,0 @@ - - * @since 2.0 - */ -class OAuthToken extends Object -{ - /** - * @var string key in {@link _params} array, which stores token key. - */ - public $tokenParamKey = 'oauth_token'; - /** - * @var string key in {@link _params} array, which stores token secret key. - */ - public $tokenSecretParamKey = 'oauth_token_secret'; - /** - * @var string key in {@link _params} array, which stores token expiration duration. - * If not set will attempt to fetch its value automatically. - */ - private $_expireDurationParamKey; - /** - * @var array token parameters. - */ - private $_params = []; - /** - * @var integer object creation timestamp. - */ - public $createTimestamp; - - public function init() - { - if ($this->createTimestamp === null) { - $this->createTimestamp = time(); - } - } - - /** - * @param string $expireDurationParamKey expire duration param key. - */ - public function setExpireDurationParamKey($expireDurationParamKey) { - $this->_expireDurationParamKey = $expireDurationParamKey; - } - - /** - * @return string expire duration param key. - */ - public function getExpireDurationParamKey() { - if ($this->_expireDurationParamKey === null) { - $this->_expireDurationParamKey = $this->defaultExpireDurationParamKey(); - } - return $this->_expireDurationParamKey; - } - - /** - * @return array - */ - public function getParams() { - return $this->_params; - } - - /** - * @param array $params - */ - public function setParams(array $params) { - $this->_params = $params; - } - - /** - * Sets param by name. - * @param string $name param name. - * @param mixed $value param value, - */ - public function setParam($name, $value) { - $this->_params[$name] = $value; - } - - /** - * Returns param by name. - * @param string $name param name. - * @return mixed param value. - */ - public function getParam($name) { - return isset($this->_params[$name]) ? $this->_params[$name] : null; - } - - /** - * Sets token value. - * @param string $token token value. - * @return static self reference. - */ - public function setToken($token) { - $this->setParam($this->tokenParamKey, $token); - } - - /** - * Returns token value. - * @return string token value. - */ - public function getToken() { - return $this->getParam($this->tokenParamKey); - } - - /** - * Sets the token secret value. - * @param string $tokenSecret token secret. - */ - public function setTokenSecret($tokenSecret) { - $this->setParam($this->tokenSecretParamKey, $tokenSecret); - } - - /** - * Returns the token secret value. - * @return string token secret value. - */ - public function getTokenSecret() { - return $this->getParam($this->tokenSecretParamKey); - } - - /** - * Sets token expire duration. - * @param string $expireDuration token expiration duration. - */ - public function setExpireDuration($expireDuration) { - $this->setParam($this->getExpireDurationParamKey(), $expireDuration); - } - - /** - * Returns the token expiration duration. - * @return integer token expiration duration. - */ - public function getExpireDuration() { - return $this->getParam($this->getExpireDurationParamKey()); - } - - /** - * Fetches default expire duration param key. - * @return string expire duration param key. - */ - protected function defaultExpireDurationParamKey() { - $expireDurationParamKey = 'expires_in'; - foreach ($this->getParams() as $name => $value) { - if (strpos($name, 'expir') !== false) { - $expireDurationParamKey = $name; - break; - } - } - return $expireDurationParamKey; - } - - /** - * Checks if token has expired. - * @return boolean is token expired. - */ - public function getIsExpired() { - $expirationDuration = $this->getExpireDuration(); - if (empty($expirationDuration)) { - return false; - } - return (time() >= ($this->createTimestamp + $expirationDuration)); - } - - /** - * Checks if token is valid. - * @return boolean is token valid. - */ - public function getIsValid() { - $token = $this->getToken(); - return (!empty($token) && !$this->getIsExpired()); - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/OpenId.php b/extensions/yii/authclient/OpenId.php deleted file mode 100644 index e410d4c..0000000 --- a/extensions/yii/authclient/OpenId.php +++ /dev/null @@ -1,928 +0,0 @@ -authUrl = 'https://open.id.provider.url'; // Setup provider endpoint - * $url = $client->buildAuthUrl(); // Get authentication URL - * return Yii::$app->getResponse()->redirect($url); // Redirect to authentication URL - * // After user returns at our site: - * if ($client->validate()) { // validate response - * $userAttributes = $client->getUserAttributes(); // get account info - * ... - * } - * ~~~ - * - * AX and SREG extensions are supported. - * To use them, specify [[requiredAttributes]] and/or [[optionalAttributes]]. - * - * @see http://openid.net/ - * - * @property string $claimedId Claimed identifier (identity). - * @property string $returnUrl Authentication return URL. - * @property string $trustRoot Client trust root (realm). - * - * @author Paul Klimov - * @since 2.0 - */ -class OpenId extends BaseClient implements ClientInterface -{ - /** - * @var string authentication base URL, which should be used to compose actual authentication URL - * by [[buildAuthUrl()]] method. - */ - public $authUrl; - /** - * @var array list of attributes, which always should be returned from server. - * Attribute names should be always specified in AX format. - * For example: - * ~~~ - * ['namePerson/friendly', 'contact/email'] - * ~~~ - */ - public $requiredAttributes = []; - /** - * @var array list of attributes, which could be returned from server. - * Attribute names should be always specified in AX format. - * For example: - * ~~~ - * ['namePerson/first', 'namePerson/last'] - * ~~~ - */ - public $optionalAttributes = []; - - /** - * @var boolean whether to verify the peer's certificate. - */ - public $verifyPeer; - /** - * @var string directory that holds multiple CA certificates. - * This value will take effect only if [[verifyPeer]] is set. - */ - public $capath; - /** - * @var string the name of a file holding one or more certificates to verify the peer with. - * This value will take effect only if [[verifyPeer]] is set. - */ - public $cainfo; - - /** - * @var string authentication return URL. - */ - private $_returnUrl; - /** - * @var string claimed identifier (identity) - */ - private $_claimedId; - /** - * @var string client trust root (realm), by default [[\yii\web\Request::hostInfo]] value will be used. - */ - private $_trustRoot; - /** - * @var array data, which should be used to retrieve the OpenID response. - * If not set combination of GET and POST will be used. - */ - public $data; - /** - * @var array map of matches between AX and SREG attribute names in format: axAttributeName => sregAttributeName - */ - public $axToSregMap = [ - 'namePerson/friendly' => 'nickname', - 'contact/email' => 'email', - 'namePerson' => 'fullname', - 'birthDate' => 'dob', - 'person/gender' => 'gender', - 'contact/postalCode/home' => 'postcode', - 'contact/country/home' => 'country', - 'pref/language' => 'language', - 'pref/timezone' => 'timezone', - ]; - - /** - * @inheritdoc - */ - public function init() - { - if ($this->data === null) { - $this->data = array_merge($_GET, $_POST); // OPs may send data as POST or GET. - } - } - - /** - * @param string $claimedId claimed identifier (identity). - */ - public function setClaimedId($claimedId) - { - $this->_claimedId = $claimedId; - } - - /** - * @return string claimed identifier (identity). - */ - public function getClaimedId() - { - if ($this->_claimedId === null) { - if (isset($this->data['openid_claimed_id'])) { - $this->_claimedId = $this->data['openid_claimed_id']; - } elseif (isset($this->data['openid_identity'])) { - $this->_claimedId = $this->data['openid_identity']; - } - } - return $this->_claimedId; - } - - /** - * @param string $returnUrl authentication return URL. - */ - public function setReturnUrl($returnUrl) - { - $this->_returnUrl = $returnUrl; - } - - /** - * @return string authentication return URL. - */ - public function getReturnUrl() - { - if ($this->_returnUrl === null) { - $this->_returnUrl = $this->defaultReturnUrl(); - } - return $this->_returnUrl; - } - - /** - * @param string $value client trust root (realm). - */ - public function setTrustRoot($value) - { - $this->_trustRoot = $value; - } - - /** - * @return string client trust root (realm). - */ - public function getTrustRoot() - { - if ($this->_trustRoot === null) { - $this->_trustRoot = Yii::$app->getRequest()->getHostInfo(); - } - return $this->_trustRoot; - } - - /** - * Generates default [[returnUrl]] value. - * @return string default authentication return URL. - */ - protected function defaultReturnUrl() - { - $params = $_GET; - foreach ($params as $name => $value) { - if (strncmp('openid', $name, 6) === 0) { - unset($params[$name]); - } - } - $url = Yii::$app->getUrlManager()->createUrl(Yii::$app->requestedRoute, $params); - return $this->getTrustRoot() . $url; - } - - /** - * Checks if the server specified in the url exists. - * @param string $url URL to check - * @return boolean true, if the server exists; false otherwise - */ - public function hostExists($url) - { - if (strpos($url, '/') === false) { - $server = $url; - } else { - $server = @parse_url($url, PHP_URL_HOST); - } - if (!$server) { - return false; - } - $ips = gethostbynamel($server); - return !empty($ips); - } - - /** - * Sends HTTP request. - * @param string $url request URL. - * @param string $method request method. - * @param array $params request params. - * @return array|string response. - * @throws \yii\base\Exception on failure. - */ - protected function sendCurlRequest($url, $method = 'GET', $params = []) - { - $params = http_build_query($params, '', '&'); - $curl = curl_init($url . ($method == 'GET' && $params ? '?' . $params : '')); - curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); - curl_setopt($curl, CURLOPT_HEADER, false); - curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/xrds+xml, */*')); - - if ($this->verifyPeer !== null) { - curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifyPeer); - if($this->capath) { - curl_setopt($curl, CURLOPT_CAPATH, $this->capath); - } - if($this->cainfo) { - curl_setopt($curl, CURLOPT_CAINFO, $this->cainfo); - } - } - - if ($method == 'POST') { - curl_setopt($curl, CURLOPT_POST, true); - curl_setopt($curl, CURLOPT_POSTFIELDS, $params); - } elseif ($method == 'HEAD') { - curl_setopt($curl, CURLOPT_HEADER, true); - curl_setopt($curl, CURLOPT_NOBODY, true); - } else { - curl_setopt($curl, CURLOPT_HTTPGET, true); - } - $response = curl_exec($curl); - - if ($method == 'HEAD') { - $headers = []; - foreach (explode("\n", $response) as $header) { - $pos = strpos($header, ':'); - $name = strtolower(trim(substr($header, 0, $pos))); - $headers[$name] = trim(substr($header, $pos+1)); - } - return $headers; - } - - if (curl_errno($curl)) { - throw new Exception(curl_error($curl), curl_errno($curl)); - } - - return $response; - } - - /** - * Sends HTTP request. - * @param string $url request URL. - * @param string $method request method. - * @param array $params request params. - * @return array|string response. - * @throws \yii\base\Exception on failure. - * @throws \yii\base\NotSupportedException if request method is not supported. - */ - protected function sendStreamRequest($url, $method = 'GET', $params = []) - { - if (!$this->hostExists($url)) { - throw new Exception('Invalid request.'); - } - - $params = http_build_query($params, '', '&'); - switch ($method) { - case 'GET': - $options = [ - 'http' => [ - 'method' => 'GET', - 'header' => 'Accept: application/xrds+xml, */*', - 'ignore_errors' => true, - ] - ]; - $url = $url . ($params ? '?' . $params : ''); - break; - case 'POST': - $options = [ - 'http' => [ - 'method' => 'POST', - 'header' => 'Content-type: application/x-www-form-urlencoded', - 'content' => $params, - 'ignore_errors' => true, - ] - ]; - break; - case 'HEAD': - /* We want to send a HEAD request, - but since get_headers doesn't accept $context parameter, - we have to change the defaults.*/ - $default = stream_context_get_options(stream_context_get_default()); - stream_context_get_default([ - 'http' => [ - 'method' => 'HEAD', - 'header' => 'Accept: application/xrds+xml, */*', - 'ignore_errors' => true, - ] - ]); - - $url = $url . ($params ? '?' . $params : ''); - $headersTmp = get_headers($url); - if (empty($headersTmp)) { - return []; - } - - // Parsing headers. - $headers = []; - foreach ($headersTmp as $header) { - $pos = strpos($header, ':'); - $name = strtolower(trim(substr($header, 0, $pos))); - $headers[$name] = trim(substr($header, $pos + 1)); - } - - // and restore them - stream_context_get_default($default); - return $headers; - default: - throw new NotSupportedException("Method {$method} not supported"); - } - - if ($this->verifyPeer) { - $options = array_merge( - $options, - [ - 'ssl' => [ - 'verify_peer' => true, - 'capath' => $this->capath, - 'cafile' => $this->cainfo, - ] - ] - ); - } - - $context = stream_context_create($options); - return file_get_contents($url, false, $context); - } - - /** - * Sends request to the server - * @param string $url request URL. - * @param string $method request method. - * @param array $params request parameters. - * @return array|string response. - */ - protected function sendRequest($url, $method = 'GET', $params = []) - { - if (function_exists('curl_init') && !ini_get('safe_mode')) { - return $this->sendCurlRequest($url, $method, $params); - } - return $this->sendStreamRequest($url, $method, $params); - } - - /** - * Combines given URLs into single one. - * @param string $baseUrl base URL. - * @param string|array $additionalUrl additional URL string or information array. - * @return string composed URL. - */ - protected function buildUrl($baseUrl, $additionalUrl) - { - $baseUrl = parse_url($baseUrl); - if (!is_array($additionalUrl)) { - $additionalUrl = parse_url($additionalUrl); - } - - if (isset($baseUrl['query'], $additionalUrl['query'])) { - $additionalUrl['query'] = $baseUrl['query'] . '&' . $additionalUrl['query']; - } - - $urlInfo = array_merge($baseUrl, $additionalUrl); - $url = $urlInfo['scheme'] . '://' - . (empty($urlInfo['username']) ? '' - :(empty($urlInfo['password']) ? "{$urlInfo['username']}@" - :"{$urlInfo['username']}:{$urlInfo['password']}@")) - . $urlInfo['host'] - . (empty($urlInfo['port']) ? '' : ":{$urlInfo['port']}") - . (empty($urlInfo['path']) ? '' : $urlInfo['path']) - . (empty($urlInfo['query']) ? '' : "?{$urlInfo['query']}") - . (empty($urlInfo['fragment']) ? '' : "#{$urlInfo['fragment']}"); - return $url; - } - - /** - * Scans content for / tags and extract information from them. - * @param string $content HTML content to be be parsed. - * @param string $tag name of the source tag. - * @param string $matchAttributeName name of the source tag attribute, which should contain $matchAttributeValue - * @param string $matchAttributeValue required value of $matchAttributeName - * @param string $valueAttributeName name of the source tag attribute, which should contain searched value. - * @return string|boolean searched value, "false" on failure. - */ - protected function extractHtmlTagValue($content, $tag, $matchAttributeName, $matchAttributeValue, $valueAttributeName) - { - preg_match_all("#<{$tag}[^>]*$matchAttributeName=['\"].*?$matchAttributeValue.*?['\"][^>]*$valueAttributeName=['\"](.+?)['\"][^>]*/?>#i", $content, $matches1); - preg_match_all("#<{$tag}[^>]*$valueAttributeName=['\"](.+?)['\"][^>]*$matchAttributeName=['\"].*?$matchAttributeValue.*?['\"][^>]*/?>#i", $content, $matches2); - $result = array_merge($matches1[1], $matches2[1]); - return empty($result) ? false : $result[0]; - } - - /** - * Performs Yadis and HTML discovery. - * @param string $url Identity URL. - * @return array OpenID provider info, following keys will be available: - * - 'url' - string OP Endpoint (i.e. OpenID provider address). - * - 'version' - integer OpenID protocol version used by provider. - * - 'identity' - string identity value. - * - 'identifier_select' - boolean whether to request OP to select identity for an user in OpenID 2, does not affect OpenID 1. - * - 'ax' - boolean whether AX attributes should be used. - * - 'sreg' - boolean whether SREG attributes should be used. - * @throws Exception on failure. - */ - public function discover($url) - { - if (empty($url)) { - throw new Exception('No identity supplied.'); - } - $result = [ - 'url' => null, - 'version' => null, - 'identity' => $url, - 'identifier_select' => false, - 'ax' => false, - 'sreg' => false, - ]; - - // Use xri.net proxy to resolve i-name identities - if (!preg_match('#^https?:#', $url)) { - $url = 'https://xri.net/' . $url; - } - - /* We save the original url in case of Yadis discovery failure. - It can happen when we'll be lead to an XRDS document - which does not have any OpenID2 services.*/ - $originalUrl = $url; - - // A flag to disable yadis discovery in case of failure in headers. - $yadis = true; - - // We'll jump a maximum of 5 times, to avoid endless redirections. - for ($i = 0; $i < 5; $i ++) { - if ($yadis) { - $headers = $this->sendRequest($url, 'HEAD'); - - $next = false; - if (isset($headers['x-xrds-location'])) { - $url = $this->buildUrl($url, trim($headers['x-xrds-location'])); - $next = true; - } - - if (isset($headers['content-type']) - && (strpos($headers['content-type'], 'application/xrds+xml') !== false - || strpos($headers['content-type'], 'text/xml') !== false) - ) { - /* Apparently, some providers return XRDS documents as text/html. - While it is against the spec, allowing this here shouldn't break - compatibility with anything. - --- - Found an XRDS document, now let's find the server, and optionally delegate.*/ - $content = $this->sendRequest($url, 'GET'); - - preg_match_all('#(.*?)#s', $content, $m); - foreach ($m[1] as $content) { - $content = ' ' . $content; // The space is added, so that strpos doesn't return 0. - - // OpenID 2 - $ns = preg_quote('http://specs.openid.net/auth/2.0/'); - if (preg_match('#\s*'.$ns.'(server|signon)\s*#s', $content, $type)) { - if ($type[1] == 'server') { - $result['identifier_select'] = true; - } - - preg_match('#(.*)#', $content, $server); - preg_match('#<(Local|Canonical)ID>(.*)#', $content, $delegate); - if (empty($server)) { - throw new Exception('No servers found!'); - } - // Does the server advertise support for either AX or SREG? - $result['ax'] = (bool) strpos($content, 'http://openid.net/srv/ax/1.0'); - $result['sreg'] = strpos($content, 'http://openid.net/sreg/1.0') || strpos($content, 'http://openid.net/extensions/sreg/1.1'); - - $server = $server[1]; - if (isset($delegate[2])) { - $result['identity'] = trim($delegate[2]); - } - - $result['url'] = $server; - $result['version'] = 2; - return $result; - } - - // OpenID 1.1 - $ns = preg_quote('http://openid.net/signon/1.1'); - if (preg_match('#\s*'.$ns.'\s*#s', $content)) { - preg_match('#(.*)#', $content, $server); - preg_match('#<.*?Delegate>(.*)#', $content, $delegate); - if (empty($server)) { - throw new Exception('No servers found!'); - } - // AX can be used only with OpenID 2.0, so checking only SREG - $result['sreg'] = strpos($content, 'http://openid.net/sreg/1.0') || strpos($content, 'http://openid.net/extensions/sreg/1.1'); - - $server = $server[1]; - if (isset($delegate[1])) { - $result['identity'] = $delegate[1]; - } - - $result['url'] = $server; - $result['version'] = 1; - return $result; - } - } - - $next = true; - $yadis = false; - $url = $originalUrl; - $content = null; - break; - } - if ($next) { - continue; - } - - // There are no relevant information in headers, so we search the body. - $content = $this->sendRequest($url, 'GET'); - $location = $this->extractHtmlTagValue($content, 'meta', 'http-equiv', 'X-XRDS-Location', 'content'); - if ($location) { - $url = $this->buildUrl($url, $location); - continue; - } - } - - if (!isset($content)) { - $content = $this->sendRequest($url, 'GET'); - } - - // At this point, the YADIS Discovery has failed, so we'll switch to openid2 HTML discovery, then fallback to openid 1.1 discovery. - $server = $this->extractHtmlTagValue($content, 'link', 'rel', 'openid2.provider', 'href'); - if (!$server) { - // The same with openid 1.1 - $server = $this->extractHtmlTagValue($content, 'link', 'rel', 'openid.server', 'href'); - $delegate = $this->extractHtmlTagValue($content, 'link', 'rel', 'openid.delegate', 'href'); - $version = 1; - } else { - $delegate = $this->extractHtmlTagValue($content, 'link', 'rel', 'openid2.local_id', 'href'); - $version = 2; - } - - if ($server) { - // We found an OpenID2 OP Endpoint - if ($delegate) { - // We have also found an OP-Local ID. - $result['identity'] = $delegate; - } - $result['url'] = $server; - $result['version'] = $version; - return $result; - } - throw new Exception('No servers found!'); - } - throw new Exception('Endless redirection!'); - } - - /** - * Composes SREG request parameters. - * @return array SREG parameters. - */ - protected function buildSregParams() - { - $params = []; - /* We always use SREG 1.1, even if the server is advertising only support for 1.0. - That's because it's fully backwards compatible with 1.0, and some providers - advertise 1.0 even if they accept only 1.1. One such provider is myopenid.com */ - $params['openid.ns.sreg'] = 'http://openid.net/extensions/sreg/1.1'; - if (!empty($this->requiredAttributes)) { - $params['openid.sreg.required'] = []; - foreach ($this->requiredAttributes as $required) { - if (!isset($this->axToSregMap[$required])) { - continue; - } - $params['openid.sreg.required'][] = $this->axToSregMap[$required]; - } - $params['openid.sreg.required'] = implode(',', $params['openid.sreg.required']); - } - - if (!empty($this->optionalAttributes)) { - $params['openid.sreg.optional'] = []; - foreach ($this->optionalAttributes as $optional) { - if (!isset($this->axToSregMap[$optional])) { - continue; - } - $params['openid.sreg.optional'][] = $this->axToSregMap[$optional]; - } - $params['openid.sreg.optional'] = implode(',', $params['openid.sreg.optional']); - } - return $params; - } - - /** - * Composes AX request parameters. - * @return array AX parameters. - */ - protected function buildAxParams() - { - $params = []; - if (!empty($this->requiredAttributes) || !empty($this->optionalAttributes)) { - $params['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0'; - $params['openid.ax.mode'] = 'fetch_request'; - $aliases = []; - $counts = []; - $requiredAttributes = []; - $optionalAttributes = []; - foreach (['requiredAttributes', 'optionalAttributes'] as $type) { - foreach ($this->$type as $alias => $field) { - if (is_int($alias)) { - $alias = strtr($field, '/', '_'); - } - $aliases[$alias] = 'http://axschema.org/' . $field; - if (empty($counts[$alias])) { - $counts[$alias] = 0; - } - $counts[$alias] += 1; - ${$type}[] = $alias; - } - } - foreach ($aliases as $alias => $ns) { - $params['openid.ax.type.' . $alias] = $ns; - } - foreach ($counts as $alias => $count) { - if ($count == 1) { - continue; - } - $params['openid.ax.count.' . $alias] = $count; - } - - // Don't send empty ax.required and ax.if_available. - // Google and possibly other providers refuse to support ax when one of these is empty. - if (!empty($requiredAttributes)) { - $params['openid.ax.required'] = implode(',', $requiredAttributes); - } - if (!empty($optionalAttributes)) { - $params['openid.ax.if_available'] = implode(',', $optionalAttributes); - } - } - return $params; - } - - /** - * Builds authentication URL for the protocol version 1. - * @param array $serverInfo OpenID server info. - * @return string authentication URL. - */ - protected function buildAuthUrlV1($serverInfo) - { - $returnUrl = $this->getReturnUrl(); - /* If we have an openid.delegate that is different from our claimed id, - we need to somehow preserve the claimed id between requests. - The simplest way is to just send it along with the return_to url.*/ - if ($serverInfo['identity'] != $this->getClaimedId()) { - $returnUrl .= (strpos($returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $this->getClaimedId(); - } - - $params = array_merge( - [ - 'openid.return_to' => $returnUrl, - 'openid.mode' => 'checkid_setup', - 'openid.identity' => $serverInfo['identity'], - 'openid.trust_root' => $this->trustRoot, - ], - $this->buildSregParams() - ); - - return $this->buildUrl($serverInfo['url'], ['query' => http_build_query($params, '', '&')]); - } - - /** - * Builds authentication URL for the protocol version 2. - * @param array $serverInfo OpenID server info. - * @return string authentication URL. - */ - protected function buildAuthUrlV2($serverInfo) - { - $params = [ - 'openid.ns' => 'http://specs.openid.net/auth/2.0', - 'openid.mode' => 'checkid_setup', - 'openid.return_to' => $this->getReturnUrl(), - 'openid.realm' => $this->getTrustRoot(), - ]; - if ($serverInfo['ax']) { - $params = array_merge($params, $this->buildAxParams()); - } - if ($serverInfo['sreg']) { - $params = array_merge($params, $this->buildSregParams()); - } - if (!$serverInfo['ax'] && !$serverInfo['sreg']) { - // If OP doesn't advertise either SREG, nor AX, let's send them both in worst case we don't get anything in return. - $params = array_merge($this->buildSregParams(), $this->buildAxParams(), $params); - } - - if ($serverInfo['identifier_select']) { - $url = 'http://specs.openid.net/auth/2.0/identifier_select'; - $params['openid.identity'] = $url; - $params['openid.claimed_id']= $url; - } else { - $params['openid.identity'] = $serverInfo['identity']; - $params['openid.claimed_id'] = $this->getClaimedId(); - } - return $this->buildUrl($serverInfo['url'], ['query' => http_build_query($params, '', '&')]); - } - - /** - * Returns authentication URL. Usually, you want to redirect your user to it. - * @param boolean $identifierSelect whether to request OP to select identity for an user in OpenID 2, does not affect OpenID 1. - * @return string the authentication URL. - * @throws Exception on failure. - */ - public function buildAuthUrl($identifierSelect = null) - { - $authUrl = $this->authUrl; - $claimedId = $this->getClaimedId(); - if (empty($claimedId)) { - $this->setClaimedId($authUrl); - } - $serverInfo = $this->discover($authUrl); - if ($serverInfo['version'] == 2) { - if ($identifierSelect !== null) { - $serverInfo['identifier_select'] = $identifierSelect; - } - return $this->buildAuthUrlV2($serverInfo); - } - return $this->buildAuthUrlV1($serverInfo); - } - - /** - * Performs OpenID verification with the OP. - * @param boolean $validateRequiredAttributes whether to validate required attributes. - * @return boolean whether the verification was successful. - */ - public function validate($validateRequiredAttributes = true) - { - $claimedId = $this->getClaimedId(); - if (empty($claimedId)) { - return false; - } - $params = [ - 'openid.assoc_handle' => $this->data['openid_assoc_handle'], - 'openid.signed' => $this->data['openid_signed'], - 'openid.sig' => $this->data['openid_sig'], - ]; - - if (isset($this->data['openid_ns'])) { - /* We're dealing with an OpenID 2.0 server, so let's set an ns - Even though we should know location of the endpoint, - we still need to verify it by discovery, so $server is not set here*/ - $params['openid.ns'] = 'http://specs.openid.net/auth/2.0'; - } elseif (isset($this->data['openid_claimed_id']) && $this->data['openid_claimed_id'] != $this->data['openid_identity']) { - // If it's an OpenID 1 provider, and we've got claimed_id, - // we have to append it to the returnUrl, like authUrlV1 does. - $this->returnUrl .= (strpos($this->returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $claimedId; - } - - if ($this->data['openid_return_to'] != $this->returnUrl) { - // The return_to url must match the url of current request. - return false; - } - - $serverInfo = $this->discover($claimedId); - - foreach (explode(',', $this->data['openid_signed']) as $item) { - $value = $this->data['openid_' . str_replace('.', '_', $item)]; - $params['openid.' . $item] = $value; - } - - $params['openid.mode'] = 'check_authentication'; - - $response = $this->sendRequest($serverInfo['url'], 'POST', $params); - - if (preg_match('/is_valid\s*:\s*true/i', $response)) { - if ($validateRequiredAttributes) { - return $this->validateRequiredAttributes(); - } else { - return true; - } - } else { - return false; - } - } - - /** - * Checks if all required attributes are present in the server response. - * @return boolean whether all required attributes are present. - */ - protected function validateRequiredAttributes() - { - if (!empty($this->requiredAttributes)) { - $attributes = $this->fetchAttributes(); - foreach ($this->requiredAttributes as $openIdAttributeName) { - if (!isset($attributes[$openIdAttributeName])) { - return false; - } - } - } - return true; - } - - /** - * Gets AX attributes provided by OP. - * @return array array of attributes. - */ - protected function fetchAxAttributes() - { - $alias = null; - if (isset($this->data['openid_ns_ax']) && $this->data['openid_ns_ax'] != 'http://openid.net/srv/ax/1.0') { - // It's the most likely case, so we'll check it before - $alias = 'ax'; - } else { - // 'ax' prefix is either undefined, or points to another extension, so we search for another prefix - foreach ($this->data as $key => $value) { - if (substr($key, 0, strlen('openid_ns_')) == 'openid_ns_' && $value == 'http://openid.net/srv/ax/1.0') { - $alias = substr($key, strlen('openid_ns_')); - break; - } - } - } - if (!$alias) { - // An alias for AX schema has not been found, so there is no AX data in the OP's response - return []; - } - - $attributes = []; - foreach ($this->data as $key => $value) { - $keyMatch = 'openid_' . $alias . '_value_'; - if (substr($key, 0, strlen($keyMatch)) != $keyMatch) { - continue; - } - $key = substr($key, strlen($keyMatch)); - if (!isset($this->data['openid_' . $alias . '_type_' . $key])) { - /* OP is breaking the spec by returning a field without - associated ns. This shouldn't happen, but it's better - to check, than cause an E_NOTICE.*/ - continue; - } - $key = substr($this->data['openid_' . $alias . '_type_' . $key], strlen('http://axschema.org/')); - $attributes[$key] = $value; - } - return $attributes; - } - - /** - * Gets SREG attributes provided by OP. SREG names will be mapped to AX names. - * @return array array of attributes with keys being the AX schema names, e.g. 'contact/email' - */ - protected function fetchSregAttributes() - { - $attributes = []; - $sregToAx = array_flip($this->axToSregMap); - foreach ($this->data as $key => $value) { - $keyMatch = 'openid_sreg_'; - if (substr($key, 0, strlen($keyMatch)) != $keyMatch) { - continue; - } - $key = substr($key, strlen($keyMatch)); - if (!isset($sregToAx[$key])) { - // The field name isn't part of the SREG spec, so we ignore it. - continue; - } - $attributes[$sregToAx[$key]] = $value; - } - return $attributes; - } - - /** - * Gets AX/SREG attributes provided by OP. Should be used only after successful validation. - * Note that it does not guarantee that any of the required/optional parameters will be present, - * or that there will be no other attributes besides those specified. - * In other words. OP may provide whatever information it wants to. - * SREG names will be mapped to AX names. - * @return array array of attributes with keys being the AX schema names, e.g. 'contact/email' - * @see http://www.axschema.org/types/ - */ - public function fetchAttributes() - { - if (isset($this->data['openid_ns']) && $this->data['openid_ns'] == 'http://specs.openid.net/auth/2.0') { - // OpenID 2.0 - // We search for both AX and SREG attributes, with AX taking precedence. - return array_merge($this->fetchSregAttributes(), $this->fetchAxAttributes()); - } - return $this->fetchSregAttributes(); - } - - /** - * @inheritdoc - */ - protected function initUserAttributes() - { - return array_merge(['id' => $this->getClaimedId()], $this->fetchAttributes()); - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/README.md b/extensions/yii/authclient/README.md deleted file mode 100644 index 3484028..0000000 --- a/extensions/yii/authclient/README.md +++ /dev/null @@ -1,298 +0,0 @@ -AuthClient Extension for Yii 2 -============================== - -This extension adds [OpenID](http://openid.net/), [OAuth](http://oauth.net/) and [OAuth2](http://oauth.net/2/) consumers for the Yii 2 framework. - - -Installation ------------- - -The preferred way to install this extension is through [composer](http://getcomposer.org/download/). - -Either run - -``` -php composer.phar require --prefer-dist yiisoft/yii2-authclient "*" -``` - -or add - -```json -"yiisoft/yii2-authclient": "*" -``` - -to the `require` section of your composer.json. - - -Quick start ------------ - -This extension provides the ability of the authentication via external credentials providers. -It covers OpenID, OAuth1 and OAuth2 protocols. - -You need to setup auth client collection application component: - -``` -'components' => [ - 'authClientCollection' => [ - 'class' => 'yii\authclient\Collection', - 'clients' => [ - 'google' => [ - 'class' => 'yii\authclient\clients\GoogleOpenId' - ], - 'facebook' => [ - 'class' => 'yii\authclient\clients\Facebook', - 'clientId' => 'facebook_client_id', - 'clientSecret' => 'facebook_client_secret', - ], - ], - ] - ... -] -``` - -Then you need to add [[yii\authclient\AuthAction]] to some of your web controllers: - -``` -class SiteController extends Controller -{ - public function actions() - { - return [ - 'auth' => [ - 'class' => 'yii\authclient\AuthAction', - 'successCallback' => [$this, 'successCallback'], - ], - ] - } - - public function successCallback($client) - { - $attributes = $client->getUserAttributes(); - // user login or signup comes here - } -} -``` - -You may use [[yii\authclient\widgets\Choice]] to compose auth client selection: - -``` - ['site/auth'] -]) ?> -``` - - -Base auth clients overview --------------------------- - -This extension provides the base client class for each supported auth protocols: - - [[yii\authclient\OpenId]] supports [OpenID](http://openid.net/) - - [[yii\authclient\OAuth1]] supports [OAuth 1/1.0a](http://oauth.net/) - - [[yii\authclient\OAuth2]] supports [OAuth 2](http://oauth.net/2/) - -You may use these classes as they are to use external auth provider, or extend them -in order to create some particular provider oriented client. - -Please, refer to the particular base client class documentation for its actual usage. - -Although, all clients are different they shares same basic interface [[yii\authclient\ClientInterface]], -which governs some common API. - -Each client has some descriptive data, which can be used for different purposes: - - id - unique client id, which separates it from other clients, it could be used in URLs, logs etc. - - name - external auth provider name, which this client is match too. Different auth clients - can share the same name, if they refer to the same external auth provider. - For example: clients for Google OpenID and Google OAuth have same name "google". - This attribute can be used inside the database, CSS styles and so on. - - title - user friendly name for the external auth provider, it is used to present auth client - at the view layer. - -Each auth client has different auth flow, but all of them supports "getUserAttributes()" method, -which can be invoked if authentication was successful. -This method allows you to get information about external user account, such as id, email address, -full name, preferred language etc. -Defining list of attributes, which external auth provider should return, depends on client type: - - [[yii\authclient\OpenId]]: combination of "requiredAttributes" and "optionalAttributes" - - [[yii\authclient\OAuth1]] and [[yii\authclient\OAuth2]]: field "scope", note that different - providers use different formats for the scope. - -Each auth client has "viewOptions" attribute. It is an array, which stores name-value pairs, -which serve to compose client representation in the view. -For example widget [[yii\authclient\widgets\Choice]] uses keys "popupWidth" and "popupHeight" to -determine the size of authentication popup window. - - -External API usage ------------------- - -Both [[yii\authclient\OAuth1]] and [[yii\authclient\OAuth2]] provide method "api()", which -can be used to access external auth provider REST API. However this method is very basic and -it may be not enough to access full external API functionality. This method is mainly used to -fetch the external user account data. -To use API calls, you need to setup [[yii\authclient\BaseOAuth::apiBaseUrl]] according to the -API specification. Then you can call [[yii\authclient\BaseOAuth::api()]] method: -``` -use yii\authclient\OAuth2; - -$client = new OAuth2; -... -$client->apiBaseUrl = 'https://www.googleapis.com/oauth2/v1'; -$userInfo = $client->api('userinfo', 'GET'); -``` - - -Predefined auth clients ------------------------ - -This extension provides the list of ready to use auth clients, which covers most -popular external authentication providers. These clients are located under "yii\authclient\clients" -namespace. - -Following predefined auth clients are available: - - [[yii\authclient\clients\Facebook]] - [Facebook](https://www.facebook.com/) OAuth2 client - - [[yii\authclient\clients\GitHub]] - [GitHub](https://github.com/) OAuth2 client - - [[yii\authclient\clients\GoogleOAuth]] - [Google](https://www.google.com/) OAuth2 client - - [[yii\authclient\clients\GoogleOpenId]] - [Google](https://www.google.com/) OpenID client - - [[yii\authclient\clients\LinkedIn]] - [LinkedIn](http://www.linkedin.com/) OAuth2 client - - [[yii\authclient\clients\LinkedIn]] - [LinkedIn](http://www.linkedin.com/) OAuth2 client - - [[yii\authclient\clients\Twitter]] - [Twitter](https://twitter.com/) OAuth1 client - - [[yii\authclient\clients\YandexOAuth]] - [Yandex](http://www.yandex.ru/) OAuth2 client - - [[yii\authclient\clients\YandexOpenId]] - [Yandex](http://www.yandex.ru/) OpenID client - -Please, refer to the particular client class documentation for its actual usage. - - -Creating your own auth clients ------------------------------- - -You may create your own auth client for any external auth provider, which supports -OpenId or OAuth protocol. To do so, first of all, you need to find out which protocol is -supported by the external auth provider, this will give you the name of the base class -for your extension: - - for OAuth 2 use [[yii\authclient\OAuth2]] - - for OAuth 1/1.0a use [[yii\authclient\OAuth1]] - - for OpenID use [[yii\authclient\OpenId]] - -At this stage you can determine auth client default name, title and view options, declaring -corresponding methods: - -``` -use yii\authclient\OAuth2; - -class MyAuthClient extends OAuth2 -{ - protected function defaultName() - { - return 'my_auth_client'; - } - - protected function defaultTitle() - { - return 'My Auth Client'; - } - - protected function defaultViewOptions() - { - return [ - 'popupWidth' => 800, - 'popupHeight' => 500, - ]; - } -} -``` - -Depending on actual base class, you will need to redeclare different fields and methods. - -1) [[yii\authclient\OpenId]] - -All you need is specify auth URL, by redeclaring "authUrl" field. -You may also setup default required and/or optional attributes. -For example: - -``` -use yii\authclient\OpenId; - -class MyAuthClient extends OpenId -{ - public $authUrl = 'https://www.my.com/openid/'; - - public $requiredAttributes = [ - 'contact/email', - ]; - - public $optionalAttributes = [ - 'namePerson/first', - 'namePerson/last', - ]; -} -``` - -2) [[yii\authclient\OAuth2]] - -You will need to specify: -- authorize URL - redeclare "authUrl" field -- token request URL - redeclare "tokenUrl" field -- API base URL - redeclare "apiBaseUrl" field -- User attribute fetching strategy - redeclare "initUserAttributes" method - -For example: - -``` -use yii\authclient\OAuth2; - -class MyAuthClient extends OAuth2 -{ - public $authUrl = 'https://www.my.com/oauth2/auth'; - - public $tokenUrl = 'https://www.my.com/oauth2/token'; - - public $apiBaseUrl = 'https://www.my.com/apis/oauth2/v1'; - - protected function initUserAttributes() - { - return $this->api('userinfo', 'GET'); - } -} -``` - -You may also specify default auth scopes. - -Note: some OAuth providers may not follow OAuth standards clearly, introducing -some differences, which may require additional efforts to apply. - -3) [[yii\authclient\OAuth1]] - -You will need to specify: -- authorize URL - redeclare "authUrl" field -- request token URL - redeclare "requestTokenUrl" field -- access token URL - redeclare "accessTokenUrl" field -- API base URL - redeclare "apiBaseUrl" field -- User attribute fetching strategy - redeclare "initUserAttributes" method - -For example: - -``` -use yii\authclient\OAuth1; - -class MyAuthClient extends OAuth1 -{ - public $authUrl = 'https://www.my.com/oauth/auth'; - - public $requestTokenUrl = 'https://www.my.com/oauth/request_token'; - - public $accessTokenUrl = 'https://www.my.com/oauth/access_token'; - - public $apiBaseUrl = 'https://www.my.com/apis/oauth/v1'; - - protected function initUserAttributes() - { - return $this->api('userinfo', 'GET'); - } -} -``` - -You may also specify default auth scopes. - -Note: some OAuth providers may not follow OAuth standards clearly, introducing -some differences, which may require additional efforts to apply. \ No newline at end of file diff --git a/extensions/yii/authclient/clients/Facebook.php b/extensions/yii/authclient/clients/Facebook.php deleted file mode 100644 index 3b78d47..0000000 --- a/extensions/yii/authclient/clients/Facebook.php +++ /dev/null @@ -1,83 +0,0 @@ -. - * - * Example application configuration: - * - * ~~~ - * 'components' => [ - * 'authClientCollection' => [ - * 'class' => 'yii\authclient\Collection', - * 'clients' => [ - * 'facebook' => [ - * 'class' => 'yii\authclient\clients\Facebook', - * 'clientId' => 'facebook_client_id', - * 'clientSecret' => 'facebook_client_secret', - * ], - * ], - * ] - * ... - * ] - * ~~~ - * - * @see https://developers.facebook.com/apps - * @see http://developers.facebook.com/docs/reference/api - * - * @author Paul Klimov - * @since 2.0 - */ -class Facebook extends OAuth2 -{ - /** - * @inheritdoc - */ - public $authUrl = 'https://www.facebook.com/dialog/oauth'; - /** - * @inheritdoc - */ - public $tokenUrl = 'https://graph.facebook.com/oauth/access_token'; - /** - * @inheritdoc - */ - public $apiBaseUrl = 'https://graph.facebook.com'; - /** - * @inheritdoc - */ - public $scope = 'email'; - - /** - * @inheritdoc - */ - protected function initUserAttributes() - { - return $this->api('me', 'GET'); - } - - /** - * @inheritdoc - */ - protected function defaultName() - { - return 'facebook'; - } - - /** - * @inheritdoc - */ - protected function defaultTitle() - { - return 'Facebook'; - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/clients/GitHub.php b/extensions/yii/authclient/clients/GitHub.php deleted file mode 100644 index 6028512..0000000 --- a/extensions/yii/authclient/clients/GitHub.php +++ /dev/null @@ -1,93 +0,0 @@ -. - * - * Example application configuration: - * - * ~~~ - * 'components' => [ - * 'authClientCollection' => [ - * 'class' => 'yii\authclient\Collection', - * 'clients' => [ - * 'github' => [ - * 'class' => 'yii\authclient\clients\GitHub', - * 'clientId' => 'github_client_id', - * 'clientSecret' => 'github_client_secret', - * ], - * ], - * ] - * ... - * ] - * ~~~ - * - * @see http://developer.github.com/v3/oauth/ - * @see https://github.com/settings/applications/new - * - * @author Paul Klimov - * @since 2.0 - */ -class GitHub extends OAuth2 -{ - /** - * @inheritdoc - */ - public $authUrl = 'https://github.com/login/oauth/authorize'; - /** - * @inheritdoc - */ - public $tokenUrl = 'https://github.com/login/oauth/access_token'; - /** - * @inheritdoc - */ - public $apiBaseUrl = 'https://api.github.com'; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->scope === null) { - $this->scope = implode(' ', [ - 'user', - 'user:email', - ]); - } - } - - /** - * @inheritdoc - */ - protected function initUserAttributes() - { - return $this->api('user', 'GET'); - } - - /** - * @inheritdoc - */ - protected function defaultName() - { - return 'github'; - } - - /** - * @inheritdoc - */ - protected function defaultTitle() - { - return 'GitHub'; - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/clients/GoogleOAuth.php b/extensions/yii/authclient/clients/GoogleOAuth.php deleted file mode 100644 index a94a4d3..0000000 --- a/extensions/yii/authclient/clients/GoogleOAuth.php +++ /dev/null @@ -1,93 +0,0 @@ -. - * - * Example application configuration: - * - * ~~~ - * 'components' => [ - * 'authClientCollection' => [ - * 'class' => 'yii\authclient\Collection', - * 'clients' => [ - * 'google' => [ - * 'class' => 'yii\authclient\clients\GoogleOAuth', - * 'clientId' => 'google_client_id', - * 'clientSecret' => 'google_client_secret', - * ], - * ], - * ] - * ... - * ] - * ~~~ - * - * @see https://code.google.com/apis/console#access - * @see https://developers.google.com/google-apps/contacts/v3/ - * - * @author Paul Klimov - * @since 2.0 - */ -class GoogleOAuth extends OAuth2 -{ - /** - * @inheritdoc - */ - public $authUrl = 'https://accounts.google.com/o/oauth2/auth'; - /** - * @inheritdoc - */ - public $tokenUrl = 'https://accounts.google.com/o/oauth2/token'; - /** - * @inheritdoc - */ - public $apiBaseUrl = 'https://www.googleapis.com/oauth2/v1'; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->scope === null) { - $this->scope = implode(' ', [ - 'https://www.googleapis.com/auth/userinfo.profile', - 'https://www.googleapis.com/auth/userinfo.email', - ]); - } - } - - /** - * @inheritdoc - */ - protected function initUserAttributes() - { - return $this->api('userinfo', 'GET'); - } - - /** - * @inheritdoc - */ - protected function defaultName() - { - return 'google'; - } - - /** - * @inheritdoc - */ - protected function defaultTitle() - { - return 'Google'; - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/clients/GoogleOpenId.php b/extensions/yii/authclient/clients/GoogleOpenId.php deleted file mode 100644 index 8b463d6..0000000 --- a/extensions/yii/authclient/clients/GoogleOpenId.php +++ /dev/null @@ -1,90 +0,0 @@ - [ - * 'authClientCollection' => [ - * 'class' => 'yii\authclient\Collection', - * 'clients' => [ - * 'google' => [ - * 'class' => 'yii\authclient\clients\GoogleOpenId' - * ], - * ], - * ] - * ... - * ] - * ~~~ - * - * @author Paul Klimov - * @since 2.0 - */ -class GoogleOpenId extends OpenId -{ - /** - * @inheritdoc - */ - public $authUrl = 'https://www.google.com/accounts/o8/id'; - /** - * @inheritdoc - */ - public $requiredAttributes = [ - 'namePerson/first', - 'namePerson/last', - 'contact/email', - 'pref/language', - ]; - - /** - * @inheritdoc - */ - protected function defaultNormalizeUserAttributeMap() - { - return [ - 'first_name' => 'namePerson/first', - 'last_name' => 'namePerson/last', - 'email' => 'contact/email', - 'language' => 'pref/language', - ]; - } - - /** - * @inheritdoc - */ - protected function defaultViewOptions() - { - return [ - 'popupWidth' => 880, - 'popupHeight' => 520, - ]; - } - - /** - * @inheritdoc - */ - protected function defaultName() - { - return 'google'; - } - - /** - * @inheritdoc - */ - protected function defaultTitle() - { - return 'Google'; - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/clients/LinkedIn.php b/extensions/yii/authclient/clients/LinkedIn.php deleted file mode 100644 index b4e8fdc..0000000 --- a/extensions/yii/authclient/clients/LinkedIn.php +++ /dev/null @@ -1,168 +0,0 @@ -. - * - * Example application configuration: - * - * ~~~ - * 'components' => [ - * 'authClientCollection' => [ - * 'class' => 'yii\authclient\Collection', - * 'clients' => [ - * 'linkedin' => [ - * 'class' => 'yii\authclient\clients\LinkedIn', - * 'clientId' => 'linkedin_client_id', - * 'clientSecret' => 'linkedin_client_secret', - * ], - * ], - * ] - * ... - * ] - * ~~~ - * - * @see http://developer.linkedin.com/documents/authentication - * @see https://www.linkedin.com/secure/developer - * @see http://developer.linkedin.com/apis - * - * @author Paul Klimov - * @since 2.0 - */ -class LinkedIn extends OAuth2 -{ - /** - * @inheritdoc - */ - public $authUrl = 'https://www.linkedin.com/uas/oauth2/authorization'; - /** - * @inheritdoc - */ - public $tokenUrl = 'https://www.linkedin.com/uas/oauth2/accessToken'; - /** - * @inheritdoc - */ - public $apiBaseUrl = 'https://api.linkedin.com/v1'; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->scope === null) { - $this->scope = implode(' ', [ - 'r_basicprofile', - 'r_emailaddress', - ]); - } - } - - /** - * @inheritdoc - */ - protected function defaultNormalizeUserAttributeMap() - { - return [ - 'email' => 'email-address', - 'first_name' => 'first-name', - 'last_name' => 'last-name', - ]; - } - - /** - * @inheritdoc - */ - protected function initUserAttributes() - { - $attributeNames = [ - 'id', - 'email-address', - 'first-name', - 'last-name', - 'public-profile-url', - ]; - return $this->api('people/~:(' . implode(',', $attributeNames) . ')', 'GET'); - } - - /** - * @inheritdoc - */ - public function buildAuthUrl(array $params = []) - { - $authState = $this->generateAuthState(); - $this->setState('authState', $authState); - $params['state'] = $authState; - return parent::buildAuthUrl($params); - } - - /** - * @inheritdoc - */ - public function fetchAccessToken($authCode, array $params = []) - { - $authState = $this->getState('authState'); - if (!isset($_REQUEST['state']) || empty($authState) || strcmp($_REQUEST['state'], $authState) !== 0) { - throw new HttpException(400, 'Invalid auth state parameter.'); - } else { - $this->removeState('authState'); - } - return parent::fetchAccessToken($authCode, $params); - } - - /** - * @inheritdoc - */ - protected function apiInternal($accessToken, $url, $method, array $params) - { - $params['oauth2_access_token'] = $accessToken->getToken(); - return $this->sendRequest($method, $url, $params); - } - - /** - * @inheritdoc - */ - protected function defaultReturnUrl() - { - $params = $_GET; - unset($params['code']); - unset($params['state']); - return Yii::$app->getUrlManager()->createAbsoluteUrl(Yii::$app->controller->getRoute(), $params); - } - - /** - * Generates the auth state value. - * @return string auth state value. - */ - protected function generateAuthState() { - return sha1(uniqid(get_class($this), true)); - } - - /** - * @inheritdoc - */ - protected function defaultName() - { - return 'linkedin'; - } - - /** - * @inheritdoc - */ - protected function defaultTitle() - { - return 'LinkedIn'; - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/clients/Twitter.php b/extensions/yii/authclient/clients/Twitter.php deleted file mode 100644 index 1bee436..0000000 --- a/extensions/yii/authclient/clients/Twitter.php +++ /dev/null @@ -1,91 +0,0 @@ -. - * - * Example application configuration: - * - * ~~~ - * 'components' => [ - * 'authClientCollection' => [ - * 'class' => 'yii\authclient\Collection', - * 'clients' => [ - * 'twitter' => [ - * 'class' => 'yii\authclient\clients\Twitter', - * 'consumerKey' => 'twitter_consumer_key', - * 'consumerSecret' => 'twitter_consumer_secret', - * ], - * ], - * ] - * ... - * ] - * ~~~ - * - * @see https://dev.twitter.com/apps/new - * @see https://dev.twitter.com/docs/api - * - * @author Paul Klimov - * @since 2.0 - */ -class Twitter extends OAuth1 -{ - /** - * @inheritdoc - */ - public $authUrl = 'https://api.twitter.com/oauth/authorize'; - /** - * @inheritdoc - */ - public $requestTokenUrl = 'https://api.twitter.com/oauth/request_token'; - /** - * @inheritdoc - */ - public $requestTokenMethod = 'POST'; - /** - * @inheritdoc - */ - public $accessTokenUrl = 'https://api.twitter.com/oauth/access_token'; - /** - * @inheritdoc - */ - public $accessTokenMethod = 'POST'; - /** - * @inheritdoc - */ - public $apiBaseUrl = 'https://api.twitter.com/1.1'; - - /** - * @inheritdoc - */ - protected function initUserAttributes() - { - return $this->api('account/verify_credentials.json', 'GET'); - } - - /** - * @inheritdoc - */ - protected function defaultName() - { - return 'twitter'; - } - - /** - * @inheritdoc - */ - protected function defaultTitle() - { - return 'Twitter'; - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/clients/YandexOAuth.php b/extensions/yii/authclient/clients/YandexOAuth.php deleted file mode 100644 index e2ddb13..0000000 --- a/extensions/yii/authclient/clients/YandexOAuth.php +++ /dev/null @@ -1,91 +0,0 @@ -. - * - * Example application configuration: - * - * ~~~ - * 'components' => [ - * 'authClientCollection' => [ - * 'class' => 'yii\authclient\Collection', - * 'clients' => [ - * 'yandex' => [ - * 'class' => 'yii\authclient\clients\YandexOAuth', - * 'clientId' => 'yandex_client_id', - * 'clientSecret' => 'yandex_client_secret', - * ], - * ], - * ] - * ... - * ] - * ~~~ - * - * @see https://oauth.yandex.ru/client/new - * @see http://api.yandex.ru/login/doc/dg/reference/response.xml - * - * @author Paul Klimov - * @since 2.0 - */ -class YandexOAuth extends OAuth2 -{ - /** - * @inheritdoc - */ - public $authUrl = 'https://oauth.yandex.ru/authorize'; - /** - * @inheritdoc - */ - public $tokenUrl = 'https://oauth.yandex.ru/token'; - /** - * @inheritdoc - */ - public $apiBaseUrl = 'https://login.yandex.ru'; - - /** - * @inheritdoc - */ - protected function initUserAttributes() - { - return $this->api('info', 'GET'); - } - - /** - * @inheritdoc - */ - protected function apiInternal($accessToken, $url, $method, array $params) - { - if (!isset($params['format'])) { - $params['format'] = 'json'; - } - $params['oauth_token'] = $accessToken->getToken(); - return $this->sendRequest($method, $url, $params); - } - - /** - * @inheritdoc - */ - protected function defaultName() - { - return 'yandex'; - } - - /** - * @inheritdoc - */ - protected function defaultTitle() - { - return 'Yandex'; - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/clients/YandexOpenId.php b/extensions/yii/authclient/clients/YandexOpenId.php deleted file mode 100644 index 20c3b81..0000000 --- a/extensions/yii/authclient/clients/YandexOpenId.php +++ /dev/null @@ -1,86 +0,0 @@ - [ - * 'authClientCollection' => [ - * 'class' => 'yii\authclient\Collection', - * 'clients' => [ - * 'yandex' => [ - * 'class' => 'yii\authclient\clients\YandexOpenId' - * ], - * ], - * ] - * ... - * ] - * ~~~ - * - * @author Paul Klimov - * @since 2.0 - */ -class YandexOpenId extends OpenId -{ - /** - * @inheritdoc - */ - public $authUrl = 'http://openid.yandex.ru'; - /** - * @inheritdoc - */ - public $requiredAttributes = [ - 'namePerson', - 'contact/email', - ]; - - /** - * @inheritdoc - */ - protected function defaultNormalizeUserAttributeMap() - { - return [ - 'name' => 'namePerson', - 'email' => 'contact/email', - ]; - } - - /** - * @inheritdoc - */ - protected function defaultViewOptions() - { - return [ - 'popupWidth' => 900, - 'popupHeight' => 550, - ]; - } - - /** - * @inheritdoc - */ - protected function defaultName() - { - return 'yandex'; - } - - /** - * @inheritdoc - */ - protected function defaultTitle() - { - return 'Yandex'; - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/composer.json b/extensions/yii/authclient/composer.json deleted file mode 100644 index d40889e..0000000 --- a/extensions/yii/authclient/composer.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "yiisoft/yii2-authclient", - "description": "External authentication via OAuth and OpenID for the Yii framework", - "keywords": ["yii", "OAuth", "OpenID", "auth"], - "type": "yii2-extension", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?state=open", - "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": "Paul Klimov", - "email": "klimov.paul@gmail.com" - } - ], - "require": { - "yiisoft/yii2": "*", - "ext-curl": "*" - }, - "autoload": { - "psr-0": { "yii\\authclient\\": "" } - }, - "target-dir": "yii/authclient" -} diff --git a/extensions/yii/authclient/signature/BaseMethod.php b/extensions/yii/authclient/signature/BaseMethod.php deleted file mode 100644 index f0deadc..0000000 --- a/extensions/yii/authclient/signature/BaseMethod.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @since 2.0 - */ -abstract class BaseMethod extends Object -{ - /** - * Return the canonical name of the Signature Method. - * @return string method name. - */ - abstract public function getName(); - - /** - * Generates OAuth request signature. - * @param string $baseString signature base string. - * @param string $key signature key. - * @return string signature string. - */ - abstract public function generateSignature($baseString, $key); - - /** - * Verifies given OAuth request. - * @param string $signature signature to be verified. - * @param string $baseString signature base string. - * @param string $key signature key. - * @return boolean success. - */ - public function verify($signature, $baseString, $key) - { - $expectedSignature = $this->generateSignature($baseString, $key); - if (empty($signature) || empty($expectedSignature)) { - return false; - } - return (strcmp($expectedSignature, $signature) === 0); - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/signature/HmacSha1.php b/extensions/yii/authclient/signature/HmacSha1.php deleted file mode 100644 index 3f88435..0000000 --- a/extensions/yii/authclient/signature/HmacSha1.php +++ /dev/null @@ -1,47 +0,0 @@ - - * @since 2.0 - */ -class HmacSha1 extends BaseMethod -{ - /** - * @inheritdoc - */ - public function init() - { - if (!function_exists('hash_hmac')) { - throw new NotSupportedException('PHP "Hash" extension is required.'); - } - } - - /** - * @inheritdoc - */ - public function getName() - { - return 'HMAC-SHA1'; - } - - /** - * @inheritdoc - */ - public function generateSignature($baseString, $key) - { - return base64_encode(hash_hmac('sha1', $baseString, $key, true)); - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/signature/PlainText.php b/extensions/yii/authclient/signature/PlainText.php deleted file mode 100644 index 867c319..0000000 --- a/extensions/yii/authclient/signature/PlainText.php +++ /dev/null @@ -1,33 +0,0 @@ - - * @since 2.0 - */ -class PlainText extends BaseMethod -{ - /** - * @inheritdoc - */ - public function getName() - { - return 'PLAINTEXT'; - } - - /** - * @inheritdoc - */ - public function generateSignature($baseString, $key) - { - return $key; - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/signature/RsaSha1.php b/extensions/yii/authclient/signature/RsaSha1.php deleted file mode 100644 index 83e4950..0000000 --- a/extensions/yii/authclient/signature/RsaSha1.php +++ /dev/null @@ -1,168 +0,0 @@ - - * @since 2.0 - */ -class RsaSha1 extends BaseMethod -{ - /** - * @var string OpenSSL private key certificate content. - * This value can be fetched from file specified by {@link privateCertificateFile}. - */ - protected $_privateCertificate; - /** - * @var string OpenSSL public key certificate content. - * This value can be fetched from file specified by {@link publicCertificateFile}. - */ - protected $_publicCertificate; - /** - * @var string path to the file, which holds private key certificate. - */ - public $privateCertificateFile = ''; - /** - * @var string path to the file, which holds public key certificate. - */ - public $publicCertificateFile = ''; - - /** - * @inheritdoc - */ - public function init() - { - if (!function_exists('openssl_sign')) { - throw new NotSupportedException('PHP "OpenSSL" extension is required.'); - } - } - - /** - * @param string $publicCertificate public key certificate content. - */ - public function setPublicCertificate($publicCertificate) - { - $this->_publicCertificate = $publicCertificate; - } - - /** - * @return string public key certificate content. - */ - public function getPublicCertificate() - { - if ($this->_publicCertificate === null) { - $this->_publicCertificate = $this->initPublicCertificate(); - } - return $this->_publicCertificate; - } - - /** - * @param string $privateCertificate private key certificate content. - */ - public function setPrivateCertificate($privateCertificate) - { - $this->_privateCertificate = $privateCertificate; - } - - /** - * @return string private key certificate content. - */ - public function getPrivateCertificate() - { - if ($this->_privateCertificate === null) { - $this->_privateCertificate = $this->initPrivateCertificate(); - } - return $this->_privateCertificate; - } - - /** - * @inheritdoc - */ - public function getName() - { - return 'RSA-SHA1'; - } - - /** - * Creates initial value for {@link publicCertificate}. - * This method will attempt to fetch the certificate value from {@link publicCertificateFile} file. - * @throws InvalidConfigException on failure. - * @return string public certificate content. - */ - protected function initPublicCertificate() - { - if (!empty($this->publicCertificateFile)) { - if (!file_exists($this->publicCertificateFile)) { - throw new InvalidConfigException("Public certificate file '{$this->publicCertificateFile}' does not exist!"); - } - return file_get_contents($this->publicCertificateFile); - } else { - return ''; - } - } - - /** - * Creates initial value for {@link privateCertificate}. - * This method will attempt to fetch the certificate value from {@link privateCertificateFile} file. - * @throws InvalidConfigException on failure. - * @return string private certificate content. - */ - protected function initPrivateCertificate() - { - if (!empty($this->privateCertificateFile)) { - if (!file_exists($this->privateCertificateFile)) { - throw new InvalidConfigException("Private certificate file '{$this->privateCertificateFile}' does not exist!"); - } - return file_get_contents($this->privateCertificateFile); - } else { - return ''; - } - } - - /** - * @inheritdoc - */ - public function generateSignature($baseString, $key) - { - $privateCertificateContent = $this->getPrivateCertificate(); - // Pull the private key ID from the certificate - $privateKeyId = openssl_pkey_get_private($privateCertificateContent); - // Sign using the key - openssl_sign($baseString, $signature, $privateKeyId); - // Release the key resource - openssl_free_key($privateKeyId); - return base64_encode($signature); - } - - /** - * @inheritdoc - */ - public function verify($signature, $baseString, $key) - { - $decodedSignature = base64_decode($signature); - // Fetch the public key cert based on the request - $publicCertificate = $this->getPublicCertificate(); - // Pull the public key ID from the certificate - $publicKeyId = openssl_pkey_get_public($publicCertificate); - // Check the computed signature against the one passed in the query - $verificationResult = openssl_verify($baseString, $decodedSignature, $publicKeyId); - // Release the key resource - openssl_free_key($publicKeyId); - return ($verificationResult == 1); - } -} \ No newline at end of file diff --git a/extensions/yii/authclient/views/redirect.php b/extensions/yii/authclient/views/redirect.php deleted file mode 100644 index 9261ffa..0000000 --- a/extensions/yii/authclient/views/redirect.php +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - diff --git a/extensions/yii/authclient/widgets/Choice.php b/extensions/yii/authclient/widgets/Choice.php deleted file mode 100644 index a942c83..0000000 --- a/extensions/yii/authclient/widgets/Choice.php +++ /dev/null @@ -1,239 +0,0 @@ - ['site/auth'] - * ]); ?> - * ~~~ - * - * You can customize the widget appearance by using [[begin()]] and [[end()]] syntax - * along with using method {@link clientLink()} or {@link createClientUrl()}. - * For example: - * - * ~~~php - * - * ['site/auth'] - * ]); ?> - *
      - * getClients() as $client): ?> - *
    • clientLink($client); ?>
    • - * - *
    - * - * ~~~ - * - * This widget supports following keys for [[ClientInterface::getViewOptions()]] result: - * - popupWidth - integer width of the popup window in pixels. - * - popupHeight - integer height of the popup window in pixels. - * - * @see \yii\authclient\AuthAction - * - * @property array $baseAuthUrl Base auth URL configuration. This property is read-only. - * @property ClientInterface[] $clients Auth providers. This property is read-only. - * - * @author Paul Klimov - * @since 2.0 - */ -class Choice extends Widget -{ - /** - * @var string name of the auth client collection application component. - * This component will be used to fetch services value if it is not set. - */ - public $clientCollection = 'authClientCollection'; - /** - * @var string name of the GET param , which should be used to passed auth client id to URL - * defined by [[baseAuthUrl]]. - */ - public $clientIdGetParamName = 'authclient'; - /** - * @var array the HTML attributes that should be rendered in the div HTML tag representing the container element. - */ - public $options = [ - 'class' => 'auth-clients' - ]; - /** - * @var boolean indicates if popup window should be used instead of direct links. - */ - public $popupMode = true; - /** - * @var boolean indicates if widget content, should be rendered automatically. - * Note: this value automatically set to 'false' at the first call of [[createProviderUrl()]] - */ - public $autoRender = true; - - /** - * @var array configuration for the external clients base authentication URL. - */ - private $_baseAuthUrl; - /** - * @var ClientInterface[] auth providers list. - */ - private $_clients; - - /** - * @param ClientInterface[] $clients auth providers - */ - public function setClients(array $clients) - { - $this->_clients = $clients; - } - - /** - * @return ClientInterface[] auth providers - */ - public function getClients() - { - if ($this->_clients === null) { - $this->_clients = $this->defaultClients(); - } - return $this->_clients; - } - - /** - * @param array $baseAuthUrl base auth URL configuration. - */ - public function setBaseAuthUrl(array $baseAuthUrl) - { - $this->_baseAuthUrl = $baseAuthUrl; - } - - /** - * @return array base auth URL configuration. - */ - public function getBaseAuthUrl() - { - if (!is_array($this->_baseAuthUrl)) { - $this->_baseAuthUrl = $this->defaultBaseAuthUrl(); - } - return $this->_baseAuthUrl; - } - - /** - * Returns default auth clients list. - * @return ClientInterface[] auth clients list. - */ - protected function defaultClients() - { - /** @var $collection \yii\authclient\Collection */ - $collection = Yii::$app->getComponent($this->clientCollection); - return $collection->getClients(); - } - - /** - * Composes default base auth URL configuration. - * @return array base auth URL configuration. - */ - protected function defaultBaseAuthUrl() - { - $baseAuthUrl = [ - Yii::$app->controller->getRoute() - ]; - $params = $_GET; - unset($params[$this->clientIdGetParamName]); - $baseAuthUrl = array_merge($baseAuthUrl, $params); - return $baseAuthUrl; - } - - /** - * Outputs client auth link. - * @param ClientInterface $client external auth client instance. - * @param string $text link text, if not set - default value will be generated. - * @param array $htmlOptions link HTML options. - */ - public function clientLink($client, $text = null, array $htmlOptions = []) - { - if ($text === null) { - $text = Html::tag('span', '', ['class' => 'auth-icon ' . $client->getName()]); - $text .= Html::tag('span', $client->getTitle(), ['class' => 'auth-title']); - } - if (!array_key_exists('class', $htmlOptions)) { - $htmlOptions['class'] = 'auth-link ' . $client->getName(); - } - if ($this->popupMode) { - $viewOptions = $client->getViewOptions(); - if (isset($viewOptions['popupWidth'])) { - $htmlOptions['data-popup-width'] = $viewOptions['popupWidth']; - } - if (isset($viewOptions['popupHeight'])) { - $htmlOptions['data-popup-height'] = $viewOptions['popupHeight']; - } - } - echo Html::a($text, $this->createClientUrl($client), $htmlOptions); - } - - /** - * Composes client auth URL. - * @param ClientInterface $provider external auth client instance. - * @return string auth URL. - */ - public function createClientUrl($provider) - { - $this->autoRender = false; - $url = $this->getBaseAuthUrl(); - $url[$this->clientIdGetParamName] = $provider->getId(); - return Html::url($url); - } - - /** - * Renders the main content, which includes all external services links. - */ - protected function renderMainContent() - { - echo Html::beginTag('ul', ['class' => 'auth-clients clear']); - foreach ($this->getClients() as $externalService) { - echo Html::beginTag('li', ['class' => 'auth-client']); - $this->clientLink($externalService); - echo Html::endTag('li'); - } - echo Html::endTag('ul'); - } - - /** - * Initializes the widget. - */ - public function init() - { - if ($this->popupMode) { - $view = Yii::$app->getView(); - ChoiceAsset::register($view); - $view->registerJs("\$('#" . $this->getId() . "').authchoice();"); - } - $this->options['id'] = $this->getId(); - echo Html::beginTag('div', $this->options); - } - - /** - * Runs the widget. - */ - public function run() - { - if ($this->autoRender) { - $this->renderMainContent(); - } - echo Html::endTag('div'); - } -} diff --git a/extensions/yii/authclient/widgets/ChoiceAsset.php b/extensions/yii/authclient/widgets/ChoiceAsset.php deleted file mode 100644 index a30570a..0000000 --- a/extensions/yii/authclient/widgets/ChoiceAsset.php +++ /dev/null @@ -1,30 +0,0 @@ - - * @since 2.0 - */ -class ChoiceAsset extends AssetBundle -{ - public $sourcePath = '@yii/authclient/widgets/assets'; - public $js = [ - 'authchoice.js', - ]; - public $css = [ - 'authchoice.css', - ]; - public $depends = [ - 'yii\web\YiiAsset', - ]; -} \ No newline at end of file diff --git a/extensions/yii/authclient/widgets/assets/authchoice.css b/extensions/yii/authclient/widgets/assets/authchoice.css deleted file mode 100644 index e9195f0..0000000 --- a/extensions/yii/authclient/widgets/assets/authchoice.css +++ /dev/null @@ -1,82 +0,0 @@ -.clients { - overflow:auto; -} - -.auth-icon { - display: block; - width: 32px; - height: 32px; - background: url(authchoice.png) no-repeat; -} - -.auth-icon.google, -.auth-icon.google_openid, -.auth-icon.google_oauth { - background-position: 0 -34px; -} -.auth-icon.twitter { - background-position: 0 -68px; -} -.auth-icon.yandex, -.auth-icon.yandex_openid, -.auth-icon.yandex_oauth { - background-position: 0 -102px; -} -.auth-icon.vkontakte { - background-position: 0 -136px; -} -.auth-icon.facebook { - background-position: 0 -170px; -} -.auth-icon.mailru { - background-position: 0 -204px; -} -.auth-icon.moikrug { - background-position: 0 -238px; -} -.auth-icon.odnoklassniki { - background-position: 0 -272px; -} -.auth-icon.linkedin { - background-position: 0 -306px; -} -.auth-icon.github { - background-position: 0 -340px; -} -.auth-icon.live { - background-position: 0 -372px; -} - -.auth-link:hover .auth-icon i, -.auth-link:focus .auth-icon i { - display: block; - width: 32px; - height: 32px; - background: url(authchoice.png) 0 0 no-repeat; -} - -.auth-clients { - margin: 0 0 1em; - list-style: none; - overflow: auto; -} - -.auth-client { - float: left; - margin: 0 1em 0 0; -} - -.auth-clients .auth-client .auth-link { - display: block; - width: 58px; -} - -.auth-client .auth-link .auth-icon { - margin: 0 auto; -} - -.auth-client .auth-link .auth-title { - display: block; - margin-top: 0.4em; - text-align: center; -} \ No newline at end of file diff --git a/extensions/yii/authclient/widgets/assets/authchoice.js b/extensions/yii/authclient/widgets/assets/authchoice.js deleted file mode 100644 index 3e019d9..0000000 --- a/extensions/yii/authclient/widgets/assets/authchoice.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Yii auth choice widget. - * - * This is the JavaScript widget used by the yii\authclient\widgets\Choice widget. - * - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - * @author Paul Klimov - * @since 2.0 - */ -jQuery(function($) { - $.fn.authchoice = function(options) { - options = $.extend({ - popup: { - resizable: 'yes', - scrollbars: 'no', - toolbar: 'no', - menubar: 'no', - location: 'no', - directories: 'no', - status: 'yes', - width: 450, - height: 380 - } - }, options); - - return this.each(function() { - var $container = $(this); - - $container.find('a').on('click', function(e) { - e.preventDefault(); - - var authChoicePopup = null; - - if (authChoicePopup = $container.data('authChoicePopup')) { - authChoicePopup.close(); - } - - var url = this.href; - var popupOptions = options.popup; - - var localPopupWidth = this.getAttribute('data-popup-width'); - if (localPopupWidth) { - popupOptions.width = localPopupWidth; - } - var localPopupHeight = this.getAttribute('data-popup-height'); - if (localPopupWidth) { - popupOptions.height = localPopupHeight; - } - - popupOptions.left = (window.screen.width - options.popup.width) / 2; - popupOptions.top = (window.screen.height - options.popup.height) / 2; - - var popupFeatureParts = []; - for (var propName in popupOptions) { - popupFeatureParts.push(propName + '=' + popupOptions[propName]); - } - var popupFeature = popupFeatureParts.join(','); - - authChoicePopup = window.open(url, 'yii_auth_choice', popupFeature); - authChoicePopup.focus(); - - $container.data('authChoicePopup', authChoicePopup); - }); - }); - }; -}); diff --git a/extensions/yii/authclient/widgets/assets/authchoice.png b/extensions/yii/authclient/widgets/assets/authchoice.png deleted file mode 100644 index ffc3c5e7ec3298f40e08c6ec0fdd27c6a372f2ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14959 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 diff --git a/extensions/yii/bootstrap/Alert.php b/extensions/yii/bootstrap/Alert.php deleted file mode 100644 index 29844bd..0000000 --- a/extensions/yii/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/yii/bootstrap/BootstrapAsset.php b/extensions/yii/bootstrap/BootstrapAsset.php deleted file mode 100644 index 27dabc0..0000000 --- a/extensions/yii/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/yii/bootstrap/BootstrapPluginAsset.php b/extensions/yii/bootstrap/BootstrapPluginAsset.php deleted file mode 100644 index 35bf18a..0000000 --- a/extensions/yii/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/yii/bootstrap/BootstrapThemeAsset.php b/extensions/yii/bootstrap/BootstrapThemeAsset.php deleted file mode 100644 index f15a0fb..0000000 --- a/extensions/yii/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/yii/bootstrap/Button.php b/extensions/yii/bootstrap/Button.php deleted file mode 100644 index 88acab7..0000000 --- a/extensions/yii/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/yii/bootstrap/ButtonDropdown.php b/extensions/yii/bootstrap/ButtonDropdown.php deleted file mode 100644 index 34d3ae2..0000000 --- a/extensions/yii/bootstrap/ButtonDropdown.php +++ /dev/null @@ -1,119 +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; - /** - * @var string the tag to use to render the button - */ - public $tagName = 'button'; - /** - * @var boolean whether the label should be HTML-encoded. - */ - public $encodeLabel = true; - - - /** - * 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'); - $label = $this->label; - if ($this->encodeLabel) { - $label = Html::encode($label); - } - if ($this->split) { - $options = $this->options; - $this->options['data-toggle'] = 'dropdown'; - Html::addCssClass($this->options, 'dropdown-toggle'); - $splitButton = Button::widget([ - 'label' => '', - 'encodeLabel' => false, - 'options' => $this->options, - ]); - } else { - $label .= ' '; - $options = $this->options; - if (!isset($options['href'])) { - $options['href'] = '#'; - } - Html::addCssClass($options, 'dropdown-toggle'); - $options['data-toggle'] = 'dropdown'; - $splitButton = ''; - } - return Button::widget([ - 'tagName' => $this->tagName, - 'label' => $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/yii/bootstrap/ButtonGroup.php b/extensions/yii/bootstrap/ButtonGroup.php deleted file mode 100644 index 4fc2eb3..0000000 --- a/extensions/yii/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/yii/bootstrap/CHANGELOG.md b/extensions/yii/bootstrap/CHANGELOG.md deleted file mode 100644 index 58fc73d..0000000 --- a/extensions/yii/bootstrap/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -Yii Framework 2 bootstrap extension Change Log -============================================== - -2.0.0 beta under development ----------------------------- - -- Enh #1474: Added option to make NavBar 100% width (cebe) -- Enh #1553: Only add navbar-default class to NavBar when no other class is specified (cebe) -- Enh #1601: Added support for tagName and encodeLabel parameters in ButtonDropdown (omnilight) -- Chg #1459: Update Collapse to use bootstrap 3 classes (tonydspaniard) -- Chg #1820: Update Progress to use bootstrap 3 markup (samdark) - -2.0.0 alpha, December 1, 2013 ------------------------------ - -- Initial release. diff --git a/extensions/yii/bootstrap/Carousel.php b/extensions/yii/bootstrap/Carousel.php deleted file mode 100644 index 8344929..0000000 --- a/extensions/yii/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/yii/bootstrap/Collapse.php b/extensions/yii/bootstrap/Collapse.php deleted file mode 100644 index 794c5e8..0000000 --- a/extensions/yii/bootstrap/Collapse.php +++ /dev/null @@ -1,135 +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, 'panel-group'); - } - - /** - * 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, 'panel panel-default'); - $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, 'panel-collapse collapse'); - - $headerToggle = Html::a($header, '#' . $id, [ - 'class' => 'collapse-toggle', - 'data-toggle' => 'collapse', - 'data-parent' => '#' . $this->options['id'] - ]) . "\n"; - - $header = Html::tag('h4', $headerToggle, ['class' => 'panel-title']); - - $content = Html::tag('div', $item['content'], ['class' => 'panel-body']) . "\n"; - } else { - throw new InvalidConfigException('The "content" option is required.'); - } - $group = []; - - $group[] = Html::tag('div', $header, ['class' => 'panel-heading']); - $group[] = Html::tag('div', $content, $options); - - return implode("\n", $group); - } -} diff --git a/extensions/yii/bootstrap/Dropdown.php b/extensions/yii/bootstrap/Dropdown.php deleted file mode 100644 index fecfb0b..0000000 --- a/extensions/yii/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/yii/bootstrap/Modal.php b/extensions/yii/bootstrap/Modal.php deleted file mode 100644 index 94a3997..0000000 --- a/extensions/yii/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/yii/bootstrap/Nav.php b/extensions/yii/bootstrap/Nav.php deleted file mode 100644 index 42e6346..0000000 --- a/extensions/yii/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($linkOptions, '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/yii/bootstrap/NavBar.php b/extensions/yii/bootstrap/NavBar.php deleted file mode 100644 index 4a15481..0000000 --- a/extensions/yii/bootstrap/NavBar.php +++ /dev/null @@ -1,122 +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 = []; - /** - * @var string text to show for screen readers for the button to toggle the navbar. - */ - public $screenReaderToggleText = 'Toggle navigation'; - /** - * @var bool whether the navbar content should be included in a `container` div which adds left and right padding. - * Set this to false for a 100% width navbar. - */ - public $padded = true; - - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - $this->clientOptions = false; - Html::addCssClass($this->options, 'navbar'); - if ($this->options['class'] == 'navbar') { - Html::addCssClass($this->options, 'navbar-default'); - } - Html::addCssClass($this->brandOptions, 'navbar-brand'); - if (empty($this->options['role'])) { - $this->options['role'] = 'navigation'; - } - - echo Html::beginTag('nav', $this->options); - if ($this->padded) { - 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-{$this->options['id']}-collapse"]); - } - - /** - * Renders the widget. - */ - public function run() - { - - echo Html::endTag('div'); - if ($this->padded) { - 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-{$this->options['id']}-collapse", - ]); - } -} diff --git a/extensions/yii/bootstrap/Progress.php b/extensions/yii/bootstrap/Progress.php deleted file mode 100644 index 8f23a58..0000000 --- a/extensions/yii/bootstrap/Progress.php +++ /dev/null @@ -1,161 +0,0 @@ - 60, - * 'label' => 'test', - * ]); - * - * // styled - * echo Progress::widget([ - * 'percent' => 65, - * 'barOptions' => ['class' => 'progress-bar-danger'] - * ]); - * - * // striped - * echo Progress::widget([ - * 'percent' => 70, - * 'barOptions' => ['class' => 'progress-bar-warning'], - * 'options' => ['class' => 'progress-striped'] - * ]); - * - * // striped animated - * echo Progress::widget([ - * 'percent' => 70, - * 'barOptions' => ['class' => 'progress-bar-success'], - * 'options' => ['class' => 'active progress-striped'] - * ]); - * - * // stacked bars - * echo Progress::widget([ - * 'bars' => [ - * ['percent' => 30, 'options' => ['class' => 'progress-bar-danger']], - * ['percent' => 30, 'label' => 'test', 'options' => ['class' => 'progress-bar-success']], - * ['percent' => 35, 'options' => ['class' => 'progress-bar-warning']], - * ] - * ]); - * ``` - * @see http://getbootstrap.com/components/#progress - * @author Antonio Ramirez - * @author Alexander Makarov - * @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 bar - */ - 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 = []) - { - $defaultOptions = [ - 'role' => 'progressbar', - 'aria-valuenow' => $percent, - 'aria-valuemin' => 0, - 'aria-valuemax' => 100, - 'style' => "width:{$percent}%", - ]; - $options = array_merge($defaultOptions, $options); - Html::addCssClass($options, 'progress-bar'); - - $out = Html::beginTag('div', $options); - $out .= $label; - $out .= Html::tag('span', \Yii::t('yii', '{percent}% Complete', ['percent' => $percent]), [ - 'class' => 'sr-only' - ]); - $out .= Html::endTag('div'); - return $out; - } -} diff --git a/extensions/yii/bootstrap/README.md b/extensions/yii/bootstrap/README.md deleted file mode 100644 index bffc715..0000000 --- a/extensions/yii/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 --prefer-dist yiisoft/yii2-bootstrap "*" -``` - -or add - -``` -"yiisoft/yii2-bootstrap": "*" -``` - -to the require section of your `composer.json` file. - diff --git a/extensions/yii/bootstrap/Tabs.php b/extensions/yii/bootstrap/Tabs.php deleted file mode 100644 index 2e76398..0000000 --- a/extensions/yii/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/yii/bootstrap/Widget.php b/extensions/yii/bootstrap/Widget.php deleted file mode 100644 index ff4084d..0000000 --- a/extensions/yii/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/yii/bootstrap/composer.json b/extensions/yii/bootstrap/composer.json deleted file mode 100644 index 3e6031e..0000000 --- a/extensions/yii/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/yii/codeception/BasePage.php b/extensions/yii/codeception/BasePage.php deleted file mode 100644 index 3a9f8f8..0000000 --- a/extensions/yii/codeception/BasePage.php +++ /dev/null @@ -1,73 +0,0 @@ - - * @since 2.0 - */ -abstract class BasePage extends Component -{ - /** - * @var string|array the route (controller ID and action ID, e.g. `site/about`) to this page. - * Use array to represent a route with GET parameters. The first element of the array represents - * the route and the rest of the name-value pairs are treated as GET parameters, e.g. `array('site/page', 'name' => 'about')`. - */ - public $route; - /** - * @var \Codeception\AbstractGuy the testing guy object - */ - protected $guy; - - /** - * Constructor. - * @param \Codeception\AbstractGuy the testing guy object - */ - public function __construct($I) - { - $this->guy = $I; - } - - /** - * Returns the URL to this page. - * The URL will be returned by calling the URL manager of the application - * with [[route]] and the provided parameters. - * @param array $params the GET parameters for creating the URL - * @return string the URL to this page - * @throws InvalidConfigException if [[route]] is not set or invalid - */ - public function getUrl($params = []) - { - if (is_string($this->route)) { - return Yii::$app->getUrlManager()->createUrl($this->route, $params); - } elseif (is_array($this->route) && isset($this->route[0])) { - $route = $this->route[0]; - $ps = $this->route; - unset($this->route[0]); - return Yii::$app->getUrlManager()->createUrl($route, array_merge($ps, $params)); - } else { - throw new InvalidConfigException('The "route" property must be set.'); - } - } - - /** - * Creates a page instance and sets the test guy to use [[url]]. - * @param \Codeception\AbstractGuy $I the test guy instance - * @param array $params the GET parameters to be used to generate [[url]] - * @return static the page instance - */ - public static function openBy($I, $params = []) - { - $page = new static($I); - $I->amOnPage($page->getUrl($params)); - return $page; - } -} diff --git a/extensions/yii/codeception/CHANGELOG.md b/extensions/yii/codeception/CHANGELOG.md deleted file mode 100644 index 8ebfe93..0000000 --- a/extensions/yii/codeception/CHANGELOG.md +++ /dev/null @@ -1,7 +0,0 @@ -Yii Framework 2 Codeception extension Change Log -================================================ - -2.0.0 beta under development ----------------------------- - -- Initial release. \ No newline at end of file diff --git a/extensions/yii/codeception/LICENSE.md b/extensions/yii/codeception/LICENSE.md deleted file mode 100644 index 0bb1a8d..0000000 --- a/extensions/yii/codeception/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-2013 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/yii/codeception/README.md b/extensions/yii/codeception/README.md deleted file mode 100644 index d065961..0000000 --- a/extensions/yii/codeception/README.md +++ /dev/null @@ -1,199 +0,0 @@ -Codeception Extension for Yii 2 -=============================== - -This extension provides [Codeception](http://codeception.com/) integration for the Yii Framework 2.0. - -It provides classes that help with testing with codeception: - -- a base class for unit-tests: `yii\codeception\TestCase`; -- a base class for codeception page-objects: `yii\codeception\BasePage`. - - -Installation ------------- - -The preferred way to install this extension is through [composer](http://getcomposer.org/download/). - -Either run - -``` -php composer.phar require --prefer-dist yiisoft/yii2-codeception "*" -``` - -or add - -```json -"yiisoft/yii2-codeception": "*" -``` - -to the require section of your composer.json. - - -Usage ------ - -When using codeception page-objects they have some similar code, this code was extracted and put into the `BasePage` -class to reduce code duplication. Simply extend your page object from this class, like it is done in `yii2-app-basic` and -`yii2-app-advanced` boilerplates. - -For unit testing there is a `TestCase` class which holds some common features like application creation before each test -and application destroy after each test. You can configure a mock application using this class. -`TestCase` is extended from `Codeception\TestCase\Case` so all methods and assertions are available. -You may use codeception modules and fire events in your test, just use methods: - -```php -getModule('CodeHelper'); #or some other module -``` - -You also can use all guy methods by accessing guy instance like: - -```php -codeGuy->someMethodFromModule(); -``` - -to fire event do this: - -```php -fire('myevent', new TestEvent($this)); -} -``` -this event can be catched in modules and helpers. If your test is in the group, then event name will be followed by the groupname, -for example ```myevent.somegroup```. - -Execution of special tests methods is (for example on ```UserTest``` class): - -``` -tests\unit\models\UserTest::setUpBeforeClass(); - - tests\unit\models\UserTest::_before(); - - tests\unit\models\UserTest::setUp(); - - tests\unit\models\UserTest::testSomething(); - - tests\unit\models\UserTest::tearDown(); - - tests\unit\models\UserTest::_after(); - -tests\unit\models\UserTest::tearDownAfterClass(); -``` - -If you use special methods dont forget to call its parent. - -```php - [ - 'mail' => [ - 'useFileTransport' => true, - ], - ] - ]; -} -``` - -Because of Codeception buffers all output you can't make simple `var_dump()` in the TestCase, instead you need to use -`Codeception\Util\Debug::debug()` function and then run test with `--debug` key, for example: - -```php - 1 - [1] => 2 - [2] => 3 - [3] => 4 - [4] => 5 - ) - - yii\web\User Object - ( - [identityClass] => app\models\User - [enableAutoLogin] => - [loginUrl] => Array - ( - [0] => site/login - ) - - [identityCookie] => Array - ( - [name] => _identity - [httpOnly] => 1 - ) - - [authTimeout] => - [autoRenewCookie] => 1 - [idVar] => __id - [authTimeoutVar] => __expire - [returnUrlVar] => __returnUrl - [_access:yii\web\User:private] => Array - ( - ) - - [_identity:yii\web\User:private] => - [_events:yii\base\Component:private] => - [_behaviors:yii\base\Component:private] => - ) - -``` - -For further instructions refer to the testing section in the [Yii Definitive Guide](https://github.com/yiisoft/yii2/blob/master/docs/guide/testing.md). diff --git a/extensions/yii/codeception/TestCase.php b/extensions/yii/codeception/TestCase.php deleted file mode 100644 index 212f3b7..0000000 --- a/extensions/yii/codeception/TestCase.php +++ /dev/null @@ -1,77 +0,0 @@ - - * @since 2.0 - */ -class TestCase extends Test -{ - /** - * @var array|string the application configuration that will be used for creating an application instance for each test. - * You can use a string to represent the file path or path alias of a configuration file. - * The application configuration array may contain an optional `class` element which specifies the class - * name of the application instance to be created. By default, a [[yii\web\Application]] instance will be created. - */ - public $appConfig = '@tests/unit/_config.php'; - - /** - * @inheritdoc - */ - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - - /** - * @inheritdoc - */ - protected function tearDown() - { - $this->destroyApplication(); - parent::tearDown(); - } - - /** - * Mocks up the application instance. - * @param array $config the configuration that should be used to generate the application instance. - * If null, [[appConfig]] will be used. - * @return \yii\web\Application|\yii\console\Application the application instance - * @throws InvalidConfigException if the application configuration is invalid - */ - protected function mockApplication($config = null) - { - $config = $config === null ? $this->appConfig : $config; - if (is_string($config)) { - $configFile = Yii::getAlias($config); - if (!is_file($configFile)) { - throw new InvalidConfigException("The application configuration file does not exist: $config"); - } - $config = require($configFile); - } - if (is_array($config)) { - if (!isset($config['class'])) { - $config['class'] = 'yii\web\Application'; - } - return Yii::createObject($config); - } else { - throw new InvalidConfigException('Please provide a configuration array to mock up an application.'); - } - } - - /** - * Destroys the application instance created by [[mockApplication]]. - */ - protected function destroyApplication() - { - Yii::$app = null; - } -} diff --git a/extensions/yii/codeception/composer.json b/extensions/yii/codeception/composer.json deleted file mode 100644 index 66957bc..0000000 --- a/extensions/yii/codeception/composer.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "yiisoft/yii2-codeception", - "description": "The Codeception integration for the Yii framework", - "keywords": ["yii", "codeception"], - "type": "yii2-extension", - "license": "BSD-3-Clause", - "support": { - "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": "Mark Jebri", - "email": "mark.github@yandex.ru" - } - ], - "require": { - "yiisoft/yii2": "*" - }, - "autoload": { - "psr-0": { "yii\\codeception\\": "" } - }, - "target-dir": "yii/codeception" -} diff --git a/extensions/yii/composer/CHANGELOG.md b/extensions/yii/composer/CHANGELOG.md deleted file mode 100644 index 3156dbc..0000000 --- a/extensions/yii/composer/CHANGELOG.md +++ /dev/null @@ -1,14 +0,0 @@ -Yii Framework 2 composer extension Change Log -============================================= - -2.0.0 beta under development ----------------------------- - -- Bug #1480: Fixed issue with creating extensions.php when php opcache is enabled (cebe) -- Enh: Added support for installing packages conforming to PSR-4 standard (qiangxue) - - -2.0.0 alpha, December 1, 2013 ------------------------------ - -- Initial release. diff --git a/extensions/yii/composer/Installer.php b/extensions/yii/composer/Installer.php deleted file mode 100644 index 2668d3e..0000000 --- a/extensions/yii/composer/Installer.php +++ /dev/null @@ -1,259 +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->linkBaseYiiFiles(); - } - } - - /** - * @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->linkBaseYiiFiles(); - } - } - - /** - * @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->removeBaseYiiFiles(); - } - } - - 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) - { - $fs = new Filesystem; - $vendorDir = $fs->normalizePath($this->vendorDir); - $autoload = $package->getAutoload(); - - $aliases = []; - - if (!empty($autoload['psr-0'])) { - 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; - } - } - } - - if (!empty($autoload['psr-4'])) { - foreach ($autoload['psr-4'] 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)); - } else { - $aliases["@$name"] = $path; - } - } - } - - 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 []; - } - // invalidate opcache of extensions.php if exists - if (function_exists('opcache_invalidate')) { - opcache_invalidate($file, true); - } - $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', 'BaseYii.php', 'classes.php'] as $file) { - file_put_contents($yiiDir . '/' . $file, <<vendorDir . '/yiisoft/yii2/yii'; - foreach(['Yii.php', 'BaseYii.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/yii/composer/LICENSE.md b/extensions/yii/composer/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/extensions/yii/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/yii/composer/Plugin.php b/extensions/yii/composer/Plugin.php deleted file mode 100644 index 1111738..0000000 --- a/extensions/yii/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', - 'toolbar.css', - ]; - public $depends = [ - 'yii\web\YiiAsset', - 'yii\bootstrap\BootstrapAsset', - ]; -} diff --git a/extensions/yii/debug/LogTarget.php b/extensions/yii/debug/LogTarget.php deleted file mode 100644 index 1359b36..0000000 --- a/extensions/yii/debug/LogTarget.php +++ /dev/null @@ -1,125 +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(); - $response = Yii::$app->getResponse(); - $manifest[$this->tag] = $summary = [ - 'tag' => $this->tag, - 'url' => $request->getAbsoluteUrl(), - 'ajax' => $request->getIsAjax(), - 'method' => $request->getMethod(), - 'ip' => $request->getUserIP(), - 'time' => time(), - 'statusCode' => $response->statusCode, - 'sqlCount' => $this->getSqlTotalCount(), - ]; - $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; - } - } - } - } - - /** - * Returns total sql count executed in current request. If database panel is not configured - * returns 0. - * @return integer - */ - protected function getSqlTotalCount() - { - if (!isset($this->module->panels['db'])) { - return 0; - } - $profileLogs = $this->module->panels['db']->save(); - - # / 2 because messages are in couple (begin/end) - return count($profileLogs['messages']) / 2; - } - -} diff --git a/extensions/yii/debug/Module.php b/extensions/yii/debug/Module.php deleted file mode 100644 index 06f2b76..0000000 --- a/extensions/yii/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_REQUEST, 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/yii/debug/Panel.php b/extensions/yii/debug/Panel.php deleted file mode 100644 index ebfa8b3..0000000 --- a/extensions/yii/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/yii/debug/README.md b/extensions/yii/debug/README.md deleted file mode 100644 index aaac00d..0000000 --- a/extensions/yii/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 --prefer-dist 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/yii/debug/assets/bg.png b/extensions/yii/debug/assets/bg.png deleted file mode 100644 index 459dd788897ac6e4743123bb22018d5f672020bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfx!3HGlw@oMq2^0spJ29*~C-V}>VN3FMcVYMs zf(!O8p9~b?EbxddW? [rule1, rule2,..]] - */ - protected $rules = []; - - /** - * Adds rules for filtering data. Match can be partial or exactly. - * @param string $name attribute name - * @param \yii\debug\components\search\matches\Base $rule - */ - public function addMatch($name, $rule) - { - if (empty($rule->value) && $rule->value !== 0) { - return; - } - - $this->rules[$name][] = $rule; - } - - /** - * Applies filter on given array and returns filtered data. - * @param array $data data to filter - * @return array filtered data - */ - public function filter(array $data) - { - $filtered = []; - - foreach ($data as $row) { - if ($this->checkFilter($row)) { - $filtered[] = $row; - } - } - - return $filtered; - } - - /** - * Check if the given data satisfies filters. - * @param array $row - */ - public function checkFilter(array $row) - { - $matched = true; - - foreach ($row as $name => $value) { - if (isset($this->rules[$name])) { - - #check all rules for given attribute - - foreach ($this->rules[$name] as $rule) { - if (!$rule->check($value)) { - $matched = false; - } - } - - } - } - - return $matched; - } - -} diff --git a/extensions/yii/debug/components/search/matches/Base.php b/extensions/yii/debug/components/search/matches/Base.php deleted file mode 100644 index ce2ceae..0000000 --- a/extensions/yii/debug/components/search/matches/Base.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @since 2.0 - */ -abstract class Base extends Component implements MatcherInterface -{ - - /** - * @var mixed current value to check for the matcher - */ - public $value; - -} diff --git a/extensions/yii/debug/components/search/matches/Exact.php b/extensions/yii/debug/components/search/matches/Exact.php deleted file mode 100644 index 46992e9..0000000 --- a/extensions/yii/debug/components/search/matches/Exact.php +++ /dev/null @@ -1,36 +0,0 @@ - - * @since 2.0 - */ -class Exact extends Base -{ - - /** - * @var boolean if current matcher should consider partial match of given value. - */ - public $partial = false; - - /** - * Checks if the given value is the same as base one or has partial match with base one. - * @param mixed $value - */ - public function check($value) - { - if (!$this->partial) { - return (mb_strtolower($this->value, 'utf8') == mb_strtolower($value, 'utf8')); - } else { - return (mb_strpos(mb_strtolower($value, 'utf8'), mb_strtolower($this->value,'utf8')) !== false); - } - } - -} diff --git a/extensions/yii/debug/components/search/matches/Greater.php b/extensions/yii/debug/components/search/matches/Greater.php deleted file mode 100644 index 7796f6b..0000000 --- a/extensions/yii/debug/components/search/matches/Greater.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @since 2.0 - */ -class Greater extends Base -{ - - /** - * Checks if the given value is the same as base one or has partial match with base one. - * @param mixed $value - */ - public function check($value) - { - return ($value > $this->value); - } - -} diff --git a/extensions/yii/debug/components/search/matches/Lower.php b/extensions/yii/debug/components/search/matches/Lower.php deleted file mode 100644 index 034ea4a..0000000 --- a/extensions/yii/debug/components/search/matches/Lower.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @since 2.0 - */ -class Lower extends Base -{ - - /** - * Checks if the given value is the same as base one or has partial match with base one. - * @param mixed $value - */ - public function check($value) - { - return ($value < $this->value); - } - -} diff --git a/extensions/yii/debug/components/search/matches/MatcherInterface.php b/extensions/yii/debug/components/search/matches/MatcherInterface.php deleted file mode 100644 index 16c0705..0000000 --- a/extensions/yii/debug/components/search/matches/MatcherInterface.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -interface MatcherInterface -{ - - /** - * Check if the value is correct according current matcher. - * @param mixed $value - */ - public function check($value); - -} diff --git a/extensions/yii/debug/composer.json b/extensions/yii/debug/composer.json deleted file mode 100644 index d8cbc1e..0000000 --- a/extensions/yii/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/yii/debug/controllers/DefaultController.php b/extensions/yii/debug/controllers/DefaultController.php deleted file mode 100644 index 521116c..0000000 --- a/extensions/yii/debug/controllers/DefaultController.php +++ /dev/null @@ -1,132 +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() - { - $searchModel = new Debug(); - $dataProvider = $searchModel->search($_GET, $this->getManifest()); - - return $this->render('index', [ - 'dataProvider' => $dataProvider, - 'searchModel' => $searchModel, - ]); - } - - 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, 5); - return $this->renderPartial('toolbar', [ - 'tag' => $tag, - 'panels' => $this->module->panels, - 'position' => 'bottom', - ]); - } - - public function actionPhpinfo() - { - phpinfo(); - } - - private $_manifest; - - protected function getManifest($forceReload = false) - { - if ($this->_manifest === null || $forceReload) { - if ($forceReload) { - clearstatcache(); - } - $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, $maxRetry = 0) - { - // retry loading debug data because the debug data is logged in shutdown function - // which may be delayed in some environment if xdebug is enabled. - // See: https://github.com/yiisoft/yii2/issues/1504 - for ($retry = 0; $retry <= $maxRetry; ++$retry) { - $manifest = $this->getManifest($retry > 0); - 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']; - return; - } - sleep(1); - } - - throw new NotFoundHttpException("Unable to find debug data tagged with '$tag'."); - } -} diff --git a/extensions/yii/debug/models/search/Base.php b/extensions/yii/debug/models/search/Base.php deleted file mode 100644 index be9b852..0000000 --- a/extensions/yii/debug/models/search/Base.php +++ /dev/null @@ -1,37 +0,0 @@ -$attribute; - - if (mb_strpos($value, '>') !== false) { - - $value = intval(str_replace('>', '', $value)); - $filter->addMatch($attribute, new matches\Greater(['value' => $value])); - - } elseif (mb_strpos($value, '<') !== false) { - - $value = intval(str_replace('<', '', $value)); - $filter->addMatch($attribute, new matches\Lower(['value' => $value])); - - } else { - $filter->addMatch($attribute, new matches\Exact(['value' => $value, 'partial' => $partial])); - } - - } - -} diff --git a/extensions/yii/debug/models/search/Db.php b/extensions/yii/debug/models/search/Db.php deleted file mode 100644 index 679ef77..0000000 --- a/extensions/yii/debug/models/search/Db.php +++ /dev/null @@ -1,75 +0,0 @@ - 'Type', - 'query' => 'Query', - ]; - } - - /** - * Returns data provider with filled models. Filter applied if needed. - * @param array $params - * @param array $models - * @return \yii\data\ArrayDataProvider - */ - public function search($params, $models) - { - $dataProvider = new ArrayDataProvider([ - 'allModels' => $models, - 'pagination' => [ - 'pageSize' => 10, - ], - 'sort' => [ - 'attributes' => ['duration', 'seq', 'type', 'query'], - 'defaultOrder' => [ - 'duration' => SORT_DESC, - ], - ], - ]); - - if (!($this->load($params) && $this->validate())) { - return $dataProvider; - } - - $filter = new Filter(); - $this->addCondition($filter, 'type', true); - $this->addCondition($filter, 'query', true); - $dataProvider->allModels = $filter->filter($models); - - return $dataProvider; - } - -} diff --git a/extensions/yii/debug/models/search/Debug.php b/extensions/yii/debug/models/search/Debug.php deleted file mode 100644 index 51bd45f..0000000 --- a/extensions/yii/debug/models/search/Debug.php +++ /dev/null @@ -1,122 +0,0 @@ - 'Tag', - 'ip' => 'Ip', - 'method' => 'Method', - 'ajax' => 'Ajax', - 'url' => 'url', - 'statusCode' => 'Status code', - 'sqlCount' => 'Total queries count', - ]; - } - - /** - * Returns data provider with filled models. Filter applied if needed. - * @param array $params - * @param array $models - * @return \yii\data\ArrayDataProvider - */ - public function search($params, $models) - { - $dataProvider = new ArrayDataProvider([ - 'allModels' => $models, - 'sort' => [ - 'attributes' => ['method', 'ip', 'tag', 'time', 'statusCode', 'sqlCount'], - ], - 'pagination' => [ - 'pageSize' => 10, - ], - ]); - - if (!($this->load($params) && $this->validate())) { - return $dataProvider; - } - - $filter = new Filter(); - $this->addCondition($filter, 'tag', true); - $this->addCondition($filter, 'ip', true); - $this->addCondition($filter, 'method'); - $this->addCondition($filter, 'ajax'); - $this->addCondition($filter, 'url', true); - $this->addCondition($filter, 'statusCode'); - $this->addCondition($filter, 'sqlCount'); - $dataProvider->allModels = $filter->filter($models); - - return $dataProvider; - } - - /** - * Checks if the code is critical: 400 or greater, 500 or greater. - * @param integer $code - * @return bool - */ - public function isCodeCritical($code) - { - return in_array($code, $this->criticalCodes); - } - -} diff --git a/extensions/yii/debug/models/search/Log.php b/extensions/yii/debug/models/search/Log.php deleted file mode 100644 index 1a170b2..0000000 --- a/extensions/yii/debug/models/search/Log.php +++ /dev/null @@ -1,79 +0,0 @@ - 'Level', - 'category' => 'Category', - 'message' => 'Message', - ]; - } - - /** - * Returns data provider with filled models. Filter applied if needed. - * @param array $params - * @param array $models - * @return \yii\data\ArrayDataProvider - */ - public function search($params, $models) - { - $dataProvider = new ArrayDataProvider([ - 'allModels' => $models, - 'pagination' => [ - 'pageSize' => 10, - ], - 'sort' => [ - 'attributes' => ['time', 'level', 'category', 'message'], - ], - ]); - - if (!($this->load($params) && $this->validate())) { - return $dataProvider; - } - - $filter = new Filter(); - $this->addCondition($filter, 'level'); - $this->addCondition($filter, 'category', true); - $this->addCondition($filter, 'message', true); - $dataProvider->allModels = $filter->filter($models); - - return $dataProvider; - } - -} diff --git a/extensions/yii/debug/models/search/Profile.php b/extensions/yii/debug/models/search/Profile.php deleted file mode 100644 index 945683b..0000000 --- a/extensions/yii/debug/models/search/Profile.php +++ /dev/null @@ -1,75 +0,0 @@ - 'Category', - 'info' => 'Info', - ]; - } - - /** - * Returns data provider with filled models. Filter applied if needed. - * @param array $params - * @param array $models - * @return \yii\data\ArrayDataProvider - */ - public function search($params, $models) - { - $dataProvider = new ArrayDataProvider([ - 'allModels' => $models, - 'pagination' => [ - 'pageSize' => 10, - ], - 'sort' => [ - 'attributes' => ['category', 'seq', 'duration', 'info'], - 'defaultOrder' => [ - 'seq' => SORT_ASC, - ], - ], - ]); - - if (!($this->load($params) && $this->validate())) { - return $dataProvider; - } - - $filter = new Filter(); - $this->addCondition($filter, 'category', true); - $this->addCondition($filter, 'info', true); - $dataProvider->allModels = $filter->filter($models); - - return $dataProvider; - } - -} diff --git a/extensions/yii/debug/panels/ConfigPanel.php b/extensions/yii/debug/panels/ConfigPanel.php deleted file mode 100644 index 8e1b9ed..0000000 --- a/extensions/yii/debug/panels/ConfigPanel.php +++ /dev/null @@ -1,70 +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() - { - return Yii::$app->view->render('panels/config/summary', ['panel' => $this]); - } - - public function getDetail() - { - return Yii::$app->view->render('panels/config/detail', ['panel' => $this]); - } - - public function getExtensions() - { - $data = []; - foreach ($this->data['extensions'] as $extension) { - $data[$extension['name']] = $extension['version']; - } - return $data; - } - - 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/yii/debug/panels/DbPanel.php b/extensions/yii/debug/panels/DbPanel.php deleted file mode 100644 index 271373b..0000000 --- a/extensions/yii/debug/panels/DbPanel.php +++ /dev/null @@ -1,138 +0,0 @@ - - * @since 2.0 - */ -class DbPanel extends Panel -{ - - /** - * @var array db queries info extracted to array as models, to use with data provider. - */ - private $_models; - - /** - * @var array current database request timings - */ - private $_timings; - - public function getName() - { - return 'Database'; - } - - public function getSummary() - { - $timings = $this->calculateTimings(); - $queryCount = count($timings); - $queryTime = number_format($this->getTotalQueryTime($timings) * 1000) . ' ms'; - - return Yii::$app->view->render('panels/db/summary', [ - 'timings' => $this->calculateTimings(), - 'panel' => $this, - 'queryCount' => $queryCount, - 'queryTime' => $queryTime, - ]); - } - - public function getDetail() - { - $searchModel = new Db(); - $dataProvider = $searchModel->search(Yii::$app->request->get(), $this->getModels()); - - return Yii::$app->view->render('panels/db/detail', [ - 'panel' => $this, - 'dataProvider' => $dataProvider, - 'searchModel' => $searchModel, - ]); - } - - /** - * Calculates given request profile messages timings. - * @return array timings [token, category, timestamp, traces, nesting level, elapsed time] - */ - protected function calculateTimings() - { - if ($this->_timings === null) { - $this->_timings = Yii::$app->getLog()->calculateTimings($this->data['messages']); - } - return $this->_timings; - } - - public function save() - { - $target = $this->module->logTarget; - $messages = $target->filterMessages($target->messages, Logger::LEVEL_PROFILE, ['yii\db\Command::query', 'yii\db\Command::execute']); - return ['messages' => $messages]; - } - - /** - * Returns total queries time. - * @param array $timings - * @return integer total time - */ - protected function getTotalQueryTime($timings) - { - $queryTime = 0; - - foreach ($timings as $timing) { - $queryTime += $timing['duration']; - } - - return $queryTime; - } - - /** - * Returns array of models that represents logs of the current request. Can be used with data providers, - * like yii\data\ArrayDataProvider. - * @return array models - */ - protected function getModels() - { - if ($this->_models === null) { - $this->_models = []; - $timings = $this->calculateTimings(); - - foreach($timings as $seq => $dbTiming) { - $this->_models[] = [ - 'type' => $this->detectQueryType($dbTiming['info']), - 'query' => $dbTiming['info'], - 'duration' => ($dbTiming['duration'] * 1000), // in milliseconds - 'trace' => $dbTiming['trace'], - 'timestamp' => ($dbTiming['timestamp'] * 1000), // in milliseconds - 'seq' => $seq, - ]; - } - } - return $this->_models; - } - - /** - * Detects databse timing type. Detecting is produced through simple parsing to the first space|tab|new row. - * First word before space is timing type. If there is no such words, timing will have empty type. - * @param string $timing timing procedure string - * @return string query type select|insert|delete|etc - */ - protected function detectQueryType($timing) - { - $timing = ltrim($timing); - preg_match('/^([a-zA-z]*)/', $timing, $matches); - return count($matches) ? $matches[0] : ''; - } - -} diff --git a/extensions/yii/debug/panels/LogPanel.php b/extensions/yii/debug/panels/LogPanel.php deleted file mode 100644 index d96704e..0000000 --- a/extensions/yii/debug/panels/LogPanel.php +++ /dev/null @@ -1,82 +0,0 @@ - - * @since 2.0 - */ -class LogPanel extends Panel -{ - - /** - * @var array log messages extracted to array as models, to use with data provider. - */ - private $_models; - - public function getName() - { - return 'Logs'; - } - - public function getSummary() - { - return Yii::$app->view->render('panels/log/summary', ['data' => $this->data, 'panel' => $this]); - } - - public function getDetail() - { - $searchModel = new Log(); - $dataProvider = $searchModel->search(Yii::$app->request->get(), $this->getModels()); - - return Yii::$app->view->render('panels/log/detail', [ - 'dataProvider' => $dataProvider, - 'panel' => $this, - 'searchModel' => $searchModel, - ]); - } - - 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]; - } - - /** - * Returns array of models that represents logs of the current request. Can be used with data providers, - * like yii\data\ArrayDataProvider. - * @param boolean $refresh if needed to build models from log messages and refresh them. - * @return array models - */ - protected function getModels($refresh = false) - { - if ($this->_models === null || $refresh) { - $this->_models = []; - - foreach($this->data['messages'] as $message) { - $this->_models[] = [ - 'message' => $message[0], - 'level' => $message[1], - 'category' => $message[2], - 'time' => ($message[3] * 1000), // time in milliseconds - 'trace' => $message[4] - ]; - } - } - return $this->_models; - } - -} diff --git a/extensions/yii/debug/panels/ProfilingPanel.php b/extensions/yii/debug/panels/ProfilingPanel.php deleted file mode 100644 index 9316552..0000000 --- a/extensions/yii/debug/panels/ProfilingPanel.php +++ /dev/null @@ -1,91 +0,0 @@ - - * @since 2.0 - */ -class ProfilingPanel extends Panel -{ - /** - * @var array current request profile timings - */ - private $_models; - - public function getName() - { - return 'Profiling'; - } - - public function getSummary() - { - return Yii::$app->view->render('panels/profile/summary', [ - 'memory' => sprintf('%.1f MB', $this->data['memory'] / 1048576), - 'time' => number_format($this->data['time'] * 1000) . ' ms', - 'panel' => $this - ]); - } - - public function getDetail() - { - $searchModel = new Profile(); - $dataProvider = $searchModel->search(Yii::$app->request->get(), $this->getModels()); - - return Yii::$app->view->render('panels/profile/detail', [ - 'panel' => $this, - 'dataProvider' => $dataProvider, - 'searchModel' => $searchModel, - 'memory' => sprintf('%.1f MB', $this->data['memory'] / 1048576), - 'time' => number_format($this->data['time'] * 1000) . ' ms', - ]); - } - - 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, - ]; - } - - /** - * Returns array of profiling models that can be used in data provider. - * @return array models - */ - protected function getModels() - { - if ($this->_models === null) { - $this->_models = []; - $timings = Yii::$app->getLog()->calculateTimings($this->data['messages']); - - foreach($timings as $seq => $profileTiming) { - $this->_models[] = [ - 'duration' => $profileTiming['duration'] * 1000, // in milliseconds - 'category' => $profileTiming['category'], - 'info' => $profileTiming['info'], - 'level' => $profileTiming['level'], - 'timestamp' => $profileTiming['timestamp'] * 1000, //in milliseconds - 'seq' => $seq, - ]; - } - } - return $this->_models; - } - -} diff --git a/extensions/yii/debug/panels/RequestPanel.php b/extensions/yii/debug/panels/RequestPanel.php deleted file mode 100644 index 74d0f6a..0000000 --- a/extensions/yii/debug/panels/RequestPanel.php +++ /dev/null @@ -1,92 +0,0 @@ - - * @since 2.0 - */ -class RequestPanel extends Panel -{ - public function getName() - { - return 'Request'; - } - - public function getSummary() - { - return Yii::$app->view->render('panels/request/summary', ['panel' => $this]); - } - - public function getDetail() - { - return Yii::$app->view->render('panels/request/detail', ['panel' => $this]); - } - - 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, - ]; - } - -} diff --git a/extensions/yii/debug/views/default/index.php b/extensions/yii/debug/views/default/index.php deleted file mode 100644 index 082eda7..0000000 --- a/extensions/yii/debug/views/default/index.php +++ /dev/null @@ -1,85 +0,0 @@ -title = 'Yii Debugger'; -?> -
    -
    -
    - Yii Debugger -
    -
    - -
    -
    -

    Available Debug Data

    - - 'yii\i18n\Formatter']) : Yii::$app->formatter; - -echo GridView::widget([ - 'dataProvider' => $dataProvider, - 'filterModel' => $searchModel, - 'rowOptions' => function ($model, $key, $index, $grid) use ($searchModel) { - if ($searchModel->isCodeCritical($model['statusCode'])) { - return ['class'=>'danger']; - } else { - return []; - } - }, - 'columns' => [ - ['class' => 'yii\grid\SerialColumn'], - [ - 'attribute' => 'tag', - 'value' => function ($data) - { - return Html::a($data['tag'], ['view', 'tag' => $data['tag']]); - }, - 'format' => 'html', - ], - [ - 'attribute' => 'time', - 'value' => function ($data) use ($timeFormatter) - { - return $timeFormatter->asDateTime($data['time'], 'long'); - }, - ], - 'ip', - [ - 'attribute' => 'sqlCount', - 'label' => 'Total queries count' - ], - [ - 'attribute' => 'method', - 'filter' => ['get' => 'GET', 'post' => 'POST', 'delete' => 'DELETE', 'put' => 'PUT', 'head' => 'HEAD'] - ], - [ - 'attribute'=>'ajax', - 'value' => function ($data) - { - return $data['ajax'] ? 'Yes' : 'No'; - }, - 'filter' => ['No', 'Yes'], - ], - 'url', - [ - 'attribute' => 'statusCode', - 'filter' => [200 => 200, 404 => 404, 403 => 403, 500 => 500], - 'label' => 'Status code' - ], - ], -]); ?> -
    -
    -
    diff --git a/extensions/yii/debug/views/default/panels/config/detail.php b/extensions/yii/debug/views/default/panels/config/detail.php deleted file mode 100644 index e8bdf73..0000000 --- a/extensions/yii/debug/views/default/panels/config/detail.php +++ /dev/null @@ -1,38 +0,0 @@ -getExtensions(); -?> -

    Configuration

    -render('panels/config/table', [ - 'caption' => 'Application Configuration', - 'values' => [ - 'Yii Version' => $panel->data['application']['yii'], - 'Application Name' => $panel->data['application']['name'], - 'Environment' => $panel->data['application']['env'], - 'Debug Mode' => $panel->data['application']['debug'] ? 'Yes' : 'No', - ], -]); - -if (!empty($extensions)) { - echo $this->render('panels/config/table', [ - 'caption' => 'Installed Extensions', - 'values' => $extensions, - ]); -} - -echo $this->render('panels/config/table', [ - 'caption' => 'PHP Configuration', - 'values' => [ - 'PHP Version' => $panel->data['php']['version'], - 'Xdebug' => $panel->data['php']['xdebug'] ? 'Enabled' : 'Disabled', - 'APC' => $panel->data['php']['apc'] ? 'Enabled' : 'Disabled', - 'Memcache' => $panel->data['php']['memcache'] ? 'Enabled' : 'Disabled', - ], -]); -?> -
    'btn btn-primary']) ?>
    diff --git a/extensions/yii/debug/views/default/panels/config/summary.php b/extensions/yii/debug/views/default/panels/config/summary.php deleted file mode 100644 index 5ee3766..0000000 --- a/extensions/yii/debug/views/default/panels/config/summary.php +++ /dev/null @@ -1,17 +0,0 @@ - - -
    - data['php']['version'], ['phpinfo'], ['title' => 'Show phpinfo()']) ?> -
    diff --git a/extensions/yii/debug/views/default/panels/config/table.php b/extensions/yii/debug/views/default/panels/config/table.php deleted file mode 100644 index 0dc2d8d..0000000 --- a/extensions/yii/debug/views/default/panels/config/table.php +++ /dev/null @@ -1,35 +0,0 @@ - - -

    - - - -

    Empty.

    - - - - - - - - - - - - $value): ?> - - - - - - -
    NameValue
    - - diff --git a/extensions/yii/debug/views/default/panels/db/detail.php b/extensions/yii/debug/views/default/panels/db/detail.php deleted file mode 100644 index ee5b2a5..0000000 --- a/extensions/yii/debug/views/default/panels/db/detail.php +++ /dev/null @@ -1,69 +0,0 @@ - -

    Database Queries

    - - $dataProvider, - 'id' => 'db-panel-detailed-grid', - 'options' => ['class' => 'detail-grid-view'], - 'filterModel' => $searchModel, - 'filterUrl' => $panel->getUrl(), - 'columns' => [ - ['class' => 'yii\grid\SerialColumn'], - [ - 'attribute' => 'seq', - 'label' => 'Time', - 'value' => function ($data) { - $timeInSeconds = $data['timestamp'] / 1000; - $millisecondsDiff = (int)(($timeInSeconds - (int)$timeInSeconds) * 1000); - return date('H:i:s.', $timeInSeconds) . sprintf('%03d', $millisecondsDiff); - }, - 'headerOptions' => [ - 'class' => 'sort-numerical' - ] - ], - [ - 'attribute' => 'duration', - 'value' => function ($data) { - return sprintf('%.1f ms', $data['duration']); - }, - 'options' => [ - 'width' => '10%', - ], - 'headerOptions' => [ - 'class' => 'sort-numerical' - ] - ], - [ - 'attribute' => 'type', - 'value' => function ($data) { - return Html::encode(mb_strtoupper($data['type'], 'utf8')); - }, - ], - [ - 'attribute' => 'query', - 'value' => function ($data) { - $query = Html::encode($data['query']); - - if (!empty($data['trace'])) { - $query .= Html::ul($data['trace'], [ - 'class' => 'trace', - 'item' => function ($trace) { - return "
  • {$trace['file']} ({$trace['line']})
  • "; - }, - ]); - } - return $query; - }, - 'format' => 'html', - 'options' => [ - 'width' => '60%', - ], - ] - ], -]); -?> diff --git a/extensions/yii/debug/views/default/panels/db/summary.php b/extensions/yii/debug/views/default/panels/db/summary.php deleted file mode 100644 index 122999c..0000000 --- a/extensions/yii/debug/views/default/panels/db/summary.php +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/extensions/yii/debug/views/default/panels/log/detail.php b/extensions/yii/debug/views/default/panels/log/detail.php deleted file mode 100644 index 83f9817..0000000 --- a/extensions/yii/debug/views/default/panels/log/detail.php +++ /dev/null @@ -1,73 +0,0 @@ - -

    Log Messages

    - $dataProvider, - 'id' => 'log-panel-detailed-grid', - 'options' => ['class' => 'detail-grid-view'], - 'filterModel' => $searchModel, - 'filterUrl' => $panel->getUrl(), - 'rowOptions' => function ($model, $key, $index, $grid) { - switch($model['level']) { - case Logger::LEVEL_ERROR : return ['class' => 'danger']; - case Logger::LEVEL_WARNING : return ['class' => 'warning']; - case Logger::LEVEL_INFO : return ['class' => 'success']; - default: return []; - } - }, - 'columns' => [ - ['class' => 'yii\grid\SerialColumn'], - [ - 'attribute' => 'time', - 'value' => function ($data) { - $timeInSeconds = $data['time'] / 1000; - $millisecondsDiff = (int)(($timeInSeconds - (int)$timeInSeconds) * 1000); - return date('H:i:s.',$timeInSeconds) . sprintf('%03d',$millisecondsDiff); - }, - 'headerOptions' => [ - 'class' => 'sort-numerical' - ] - ], - [ - 'attribute' => 'level', - 'value' => function ($data) { - return Logger::getLevelName($data['level']); - }, - 'filter' => [ - Logger::LEVEL_TRACE => ' Trace ', - Logger::LEVEL_INFO => ' Info ', - Logger::LEVEL_WARNING => ' Warning ', - Logger::LEVEL_ERROR => ' Error ', - ], - ], - 'category', - [ - 'attribute' => 'message', - 'value' => function ($data) { - $message = nl2br(Html::encode($data['message'])); - - if (!empty($data['trace'])) { - $message .= Html::ul($data['trace'], [ - 'class' => 'trace', - 'item' => function ($trace) { - return "
  • {$trace['file']} ({$trace['line']})
  • "; - } - ]); - }; - - return $message; - }, - 'format' => 'html', - 'options' => [ - 'width' => '50%', - ], - ], - ], -]); -?> \ No newline at end of file diff --git a/extensions/yii/debug/views/default/panels/log/summary.php b/extensions/yii/debug/views/default/panels/log/summary.php deleted file mode 100644 index a8a931b..0000000 --- a/extensions/yii/debug/views/default/panels/log/summary.php +++ /dev/null @@ -1,28 +0,0 @@ - - -$errorCount"; - $title .= ", $errorCount errors"; -} - -if ($warningCount) { - $output[] = "$warningCount"; - $title .= ", $warningCount warnings"; -} -?> - - diff --git a/extensions/yii/debug/views/default/panels/profile/detail.php b/extensions/yii/debug/views/default/panels/profile/detail.php deleted file mode 100644 index 95c50e1..0000000 --- a/extensions/yii/debug/views/default/panels/profile/detail.php +++ /dev/null @@ -1,53 +0,0 @@ - -

    Performance Profiling

    -

    Total processing time: ; Peak memory: .

    - $dataProvider, - 'id' => 'profile-panel-detailed-grid', - 'options' => ['class' => 'detail-grid-view'], - 'filterModel' => $searchModel, - 'filterUrl' => $panel->getUrl(), - 'columns' => [ - ['class' => 'yii\grid\SerialColumn'], - [ - 'attribute' => 'seq', - 'label' => 'Time', - 'value' => function ($data) { - $timeInSeconds = $data['timestamp'] / 1000; - $millisecondsDiff = (int)(($timeInSeconds - (int)$timeInSeconds) * 1000); - return date('H:i:s.', $timeInSeconds) . sprintf('%03d', $millisecondsDiff); - }, - 'headerOptions' => [ - 'class' => 'sort-numerical' - ] - ], - [ - 'attribute' => 'duration', - 'value' => function ($data) { - return sprintf('%.1f ms',$data['duration']); - }, - 'options' => [ - 'width' => '10%', - ], - 'headerOptions' => [ - 'class' => 'sort-numerical' - ] - ], - 'category', - [ - 'attribute' => 'info', - 'value' => function ($data) { - return str_repeat('', $data['level']) . Html::encode($data['info']); - }, - 'format' => 'html', - 'options' => [ - 'width' => '60%', - ], - ], - ], -]); -?> diff --git a/extensions/yii/debug/views/default/panels/profile/summary.php b/extensions/yii/debug/views/default/panels/profile/summary.php deleted file mode 100644 index f12ea88..0000000 --- a/extensions/yii/debug/views/default/panels/profile/summary.php +++ /dev/null @@ -1,6 +0,0 @@ -
    - Time -
    - diff --git a/extensions/yii/debug/views/default/panels/request/detail.php b/extensions/yii/debug/views/default/panels/request/detail.php deleted file mode 100644 index cca0af2..0000000 --- a/extensions/yii/debug/views/default/panels/request/detail.php +++ /dev/null @@ -1,35 +0,0 @@ - [ - [ - 'label' => 'Parameters', - 'content' => $this->render('panels/request/table', ['caption' => 'Routing', 'values' => ['Route' => $panel->data['route'], 'Action' => $panel->data['action'], 'Parameters' => $panel->data['actionParams']]]) - . $this->render('panels/request/table', ['caption' => '$_GET', 'values' => $panel->data['GET']]) - . $this->render('panels/request/table', ['caption' => '$_POST', 'values' => $panel->data['POST']]) - . $this->render('panels/request/table', ['caption' => '$_FILES', 'values' => $panel->data['FILES']]) - . $this->render('panels/request/table', ['caption' => '$_COOKIE', 'values' => $panel->data['COOKIE']]), - 'active' => true, - ], - [ - 'label' => 'Headers', - 'content' => $this->render('panels/request/table', ['caption' => 'Request Headers', 'values' => $panel->data['requestHeaders']]) - . $this->render('panels/request/table', ['caption' => 'Response Headers', 'values' => $panel->data['responseHeaders']]) - ], - [ - 'label' => 'Session', - 'content' => $this->render('panels/request/table', ['caption' => '$_SESSION', 'values' => $panel->data['SESSION']]) - . $this->render('panels/request/table', ['caption' => 'Flashes', 'values' => $panel->data['flashes']]) - ], - [ - 'label' => '$_SERVER', - 'content' => $this->render('panels/request/table', ['caption' => '$_SERVER', 'values' => $panel->data['SERVER']]), - ], - ], -]); -?> diff --git a/extensions/yii/debug/views/default/panels/request/summary.php b/extensions/yii/debug/views/default/panels/request/summary.php deleted file mode 100644 index ca4386f..0000000 --- a/extensions/yii/debug/views/default/panels/request/summary.php +++ /dev/null @@ -1,27 +0,0 @@ -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] : ''); -?> - - diff --git a/extensions/yii/debug/views/default/panels/request/table.php b/extensions/yii/debug/views/default/panels/request/table.php deleted file mode 100644 index c5a5d89..0000000 --- a/extensions/yii/debug/views/default/panels/request/table.php +++ /dev/null @@ -1,34 +0,0 @@ - -

    - - - -

    Empty.

    - - - - - - - - - - - - $value): ?> - - - - - - -
    NameValue
    charset, true) ?>
    - - diff --git a/extensions/yii/debug/views/default/toolbar.php b/extensions/yii/debug/views/default/toolbar.php deleted file mode 100644 index 6d3146f..0000000 --- a/extensions/yii/debug/views/default/toolbar.php +++ /dev/null @@ -1,39 +0,0 @@ -getUrl(); -?> -
    - - getSummary() ?> - - -
    -
    - - -
    diff --git a/extensions/yii/debug/views/default/view.php b/extensions/yii/debug/views/default/view.php deleted file mode 100644 index 6b3bdca..0000000 --- a/extensions/yii/debug/views/default/view.php +++ /dev/null @@ -1,78 +0,0 @@ -title = 'Yii Debugger'; -?> -
    -
    -
    - 'Back to main debug page']) ?> -
    - - 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/yii/debug/views/layouts/main.php b/extensions/yii/debug/views/layouts/main.php deleted file mode 100644 index b3a751f..0000000 --- a/extensions/yii/debug/views/layouts/main.php +++ /dev/null @@ -1,25 +0,0 @@ - -beginPage() ?> - - - - - - <?= Html::encode($this->title) ?> - head() ?> - - -beginBody() ?> - -endBody() ?> - - -endPage() ?> diff --git a/extensions/yii/elasticsearch/ActiveQuery.php b/extensions/yii/elasticsearch/ActiveQuery.php deleted file mode 100644 index d67327c..0000000 --- a/extensions/yii/elasticsearch/ActiveQuery.php +++ /dev/null @@ -1,221 +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); - } - /** @var ActiveRecord $modelClass */ - $modelClass = $this->modelClass; - $pk = $modelClass::primaryKey()[0]; - if ($this->asArray && $this->indexBy) { - foreach ($result['hits']['hits'] as &$row) { - if ($pk === '_id') { - $row['_source']['_id'] = $row['_id']; - } - $row['_source']['_score'] = $row['_score']; - $row = $row['_source']; - } - unset($row); - } - $models = $this->createModels($result['hits']['hits']); - if ($this->asArray && !$this->indexBy) { - foreach($models as $key => $model) { - if ($pk === '_id') { - $model['_source']['_id'] = $model['_id']; - } - $model['_source']['_score'] = $model['_score']; - $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) { - /** @var ActiveRecord $modelClass */ - $modelClass = $this->modelClass; - $model = $result['_source']; - $pk = $modelClass::primaryKey()[0]; - if ($pk === '_id') { - $model['_id'] = $result['_id']; - } - $model['_score'] = $result['_score']; - } 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) { - /** @var ActiveRecord $modelClass */ - $modelClass = $this->modelClass; - $pk = $modelClass::primaryKey()[0]; - foreach($models as $key => $model) { - if ($pk === '_id') { - $model['_source']['_id'] = $model['_id']; - } - $model['_source']['_score'] = $model['_score']; - $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 == '_id') { - return $record['_id']; - } elseif (isset($record['_source'][$field])) { - return $record['_source'][$field]; - } - } - return null; - } - - /** - * @inheritdoc - */ - public function column($field, $db = null) - { - if ($field == '_id') { - $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/yii/elasticsearch/ActiveRecord.php b/extensions/yii/elasticsearch/ActiveRecord.php deleted file mode 100644 index f91df2c..0000000 --- a/extensions/yii/elasticsearch/ActiveRecord.php +++ /dev/null @@ -1,532 +0,0 @@ - - * @since 2.0 - */ -class ActiveRecord extends BaseActiveRecord -{ - private $_id; - private $_score; - 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)) { - return $query->andWhere($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 - - /** - * @return float returns the score of this record when it was retrieved via a [[find()]] query. - */ - public function getScore() - { - return $this->_score; - } - - /** - * Sets the primary key - * @param mixed $value - * @throws \yii\base\InvalidCallException when record is not new - */ - public function setPrimaryKey($value) - { - $pk = static::primaryKey()[0]; - if ($this->getIsNewRecord() || $pk != '_id') { - $this->$pk = $value; - } else { - throw new InvalidCallException('Changing the primaryKey of an already saved record is not allowed.'); - } - } - - /** - * @inheritdoc - */ - public function getPrimaryKey($asArray = false) - { - $pk = static::primaryKey()[0]; - if ($asArray) { - return [$pk => $this->$pk]; - } else { - return $this->$pk; - } - } - - /** - * @inheritdoc - */ - public function getOldPrimaryKey($asArray = false) - { - $pk = static::primaryKey()[0]; - if ($this->getIsNewRecord()) { - $id = null; - } elseif ($pk == '_id') { - $id = $this->_id; - } else { - $id = $this->getOldAttribute($pk); - } - if ($asArray) { - return [$pk => $id]; - } else { - return $id; - } - } - - /** - * This method defines the attribute that uniquely identifies a record. - * - * The primaryKey for elasticsearch documents is the `_id` field by default. This field is not part of the - * ActiveRecord attributes so you should never add `_id` to the list of [[attributes()|attributes]]. - * - * You may overide this method to define the primary key name when you have defined - * [path mapping](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-id-field.html) - * for the `_id` field so that it is part of the `_source` and thus part of the [[attributes()|attributes]]. - * - * Note that elasticsearch only supports _one_ attribute to be the primary key. However to match the signature - * of the [[\yii\db\ActiveRecordInterface|ActiveRecordInterface]] this methods returns an array instead of a - * single string. - * - * @return string[] array of primary key attributes. Only the first element of the array will be used. - */ - public static function primaryKey() - { - return ['_id']; - } - - /** - * Returns the list of all attribute names of the model. - * - * This method must be overridden by child classes to define available attributes. - * - * Attributes are names of fields of the corresponding elasticsearch document. - * The primaryKey for elasticsearch documents is the `_id` field by default which is not part of the attributes. - * You may define [path mapping](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-id-field.html) - * for the `_id` field so that it is part of the `_source` fields and thus becomes part of the attributes. - * - * @return string[] 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) - { - $record = parent::create($row['_source']); - $pk = static::primaryKey()[0]; - $record->$pk = $row['_id']; - $record->_score = isset($row['_score']) ? $row['_score'] : null; - $record->_version = isset($row['_version']) ? $row['_version'] : null; // TODO version should always be available... - 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 (!isset($response['ok'])) { - return false; - } - $pk = static::primaryKey()[0]; - $this->$pk = $response['_id']; - if ($pk != '_id') { - $values[$pk] = $response['_id']; - } - $this->_version = $response['_version']; - $this->_score = null; - $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 = []) - { - $pkName = static::primaryKey()[0]; - if (count($condition) == 1 && isset($condition[$pkName])) { - $primaryKeys = is_array($condition[$pkName]) ? $condition[$pkName] : [$condition[$pkName]]; - } else { - $primaryKeys = static::find()->where($condition)->column($pkName); // TODO check whether this works with default pk _id - } - if (empty($primaryKeys)) { - return 0; - } - $bulk = ''; - foreach($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; - $errors = []; - foreach($response['items'] as $item) { - if (isset($item['update']['error'])) { - $errors[] = $item['update']; - } elseif ($item['update']['ok']) { - $n++; - } - } - if (!empty($errors)) { - throw new Exception(__METHOD__ . ' failed updating records.', $errors); - } - 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 = []) - { - $pkName = static::primaryKey()[0]; - if (count($condition) == 1 && isset($condition[$pkName])) { - $primaryKeys = is_array($condition[$pkName]) ? $condition[$pkName] : [$condition[$pkName]]; - } else { - $primaryKeys = static::find()->where($condition)->column($pkName); // TODO check whether this works with default pk _id - } - if (empty($primaryKeys) || empty($counters)) { - return 0; - } - $bulk = ''; - foreach($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; - $errors = []; - foreach($response['items'] as $item) { - if (isset($item['update']['error'])) { - $errors[] = $item['update']; - } elseif ($item['update']['ok']) { - $n++; - } - } - if (!empty($errors)) { - throw new Exception(__METHOD__ . ' failed updating records counters.', $errors); - } - 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 = []) - { - $pkName = static::primaryKey()[0]; - if (count($condition) == 1 && isset($condition[$pkName])) { - $primaryKeys = is_array($condition[$pkName]) ? $condition[$pkName] : [$condition[$pkName]]; - } else { - $primaryKeys = static::find()->where($condition)->column($pkName); // TODO check whether this works with default pk _id - } - if (empty($primaryKeys)) { - return 0; - } - $bulk = ''; - foreach($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; - $errors = []; - foreach($response['items'] as $item) { - if (isset($item['delete']['error'])) { - $errors[] = $item['delete']; - } elseif ($item['delete']['found'] && $item['delete']['ok']) { - $n++; - } - } - if (!empty($errors)) { - throw new Exception(__METHOD__ . ' failed deleting records.', $errors); - } - return $n; - } -} diff --git a/extensions/yii/elasticsearch/ActiveRelation.php b/extensions/yii/elasticsearch/ActiveRelation.php deleted file mode 100644 index a102697..0000000 --- a/extensions/yii/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/yii/elasticsearch/CHANGELOG.md b/extensions/yii/elasticsearch/CHANGELOG.md deleted file mode 100644 index 55d52af..0000000 --- a/extensions/yii/elasticsearch/CHANGELOG.md +++ /dev/null @@ -1,14 +0,0 @@ -Yii Framework 2 elasticsearch extension Change Log -================================================== - -2.0.0 beta under development ----------------------------- - -- Enh #1382: Added a debug toolbar panel for elasticsearch (cebe) -- Enh #1765: Added support for primary key path mapping, pk can now be part of the attributes when mapping is defined (cebe) -- Chg #1765: Changed handling of ActiveRecord primary keys, removed getId(), use getPrimaryKey() instead (cebe) - -2.0.0 alpha, December 1, 2013 ------------------------------ - -- Initial release. diff --git a/extensions/yii/elasticsearch/Command.php b/extensions/yii/elasticsearch/Command.php deleted file mode 100644 index 9ea4a60..0000000 --- a/extensions/yii/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 chosen - * @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/yii/elasticsearch/Connection.php b/extensions/yii/elasticsearch/Connection.php deleted file mode 100644 index 75de7a3..0000000 --- a/extensions/yii/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/yii/elasticsearch/DebugAction.php b/extensions/yii/elasticsearch/DebugAction.php deleted file mode 100644 index d4ddd41..0000000 --- a/extensions/yii/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/yii/elasticsearch/DebugPanel.php b/extensions/yii/elasticsearch/DebugPanel.php deleted file mode 100644 index 1782b8d..0000000 --- a/extensions/yii/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/yii/elasticsearch/Exception.php b/extensions/yii/elasticsearch/Exception.php deleted file mode 100644 index 1736dec..0000000 --- a/extensions/yii/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 'Elasticsearch Database Exception'; - } -} \ No newline at end of file diff --git a/extensions/yii/elasticsearch/LICENSE.md b/extensions/yii/elasticsearch/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/extensions/yii/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/yii/elasticsearch/Query.php b/extensions/yii/elasticsearch/Query.php deleted file mode 100644 index f404fc1..0000000 --- a/extensions/yii/elasticsearch/Query.php +++ /dev/null @@ -1,502 +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'; - return $this->createCommand($db)->search($options)['hits']['total']; - } - - /** - * 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/yii/elasticsearch/QueryBuilder.php b/extensions/yii/elasticsearch/QueryBuilder.php deleted file mode 100644 index aa37471..0000000 --- a/extensions/yii/elasticsearch/QueryBuilder.php +++ /dev/null @@ -1,311 +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 == '_id') { - $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( - 'not' => 'buildNotCondition', - '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 == '_id') { - 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 buildNotCondition($operator, $operands, &$params) - { - if (count($operands) != 1) { - throw new InvalidParamException("Operator '$operator' requires exactly one operand."); - } - - $operand = reset($operands); - if (is_array($operand)) { - $operand = $this->buildCondition($operand, $params); - } - return [$operator => $operand]; - } - - 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 == '_id') { - throw new NotSupportedException('Between condition is not supported for the _id field.'); - } - $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 == '_id') { - 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 are not supported by elasticsearch.'); - } -} diff --git a/extensions/yii/elasticsearch/README-debug.png b/extensions/yii/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 --prefer-dist 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 handling of primary keys is different in elasticsearch as the primary key (the `_id` field in elasticsearch terms) -is not part of the attributes by default. However it is possible to define a [path mapping](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-id-field.html) -for the `_id` field to be part of the attributes. -See [elasticsearch docs](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-id-field.html) on how to define it. -The `_id` field of a document/record can be accessed using [[ActiveRecord::getPrimaryKey()]] and [[ActiveRecord::setPrimaryKey()]]. -When path mapping is defined, the attribute name can be defined using the [[primaryKey()]] method. - -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() - { - // path mapping for '_id' is setup to field 'id' - 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 no tables in elasticsearch. You can only define relations via other records. -- As elasticsearch is not only a data storage but also a 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. - -Usage example: - -```php -$customer = new Customer(); -$customer->primaryKey = 1; // in this case equivalent to $customer->id = 1; -$customer->attributes = ['name' => 'test']; -$customer->save(); - -$customer = Customer::get(1); // get a record by pk -$customers = Customer::mget([1,2,3]); // get multiple records 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 -and shows the executed elasticsearch queries. It also allows to run these queries -and view the results. - -Add the following to you application config to enable it (if you already have the debug module -enabled, it is sufficient to just add the panels configuration): - -```php - // ... - 'preload' => 'debug', - 'modules' => [ - 'debug' => [ - 'class' => 'yii\\debug\\Module', - 'panels' => [ - 'elasticsearch' => [ - 'class' => 'yii\\elasticsearch\\DebugPanel', - ], - ], - ], - ], - // ... -``` - -![elasticsearch DebugPanel](README-debug.png) - - -Relation definitions with records whose primary keys are not part of attributes -------------------------------------------------------------------------------- - -TODO - - -Patterns --------- - -### Fetching records from different indexes/types - -TODO diff --git a/extensions/yii/elasticsearch/composer.json b/extensions/yii/elasticsearch/composer.json deleted file mode 100644 index c72cd81..0000000 --- a/extensions/yii/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/yii/gii/CHANGELOG.md b/extensions/yii/gii/CHANGELOG.md deleted file mode 100644 index 0174387..0000000 --- a/extensions/yii/gii/CHANGELOG.md +++ /dev/null @@ -1,13 +0,0 @@ -Yii Framework 2 gii extension Change Log -======================================== - -2.0.0 beta under development ----------------------------- - -- Bug #1405: fixed disambiguation of relation names generated by gii (qiangxue) -- Enh #1624: generate rules for unique indexes (lucianobaraglia) - -2.0.0 alpha, December 1, 2013 ------------------------------ - -- Initial release. diff --git a/extensions/yii/gii/CodeFile.php b/extensions/yii/gii/CodeFile.php deleted file mode 100644 index a5196d9..0000000 --- a/extensions/yii/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/yii/gii/Generator.php b/extensions/yii/gii/Generator.php deleted file mode 100644 index 05c45a7..0000000 --- a/extensions/yii/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/yii/gii/GiiAsset.php b/extensions/yii/gii/GiiAsset.php deleted file mode 100644 index b100750..0000000 --- a/extensions/yii/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/yii/gii/Module.php b/extensions/yii/gii/Module.php deleted file mode 100644 index a7bb3ed..0000000 --- a/extensions/yii/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/yii/gii/README.md b/extensions/yii/gii/README.md deleted file mode 100644 index 9611960..0000000 --- a/extensions/yii/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 --prefer-dist 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/yii/gii/assets/gii.js b/extensions/yii/gii/assets/gii.js deleted file mode 100644 index a95221e..0000000 --- a/extensions/yii/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/yii/gii/assets/logo.png b/extensions/yii/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/yii/gii/assets/main.css b/extensions/yii/gii/assets/main.css deleted file mode 100644 index 94d7dd2..0000000 --- a/extensions/yii/gii/assets/main.css +++ /dev/null @@ -1,219 +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; -} - -.error-summary { - color: #a94442; - background: #fdf7f7; - border-left: 3px solid #eed3d7; - padding: 10px 20px; - margin: 0 0 15px 0; -} - -.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/yii/gii/assets/typeahead.js b/extensions/yii/gii/assets/typeahead.js deleted file mode 100644 index 9365bd6..0000000 --- a/extensions/yii/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/yii/gii/assets/typeahead.js-bootstrap.css b/extensions/yii/gii/assets/typeahead.js-bootstrap.css deleted file mode 100644 index 987aaf5..0000000 --- a/extensions/yii/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/yii/gii/components/ActiveField.php b/extensions/yii/gii/components/ActiveField.php deleted file mode 100644 index ae6f144..0000000 --- a/extensions/yii/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/yii/gii/composer.json b/extensions/yii/gii/composer.json deleted file mode 100644 index 4e17844..0000000 --- a/extensions/yii/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/yii/gii/controllers/DefaultController.php b/extensions/yii/gii/controllers/DefaultController.php deleted file mode 100644 index 2b3bf00..0000000 --- a/extensions/yii/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/yii/gii/generators/controller/Generator.php b/extensions/yii/gii/generators/controller/Generator.php deleted file mode 100644 index 08b29d5..0000000 --- a/extensions/yii/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/yii/gii/generators/controller/form.php b/extensions/yii/gii/generators/controller/form.php deleted file mode 100644 index 4fba36f..0000000 --- a/extensions/yii/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/yii/gii/generators/controller/templates/controller.php b/extensions/yii/gii/generators/controller/templates/controller.php deleted file mode 100644 index b62edc3..0000000 --- a/extensions/yii/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/yii/gii/generators/controller/templates/view.php b/extensions/yii/gii/generators/controller/templates/view.php deleted file mode 100644 index 6ef2a87..0000000 --- a/extensions/yii/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/yii/gii/generators/crud/Generator.php b/extensions/yii/gii/generators/crud/Generator.php deleted file mode 100644 index bbd2ab5..0000000 --- a/extensions/yii/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/yii/gii/generators/crud/form.php b/extensions/yii/gii/generators/crud/form.php deleted file mode 100644 index 1b101c2..0000000 --- a/extensions/yii/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/yii/gii/generators/crud/templates/controller.php b/extensions/yii/gii/generators/crud/templates/controller.php deleted file mode 100644 index bb5d3f4..0000000 --- a/extensions/yii/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/yii/gii/generators/crud/templates/search.php b/extensions/yii/gii/generators/crud/templates/search.php deleted file mode 100644 index bc55c60..0000000 --- a/extensions/yii/gii/generators/crud/templates/search.php +++ /dev/null @@ -1,82 +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) { - $query->andWhere(['like', $attribute, $value]); - } else { - $query->andWhere([$attribute => $value]); - } - } -} diff --git a/extensions/yii/gii/generators/crud/templates/views/_form.php b/extensions/yii/gii/generators/crud/templates/views/_form.php deleted file mode 100644 index 52538d5..0000000 --- a/extensions/yii/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/yii/gii/generators/crud/templates/views/_search.php b/extensions/yii/gii/generators/crud/templates/views/_search.php deleted file mode 100644 index af2f948..0000000 --- a/extensions/yii/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/yii/gii/generators/crud/templates/views/create.php b/extensions/yii/gii/generators/crud/templates/views/create.php deleted file mode 100644 index 68d08ba..0000000 --- a/extensions/yii/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/yii/gii/generators/crud/templates/views/index.php b/extensions/yii/gii/generators/crud/templates/views/index.php deleted file mode 100644 index a4f5f0d..0000000 --- a/extensions/yii/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/yii/gii/generators/crud/templates/views/update.php b/extensions/yii/gii/generators/crud/templates/views/update.php deleted file mode 100644 index 2fbbecf..0000000 --- a/extensions/yii/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/yii/gii/generators/crud/templates/views/view.php b/extensions/yii/gii/generators/crud/templates/views/view.php deleted file mode 100644 index 9e74aff..0000000 --- a/extensions/yii/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/yii/gii/generators/form/Generator.php b/extensions/yii/gii/generators/form/Generator.php deleted file mode 100644 index 3bc0be6..0000000 --- a/extensions/yii/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/yii/gii/generators/form/form.php b/extensions/yii/gii/generators/form/form.php deleted file mode 100644 index 3d46777..0000000 --- a/extensions/yii/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/yii/gii/generators/form/templates/action.php b/extensions/yii/gii/generators/form/templates/action.php deleted file mode 100644 index 9e6840d..0000000 --- a/extensions/yii/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/yii/gii/generators/form/templates/form.php b/extensions/yii/gii/generators/form/templates/form.php deleted file mode 100644 index b30570c..0000000 --- a/extensions/yii/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/yii/gii/generators/model/Generator.php b/extensions/yii/gii/generators/model/Generator.php deleted file mode 100644 index b234b47..0000000 --- a/extensions/yii/gii/generators/model/Generator.php +++ /dev/null @@ -1,588 +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]"; - } - - // Unique indexes rules - try { - $db = $this->getDbConnection(); - $uniqueIndexes = $db->getSchema()->findUniqueIndexes($table); - foreach ($uniqueIndexes as $indexName => $uniqueColumns) { - // Avoid validating auto incrementable columns - if (!$this->isUniqueColumnAutoIncrementable($table, $uniqueColumns)) { - $attributesCount = count($uniqueColumns); - - if ($attributesCount == 1) { - $rules[] = "[['" . $uniqueColumns[0] . "'], 'unique']"; - } elseif ($attributesCount > 1) { - $labels = array_intersect_key($this->generateLabels($table), array_flip($uniqueColumns)); - $lastLabel = array_pop($labels); - $columnsList = implode("', '", $uniqueColumns); - $rules[] = "[['" . $columnsList . "'], 'unique', 'targetAttribute' => ['" . $columnsList . "'], 'message' => 'The combination of " . implode(', ', $labels) . " and " . $lastLabel . " has already been taken.']"; - } - } - } - } catch (NotSupportedException $e) { - // doesn't support unique indexes information...do nothing - } - 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) . '$/'; - } - $patterns[] = "/^{$db->tablePrefix}(.*?)$/"; - $patterns[] = "/^(.*?){$db->tablePrefix}$/"; - $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}; - } - - /** - * Checks if any of the specified columns of an unique index is auto incrementable. - * @param \yii\db\TableSchema $table the table schema - * @param array $columns columns to check for autoIncrement property - * @return boolean whether any of the specified columns is auto incrementable. - */ - protected function isUniqueColumnAutoIncrementable($table, $columns) - { - foreach ($columns as $column) { - if ($table->columns[$column]->autoIncrement) { - return true; - } - } - return false; - } -} diff --git a/extensions/yii/gii/generators/model/form.php b/extensions/yii/gii/generators/model/form.php deleted file mode 100644 index ddc40f8..0000000 --- a/extensions/yii/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/yii/gii/generators/model/templates/model.php b/extensions/yii/gii/generators/model/templates/model.php deleted file mode 100644 index dcd1461..0000000 --- a/extensions/yii/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/yii/gii/generators/module/Generator.php b/extensions/yii/gii/generators/module/Generator.php deleted file mode 100644 index a97aa20..0000000 --- a/extensions/yii/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/yii/gii/generators/module/form.php b/extensions/yii/gii/generators/module/form.php deleted file mode 100644 index 2874d90..0000000 --- a/extensions/yii/gii/generators/module/form.php +++ /dev/null @@ -1,13 +0,0 @@ - -
    -field($generator, 'moduleClass'); - echo $form->field($generator, 'moduleID'); -?> -
    diff --git a/extensions/yii/gii/generators/module/templates/controller.php b/extensions/yii/gii/generators/module/templates/controller.php deleted file mode 100644 index 018450c..0000000 --- a/extensions/yii/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/yii/gii/generators/module/templates/module.php b/extensions/yii/gii/generators/module/templates/module.php deleted file mode 100644 index 72b32be..0000000 --- a/extensions/yii/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/yii/gii/generators/module/templates/view.php b/extensions/yii/gii/generators/module/templates/view.php deleted file mode 100644 index f5f4248..0000000 --- a/extensions/yii/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/yii/gii/views/default/diff.php b/extensions/yii/gii/views/default/diff.php deleted file mode 100644 index 6ee91a1..0000000 --- a/extensions/yii/gii/views/default/diff.php +++ /dev/null @@ -1,15 +0,0 @@ - -
    - -
    Diff is not supported for this file type.
    - -
    Identical.
    - -
    - -
    diff --git a/extensions/yii/gii/views/default/index.php b/extensions/yii/gii/views/default/index.php deleted file mode 100644 index 2e48816..0000000 --- a/extensions/yii/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/yii/gii/views/default/view.php b/extensions/yii/gii/views/default/view.php deleted file mode 100644 index d600f83..0000000 --- a/extensions/yii/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/yii/gii/views/default/view/files.php b/extensions/yii/gii/views/default/view/files.php deleted file mode 100644 index d8d5f0f..0000000 --- a/extensions/yii/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/yii/gii/views/default/view/results.php b/extensions/yii/gii/views/default/view/results.php deleted file mode 100644 index 0e9b7d9..0000000 --- a/extensions/yii/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/yii/gii/views/layouts/generator.php b/extensions/yii/gii/views/layouts/generator.php deleted file mode 100644 index d4c205a..0000000 --- a/extensions/yii/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/yii/gii/views/layouts/main.php b/extensions/yii/gii/views/layouts/main.php deleted file mode 100644 index f324e41..0000000 --- a/extensions/yii/gii/views/layouts/main.php +++ /dev/null @@ -1,54 +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' => 'https://github.com/yiisoft/yii2/blob/master/docs/guide/gii.md'], - ['label' => 'Application', 'url' => Yii::$app->homeUrl], - ], -]); -NavBar::end(); -?> - -
    - -
    - - - -endBody() ?> - - -endPage() ?> diff --git a/extensions/yii/imagine/BaseImage.php b/extensions/yii/imagine/BaseImage.php deleted file mode 100644 index da4e016..0000000 --- a/extensions/yii/imagine/BaseImage.php +++ /dev/null @@ -1,255 +0,0 @@ - - * @author Qiang Xue - * @since 2.0 - */ -class BaseImage -{ - /** - * GD2 driver definition for Imagine implementation using the GD library. - */ - const DRIVER_GD2 = 'gd2'; - /** - * imagick driver definition. - */ - const DRIVER_IMAGICK = 'imagick'; - /** - * gmagick driver definition. - */ - const DRIVER_GMAGICK = 'gmagick'; - /** - * @var array|string the driver to use. This can be either a single driver name or an array of driver names. - * If the latter, the first available driver will be used. - */ - public static $driver = [self::DRIVER_GMAGICK, self::DRIVER_IMAGICK, self::DRIVER_GD2]; - - /** - * @var ImagineInterface instance. - */ - private static $_imagine; - - /** - * Returns the `Imagine` object that supports various image manipulations. - * @return ImagineInterface the `Imagine` object - */ - public static function getImagine() - { - if (self::$_imagine === null) { - self::$_imagine = static::createImagine(); - } - return self::$_imagine; - } - - /** - * @param ImagineInterface $imagine the `Imagine` object. - */ - public static function setImagine($imagine) - { - self::$_imagine = $imagine; - } - - /** - * Creates an `Imagine` object based on the specified [[driver]]. - * @return ImagineInterface the new `Imagine` object - * @throws InvalidConfigException if [[driver]] is unknown or the system doesn't support any [[driver]]. - */ - protected static function createImagine() - { - foreach ((array)static::$driver as $driver) { - switch ($driver) { - case self::DRIVER_GMAGICK: - if (class_exists('Gmagick', false)) { - return new \Imagine\Gmagick\Imagine(); - } - break; - case self::DRIVER_IMAGICK: - if (class_exists('Imagick', false)) { - return new \Imagine\Imagick\Imagine(); - } - break; - case self::DRIVER_GD2: - if (function_exists('gd_info')) { - return new \Imagine\Gd\Imagine(); - } - break; - default: - throw new InvalidConfigException("Unknown driver: $driver"); - } - } - throw new InvalidConfigException("Your system does not support any of these drivers: " . implode(',', (array)static::$driver)); - } - - /** - * Crops an image. - * - * For example, - * - * ~~~ - * $obj->crop('path\to\image.jpg', 200, 200, [5, 5]); - * - * $point = new \Imagine\Image\Point(5, 5); - * $obj->crop('path\to\image.jpg', 200, 200, $point); - * ~~~ - * - * @param string $filename the image file path or path alias. - * @param integer $width the crop width - * @param integer $height the crop height - * @param array $start the starting point. This must be an array with two elements representing `x` and `y` coordinates. - * @return ImageInterface - * @throws InvalidParamException if the `$start` parameter is invalid - */ - public static function crop($filename, $width, $height, array $start = [0, 0]) - { - if (!isset($start[0], $start[1])) { - throw new InvalidParamException('$start must be an array of two elements.'); - } - - return static::getImagine() - ->open(Yii::getAlias($filename)) - ->copy() - ->crop(new Point($start[0], $start[1]), new Box($width, $height)); - } - - /** - * Creates a thumbnail image. The function differs from [[\Imagine\Image\ImageInterface::thumbnail()]] function that - * it keeps the aspect ratio of the image. - * @param string $filename the image file path or path alias. - * @param integer $width the width in pixels to create the thumbnail - * @param integer $height the height in pixels to create the thumbnail - * @param string $mode - * @return ImageInterface - */ - public static function thumbnail($filename, $width, $height, $mode = ManipulatorInterface::THUMBNAIL_OUTBOUND) - { - $box = new Box($width, $height); - $img = static::getImagine()->open(Yii::getAlias($filename)); - - if (($img->getSize()->getWidth() <= $box->getWidth() && $img->getSize()->getHeight() <= $box->getHeight()) || (!$box->getWidth() && !$box->getHeight())) { - return $img->copy(); - } - - $img = $img->thumbnail($box, $mode); - - // create empty image to preserve aspect ratio of thumbnail - $thumb = static::getImagine()->create($box); - - // calculate points - $size = $img->getSize(); - - $startX = 0; - $startY = 0; - if ($size->getWidth() < $width) { - $startX = ceil($width - $size->getWidth()) / 2; - } - if ($size->getHeight() < $height) { - $startY = ceil($height - $size->getHeight()) / 2; - } - - $thumb->paste($img, new Point($startX, $startY)); - - return $thumb; - } - - /** - * Adds a watermark to an existing image. - * @param string $filename the image file path or path alias. - * @param string $watermarkFilename the file path or path alias of the watermark image. - * @param array $start the starting point. This must be an array with two elements representing `x` and `y` coordinates. - * @return ImageInterface - * @throws InvalidParamException if `$start` is invalid - */ - public static function watermark($filename, $watermarkFilename, array $start = [0, 0]) - { - if (!isset($start[0], $start[1])) { - throw new InvalidParamException('$start must be an array of two elements.'); - } - - $img = static::getImagine()->open(Yii::getAlias($filename)); - $watermark = static::getImagine()->open(Yii::getAlias($watermarkFilename)); - $img->paste($watermark, new Point($start[0], $start[1])); - return $img; - } - - /** - * Draws a text string on an existing image. - * @param string $filename the image file path or path alias. - * @param string $text the text to write to the image - * @param string $fontFile the file path or path alias - * @param array $start the starting position of the text. This must be an array with two elements representing `x` and `y` coordinates. - * @param array $fontOptions the font options. The following options may be specified: - * - * - color: The font color. Defaults to "fff". - * - size: The font size. Defaults to 12. - * - angle: The angle to use to write the text. Defaults to 0. - * - * @return ImageInterface - * @throws InvalidParamException if `$fontOptions` is invalid - */ - public static function text($filename, $text, $fontFile, array $start = [0, 0], array $fontOptions = []) - { - if (!isset($start[0], $start[1])) { - throw new InvalidParamException('$start must be an array of two elements.'); - } - - $fontSize = ArrayHelper::getValue($fontOptions, 'size', 12); - $fontColor = ArrayHelper::getValue($fontOptions, 'color', 'fff'); - $fontAngle = ArrayHelper::getValue($fontOptions, 'angle', 0); - - $img = static::getImagine()->open(Yii::getAlias($filename)); - $font = static::getImagine()->font(Yii::getAlias($fontFile), $fontSize, new Color($fontColor)); - - $img->draw()->text($text, $font, new Point($start[0], $start[1]), $fontAngle); - - return $img; - } - - /** - * Adds a frame around of the image. Please note that the image size will increase by `$margin` x 2. - * @param string $filename the full path to the image file - * @param integer $margin the frame size to add around the image - * @param string $color the frame color - * @param integer $alpha the alpha value of the frame. - * @return ImageInterface - */ - public static function frame($filename, $margin = 20, $color = '666', $alpha = 100) - { - $img = static::getImagine()->open(Yii::getAlias($filename)); - - $size = $img->getSize(); - - $pasteTo = new Point($margin, $margin); - $padColor = new Color($color, $alpha); - - $box = new Box($size->getWidth() + ceil($margin * 2), $size->getHeight() + ceil($margin * 2)); - - $image = static::getImagine()->create($box, $padColor); - - $image->paste($img, $pasteTo); - - return $image; - } -} diff --git a/extensions/yii/imagine/CHANGELOG.md b/extensions/yii/imagine/CHANGELOG.md deleted file mode 100644 index b751ac2..0000000 --- a/extensions/yii/imagine/CHANGELOG.md +++ /dev/null @@ -1,7 +0,0 @@ -Yii Framework 2 imagine extension Change Log -================================================ - -2.0.0 beta under development ----------------------------- - -- Initial release. diff --git a/extensions/yii/imagine/Image.php b/extensions/yii/imagine/Image.php deleted file mode 100644 index 3a2d300..0000000 --- a/extensions/yii/imagine/Image.php +++ /dev/null @@ -1,29 +0,0 @@ -getBasePath() . '/web/img/test-image.jpg'; - * $runtimePath = Yii::$app->getRuntimePath(); - * Image::thumbnail('@app/web/img/test-image.jpg', 120, 120) - * ->save('thumb-test-image.jpg', ['quality' => 50]); - * ~~~ - * - * @author Antonio Ramirez - * @author Qiang Xue - * @since 2.0 - */ -class Image extends BaseImage -{ -} diff --git a/extensions/yii/imagine/LICENSE.md b/extensions/yii/imagine/LICENSE.md deleted file mode 100644 index 0bb1a8d..0000000 --- a/extensions/yii/imagine/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-2013 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/yii/imagine/README.md b/extensions/yii/imagine/README.md deleted file mode 100644 index 4979f0a..0000000 --- a/extensions/yii/imagine/README.md +++ /dev/null @@ -1,45 +0,0 @@ -Imagine Extension for Yii 2 -=========================== - -This extension adds most common image functions and also acts as a wrapper to [Imagine](http://imagine.readthedocs.org/) -image manipulation library. - -Installation ------------- - -The preferred way to install this extension is through [composer](http://getcomposer.org/download/). - -Either run - -``` -php composer.phar require --prefer-dist yiisoft/yii2-imagine "*" -``` - -or add - -```json -"yiisoft/yii2-imagine": "*" -``` - -to the `require` section of your composer.json. - - -Usage & Documentation ---------------------- - -This extension is a wrapper to the [Imagine](http://imagine.readthedocs.org/) and also adds the most commonly used -image manipulation methods. - -The following example shows how to use this extension: - -```php -use yii\imagine\Image; - -// frame, rotate and save an image -Image::frame('path/to/image.jpg', 5, '666', 0) - ->rotate(-8) - ->save('path/to/destination/image.jpg', ['quality' => 50]); -``` - -Note that each `Image` method returns an instance of `\Imagine\Image\ImageInterface`. -This means you can make use of the methods included in the `Imagine` library: diff --git a/extensions/yii/imagine/composer.json b/extensions/yii/imagine/composer.json deleted file mode 100644 index 7cfff10..0000000 --- a/extensions/yii/imagine/composer.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "yiisoft/yii2-imagine", - "description": "The Imagine integration for the Yii framework", - "keywords": ["yii", "imagine", "image", "helper"], - "type": "yii2-extension", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?labels=ext%3Aimagine", - "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": "Antonio Ramirez", - "email": "amigo.cobos@gmail.com" - } - ], - "require": { - "yiisoft/yii2": "*", - "imagine/imagine": "v0.5.0" - }, - "autoload": { - "psr-0": { - "yii\\imagine\\": "" - } - }, - "target-dir": "yii/imagine" -} diff --git a/extensions/yii/jui/Accordion.php b/extensions/yii/jui/Accordion.php deleted file mode 100644 index 42897a9..0000000 --- a/extensions/yii/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/yii/jui/AccordionAsset.php b/extensions/yii/jui/AccordionAsset.php deleted file mode 100644 index 05c1e20..0000000 --- a/extensions/yii/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/yii/jui/AutoComplete.php b/extensions/yii/jui/AutoComplete.php deleted file mode 100644 index 93f4332..0000000 --- a/extensions/yii/jui/AutoComplete.php +++ /dev/null @@ -1,65 +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/yii/jui/AutoCompleteAsset.php b/extensions/yii/jui/AutoCompleteAsset.php deleted file mode 100644 index f48e064..0000000 --- a/extensions/yii/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/yii/jui/ButtonAsset.php b/extensions/yii/jui/ButtonAsset.php deleted file mode 100644 index 6616b34..0000000 --- a/extensions/yii/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/yii/jui/CHANGELOG.md b/extensions/yii/jui/CHANGELOG.md deleted file mode 100644 index b31c34e..0000000 --- a/extensions/yii/jui/CHANGELOG.md +++ /dev/null @@ -1,12 +0,0 @@ -Yii Framework 2 jui extension Change Log -======================================== - -2.0.0 beta under development ----------------------------- - -- Bug #1550: fixed the issue that JUI input widgets did not property input IDs. - -2.0.0 alpha, December 1, 2013 ------------------------------ - -- Initial release. diff --git a/extensions/yii/jui/CoreAsset.php b/extensions/yii/jui/CoreAsset.php deleted file mode 100644 index d77a25f..0000000 --- a/extensions/yii/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/yii/jui/DatePicker.php b/extensions/yii/jui/DatePicker.php deleted file mode 100644 index 6fc73bb..0000000 --- a/extensions/yii/jui/DatePicker.php +++ /dev/null @@ -1,124 +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; - /** - * @var array the HTML attributes for the container tag. This is only used when [[inline]] is true. - */ - public $containerOptions = []; - - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->inline && !isset($this->containerOptions['id'])) { - $this->containerOptions['id'] = $this->options['id'] . '-container'; - } - } - - /** - * Renders the widget. - */ - public function run() - { - echo $this->renderWidget() . "\n"; - $containerID = $this->inline ? $this->containerOptions['id'] : $this->options['id']; - if ($this->language !== false) { - $view = $this->getView(); - DatePickerRegionalAsset::register($view); - - $options = Json::encode($this->clientOptions); - $view->registerJs("$('#{$containerID}').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(), $containerID); - $this->clientOptions = $options; - } else { - $this->registerWidget('datepicker', DatePickerAsset::className(), $containerID); - } - } - - /** - * 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']; - $contents[] = Html::tag('div', null, $this->containerOptions); - } - - return implode("\n", $contents); - } -} diff --git a/extensions/yii/jui/DatePickerAsset.php b/extensions/yii/jui/DatePickerAsset.php deleted file mode 100644 index fddd8df..0000000 --- a/extensions/yii/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/yii/jui/DatePickerRegionalAsset.php b/extensions/yii/jui/DatePickerRegionalAsset.php deleted file mode 100644 index 249373a..0000000 --- a/extensions/yii/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/yii/jui/Dialog.php b/extensions/yii/jui/Dialog.php deleted file mode 100644 index a5cbaf2..0000000 --- a/extensions/yii/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/yii/jui/DialogAsset.php b/extensions/yii/jui/DialogAsset.php deleted file mode 100644 index 109243e..0000000 --- a/extensions/yii/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/yii/jui/Draggable.php b/extensions/yii/jui/Draggable.php deleted file mode 100644 index 02e4973..0000000 --- a/extensions/yii/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/yii/jui/DraggableAsset.php b/extensions/yii/jui/DraggableAsset.php deleted file mode 100644 index f3286a5..0000000 --- a/extensions/yii/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/yii/jui/Droppable.php b/extensions/yii/jui/Droppable.php deleted file mode 100644 index 530e736..0000000 --- a/extensions/yii/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/yii/jui/DroppableAsset.php b/extensions/yii/jui/DroppableAsset.php deleted file mode 100644 index 84b64b8..0000000 --- a/extensions/yii/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/yii/jui/EffectAsset.php b/extensions/yii/jui/EffectAsset.php deleted file mode 100644 index 79c5aaa..0000000 --- a/extensions/yii/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/yii/jui/InputWidget.php b/extensions/yii/jui/InputWidget.php deleted file mode 100644 index 77201ba..0000000 --- a/extensions/yii/jui/InputWidget.php +++ /dev/null @@ -1,62 +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."); - } - if ($this->hasModel() && !isset($this->options['id'])) { - $this->options['id'] = Html::getInputId($this->model, $this->attribute); - } - 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/yii/jui/LICENSE.md b/extensions/yii/jui/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/extensions/yii/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/yii/jui/Menu.php b/extensions/yii/jui/Menu.php deleted file mode 100644 index bce2157..0000000 --- a/extensions/yii/jui/Menu.php +++ /dev/null @@ -1,77 +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/yii/jui/MenuAsset.php b/extensions/yii/jui/MenuAsset.php deleted file mode 100644 index 8b840a8..0000000 --- a/extensions/yii/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/yii/jui/ProgressBar.php b/extensions/yii/jui/ProgressBar.php deleted file mode 100644 index 1c555f1..0000000 --- a/extensions/yii/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/yii/jui/ProgressBarAsset.php b/extensions/yii/jui/ProgressBarAsset.php deleted file mode 100644 index d485fbd..0000000 --- a/extensions/yii/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/yii/jui/README.md b/extensions/yii/jui/README.md deleted file mode 100644 index f35db1c..0000000 --- a/extensions/yii/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 --prefer-dist yiisoft/yii2-jui "*" -``` - -or add - -``` -"yiisoft/yii2-jui": "*" -``` - -to the require section of your `composer.json` file. - diff --git a/extensions/yii/jui/Resizable.php b/extensions/yii/jui/Resizable.php deleted file mode 100644 index bcff9a8..0000000 --- a/extensions/yii/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/yii/jui/ResizableAsset.php b/extensions/yii/jui/ResizableAsset.php deleted file mode 100644 index acf4c73..0000000 --- a/extensions/yii/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/yii/jui/Selectable.php b/extensions/yii/jui/Selectable.php deleted file mode 100644 index 94e4faf..0000000 --- a/extensions/yii/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/yii/jui/SelectableAsset.php b/extensions/yii/jui/SelectableAsset.php deleted file mode 100644 index 61f405f..0000000 --- a/extensions/yii/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/yii/jui/Slider.php b/extensions/yii/jui/Slider.php deleted file mode 100644 index b1efcce..0000000 --- a/extensions/yii/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 $clientEventMap = [ - '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()); - } -} diff --git a/extensions/yii/jui/SliderAsset.php b/extensions/yii/jui/SliderAsset.php deleted file mode 100644 index 56c2451..0000000 --- a/extensions/yii/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/yii/jui/SliderInput.php b/extensions/yii/jui/SliderInput.php deleted file mode 100644 index 20599cf..0000000 --- a/extensions/yii/jui/SliderInput.php +++ /dev/null @@ -1,92 +0,0 @@ - $model, - * 'attribute' => 'amount', - * 'clientOptions' => [ - * 'min' => 1, - * 'max' => 10, - * ], - * ]); - * ``` - * - * The following example will use the name property instead: - * - * ``` - * echo SliderInput::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 $clientEventMap = [ - 'change' => 'slidechange', - 'create' => 'slidecreate', - 'slide' => 'slide', - 'start' => 'slidestart', - 'stop' => 'slidestop', - ]; - /** - * @var array the HTML attributes for the container tag. - */ - public $containerOptions = []; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if (!isset($this->containerOptions['id'])) { - $this->containerOptions['id'] = $this->options['id'] . '-container'; - } - } - - /** - * Executes the widget. - */ - public function run() - { - echo Html::tag('div', '', $this->containerOptions); - - if ($this->hasModel()) { - echo Html::activeHiddenInput($this->model, $this->attribute, $this->options); - $this->clientOptions['value'] = $this->model{$this->attribute}; - } else { - echo Html::hiddenInput($this->name, $this->value, $this->options); - $this->clientOptions['value'] = $this->value; - } - - if (!isset($this->clientEvents['slide'])) { - $this->clientEvents['slide'] = 'function(event, ui) { - $("#' . $this->options['id'] . '").val(ui.value); - }'; - } - - $this->registerWidget('slider', SliderAsset::className(), $this->containerOptions['id']); - } -} diff --git a/extensions/yii/jui/Sortable.php b/extensions/yii/jui/Sortable.php deleted file mode 100644 index 6209cb6..0000000 --- a/extensions/yii/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/yii/jui/SortableAsset.php b/extensions/yii/jui/SortableAsset.php deleted file mode 100644 index 69c9ba3..0000000 --- a/extensions/yii/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/yii/jui/Spinner.php b/extensions/yii/jui/Spinner.php deleted file mode 100644 index b88c70b..0000000 --- a/extensions/yii/jui/Spinner.php +++ /dev/null @@ -1,65 +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 -{ - protected $clientEventMap = [ - 'spin' => 'spin', - ]; - - /** - * 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/yii/jui/SpinnerAsset.php b/extensions/yii/jui/SpinnerAsset.php deleted file mode 100644 index 89a8c59..0000000 --- a/extensions/yii/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/yii/jui/Tabs.php b/extensions/yii/jui/Tabs.php deleted file mode 100644 index 9d2a2be..0000000 --- a/extensions/yii/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/yii/jui/TabsAsset.php b/extensions/yii/jui/TabsAsset.php deleted file mode 100644 index 5bef4c0..0000000 --- a/extensions/yii/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/yii/jui/ThemeAsset.php b/extensions/yii/jui/ThemeAsset.php deleted file mode 100644 index dedcb00..0000000 --- a/extensions/yii/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/yii/jui/TooltipAsset.php b/extensions/yii/jui/TooltipAsset.php deleted file mode 100644 index 1fa4490..0000000 --- a/extensions/yii/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/yii/jui/Widget.php b/extensions/yii/jui/Widget.php deleted file mode 100644 index 62bbd16..0000000 --- a/extensions/yii/jui/Widget.php +++ /dev/null @@ -1,125 +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 $clientEventMap = []; - - /** - * 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 - * @param string $id the ID of the widget - */ - protected function registerClientOptions($name, $id) - { - if ($this->clientOptions !== false) { - $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 - * @param string $id the ID of the widget - */ - protected function registerClientEvents($name, $id) - { - if (!empty($this->clientEvents)) { - $js = []; - foreach ($this->clientEvents as $event => $handler) { - if (isset($this->clientEventMap[$event])) { - $eventName = $this->clientEventMap[$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 - * @param string $id the ID of the widget. If null, it will use the `id` value of [[options]]. - */ - protected function registerWidget($name, $assetBundle, $id = null) - { - if ($id === null) { - $id = $this->options['id']; - } - $this->registerAssets($assetBundle); - $this->registerClientOptions($name, $id); - $this->registerClientEvents($name, $id); - } -} diff --git a/extensions/yii/jui/assets/UPGRADE.md b/extensions/yii/jui/assets/UPGRADE.md deleted file mode 100644 index 5cd32d2..0000000 --- a/extensions/yii/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/yii/jui/assets/jquery.ui.accordion.js b/extensions/yii/jui/assets/jquery.ui.accordion.js deleted file mode 100644 index bdd2d53..0000000 --- a/extensions/yii/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/yii/jui/assets/jquery.ui.autocomplete.js b/extensions/yii/jui/assets/jquery.ui.autocomplete.js deleted file mode 100644 index ca53d2c..0000000 --- a/extensions/yii/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 = $( " -EOD; - $this->assertEqualsWithoutLE($expected, Html::ul($data)); - $expected = << -
  • 1
  • -
  • abc
  • -
  • <>
  • - -EOD; - $this->assertEqualsWithoutLE($expected, Html::ul($data, [ - 'class' => 'test', - 'item' => function ($item, $index) { - return "
  • $item
  • "; - } - ])); - } - - public function testOl() - { - $data = [ - 1, 'abc', '<>', - ]; - $expected = << -
  • 1
  • -
  • abc
  • -
  • <>
  • - -EOD; - $this->assertEqualsWithoutLE($expected, Html::ol($data, [ - 'itemOptions' => ['class' => 'ti'], - ])); - $expected = << -
  • 1
  • -
  • abc
  • -
  • <>
  • - -EOD; - $this->assertEqualsWithoutLE($expected, Html::ol($data, [ - 'class' => 'test', - 'item' => function ($item, $index) { - return "
  • $item
  • "; - } - ])); - } - - public function testRenderOptions() - { - $data = [ - 'value1' => 'label1', - 'group1' => [ - 'value11' => 'label11', - 'group11' => [ - 'value111' => 'label111', - ], - 'group12' => [], - ], - 'value2' => 'label2', - 'group2' => [], - ]; - $expected = <<please select<> - - - - - - - - - - - - - - -EOD; - $attributes = [ - 'prompt' => 'please select<>', - 'options' => [ - 'value111' => ['class' => 'option'], - ], - 'groups' => [ - 'group12' => ['class' => 'group'], - ], - ]; - $this->assertEqualsWithoutLE($expected, Html::renderSelectOptions(['value111', 'value1'], $data, $attributes)); - } - - public function testRenderAttributes() - { - $this->assertEquals('', Html::renderTagAttributes([])); - $this->assertEquals(' name="test" value="1<>"', Html::renderTagAttributes(['name' => 'test', 'empty' => null, 'value' => '1<>'])); - $this->assertEquals(' checked disabled', Html::renderTagAttributes(['checked' => true, 'disabled' => true, 'hidden' => false])); - } - - public function testAddCssClass() - { - $options = []; - Html::addCssClass($options, 'test'); - $this->assertEquals(['class' => 'test'], $options); - Html::addCssClass($options, 'test'); - $this->assertEquals(['class' => 'test'], $options); - Html::addCssClass($options, 'test2'); - $this->assertEquals(['class' => 'test test2'], $options); - Html::addCssClass($options, 'test'); - $this->assertEquals(['class' => 'test test2'], $options); - Html::addCssClass($options, 'test2'); - $this->assertEquals(['class' => 'test test2'], $options); - Html::addCssClass($options, 'test3'); - $this->assertEquals(['class' => 'test test2 test3'], $options); - Html::addCssClass($options, 'test2'); - $this->assertEquals(['class' => 'test test2 test3'], $options); - } - - public function testRemoveCssClass() - { - $options = ['class' => 'test test2 test3']; - Html::removeCssClass($options, 'test2'); - $this->assertEquals(['class' => 'test test3'], $options); - Html::removeCssClass($options, 'test2'); - $this->assertEquals(['class' => 'test test3'], $options); - Html::removeCssClass($options, 'test'); - $this->assertEquals(['class' => 'test3'], $options); - Html::removeCssClass($options, 'test3'); - $this->assertEquals([], $options); - } - - protected function getDataItems() - { - return [ - 'value1' => 'text1', - 'value2' => 'text2', - ]; - } - - protected function getDataItems2() - { - return [ - 'value1<>' => 'text1<>', - 'value 2' => 'text 2', - ]; - } -} diff --git a/tests/unit/framework/helpers/InflectorTest.php b/tests/unit/framework/helpers/InflectorTest.php deleted file mode 100644 index ff414ba..0000000 --- a/tests/unit/framework/helpers/InflectorTest.php +++ /dev/null @@ -1,147 +0,0 @@ - 'moves', - 'foot' => 'feet', - 'child' => 'children', - 'human' => 'humans', - 'man' => 'men', - 'staff' => 'staff', - 'tooth' => 'teeth', - 'person' => 'people', - 'mouse' => 'mice', - 'touch' => 'touches', - 'hash' => 'hashes', - 'shelf' => 'shelves', - 'potato' => 'potatoes', - 'bus' => 'buses', - 'test' => 'tests', - 'car' => 'cars', - ]; - - foreach ($testData as $testIn => $testOut) { - $this->assertEquals($testOut, Inflector::pluralize($testIn)); - $this->assertEquals(ucfirst($testOut), ucfirst(Inflector::pluralize($testIn))); - } - } - - public function testSingularize() - { - $testData = [ - 'moves' => 'move', - 'feet' => 'foot', - 'children' => 'child', - 'humans' => 'human', - 'men' => 'man', - 'staff' => 'staff', - 'teeth' => 'tooth', - 'people' => 'person', - 'mice' => 'mouse', - 'touches' => 'touch', - 'hashes' => 'hash', - 'shelves' => 'shelf', - 'potatoes' => 'potato', - 'buses' => 'bus', - 'tests' => 'test', - 'cars' => 'car', - ]; - foreach ($testData as $testIn => $testOut) { - $this->assertEquals($testOut, Inflector::singularize($testIn)); - $this->assertEquals(ucfirst($testOut), ucfirst(Inflector::singularize($testIn))); - } - } - - public function testTitleize() - { - $this->assertEquals("Me my self and i", Inflector::titleize('MeMySelfAndI')); - $this->assertEquals("Me My Self And I", Inflector::titleize('MeMySelfAndI', true)); - } - - public function testCamelize() - { - $this->assertEquals("MeMySelfAndI", Inflector::camelize('me my_self-andI')); - $this->assertEquals("QweQweEwq", Inflector::camelize('qwe qwe^ewq')); - } - - public function testUnderscore() - { - $this->assertEquals("me_my_self_and_i", Inflector::underscore('MeMySelfAndI')); - } - - public function testCamel2words() - { - $this->assertEquals('Camel Case', Inflector::camel2words('camelCase')); - $this->assertEquals('Lower Case', Inflector::camel2words('lower_case')); - $this->assertEquals('Tricky Stuff It Is Testing', Inflector::camel2words(' tricky_stuff.it-is testing... ')); - } - - public function testCamel2id() - { - $this->assertEquals('post-tag', Inflector::camel2id('PostTag')); - $this->assertEquals('post_tag', Inflector::camel2id('PostTag', '_')); - - $this->assertEquals('post-tag', Inflector::camel2id('postTag')); - $this->assertEquals('post_tag', Inflector::camel2id('postTag', '_')); - } - - public function testId2camel() - { - $this->assertEquals('PostTag', Inflector::id2camel('post-tag')); - $this->assertEquals('PostTag', Inflector::id2camel('post_tag', '_')); - - $this->assertEquals('PostTag', Inflector::id2camel('post-tag')); - $this->assertEquals('PostTag', Inflector::id2camel('post_tag', '_')); - } - - public function testHumanize() - { - $this->assertEquals("Me my self and i", Inflector::humanize('me_my_self_and_i')); - $this->assertEquals("Me My Self And I", Inflector::humanize('me_my_self_and_i', true)); - } - - public function testVariablize() - { - $this->assertEquals("customerTable", Inflector::variablize('customer_table')); - } - - public function testTableize() - { - $this->assertEquals("customer_tables", Inflector::tableize('customerTable')); - } - - public function testSlug() - { - $this->assertEquals("privet-hello-jii-framework-kak-dela-how-it-goes", Inflector::slug('Привет Hello Йии-- Framework !--- Как дела ? How it goes ?')); - - $this->assertEquals("this-is-a-title", Inflector::slug('this is a title')); - } - - public function testClassify() - { - $this->assertEquals("CustomerTable", Inflector::classify('customer_tables')); - } - - public function testOrdinalize() - { - $this->assertEquals('21st', Inflector::ordinalize('21')); - $this->assertEquals('22nd', Inflector::ordinalize('22')); - $this->assertEquals('23rd', Inflector::ordinalize('23')); - $this->assertEquals('24th', Inflector::ordinalize('24')); - $this->assertEquals('25th', Inflector::ordinalize('25')); - $this->assertEquals('111th', Inflector::ordinalize('111')); - $this->assertEquals('113th', Inflector::ordinalize('113')); - } -} diff --git a/tests/unit/framework/helpers/JsonTest.php b/tests/unit/framework/helpers/JsonTest.php deleted file mode 100644 index 20da347..0000000 --- a/tests/unit/framework/helpers/JsonTest.php +++ /dev/null @@ -1,69 +0,0 @@ -assertSame('"1"', Json::encode($data)); - - // simple array encoding - $data = [1, 2]; - $this->assertSame('[1,2]', Json::encode($data)); - $data = ['a' => 1, 'b' => 2]; - $this->assertSame('{"a":1,"b":2}', Json::encode($data)); - - // simple object encoding - $data = new \stdClass(); - $data->a = 1; - $data->b = 2; - $this->assertSame('{"a":1,"b":2}', Json::encode($data)); - - // expression encoding - $expression = 'function () {}'; - $data = new JsExpression($expression); - $this->assertSame($expression, Json::encode($data)); - - // complex data - $expression1 = 'function (a) {}'; - $expression2 = 'function (b) {}'; - $data = [ - 'a' => [ - 1, new JsExpression($expression1) - ], - 'b' => new JsExpression($expression2), - ]; - $this->assertSame("{\"a\":[1,$expression1],\"b\":$expression2}", Json::encode($data)); - - // https://github.com/yiisoft/yii2/issues/957 - $data = (object)null; - $this->assertSame('{}', Json::encode($data)); - } - - public function testDecode() - { - // basic data decoding - $json = '"1"'; - $this->assertSame('1', Json::decode($json)); - - // array decoding - $json = '{"a":1,"b":2}'; - $this->assertSame(['a' => 1, 'b' => 2], Json::decode($json)); - - // exception - $json = '{"a":1,"b":2'; - $this->setExpectedException('yii\base\InvalidParamException'); - Json::decode($json); - } -} diff --git a/tests/unit/framework/helpers/SecurityTest.php b/tests/unit/framework/helpers/SecurityTest.php deleted file mode 100644 index 6a1d2fd..0000000 --- a/tests/unit/framework/helpers/SecurityTest.php +++ /dev/null @@ -1,43 +0,0 @@ -assertTrue(Security::validatePassword($password, $hash)); - $this->assertFalse(Security::validatePassword('test', $hash)); - } - - public function testHashData() - { - $data = 'known data'; - $key = 'secret'; - $hashedData = Security::hashData($data, $key); - $this->assertFalse($data === $hashedData); - $this->assertEquals($data, Security::validateData($hashedData, $key)); - $hashedData[strlen($hashedData) - 1] = 'A'; - $this->assertFalse(Security::validateData($hashedData, $key)); - } - - public function testEncrypt() - { - $data = 'known data'; - $key = 'secret'; - $encryptedData = Security::encrypt($data, $key); - $this->assertFalse($data === $encryptedData); - $decryptedData = Security::decrypt($encryptedData, $key); - $this->assertEquals($data, $decryptedData); - } -} diff --git a/tests/unit/framework/helpers/StringHelperTest.php b/tests/unit/framework/helpers/StringHelperTest.php deleted file mode 100644 index a641001..0000000 --- a/tests/unit/framework/helpers/StringHelperTest.php +++ /dev/null @@ -1,68 +0,0 @@ -assertEquals(4, StringHelper::byteLength('this')); - $this->assertEquals(6, StringHelper::byteLength('это')); - } - - public function testSubstr() - { - $this->assertEquals('th', StringHelper::byteSubstr('this', 0, 2)); - $this->assertEquals('э', StringHelper::byteSubstr('это', 0, 2)); - } - - public function testBasename() - { - $this->assertEquals('', StringHelper::basename('')); - - $this->assertEquals('file', StringHelper::basename('file')); - $this->assertEquals('file.test', StringHelper::basename('file.test', '.test2')); - $this->assertEquals('file', StringHelper::basename('file.test', '.test')); - - $this->assertEquals('file', StringHelper::basename('/file')); - $this->assertEquals('file.test', StringHelper::basename('/file.test', '.test2')); - $this->assertEquals('file', StringHelper::basename('/file.test', '.test')); - - $this->assertEquals('file', StringHelper::basename('/path/to/file')); - $this->assertEquals('file.test', StringHelper::basename('/path/to/file.test', '.test2')); - $this->assertEquals('file', StringHelper::basename('/path/to/file.test', '.test')); - - $this->assertEquals('file', StringHelper::basename('\file')); - $this->assertEquals('file.test', StringHelper::basename('\file.test', '.test2')); - $this->assertEquals('file', StringHelper::basename('\file.test', '.test')); - - $this->assertEquals('file', StringHelper::basename('C:\file')); - $this->assertEquals('file.test', StringHelper::basename('C:\file.test', '.test2')); - $this->assertEquals('file', StringHelper::basename('C:\file.test', '.test')); - - $this->assertEquals('file', StringHelper::basename('C:\path\to\file')); - $this->assertEquals('file.test', StringHelper::basename('C:\path\to\file.test', '.test2')); - $this->assertEquals('file', StringHelper::basename('C:\path\to\file.test', '.test')); - - // mixed paths - $this->assertEquals('file.test', StringHelper::basename('/path\to/file.test')); - $this->assertEquals('file.test', StringHelper::basename('/path/to\file.test')); - $this->assertEquals('file.test', StringHelper::basename('\path/to\file.test')); - - // \ and / in suffix - $this->assertEquals('file', StringHelper::basename('/path/to/filete/st', 'te/st')); - $this->assertEquals('st', StringHelper::basename('/path/to/filete/st', 'te\st')); - $this->assertEquals('file', StringHelper::basename('/path/to/filete\st', 'te\st')); - $this->assertEquals('st', StringHelper::basename('/path/to/filete\st', 'te/st')); - - // http://www.php.net/manual/en/function.basename.php#72254 - $this->assertEquals('foo', StringHelper::basename('/bar/foo/')); - $this->assertEquals('foo', StringHelper::basename('\\bar\\foo\\')); - } -} diff --git a/tests/unit/framework/helpers/VarDumperTest.php b/tests/unit/framework/helpers/VarDumperTest.php deleted file mode 100644 index 11fe6d4..0000000 --- a/tests/unit/framework/helpers/VarDumperTest.php +++ /dev/null @@ -1,20 +0,0 @@ -assertEquals("stdClass#1\n(\n)", ob_get_contents()); - ob_end_clean(); - } -} diff --git a/tests/unit/framework/i18n/FallbackMessageFormatterTest.php b/tests/unit/framework/i18n/FallbackMessageFormatterTest.php deleted file mode 100644 index bdc4e43..0000000 --- a/tests/unit/framework/i18n/FallbackMessageFormatterTest.php +++ /dev/null @@ -1,171 +0,0 @@ - - * @since 2.0 - * @group i18n - */ -class FallbackMessageFormatterTest extends TestCase -{ - const N = 'n'; - const N_VALUE = 42; - const SUBJECT = 'сабж'; - const SUBJECT_VALUE = 'Answer to the Ultimate Question of Life, the Universe, and Everything'; - - public function patterns() - { - return [ - [ - '{'.self::SUBJECT.'} is {'.self::N.'}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - self::N => self::N_VALUE, - self::SUBJECT => self::SUBJECT_VALUE, - ] - ], - - [ - '{'.self::SUBJECT.'} is {'.self::N.', number}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - self::N => self::N_VALUE, - self::SUBJECT => self::SUBJECT_VALUE, - ] - ], - - [ - '{'.self::SUBJECT.'} is {'.self::N.', number, integer}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - self::N => self::N_VALUE, - self::SUBJECT => self::SUBJECT_VALUE, - ] - ], - - // This one was provided by Aura.Intl. Thanks! - [<<<_MSG_ -{gender_of_host, select, - female {{num_guests, plural, offset:1 - =0 {{host} does not give a party.} - =1 {{host} invites {guest} to her party.} - =2 {{host} invites {guest} and one other person to her party.} - other {{host} invites {guest} and # other people to her party.}}} - male {{num_guests, plural, offset:1 - =0 {{host} does not give a party.} - =1 {{host} invites {guest} to his party.} - =2 {{host} invites {guest} and one other person to his party.} - other {{host} invites {guest} and # other people to his party.}}} - other {{num_guests, plural, offset:1 - =0 {{host} does not give a party.} - =1 {{host} invites {guest} to their party.} - =2 {{host} invites {guest} and one other person to their party.} - other {{host} invites {guest} and # other people to their party.}}}} -_MSG_ - , - 'ralph invites beep and 3 other people to his party.', - [ - 'gender_of_host' => 'male', - 'num_guests' => 4, - 'host' => 'ralph', - 'guest' => 'beep' - ] - ], - - [ - '{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', - 'Alexander is male and he loves Yii!', - [ - 'name' => 'Alexander', - 'gender' => 'male', - ], - ], - - // verify pattern in select does not get replaced - [ - '{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', - 'Alexander is male and he loves Yii!', - [ - 'name' => 'Alexander', - 'gender' => 'male', - // following should not be replaced - 'he' => 'wtf', - 'she' => 'wtf', - 'it' => 'wtf', - ] - ], - - // verify pattern in select message gets replaced - [ - '{name} is {gender} and {gender, select, female{she} male{{he}} other{it}} loves Yii!', - 'Alexander is male and wtf loves Yii!', - [ - 'name' => 'Alexander', - 'gender' => 'male', - 'he' => 'wtf', - 'she' => 'wtf', - ], - ], - - // some parser specific verifications - [ - '{gender} and {gender, select, female{she} male{{he}} other{it}} loves {nr} is {gender}!', - 'male and wtf loves 42 is male!', - [ - 'nr' => 42, - 'gender' => 'male', - 'he' => 'wtf', - 'she' => 'wtf', - ], - ], - ]; - } - - /** - * @dataProvider patterns - */ - public function testNamedArguments($pattern, $expected, $args) - { - $formatter = new FallbackMessageFormatter(); - $result = $formatter->fallbackFormat($pattern, $args, 'en-US'); - $this->assertEquals($expected, $result, $formatter->getErrorMessage()); - } - - public function testInsufficientArguments() - { - $expected = '{'.self::SUBJECT.'} is '.self::N_VALUE; - - $formatter = new FallbackMessageFormatter(); - $result = $formatter->fallbackFormat('{'.self::SUBJECT.'} is {'.self::N.'}', [ - self::N => self::N_VALUE, - ], 'en-US'); - - $this->assertEquals($expected, $result); - } - - public function testNoParams() - { - $pattern = '{'.self::SUBJECT.'} is '.self::N; - - $formatter = new FallbackMessageFormatter(); - $result = $formatter->fallbackFormat($pattern, [], 'en-US'); - $this->assertEquals($pattern, $result, $formatter->getErrorMessage()); - } -} - -class FallbackMessageFormatter extends MessageFormatter -{ - public function fallbackFormat($pattern, $args, $locale) - { - return parent::fallbackFormat($pattern, $args, $locale); - } -} diff --git a/tests/unit/framework/i18n/FormatterTest.php b/tests/unit/framework/i18n/FormatterTest.php deleted file mode 100644 index 97e198d..0000000 --- a/tests/unit/framework/i18n/FormatterTest.php +++ /dev/null @@ -1,96 +0,0 @@ - - * @since 2.0 - * @group i18n - */ -class FormatterTest extends TestCase -{ - /** - * @var Formatter - */ - protected $formatter; - - protected function setUp() - { - parent::setUp(); - if (!extension_loaded('intl')) { - $this->markTestSkipped('intl extension is required.'); - } - $this->mockApplication([ - 'timeZone' => 'UTC', - ]); - $this->formatter = new Formatter(['locale' => 'en-US']); - } - - protected function tearDown() - { - parent::tearDown(); - $this->formatter = null; - } - - public function testAsDecimal() - { - $value = '123'; - $this->assertSame($value, $this->formatter->asDecimal($value)); - $value = '123456'; - $this->assertSame("123,456", $this->formatter->asDecimal($value)); - $value = '-123456.123'; - $this->assertSame("-123,456.123", $this->formatter->asDecimal($value)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asDecimal(null)); - } - - public function testAsPercent() - { - $value = '123'; - $this->assertSame('12,300%', $this->formatter->asPercent($value)); - $value = '0.1234'; - $this->assertSame("12%", $this->formatter->asPercent($value)); - $value = '-0.009343'; - $this->assertSame("-1%", $this->formatter->asPercent($value)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asPercent(null)); - } - - public function testAsScientific() - { - $value = '123'; - $this->assertSame('1.23E2', $this->formatter->asScientific($value)); - $value = '123456'; - $this->assertSame("1.23456E5", $this->formatter->asScientific($value)); - $value = '-123456.123'; - $this->assertSame("-1.23456123E5", $this->formatter->asScientific($value)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asScientific(null)); - } - - public function testAsCurrency() - { - $value = '123'; - $this->assertSame('$123.00', $this->formatter->asCurrency($value)); - $value = '123.456'; - $this->assertSame("$123.46", $this->formatter->asCurrency($value)); - // Starting from ICU 52.1, negative currency value will be formatted as -$123,456.12 - // see: http://source.icu-project.org/repos/icu/icu/tags/release-52-1/source/data/locales/en.txt -// $value = '-123456.123'; -// $this->assertSame("($123,456.12)", $this->formatter->asCurrency($value)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asCurrency(null)); - } - - public function testDate() - { - $time = time(); - $this->assertSame(date('n/j/y', $time), $this->formatter->asDate($time)); - $this->assertSame(date('F j, Y', $time), $this->formatter->asDate($time, 'long')); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asDate(null)); - } -} diff --git a/tests/unit/framework/i18n/GettextMessageSourceTest.php b/tests/unit/framework/i18n/GettextMessageSourceTest.php deleted file mode 100644 index 727fee9..0000000 --- a/tests/unit/framework/i18n/GettextMessageSourceTest.php +++ /dev/null @@ -1,16 +0,0 @@ -markTestIncomplete(); - } -} diff --git a/tests/unit/framework/i18n/GettextMoFileTest.php b/tests/unit/framework/i18n/GettextMoFileTest.php deleted file mode 100644 index 373fa20..0000000 --- a/tests/unit/framework/i18n/GettextMoFileTest.php +++ /dev/null @@ -1,98 +0,0 @@ -load($moFilePath, 'context1'); - $context2 = $moFile->load($moFilePath, 'context2'); - - // item count - $this->assertCount(3, $context1); - $this->assertCount(2, $context2); - - // original messages - $this->assertArrayNotHasKey("Missing\n\r\t\"translation.", $context1); - $this->assertArrayHasKey("Aliquam tempus elit vel purus molestie placerat. In sollicitudin tincidunt\naliquet. Integer tincidunt gravida tempor. In convallis blandit dui vel malesuada.\nNunc vel sapien nunc, a pretium nulla.", $context1); - $this->assertArrayHasKey("String number two.", $context1); - $this->assertArrayHasKey("Nunc vel sapien nunc, a pretium nulla.\nPellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.", $context1); - - $this->assertArrayHasKey("The other\n\ncontext.\n", $context2); - $this->assertArrayHasKey("test1\\ntest2\n\\\ntest3", $context2); - - // translated messages - $this->assertFalse(in_array("", $context1)); - $this->assertTrue(in_array("Олицетворение однократно. Представленный лексико-семантический анализ является\nпсихолингвистическим в своей основе, но механизм сочленений полидисперсен. Впечатление\nоднократно. Различное расположение выбирает сюжетный механизм сочленений.", $context1)); - $this->assertTrue(in_array('Строка номер два.', $context1)); - $this->assertTrue(in_array('Короткий перевод.', $context1)); - - $this->assertTrue(in_array("Другой\n\nконтекст.\n", $context2)); - $this->assertTrue(in_array("тест1\\nтест2\n\\\nтест3", $context2)); - } - - public function testSave() - { - // initial data - $s = chr(4); - $messages = [ - 'Hello!' => 'Привет!', - "context1{$s}Hello?" => 'Привет?', - 'Hello!?' => '', - "context1{$s}Hello!?!" => '', - "context2{$s}\"Quotes\"" => '"Кавычки"', - "context2{$s}\nNew lines\n" => "\nПереносы строк\n", - "context2{$s}\tTabs\t" => "\tТабы\t", - "context2{$s}\rCarriage returns\r" => "\rВозвраты кареток\r", - ]; - - // create temporary directory and dump messages - $poFileDirectory = __DIR__ . '/../../runtime/i18n'; - if (!is_dir($poFileDirectory)) { - mkdir($poFileDirectory); - } - if (is_file($poFileDirectory . '/test.mo')) { - unlink($poFileDirectory . '/test.mo'); - } - - $moFile = new GettextMoFile(); - $moFile->save($poFileDirectory . '/test.mo', $messages); - - // load messages - $context1 = $moFile->load($poFileDirectory . '/test.mo', 'context1'); - $context2 = $moFile->load($poFileDirectory . '/test.mo', 'context2'); - - // context1 - $this->assertCount(2, $context1); - - $this->assertArrayHasKey('Hello?', $context1); - $this->assertTrue(in_array('Привет?', $context1)); - - $this->assertArrayHasKey('Hello!?!', $context1); - $this->assertTrue(in_array('', $context1)); - - // context2 - $this->assertCount(4, $context2); - - $this->assertArrayHasKey("\"Quotes\"", $context2); - $this->assertTrue(in_array('"Кавычки"', $context2)); - - $this->assertArrayHasKey("\nNew lines\n", $context2); - $this->assertTrue(in_array("\nПереносы строк\n", $context2)); - - $this->assertArrayHasKey("\tTabs\t", $context2); - $this->assertTrue(in_array("\tТабы\t", $context2)); - - $this->assertArrayHasKey("\rCarriage returns\r", $context2); - $this->assertTrue(in_array("\rВозвраты кареток\r", $context2)); - } -} diff --git a/tests/unit/framework/i18n/GettextPoFileTest.php b/tests/unit/framework/i18n/GettextPoFileTest.php deleted file mode 100644 index 29db141..0000000 --- a/tests/unit/framework/i18n/GettextPoFileTest.php +++ /dev/null @@ -1,98 +0,0 @@ -load($poFilePath, 'context1'); - $context2 = $poFile->load($poFilePath, 'context2'); - - // item count - $this->assertCount(4, $context1); - $this->assertCount(2, $context2); - - // original messages - $this->assertArrayHasKey("Missing\n\r\t\"translation.", $context1); - $this->assertArrayHasKey("Aliquam tempus elit vel purus molestie placerat. In sollicitudin tincidunt\naliquet. Integer tincidunt gravida tempor. In convallis blandit dui vel malesuada.\nNunc vel sapien nunc, a pretium nulla.", $context1); - $this->assertArrayHasKey("String number two.", $context1); - $this->assertArrayHasKey("Nunc vel sapien nunc, a pretium nulla.\nPellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.", $context1); - - $this->assertArrayHasKey("The other\n\ncontext.\n", $context2); - $this->assertArrayHasKey("test1\\\ntest2\n\\\\\ntest3", $context2); - - // translated messages - $this->assertTrue(in_array("", $context1)); - $this->assertTrue(in_array("Олицетворение однократно. Представленный лексико-семантический анализ является\nпсихолингвистическим в своей основе, но механизм сочленений полидисперсен. Впечатление\nоднократно. Различное расположение выбирает сюжетный механизм сочленений.", $context1)); - $this->assertTrue(in_array('Строка номер два.', $context1)); - $this->assertTrue(in_array('Короткий перевод.', $context1)); - - $this->assertTrue(in_array("Другой\n\nконтекст.\n", $context2)); - $this->assertTrue(in_array("тест1\\\nтест2\n\\\\\nтест3", $context2)); - } - - public function testSave() - { - // initial data - $s = chr(4); - $messages = [ - 'Hello!' => 'Привет!', - "context1{$s}Hello?" => 'Привет?', - 'Hello!?' => '', - "context1{$s}Hello!?!" => '', - "context2{$s}\"Quotes\"" => '"Кавычки"', - "context2{$s}\nNew lines\n" => "\nПереносы строк\n", - "context2{$s}\tTabs\t" => "\tТабы\t", - "context2{$s}\rCarriage returns\r" => "\rВозвраты кареток\r", - ]; - - // create temporary directory and dump messages - $poFileDirectory = __DIR__ . '/../../runtime/i18n'; - if (!is_dir($poFileDirectory)) { - mkdir($poFileDirectory); - } - if (is_file($poFileDirectory . '/test.po')) { - unlink($poFileDirectory . '/test.po'); - } - - $poFile = new GettextPoFile(); - $poFile->save($poFileDirectory . '/test.po', $messages); - - // load messages - $context1 = $poFile->load($poFileDirectory . '/test.po', 'context1'); - $context2 = $poFile->load($poFileDirectory . '/test.po', 'context2'); - - // context1 - $this->assertCount(2, $context1); - - $this->assertArrayHasKey('Hello?', $context1); - $this->assertTrue(in_array('Привет?', $context1)); - - $this->assertArrayHasKey('Hello!?!', $context1); - $this->assertTrue(in_array('', $context1)); - - // context2 - $this->assertCount(4, $context2); - - $this->assertArrayHasKey("\"Quotes\"", $context2); - $this->assertTrue(in_array('"Кавычки"', $context2)); - - $this->assertArrayHasKey("\nNew lines\n", $context2); - $this->assertTrue(in_array("\nПереносы строк\n", $context2)); - - $this->assertArrayHasKey("\tTabs\t", $context2); - $this->assertTrue(in_array("\tТабы\t", $context2)); - - $this->assertArrayHasKey("\rCarriage returns\r", $context2); - $this->assertTrue(in_array("\rВозвраты кареток\r", $context2)); - } -} diff --git a/tests/unit/framework/i18n/I18NTest.php b/tests/unit/framework/i18n/I18NTest.php deleted file mode 100644 index aa2356b..0000000 --- a/tests/unit/framework/i18n/I18NTest.php +++ /dev/null @@ -1,88 +0,0 @@ - - * @since 2.0 - * @group i18n - */ -class I18NTest extends TestCase -{ - /** - * @var I18N - */ - public $i18n; - - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - $this->i18n = new I18N([ - 'translations' => [ - 'test' => new PhpMessageSource([ - 'basePath' => '@yiiunit/data/i18n/messages', - ]) - ] - ]); - } - - public function testTranslate() - { - $msg = 'The dog runs fast.'; - $this->assertEquals('The dog runs fast.', $this->i18n->translate('test', $msg, [], 'en-US')); - $this->assertEquals('Der Hund rennt schnell.', $this->i18n->translate('test', $msg, [], 'de-DE')); - } - - public function testTranslateParams() - { - $msg = 'His speed is about {n} km/h.'; - $params = ['n' => 42]; - $this->assertEquals('His speed is about 42 km/h.', $this->i18n->translate('test', $msg, $params, 'en-US')); - $this->assertEquals('Seine Geschwindigkeit beträgt 42 km/h.', $this->i18n->translate('test', $msg, $params, 'de-DE')); - } - - public function testTranslateParams2() - { - if (!extension_loaded("intl")) { - $this->markTestSkipped("intl not installed. Skipping."); - } - $msg = 'His name is {name} and his speed is about {n, number} km/h.'; - $params = [ - 'n' => 42, - 'name' => 'DA VINCI', // http://petrix.com/dognames/d.html - ]; - $this->assertEquals('His name is DA VINCI and his speed is about 42 km/h.', $this->i18n->translate('test', $msg, $params, 'en-US')); - $this->assertEquals('Er heißt DA VINCI und ist 42 km/h schnell.', $this->i18n->translate('test', $msg, $params, 'de-DE')); - } - - public function testSpecialParams() - { - $msg = 'His speed is about {0} km/h.'; - - $this->assertEquals('His speed is about 0 km/h.', $this->i18n->translate('test', $msg, 0, 'en-US')); - $this->assertEquals('His speed is about 42 km/h.', $this->i18n->translate('test', $msg, 42, 'en-US')); - $this->assertEquals('His speed is about {0} km/h.', $this->i18n->translate('test', $msg, null, 'en-US')); - $this->assertEquals('His speed is about {0} km/h.', $this->i18n->translate('test', $msg, [], 'en-US')); - - $msg = 'His name is {name} and he is {age} years old.'; - $model = new ParamModel(); - $this->assertEquals('His name is peer and he is 5 years old.', $this->i18n->translate('test', $msg, $model, 'en-US')); - } -} - -class ParamModel extends Model -{ - public $name = 'peer'; - public $age = 5; -} diff --git a/tests/unit/framework/i18n/MessageFormatterTest.php b/tests/unit/framework/i18n/MessageFormatterTest.php deleted file mode 100644 index 1d5d007..0000000 --- a/tests/unit/framework/i18n/MessageFormatterTest.php +++ /dev/null @@ -1,337 +0,0 @@ - - * @since 2.0 - * @group i18n - */ -class MessageFormatterTest extends TestCase -{ - const N = 'n'; - const N_VALUE = 42; - const SUBJECT = 'сабж'; - const SUBJECT_VALUE = 'Answer to the Ultimate Question of Life, the Universe, and Everything'; - - public function patterns() - { - return [ - [ - '{'.self::SUBJECT.'} is {'.self::N.', number}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - self::N => self::N_VALUE, - self::SUBJECT => self::SUBJECT_VALUE, - ] - ], - - [ - '{'.self::SUBJECT.'} is {'.self::N.', number, integer}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - self::N => self::N_VALUE, - self::SUBJECT => self::SUBJECT_VALUE, - ] - ], - - // This one was provided by Aura.Intl. Thanks! - [<<<_MSG_ -{gender_of_host, select, - female {{num_guests, plural, offset:1 - =0 {{host} does not give a party.} - =1 {{host} invites {guest} to her party.} - =2 {{host} invites {guest} and one other person to her party.} - other {{host} invites {guest} and # other people to her party.}}} - male {{num_guests, plural, offset:1 - =0 {{host} does not give a party.} - =1 {{host} invites {guest} to his party.} - =2 {{host} invites {guest} and one other person to his party.} - other {{host} invites {guest} and # other people to his party.}}} - other {{num_guests, plural, offset:1 - =0 {{host} does not give a party.} - =1 {{host} invites {guest} to their party.} - =2 {{host} invites {guest} and one other person to their party.} - other {{host} invites {guest} and # other people to their party.}}}} -_MSG_ - , - 'ralph invites beep and 3 other people to his party.', - [ - 'gender_of_host' => 'male', - 'num_guests' => 4, - 'host' => 'ralph', - 'guest' => 'beep' - ], - defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.8', '<'), - 'select format is available in ICU > 4.4 and plural format with =X selector is avilable since 4.8' - ], - - [ - '{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', - 'Alexander is male and he loves Yii!', - [ - 'name' => 'Alexander', - 'gender' => 'male', - ], - defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.4.2', '<'), - 'select format is available in ICU > 4.4' - ], - - // verify pattern in select does not get replaced - [ - '{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', - 'Alexander is male and he loves Yii!', - [ - 'name' => 'Alexander', - 'gender' => 'male', - // following should not be replaced - 'he' => 'wtf', - 'she' => 'wtf', - 'it' => 'wtf', - ], - defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.4.2', '<'), - 'select format is available in ICU > 4.4' - ], - - // verify pattern in select message gets replaced - [ - '{name} is {gender} and {gender, select, female{she} male{{he}} other{it}} loves Yii!', - 'Alexander is male and wtf loves Yii!', - [ - 'name' => 'Alexander', - 'gender' => 'male', - 'he' => 'wtf', - 'she' => 'wtf', - ], - defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.8', '<'), - 'parameters in select format do not seem to work in ICU < 4.8' - ], - - // some parser specific verifications - [ - '{gender} and {gender, select, female{she} male{{he}} other{it}} loves {nr, number} is {gender}!', - 'male and wtf loves 42 is male!', - [ - 'nr' => 42, - 'gender' => 'male', - 'he' => 'wtf', - 'she' => 'wtf', - ], - defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.4.2', '<'), - 'select format is available in ICU > 4.4' - ], - - // test ICU version compatibility - [ - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', - [], - ], - [ - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', - 'Showing 1-10 of 12 items.', - [// A - 'begin' => 1, - 'end' => 10, - 'count' => 10, - 'totalCount' => 12, - 'page' => 1, - 'pageCount' => 2, - ] - ], - [ - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', - 'Showing 1-1 of 1 item.', - [// B - 'begin' => 1, - 'end' => 1, - 'count' => 1, - 'totalCount' => 1, - 'page' => 1, - 'pageCount' => 1, - ] - ], - [ - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', - 'Showing 0-0 of 0 items.', - [// C - 'begin' => 0, - 'end' => 0, - 'count' => 0, - 'totalCount' => 0, - 'page' => 1, - 'pageCount' => 1, - ] - ], - [ - 'Total {count, number} {count, plural, one{item} other{items}}.', - 'Total {count, number} {count, plural, one{item} other{items}}.', - [] - ], - [ - 'Total {count, number} {count, plural, one{item} other{items}}.', - 'Total 1 item.', - [ - 'count' => 1, - ] - ], - [ - 'Total {count, number} {count, plural, one{item} other{items}}.', - 'Total 1 item.', - [ - 'begin' => 5, - 'count' => 1, - 'end' => 10, - ] - ], - [ - '{0, plural, one {offer} other {offers}}', - '{0, plural, one {offer} other {offers}}', - [], - ], - [ - '{0, plural, one {offer} other {offers}}', - 'offers', - [0], - ], - [ - '{0, plural, one {offer} other {offers}}', - 'offer', - [1], - ], - [ - '{0, plural, one {offer} other {offers}}', - 'offers', - [13], - ], - ]; - } - - public function parsePatterns() - { - return [ - [ - self::SUBJECT_VALUE.' is {0, number}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - 0 => self::N_VALUE, - ] - ], - - [ - self::SUBJECT_VALUE.' is {'.self::N.', number}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - self::N => self::N_VALUE, - ] - ], - - [ - self::SUBJECT_VALUE.' is {'.self::N.', number, integer}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - self::N => self::N_VALUE, - ] - ], - - [ - "{0,number,integer} monkeys on {1,number,integer} trees make {2,number} monkeys per tree", - "4,560 monkeys on 123 trees make 37.073 monkeys per tree", - [ - 0 => 4560, - 1 => 123, - 2 => 37.073 - ], - 'en-US' - ], - - [ - "{0,number,integer} Affen auf {1,number,integer} Bäumen sind {2,number} Affen pro Baum", - "4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum", - [ - 0 => 4560, - 1 => 123, - 2 => 37.073 - ], - 'de', - ], - - [ - "{monkeyCount,number,integer} monkeys on {trees,number,integer} trees make {monkeysPerTree,number} monkeys per tree", - "4,560 monkeys on 123 trees make 37.073 monkeys per tree", - [ - 'monkeyCount' => 4560, - 'trees' => 123, - 'monkeysPerTree' => 37.073 - ], - 'en-US' - ], - - [ - "{monkeyCount,number,integer} Affen auf {trees,number,integer} Bäumen sind {monkeysPerTree,number} Affen pro Baum", - "4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum", - [ - 'monkeyCount' => 4560, - 'trees' => 123, - 'monkeysPerTree' => 37.073 - ], - 'de', - ], - ]; - } - - /** - * @dataProvider patterns - */ - public function testNamedArguments($pattern, $expected, $args, $skip = false, $skipMessage = '') - { - if ($skip) { - $this->markTestSkipped($skipMessage); - } - $formatter = new MessageFormatter(); - $result = $formatter->format($pattern, $args, 'en-US'); - $this->assertEquals($expected, $result, $formatter->getErrorMessage()); - } - - /** - * @dataProvider parsePatterns - */ - public function testParseNamedArguments($pattern, $expected, $args, $locale = 'en-US') - { - if (!extension_loaded("intl")) { - $this->markTestSkipped("intl not installed. Skipping."); - } - - $formatter = new MessageFormatter(); - $result = $formatter->parse($pattern, $expected, $locale); - $this->assertEquals($args, $result, $formatter->getErrorMessage() . ' Pattern: ' . $pattern); - } - - public function testInsufficientArguments() - { - $expected = '{'.self::SUBJECT.'} is '.self::N_VALUE; - - $formatter = new MessageFormatter(); - $result = $formatter->format('{'.self::SUBJECT.'} is {'.self::N.', number}', [ - self::N => self::N_VALUE, - ], 'en-US'); - - $this->assertEquals($expected, $result, $formatter->getErrorMessage()); - } - - public function testNoParams() - { - $pattern = '{'.self::SUBJECT.'} is '.self::N; - $formatter = new MessageFormatter(); - $result = $formatter->format($pattern, [], 'en-US'); - $this->assertEquals($pattern, $result, $formatter->getErrorMessage()); - } -} diff --git a/tests/unit/framework/log/LoggerTest.php b/tests/unit/framework/log/LoggerTest.php deleted file mode 100644 index 31a4c3b..0000000 --- a/tests/unit/framework/log/LoggerTest.php +++ /dev/null @@ -1,33 +0,0 @@ - - */ - -namespace yiiunit\framework\log; - - -use yii\debug\LogTarget; -use yii\log\FileTarget; -use yii\log\Logger; -use yiiunit\TestCase; - -class LoggerTest extends TestCase -{ - - public function testLog() - { - $logger = new Logger(); - - $logger->log('test1', Logger::LEVEL_INFO); - $this->assertEquals(1, count($logger->messages)); - $this->assertEquals('test1', $logger->messages[0][0]); - $this->assertEquals(Logger::LEVEL_INFO, $logger->messages[0][1]); - $this->assertEquals('application', $logger->messages[0][2]); - - $logger->log('test2', Logger::LEVEL_ERROR, 'category'); - $this->assertEquals(2, count($logger->messages)); - $this->assertEquals('test2', $logger->messages[1][0]); - $this->assertEquals(Logger::LEVEL_ERROR, $logger->messages[1][1]); - $this->assertEquals('category', $logger->messages[1][2]); - } -} \ No newline at end of file diff --git a/tests/unit/framework/log/TargetTest.php b/tests/unit/framework/log/TargetTest.php deleted file mode 100644 index b4ceb4c..0000000 --- a/tests/unit/framework/log/TargetTest.php +++ /dev/null @@ -1,90 +0,0 @@ - - */ - -namespace yiiunit\framework\log; - - -use yii\debug\LogTarget; -use yii\log\FileTarget; -use yii\log\Logger; -use yii\log\Target; -use yiiunit\TestCase; - -class TargetTest extends TestCase -{ - public static $messages; - - public function filters() - { - return [ - [[], ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']], - - [['levels' => 0], ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']], - [ - ['levels' => Logger::LEVEL_INFO | Logger::LEVEL_WARNING | Logger::LEVEL_ERROR | Logger::LEVEL_TRACE], - ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] - ], - [['levels' => ['error']], ['B', 'G', 'H']], - [['levels' => Logger::LEVEL_ERROR], ['B', 'G', 'H']], - [['levels' => ['error', 'warning']], ['B', 'C', 'G', 'H']], - [['levels' => Logger::LEVEL_ERROR | Logger::LEVEL_WARNING], ['B', 'C', 'G', 'H']], - - [['categories' => ['application']], ['A', 'B', 'C', 'D', 'E']], - [['categories' => ['application*']], ['A', 'B', 'C', 'D', 'E', 'F']], - [['categories' => ['application.*']], ['F']], - [['categories' => ['application.components']], []], - [['categories' => ['application.components.Test']], ['F']], - [['categories' => ['application.components.*']], ['F']], - [['categories' => ['application.*', 'yii.db.*']], ['F', 'G', 'H']], - [['categories' => ['application.*', 'yii.db.*'], 'except' => ['yii.db.Command.*']], ['F', 'G']], - - [['categories' => ['application', 'yii.db.*'], 'levels' => Logger::LEVEL_ERROR], ['B', 'G', 'H']], - [['categories' => ['application'], 'levels' => Logger::LEVEL_ERROR], ['B']], - [['categories' => ['application'], 'levels' => Logger::LEVEL_ERROR | Logger::LEVEL_WARNING], ['B', 'C']], - ]; - } - - /** - * @dataProvider filters - */ - public function testFilter($filter, $expected) - { - static::$messages = []; - - $logger = new Logger([ - 'targets' => [new TestTarget(array_merge($filter, ['logVars' => []]))], - 'flushInterval' => 1, - ]); - $logger->log('testA', Logger::LEVEL_INFO); - $logger->log('testB', Logger::LEVEL_ERROR); - $logger->log('testC', Logger::LEVEL_WARNING); - $logger->log('testD', Logger::LEVEL_TRACE); - $logger->log('testE', Logger::LEVEL_INFO, 'application'); - $logger->log('testF', Logger::LEVEL_INFO, 'application.components.Test'); - $logger->log('testG', Logger::LEVEL_ERROR, 'yii.db.Command'); - $logger->log('testH', Logger::LEVEL_ERROR, 'yii.db.Command.whatever'); - - $this->assertEquals(count($expected), count(static::$messages)); - $i = 0; - foreach($expected as $e) { - $this->assertEquals('test' . $e, static::$messages[$i++][0]); - } - } -} - -class TestTarget extends Target -{ - public $exportInterval = 1; - - /** - * Exports log [[messages]] to a specific destination. - * Child classes must implement this method. - */ - public function export() - { - TargetTest::$messages = array_merge(TargetTest::$messages, $this->messages); - $this->messages = []; - } -} \ No newline at end of file diff --git a/tests/unit/framework/mail/BaseMailerTest.php b/tests/unit/framework/mail/BaseMailerTest.php deleted file mode 100644 index 54a7952..0000000 --- a/tests/unit/framework/mail/BaseMailerTest.php +++ /dev/null @@ -1,379 +0,0 @@ -mockApplication([ - 'components' => [ - 'mail' => $this->createTestMailComponent(), - ] - ]); - $filePath = $this->getTestFilePath(); - if (!file_exists($filePath)) { - FileHelper::createDirectory($filePath); - } - } - - public function tearDown() - { - $filePath = $this->getTestFilePath(); - if (file_exists($filePath)) { - FileHelper::removeDirectory($filePath); - } - } - - /** - * @return string test file path. - */ - protected function getTestFilePath() - { - return Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . basename(get_class($this)) . '_' . getmypid(); - } - - /** - * @return Mailer test email component instance. - */ - protected function createTestMailComponent() - { - $component = new Mailer(); - $component->viewPath = $this->getTestFilePath(); - return $component; - } - - /** - * @return Mailer mailer instance - */ - protected function getTestMailComponent() - { - return Yii::$app->getComponent('mail'); - } - - // Tests : - - public function testSetupView() - { - $mailer = new Mailer(); - - $view = new View(); - $mailer->setView($view); - $this->assertEquals($view, $mailer->getView(), 'Unable to setup view!'); - - $viewConfig = [ - 'params' => [ - 'param1' => 'value1', - 'param2' => 'value2', - ] - ]; - $mailer->setView($viewConfig); - $view = $mailer->getView(); - $this->assertTrue(is_object($view), 'Unable to setup view via config!'); - $this->assertEquals($viewConfig['params'], $view->params, 'Unable to configure view via config array!'); - } - - /** - * @depends testSetupView - */ - public function testGetDefaultView() - { - $mailer = new Mailer(); - $view = $mailer->getView(); - $this->assertTrue(is_object($view), 'Unable to get default view!'); - } - - public function testCreateMessage() - { - $mailer = new Mailer(); - $message = $mailer->compose(); - $this->assertTrue(is_object($message), 'Unable to create message instance!'); - $this->assertEquals($mailer->messageClass, get_class($message), 'Invalid message class!'); - } - - /** - * @depends testCreateMessage - */ - public function testDefaultMessageConfig() - { - $mailer = new Mailer(); - - $notPropertyConfig = [ - 'charset' => 'utf-16', - 'from' => 'from@domain.com', - 'to' => 'to@domain.com', - 'cc' => 'cc@domain.com', - 'bcc' => 'bcc@domain.com', - 'subject' => 'Test subject', - 'textBody' => 'Test text body', - 'htmlBody' => 'Test HTML body', - ]; - $propertyConfig = [ - 'id' => 'test-id', - 'encoding' => 'test-encoding', - ]; - $messageConfig = array_merge($notPropertyConfig, $propertyConfig); - $mailer->messageConfig = $messageConfig; - - $message = $mailer->compose(); - - foreach ($notPropertyConfig as $name => $value) { - $this->assertEquals($value, $message->{'_' . $name}); - } - foreach ($propertyConfig as $name => $value) { - $this->assertEquals($value, $message->$name); - } - } - - /** - * @depends testGetDefaultView - */ - public function testRender() - { - $mailer = $this->getTestMailComponent(); - - $viewName = 'test_view'; - $viewFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . $viewName . '.php'; - $viewFileContent = ''; - file_put_contents($viewFileName, $viewFileContent); - - $params = [ - 'testParam' => 'test output' - ]; - $renderResult = $mailer->render($viewName, $params); - $this->assertEquals($params['testParam'], $renderResult); - } - - /** - * @depends testRender - */ - public function testRenderLayout() - { - $mailer = $this->getTestMailComponent(); - - $filePath = $this->getTestFilePath(); - - $viewName = 'test_view'; - $viewFileName = $filePath . DIRECTORY_SEPARATOR . $viewName . '.php'; - $viewFileContent = 'view file content'; - file_put_contents($viewFileName, $viewFileContent); - - $layoutName = 'test_layout'; - $layoutFileName = $filePath . DIRECTORY_SEPARATOR . $layoutName . '.php'; - $layoutFileContent = 'Begin Layout End Layout'; - file_put_contents($layoutFileName, $layoutFileContent); - - $renderResult = $mailer->render($viewName, [], $layoutName); - $this->assertEquals('Begin Layout ' . $viewFileContent . ' End Layout', $renderResult); - } - - /** - * @depends testCreateMessage - * @depends testRender - */ - public function testCompose() - { - $mailer = $this->getTestMailComponent(); - $mailer->htmlLayout = false; - $mailer->textLayout = false; - - $htmlViewName = 'test_html_view'; - $htmlViewFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . $htmlViewName . '.php'; - $htmlViewFileContent = 'HTML view file content'; - file_put_contents($htmlViewFileName, $htmlViewFileContent); - - $textViewName = 'test_text_view'; - $textViewFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . $textViewName . '.php'; - $textViewFileContent = 'Plain text view file content'; - file_put_contents($textViewFileName, $textViewFileContent); - - $message = $mailer->compose([ - 'html' => $htmlViewName, - 'text' => $textViewName, - ]); - $this->assertEquals($htmlViewFileContent, $message->_htmlBody, 'Unable to render html!'); - $this->assertEquals($textViewFileContent, $message->_textBody, 'Unable to render text!'); - - $message = $mailer->compose($htmlViewName); - $this->assertEquals($htmlViewFileContent, $message->_htmlBody, 'Unable to render html by direct view!'); - $this->assertEquals(strip_tags($htmlViewFileContent), $message->_textBody, 'Unable to render text by direct view!'); - } - - public function testUseFileTransport() - { - $mailer = new Mailer(); - $this->assertFalse($mailer->useFileTransport); - $this->assertEquals('@runtime/mail', $mailer->fileTransportPath); - - $mailer->fileTransportPath = '@yiiunit/runtime/mail'; - $mailer->useFileTransport = true; - $mailer->fileTransportCallback = function () { - return 'message.txt'; - }; - $message = $mailer->compose() - ->setTo('to@example.com') - ->setFrom('from@example.com') - ->setSubject('test subject') - ->setTextBody('text body' . microtime(true)); - $this->assertTrue($mailer->send($message)); - $file = Yii::getAlias($mailer->fileTransportPath) . '/message.txt'; - $this->assertTrue(is_file($file)); - $this->assertEquals($message->toString(), file_get_contents($file)); - } - - public function testBeforeSendEvent() - { - $message = new Message(); - - $mailerMock = $this->getMockBuilder('yiiunit\framework\mail\Mailer')->setMethods(['beforeSend','afterSend'])->getMock(); - $mailerMock->expects($this->once())->method('beforeSend')->with($message)->will($this->returnValue(true)); - $mailerMock->expects($this->once())->method('afterSend')->with($message,true); - $mailerMock->send($message); - } - -} - -/** - * Test Mailer class - */ -class Mailer extends BaseMailer -{ - public $messageClass = 'yiiunit\framework\mail\Message'; - public $sentMessages = []; - - protected function sendMessage($message) - { - $this->sentMessages[] = $message; - return true; - } -} - -/** - * Test Message class - */ -class Message extends BaseMessage -{ - public $id; - public $encoding; - public $_charset; - public $_from; - public $_replyTo; - public $_to; - public $_cc; - public $_bcc; - public $_subject; - public $_textBody; - public $_htmlBody; - - public function getCharset() - { - return $this->_charset; - } - - public function setCharset($charset) - { - $this->_charset = $charset; - return $this; - } - - public function getFrom() - { - return $this->_from; - } - - public function setFrom($from) - { - $this->_from = $from; - return $this; - } - - public function getTo() - { - return $this->_to; - } - - public function setTo($to) - { - $this->_to = $to; - return $this; - } - - public function getCc() - { - return $this->_cc; - } - - public function setCc($cc) - { - $this->_cc = $cc; - return $this; - } - - public function getBcc() - { - return $this->_bcc; - } - - public function setBcc($bcc) - { - $this->_bcc = $bcc; - return $this; - } - - public function getSubject() - { - return $this->_subject; - } - - public function setSubject($subject) - { - $this->_subject = $subject; - return $this; - } - - public function getReplyTo() - { - return $this->_replyTo; - } - - public function setReplyTo($replyTo) - { - $this->_replyTo = $replyTo; - return $this; - } - - public function setTextBody($text) - { - $this->_textBody = $text; - return $this; - } - - public function setHtmlBody($html) - { - $this->_htmlBody = $html; - return $this; - } - - public function attachContent($content, array $options = []) {} - - public function attach($fileName, array $options = []) {} - - public function embed($fileName, array $options = []) {} - - public function embedContent($content, array $options = []) {} - - public function toString() - { - return var_export($this, true); - } -} diff --git a/tests/unit/framework/mail/BaseMessageTest.php b/tests/unit/framework/mail/BaseMessageTest.php deleted file mode 100644 index e9ed49e..0000000 --- a/tests/unit/framework/mail/BaseMessageTest.php +++ /dev/null @@ -1,129 +0,0 @@ -mockApplication([ - 'components' => [ - 'mail' => $this->createTestEmailComponent() - ] - ]); - } - - /** - * @return Mailer test email component instance. - */ - protected function createTestEmailComponent() - { - $component = new TestMailer(); - return $component; - } - - /** - * @return TestMailer mailer instance. - */ - protected function getMailer() - { - return Yii::$app->getComponent('mail'); - } - - // Tests : - - public function testSend() - { - $mailer = $this->getMailer(); - $message = $mailer->compose(); - $message->send($mailer); - $this->assertEquals($message, $mailer->sentMessages[0], 'Unable to send message!'); - } - - public function testToString() - { - $mailer = $this->getMailer(); - $message = $mailer->compose(); - $this->assertEquals($message->toString(), '' . $message); - } -} - -/** - * Test Mailer class - */ -class TestMailer extends BaseMailer -{ - public $messageClass = 'yiiunit\framework\mail\TestMessage'; - public $sentMessages = []; - - protected function sendMessage($message) - { - $this->sentMessages[] = $message; - } -} - -/** - * Test Message class - */ -class TestMessage extends BaseMessage -{ - public $text; - public $html; - - public function getCharset() {return '';} - - public function setCharset($charset) {} - - public function getFrom() {return '';} - - public function setFrom($from) {} - - public function getReplyTo() {return '';} - - public function setReplyTo($replyTo) {} - - public function getTo() {return '';} - - public function setTo($to) {} - - public function getCc() {return '';} - - public function setCc($cc) {} - - public function getBcc() {return '';} - - public function setBcc($bcc) {} - - public function getSubject() {return '';} - - public function setSubject($subject) {} - - public function setTextBody($text) { - $this->text = $text; - } - - public function setHtmlBody($html) { - $this->html = $html; - } - - public function attachContent($content, array $options = []) {} - - public function attach($fileName, array $options = []) {} - - public function embed($fileName, array $options = []) {} - - public function embedContent($content, array $options = []) {} - - public function toString() - { - return get_class($this); - } -} diff --git a/tests/unit/framework/rbac/ManagerTestCase.php b/tests/unit/framework/rbac/ManagerTestCase.php deleted file mode 100644 index cbf8de8..0000000 --- a/tests/unit/framework/rbac/ManagerTestCase.php +++ /dev/null @@ -1,263 +0,0 @@ -auth->createItem($name, $type, $description, $bizRule, $data); - $this->assertTrue($item instanceof Item); - $this->assertEquals($item->type, $type); - $this->assertEquals($item->name, $name); - $this->assertEquals($item->description, $description); - $this->assertEquals($item->bizRule, $bizRule); - $this->assertEquals($item->data, $data); - - // test shortcut - $name2 = 'createUser'; - $item2 = $this->auth->createRole($name2, $description, $bizRule, $data); - $this->assertEquals($item2->type, Item::TYPE_ROLE); - - // test adding an item with the same name - $this->setExpectedException('\yii\base\Exception'); - $this->auth->createItem($name, $type, $description, $bizRule, $data); - } - - public function testGetItem() - { - $this->assertTrue($this->auth->getItem('readPost') instanceof Item); - $this->assertTrue($this->auth->getItem('reader') instanceof Item); - $this->assertNull($this->auth->getItem('unknown')); - } - - public function testRemoveAuthItem() - { - $this->assertTrue($this->auth->getItem('updatePost') instanceof Item); - $this->assertTrue($this->auth->removeItem('updatePost')); - $this->assertNull($this->auth->getItem('updatePost')); - $this->assertFalse($this->auth->removeItem('updatePost')); - } - - public function testChangeItemName() - { - $item = $this->auth->getItem('readPost'); - $this->assertTrue($item instanceof Item); - $this->assertTrue($this->auth->hasItemChild('reader', 'readPost')); - $item->name = 'readPost2'; - $item->save(); - $this->assertNull($this->auth->getItem('readPost')); - $this->assertEquals($this->auth->getItem('readPost2'), $item); - $this->assertFalse($this->auth->hasItemChild('reader', 'readPost')); - $this->assertTrue($this->auth->hasItemChild('reader', 'readPost2')); - } - - public function testAddItemChild() - { - $this->auth->addItemChild('createPost', 'updatePost'); - - // test adding upper level item to lower one - $this->setExpectedException('\yii\base\Exception'); - $this->auth->addItemChild('readPost', 'reader'); - } - - public function testAddItemChild2() - { - // test adding inexistent items - $this->setExpectedException('\yii\base\Exception'); - $this->assertFalse($this->auth->addItemChild('createPost2', 'updatePost')); - } - - public function testRemoveItemChild() - { - $this->assertTrue($this->auth->hasItemChild('reader', 'readPost')); - $this->assertTrue($this->auth->removeItemChild('reader', 'readPost')); - $this->assertFalse($this->auth->hasItemChild('reader', 'readPost')); - $this->assertFalse($this->auth->removeItemChild('reader', 'readPost')); - } - - public function testGetItemChildren() - { - $this->assertEquals([], $this->auth->getItemChildren('readPost')); - $children = $this->auth->getItemChildren('author'); - $this->assertEquals(3, count($children)); - $this->assertTrue(reset($children) instanceof Item); - } - - public function testAssign() - { - $auth = $this->auth->assign('new user', 'createPost', 'rule', 'data'); - $this->assertTrue($auth instanceof Assignment); - $this->assertEquals($auth->userId, 'new user'); - $this->assertEquals($auth->itemName, 'createPost'); - $this->assertEquals($auth->bizRule, 'rule'); - $this->assertEquals($auth->data, 'data'); - - $this->setExpectedException('\yii\base\Exception'); - $this->auth->assign('new user', 'createPost2', 'rule', 'data'); - } - - public function testRevoke() - { - $this->assertTrue($this->auth->isAssigned('author B', 'author')); - $auth = $this->auth->getAssignment('author B', 'author'); - $this->assertTrue($auth instanceof Assignment); - $this->assertTrue($this->auth->revoke('author B', 'author')); - $this->assertFalse($this->auth->isAssigned('author B', 'author')); - $this->assertFalse($this->auth->revoke('author B', 'author')); - } - - public function testRevokeAll() - { - $this->assertTrue($this->auth->revokeAll('reader E')); - $this->assertFalse($this->auth->isAssigned('reader E', 'reader')); - } - - public function testGetAssignments() - { - $this->auth->assign('author B', 'deletePost'); - $auths = $this->auth->getAssignments('author B'); - $this->assertEquals(2, count($auths)); - $this->assertTrue(reset($auths) instanceof Assignment); - } - - public function testGetItems() - { - $this->assertEquals(count($this->auth->getRoles()), 4); - $this->assertEquals(count($this->auth->getOperations()), 4); - $this->assertEquals(count($this->auth->getTasks()), 1); - $this->assertEquals(count($this->auth->getItems()), 9); - - $this->assertEquals(count($this->auth->getItems('author B', null)), 1); - $this->assertEquals(count($this->auth->getItems('author C', null)), 0); - $this->assertEquals(count($this->auth->getItems('author B', Item::TYPE_ROLE)), 1); - $this->assertEquals(count($this->auth->getItems('author B', Item::TYPE_OPERATION)), 0); - } - - public function testClearAll() - { - $this->auth->clearAll(); - $this->assertEquals(count($this->auth->getRoles()), 0); - $this->assertEquals(count($this->auth->getOperations()), 0); - $this->assertEquals(count($this->auth->getTasks()), 0); - $this->assertEquals(count($this->auth->getItems()), 0); - $this->assertEquals(count($this->auth->getAssignments('author B')), 0); - } - - public function testClearAssignments() - { - $this->auth->clearAssignments(); - $this->assertEquals(count($this->auth->getAssignments('author B')), 0); - } - - public function testDetectLoop() - { - $this->setExpectedException('\yii\base\Exception'); - $this->auth->addItemChild('readPost', 'readPost'); - } - - public function testExecuteBizRule() - { - $this->assertTrue($this->auth->executeBizRule(null, [], null)); - $this->assertTrue($this->auth->executeBizRule('return 1 == true;', [], null)); - $this->assertTrue($this->auth->executeBizRule('return $params[0] == $params[1];', [1, '1'], null)); - $this->assertFalse($this->auth->executeBizRule('invalid;', [], null)); - } - - public function testCheckAccess() - { - $results = [ - 'reader A' => [ - 'createPost' => false, - 'readPost' => true, - 'updatePost' => false, - 'updateOwnPost' => false, - 'deletePost' => false, - ], - 'author B' => [ - 'createPost' => true, - 'readPost' => true, - 'updatePost' => true, - 'updateOwnPost' => true, - 'deletePost' => false, - ], - 'editor C' => [ - 'createPost' => false, - 'readPost' => true, - 'updatePost' => true, - 'updateOwnPost' => false, - 'deletePost' => false, - ], - 'admin D' => [ - 'createPost' => true, - 'readPost' => true, - 'updatePost' => true, - 'updateOwnPost' => false, - 'deletePost' => true, - ], - 'reader E' => [ - 'createPost' => false, - 'readPost' => false, - 'updatePost' => false, - 'updateOwnPost' => false, - 'deletePost' => false, - ], - ]; - - $params = ['authorID' => 'author B']; - - foreach (['reader A', 'author B', 'editor C', 'admin D'] as $user) { - $params['userID'] = $user; - foreach (['createPost', 'readPost', 'updatePost', 'updateOwnPost', 'deletePost'] as $operation) { - $result = $this->auth->checkAccess($user, $operation, $params); - $this->assertEquals($results[$user][$operation], $result); - } - } - } - - protected function prepareData() - { - $this->auth->createOperation('createPost', 'create a post'); - $this->auth->createOperation('readPost', 'read a post'); - $this->auth->createOperation('updatePost', 'update a post'); - $this->auth->createOperation('deletePost', 'delete a post'); - - $task = $this->auth->createTask('updateOwnPost', 'update a post by author himself', 'return $params["authorID"] == $params["userID"];'); - $task->addChild('updatePost'); - - $role = $this->auth->createRole('reader'); - $role->addChild('readPost'); - - $role = $this->auth->createRole('author'); - $role->addChild('reader'); - $role->addChild('createPost'); - $role->addChild('updateOwnPost'); - - $role = $this->auth->createRole('editor'); - $role->addChild('reader'); - $role->addChild('updatePost'); - - $role = $this->auth->createRole('admin'); - $role->addChild('editor'); - $role->addChild('author'); - $role->addChild('deletePost'); - - $this->auth->assign('reader A', 'reader'); - $this->auth->assign('author B', 'author'); - $this->auth->assign('editor C', 'editor'); - $this->auth->assign('admin D', 'admin'); - $this->auth->assign('reader E', 'reader'); - } -} diff --git a/tests/unit/framework/rbac/PhpManagerTest.php b/tests/unit/framework/rbac/PhpManagerTest.php deleted file mode 100644 index 8c5d366..0000000 --- a/tests/unit/framework/rbac/PhpManagerTest.php +++ /dev/null @@ -1,38 +0,0 @@ -mockApplication(); - $authFile = Yii::$app->getRuntimePath() . '/rbac.php'; - @unlink($authFile); - $this->auth = new PhpManager; - $this->auth->authFile = $authFile; - $this->auth->init(); - $this->prepareData(); - } - - protected function tearDown() - { - parent::tearDown(); - @unlink($this->auth->authFile); - } - - public function testSaveLoad() - { - $this->auth->save(); - $this->auth->clearAll(); - $this->auth->load(); - $this->testCheckAccess(); - } -} diff --git a/tests/unit/framework/requirements/YiiRequirementCheckerTest.php b/tests/unit/framework/requirements/YiiRequirementCheckerTest.php deleted file mode 100644 index 4339dcf..0000000 --- a/tests/unit/framework/requirements/YiiRequirementCheckerTest.php +++ /dev/null @@ -1,197 +0,0 @@ - [ - 'name' => 'Requirement 1', - 'mandatory' => true, - 'condition' => true, - 'by' => 'Requirement 1', - 'memo' => 'Requirement 1', - ], - 'requirementError' => [ - 'name' => 'Requirement 2', - 'mandatory' => true, - 'condition' => false, - 'by' => 'Requirement 2', - 'memo' => 'Requirement 2', - ], - 'requirementWarning' => [ - 'name' => 'Requirement 3', - 'mandatory' => false, - 'condition' => false, - 'by' => 'Requirement 3', - 'memo' => 'Requirement 3', - ], - ]; - - $checkResult = $requirementsChecker->check($requirements)->getResult(); - $summary = $checkResult['summary']; - - $this->assertEquals(count($requirements), $summary['total'], 'Wrong summary total!'); - $this->assertEquals(1, $summary['errors'], 'Wrong summary errors!'); - $this->assertEquals(1, $summary['warnings'], 'Wrong summary warnings!'); - - $checkedRequirements = $checkResult['requirements']; - $requirementsKeys = array_flip(array_keys($requirements)); - - $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['error'], 'Passed requirement has an error!'); - $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['warning'], 'Passed requirement has a warning!'); - - $this->assertEquals(true, $checkedRequirements[$requirementsKeys['requirementError']]['error'], 'Error requirement has no error!'); - - $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementWarning']]['error'], 'Error requirement has an error!'); - $this->assertEquals(true, $checkedRequirements[$requirementsKeys['requirementWarning']]['warning'], 'Error requirement has no warning!'); - } - - /** - * @depends testCheck - */ - public function testCheckEval() - { - $requirementsChecker = new YiiRequirementChecker(); - - $requirements = [ - 'requirementPass' => [ - 'name' => 'Requirement 1', - 'mandatory' => true, - 'condition' => 'eval:2>1', - 'by' => 'Requirement 1', - 'memo' => 'Requirement 1', - ], - 'requirementError' => [ - 'name' => 'Requirement 2', - 'mandatory' => true, - 'condition' => 'eval:2<1', - 'by' => 'Requirement 2', - 'memo' => 'Requirement 2', - ], - ]; - - $checkResult = $requirementsChecker->check($requirements)->getResult(); - $checkedRequirements = $checkResult['requirements']; - $requirementsKeys = array_flip(array_keys($requirements)); - - $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['error'], 'Passed requirement has an error!'); - $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['warning'], 'Passed requirement has a warning!'); - - $this->assertEquals(true, $checkedRequirements[$requirementsKeys['requirementError']]['error'], 'Error requirement has no error!'); - } - - /** - * @depends testCheck - */ - public function testCheckChained() - { - $requirementsChecker = new YiiRequirementChecker(); - - $requirements1 = [ - [ - 'name' => 'Requirement 1', - 'mandatory' => true, - 'condition' => true, - 'by' => 'Requirement 1', - 'memo' => 'Requirement 1', - ], - ]; - $requirements2 = [ - [ - 'name' => 'Requirement 2', - 'mandatory' => true, - 'condition' => true, - 'by' => 'Requirement 2', - 'memo' => 'Requirement 2', - ], - ]; - $checkResult = $requirementsChecker->check($requirements1)->check($requirements2)->getResult(); - - $mergedRequirements = array_merge($requirements1, $requirements2); - - $this->assertEquals(count($mergedRequirements), $checkResult['summary']['total'], 'Wrong total checks count!'); - foreach ($mergedRequirements as $key => $mergedRequirement) { - $this->assertEquals($mergedRequirement['name'], $checkResult['requirements'][$key]['name'], 'Wrong requirements list!'); - } - } - - public function testCheckPhpExtensionVersion() - { - $requirementsChecker = new YiiRequirementChecker(); - - $this->assertFalse($requirementsChecker->checkPhpExtensionVersion('some_unexisting_php_extension', '0.1'), 'No fail while checking unexisting extension!'); - $this->assertTrue($requirementsChecker->checkPhpExtensionVersion('pdo', '1.0'), 'Unable to check PDO version!'); - } - - /** - * Data provider for [[testGetByteSize()]]. - * @return array - */ - public function dataProviderGetByteSize() - { - return [ - ['456', 456], - ['5K', 5*1024], - ['16KB', 16*1024], - ['4M', 4*1024*1024], - ['14MB', 14*1024*1024], - ['7G', 7*1024*1024*1024], - ['12GB', 12*1024*1024*1024], - ]; - } - - /** - * @dataProvider dataProviderGetByteSize - * - * @param string $verboseValue verbose value. - * @param integer $expectedByteSize expected byte size. - */ - public function testGetByteSize($verboseValue, $expectedByteSize) - { - $requirementsChecker = new YiiRequirementChecker(); - - $this->assertEquals($expectedByteSize, $requirementsChecker->getByteSize($verboseValue), "Wrong byte size for '{$verboseValue}'!"); - } - - /** - * Data provider for [[testCompareByteSize()]] - * @return array - */ - public function dataProviderCompareByteSize() - { - return [ - ['2M', '2K', '>', true], - ['2M', '2K', '>=', true], - ['1K', '1024', '==', true], - ['10M', '11M', '<', true], - ['10M', '11M', '<=', true], - ]; - } - - /** - * @depends testGetByteSize - * @dataProvider dataProviderCompareByteSize - * - * @param string $a first value. - * @param string $b second value. - * @param string $compare comparison. - * @param boolean $expectedComparisonResult expected comparison result. - */ - public function testCompareByteSize($a, $b, $compare, $expectedComparisonResult) - { - $requirementsChecker = new YiiRequirementChecker(); - $this->assertEquals($expectedComparisonResult, $requirementsChecker->compareByteSize($a, $b, $compare), "Wrong compare '{$a}{$compare}{$b}'"); - } -} diff --git a/tests/unit/framework/validators/BooleanValidatorTest.php b/tests/unit/framework/validators/BooleanValidatorTest.php deleted file mode 100644 index 5ed0307..0000000 --- a/tests/unit/framework/validators/BooleanValidatorTest.php +++ /dev/null @@ -1,59 +0,0 @@ -mockApplication(); - } - - public function testValidateValue() - { - $val = new BooleanValidator; - $this->assertTrue($val->validate(true)); - $this->assertTrue($val->validate(false)); - $this->assertTrue($val->validate('0')); - $this->assertTrue($val->validate('1')); - $this->assertFalse($val->validate(null)); - $this->assertFalse($val->validate([])); - $val->strict = true; - $this->assertTrue($val->validate('0')); - $this->assertTrue($val->validate('1')); - $this->assertFalse($val->validate(true)); - $this->assertFalse($val->validate(false)); - $val->trueValue = true; - $val->falseValue = false; - $this->assertFalse($val->validate('0')); - $this->assertFalse($val->validate([])); - $this->assertTrue($val->validate(true)); - $this->assertTrue($val->validate(false)); - } - - public function testValidateAttributeAndError() - { - $obj = new FakedValidationModel; - $obj->attrA = true; - $obj->attrB = '1'; - $obj->attrC = '0'; - $obj->attrD = []; - $val = new BooleanValidator; - $val->validateAttribute($obj, 'attrA'); - $this->assertFalse($obj->hasErrors('attrA')); - $val->validateAttribute($obj, 'attrC'); - $this->assertFalse($obj->hasErrors('attrC')); - $val->strict = true; - $val->validateAttribute($obj, 'attrB'); - $this->assertFalse($obj->hasErrors('attrB')); - $val->validateAttribute($obj, 'attrD'); - $this->assertTrue($obj->hasErrors('attrD')); - } -} diff --git a/tests/unit/framework/validators/CompareValidatorTest.php b/tests/unit/framework/validators/CompareValidatorTest.php deleted file mode 100644 index 1e18faf..0000000 --- a/tests/unit/framework/validators/CompareValidatorTest.php +++ /dev/null @@ -1,175 +0,0 @@ -mockApplication(); - } - - public function testValidateValueException() - { - $this->setExpectedException('yii\base\InvalidConfigException'); - $val = new CompareValidator; - $val->validate('val'); - } - - public function testValidateValue() - { - $value = 18449; - // default config - $val = new CompareValidator(['compareValue' => $value]); - $this->assertTrue($val->validate($value)); - $this->assertTrue($val->validate((string)$value)); - $this->assertFalse($val->validate($value + 1)); - foreach ($this->getOperationTestData($value) as $op => $tests) { - $val = new CompareValidator(['compareValue' => $value]); - $val->operator = $op; - foreach ($tests as $test) { - $this->assertEquals($test[1], $val->validate($test[0])); - } - } - } - - protected function getOperationTestData($value) - { - return [ - '===' => [ - [$value, true], - [(string)$value, false], - [(float)$value, false], - [$value + 1, false], - ], - '!=' => [ - [$value, false], - [(string)$value, false], - [(float)$value, false], - [$value + 0.00001, true], - [false, true], - ], - '!==' => [ - [$value, false], - [(string)$value, true], - [(float)$value, true], - [false, true], - ], - '>' => [ - [$value, false], - [$value + 1, true], - [$value - 1, false], - ], - '>=' => [ - [$value, true], - [$value + 1, true], - [$value - 1, false], - ], - '<' => [ - [$value, false], - [$value + 1, false], - [$value - 1, true], - ], - '<=' => [ - [$value, true], - [$value + 1, false], - [$value - 1, true], - ], - //'non-op' => [ - // [$value, false], - // [$value + 1, false], - // [$value - 1, false], - //], - ]; - } - - public function testValidateAttribute() - { - // invalid-array - $val = new CompareValidator; - $model = new FakedValidationModel; - $model->attr = ['test_val']; - $val->validateAttribute($model, 'attr'); - $this->assertTrue($model->hasErrors('attr')); - $val = new CompareValidator(['compareValue' => 'test-string']); - $model = new FakedValidationModel; - $model->attr_test = 'test-string'; - $val->validateAttribute($model, 'attr_test'); - $this->assertFalse($model->hasErrors('attr_test')); - $val = new CompareValidator(['compareAttribute' => 'attr_test_val']); - $model = new FakedValidationModel; - $model->attr_test = 'test-string'; - $model->attr_test_val = 'test-string'; - $val->validateAttribute($model, 'attr_test'); - $this->assertFalse($model->hasErrors('attr_test')); - $this->assertFalse($model->hasErrors('attr_test_val')); - $val = new CompareValidator(['compareAttribute' => 'attr_test_val']); - $model = new FakedValidationModel; - $model->attr_test = 'test-string'; - $model->attr_test_val = 'test-string-false'; - $val->validateAttribute($model, 'attr_test'); - $this->assertTrue($model->hasErrors('attr_test')); - $this->assertFalse($model->hasErrors('attr_test_val')); - // assume: _repeat - $val = new CompareValidator; - $model = new FakedValidationModel; - $model->attr_test = 'test-string'; - $model->attr_test_repeat = 'test-string'; - $val->validateAttribute($model, 'attr_test'); - $this->assertFalse($model->hasErrors('attr_test')); - $this->assertFalse($model->hasErrors('attr_test_repeat')); - $val = new CompareValidator; - $model = new FakedValidationModel; - $model->attr_test = 'test-string'; - $model->attr_test_repeat = 'test-string2'; - $val->validateAttribute($model, 'attr_test'); - $this->assertTrue($model->hasErrors('attr_test')); - $this->assertFalse($model->hasErrors('attr_test_repeat')); - // not existing op - $val = new CompareValidator(); - $val->operator = '<>'; - $model = FakedValidationModel::createWithAttributes(['attr_o' => 5, 'attr_o_repeat' => 5]); - $val->validateAttribute($model, 'attr_o'); - $this->assertTrue($model->hasErrors('attr_o')); - } - - public function testValidateAttributeOperators() - { - $value = 55; - foreach ($this->getOperationTestData($value) as $operator => $tests) { - $val = new CompareValidator(['operator' => $operator, 'compareValue' => $value]); - foreach ($tests as $test) { - $model = new FakedValidationModel; - $model->attr_test = $test[0]; - $val->validateAttribute($model, 'attr_test'); - $this->assertEquals($test[1], !$model->hasErrors('attr_test')); - } - - } - } - - public function testEnsureMessageSetOnInit() - { - foreach ($this->getOperationTestData(1337) as $operator => $tests) { - $val = new CompareValidator(['operator' => $operator]); - $this->assertTrue(strlen($val->message) > 1); - } - try { - $val = new CompareValidator(['operator' => '<>']); - } catch (InvalidConfigException $e) { - return; - } - catch (\Exception $e) { - $this->fail('InvalidConfigException expected' . get_class($e) . 'received'); - return; - } - $this->fail('InvalidConfigException expected none received'); - } -} diff --git a/tests/unit/framework/validators/DateValidatorTest.php b/tests/unit/framework/validators/DateValidatorTest.php deleted file mode 100644 index 98a114f..0000000 --- a/tests/unit/framework/validators/DateValidatorTest.php +++ /dev/null @@ -1,71 +0,0 @@ -mockApplication(); - } - - public function testEnsureMessageIsSet() - { - $val = new DateValidator; - $this->assertTrue($val->message !== null && strlen($val->message) > 1); - } - - public function testValidateValue() - { - $val = new DateValidator; - $this->assertFalse($val->validate('3232-32-32')); - $this->assertTrue($val->validate('2013-09-13')); - $this->assertFalse($val->validate('31.7.2013')); - $this->assertFalse($val->validate('31-7-2013')); - $this->assertFalse($val->validate(time())); - $val->format = 'U'; - $this->assertTrue($val->validate(time())); - $val->format = 'd.m.Y'; - $this->assertTrue($val->validate('31.7.2013')); - $val->format = 'Y-m-!d H:i:s'; - $this->assertTrue($val->validate('2009-02-15 15:16:17')); - } - - public function testValidateAttribute() - { - // error-array-add - $val = new DateValidator; - $model = new FakedValidationModel; - $model->attr_date = '2013-09-13'; - $val->validateAttribute($model, 'attr_date'); - $this->assertFalse($model->hasErrors('attr_date')); - $model = new FakedValidationModel; - $model->attr_date = '1375293913'; - $val->validateAttribute($model, 'attr_date'); - $this->assertTrue($model->hasErrors('attr_date')); - //// timestamp attribute - $val = new DateValidator(['timestampAttribute' => 'attr_timestamp']); - $model = new FakedValidationModel; - $model->attr_date = '2013-09-13'; - $model->attr_timestamp = true; - $val->validateAttribute($model, 'attr_date'); - $this->assertFalse($model->hasErrors('attr_date')); - $this->assertFalse($model->hasErrors('attr_timestamp')); - $this->assertEquals( - DateTime::createFromFormat($val->format, '2013-09-13')->getTimestamp(), - $model->attr_timestamp - ); - $val = new DateValidator(); - $model = FakedValidationModel::createWithAttributes(['attr_date' => []]); - $val->validateAttribute($model, 'attr_date'); - $this->assertTrue($model->hasErrors('attr_date')); - - } -} diff --git a/tests/unit/framework/validators/DefaultValueValidatorTest.php b/tests/unit/framework/validators/DefaultValueValidatorTest.php deleted file mode 100644 index 48537d8..0000000 --- a/tests/unit/framework/validators/DefaultValueValidatorTest.php +++ /dev/null @@ -1,38 +0,0 @@ -mockApplication(); - } - - public function testValidateAttribute() - { - $val = new DefaultValueValidator; - $val->value = 'test_value'; - $obj = new \stdclass; - $obj->attrA = 'attrA'; - $obj->attrB = null; - $obj->attrC = ''; - // original values to chek which attritubes where modified - $objB = clone $obj; - $val->validateAttribute($obj, 'attrB'); - $this->assertEquals($val->value, $obj->attrB); - $this->assertEquals($objB->attrA, $obj->attrA); - $val->value = 'new_test_value'; - $obj = clone $objB; // get clean object - $val->validateAttribute($obj, 'attrC'); - $this->assertEquals('new_test_value', $obj->attrC); - $this->assertEquals($objB->attrA, $obj->attrA); - $val->validateAttribute($obj, 'attrA'); - $this->assertEquals($objB->attrA, $obj->attrA); - } -} diff --git a/tests/unit/framework/validators/EmailValidatorTest.php b/tests/unit/framework/validators/EmailValidatorTest.php deleted file mode 100644 index 3fcd2dd..0000000 --- a/tests/unit/framework/validators/EmailValidatorTest.php +++ /dev/null @@ -1,108 +0,0 @@ -mockApplication(); - } - - public function testValidateValue() - { - $validator = new EmailValidator(); - - $this->assertTrue($validator->validate('sam@rmcreative.ru')); - $this->assertTrue($validator->validate('5011@gmail.com')); - $this->assertFalse($validator->validate('rmcreative.ru')); - $this->assertFalse($validator->validate('Carsten Brandt ')); - $this->assertFalse($validator->validate('"Carsten Brandt" ')); - $this->assertFalse($validator->validate('')); - $this->assertFalse($validator->validate('info@örtliches.de')); - $this->assertFalse($validator->validate('sam@рмкреатиф.ru')); - - $validator->allowName = true; - - $this->assertTrue($validator->validate('sam@rmcreative.ru')); - $this->assertTrue($validator->validate('5011@gmail.com')); - $this->assertFalse($validator->validate('rmcreative.ru')); - $this->assertTrue($validator->validate('Carsten Brandt ')); - $this->assertTrue($validator->validate('"Carsten Brandt" ')); - $this->assertTrue($validator->validate('')); - $this->assertFalse($validator->validate('info@örtliches.de')); - $this->assertFalse($validator->validate('sam@рмкреатиф.ru')); - $this->assertFalse($validator->validate('Informtation info@oertliches.de')); - $this->assertTrue($validator->validate('test@example.com')); - $this->assertTrue($validator->validate('John Smith ')); - $this->assertFalse($validator->validate('John Smith ')); - } - - public function testValidateValueIdn() - { - if (!function_exists('idn_to_ascii')) { - $this->markTestSkipped('Intl extension required'); - return; - } - $validator = new EmailValidator(); - $validator->enableIDN = true; - - $this->assertTrue($validator->validate('5011@example.com')); - $this->assertTrue($validator->validate('example@äüößìà.de')); - $this->assertTrue($validator->validate('example@xn--zcack7ayc9a.de')); - $this->assertTrue($validator->validate('info@örtliches.de')); - $this->assertTrue($validator->validate('sam@рмкреатиф.ru')); - $this->assertTrue($validator->validate('sam@rmcreative.ru')); - $this->assertTrue($validator->validate('5011@gmail.com')); - $this->assertFalse($validator->validate('rmcreative.ru')); - $this->assertFalse($validator->validate('Carsten Brandt ')); - $this->assertFalse($validator->validate('"Carsten Brandt" ')); - $this->assertFalse($validator->validate('')); - - $validator->allowName = true; - - $this->assertTrue($validator->validate('info@örtliches.de')); - $this->assertTrue($validator->validate('Informtation ')); - $this->assertFalse($validator->validate('Informtation info@örtliches.de')); - $this->assertTrue($validator->validate('sam@рмкреатиф.ru')); - $this->assertTrue($validator->validate('sam@rmcreative.ru')); - $this->assertTrue($validator->validate('5011@gmail.com')); - $this->assertFalse($validator->validate('rmcreative.ru')); - $this->assertTrue($validator->validate('Carsten Brandt ')); - $this->assertTrue($validator->validate('"Carsten Brandt" ')); - $this->assertTrue($validator->validate('')); - $this->assertTrue($validator->validate('test@example.com')); - $this->assertTrue($validator->validate('John Smith ')); - $this->assertFalse($validator->validate('John Smith ')); - } - - public function testValidateValueMx() - { - $validator = new EmailValidator(); - - $validator->checkDNS = true; - $this->assertTrue($validator->validate('5011@gmail.com')); - - $validator->checkDNS = false; - $this->assertTrue($validator->validate('test@nonexistingsubdomain.example.com')); - $validator->checkDNS = true; - $this->assertFalse($validator->validate('test@nonexistingsubdomain.example.com')); - } - - public function testValidateAttribute() - { - $val = new EmailValidator(); - $model = new FakedValidationModel(); - $model->attr_email = '5011@gmail.com'; - $val->validateAttribute($model, 'attr_email'); - $this->assertFalse($model->hasErrors('attr_email')); - } -} diff --git a/tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php b/tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php deleted file mode 100644 index 539b458..0000000 --- a/tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php +++ /dev/null @@ -1,10 +0,0 @@ -mockApplication(); - ActiveRecord::$db = $this->getConnection(); - } - - public function testValidateValueExpectedException() - { - try { - $val = new ExistValidator(); - $result = $val->validate('ref'); - $this->fail('Exception should have been thrown at this time'); - } catch (Exception $e) { - $this->assertInstanceOf('yii\base\InvalidConfigException', $e); - $this->assertEquals('The "className" property must be set.', $e->getMessage()); - } - // combine to save the time creating a new db-fixture set (likely ~5 sec) - try { - $val = new ExistValidator(['targetClass' => ValidatorTestMainModel::className()]); - $val->validate('ref'); - $this->fail('Exception should have been thrown at this time'); - } catch (Exception $e) { - $this->assertInstanceOf('yii\base\InvalidConfigException', $e); - $this->assertEquals('The "attributeName" property must be configured as a string.', $e->getMessage()); - } - } - - public function testValidateValue() - { - $val = new ExistValidator(['targetClass' => ValidatorTestRefModel::className(), 'targetAttribute' => 'id']); - $this->assertTrue($val->validate(2)); - $this->assertTrue($val->validate(5)); - $this->assertFalse($val->validate(99)); - $this->assertFalse($val->validate(['1'])); - } - - public function testValidateAttribute() - { - // existing value on different table - $val = new ExistValidator(['targetClass' => ValidatorTestMainModel::className(), 'targetAttribute' => 'id']); - $m = ValidatorTestRefModel::find(['id' => 1]); - $val->validateAttribute($m, 'ref'); - $this->assertFalse($m->hasErrors()); - // non-existing value on different table - $val = new ExistValidator(['targetClass' => ValidatorTestMainModel::className(), 'targetAttribute' => 'id']); - $m = ValidatorTestRefModel::find(['id' => 6]); - $val->validateAttribute($m, 'ref'); - $this->assertTrue($m->hasErrors('ref')); - // existing value on same table - $val = new ExistValidator(['targetAttribute' => 'ref']); - $m = ValidatorTestRefModel::find(['id' => 2]); - $val->validateAttribute($m, 'test_val'); - $this->assertFalse($m->hasErrors()); - // non-existing value on same table - $val = new ExistValidator(['targetAttribute' => 'ref']); - $m = ValidatorTestRefModel::find(['id' => 5]); - $val->validateAttribute($m, 'test_val_fail'); - $this->assertTrue($m->hasErrors('test_val_fail')); - // check for given value (true) - $val = new ExistValidator(); - $m = ValidatorTestRefModel::find(['id' => 3]); - $val->validateAttribute($m, 'ref'); - $this->assertFalse($m->hasErrors()); - // check for given defaults (false) - $val = new ExistValidator(); - $m = ValidatorTestRefModel::find(['id' => 4]); - $m->a_field = 'some new value'; - $val->validateAttribute($m, 'a_field'); - $this->assertTrue($m->hasErrors('a_field')); - // check array - $val = new ExistValidator(['targetAttribute' => 'ref']); - $m = ValidatorTestRefModel::find(['id' => 2]); - $m->test_val = [1,2,3]; - $val->validateAttribute($m, 'test_val'); - $this->assertTrue($m->hasErrors('test_val')); - } - - public function testValidateCompositeKeys() - { - $val = new ExistValidator([ - 'targetClass' => OrderItem::className(), - 'targetAttribute' => ['order_id', 'item_id'], - ]); - // validate old record - $m = OrderItem::find(['order_id' => 1, 'item_id' => 2]); - $val->validateAttribute($m, 'order_id'); - $this->assertFalse($m->hasErrors('order_id')); - - // validate new record - $m = new OrderItem(['order_id' => 1, 'item_id' => 2]); - $val->validateAttribute($m, 'order_id'); - $this->assertFalse($m->hasErrors('order_id')); - $m = new OrderItem(['order_id' => 10, 'item_id' => 2]); - $val->validateAttribute($m, 'order_id'); - $this->assertTrue($m->hasErrors('order_id')); - - $val = new ExistValidator([ - 'targetClass' => OrderItem::className(), - 'targetAttribute' => ['id' => 'order_id'], - ]); - // validate old record - $m = Order::find(1); - $val->validateAttribute($m, 'id'); - $this->assertFalse($m->hasErrors('id')); - $m = Order::find(1); - $m->id = 10; - $val->validateAttribute($m, 'id'); - $this->assertTrue($m->hasErrors('id')); - - $m = new Order(['id' => 1]); - $val->validateAttribute($m, 'id'); - $this->assertFalse($m->hasErrors('id')); - $m = new Order(['id' => 10]); - $val->validateAttribute($m, 'id'); - $this->assertTrue($m->hasErrors('id')); - } -} diff --git a/tests/unit/framework/validators/FileValidatorTest.php b/tests/unit/framework/validators/FileValidatorTest.php deleted file mode 100644 index 5926d7a..0000000 --- a/tests/unit/framework/validators/FileValidatorTest.php +++ /dev/null @@ -1,274 +0,0 @@ -mockApplication(); - } - - public function testAssureMessagesSetOnInit() - { - $val = new FileValidator(); - foreach (['message', 'uploadRequired', 'tooMany', 'wrongType', 'tooBig', 'tooSmall'] as $attr) { - $this->assertTrue(is_string($val->$attr)); - } - } - - public function testTypeSplitOnInit() - { - $val = new FileValidator(['types' => 'jpeg, jpg, gif']); - $this->assertEquals(['jpeg', 'jpg', 'gif'], $val->types); - $val = new FileValidator(['types' => 'jpeg']); - $this->assertEquals(['jpeg'], $val->types); - $val = new FileValidator(['types' => '']); - $this->assertEquals([], $val->types); - $val = new FileValidator(['types' => []]); - $this->assertEquals([], $val->types); - $val = new FileValidator(); - $this->assertEquals([], $val->types); - $val = new FileValidator(['types' => ['jpeg', 'exe']]); - $this->assertEquals(['jpeg', 'exe'], $val->types); - } - - public function testGetSizeLimit() - { - $size = $this->sizeToBytes(ini_get('upload_max_filesize')); - $val = new FileValidator(); - $this->assertEquals($size, $val->getSizeLimit()); - $val->maxSize = $size + 1; // set and test if value is overridden - $this->assertEquals($size, $val->getSizeLimit()); - $val->maxSize = abs($size - 1); - $this->assertEquals($size - 1, $val->getSizeLimit()); - $_POST['MAX_FILE_SIZE'] = $size + 1; - $this->assertEquals($size - 1, $val->getSizeLimit()); - $_POST['MAX_FILE_SIZE'] = abs($size - 2); - $this->assertSame($_POST['MAX_FILE_SIZE'], $val->getSizeLimit()); - } - - protected function sizeToBytes($sizeStr) - { - switch (substr($sizeStr, -1)) { - case 'M': - case 'm': - return (int)$sizeStr * 1048576; - case 'K': - case 'k': - return (int)$sizeStr * 1024; - case 'G': - case 'g': - return (int)$sizeStr * 1073741824; - default: - return (int)$sizeStr; - } - } - - public function testValidateAttributeMultiple() - { - $val = new FileValidator(['maxFiles' => 2]); - $m = FakedValidationModel::createWithAttributes(['attr_files' => 'path']); - $val->validateAttribute($m, 'attr_files'); - $this->assertTrue($m->hasErrors('attr_files')); - $m = FakedValidationModel::createWithAttributes(['attr_files' => []]); - $val->validateAttribute($m, 'attr_files'); - $this->assertTrue($m->hasErrors('attr_files')); - $this->assertSame($val->uploadRequired, current($m->getErrors('attr_files'))); - $m = FakedValidationModel::createWithAttributes( - [ - 'attr_files' => $this->createTestFiles( - [ - [ - 'name' => 'test_up_1.txt', - 'size' => 1024, - ], - [ - 'error' => UPLOAD_ERR_NO_FILE, - ], - ] - ) - ] - ); - $val->validateAttribute($m, 'attr_files'); - $this->assertFalse($m->hasErrors('attr_files')); - $m = FakedValidationModel::createWithAttributes([ - 'attr_files' => $this->createTestFiles([ - [''], [''], [''] - ]) - ]); - $val->validateAttribute($m, 'attr_files'); - $this->assertTrue($m->hasErrors()); - $this->assertTrue(stripos(current($m->getErrors('attr_files')), 'you can upload at most') !== false); - } - - /** - * @param array $params - * @return UploadedFile[] - */ - protected function createTestFiles($params = []) - { - $rndString = function ($len = 10) { - $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - $randomString = ''; - for ($i = 0; $i < $len; $i++) { - $randomString .= $characters[rand(0, strlen($characters) - 1)]; - } - return $randomString; - }; - $files = []; - foreach ($params as $param) { - if (empty($param) && count($params) != 1) { - $files[] = ['no instance of UploadedFile']; - continue; - } - $name = isset($param['name']) ? $param['name'] : $rndString(); - $tempName = \Yii::getAlias('@yiiunit/runtime/validators/file/tmp') . $name; - if (is_readable($tempName)) { - $size = filesize($tempName); - } else { - $size = isset($param['size']) ? $param['size'] : rand( - 1, - $this->sizeToBytes(ini_get('upload_max_filesize')) - ); - } - $type = isset($param['type']) ? $param['type'] : 'text/plain'; - $error = isset($param['error']) ? $param['error'] : UPLOAD_ERR_OK; - if (count($params) == 1) { - $error = empty($param) ? UPLOAD_ERR_NO_FILE : $error; - return new UploadedFile([ - 'name' => $name, - 'tempName' => $tempName, - 'type' => $type, - 'size' => $size, - 'error' => $error - ]); - } - $files[] = new UploadedFile([ - 'name' => $name, - 'tempName' => $tempName, - 'type' => $type, - 'size' => $size, - 'error' => $error - ]); - } - return $files; - } - - public function testValidateAttribute() - { - // single File - $val = new FileValidator(); - $m = $this->createModelForAttributeTest(); - $val->validateAttribute($m, 'attr_files'); - $this->assertFalse($m->hasErrors()); - $val->validateAttribute($m, 'attr_files_empty'); - $this->assertTrue($m->hasErrors('attr_files_empty')); - $this->assertSame($val->uploadRequired, current($m->getErrors('attr_files_empty'))); - $m = $this->createModelForAttributeTest(); - // too big - $val = new FileValidator(['maxSize' => 128]); - $val->validateAttribute($m, 'attr_files'); - $this->assertTrue($m->hasErrors('attr_files')); - $this->assertTrue(stripos(current($m->getErrors('attr_files')), 'too big') !== false); - // to Small - $m = $this->createModelForAttributeTest(); - $val = new FileValidator(['minSize' => 2048]); - $val->validateAttribute($m, 'attr_files'); - $this->assertTrue($m->hasErrors('attr_files')); - $this->assertTrue(stripos(current($m->getErrors('attr_files')), 'too small') !== false); - // UPLOAD_ERR_INI_SIZE/UPLOAD_ERR_FORM_SIZE - $m = $this->createModelForAttributeTest(); - $val = new FileValidator(); - $val->validateAttribute($m, 'attr_err_ini'); - $this->assertTrue($m->hasErrors('attr_err_ini')); - $this->assertTrue(stripos(current($m->getErrors('attr_err_ini')), 'too big') !== false); - // UPLOAD_ERR_PARTIAL - $m = $this->createModelForAttributeTest(); - $val = new FileValidator(); - $val->validateAttribute($m, 'attr_err_part'); - $this->assertTrue($m->hasErrors('attr_err_part')); - $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_part'))); - } - - public function testValidateAttributeType() - { - $val = new FileValidator(['types' => 'jpeg, jpg']); - $m = FakedValidationModel::createWithAttributes( - [ - 'attr_jpg' => $this->createTestFiles([['name' => 'one.jpeg']]), - 'attr_exe' => $this->createTestFiles([['name' => 'bad.exe']]), - ] - ); - $val->validateAttribute($m, 'attr_jpg'); - $this->assertFalse($m->hasErrors('attr_jpg')); - $val->validateAttribute($m, 'attr_exe'); - $this->assertTrue($m->hasErrors('attr_exe')); - $this->assertTrue(stripos(current($m->getErrors('attr_exe')), 'Only files with these extensions ') !== false); - } - - - protected function createModelForAttributeTest() - { - return FakedValidationModel::createWithAttributes( - [ - 'attr_files' => $this->createTestFiles([ - ['name' => 'abc.jpg', 'size' => 1024, 'type' => 'image/jpeg'], - ]), - 'attr_files_empty' => $this->createTestFiles([[]]), - 'attr_err_ini' => $this->createTestFiles([['error' => UPLOAD_ERR_INI_SIZE]]), - 'attr_err_part' => $this->createTestFiles([['error' => UPLOAD_ERR_PARTIAL]]), - 'attr_err_tmp' => $this->createTestFiles([['error' => UPLOAD_ERR_NO_TMP_DIR]]), - 'attr_err_write' => $this->createTestFiles([['error' => UPLOAD_ERR_CANT_WRITE]]), - 'attr_err_ext' => $this->createTestFiles([['error' => UPLOAD_ERR_EXTENSION]]), - ] - ); - } - - public function testValidateAttributeErrPartial() - { - $m = $this->createModelForAttributeTest(); - $val = new FileValidator(); - $val->validateAttribute($m, 'attr_err_part'); - $this->assertTrue($m->hasErrors('attr_err_part')); - $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_part'))); - $log = Yii::$app->getLog()->toArray(); - } - - public function testValidateAttributeErrCantWrite() - { - $m = $this->createModelForAttributeTest(); - $val = new FileValidator(); - $val->validateAttribute($m, 'attr_err_write'); - $this->assertTrue($m->hasErrors('attr_err_write')); - $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_write'))); - $log = Yii::$app->getLog()->toArray(); - } - - public function testValidateAttributeErrExtension() - { - $m = $this->createModelForAttributeTest(); - $val = new FileValidator(); - $val->validateAttribute($m, 'attr_err_ext'); - $this->assertTrue($m->hasErrors('attr_err_ext')); - $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_ext'))); - $log = Yii::$app->getLog()->toArray(); - } - - public function testValidateAttributeErrNoTmpDir() - { - $m = $this->createModelForAttributeTest(); - $val = new FileValidator(); - $val->validateAttribute($m, 'attr_err_tmp'); - $this->assertTrue($m->hasErrors('attr_err_tmp')); - $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_tmp'))); - $log = Yii::$app->getLog()->toArray(); - } -} diff --git a/tests/unit/framework/validators/FilterValidatorTest.php b/tests/unit/framework/validators/FilterValidatorTest.php deleted file mode 100644 index ec96f21..0000000 --- a/tests/unit/framework/validators/FilterValidatorTest.php +++ /dev/null @@ -1,52 +0,0 @@ -mockApplication(); - } - - public function testAssureExceptionOnInit() - { - $this->setExpectedException('yii\base\InvalidConfigException'); - $val = new FilterValidator(); - } - - public function testValidateAttribute() - { - $m = FakedValidationModel::createWithAttributes([ - 'attr_one' => ' to be trimmed ', - 'attr_two' => 'set this to null', - 'attr_empty1' => '', - 'attr_empty2' => null - ]); - $val = new FilterValidator(['filter' => 'trim']); - $val->validateAttribute($m, 'attr_one'); - $this->assertSame('to be trimmed', $m->attr_one); - $val->filter = function ($value) { - return null; - }; - $val->validateAttribute($m, 'attr_two'); - $this->assertNull($m->attr_two); - $val->filter = [$this, 'notToBeNull']; - $val->validateAttribute($m, 'attr_empty1'); - $this->assertSame($this->notToBeNull(''), $m->attr_empty1); - $val->skipOnEmpty = true; - $val->validateAttribute($m, 'attr_empty2'); - $this->assertNotNull($m->attr_empty2); - } - - public function notToBeNull($value) - { - return 'not null'; - } -} \ No newline at end of file diff --git a/tests/unit/framework/validators/NumberValidatorTest.php b/tests/unit/framework/validators/NumberValidatorTest.php deleted file mode 100644 index a7fa195..0000000 --- a/tests/unit/framework/validators/NumberValidatorTest.php +++ /dev/null @@ -1,166 +0,0 @@ -mockApplication(); - } - - public function testEnsureMessageOnInit() - { - $val = new NumberValidator; - $this->assertTrue(is_string($val->message)); - $this->assertTrue(is_null($val->max)); - $val = new NumberValidator(['min' => -1, 'max' => 20, 'integerOnly' => true]); - $this->assertTrue(is_string($val->message)); - $this->assertTrue(is_string($val->tooSmall)); - $this->assertTrue(is_string($val->tooBig)); - } - - public function testValidateValueSimple() - { - $val = new NumberValidator(); - $this->assertTrue($val->validate(20)); - $this->assertTrue($val->validate(0)); - $this->assertTrue($val->validate(-20)); - $this->assertTrue($val->validate('20')); - $this->assertTrue($val->validate(25.45)); - $this->assertFalse($val->validate('25,45')); - $this->assertFalse($val->validate('12:45')); - $val = new NumberValidator(['integerOnly' => true]); - $this->assertTrue($val->validate(20)); - $this->assertTrue($val->validate(0)); - $this->assertFalse($val->validate(25.45)); - $this->assertTrue($val->validate('20')); - $this->assertFalse($val->validate('25,45')); - $this->assertTrue($val->validate('020')); - $this->assertTrue($val->validate(0x14)); - $this->assertFalse($val->validate('0x14')); // todo check this - } - - public function testValidateValueAdvanced() - { - $val = new NumberValidator(); - $this->assertTrue($val->validate('-1.23')); // signed float - $this->assertTrue($val->validate('-4.423e-12')); // signed float + exponent - $this->assertTrue($val->validate('12E3')); // integer + exponent - $this->assertFalse($val->validate('e12')); // just exponent - $this->assertFalse($val->validate('-e3')); - $this->assertFalse($val->validate('-4.534-e-12')); // 'signed' exponent - $this->assertFalse($val->validate('12.23^4')); // expression instead of value - $val = new NumberValidator(['integerOnly' => true]); - $this->assertFalse($val->validate('-1.23')); - $this->assertFalse($val->validate('-4.423e-12')); - $this->assertFalse($val->validate('12E3')); - $this->assertFalse($val->validate('e12')); - $this->assertFalse($val->validate('-e3')); - $this->assertFalse($val->validate('-4.534-e-12')); - $this->assertFalse($val->validate('12.23^4')); - } - - public function testValidateValueMin() - { - $val = new NumberValidator(['min' => 1]); - $this->assertTrue($val->validate(1)); - $this->assertFalse($val->validate(-1)); - $this->assertFalse($val->validate('22e-12')); - $this->assertTrue($val->validate(PHP_INT_MAX + 1)); - $val = new NumberValidator(['min' => 1], ['integerOnly' => true]); - $this->assertTrue($val->validate(1)); - $this->assertFalse($val->validate(-1)); - $this->assertFalse($val->validate('22e-12')); - $this->assertTrue($val->validate(PHP_INT_MAX + 1)); - } - - public function testValidateValueMax() - { - $val = new NumberValidator(['max' => 1.25]); - $this->assertTrue($val->validate(1)); - $this->assertFalse($val->validate(1.5)); - $this->assertTrue($val->validate('22e-12')); - $this->assertTrue($val->validate('125e-2')); - $val = new NumberValidator(['max' => 1.25, 'integerOnly' => true]); - $this->assertTrue($val->validate(1)); - $this->assertFalse($val->validate(1.5)); - $this->assertFalse($val->validate('22e-12')); - $this->assertFalse($val->validate('125e-2')); - } - - public function testValidateValueRange() - { - $val = new NumberValidator(['min' => -10, 'max' => 20]); - $this->assertTrue($val->validate(0)); - $this->assertTrue($val->validate(-10)); - $this->assertFalse($val->validate(-11)); - $this->assertFalse($val->validate(21)); - $val = new NumberValidator(['min' => -10, 'max' => 20, 'integerOnly' => true]); - $this->assertTrue($val->validate(0)); - $this->assertFalse($val->validate(-11)); - $this->assertFalse($val->validate(22)); - $this->assertFalse($val->validate('20e-1')); - } - - public function testValidateAttribute() - { - $val = new NumberValidator(); - $model = new FakedValidationModel(); - $model->attr_number = '5.5e1'; - $val->validateAttribute($model, 'attr_number'); - $this->assertFalse($model->hasErrors('attr_number')); - $model->attr_number = '43^32'; //expression - $val->validateAttribute($model, 'attr_number'); - $this->assertTrue($model->hasErrors('attr_number')); - $val = new NumberValidator(['min' => 10]); - $model = new FakedValidationModel(); - $model->attr_number = 10; - $val->validateAttribute($model, 'attr_number'); - $this->assertFalse($model->hasErrors('attr_number')); - $model->attr_number = 5; - $val->validateAttribute($model, 'attr_number'); - $this->assertTrue($model->hasErrors('attr_number')); - $val = new NumberValidator(['max' => 10]); - $model = new FakedValidationModel(); - $model->attr_number = 10; - $val->validateAttribute($model, 'attr_number'); - $this->assertFalse($model->hasErrors('attr_number')); - $model->attr_number = 15; - $val->validateAttribute($model, 'attr_number'); - $this->assertTrue($model->hasErrors('attr_number')); - $val = new NumberValidator(['max' => 10, 'integerOnly' => true]); - $model = new FakedValidationModel(); - $model->attr_number = 10; - $val->validateAttribute($model, 'attr_number'); - $this->assertFalse($model->hasErrors('attr_number')); - $model->attr_number = 3.43; - $val->validateAttribute($model, 'attr_number'); - $this->assertTrue($model->hasErrors('attr_number')); - $val = new NumberValidator(['min' => 1]); - $model = FakedValidationModel::createWithAttributes(['attr_num' => [1,2,3]]); - $val->validateAttribute($model, 'attr_num'); - $this->assertTrue($model->hasErrors('attr_num')); - } - - public function testEnsureCustomMessageIsSetOnValidateAttribute() - { - $val = new NumberValidator([ - 'tooSmall' => '{attribute} is to small.', - 'min' => 5 - ]); - $model = new FakedValidationModel(); - $model->attr_number = 0; - $val->validateAttribute($model, 'attr_number'); - $this->assertTrue($model->hasErrors('attr_number')); - $this->assertEquals(1, count($model->getErrors('attr_number'))); - $msgs = $model->getErrors('attr_number'); - $this->assertSame('attr_number is to small.', $msgs[0]); - } -} diff --git a/tests/unit/framework/validators/RangeValidatorTest.php b/tests/unit/framework/validators/RangeValidatorTest.php deleted file mode 100644 index 583eeca..0000000 --- a/tests/unit/framework/validators/RangeValidatorTest.php +++ /dev/null @@ -1,76 +0,0 @@ -mockApplication(); - } - - public function testInitException() - { - $this->setExpectedException('yii\base\InvalidConfigException', 'The "range" property must be set.'); - $val = new RangeValidator(['range' => 'not an array']); - } - - public function testAssureMessageSetOnInit() - { - $val = new RangeValidator(['range' => []]); - $this->assertTrue(is_string($val->message)); - } - - public function testValidateValue() - { - $val = new RangeValidator(['range' => range(1, 10, 1)]); - $this->assertTrue($val->validate(1)); - $this->assertFalse($val->validate(0)); - $this->assertFalse($val->validate(11)); - $this->assertFalse($val->validate(5.5)); - $this->assertTrue($val->validate(10)); - $this->assertTrue($val->validate("10")); - $this->assertTrue($val->validate("5")); - } - - public function testValidateValueStrict() - { - $val = new RangeValidator(['range' => range(1, 10, 1), 'strict' => true]); - $this->assertTrue($val->validate(1)); - $this->assertTrue($val->validate(5)); - $this->assertTrue($val->validate(10)); - $this->assertFalse($val->validate("1")); - $this->assertFalse($val->validate("10")); - $this->assertFalse($val->validate("5.5")); - } - - public function testValidateValueNot() - { - $val = new RangeValidator(['range' => range(1, 10, 1), 'not' => true]); - $this->assertFalse($val->validate(1)); - $this->assertTrue($val->validate(0)); - $this->assertTrue($val->validate(11)); - $this->assertTrue($val->validate(5.5)); - $this->assertFalse($val->validate(10)); - $this->assertFalse($val->validate("10")); - $this->assertFalse($val->validate("5")); - } - - public function testValidateAttribute() - { - $val = new RangeValidator(['range' => range(1, 10, 1)]); - $m = FakedValidationModel::createWithAttributes(['attr_r1' => 5, 'attr_r2' => 999]); - $val->validateAttribute($m, 'attr_r1'); - $this->assertFalse($m->hasErrors()); - $val->validateAttribute($m, 'attr_r2'); - $this->assertTrue($m->hasErrors('attr_r2')); - $err = $m->getErrors('attr_r2'); - $this->assertTrue(stripos($err[0], 'attr_r2') !== false); - } -} diff --git a/tests/unit/framework/validators/RegularExpressionValidatorTest.php b/tests/unit/framework/validators/RegularExpressionValidatorTest.php deleted file mode 100644 index 0dd8b04..0000000 --- a/tests/unit/framework/validators/RegularExpressionValidatorTest.php +++ /dev/null @@ -1,54 +0,0 @@ -mockApplication(); - } - - public function testValidateValue() - { - $val = new RegularExpressionValidator(['pattern' => '/^[a-zA-Z0-9](\.)?([^\/]*)$/m']); - $this->assertTrue($val->validate('b.4')); - $this->assertFalse($val->validate('b./')); - $this->assertFalse($val->validate(['a', 'b'])); - $val->not = true; - $this->assertFalse($val->validate('b.4')); - $this->assertTrue($val->validate('b./')); - $this->assertFalse($val->validate(['a', 'b'])); - } - - public function testValidateAttribute() - { - $val = new RegularExpressionValidator(['pattern' => '/^[a-zA-Z0-9](\.)?([^\/]*)$/m']); - $m = FakedValidationModel::createWithAttributes(['attr_reg1' => 'b.4']); - $val->validateAttribute($m, 'attr_reg1'); - $this->assertFalse($m->hasErrors('attr_reg1')); - $m->attr_reg1 = 'b./'; - $val->validateAttribute($m, 'attr_reg1'); - $this->assertTrue($m->hasErrors('attr_reg1')); - } - - public function testMessageSetOnInit() - { - $val = new RegularExpressionValidator(['pattern' => '/^[a-zA-Z0-9](\.)?([^\/]*)$/m']); - $this->assertTrue(is_string($val->message)); - } - - public function testInitException() - { - $this->setExpectedException('yii\base\InvalidConfigException'); - $val = new RegularExpressionValidator(); - $val->validate('abc'); - } - -} diff --git a/tests/unit/framework/validators/RequiredValidatorTest.php b/tests/unit/framework/validators/RequiredValidatorTest.php deleted file mode 100644 index 44102eb..0000000 --- a/tests/unit/framework/validators/RequiredValidatorTest.php +++ /dev/null @@ -1,60 +0,0 @@ -mockApplication(); - } - - public function testValidateValueWithDefaults() - { - $val = new RequiredValidator(); - $this->assertFalse($val->validate(null)); - $this->assertFalse($val->validate([])); - $this->assertTrue($val->validate('not empty')); - $this->assertTrue($val->validate(['with', 'elements'])); - } - - public function testValidateValueWithValue() - { - $val = new RequiredValidator(['requiredValue' => 55]); - $this->assertTrue($val->validate(55)); - $this->assertTrue($val->validate("55")); - $this->assertTrue($val->validate("0x37")); - $this->assertFalse($val->validate("should fail")); - $this->assertTrue($val->validate(true)); - $val->strict = true; - $this->assertTrue($val->validate(55)); - $this->assertFalse($val->validate("55")); - $this->assertFalse($val->validate("0x37")); - $this->assertFalse($val->validate("should fail")); - $this->assertFalse($val->validate(true)); - } - - public function testValidateAttribute() - { - // empty req-value - $val = new RequiredValidator(); - $m = FakedValidationModel::createWithAttributes(['attr_val' => null]); - $val->validateAttribute($m, 'attr_val'); - $this->assertTrue($m->hasErrors('attr_val')); - $this->assertTrue(stripos(current($m->getErrors('attr_val')), 'blank') !== false); - $val = new RequiredValidator(['requiredValue' => 55]); - $m = FakedValidationModel::createWithAttributes(['attr_val' => 56]); - $val->validateAttribute($m, 'attr_val'); - $this->assertTrue($m->hasErrors('attr_val')); - $this->assertTrue(stripos(current($m->getErrors('attr_val')), 'must be') !== false); - $val = new RequiredValidator(['requiredValue' => 55]); - $m = FakedValidationModel::createWithAttributes(['attr_val' => 55]); - $val->validateAttribute($m, 'attr_val'); - $this->assertFalse($m->hasErrors('attr_val')); - } -} diff --git a/tests/unit/framework/validators/StringValidatorTest.php b/tests/unit/framework/validators/StringValidatorTest.php deleted file mode 100644 index 50ebbbb..0000000 --- a/tests/unit/framework/validators/StringValidatorTest.php +++ /dev/null @@ -1,116 +0,0 @@ -mockApplication(); - } - - public function testValidateValue() - { - $val = new StringValidator(); - $this->assertFalse($val->validate(['not a string'])); - $this->assertTrue($val->validate('Just some string')); - } - - public function testValidateValueLength() - { - $val = new StringValidator(['length' => 25]); - $this->assertTrue($val->validate(str_repeat('x', 25))); - $this->assertTrue($val->validate(str_repeat('€', 25))); - $this->assertFalse($val->validate(str_repeat('x', 125))); - $this->assertFalse($val->validate('')); - $val = new StringValidator(['length' => [25]]); - $this->assertTrue($val->validate(str_repeat('x', 25))); - $this->assertTrue($val->validate(str_repeat('x', 1250))); - $this->assertFalse($val->validate(str_repeat('Ä', 24))); - $this->assertFalse($val->validate('')); - $val = new StringValidator(['length' => [10, 20]]); - $this->assertTrue($val->validate(str_repeat('x', 15))); - $this->assertTrue($val->validate(str_repeat('x', 10))); - $this->assertTrue($val->validate(str_repeat('x', 20))); - $this->assertFalse($val->validate(str_repeat('x', 5))); - $this->assertFalse($val->validate(str_repeat('x', 25))); - $this->assertFalse($val->validate('')); - // make sure min/max are overridden - $val = new StringValidator(['length' => [10, 20], 'min' => 25, 'max' => 35]); - $this->assertTrue($val->validate(str_repeat('x', 15))); - $this->assertFalse($val->validate(str_repeat('x', 30))); - } - - public function testValidateValueMinMax() - { - $val = new StringValidator(['min' => 10]); - $this->assertTrue($val->validate(str_repeat('x', 10))); - $this->assertFalse($val->validate('xxxx')); - $val = new StringValidator(['max' => 10]); - $this->assertTrue($val->validate('xxxx')); - $this->assertFalse($val->validate(str_repeat('y', 20))); - $val = new StringValidator(['min' => 10, 'max' => 20]); - $this->assertTrue($val->validate(str_repeat('y', 15))); - $this->assertFalse($val->validate('abc')); - $this->assertFalse($val->validate(str_repeat('b', 25))); - } - - public function testValidateAttribute() - { - $val = new StringValidator(); - $model = new FakedValidationModel(); - $model->attr_string = 'a tet string'; - $val->validateAttribute($model, 'attr_string'); - $this->assertFalse($model->hasErrors()); - $val = new StringValidator(['length' => 20]); - $model = new FakedValidationModel(); - $model->attr_string = str_repeat('x', 20); - $val->validateAttribute($model, 'attr_string'); - $this->assertFalse($model->hasErrors()); - $model = new FakedValidationModel(); - $model->attr_string = 'abc'; - $val->validateAttribute($model, 'attr_string'); - $this->assertTrue($model->hasErrors('attr_string')); - $val = new StringValidator(['max' => 2]); - $model = new FakedValidationModel(); - $model->attr_string = 'a'; - $val->validateAttribute($model, 'attr_string'); - $this->assertFalse($model->hasErrors()); - $model = new FakedValidationModel(); - $model->attr_string = 'abc'; - $val->validateAttribute($model, 'attr_string'); - $this->assertTrue($model->hasErrors('attr_string')); - $val = new StringValidator(['max' => 1]); - $model = FakedValidationModel::createWithAttributes(['attr_str' => ['abc']]); - $val->validateAttribute($model, 'attr_str'); - $this->assertTrue($model->hasErrors('attr_str')); - } - - public function testEnsureMessagesOnInit() - { - $val = new StringValidator(['min' => 1, 'max' => 2]); - $this->assertTrue(is_string($val->message)); - $this->assertTrue(is_string($val->tooLong)); - $this->assertTrue(is_string($val->tooShort)); - } - - public function testCustomErrorMessageInValidateAttribute() - { - $val = new StringValidator([ - 'min' => 5, - 'tooShort' => '{attribute} to short. Min is {min}', - ]); - $model = new FakedValidationModel(); - $model->attr_string = 'abc'; - $val->validateAttribute($model, 'attr_string'); - $this->assertTrue($model->hasErrors('attr_string')); - $errorMsg = $model->getErrors('attr_string'); - $this->assertEquals('attr_string to short. Min is 5', $errorMsg[0]); - } -} diff --git a/tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php b/tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php deleted file mode 100644 index 9adc57c..0000000 --- a/tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php +++ /dev/null @@ -1,11 +0,0 @@ -mockApplication(); - ActiveRecord::$db = $this->getConnection(); - } - - public function testAssureMessageSetOnInit() - { - $val = new UniqueValidator(); - $this->assertTrue(is_string($val->message)); - } - - public function testValidateAttributeDefault() - { - $val = new UniqueValidator(); - $m = ValidatorTestMainModel::find()->one(); - $val->validateAttribute($m, 'id'); - $this->assertFalse($m->hasErrors('id')); - $m = ValidatorTestRefModel::find(1); - $val->validateAttribute($m, 'ref'); - $this->assertTrue($m->hasErrors('ref')); - // new record: - $m = new ValidatorTestRefModel(); - $m->ref = 5; - $val->validateAttribute($m, 'ref'); - $this->assertTrue($m->hasErrors('ref')); - $m = new ValidatorTestRefModel(); - $m->id = 7; - $m->ref = 12121; - $val->validateAttribute($m, 'ref'); - $this->assertFalse($m->hasErrors('ref')); - $m->save(false); - $val->validateAttribute($m, 'ref'); - $this->assertFalse($m->hasErrors('ref')); - // array error - $m = FakedValidationModel::createWithAttributes(['attr_arr' => ['a', 'b']]); - $val->validateAttribute($m, 'attr_arr'); - $this->assertTrue($m->hasErrors('attr_arr')); - } - - public function testValidateAttributeOfNonARModel() - { - $val = new UniqueValidator(['targetClass' => ValidatorTestRefModel::className(), 'targetAttribute' => 'ref']); - $m = FakedValidationModel::createWithAttributes(['attr_1' => 5, 'attr_2' => 1313]); - $val->validateAttribute($m, 'attr_1'); - $this->assertTrue($m->hasErrors('attr_1')); - $val->validateAttribute($m, 'attr_2'); - $this->assertFalse($m->hasErrors('attr_2')); - } - - public function testValidateNonDatabaseAttribute() - { - $val = new UniqueValidator(['targetClass' => ValidatorTestRefModel::className(), 'targetAttribute' => 'ref']); - $m = ValidatorTestMainModel::find(1); - $val->validateAttribute($m, 'testMainVal'); - $this->assertFalse($m->hasErrors('testMainVal')); - $m = ValidatorTestMainModel::find(1); - $m->testMainVal = 4; - $val->validateAttribute($m, 'testMainVal'); - $this->assertTrue($m->hasErrors('testMainVal')); - } - - public function testValidateAttributeAttributeNotInTableException() - { - $this->setExpectedException('yii\db\Exception'); - $val = new UniqueValidator(); - $m = new ValidatorTestMainModel(); - $val->validateAttribute($m, 'testMainVal'); - } - - public function testValidateCompositeKeys() - { - $val = new UniqueValidator([ - 'targetClass' => OrderItem::className(), - 'targetAttribute' => ['order_id', 'item_id'], - ]); - // validate old record - $m = OrderItem::find(['order_id' => 1, 'item_id' => 2]); - $val->validateAttribute($m, 'order_id'); - $this->assertFalse($m->hasErrors('order_id')); - $m->item_id = 1; - $val->validateAttribute($m, 'order_id'); - $this->assertTrue($m->hasErrors('order_id')); - - // validate new record - $m = new OrderItem(['order_id' => 1, 'item_id' => 2]); - $val->validateAttribute($m, 'order_id'); - $this->assertTrue($m->hasErrors('order_id')); - $m = new OrderItem(['order_id' => 10, 'item_id' => 2]); - $val->validateAttribute($m, 'order_id'); - $this->assertFalse($m->hasErrors('order_id')); - - $val = new UniqueValidator([ - 'targetClass' => OrderItem::className(), - 'targetAttribute' => ['id' => 'order_id'], - ]); - // validate old record - $m = Order::find(1); - $val->validateAttribute($m, 'id'); - $this->assertTrue($m->hasErrors('id')); - $m = Order::find(1); - $m->id = 2; - $val->validateAttribute($m, 'id'); - $this->assertTrue($m->hasErrors('id')); - $m = Order::find(1); - $m->id = 10; - $val->validateAttribute($m, 'id'); - $this->assertFalse($m->hasErrors('id')); - - $m = new Order(['id' => 1]); - $val->validateAttribute($m, 'id'); - $this->assertTrue($m->hasErrors('id')); - $m = new Order(['id' => 10]); - $val->validateAttribute($m, 'id'); - $this->assertFalse($m->hasErrors('id')); - } -} diff --git a/tests/unit/framework/validators/UrlValidatorTest.php b/tests/unit/framework/validators/UrlValidatorTest.php deleted file mode 100644 index 5b2cada..0000000 --- a/tests/unit/framework/validators/UrlValidatorTest.php +++ /dev/null @@ -1,100 +0,0 @@ -mockApplication(); - } - - public function testValidateValue() - { - $val = new UrlValidator; - $this->assertFalse($val->validate('google.de')); - $this->assertTrue($val->validate('http://google.de')); - $this->assertTrue($val->validate('https://google.de')); - $this->assertFalse($val->validate('htp://yiiframework.com')); - $this->assertTrue($val->validate('https://www.google.de/search?q=yii+framework&ie=utf-8&oe=utf-8' - .'&rls=org.mozilla:de:official&client=firefox-a&gws_rd=cr')); - $this->assertFalse($val->validate('ftp://ftp.ruhr-uni-bochum.de/')); - $this->assertFalse($val->validate('http://invalid,domain')); - $this->assertFalse($val->validate('http://äüö?=!"§$%&/()=}][{³²€.edu')); - } - - public function testValidateValueWithDefaultScheme() - { - $val = new UrlValidator(['defaultScheme' => 'https']); - $this->assertTrue($val->validate('yiiframework.com')); - $this->assertTrue($val->validate('http://yiiframework.com')); - } - - public function testValidateValueWithoutScheme() - { - $val = new UrlValidator(['pattern' => '/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)/i']); - $this->assertTrue($val->validate('yiiframework.com')); - } - - public function testValidateWithCustomScheme() - { - $val = new UrlValidator([ - 'validSchemes' => ['http', 'https', 'ftp', 'ftps'], - 'defaultScheme' => 'http', - ]); - $this->assertTrue($val->validate('ftp://ftp.ruhr-uni-bochum.de/')); - $this->assertTrue($val->validate('google.de')); - $this->assertTrue($val->validate('http://google.de')); - $this->assertTrue($val->validate('https://google.de')); - $this->assertFalse($val->validate('htp://yiiframework.com')); - // relative urls not supported - $this->assertFalse($val->validate('//yiiframework.com')); - } - - public function testValidateWithIdn() - { - if (!function_exists('idn_to_ascii')) { - $this->markTestSkipped('intl package required'); - return; - } - $val = new UrlValidator([ - 'enableIDN' => true, - ]); - $this->assertTrue($val->validate('http://äüößìà.de')); - // converted via http://mct.verisign-grs.com/convertServlet - $this->assertTrue($val->validate('http://xn--zcack7ayc9a.de')); - } - - public function testValidateLength() - { - $url = 'http://' . str_pad('base', 2000, 'url') . '.de'; - $val = new UrlValidator; - $this->assertFalse($val->validate($url)); - } - - public function testValidateAttributeAndError() - { - $obj = new FakedValidationModel; - $obj->attr_url = 'http://google.de'; - $val = new UrlValidator; - $val->validateAttribute($obj, 'attr_url'); - $this->assertFalse($obj->hasErrors('attr_url')); - $this->assertSame('http://google.de', $obj->attr_url); - $obj = new FakedValidationModel; - $val->defaultScheme = 'http'; - $obj->attr_url = 'google.de'; - $val->validateAttribute($obj, 'attr_url'); - $this->assertFalse($obj->hasErrors('attr_url')); - $this->assertTrue(stripos($obj->attr_url, 'http') !== false); - $obj = new FakedValidationModel; - $obj->attr_url = 'gttp;/invalid string'; - $val->validateAttribute($obj, 'attr_url'); - $this->assertTrue($obj->hasErrors('attr_url')); - } -} diff --git a/tests/unit/framework/validators/ValidatorTest.php b/tests/unit/framework/validators/ValidatorTest.php deleted file mode 100644 index e52ccdb..0000000 --- a/tests/unit/framework/validators/ValidatorTest.php +++ /dev/null @@ -1,232 +0,0 @@ -mockApplication(); - } - - protected function getTestModel($additionalAttributes = []) - { - $attributes = array_merge( - ['attr_runMe1' => true, 'attr_runMe2' => true, 'attr_skip' => true], - $additionalAttributes - ); - return FakedValidationModel::createWithAttributes($attributes); - } - - public function testCreateValidator() - { - $model = FakedValidationModel::createWithAttributes(['attr_test1' => 'abc', 'attr_test2' => '2013']); - /** @var NumberValidator $numberVal */ - $numberVal = TestValidator::createValidator('number', $model, ['attr_test1']); - $this->assertInstanceOf(NumberValidator::className(), $numberVal); - $numberVal = TestValidator::createValidator('integer', $model, ['attr_test2']); - $this->assertInstanceOf(NumberValidator::className(), $numberVal); - $this->assertTrue($numberVal->integerOnly); - $val = TestValidator::createValidator( - 'boolean', - $model, - ['attr_test1', 'attr_test2'], - ['on' => ['a', 'b']] - ); - $this->assertInstanceOf(BooleanValidator::className(), $val); - $this->assertSame(['a', 'b'], $val->on); - $this->assertSame(['attr_test1', 'attr_test2'], $val->attributes); - $val = TestValidator::createValidator( - 'boolean', - $model, - ['attr_test1', 'attr_test2'], - ['on' => ['a', 'b'], 'except' => ['c', 'd', 'e']] - ); - $this->assertInstanceOf(BooleanValidator::className(), $val); - $this->assertSame(['a', 'b'], $val->on); - $this->assertSame(['c', 'd', 'e'], $val->except); - $val = TestValidator::createValidator('inlineVal', $model, ['val_attr_a']); - $this->assertInstanceOf(InlineValidator::className(), $val); - $this->assertSame('inlineVal', $val->method); - } - - public function testValidate() - { - $val = new TestValidator(['attributes' => ['attr_runMe1', 'attr_runMe2']]); - $model = $this->getTestModel(); - $val->validateAttributes($model); - $this->assertTrue($val->isAttributeValidated('attr_runMe1')); - $this->assertTrue($val->isAttributeValidated('attr_runMe2')); - $this->assertFalse($val->isAttributeValidated('attr_skip')); - } - - public function testValidateWithAttributeIntersect() - { - $val = new TestValidator(['attributes' => ['attr_runMe1', 'attr_runMe2']]); - $model = $this->getTestModel(); - $val->validateAttributes($model, ['attr_runMe1']); - $this->assertTrue($val->isAttributeValidated('attr_runMe1')); - $this->assertFalse($val->isAttributeValidated('attr_runMe2')); - $this->assertFalse($val->isAttributeValidated('attr_skip')); - } - - public function testValidateWithEmptyAttributes() - { - $val = new TestValidator(); - $model = $this->getTestModel(); - $val->validateAttributes($model, ['attr_runMe1']); - $this->assertFalse($val->isAttributeValidated('attr_runMe1')); - $this->assertFalse($val->isAttributeValidated('attr_runMe2')); - $this->assertFalse($val->isAttributeValidated('attr_skip')); - $val->validateAttributes($model); - $this->assertFalse($val->isAttributeValidated('attr_runMe1')); - $this->assertFalse($val->isAttributeValidated('attr_runMe2')); - $this->assertFalse($val->isAttributeValidated('attr_skip')); - } - - public function testValidateWithError() - { - $val = new TestValidator(['attributes' => ['attr_runMe1', 'attr_runMe2'], 'skipOnError' => false]); - $model = $this->getTestModel(); - $val->validateAttributes($model); - $this->assertTrue($val->isAttributeValidated('attr_runMe1')); - $this->assertTrue($val->isAttributeValidated('attr_runMe2')); - $this->assertFalse($val->isAttributeValidated('attr_skip')); - $this->assertEquals(1, $val->countAttributeValidations('attr_runMe2')); - $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); - $val->validateAttributes($model, ['attr_runMe2']); - $this->assertEquals(2, $val->countAttributeValidations('attr_runMe2')); - $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); - $this->assertEquals(0, $val->countAttributeValidations('attr_skip')); - $val = new TestValidator(['attributes' => ['attr_runMe1', 'attr_runMe2'], 'skipOnError' => true]); - $model = $this->getTestModel(); - $val->enableErrorOnValidateAttribute(); - $val->validateAttributes($model); - $this->assertTrue($val->isAttributeValidated('attr_runMe1')); - $this->assertTrue($val->isAttributeValidated('attr_runMe2')); - $this->assertFalse($val->isAttributeValidated('attr_skip')); - $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); - $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); - $this->assertEquals(0, $val->countAttributeValidations('attr_skip')); - $val->validateAttributes($model, ['attr_runMe2']); - $this->assertEquals(1, $val->countAttributeValidations('attr_runMe2')); - $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); - $this->assertEquals(0, $val->countAttributeValidations('attr_skip')); - } - - public function testValidateWithEmpty() - { - $val = new TestValidator([ - 'attributes' => [ - 'attr_runMe1', - 'attr_runMe2', - 'attr_empty1', - 'attr_empty2' - ], - 'skipOnEmpty' => true, - ]); - $model = $this->getTestModel(['attr_empty1' => '', 'attr_emtpy2' => ' ']); - $val->validateAttributes($model); - $this->assertTrue($val->isAttributeValidated('attr_runMe1')); - $this->assertTrue($val->isAttributeValidated('attr_runMe2')); - $this->assertFalse($val->isAttributeValidated('attr_empty1')); - $this->assertFalse($val->isAttributeValidated('attr_empty2')); - $model->attr_empty1 = 'not empty anymore'; - $val->validateAttributes($model); - $this->assertTrue($val->isAttributeValidated('attr_empty1')); - $this->assertFalse($val->isAttributeValidated('attr_empty2')); - $val = new TestValidator([ - 'attributes' => [ - 'attr_runMe1', - 'attr_runMe2', - 'attr_empty1', - 'attr_empty2' - ], - 'skipOnEmpty' => false, - ]); - $model = $this->getTestModel(['attr_empty1' => '', 'attr_emtpy2' => ' ']); - $val->validateAttributes($model); - $this->assertTrue($val->isAttributeValidated('attr_runMe1')); - $this->assertTrue($val->isAttributeValidated('attr_runMe2')); - $this->assertTrue($val->isAttributeValidated('attr_empty1')); - $this->assertTrue($val->isAttributeValidated('attr_empty2')); - } - - public function testIsEmpty() - { - $val = new TestValidator(); - $this->assertTrue($val->isEmpty(null)); - $this->assertTrue($val->isEmpty([])); - $this->assertTrue($val->isEmpty('')); - $this->assertFalse($val->isEmpty(5)); - $this->assertFalse($val->isEmpty(0)); - $this->assertFalse($val->isEmpty(new \stdClass())); - $this->assertFalse($val->isEmpty(' ')); - // trim - $this->assertTrue($val->isEmpty(' ', true)); - $this->assertTrue($val->isEmpty('', true)); - $this->assertTrue($val->isEmpty(" \t\n\r\0\x0B", true)); - $this->assertTrue($val->isEmpty('', true)); - $this->assertFalse($val->isEmpty('0', true)); - $this->assertFalse($val->isEmpty(0, true)); - $this->assertFalse($val->isEmpty('this ain\'t an empty value', true)); - } - - public function testValidateValue() - { - $this->setExpectedException( - 'yii\base\NotSupportedException', - TestValidator::className() . ' does not support validateValue().' - ); - $val = new TestValidator(); - $val->validate('abc'); - } - - public function testClientValidateAttribute() - { - $val = new TestValidator(); - $this->assertNull( - $val->clientValidateAttribute($this->getTestModel(), 'attr_runMe1', []) - ); //todo pass a view instead of array - } - - public function testIsActive() - { - $val = new TestValidator(); - $this->assertTrue($val->isActive('scenA')); - $this->assertTrue($val->isActive('scenB')); - $val->except = ['scenB']; - $this->assertTrue($val->isActive('scenA')); - $this->assertFalse($val->isActive('scenB')); - $val->on = ['scenC']; - $this->assertFalse($val->isActive('scenA')); - $this->assertFalse($val->isActive('scenB')); - $this->assertTrue($val->isActive('scenC')); - } - - public function testAddError() - { - $val = new TestValidator(); - $m = $this->getTestModel(['attr_msg_val' => 'abc']); - $val->addError($m, 'attr_msg_val', '{attribute}::{value}'); - $errors = $m->getErrors('attr_msg_val'); - $this->assertEquals('attr_msg_val::abc', $errors[0]); - $m = $this->getTestModel(['attr_msg_val' => ['bcc']]); - $val->addError($m, 'attr_msg_val', '{attribute}::{value}'); - $errors = $m->getErrors('attr_msg_val'); - $this->assertEquals('attr_msg_val::array()', $errors[0]); - $m = $this->getTestModel(['attr_msg_val' => 'abc']); - $val->addError($m, 'attr_msg_val', '{attribute}::{value}::{param}', ['param' => 'param_value']); - $errors = $m->getErrors('attr_msg_val'); - $this->assertEquals('attr_msg_val::abc::param_value', $errors[0]); - } -} diff --git a/tests/unit/framework/web/AssetBundleTest.php b/tests/unit/framework/web/AssetBundleTest.php deleted file mode 100644 index d989a13..0000000 --- a/tests/unit/framework/web/AssetBundleTest.php +++ /dev/null @@ -1,256 +0,0 @@ - - */ - -namespace yiiunit\framework\web; - -use Yii; -use yii\web\View; -use yii\web\AssetBundle; -use yii\web\AssetManager; - -/** - * @group web - */ -class AssetBundleTest extends \yiiunit\TestCase -{ - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - - Yii::setAlias('@testWeb', '/'); - Yii::setAlias('@testWebRoot', '@yiiunit/data/web'); - } - - protected function getView() - { - $view = new View(); - $view->setAssetManager(new AssetManager([ - 'basePath' => '@testWebRoot/assets', - 'baseUrl' => '@testWeb/assets', - ])); - - return $view; - } - - public function testRegister() - { - $view = $this->getView(); - - $this->assertEmpty($view->assetBundles); - TestSimpleAsset::register($view); - $this->assertEquals(1, count($view->assetBundles)); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestSimpleAsset', $view->assetBundles); - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestSimpleAsset'] instanceof AssetBundle); - - $expected = <<4 -EOF; - $this->assertEquals($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php')); - } - - public function testSimpleDependency() - { - $view = $this->getView(); - - $this->assertEmpty($view->assetBundles); - TestAssetBundle::register($view); - $this->assertEquals(3, count($view->assetBundles)); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetBundle', $view->assetBundles); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetLevel3', $view->assetBundles); - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle'] instanceof AssetBundle); - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle); - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3'] instanceof AssetBundle); - - $expected = <<23 -4 -EOF; - $this->assertEquals($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php')); - } - - public function positionProvider() - { - return [ - [View::POS_HEAD, true], - [View::POS_HEAD, false], - [View::POS_BEGIN, true], - [View::POS_BEGIN, false], - [View::POS_END, true], - [View::POS_END, false], - ]; - } - - /** - * @dataProvider positionProvider - */ - public function testPositionDependency($pos, $jqAlreadyRegistered) - { - $view = $this->getView(); - - $view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestAssetBundle'] = [ - 'jsOptions' => [ - 'position' => $pos, - ], - ]; - - $this->assertEmpty($view->assetBundles); - if ($jqAlreadyRegistered) { - TestJqueryAsset::register($view); - } - TestAssetBundle::register($view); - $this->assertEquals(3, count($view->assetBundles)); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetBundle', $view->assetBundles); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetLevel3', $view->assetBundles); - - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle'] instanceof AssetBundle); - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle); - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3'] instanceof AssetBundle); - - $this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle']->jsOptions); - $this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle']->jsOptions['position']); - $this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset']->jsOptions); - $this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset']->jsOptions['position']); - $this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3']->jsOptions); - $this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3']->jsOptions['position']); - - switch($pos) - { - case View::POS_HEAD: - $expected = << - -234 -EOF; - break; - case View::POS_BEGIN: - $expected = <<2 -34 -EOF; - break; - default: - case View::POS_END: - $expected = <<23 -4 -EOF; - break; - } - $this->assertEquals($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php')); - } - - public function positionProvider2() - { - return [ - [View::POS_BEGIN, true], - [View::POS_BEGIN, false], - [View::POS_END, true], - [View::POS_END, false], - ]; - } - - /** - * @dataProvider positionProvider - */ - public function testPositionDependencyConflict($pos, $jqAlreadyRegistered) - { - $view = $this->getView(); - - $view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestAssetBundle'] = [ - 'jsOptions' => [ - 'position' => $pos - 1, - ], - ]; - $view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestJqueryAsset'] = [ - 'jsOptions' => [ - 'position' => $pos, - ], - ]; - - $this->assertEmpty($view->assetBundles); - if ($jqAlreadyRegistered) { - TestJqueryAsset::register($view); - } - $this->setExpectedException('yii\\base\\InvalidConfigException'); - TestAssetBundle::register($view); - } - - public function testCircularDependency() - { - $this->setExpectedException('yii\\base\\InvalidConfigException'); - TestAssetCircleA::register($this->getView()); - } -} - -class TestSimpleAsset extends AssetBundle -{ - public $basePath = '@testWebRoot/js'; - public $baseUrl = '@testWeb/js'; - public $js = [ - 'jquery.js', - ]; -} - -class TestAssetBundle extends AssetBundle -{ - public $basePath = '@testWebRoot/files'; - public $baseUrl = '@testWeb/files'; - public $css = [ - 'cssFile.css', - ]; - public $js = [ - 'jsFile.js', - ]; - public $depends = [ - 'yiiunit\\framework\\web\\TestJqueryAsset' - ]; -} - -class TestJqueryAsset extends AssetBundle -{ - public $basePath = '@testWebRoot/js'; - public $baseUrl = '@testWeb/js'; - public $js = [ - 'jquery.js', - ]; - public $depends = [ - 'yiiunit\\framework\\web\\TestAssetLevel3' - ]; -} - -class TestAssetLevel3 extends AssetBundle -{ - public $basePath = '@testWebRoot/js'; - public $baseUrl = '@testWeb/js'; -} - -class TestAssetCircleA extends AssetBundle -{ - public $basePath = '@testWebRoot/js'; - public $baseUrl = '@testWeb/js'; - public $js = [ - 'jquery.js', - ]; - public $depends = [ - 'yiiunit\\framework\\web\\TestAssetCircleB' - ]; -} - -class TestAssetCircleB extends AssetBundle -{ - public $basePath = '@testWebRoot/js'; - public $baseUrl = '@testWeb/js'; - public $js = [ - 'jquery.js', - ]; - public $depends = [ - 'yiiunit\\framework\\web\\TestAssetCircleA' - ]; -} \ No newline at end of file diff --git a/tests/unit/framework/web/AssetConverterTest.php b/tests/unit/framework/web/AssetConverterTest.php deleted file mode 100644 index 54669b3..0000000 --- a/tests/unit/framework/web/AssetConverterTest.php +++ /dev/null @@ -1,42 +0,0 @@ - - */ - -namespace yiiunit\framework\web; -use yii\web\AssetConverter; - -/** - * @group web - */ -class AssetConverterTest extends \yiiunit\TestCase -{ - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - - - public function testConvert() - { - $tmpPath = \Yii::$app->runtimePath . '/assetConverterTest'; - if (!is_dir($tmpPath)) { - mkdir($tmpPath, 0777, true); - } - file_put_contents($tmpPath . '/test.php', <<commands['php'] = ['txt', 'php {from} > {to}']; - $this->assertEquals('test.txt', $converter->convert('test.php', $tmpPath)); - - $this->assertTrue(file_exists($tmpPath . '/test.txt'), 'Failed asserting that asset output file exists.'); - $this->assertEquals("Hello World!\nHello Yii!", file_get_contents($tmpPath . '/test.txt')); - } -} \ No newline at end of file diff --git a/tests/unit/framework/web/CacheSessionTest.php b/tests/unit/framework/web/CacheSessionTest.php deleted file mode 100644 index ae73868..0000000 --- a/tests/unit/framework/web/CacheSessionTest.php +++ /dev/null @@ -1,36 +0,0 @@ -mockApplication(); - Yii::$app->setComponent('cache', new FileCache()); - } - - public function testCacheSession() - { - $session = new CacheSession(); - - $session->writeSession('test', 'sessionData'); - $this->assertEquals('sessionData', $session->readSession('test')); - $session->destroySession('test'); - $this->assertEquals('', $session->readSession('test')); - } - - public function testInvalidCache() - { - $this->setExpectedException('yii\base\InvalidConfigException'); - $session = new CacheSession(['cache' => 'invalid']); - } -} diff --git a/tests/unit/framework/web/ResponseTest.php b/tests/unit/framework/web/ResponseTest.php deleted file mode 100644 index 89c2a40..0000000 --- a/tests/unit/framework/web/ResponseTest.php +++ /dev/null @@ -1,80 +0,0 @@ -mockApplication(); - $this->response = new \yii\web\Response; - } - - public function rightRanges() - { - // TODO test more cases for range requests and check for rfc compatibility - // http://www.w3.org/Protocols/rfc2616/rfc2616.txt - return [ - ['0-5', '0-5', 6, '12ёж'], - ['2-', '2-66', 65, 'ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=?'], - ['-12', '55-66', 12, '(ёжик)=?'], - ]; - } - - /** - * @dataProvider rightRanges - */ - public function testSendFileRanges($rangeHeader, $expectedHeader, $length, $expectedContent) - { - $dataFile = \Yii::getAlias('@yiiunit/data/web/data.txt'); - $fullContent = file_get_contents($dataFile); - $_SERVER['HTTP_RANGE'] = 'bytes=' . $rangeHeader; - ob_start(); - $this->response->sendFile($dataFile)->send( ); - $content = ob_get_clean(); - - $this->assertEquals($expectedContent, $content); - $this->assertEquals(206, $this->response->statusCode); - $headers = $this->response->headers; - $this->assertEquals("bytes", $headers->get('Accept-Ranges')); - $this->assertEquals("bytes " . $expectedHeader . '/' . StringHelper::byteLength($fullContent), $headers->get('Content-Range')); - $this->assertEquals('text/plain', $headers->get('Content-Type')); - $this->assertEquals("$length", $headers->get('Content-Length')); - } - - public function wrongRanges() - { - // TODO test more cases for range requests and check for rfc compatibility - // http://www.w3.org/Protocols/rfc2616/rfc2616.txt - return [ - ['1-2,3-5,6-10'], // multiple range request not supported - ['5-1'], // last-byte-pos value is less than its first-byte-pos value - ['-100000'], // last-byte-pos bigger then content length - ['10000-'], // first-byte-pos bigger then content length - ]; - } - - /** - * @dataProvider wrongRanges - */ - public function testSendFileWrongRanges($rangeHeader) - { - $this->setExpectedException('yii\web\HttpException'); - - $dataFile = \Yii::getAlias('@yiiunit/data/web/data.txt'); - $_SERVER['HTTP_RANGE'] = 'bytes=' . $rangeHeader; - $this->response->sendFile($dataFile); - } - - protected function generateTestFileContent() - { - return '12ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=?'; - } -} diff --git a/tests/unit/framework/web/UrlManagerTest.php b/tests/unit/framework/web/UrlManagerTest.php deleted file mode 100644 index 2c3d458..0000000 --- a/tests/unit/framework/web/UrlManagerTest.php +++ /dev/null @@ -1,310 +0,0 @@ -mockApplication(); - } - - public function testCreateUrl() - { - // default setting with '/' as base url - $manager = new UrlManager([ - 'baseUrl' => '/', - 'cache' => null, - ]); - $url = $manager->createUrl('post/view'); - $this->assertEquals('?r=post/view', $url); - $url = $manager->createUrl('post/view', ['id' => 1, 'title' => 'sample post']); - $this->assertEquals('?r=post/view&id=1&title=sample+post', $url); - - // default setting with '/test/' as base url - $manager = new UrlManager([ - 'baseUrl' => '/test/', - 'cache' => null, - ]); - $url = $manager->createUrl('post/view', ['id' => 1, 'title' => 'sample post']); - $this->assertEquals('/test?r=post/view&id=1&title=sample+post', $url); - - // pretty URL without rules - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'baseUrl' => '/', - 'cache' => null, - ]); - $url = $manager->createUrl('post/view', ['id' => 1, 'title' => 'sample post']); - $this->assertEquals('/post/view?id=1&title=sample+post', $url); - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'baseUrl' => '/test/', - 'cache' => null, - ]); - $url = $manager->createUrl('post/view', ['id' => 1, 'title' => 'sample post']); - $this->assertEquals('/test/post/view?id=1&title=sample+post', $url); - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'baseUrl' => '/test/index.php', - 'cache' => null, - ]); - $url = $manager->createUrl('post/view', ['id' => 1, 'title' => 'sample post']); - $this->assertEquals('/test/index.php/post/view?id=1&title=sample+post', $url); - - // todo: test showScriptName - - // pretty URL with rules - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'cache' => null, - 'rules' => [ - [ - 'pattern' => 'post//', - 'route' => 'post/view', - ], - ], - 'baseUrl' => '/', - ]); - $url = $manager->createUrl('post/view', ['id' => 1, 'title' => 'sample post']); - $this->assertEquals('/post/1/sample+post', $url); - $url = $manager->createUrl('post/index', ['page' => 1]); - $this->assertEquals('/post/index?page=1', $url); - - // pretty URL with rules and suffix - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'cache' => null, - 'rules' => [ - [ - 'pattern' => 'post/<id>/<title>', - 'route' => 'post/view', - ], - ], - 'baseUrl' => '/', - 'suffix' => '.html', - ]); - $url = $manager->createUrl('post/view', ['id' => 1, 'title' => 'sample post']); - $this->assertEquals('/post/1/sample+post.html', $url); - $url = $manager->createUrl('post/index', ['page' => 1]); - $this->assertEquals('/post/index.html?page=1', $url); - - // pretty URL with rules that have host info - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'cache' => null, - 'rules' => [ - [ - 'pattern' => 'post/<id>/<title>', - 'route' => 'post/view', - 'host' => 'http://<lang:en|fr>.example.com', - ], - ], - 'baseUrl' => '/test', - ]); - $url = $manager->createUrl('post/view', ['id' => 1, 'title' => 'sample post', 'lang' => 'en']); - $this->assertEquals('http://en.example.com/test/post/1/sample+post', $url); - $url = $manager->createUrl('post/index', ['page' => 1]); - $this->assertEquals('/test/post/index?page=1', $url); - } - - public function testCreateAbsoluteUrl() - { - $manager = new UrlManager([ - 'baseUrl' => '/', - 'hostInfo' => 'http://www.example.com', - 'cache' => null, - ]); - $url = $manager->createAbsoluteUrl('post/view', ['id' => 1, 'title' => 'sample post']); - $this->assertEquals('http://www.example.com?r=post/view&id=1&title=sample+post', $url); - } - - public function testParseRequest() - { - $manager = new UrlManager(['cache' => null]); - $request = new Request; - - // default setting without 'r' param - unset($_GET['r']); - $result = $manager->parseRequest($request); - $this->assertEquals(['', []], $result); - - // default setting with 'r' param - $_GET['r'] = 'site/index'; - $result = $manager->parseRequest($request); - $this->assertEquals(['site/index', []], $result); - - // default setting with 'r' param as an array - $_GET['r'] = ['site/index']; - $result = $manager->parseRequest($request); - $this->assertEquals(['', []], $result); - - // pretty URL without rules - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'cache' => null, - ]); - // empty pathinfo - $request->pathInfo = ''; - $result = $manager->parseRequest($request); - $this->assertEquals(['', []], $result); - // normal pathinfo - $request->pathInfo = 'site/index'; - $result = $manager->parseRequest($request); - $this->assertEquals(['site/index', []], $result); - // pathinfo with module - $request->pathInfo = 'module/site/index'; - $result = $manager->parseRequest($request); - $this->assertEquals(['module/site/index', []], $result); - // pathinfo with trailing slashes - $request->pathInfo = '/module/site/index/'; - $result = $manager->parseRequest($request); - $this->assertEquals(['module/site/index/', []], $result); - - // pretty URL rules - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'cache' => null, - 'rules' => [ - [ - 'pattern' => 'post/<id>/<title>', - 'route' => 'post/view', - ], - ], - ]); - // matching pathinfo - $request->pathInfo = 'post/123/this+is+sample'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result); - // trailing slash is significant - $request->pathInfo = 'post/123/this+is+sample/'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/123/this+is+sample/', []], $result); - // empty pathinfo - $request->pathInfo = ''; - $result = $manager->parseRequest($request); - $this->assertEquals(['', []], $result); - // normal pathinfo - $request->pathInfo = 'site/index'; - $result = $manager->parseRequest($request); - $this->assertEquals(['site/index', []], $result); - // pathinfo with module - $request->pathInfo = 'module/site/index'; - $result = $manager->parseRequest($request); - $this->assertEquals(['module/site/index', []], $result); - - // pretty URL rules - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'suffix' => '.html', - 'cache' => null, - 'rules' => [ - [ - 'pattern' => 'post/<id>/<title>', - 'route' => 'post/view', - ], - ], - ]); - // matching pathinfo - $request->pathInfo = 'post/123/this+is+sample.html'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result); - // matching pathinfo without suffix - $request->pathInfo = 'post/123/this+is+sample'; - $result = $manager->parseRequest($request); - $this->assertFalse($result); - // empty pathinfo - $request->pathInfo = ''; - $result = $manager->parseRequest($request); - $this->assertEquals(['', []], $result); - // normal pathinfo - $request->pathInfo = 'site/index.html'; - $result = $manager->parseRequest($request); - $this->assertEquals(['site/index', []], $result); - // pathinfo without suffix - $request->pathInfo = 'site/index'; - $result = $manager->parseRequest($request); - $this->assertFalse($result); - - // strict parsing - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'enableStrictParsing' => true, - 'suffix' => '.html', - 'cache' => null, - 'rules' => [ - [ - 'pattern' => 'post/<id>/<title>', - 'route' => 'post/view', - ], - ], - ]); - // matching pathinfo - $request->pathInfo = 'post/123/this+is+sample.html'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result); - // unmatching pathinfo - $request->pathInfo = 'site/index.html'; - $result = $manager->parseRequest($request); - $this->assertFalse($result); - } - - public function testParseRESTRequest() - { - $request = new Request; - - // pretty URL rules - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'showScriptName' => false, - 'cache' => null, - 'rules' => [ - 'PUT,POST post/<id>/<title>' => 'post/create', - 'DELETE post/<id>' => 'post/delete', - 'post/<id>/<title>' => 'post/view', - 'POST/GET' => 'post/get', - ], - ]); - // matching pathinfo GET request - $_SERVER['REQUEST_METHOD'] = 'GET'; - $request->pathInfo = 'post/123/this+is+sample'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result); - // matching pathinfo PUT/POST request - $_SERVER['REQUEST_METHOD'] = 'PUT'; - $request->pathInfo = 'post/123/this+is+sample'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/create', ['id' => '123', 'title' => 'this+is+sample']], $result); - $_SERVER['REQUEST_METHOD'] = 'POST'; - $request->pathInfo = 'post/123/this+is+sample'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/create', ['id' => '123', 'title' => 'this+is+sample']], $result); - - // no wrong matching - $_SERVER['REQUEST_METHOD'] = 'POST'; - $request->pathInfo = 'POST/GET'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/get', []], $result); - - // createUrl should ignore REST rules - $this->mockApplication([ - 'components' => [ - 'request' => [ - 'hostInfo' => 'http://localhost/', - 'baseUrl' => '/app' - ] - ] - ], \yii\web\Application::className()); - $this->assertEquals('/app/post/delete?id=123', $manager->createUrl('post/delete', ['id' => 123])); - $this->destroyApplication(); - - unset($_SERVER['REQUEST_METHOD']); - } -} diff --git a/tests/unit/framework/web/UrlRuleTest.php b/tests/unit/framework/web/UrlRuleTest.php deleted file mode 100644 index 39fa9bd..0000000 --- a/tests/unit/framework/web/UrlRuleTest.php +++ /dev/null @@ -1,658 +0,0 @@ -<?php - -namespace yiiunit\framework\web; - -use yii\web\UrlManager; -use yii\web\UrlRule; -use yii\web\Request; -use yiiunit\TestCase; - -/** - * @group web - */ -class UrlRuleTest extends TestCase -{ - public function testCreateUrl() - { - $manager = new UrlManager(['cache' => null]); - $suites = $this->getTestsForCreateUrl(); - foreach ($suites as $i => $suite) { - list ($name, $config, $tests) = $suite; - $rule = new UrlRule($config); - foreach ($tests as $j => $test) { - list ($route, $params, $expected) = $test; - $url = $rule->createUrl($manager, $route, $params); - $this->assertEquals($expected, $url, "Test#$i-$j: $name"); - } - } - } - - public function testParseRequest() - { - $manager = new UrlManager(['cache' => null]); - $request = new Request(['hostInfo' => 'http://en.example.com']); - $suites = $this->getTestsForParseRequest(); - foreach ($suites as $i => $suite) { - list ($name, $config, $tests) = $suite; - $rule = new UrlRule($config); - foreach ($tests as $j => $test) { - $request->pathInfo = $test[0]; - $route = $test[1]; - $params = isset($test[2]) ? $test[2] : []; - $result = $rule->parseRequest($manager, $request); - if ($route === false) { - $this->assertFalse($result, "Test#$i-$j: $name"); - } else { - $this->assertEquals([$route, $params], $result, "Test#$i-$j: $name"); - } - } - } - } - - protected function getTestsForCreateUrl() - { - // structure of each test - // message for the test - // config for the URL rule - // list of inputs and outputs - // route - // params - // expected output - return [ - [ - 'empty pattern', - [ - 'pattern' => '', - 'route' => 'post/index', - ], - [ - ['post/index', [], ''], - ['comment/index', [], false], - ['post/index', ['page' => 1], '?page=1'], - ], - ], - [ - 'without param', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - ], - [ - ['post/index', [], 'posts'], - ['comment/index', [], false], - ['post/index', ['page' => 1], 'posts?page=1'], - ], - ], - [ - 'parsing only', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - 'mode' => UrlRule::PARSING_ONLY, - ], - [ - ['post/index', [], false], - ], - ], - [ - 'with param', - [ - 'pattern' => 'post/<page>', - 'route' => 'post/index', - ], - [ - ['post/index', [], false], - ['comment/index', [], false], - ['post/index', ['page' => 1], 'post/1'], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/1?tag=a'], - ], - ], - [ - 'with param requirement', - [ - 'pattern' => 'post/<page:\d+>', - 'route' => 'post/index', - ], - [ - ['post/index', ['page' => 'abc'], false], - ['post/index', ['page' => 1], 'post/1'], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/1?tag=a'], - ], - ], - [ - 'with multiple params', - [ - 'pattern' => 'post/<page:\d+>-<tag>', - 'route' => 'post/index', - ], - [ - ['post/index', ['page' => '1abc'], false], - ['post/index', ['page' => 1], false], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/1-a'], - ], - ], - [ - 'with optional param', - [ - 'pattern' => 'post/<page:\d+>/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/index', ['page' => 1], false], - ['post/index', ['page' => '1abc', 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/a'], - ['post/index', ['page' => 2, 'tag' => 'a'], 'post/2/a'], - ], - ], - [ - 'with optional param not in pattern', - [ - 'pattern' => 'post/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/index', ['page' => 1], false], - ['post/index', ['page' => '1abc', 'tag' => 'a'], false], - ['post/index', ['page' => 2, 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/a'], - ], - ], - [ - 'multiple optional params', - [ - 'pattern' => 'post/<page:\d+>/<tag>/<sort:yes|no>', - 'route' => 'post/index', - 'defaults' => ['page' => 1, 'sort' => 'yes'], - ], - [ - ['post/index', ['page' => 1], false], - ['post/index', ['page' => '1abc', 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a', 'sort' => 'YES'], false], - ['post/index', ['page' => 1, 'tag' => 'a', 'sort' => 'yes'], 'post/a'], - ['post/index', ['page' => 2, 'tag' => 'a', 'sort' => 'yes'], 'post/2/a'], - ['post/index', ['page' => 2, 'tag' => 'a', 'sort' => 'no'], 'post/2/a/no'], - ['post/index', ['page' => 1, 'tag' => 'a', 'sort' => 'no'], 'post/a/no'], - ], - ], - [ - 'optional param and required param separated by dashes', - [ - 'pattern' => 'post/<page:\d+>-<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/index', ['page' => 1], false], - ['post/index', ['page' => '1abc', 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/-a'], - ['post/index', ['page' => 2, 'tag' => 'a'], 'post/2-a'], - ], - ], - [ - 'optional param at the end', - [ - 'pattern' => 'post/<tag>/<page:\d+>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/index', ['page' => 1], false], - ['post/index', ['page' => '1abc', 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/a'], - ['post/index', ['page' => 2, 'tag' => 'a'], 'post/a/2'], - ], - ], - [ - 'consecutive optional params', - [ - 'pattern' => 'post/<page:\d+>/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1, 'tag' => 'a'], - ], - [ - ['post/index', ['page' => 1], false], - ['post/index', ['page' => '1abc', 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post'], - ['post/index', ['page' => 2, 'tag' => 'a'], 'post/2'], - ['post/index', ['page' => 1, 'tag' => 'b'], 'post/b'], - ['post/index', ['page' => 2, 'tag' => 'b'], 'post/2/b'], - ], - ], - [ - 'consecutive optional params separated by dash', - [ - 'pattern' => 'post/<page:\d+>-<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1, 'tag' => 'a'], - ], - [ - ['post/index', ['page' => 1], false], - ['post/index', ['page' => '1abc', 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/-'], - ['post/index', ['page' => 1, 'tag' => 'b'], 'post/-b'], - ['post/index', ['page' => 2, 'tag' => 'a'], 'post/2-'], - ['post/index', ['page' => 2, 'tag' => 'b'], 'post/2-b'], - ], - ], - [ - 'route has parameters', - [ - 'pattern' => '<controller>/<action>', - 'route' => '<controller>/<action>', - 'defaults' => [], - ], - [ - ['post/index', ['page' => 1], 'post/index?page=1'], - ['module/post/index', [], false], - ], - ], - [ - 'route has parameters with regex', - [ - 'pattern' => '<controller:post|comment>/<action>', - 'route' => '<controller>/<action>', - 'defaults' => [], - ], - [ - ['post/index', ['page' => 1], 'post/index?page=1'], - ['comment/index', ['page' => 1], 'comment/index?page=1'], - ['test/index', ['page' => 1], false], - ['post', [], false], - ['module/post/index', [], false], - ['post/index', ['controller' => 'comment'], 'post/index?controller=comment'], - ], - ], - [ - 'route has default parameter', - [ - 'pattern' => '<controller:post|comment>/<action>', - 'route' => '<controller>/<action>', - 'defaults' => ['action' => 'index'], - ], - [ - ['post/view', ['page' => 1], 'post/view?page=1'], - ['comment/view', ['page' => 1], 'comment/view?page=1'], - ['test/view', ['page' => 1], false], - ['test/index', ['page' => 1], false], - ['post/index', ['page' => 1], 'post?page=1'], - ], - ], - [ - 'empty pattern with suffix', - [ - 'pattern' => '', - 'route' => 'post/index', - 'suffix' => '.html', - ], - [ - ['post/index', [], ''], - ['comment/index', [], false], - ['post/index', ['page' => 1], '?page=1'], - ], - ], - [ - 'regular pattern with suffix', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - 'suffix' => '.html', - ], - [ - ['post/index', [], 'posts.html'], - ['comment/index', [], false], - ['post/index', ['page' => 1], 'posts.html?page=1'], - ], - ], - [ - 'empty pattern with slash suffix', - [ - 'pattern' => '', - 'route' => 'post/index', - 'suffix' => '/', - ], - [ - ['post/index', [], ''], - ['comment/index', [], false], - ['post/index', ['page' => 1], '?page=1'], - ], - ], - [ - 'regular pattern with slash suffix', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - 'suffix' => '/', - ], - [ - ['post/index', [], 'posts/'], - ['comment/index', [], false], - ['post/index', ['page' => 1], 'posts/?page=1'], - ], - ], - [ - 'with host info', - [ - 'pattern' => 'post/<page:\d+>/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - 'host' => 'http://<lang:en|fr>.example.com', - ], - [ - ['post/index', ['page' => 1, 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a', 'lang' => 'en'], 'http://en.example.com/post/a'], - ], - ], - ]; - } - - protected function getTestsForParseRequest() - { - // structure of each test - // message for the test - // config for the URL rule - // list of inputs and outputs - // pathInfo - // expected route, or false if the rule doesn't apply - // expected params, or not set if empty - return [ - [ - 'empty pattern', - [ - 'pattern' => '', - 'route' => 'post/index', - ], - [ - ['', 'post/index'], - ['a', false], - ], - ], - [ - 'without param', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - ], - [ - ['posts', 'post/index'], - ['a', false], - ], - ], - [ - 'with dot', // https://github.com/yiisoft/yii/issues/2945 - [ - 'pattern' => 'posts.html', - 'route' => 'post/index', - ], - [ - ['posts.html', 'post/index'], - ['postsahtml', false], - ], - ], - [ - 'creation only', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - 'mode' => UrlRule::CREATION_ONLY, - ], - [ - ['posts', false], - ], - ], - [ - 'with param', - [ - 'pattern' => 'post/<page>', - 'route' => 'post/index', - ], - [ - ['post/1', 'post/index', ['page' => '1']], - ['post/a', 'post/index', ['page' => 'a']], - ['post', false], - ['posts', false], - ], - ], - [ - 'with param requirement', - [ - 'pattern' => 'post/<page:\d+>', - 'route' => 'post/index', - ], - [ - ['post/1', 'post/index', ['page' => '1']], - ['post/a', false], - ['post/1/a', false], - ], - ], - [ - 'with multiple params', - [ - 'pattern' => 'post/<page:\d+>-<tag>', - 'route' => 'post/index', - ], - [ - ['post/1-a', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/a', false], - ['post/1', false], - ['post/1/a', false], - ], - ], - [ - 'with optional param', - [ - 'pattern' => 'post/<page:\d+>/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/1/a', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/2/a', 'post/index', ['page' => '2', 'tag' => 'a']], - ['post/a', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/1', 'post/index', ['page' => '1', 'tag' => '1']], - ], - ], - [ - 'with optional param not in pattern', - [ - 'pattern' => 'post/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/a', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/1', 'post/index', ['page' => '1', 'tag' => '1']], - ['post', false], - ], - ], - [ - 'multiple optional params', - [ - 'pattern' => 'post/<page:\d+>/<tag>/<sort:yes|no>', - 'route' => 'post/index', - 'defaults' => ['page' => 1, 'sort' => 'yes'], - ], - [ - ['post/1/a/yes', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'yes']], - ['post/1/a/no', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'no']], - ['post/2/a/no', 'post/index', ['page' => '2', 'tag' => 'a', 'sort' => 'no']], - ['post/2/a', 'post/index', ['page' => '2', 'tag' => 'a', 'sort' => 'yes']], - ['post/a/no', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'no']], - ['post/a', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'yes']], - ['post', false], - ], - ], - [ - 'optional param and required param separated by dashes', - [ - 'pattern' => 'post/<page:\d+>-<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/1-a', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/2-a', 'post/index', ['page' => '2', 'tag' => 'a']], - ['post/-a', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/a', false], - ['post-a', false], - ], - ], - [ - 'optional param at the end', - [ - 'pattern' => 'post/<tag>/<page:\d+>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/a/1', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/a/2', 'post/index', ['page' => '2', 'tag' => 'a']], - ['post/a', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/2', 'post/index', ['page' => '1', 'tag' => '2']], - ['post', false], - ], - ], - [ - 'consecutive optional params', - [ - 'pattern' => 'post/<page:\d+>/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1, 'tag' => 'a'], - ], - [ - ['post/2/b', 'post/index', ['page' => '2', 'tag' => 'b']], - ['post/2', 'post/index', ['page' => '2', 'tag' => 'a']], - ['post', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/b', 'post/index', ['page' => '1', 'tag' => 'b']], - ['post//b', false], - ], - ], - [ - 'consecutive optional params separated by dash', - [ - 'pattern' => 'post/<page:\d+>-<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1, 'tag' => 'a'], - ], - [ - ['post/2-b', 'post/index', ['page' => '2', 'tag' => 'b']], - ['post/2-', 'post/index', ['page' => '2', 'tag' => 'a']], - ['post/-b', 'post/index', ['page' => '1', 'tag' => 'b']], - ['post/-', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post', false], - ], - ], - [ - 'route has parameters', - [ - 'pattern' => '<controller>/<action>', - 'route' => '<controller>/<action>', - 'defaults' => [], - ], - [ - ['post/index', 'post/index'], - ['module/post/index', false], - ], - ], - [ - 'route has parameters with regex', - [ - 'pattern' => '<controller:post|comment>/<action>', - 'route' => '<controller>/<action>', - 'defaults' => [], - ], - [ - ['post/index', 'post/index'], - ['comment/index', 'comment/index'], - ['test/index', false], - ['post', false], - ['module/post/index', false], - ], - ], - [ - 'route has default parameter', - [ - 'pattern' => '<controller:post|comment>/<action>', - 'route' => '<controller>/<action>', - 'defaults' => ['action' => 'index'], - ], - [ - ['post/view', 'post/view'], - ['comment/view', 'comment/view'], - ['test/view', false], - ['post', 'post/index'], - ['posts', false], - ['test', false], - ['index', false], - ], - ], - [ - 'empty pattern with suffix', - [ - 'pattern' => '', - 'route' => 'post/index', - 'suffix' => '.html', - ], - [ - ['', 'post/index'], - ['.html', false], - ['a.html', false], - ], - ], - [ - 'regular pattern with suffix', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - 'suffix' => '.html', - ], - [ - ['posts.html', 'post/index'], - ['posts', false], - ['posts.HTML', false], - ['a.html', false], - ['a', false], - ], - ], - [ - 'empty pattern with slash suffix', - [ - 'pattern' => '', - 'route' => 'post/index', - 'suffix' => '/', - ], - [ - ['', 'post/index'], - ['a', false], - ], - ], - [ - 'regular pattern with slash suffix', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - 'suffix' => '/', - ], - [ - ['posts/', 'post/index'], - ['posts', false], - ['a', false], - ], - ], - [ - 'with host info', - [ - 'pattern' => 'post/<page:\d+>', - 'route' => 'post/index', - 'host' => 'http://<lang:en|fr>.example.com', - ], - [ - ['post/1', 'post/index', ['page' => '1', 'lang' => 'en']], - ['post/a', false], - ['post/1/a', false], - ], - ], - ]; - } -} diff --git a/tests/unit/framework/web/XmlResponseFormatterTest.php b/tests/unit/framework/web/XmlResponseFormatterTest.php deleted file mode 100644 index bf1aa29..0000000 --- a/tests/unit/framework/web/XmlResponseFormatterTest.php +++ /dev/null @@ -1,138 +0,0 @@ -<?php -/** - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yiiunit\framework\web; - -use yii\base\Object; -use yii\web\Response; -use yii\web\XmlResponseFormatter; - -class Post extends Object -{ - public $id; - public $title; - - public function __construct($id, $title) - { - $this->id = $id; - $this->title = $title; - } -} - -/** - * @author Qiang Xue <qiang.xue@gmail.com> - * @since 2.0 - * - * @group web - */ -class XmlResponseFormatterTest extends \yiiunit\TestCase -{ - /** - * @var Response - */ - public $response; - /** - * @var XmlResponseFormatter - */ - public $formatter; - - protected function setUp() - { - $this->mockApplication(); - $this->response = new Response; - $this->formatter = new XmlResponseFormatter; - } - - /** - * @param mixed $data the data to be formatted - * @param string $xml the expected XML body - * @dataProvider formatScalarDataProvider - */ - public function testFormatScalar($data, $xml) - { - $head = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; - $this->response->data = $data; - $this->formatter->format($this->response); - $this->assertEquals($head . $xml, $this->response->content); - } - - public function formatScalarDataProvider() - { - return [ - [null, "<response></response>\n"], - [1, "<response>1</response>\n"], - ['abc', "<response>abc</response>\n"], - [true, "<response>1</response>\n"], - ["<>", "<response><></response>\n"], - ]; - } - - /** - * @param mixed $data the data to be formatted - * @param string $xml the expected XML body - * @dataProvider formatArrayDataProvider - */ - public function testFormatArrays($data, $xml) - { - $head = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; - $this->response->data = $data; - $this->formatter->format($this->response); - $this->assertEquals($head . $xml, $this->response->content); - } - - public function formatArrayDataProvider() - { - return [ - [[], "<response/>\n"], - [[1, 'abc'], "<response><item>1</item><item>abc</item></response>\n"], - [[ - 'a' => 1, - 'b' => 'abc', - ], "<response><a>1</a><b>abc</b></response>\n"], - [[ - 1, - 'abc', - [2, 'def'], - true, - ], "<response><item>1</item><item>abc</item><item><item>2</item><item>def</item></item><item>1</item></response>\n"], - [[ - 'a' => 1, - 'b' => 'abc', - 'c' => [2, '<>'], - true, - ], "<response><a>1</a><b>abc</b><c><item>2</item><item><></item></c><item>1</item></response>\n"], - ]; - } - - /** - * @param mixed $data the data to be formatted - * @param string $xml the expected XML body - * @dataProvider formatObjectDataProvider - */ - public function testFormatObjects($data, $xml) - { - $head = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; - $this->response->data = $data; - $this->formatter->format($this->response); - $this->assertEquals($head . $xml, $this->response->content); - } - - public function formatObjectDataProvider() - { - return [ - [new Post(123, 'abc'), "<response><Post><id>123</id><title>abc\n"], - [[ - new Post(123, 'abc'), - new Post(456, 'def'), - ], "123abc456def\n"], - [[ - new Post(123, '<>'), - 'a' => new Post(456, 'def'), - ], "123<>456def\n"], - ]; - } -} diff --git a/tests/unit/framework/widgets/SpacelessTest.php b/tests/unit/framework/widgets/SpacelessTest.php deleted file mode 100644 index 00f5a96..0000000 --- a/tests/unit/framework/widgets/SpacelessTest.php +++ /dev/null @@ -1,41 +0,0 @@ -\n"; - - Spaceless::begin(); - echo "\t
    \n"; - - Spaceless::begin(); - echo "\t\t
    \n"; - echo "\t\t\t

    This is a left bar!

    \n"; - echo "\t\t
    \n\n"; - echo "\t\t
    \n"; - echo "\t\t\t

    This is a right bar!

    \n"; - echo "\t\t
    \n"; - Spaceless::end(); - - echo "\t
    \n"; - Spaceless::end(); - - echo "\t

    Bye!

    \n"; - echo "\n"; - - $expected="\n

    This is a left bar!

    ". - "

    This is a right bar!

    \t

    Bye!

    \n\n"; - $this->assertEquals($expected, ob_get_clean()); - } -} diff --git a/tests/unit/runtime/.gitignore b/tests/unit/runtime/.gitignore deleted file mode 100644 index f59ec20..0000000 --- a/tests/unit/runtime/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* \ No newline at end of file diff --git a/tests/unit/runtime/coveralls/.gitkeep b/tests/unit/runtime/coveralls/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/web/app/assets/.gitignore b/tests/web/app/assets/.gitignore deleted file mode 100644 index 72e8ffc..0000000 --- a/tests/web/app/assets/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/tests/web/app/index.php b/tests/web/app/index.php deleted file mode 100644 index 5cc5b4b..0000000 --- a/tests/web/app/index.php +++ /dev/null @@ -1,6 +0,0 @@ -run(); diff --git a/tests/web/app/protected/config/main.php b/tests/web/app/protected/config/main.php deleted file mode 100644 index 0b67a5f..0000000 --- a/tests/web/app/protected/config/main.php +++ /dev/null @@ -1,3 +0,0 @@ - 'item 1', - 'value 2' => 'item 2', - 'value 3' => 'item 3', - ], isset($_POST['test']) ? $_POST['test'] : null, - function ($index, $label, $name, $value, $checked) { - return Html::label( - $label . ' ' . Html::checkbox($name, $value, $checked), - null, ['class' => 'inline checkbox'] - ); - }); - echo Html::submitButton(); - echo Html::endForm(); - print_r($_POST); - } -} diff --git a/tests/web/app/protected/runtime/.gitignore b/tests/web/app/protected/runtime/.gitignore deleted file mode 100644 index 72e8ffc..0000000 --- a/tests/web/app/protected/runtime/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/tests/web/app/protected/views/site/index.php b/tests/web/app/protected/views/site/index.php deleted file mode 100644 index cc86af6..0000000 --- a/tests/web/app/protected/views/site/index.php +++ /dev/null @@ -1,8 +0,0 @@ -