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/extensions/yii/swiftmailer/CHANGELOG.md b/CHANGELOG.md similarity index 100% rename from extensions/yii/swiftmailer/CHANGELOG.md rename to CHANGELOG.md diff --git a/LICENSE.md b/LICENSE.md index e98f03d..0bb1a8d 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ 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) +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 diff --git a/extensions/yii/swiftmailer/Mailer.php b/Mailer.php similarity index 100% rename from extensions/yii/swiftmailer/Mailer.php rename to Mailer.php diff --git a/extensions/yii/swiftmailer/Message.php b/Message.php similarity index 100% rename from extensions/yii/swiftmailer/Message.php rename to Message.php diff --git a/README.md b/README.md index d7020d9..e21998d 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,49 @@ -Yii PHP Framework Version 2 -=========================== +SwiftMailer Extension for Yii 2 +=============================== -Thank you for choosing Yii 2 - a modern PHP framework designed for professional Web development. +This extension provides a `SwiftMailer` mail solution for Yii 2. -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. +To use this extension, simply add the following code in your application configuration: +```php +return [ + //.... + 'components' => [ + 'mail' => [ + 'class' => 'yii\swiftmailer\Mailer', + ], + ], +]; +``` -**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. +You can then send an email as follows: -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. +```php +Yii::$app->mail->compose('contact/html') + ->setFrom('from@domain.com') + ->setTo($form->email) + ->setSubject($form->subject) + ->send(); +``` -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. +For further instructions refer to the related section in the Yii Definitive Guide. -[![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. - - -HOW TO PARTICIPATE ------------------- +The preferred way to install this extension is through [composer](http://getcomposer.org/download/). -**Your participation to Yii 2 development is very welcome!** +Either run -You may participate in the following ways: +``` +php composer.phar require --prefer-dist yiisoft/yii2-swiftmailer "*" +``` -* [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. +or add -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). +```json +"yiisoft/yii2-swiftmailer": "*" +``` +to the require section of your composer.json. 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'] : [], - ]) ?> - -
- - - - 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; -?> -
-

title) ?>

- -

Please fill out the following fields to login:

- -
-
- 'login-form']); ?> - field($model, 'username') ?> - field($model, 'password')->passwordInput() ?> - field($model, 'rememberMe')->checkbox() ?> -
- 'btn btn-primary']) ?> -
- -
-
-
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 49e61e3..0000000 Binary files a/apps/advanced/backend/web/favicon.ico and /dev/null differ diff --git a/apps/advanced/backend/web/robots.txt b/apps/advanced/backend/web/robots.txt deleted file mode 100644 index c6742d8..0000000 --- a/apps/advanced/backend/web/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-Agent: * -Disallow: / diff --git a/apps/advanced/common/config/.gitignore b/apps/advanced/common/config/.gitignore deleted file mode 100644 index 46f6eb4..0000000 --- a/apps/advanced/common/config/.gitignore +++ /dev/null @@ -1 +0,0 @@ -params-local.php \ No newline at end of file diff --git a/apps/advanced/common/config/params.php b/apps/advanced/common/config/params.php deleted file mode 100644 index a3d3b3a..0000000 --- a/apps/advanced/common/config/params.php +++ /dev/null @@ -1,20 +0,0 @@ - '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'] : [], - ]) ?> - - -
- - - - 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; -?> -
-

title) ?>

- -

Please fill out the following fields to login:

- -
-
- 'login-form']); ?> - field($model, 'username') ?> - field($model, 'password')->passwordInput() ?> - field($model, 'rememberMe')->checkbox() ?> -
- If you forgot your password you can . -
-
- 'btn btn-primary']) ?> -
- -
-
-
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; -?> -
-

title) ?>

- -

Please fill out the following fields to signup:

- -
-
- 'form-signup']); ?> - field($model, 'username') ?> - field($model, 'email') ?> - field($model, 'password')->passwordInput() ?> -
- 'btn btn-primary']) ?> -
- -
-
-
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 49e61e3..0000000 Binary files a/apps/advanced/frontend/web/favicon.ico and /dev/null differ diff --git a/apps/advanced/frontend/web/robots.txt b/apps/advanced/frontend/web/robots.txt deleted file mode 100644 index 6f27bb6..0000000 --- a/apps/advanced/frontend/web/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: \ No newline at end of file diff --git a/apps/advanced/frontend/widgets/Alert.php b/apps/advanced/frontend/widgets/Alert.php deleted file mode 100644 index 390f359..0000000 --- a/apps/advanced/frontend/widgets/Alert.php +++ /dev/null @@ -1,66 +0,0 @@ -getSession()->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 49e61e3..0000000 Binary files a/apps/basic/web/favicon.ico and /dev/null differ diff --git a/apps/basic/web/index-test.php b/apps/basic/web/index-test.php deleted file mode 100644 index 2bec381..0000000 --- a/apps/basic/web/index-test.php +++ /dev/null @@ -1,16 +0,0 @@ -run(); 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..4c9e831 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-swiftmailer", + "description": "The SwiftMailer integration for the Yii framework", + "keywords": ["yii", "swift", "swiftmailer", "mail", "email", "mailer"], "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%3Aswiftmailer", "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": "Paul Klimov", + "email": "klimov.paul@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": "*", + "swiftmailer/swiftmailer": "*" }, "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\\swiftmailer\\": "" } } } 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 ffc3c5e..0000000 Binary files a/extensions/yii/authclient/widgets/assets/authchoice.png and /dev/null differ 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 459dd78..0000000 Binary files a/extensions/yii/debug/assets/bg.png and /dev/null differ diff --git a/extensions/yii/debug/assets/main.css b/extensions/yii/debug/assets/main.css deleted file mode 100644 index dd100e0..0000000 --- a/extensions/yii/debug/assets/main.css +++ /dev/null @@ -1,70 +0,0 @@ -span.indent { - color: #ccc; -} - -ul.trace { - font-size: 12px; - color: #999; - margin: 2px 0 0 0; - padding: 0; - list-style: none; - white-space: normal; -} - -.callout-danger { - background-color: #fcf2f2; - border-color: #dFb5b4; -} -.callout { - margin: 0 0 10px 0; - padding: 5px; -} - -.list-group .glyphicon { - float: right; -} - -td, th { - white-space: pre-line; - word-wrap: break-word; -} - -.detail-grid-view th { - white-space: nowrap; -} - -/* 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"; -} \ No newline at end of file diff --git a/extensions/yii/debug/assets/toolbar.css b/extensions/yii/debug/assets/toolbar.css deleted file mode 100644 index 5946675..0000000 --- a/extensions/yii/debug/assets/toolbar.css +++ /dev/null @@ -1,188 +0,0 @@ -#yii-debug-toolbar { - padding: 0; - font: 11px Verdana, Arial, sans-serif; - text-align: left; - min-height: 40px; - overflow: auto; - background: rgb(246,246,246); - background: -moz-linear-gradient(top, rgba(237,237,237,1) 0%, rgba(246,246,246,1) 53%, rgba(255,255,255,1) 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(237,237,237,1)), color-stop(53%,rgba(246,246,246,1)), color-stop(100%,rgba(255,255,255,1))); - background: -webkit-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: -o-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: -ms-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: linear-gradient(to bottom, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ededed', endColorstr='#ffffff',GradientType=0 ); - background: rgb(246,246,246) url(data:image/svg+xml;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAoCAYAAAA/tpB3AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BBQwuINct3v0AAAAjSURBVAjXY3j79u1/JgYGBgYkgpGRkYEYMSpKUGLK+/fvGQAaDAb6F86IsAAAAABJRU5ErkJggg==); /* generated using "cat assets/bg.png | base64" */ -} - -.yii-debug-toolbar-top { - margin: 0 0 20px 0; - border-bottom: 1px solid #e4e4e4; -} - -.yii-debug-toolbar-bottom { - position: fixed; - left: 0; - right: 0; - bottom: 0; - margin: 0; - z-index: 1000000; - border-top: 1px solid #ccc; -} - -.yii-debug-toolbar-block { - float: left; - margin: 0; - border-right: 1px solid #e4e4e4; - padding: 4px 8px; - line-height: 32px; - height: 40px; - white-space: nowrap; -} - -.yii-debug-toolbar-block a { - text-decoration: none; - color: black; -} - -.yii-debug-toolbar-block span { -} - -.yii-debug-toolbar-block img { - vertical-align: middle; -} - -#yii-debug-toolbar .label { - display: inline-block; - padding: 2px 4px; - font-size: 11.844px; - font-weight: normal; - line-height: 14px; - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - white-space: nowrap; - vertical-align: baseline; - background-color: #999999; -} - -#yii-debug-toolbar .label { - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; -} - -#yii-debug-toolbar .label:empty { - display: none; -} - -#yii-debug-toolbar a.label:hover, -#yii-debug-toolbar a.label:focus { - color: #ffffff; - text-decoration: none; - cursor: pointer; -} - -#yii-debug-toolbar .label-important { - background-color: #b94a48; -} - -#yii-debug-toolbar .label-important[href] { - background-color: #953b39; -} - -#yii-debug-toolbar .label-warning, -#yii-debug-toolbar .badge-warning { - background-color: #f89406; -} - -#yii-debug-toolbar .label-warning[href] { - background-color: #c67605; -} - -#yii-debug-toolbar .label-success { - background-color: #468847; -} - -#yii-debug-toolbar .label-success[href] { - background-color: #356635; -} - -#yii-debug-toolbar .label-info { - background-color: #3a87ad; -} - -#yii-debug-toolbar .label-info[href] { - background-color: #2d6987; -} - -#yii-debug-toolbar .label-inverse, -#yii-debug-toolbar .badge-inverse { - background-color: #333333; -} - -#yii-debug-toolbar .label-inverse[href], -#yii-debug-toolbar .badge-inverse[href] { - background-color: #1a1a1a; -} - -.yii-debug-toolbar-toggler { - cursor: pointer; - position: absolute; - right: 10px; - bottom: 4px; - width: 15px; - height: 30px; - font-size: 25px; - font-weight: 100; - line-height: 28px; - color: #ffffff; - text-align: center; - background: #666666; - -webkit-border-radius: 12px; - -moz-border-radius: 12px; - border-radius: 12px; - opacity: 0.5; - filter: alpha(opacity=50); -} - -.yii-debug-toolbar-toggler:hover, -.yii-debug-toolbar-toggler:focus { - color: #ffffff; - text-decoration: none; - opacity: 0.9; - filter: alpha(opacity=90); -} - -#yii-debug-toolbar-min { - display: none; - position: fixed; - right: 0; - bottom: 0; - margin: 0; - padding: 0; - z-index: 1000000; - font: 11px Verdana, Arial, sans-serif; - text-align: left; - width: 63px; - height: 38px; - border-top: 1px solid #ccc; - border-left: 1px solid #ccc; - -webkit-border-top-left-radius: 6px; - -moz-border-top-left-radius: 6px; - border-top-left-radius: 6px; - background: rgb(237,237,237); - background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2VkZWRlZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjUzJSIgc3RvcC1jb2xvcj0iI2Y2ZjZmNiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); - background: -moz-linear-gradient(top, rgba(237,237,237,1) 0%, rgba(246,246,246,1) 53%, rgba(255,255,255,1) 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(237,237,237,1)), color-stop(53%,rgba(246,246,246,1)), color-stop(100%,rgba(255,255,255,1))); - background: -webkit-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: -o-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: -ms-linear-gradient(top, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - background: linear-gradient(to bottom, rgba(237,237,237,1) 0%,rgba(246,246,246,1) 53%,rgba(255,255,255,1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ededed', endColorstr='#ffffff',GradientType=0 ); -} - -#yii-debug-toolbar-logo { - position: fixed; - right: 31px; - bottom: 4px; -} diff --git a/extensions/yii/debug/assets/toolbar.js b/extensions/yii/debug/assets/toolbar.js deleted file mode 100644 index 0dca1de..0000000 --- a/extensions/yii/debug/assets/toolbar.js +++ /dev/null @@ -1,41 +0,0 @@ -(function() { - var ajax = function(url, settings) { - var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); - settings = settings || {}; - xhr.open(settings.method || 'GET', url, true); - xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); - xhr.onreadystatechange = function(state) { - if (xhr.readyState == 4) { - if (xhr.status == 200 && settings.success) { - settings.success(xhr); - } else if (xhr.status != 200 && settings.error) { - settings.error(xhr); - } - } - }; - xhr.send(settings.data || ''); - }; - - var e = document.getElementById('yii-debug-toolbar'); - if (e) { - e.style.display = 'block'; - var url = e.getAttribute('data-url'); - ajax(url, { - success: function(xhr) { - var div = document.createElement('div'); - div.innerHTML = xhr.responseText; - e.parentNode.replaceChild(div, e); - if (window.localStorage) { - var pref = localStorage.getItem('yii-debug-toolbar'); - if (pref == 'minimized') { - document.getElementById('yii-debug-toolbar').style.display = 'none'; - document.getElementById('yii-debug-toolbar-min').style.display = 'block'; - } - } - }, - error: function(xhr) { - e.innerHTML = xhr.responseText; - } - }); - } -})(); diff --git a/extensions/yii/debug/components/search/Filter.php b/extensions/yii/debug/components/search/Filter.php deleted file mode 100644 index 557e12c..0000000 --- a/extensions/yii/debug/components/search/Filter.php +++ /dev/null @@ -1,72 +0,0 @@ - [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,iVBORw0KGgoAAAANSUhEUgAAAB0AAAAeCAYAAADQBxWhAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAADcZJREFUeAEAtg1J8gHaKRUAAP8AAAEGAQACDgMAAQgDAAIIAQABCQMAAQgEAAIKAwACCAQAAQgCAAIJBQACCQQAAgkFAAIJBwAQCwkA0hgAANAO+gAM/AEAAQABAPn++wD2/PkA+f38Of3+/Wb+//9S/v/+sQABAV4DAAEAAAAAAAQAAAAAAAAAAAD/AAAA/wAAAP8AGwD/ABoA/wAAAP8A5gD/AOUA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AAAAAAB+BgIEgf8BAwD9//4A/v/9Xfz+/hEAAABNAAAAAAQA/wAAAP8AMgADAGEAAwE7AQUBJwAGAgoBBQIAAQUB9gADAdoAAQDFAP//sQD//7sAAAAAAAAAAAAAAAAAAAAA/wD/AP///wD//wAA/wD/AAAAAH4HAwWBAP8AAP7//wD9//4A/f8DAAIB/Uz9//1mAQECmgHaKRUAAAIApwMPBFgCDAQAAQsCAAIJAwABBwMAAgkDAAEHAwABBQIAAQYDAAEFA8cCCAOEAggFtgIKBwAQCgkAzhsBANQO+wAP+wEA/gD/QP///78AAAAA/gD+AP7+/wD9//4A/P/+AP39/gD7//zp/gD/GAQCCAIAAAQA5wAJAgABCAIAAQcCAAEGAwACCAIAAAcCAAEHAgABBgQAAgcEAAIGAjkABAK1AAEAnwD//2f8AP77FPwHABACAwAEBAAAAP/+jgD//wD/AAAA/f/+AP4B/gD9//4AAv79APwB/QAA/f8X/P7+PgQCCgMAAAIBzgAGAQABBgEAAgUCAAIGAQABBgIAAQYDAAIFBAAABwQAAQcCAAEGAwABBQUAAQQCYQEDAiv6Af9HFvgD8A/+AQD2A/4hBf4CMQAAAQD/AP4A/v//AP7+/gD8//4AAgECAAL/AAAB/wAAAgD+RgQACwMAAP8AwwIFAQABBgIAAQYCAAAHAwABBgMAAQUDAAEHAwABBgIAAgYDAAEGBQACBgQAAgUEAAAFAjb9AwG+CPz+ORv6BfndDgMsBvsBAAAAAAD/AP4A/v/+APwB/gAC//0AAv4CAAL+AAAAAwEAAAH8FAICBgEAAgYA4QAEAscBBQIAAQYCAAEFAgAABAIAAQUDAAEFAwACBgMAAQYFAAIGBAABBwQAAAgEAAIHBQACCAYx/gMBpR7zAAAP/wbaBAUHAAcEBQAGAwYABgMGAAcDBQAFAwUABAMDAAQCBQAFAgMABAED/wICDAQAAgwFAAIGAngBAwEAAAUCAAEDAQACBQIAAQUCAAEFAgABBQQAAQYDAAEHBAACBgQAAgUDAAEGAwACBwUA/wn+U/0FHlULABjZBQX74AYDBwAGBAUABQMFAAUDBAAGAgUABQIEAAUCAwAEAQQABAID6AIABQEAAAYBAAAEAcIAAwGZAQMBAAAEAgAABAMAAgUCAAEEAgABBAIAAgQDAAEEAwABBQIAAQYDAAIHBQACBgQAAwYEAP8KAKIHAhEABwQChgYEBQAGAgUABwMFAAUCBQADAgMABQIEAAMCAwADAgMAAwIEugIA/wAAAP8AAAD+/wAAAABoAAMBqgIEAgABBAIAAAMBAAEEAwAABAMAAQUDAAEFAgAABAMAAgUEAAEFBAABBgUAAAcKAAUG8QgH/A93B/4amwYF/f8FAwYABAIDAAUDBAAEAgMAAwIDAAMBAgACAQHkBQIDxwIAAAAAAAAAAAAAAAAAAAAAAQABVwACAnsBAwH0AQMCAAEEAgABBAIAAAMCAAEDAgACBAMAAQUDAAEEAwABBQQAAgcFAP4FBQADAPqABfwaAQQDBbEEAwUAAwMFAAMCAwAEAgMAAwECAAMBAgACAQKaBAIDAAIAAAAAAAAAAAAAAAAAAAAAAAAAAP8A/4YAAAAvAQIBhQABAcoBAgIAAgMCAAEDAgABBAMAAAMDAAEEAwABBQQAAAcCAPwECwD9AgAIAf8LUQQBEaYGAwEAAwIEAAICAgACAgIAAQECAAECAvEDAgOTBAIDAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADeAAAAfAABADcAAgAx/wIAdwACArUAAgL3AQICAAEDAwABAwMAAAYCAPkCDgD8AgoA/QAIbP//Ec0EBAD7AgECAAIBAgACAAIAAgABAAEAAXEEAgPwBQIFAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQAAAAigAAAEwBAAAxAAIBYgACArMDA/v8AAXzAPcADwD9AgkA/gIJQf//BBsCAfrZAf8CAAAAAAAAAAAA/wAAuAEBAp8FAgUABAIEAAIA//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAwAHAffZBgHtnwQD8k4ABPQp1vVFpvYCFgANCPUA/QIIAPr9Eyb8/AOx/wH7AP///wD+//7nAQEAWQUCBAAEAgQABAIEAAT98esAAQYJAAMLEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAIACQH3AAME7AD4AigA3/0sANPtLAD5Ag3c5AE5GxcK8QAzEsgAFAnzAPH7ESMC/ATg/v/1AP3+AP7///9PAQAB8AIBAQAAAAAAAAAAAAOGorAA+9zPAPvg1wADFBQAAgYCAAEGAwAABQYACwT4AA0F9AAIB/UA8QIXANf8LgCp+WIAtvNKAOP3GwDu/BmLEAPuWvT8CgDh9iYABwX+ABUN+PD8++EL+/zuNP3/A08A//+//wD/AAAAAAAAAAAAAAAAAAH///8A+ubdAOdzRQD/7t8AESYZAA0UCAACCPwA8A4iANsJLwDRBC8A2P0rAN37IgAIAfYABv70AA0LBkERCwe+BwQCAAkHAAAAAwkA+wMRADEZ7N0qCYfF9/jR0/4CFoz///wA/f3+AAAAAAAAAAAAAAAAAAH///8A/gAAAPXn4QD90bsA58y1APH38wAIEAkApA5sANICMgD//QAACQD1AA0C8wD//wAABAICEQsIBN4IBgQQBwUCAAkGAwAJBgIAAwQGAP0DFgAuEqk+FQbDw/j+GAD///0A/v7+AAAAAAAAAAAAAAAAAAH///8A+vv7AP4FBQAIAAAAlL7hAJC+6AAZEgwA/gACAAr/9AABAAAAAQD/AP8AAQD+//8ADQgFqw0IBlQIBQMACAYDAAgFBAAHBgMACgYBAAYFBP8BBA0XAwH+6/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAQAAAP729gAACgYA6/T4AOf1+gAQDPYAA//8APIA/wAAAAEAAAAAAP3//wAGAAE5BQECVAEA+wD8/v8A/f7/AP7+/wD9//4A/v8EAAr+/OYD/fLr/v8CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAA/v0AOx0HAIkA+ADf7/sABgMBAAAAAAAAAAAAAAAAAP4A/wAMBAR+AP8AAP3//wD8/v8A/f7+AP7+/wD9/v8A/v7/AP//BLgC/P4A//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAD+/P4ANyENABgPAwDh4/QAAAsEAAAAAAAAAAAAAP8AAAAAABTyCAVI/f//ABX//gAO/v4A/v4EAP3+/wD8//8A/v//AP8AAJICAQEA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAD2+v0ADxAIAEUlEACc0+0AAAwEAAD+AAAAAAAAAAEAAAD//1b49/oA5P3/APn+/wAW/v8AD/3/AP3+/wD8/v4A/f4Fofn8/dL//v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAD/AAAAAPv9AE4oEQCcCwQAAP3/AAACAQAAAAAAAAAAAAABATAAAP8A/fr7AOj9/gD3/gYAGP//ABH+/gAK/QTfBgMCZwEAAgD9/v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAABAAAA8fH5AE0zFwA3MRYAAOv3AAAAAAAA/v8AAP7/AAD/ABgAAgEAAAMBAAD9/QDx8/gA4fT5AOX3+tv4/P4/AwEB+QMCAQADAgEAAwIBAAMCAQADAgEAAwIBAAMCAQADAgEAAwIBAAIAAAAAAQEBAAAAAAAAAAAA9/7/AAAAAACGRB0AAAQDAAD5/wAA/gEAAP4BAAAAAA4A/gAAAPr/AAD4/wAC+fwA+Pb4qfH7/jgDAgHjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT///8G/Pz8+gAAAAD///8AAgAAAPHt9wBCKBEAdFIfAMbZ7AARCwYADQkCAM7d9xzg6foABQ0D8SkVA7spHA+grNnxtfv8/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT9/f3+////AQQEBAEAAAABBAQE/f0BAQAABQcASiMNAN3g5wAbDQQADAf/AOgNAXosEgkMAQgAsA4GAe4SEAUA/P8BAAQBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAP//vNz1LVdvDhUAAAAASUVORK5CYII='; - } - - 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 8877a60..0000000 Binary files a/extensions/yii/elasticsearch/README-debug.png and /dev/null differ diff --git a/extensions/yii/elasticsearch/README.md b/extensions/yii/elasticsearch/README.md deleted file mode 100644 index 2d2529f..0000000 --- a/extensions/yii/elasticsearch/README.md +++ /dev/null @@ -1,190 +0,0 @@ -Elasticsearch Query and ActiveRecord for Yii 2 -============================================== - -This extension provides the [elasticsearch](http://www.elasticsearch.org/) integration for the Yii2 framework. -It includes basic querying/search support and also implements the `ActiveRecord` pattern that allows you to store active -records in elasticsearch. - -To use this extension, you have to configure the Connection class in your application configuration: - -```php -return [ - //.... - 'components' => [ - '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 e48b5aa..0000000 Binary files a/extensions/yii/gii/assets/logo.png and /dev/null differ 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 = $( "
      " ) - .addClass( "ui-autocomplete ui-front" ) - .appendTo( this._appendTo() ) - .menu({ - // disable ARIA support, the live region takes care of that - role: null - }) - .hide() - .data( "ui-menu" ); - - this._on( this.menu.element, { - mousedown: function( event ) { - // prevent moving focus out of the text field - event.preventDefault(); - - // IE doesn't prevent moving focus even with event.preventDefault() - // so we set a flag to know when we should ignore the blur event - this.cancelBlur = true; - this._delay(function() { - delete this.cancelBlur; - }); - - // clicking on the scrollbar causes focus to shift to the body - // but we can't detect a mouseup or a click immediately afterward - // so we have to track the next mousedown and close the menu if - // the user clicks somewhere outside of the autocomplete - var menuElement = this.menu.element[ 0 ]; - if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { - this._delay(function() { - var that = this; - this.document.one( "mousedown", function( event ) { - if ( event.target !== that.element[ 0 ] && - event.target !== menuElement && - !$.contains( menuElement, event.target ) ) { - that.close(); - } - }); - }); - } - }, - menufocus: function( event, ui ) { - // support: Firefox - // Prevent accidental activation of menu items in Firefox (#7024 #9118) - if ( this.isNewMenu ) { - this.isNewMenu = false; - if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { - this.menu.blur(); - - this.document.one( "mousemove", function() { - $( event.target ).trigger( event.originalEvent ); - }); - - return; - } - } - - var item = ui.item.data( "ui-autocomplete-item" ); - if ( false !== this._trigger( "focus", event, { item: item } ) ) { - // use value to match what will end up in the input, if it was a key event - if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { - this._value( item.value ); - } - } else { - // Normally the input is populated with the item's value as the - // menu is navigated, causing screen readers to notice a change and - // announce the item. Since the focus event was canceled, this doesn't - // happen, so we update the live region so that screen readers can - // still notice the change and announce it. - this.liveRegion.text( item.value ); - } - }, - menuselect: function( event, ui ) { - var item = ui.item.data( "ui-autocomplete-item" ), - previous = this.previous; - - // only trigger when focus was lost (click on menu) - if ( this.element[0] !== this.document[0].activeElement ) { - this.element.focus(); - this.previous = previous; - // #6109 - IE triggers two focus events and the second - // is asynchronous, so we need to reset the previous - // term synchronously and asynchronously :-( - this._delay(function() { - this.previous = previous; - this.selectedItem = item; - }); - } - - if ( false !== this._trigger( "select", event, { item: item } ) ) { - this._value( item.value ); - } - // reset the term after the select event - // this allows custom select handling to work properly - this.term = this._value(); - - this.close( event ); - this.selectedItem = item; - } - }); - - this.liveRegion = $( "", { - role: "status", - "aria-live": "polite" - }) - .addClass( "ui-helper-hidden-accessible" ) - .insertBefore( this.element ); - - // turning off autocomplete prevents the browser from remembering the - // value when navigating through history, so we re-enable autocomplete - // if the page is unloaded before the widget is destroyed. #7790 - this._on( this.window, { - beforeunload: function() { - this.element.removeAttr( "autocomplete" ); - } - }); - }, - - _destroy: function() { - clearTimeout( this.searching ); - this.element - .removeClass( "ui-autocomplete-input" ) - .removeAttr( "autocomplete" ); - this.menu.element.remove(); - this.liveRegion.remove(); - }, - - _setOption: function( key, value ) { - this._super( key, value ); - if ( key === "source" ) { - this._initSource(); - } - if ( key === "appendTo" ) { - this.menu.element.appendTo( this._appendTo() ); - } - if ( key === "disabled" && value && this.xhr ) { - this.xhr.abort(); - } - }, - - _appendTo: function() { - var element = this.options.appendTo; - - if ( element ) { - element = element.jquery || element.nodeType ? - $( element ) : - this.document.find( element ).eq( 0 ); - } - - if ( !element ) { - element = this.element.closest( ".ui-front" ); - } - - if ( !element.length ) { - element = this.document[0].body; - } - - return element; - }, - - _initSource: function() { - var array, url, - that = this; - if ( $.isArray(this.options.source) ) { - array = this.options.source; - this.source = function( request, response ) { - response( $.ui.autocomplete.filter( array, request.term ) ); - }; - } else if ( typeof this.options.source === "string" ) { - url = this.options.source; - this.source = function( request, response ) { - if ( that.xhr ) { - that.xhr.abort(); - } - that.xhr = $.ajax({ - url: url, - data: request, - dataType: "json", - success: function( data ) { - response( data ); - }, - error: function() { - response( [] ); - } - }); - }; - } else { - this.source = this.options.source; - } - }, - - _searchTimeout: function( event ) { - clearTimeout( this.searching ); - this.searching = this._delay(function() { - // only search if the value has changed - if ( this.term !== this._value() ) { - this.selectedItem = null; - this.search( null, event ); - } - }, this.options.delay ); - }, - - search: function( value, event ) { - value = value != null ? value : this._value(); - - // always save the actual value, not the one passed as an argument - this.term = this._value(); - - if ( value.length < this.options.minLength ) { - return this.close( event ); - } - - if ( this._trigger( "search", event ) === false ) { - return; - } - - return this._search( value ); - }, - - _search: function( value ) { - this.pending++; - this.element.addClass( "ui-autocomplete-loading" ); - this.cancelSearch = false; - - this.source( { term: value }, this._response() ); - }, - - _response: function() { - var that = this, - index = ++requestIndex; - - return function( content ) { - if ( index === requestIndex ) { - that.__response( content ); - } - - that.pending--; - if ( !that.pending ) { - that.element.removeClass( "ui-autocomplete-loading" ); - } - }; - }, - - __response: function( content ) { - if ( content ) { - content = this._normalize( content ); - } - this._trigger( "response", null, { content: content } ); - if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { - this._suggest( content ); - this._trigger( "open" ); - } else { - // use ._close() instead of .close() so we don't cancel future searches - this._close(); - } - }, - - close: function( event ) { - this.cancelSearch = true; - this._close( event ); - }, - - _close: function( event ) { - if ( this.menu.element.is( ":visible" ) ) { - this.menu.element.hide(); - this.menu.blur(); - this.isNewMenu = true; - this._trigger( "close", event ); - } - }, - - _change: function( event ) { - if ( this.previous !== this._value() ) { - this._trigger( "change", event, { item: this.selectedItem } ); - } - }, - - _normalize: function( items ) { - // assume all items have the right format when the first item is complete - if ( items.length && items[0].label && items[0].value ) { - return items; - } - return $.map( items, function( item ) { - if ( typeof item === "string" ) { - return { - label: item, - value: item - }; - } - return $.extend({ - label: item.label || item.value, - value: item.value || item.label - }, item ); - }); - }, - - _suggest: function( items ) { - var ul = this.menu.element.empty(); - this._renderMenu( ul, items ); - this.isNewMenu = true; - this.menu.refresh(); - - // size and position menu - ul.show(); - this._resizeMenu(); - ul.position( $.extend({ - of: this.element - }, this.options.position )); - - if ( this.options.autoFocus ) { - this.menu.next(); - } - }, - - _resizeMenu: function() { - var ul = this.menu.element; - ul.outerWidth( Math.max( - // Firefox wraps long text (possibly a rounding bug) - // so we add 1px to avoid the wrapping (#7513) - ul.width( "" ).outerWidth() + 1, - this.element.outerWidth() - ) ); - }, - - _renderMenu: function( ul, items ) { - var that = this; - $.each( items, function( index, item ) { - that._renderItemData( ul, item ); - }); - }, - - _renderItemData: function( ul, item ) { - return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); - }, - - _renderItem: function( ul, item ) { - return $( "
    • " ) - .append( $( "" ).text( item.label ) ) - .appendTo( ul ); - }, - - _move: function( direction, event ) { - if ( !this.menu.element.is( ":visible" ) ) { - this.search( null, event ); - return; - } - if ( this.menu.isFirstItem() && /^previous/.test( direction ) || - this.menu.isLastItem() && /^next/.test( direction ) ) { - this._value( this.term ); - this.menu.blur(); - return; - } - this.menu[ direction ]( event ); - }, - - widget: function() { - return this.menu.element; - }, - - _value: function() { - return this.valueMethod.apply( this.element, arguments ); - }, - - _keyEvent: function( keyEvent, event ) { - if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { - this._move( keyEvent, event ); - - // prevents moving cursor to beginning/end of the text field in some browsers - event.preventDefault(); - } - } -}); - -$.extend( $.ui.autocomplete, { - escapeRegex: function( value ) { - return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"); - }, - filter: function(array, term) { - var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" ); - return $.grep( array, function(value) { - return matcher.test( value.label || value.value || value ); - }); - } -}); - - -// live region extension, adding a `messages` option -// NOTE: This is an experimental API. We are still investigating -// a full solution for string manipulation and internationalization. -$.widget( "ui.autocomplete", $.ui.autocomplete, { - options: { - messages: { - noResults: "No search results.", - results: function( amount ) { - return amount + ( amount > 1 ? " results are" : " result is" ) + - " available, use up and down arrow keys to navigate."; - } - } - }, - - __response: function( content ) { - var message; - this._superApply( arguments ); - if ( this.options.disabled || this.cancelSearch ) { - return; - } - if ( content && content.length ) { - message = this.options.messages.results( content.length ); - } else { - message = this.options.messages.noResults; - } - this.liveRegion.text( message ); - } -}); - -}( jQuery )); diff --git a/extensions/yii/jui/assets/jquery.ui.button.js b/extensions/yii/jui/assets/jquery.ui.button.js deleted file mode 100644 index 5926642..0000000 --- a/extensions/yii/jui/assets/jquery.ui.button.js +++ /dev/null @@ -1,419 +0,0 @@ -/*! - * jQuery UI Button 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/button/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -var lastActive, startXPos, startYPos, clickDragged, - baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", - stateClasses = "ui-state-hover ui-state-active ", - typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only", - formResetHandler = function() { - var form = $( this ); - setTimeout(function() { - form.find( ":ui-button" ).button( "refresh" ); - }, 1 ); - }, - radioGroup = function( radio ) { - var name = radio.name, - form = radio.form, - radios = $( [] ); - if ( name ) { - name = name.replace( /'/g, "\\'" ); - if ( form ) { - radios = $( form ).find( "[name='" + name + "']" ); - } else { - radios = $( "[name='" + name + "']", radio.ownerDocument ) - .filter(function() { - return !this.form; - }); - } - } - return radios; - }; - -$.widget( "ui.button", { - version: "1.10.3", - defaultElement: "").addClass(this._triggerClass). - html(!buttonImage ? buttonText : $("").attr( - { src:buttonImage, alt:buttonText, title:buttonText }))); - input[isRTL ? "before" : "after"](inst.trigger); - inst.trigger.click(function() { - if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) { - $.datepicker._hideDatepicker(); - } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) { - $.datepicker._hideDatepicker(); - $.datepicker._showDatepicker(input[0]); - } else { - $.datepicker._showDatepicker(input[0]); - } - return false; - }); - } - }, - - /* Apply the maximum length for the date format. */ - _autoSize: function(inst) { - if (this._get(inst, "autoSize") && !inst.inline) { - var findMax, max, maxI, i, - date = new Date(2009, 12 - 1, 20), // Ensure double digits - dateFormat = this._get(inst, "dateFormat"); - - if (dateFormat.match(/[DM]/)) { - findMax = function(names) { - max = 0; - maxI = 0; - for (i = 0; i < names.length; i++) { - if (names[i].length > max) { - max = names[i].length; - maxI = i; - } - } - return maxI; - }; - date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? - "monthNames" : "monthNamesShort")))); - date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? - "dayNames" : "dayNamesShort"))) + 20 - date.getDay()); - } - inst.input.attr("size", this._formatDate(inst, date).length); - } - }, - - /* Attach an inline date picker to a div. */ - _inlineDatepicker: function(target, inst) { - var divSpan = $(target); - if (divSpan.hasClass(this.markerClassName)) { - return; - } - divSpan.addClass(this.markerClassName).append(inst.dpDiv); - $.data(target, PROP_NAME, inst); - this._setDate(inst, this._getDefaultDate(inst), true); - this._updateDatepicker(inst); - this._updateAlternate(inst); - //If disabled option is true, disable the datepicker before showing it (see ticket #5665) - if( inst.settings.disabled ) { - this._disableDatepicker( target ); - } - // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements - // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height - inst.dpDiv.css( "display", "block" ); - }, - - /* Pop-up the date picker in a "dialog" box. - * @param input element - ignored - * @param date string or Date - the initial date to display - * @param onSelect function - the function to call when a date is selected - * @param settings object - update the dialog date picker instance's settings (anonymous object) - * @param pos int[2] - coordinates for the dialog's position within the screen or - * event - with x/y coordinates or - * leave empty for default (screen centre) - * @return the manager object - */ - _dialogDatepicker: function(input, date, onSelect, settings, pos) { - var id, browserWidth, browserHeight, scrollX, scrollY, - inst = this._dialogInst; // internal instance - - if (!inst) { - this.uuid += 1; - id = "dp" + this.uuid; - this._dialogInput = $(""); - this._dialogInput.keydown(this._doKeyDown); - $("body").append(this._dialogInput); - inst = this._dialogInst = this._newInst(this._dialogInput, false); - inst.settings = {}; - $.data(this._dialogInput[0], PROP_NAME, inst); - } - extendRemove(inst.settings, settings || {}); - date = (date && date.constructor === Date ? this._formatDate(inst, date) : date); - this._dialogInput.val(date); - - this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); - if (!this._pos) { - browserWidth = document.documentElement.clientWidth; - browserHeight = document.documentElement.clientHeight; - scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; - scrollY = document.documentElement.scrollTop || document.body.scrollTop; - this._pos = // should use actual width/height below - [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; - } - - // move input on screen for focus, but hidden behind dialog - this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px"); - inst.settings.onSelect = onSelect; - this._inDialog = true; - this.dpDiv.addClass(this._dialogClass); - this._showDatepicker(this._dialogInput[0]); - if ($.blockUI) { - $.blockUI(this.dpDiv); - } - $.data(this._dialogInput[0], PROP_NAME, inst); - return this; - }, - - /* Detach a datepicker from its control. - * @param target element - the target input field or division or span - */ - _destroyDatepicker: function(target) { - var nodeName, - $target = $(target), - inst = $.data(target, PROP_NAME); - - if (!$target.hasClass(this.markerClassName)) { - return; - } - - nodeName = target.nodeName.toLowerCase(); - $.removeData(target, PROP_NAME); - if (nodeName === "input") { - inst.append.remove(); - inst.trigger.remove(); - $target.removeClass(this.markerClassName). - unbind("focus", this._showDatepicker). - unbind("keydown", this._doKeyDown). - unbind("keypress", this._doKeyPress). - unbind("keyup", this._doKeyUp); - } else if (nodeName === "div" || nodeName === "span") { - $target.removeClass(this.markerClassName).empty(); - } - }, - - /* Enable the date picker to a jQuery selection. - * @param target element - the target input field or division or span - */ - _enableDatepicker: function(target) { - var nodeName, inline, - $target = $(target), - inst = $.data(target, PROP_NAME); - - if (!$target.hasClass(this.markerClassName)) { - return; - } - - nodeName = target.nodeName.toLowerCase(); - if (nodeName === "input") { - target.disabled = false; - inst.trigger.filter("button"). - each(function() { this.disabled = false; }).end(). - filter("img").css({opacity: "1.0", cursor: ""}); - } else if (nodeName === "div" || nodeName === "span") { - inline = $target.children("." + this._inlineClass); - inline.children().removeClass("ui-state-disabled"); - inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). - prop("disabled", false); - } - this._disabledInputs = $.map(this._disabledInputs, - function(value) { return (value === target ? null : value); }); // delete entry - }, - - /* Disable the date picker to a jQuery selection. - * @param target element - the target input field or division or span - */ - _disableDatepicker: function(target) { - var nodeName, inline, - $target = $(target), - inst = $.data(target, PROP_NAME); - - if (!$target.hasClass(this.markerClassName)) { - return; - } - - nodeName = target.nodeName.toLowerCase(); - if (nodeName === "input") { - target.disabled = true; - inst.trigger.filter("button"). - each(function() { this.disabled = true; }).end(). - filter("img").css({opacity: "0.5", cursor: "default"}); - } else if (nodeName === "div" || nodeName === "span") { - inline = $target.children("." + this._inlineClass); - inline.children().addClass("ui-state-disabled"); - inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). - prop("disabled", true); - } - this._disabledInputs = $.map(this._disabledInputs, - function(value) { return (value === target ? null : value); }); // delete entry - this._disabledInputs[this._disabledInputs.length] = target; - }, - - /* Is the first field in a jQuery collection disabled as a datepicker? - * @param target element - the target input field or division or span - * @return boolean - true if disabled, false if enabled - */ - _isDisabledDatepicker: function(target) { - if (!target) { - return false; - } - for (var i = 0; i < this._disabledInputs.length; i++) { - if (this._disabledInputs[i] === target) { - return true; - } - } - return false; - }, - - /* Retrieve the instance data for the target control. - * @param target element - the target input field or division or span - * @return object - the associated instance data - * @throws error if a jQuery problem getting data - */ - _getInst: function(target) { - try { - return $.data(target, PROP_NAME); - } - catch (err) { - throw "Missing instance data for this datepicker"; - } - }, - - /* Update or retrieve the settings for a date picker attached to an input field or division. - * @param target element - the target input field or division or span - * @param name object - the new settings to update or - * string - the name of the setting to change or retrieve, - * when retrieving also "all" for all instance settings or - * "defaults" for all global defaults - * @param value any - the new value for the setting - * (omit if above is an object or to retrieve a value) - */ - _optionDatepicker: function(target, name, value) { - var settings, date, minDate, maxDate, - inst = this._getInst(target); - - if (arguments.length === 2 && typeof name === "string") { - return (name === "defaults" ? $.extend({}, $.datepicker._defaults) : - (inst ? (name === "all" ? $.extend({}, inst.settings) : - this._get(inst, name)) : null)); - } - - settings = name || {}; - if (typeof name === "string") { - settings = {}; - settings[name] = value; - } - - if (inst) { - if (this._curInst === inst) { - this._hideDatepicker(); - } - - date = this._getDateDatepicker(target, true); - minDate = this._getMinMaxDate(inst, "min"); - maxDate = this._getMinMaxDate(inst, "max"); - extendRemove(inst.settings, settings); - // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided - if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) { - inst.settings.minDate = this._formatDate(inst, minDate); - } - if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) { - inst.settings.maxDate = this._formatDate(inst, maxDate); - } - if ( "disabled" in settings ) { - if ( settings.disabled ) { - this._disableDatepicker(target); - } else { - this._enableDatepicker(target); - } - } - this._attachments($(target), inst); - this._autoSize(inst); - this._setDate(inst, date); - this._updateAlternate(inst); - this._updateDatepicker(inst); - } - }, - - // change method deprecated - _changeDatepicker: function(target, name, value) { - this._optionDatepicker(target, name, value); - }, - - /* Redraw the date picker attached to an input field or division. - * @param target element - the target input field or division or span - */ - _refreshDatepicker: function(target) { - var inst = this._getInst(target); - if (inst) { - this._updateDatepicker(inst); - } - }, - - /* Set the dates for a jQuery selection. - * @param target element - the target input field or division or span - * @param date Date - the new date - */ - _setDateDatepicker: function(target, date) { - var inst = this._getInst(target); - if (inst) { - this._setDate(inst, date); - this._updateDatepicker(inst); - this._updateAlternate(inst); - } - }, - - /* Get the date(s) for the first entry in a jQuery selection. - * @param target element - the target input field or division or span - * @param noDefault boolean - true if no default date is to be used - * @return Date - the current date - */ - _getDateDatepicker: function(target, noDefault) { - var inst = this._getInst(target); - if (inst && !inst.inline) { - this._setDateFromField(inst, noDefault); - } - return (inst ? this._getDate(inst) : null); - }, - - /* Handle keystrokes. */ - _doKeyDown: function(event) { - var onSelect, dateStr, sel, - inst = $.datepicker._getInst(event.target), - handled = true, - isRTL = inst.dpDiv.is(".ui-datepicker-rtl"); - - inst._keyEvent = true; - if ($.datepicker._datepickerShowing) { - switch (event.keyCode) { - case 9: $.datepicker._hideDatepicker(); - handled = false; - break; // hide on tab out - case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." + - $.datepicker._currentClass + ")", inst.dpDiv); - if (sel[0]) { - $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); - } - - onSelect = $.datepicker._get(inst, "onSelect"); - if (onSelect) { - dateStr = $.datepicker._formatDate(inst); - - // trigger custom callback - onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); - } else { - $.datepicker._hideDatepicker(); - } - - return false; // don't submit the form - case 27: $.datepicker._hideDatepicker(); - break; // hide on escape - case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? - -$.datepicker._get(inst, "stepBigMonths") : - -$.datepicker._get(inst, "stepMonths")), "M"); - break; // previous month/year on page up/+ ctrl - case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? - +$.datepicker._get(inst, "stepBigMonths") : - +$.datepicker._get(inst, "stepMonths")), "M"); - break; // next month/year on page down/+ ctrl - case 35: if (event.ctrlKey || event.metaKey) { - $.datepicker._clearDate(event.target); - } - handled = event.ctrlKey || event.metaKey; - break; // clear on ctrl or command +end - case 36: if (event.ctrlKey || event.metaKey) { - $.datepicker._gotoToday(event.target); - } - handled = event.ctrlKey || event.metaKey; - break; // current on ctrl or command +home - case 37: if (event.ctrlKey || event.metaKey) { - $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D"); - } - handled = event.ctrlKey || event.metaKey; - // -1 day on ctrl or command +left - if (event.originalEvent.altKey) { - $.datepicker._adjustDate(event.target, (event.ctrlKey ? - -$.datepicker._get(inst, "stepBigMonths") : - -$.datepicker._get(inst, "stepMonths")), "M"); - } - // next month/year on alt +left on Mac - break; - case 38: if (event.ctrlKey || event.metaKey) { - $.datepicker._adjustDate(event.target, -7, "D"); - } - handled = event.ctrlKey || event.metaKey; - break; // -1 week on ctrl or command +up - case 39: if (event.ctrlKey || event.metaKey) { - $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D"); - } - handled = event.ctrlKey || event.metaKey; - // +1 day on ctrl or command +right - if (event.originalEvent.altKey) { - $.datepicker._adjustDate(event.target, (event.ctrlKey ? - +$.datepicker._get(inst, "stepBigMonths") : - +$.datepicker._get(inst, "stepMonths")), "M"); - } - // next month/year on alt +right - break; - case 40: if (event.ctrlKey || event.metaKey) { - $.datepicker._adjustDate(event.target, +7, "D"); - } - handled = event.ctrlKey || event.metaKey; - break; // +1 week on ctrl or command +down - default: handled = false; - } - } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home - $.datepicker._showDatepicker(this); - } else { - handled = false; - } - - if (handled) { - event.preventDefault(); - event.stopPropagation(); - } - }, - - /* Filter entered characters - based on date format. */ - _doKeyPress: function(event) { - var chars, chr, - inst = $.datepicker._getInst(event.target); - - if ($.datepicker._get(inst, "constrainInput")) { - chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat")); - chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode); - return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1); - } - }, - - /* Synchronise manual entry and field/alternate field. */ - _doKeyUp: function(event) { - var date, - inst = $.datepicker._getInst(event.target); - - if (inst.input.val() !== inst.lastVal) { - try { - date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), - (inst.input ? inst.input.val() : null), - $.datepicker._getFormatConfig(inst)); - - if (date) { // only if valid - $.datepicker._setDateFromField(inst); - $.datepicker._updateAlternate(inst); - $.datepicker._updateDatepicker(inst); - } - } - catch (err) { - } - } - return true; - }, - - /* Pop-up the date picker for a given input field. - * If false returned from beforeShow event handler do not show. - * @param input element - the input field attached to the date picker or - * event - if triggered by focus - */ - _showDatepicker: function(input) { - input = input.target || input; - if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger - input = $("input", input.parentNode)[0]; - } - - if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here - return; - } - - var inst, beforeShow, beforeShowSettings, isFixed, - offset, showAnim, duration; - - inst = $.datepicker._getInst(input); - if ($.datepicker._curInst && $.datepicker._curInst !== inst) { - $.datepicker._curInst.dpDiv.stop(true, true); - if ( inst && $.datepicker._datepickerShowing ) { - $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] ); - } - } - - beforeShow = $.datepicker._get(inst, "beforeShow"); - beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; - if(beforeShowSettings === false){ - return; - } - extendRemove(inst.settings, beforeShowSettings); - - inst.lastVal = null; - $.datepicker._lastInput = input; - $.datepicker._setDateFromField(inst); - - if ($.datepicker._inDialog) { // hide cursor - input.value = ""; - } - if (!$.datepicker._pos) { // position below input - $.datepicker._pos = $.datepicker._findPos(input); - $.datepicker._pos[1] += input.offsetHeight; // add the height - } - - isFixed = false; - $(input).parents().each(function() { - isFixed |= $(this).css("position") === "fixed"; - return !isFixed; - }); - - offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; - $.datepicker._pos = null; - //to avoid flashes on Firefox - inst.dpDiv.empty(); - // determine sizing offscreen - inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"}); - $.datepicker._updateDatepicker(inst); - // fix width for dynamic number of date pickers - // and adjust position before showing - offset = $.datepicker._checkOffset(inst, offset, isFixed); - inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? - "static" : (isFixed ? "fixed" : "absolute")), display: "none", - left: offset.left + "px", top: offset.top + "px"}); - - if (!inst.inline) { - showAnim = $.datepicker._get(inst, "showAnim"); - duration = $.datepicker._get(inst, "duration"); - inst.dpDiv.zIndex($(input).zIndex()+1); - $.datepicker._datepickerShowing = true; - - if ( $.effects && $.effects.effect[ showAnim ] ) { - inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration); - } else { - inst.dpDiv[showAnim || "show"](showAnim ? duration : null); - } - - if ( $.datepicker._shouldFocusInput( inst ) ) { - inst.input.focus(); - } - - $.datepicker._curInst = inst; - } - }, - - /* Generate the date picker content. */ - _updateDatepicker: function(inst) { - this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) - instActive = inst; // for delegate hover events - inst.dpDiv.empty().append(this._generateHTML(inst)); - this._attachHandlers(inst); - inst.dpDiv.find("." + this._dayOverClass + " a").mouseover(); - - var origyearshtml, - numMonths = this._getNumberOfMonths(inst), - cols = numMonths[1], - width = 17; - - inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""); - if (cols > 1) { - inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em"); - } - inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") + - "Class"]("ui-datepicker-multi"); - inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") + - "Class"]("ui-datepicker-rtl"); - - if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) { - inst.input.focus(); - } - - // deffered render of the years select (to avoid flashes on Firefox) - if( inst.yearshtml ){ - origyearshtml = inst.yearshtml; - setTimeout(function(){ - //assure that inst.yearshtml didn't change. - if( origyearshtml === inst.yearshtml && inst.yearshtml ){ - inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml); - } - origyearshtml = inst.yearshtml = null; - }, 0); - } - }, - - // #6694 - don't focus the input if it's already focused - // this breaks the change event in IE - // Support: IE and jQuery <1.9 - _shouldFocusInput: function( inst ) { - return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" ); - }, - - /* Check positioning to remain on screen. */ - _checkOffset: function(inst, offset, isFixed) { - var dpWidth = inst.dpDiv.outerWidth(), - dpHeight = inst.dpDiv.outerHeight(), - inputWidth = inst.input ? inst.input.outerWidth() : 0, - inputHeight = inst.input ? inst.input.outerHeight() : 0, - viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()), - viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop()); - - offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0); - offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0; - offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; - - // now check if datepicker is showing outside window viewport - move to a better place if so. - offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? - Math.abs(offset.left + dpWidth - viewWidth) : 0); - offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? - Math.abs(dpHeight + inputHeight) : 0); - - return offset; - }, - - /* Find an object's position on the screen. */ - _findPos: function(obj) { - var position, - inst = this._getInst(obj), - isRTL = this._get(inst, "isRTL"); - - while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) { - obj = obj[isRTL ? "previousSibling" : "nextSibling"]; - } - - position = $(obj).offset(); - return [position.left, position.top]; - }, - - /* Hide the date picker from view. - * @param input element - the input field attached to the date picker - */ - _hideDatepicker: function(input) { - var showAnim, duration, postProcess, onClose, - inst = this._curInst; - - if (!inst || (input && inst !== $.data(input, PROP_NAME))) { - return; - } - - if (this._datepickerShowing) { - showAnim = this._get(inst, "showAnim"); - duration = this._get(inst, "duration"); - postProcess = function() { - $.datepicker._tidyDialog(inst); - }; - - // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed - if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) { - inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess); - } else { - inst.dpDiv[(showAnim === "slideDown" ? "slideUp" : - (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess); - } - - if (!showAnim) { - postProcess(); - } - this._datepickerShowing = false; - - onClose = this._get(inst, "onClose"); - if (onClose) { - onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]); - } - - this._lastInput = null; - if (this._inDialog) { - this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" }); - if ($.blockUI) { - $.unblockUI(); - $("body").append(this.dpDiv); - } - } - this._inDialog = false; - } - }, - - /* Tidy up after a dialog display. */ - _tidyDialog: function(inst) { - inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar"); - }, - - /* Close date picker if clicked elsewhere. */ - _checkExternalClick: function(event) { - if (!$.datepicker._curInst) { - return; - } - - var $target = $(event.target), - inst = $.datepicker._getInst($target[0]); - - if ( ( ( $target[0].id !== $.datepicker._mainDivId && - $target.parents("#" + $.datepicker._mainDivId).length === 0 && - !$target.hasClass($.datepicker.markerClassName) && - !$target.closest("." + $.datepicker._triggerClass).length && - $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) || - ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) { - $.datepicker._hideDatepicker(); - } - }, - - /* Adjust one of the date sub-fields. */ - _adjustDate: function(id, offset, period) { - var target = $(id), - inst = this._getInst(target[0]); - - if (this._isDisabledDatepicker(target[0])) { - return; - } - this._adjustInstDate(inst, offset + - (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning - period); - this._updateDatepicker(inst); - }, - - /* Action for current link. */ - _gotoToday: function(id) { - var date, - target = $(id), - inst = this._getInst(target[0]); - - if (this._get(inst, "gotoCurrent") && inst.currentDay) { - inst.selectedDay = inst.currentDay; - inst.drawMonth = inst.selectedMonth = inst.currentMonth; - inst.drawYear = inst.selectedYear = inst.currentYear; - } else { - date = new Date(); - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - } - this._notifyChange(inst); - this._adjustDate(target); - }, - - /* Action for selecting a new month/year. */ - _selectMonthYear: function(id, select, period) { - var target = $(id), - inst = this._getInst(target[0]); - - inst["selected" + (period === "M" ? "Month" : "Year")] = - inst["draw" + (period === "M" ? "Month" : "Year")] = - parseInt(select.options[select.selectedIndex].value,10); - - this._notifyChange(inst); - this._adjustDate(target); - }, - - /* Action for selecting a day. */ - _selectDay: function(id, month, year, td) { - var inst, - target = $(id); - - if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { - return; - } - - inst = this._getInst(target[0]); - inst.selectedDay = inst.currentDay = $("a", td).html(); - inst.selectedMonth = inst.currentMonth = month; - inst.selectedYear = inst.currentYear = year; - this._selectDate(id, this._formatDate(inst, - inst.currentDay, inst.currentMonth, inst.currentYear)); - }, - - /* Erase the input field and hide the date picker. */ - _clearDate: function(id) { - var target = $(id); - this._selectDate(target, ""); - }, - - /* Update the input field with the selected date. */ - _selectDate: function(id, dateStr) { - var onSelect, - target = $(id), - inst = this._getInst(target[0]); - - dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); - if (inst.input) { - inst.input.val(dateStr); - } - this._updateAlternate(inst); - - onSelect = this._get(inst, "onSelect"); - if (onSelect) { - onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback - } else if (inst.input) { - inst.input.trigger("change"); // fire the change event - } - - if (inst.inline){ - this._updateDatepicker(inst); - } else { - this._hideDatepicker(); - this._lastInput = inst.input[0]; - if (typeof(inst.input[0]) !== "object") { - inst.input.focus(); // restore focus - } - this._lastInput = null; - } - }, - - /* Update any alternate field to synchronise with the main field. */ - _updateAlternate: function(inst) { - var altFormat, date, dateStr, - altField = this._get(inst, "altField"); - - if (altField) { // update alternate field too - altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat"); - date = this._getDate(inst); - dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); - $(altField).each(function() { $(this).val(dateStr); }); - } - }, - - /* Set as beforeShowDay function to prevent selection of weekends. - * @param date Date - the date to customise - * @return [boolean, string] - is this date selectable?, what is its CSS class? - */ - noWeekends: function(date) { - var day = date.getDay(); - return [(day > 0 && day < 6), ""]; - }, - - /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. - * @param date Date - the date to get the week for - * @return number - the number of the week within the year that contains this date - */ - iso8601Week: function(date) { - var time, - checkDate = new Date(date.getTime()); - - // Find Thursday of this week starting on Monday - checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); - - time = checkDate.getTime(); - checkDate.setMonth(0); // Compare with Jan 1 - checkDate.setDate(1); - return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; - }, - - /* Parse a string value into a date object. - * See formatDate below for the possible formats. - * - * @param format string - the expected format of the date - * @param value string - the date in the above format - * @param settings Object - attributes include: - * shortYearCutoff number - the cutoff year for determining the century (optional) - * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) - * dayNames string[7] - names of the days from Sunday (optional) - * monthNamesShort string[12] - abbreviated names of the months (optional) - * monthNames string[12] - names of the months (optional) - * @return Date - the extracted date value or null if value is blank - */ - parseDate: function (format, value, settings) { - if (format == null || value == null) { - throw "Invalid arguments"; - } - - value = (typeof value === "object" ? value.toString() : value + ""); - if (value === "") { - return null; - } - - var iFormat, dim, extra, - iValue = 0, - shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff, - shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp : - new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)), - dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, - dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, - monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, - monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, - year = -1, - month = -1, - day = -1, - doy = -1, - literal = false, - date, - // Check whether a format character is doubled - lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); - if (matches) { - iFormat++; - } - return matches; - }, - // Extract a number from the string value - getNumber = function(match) { - var isDoubled = lookAhead(match), - size = (match === "@" ? 14 : (match === "!" ? 20 : - (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))), - digits = new RegExp("^\\d{1," + size + "}"), - num = value.substring(iValue).match(digits); - if (!num) { - throw "Missing number at position " + iValue; - } - iValue += num[0].length; - return parseInt(num[0], 10); - }, - // Extract a name from the string value and convert to an index - getName = function(match, shortNames, longNames) { - var index = -1, - names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { - return [ [k, v] ]; - }).sort(function (a, b) { - return -(a[1].length - b[1].length); - }); - - $.each(names, function (i, pair) { - var name = pair[1]; - if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) { - index = pair[0]; - iValue += name.length; - return false; - } - }); - if (index !== -1) { - return index + 1; - } else { - throw "Unknown name at position " + iValue; - } - }, - // Confirm that a literal character matches the string value - checkLiteral = function() { - if (value.charAt(iValue) !== format.charAt(iFormat)) { - throw "Unexpected literal at position " + iValue; - } - iValue++; - }; - - for (iFormat = 0; iFormat < format.length; iFormat++) { - if (literal) { - if (format.charAt(iFormat) === "'" && !lookAhead("'")) { - literal = false; - } else { - checkLiteral(); - } - } else { - switch (format.charAt(iFormat)) { - case "d": - day = getNumber("d"); - break; - case "D": - getName("D", dayNamesShort, dayNames); - break; - case "o": - doy = getNumber("o"); - break; - case "m": - month = getNumber("m"); - break; - case "M": - month = getName("M", monthNamesShort, monthNames); - break; - case "y": - year = getNumber("y"); - break; - case "@": - date = new Date(getNumber("@")); - year = date.getFullYear(); - month = date.getMonth() + 1; - day = date.getDate(); - break; - case "!": - date = new Date((getNumber("!") - this._ticksTo1970) / 10000); - year = date.getFullYear(); - month = date.getMonth() + 1; - day = date.getDate(); - break; - case "'": - if (lookAhead("'")){ - checkLiteral(); - } else { - literal = true; - } - break; - default: - checkLiteral(); - } - } - } - - if (iValue < value.length){ - extra = value.substr(iValue); - if (!/^\s+/.test(extra)) { - throw "Extra/unparsed characters found in date: " + extra; - } - } - - if (year === -1) { - year = new Date().getFullYear(); - } else if (year < 100) { - year += new Date().getFullYear() - new Date().getFullYear() % 100 + - (year <= shortYearCutoff ? 0 : -100); - } - - if (doy > -1) { - month = 1; - day = doy; - do { - dim = this._getDaysInMonth(year, month - 1); - if (day <= dim) { - break; - } - month++; - day -= dim; - } while (true); - } - - date = this._daylightSavingAdjust(new Date(year, month - 1, day)); - if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) { - throw "Invalid date"; // E.g. 31/02/00 - } - return date; - }, - - /* Standard date formats. */ - ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) - COOKIE: "D, dd M yy", - ISO_8601: "yy-mm-dd", - RFC_822: "D, d M y", - RFC_850: "DD, dd-M-y", - RFC_1036: "D, d M y", - RFC_1123: "D, d M yy", - RFC_2822: "D, d M yy", - RSS: "D, d M y", // RFC 822 - TICKS: "!", - TIMESTAMP: "@", - W3C: "yy-mm-dd", // ISO 8601 - - _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + - Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), - - /* Format a date object into a string value. - * The format can be combinations of the following: - * d - day of month (no leading zero) - * dd - day of month (two digit) - * o - day of year (no leading zeros) - * oo - day of year (three digit) - * D - day name short - * DD - day name long - * m - month of year (no leading zero) - * mm - month of year (two digit) - * M - month name short - * MM - month name long - * y - year (two digit) - * yy - year (four digit) - * @ - Unix timestamp (ms since 01/01/1970) - * ! - Windows ticks (100ns since 01/01/0001) - * "..." - literal text - * '' - single quote - * - * @param format string - the desired format of the date - * @param date Date - the date value to format - * @param settings Object - attributes include: - * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) - * dayNames string[7] - names of the days from Sunday (optional) - * monthNamesShort string[12] - abbreviated names of the months (optional) - * monthNames string[12] - names of the months (optional) - * @return string - the date in the above format - */ - formatDate: function (format, date, settings) { - if (!date) { - return ""; - } - - var iFormat, - dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, - dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, - monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, - monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, - // Check whether a format character is doubled - lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); - if (matches) { - iFormat++; - } - return matches; - }, - // Format a number, with leading zero if necessary - formatNumber = function(match, value, len) { - var num = "" + value; - if (lookAhead(match)) { - while (num.length < len) { - num = "0" + num; - } - } - return num; - }, - // Format a name, short or long as requested - formatName = function(match, value, shortNames, longNames) { - return (lookAhead(match) ? longNames[value] : shortNames[value]); - }, - output = "", - literal = false; - - if (date) { - for (iFormat = 0; iFormat < format.length; iFormat++) { - if (literal) { - if (format.charAt(iFormat) === "'" && !lookAhead("'")) { - literal = false; - } else { - output += format.charAt(iFormat); - } - } else { - switch (format.charAt(iFormat)) { - case "d": - output += formatNumber("d", date.getDate(), 2); - break; - case "D": - output += formatName("D", date.getDay(), dayNamesShort, dayNames); - break; - case "o": - output += formatNumber("o", - Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); - break; - case "m": - output += formatNumber("m", date.getMonth() + 1, 2); - break; - case "M": - output += formatName("M", date.getMonth(), monthNamesShort, monthNames); - break; - case "y": - output += (lookAhead("y") ? date.getFullYear() : - (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100); - break; - case "@": - output += date.getTime(); - break; - case "!": - output += date.getTime() * 10000 + this._ticksTo1970; - break; - case "'": - if (lookAhead("'")) { - output += "'"; - } else { - literal = true; - } - break; - default: - output += format.charAt(iFormat); - } - } - } - } - return output; - }, - - /* Extract all possible characters from the date format. */ - _possibleChars: function (format) { - var iFormat, - chars = "", - literal = false, - // Check whether a format character is doubled - lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); - if (matches) { - iFormat++; - } - return matches; - }; - - for (iFormat = 0; iFormat < format.length; iFormat++) { - if (literal) { - if (format.charAt(iFormat) === "'" && !lookAhead("'")) { - literal = false; - } else { - chars += format.charAt(iFormat); - } - } else { - switch (format.charAt(iFormat)) { - case "d": case "m": case "y": case "@": - chars += "0123456789"; - break; - case "D": case "M": - return null; // Accept anything - case "'": - if (lookAhead("'")) { - chars += "'"; - } else { - literal = true; - } - break; - default: - chars += format.charAt(iFormat); - } - } - } - return chars; - }, - - /* Get a setting value, defaulting if necessary. */ - _get: function(inst, name) { - return inst.settings[name] !== undefined ? - inst.settings[name] : this._defaults[name]; - }, - - /* Parse existing date and initialise date picker. */ - _setDateFromField: function(inst, noDefault) { - if (inst.input.val() === inst.lastVal) { - return; - } - - var dateFormat = this._get(inst, "dateFormat"), - dates = inst.lastVal = inst.input ? inst.input.val() : null, - defaultDate = this._getDefaultDate(inst), - date = defaultDate, - settings = this._getFormatConfig(inst); - - try { - date = this.parseDate(dateFormat, dates, settings) || defaultDate; - } catch (event) { - dates = (noDefault ? "" : dates); - } - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - inst.currentDay = (dates ? date.getDate() : 0); - inst.currentMonth = (dates ? date.getMonth() : 0); - inst.currentYear = (dates ? date.getFullYear() : 0); - this._adjustInstDate(inst); - }, - - /* Retrieve the default date shown on opening. */ - _getDefaultDate: function(inst) { - return this._restrictMinMax(inst, - this._determineDate(inst, this._get(inst, "defaultDate"), new Date())); - }, - - /* A date may be specified as an exact value or a relative one. */ - _determineDate: function(inst, date, defaultDate) { - var offsetNumeric = function(offset) { - var date = new Date(); - date.setDate(date.getDate() + offset); - return date; - }, - offsetString = function(offset) { - try { - return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), - offset, $.datepicker._getFormatConfig(inst)); - } - catch (e) { - // Ignore - } - - var date = (offset.toLowerCase().match(/^c/) ? - $.datepicker._getDate(inst) : null) || new Date(), - year = date.getFullYear(), - month = date.getMonth(), - day = date.getDate(), - pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, - matches = pattern.exec(offset); - - while (matches) { - switch (matches[2] || "d") { - case "d" : case "D" : - day += parseInt(matches[1],10); break; - case "w" : case "W" : - day += parseInt(matches[1],10) * 7; break; - case "m" : case "M" : - month += parseInt(matches[1],10); - day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); - break; - case "y": case "Y" : - year += parseInt(matches[1],10); - day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); - break; - } - matches = pattern.exec(offset); - } - return new Date(year, month, day); - }, - newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) : - (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); - - newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate); - if (newDate) { - newDate.setHours(0); - newDate.setMinutes(0); - newDate.setSeconds(0); - newDate.setMilliseconds(0); - } - return this._daylightSavingAdjust(newDate); - }, - - /* Handle switch to/from daylight saving. - * Hours may be non-zero on daylight saving cut-over: - * > 12 when midnight changeover, but then cannot generate - * midnight datetime, so jump to 1AM, otherwise reset. - * @param date (Date) the date to check - * @return (Date) the corrected date - */ - _daylightSavingAdjust: function(date) { - if (!date) { - return null; - } - date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); - return date; - }, - - /* Set the date(s) directly. */ - _setDate: function(inst, date, noChange) { - var clear = !date, - origMonth = inst.selectedMonth, - origYear = inst.selectedYear, - newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); - - inst.selectedDay = inst.currentDay = newDate.getDate(); - inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); - inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); - if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) { - this._notifyChange(inst); - } - this._adjustInstDate(inst); - if (inst.input) { - inst.input.val(clear ? "" : this._formatDate(inst)); - } - }, - - /* Retrieve the date(s) directly. */ - _getDate: function(inst) { - var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null : - this._daylightSavingAdjust(new Date( - inst.currentYear, inst.currentMonth, inst.currentDay))); - return startDate; - }, - - /* Attach the onxxx handlers. These are declared statically so - * they work with static code transformers like Caja. - */ - _attachHandlers: function(inst) { - var stepMonths = this._get(inst, "stepMonths"), - id = "#" + inst.id.replace( /\\\\/g, "\\" ); - inst.dpDiv.find("[data-handler]").map(function () { - var handler = { - prev: function () { - $.datepicker._adjustDate(id, -stepMonths, "M"); - }, - next: function () { - $.datepicker._adjustDate(id, +stepMonths, "M"); - }, - hide: function () { - $.datepicker._hideDatepicker(); - }, - today: function () { - $.datepicker._gotoToday(id); - }, - selectDay: function () { - $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this); - return false; - }, - selectMonth: function () { - $.datepicker._selectMonthYear(id, this, "M"); - return false; - }, - selectYear: function () { - $.datepicker._selectMonthYear(id, this, "Y"); - return false; - } - }; - $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]); - }); - }, - - /* Generate the HTML for the current state of the date picker. */ - _generateHTML: function(inst) { - var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, - controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, - monthNames, monthNamesShort, beforeShowDay, showOtherMonths, - selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, - cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, - printDate, dRow, tbody, daySettings, otherMonth, unselectable, - tempDate = new Date(), - today = this._daylightSavingAdjust( - new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time - isRTL = this._get(inst, "isRTL"), - showButtonPanel = this._get(inst, "showButtonPanel"), - hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"), - navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"), - numMonths = this._getNumberOfMonths(inst), - showCurrentAtPos = this._get(inst, "showCurrentAtPos"), - stepMonths = this._get(inst, "stepMonths"), - isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1), - currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : - new Date(inst.currentYear, inst.currentMonth, inst.currentDay))), - minDate = this._getMinMaxDate(inst, "min"), - maxDate = this._getMinMaxDate(inst, "max"), - drawMonth = inst.drawMonth - showCurrentAtPos, - drawYear = inst.drawYear; - - if (drawMonth < 0) { - drawMonth += 12; - drawYear--; - } - if (maxDate) { - maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), - maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); - maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); - while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { - drawMonth--; - if (drawMonth < 0) { - drawMonth = 11; - drawYear--; - } - } - } - inst.drawMonth = drawMonth; - inst.drawYear = drawYear; - - prevText = this._get(inst, "prevText"); - prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, - this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), - this._getFormatConfig(inst))); - - prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? - "" + prevText + "" : - (hideIfNoPrevNext ? "" : "" + prevText + "")); - - nextText = this._get(inst, "nextText"); - nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, - this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), - this._getFormatConfig(inst))); - - next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? - "" + nextText + "" : - (hideIfNoPrevNext ? "" : "" + nextText + "")); - - currentText = this._get(inst, "currentText"); - gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today); - currentText = (!navigationAsDateFormat ? currentText : - this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); - - controls = (!inst.inline ? "" : ""); - - buttonPanel = (showButtonPanel) ? "
      " + (isRTL ? controls : "") + - (this._isInRange(inst, gotoDate) ? "" : "") + (isRTL ? "" : controls) + "
      " : ""; - - firstDay = parseInt(this._get(inst, "firstDay"),10); - firstDay = (isNaN(firstDay) ? 0 : firstDay); - - showWeek = this._get(inst, "showWeek"); - dayNames = this._get(inst, "dayNames"); - dayNamesMin = this._get(inst, "dayNamesMin"); - monthNames = this._get(inst, "monthNames"); - monthNamesShort = this._get(inst, "monthNamesShort"); - beforeShowDay = this._get(inst, "beforeShowDay"); - showOtherMonths = this._get(inst, "showOtherMonths"); - selectOtherMonths = this._get(inst, "selectOtherMonths"); - defaultDate = this._getDefaultDate(inst); - html = ""; - dow; - for (row = 0; row < numMonths[0]; row++) { - group = ""; - this.maxRows = 4; - for (col = 0; col < numMonths[1]; col++) { - selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); - cornerClass = " ui-corner-all"; - calender = ""; - if (isMultiMonth) { - calender += "
      "; - } - calender += "
      " + - (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") + - (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") + - this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, - row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers - "
      " + - ""; - thead = (showWeek ? "" : ""); - for (dow = 0; dow < 7; dow++) { // days of the week - day = (dow + firstDay) % 7; - thead += "= 5 ? " class='ui-datepicker-week-end'" : "") + ">" + - "" + dayNamesMin[day] + ""; - } - calender += thead + ""; - daysInMonth = this._getDaysInMonth(drawYear, drawMonth); - if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) { - inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); - } - leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; - curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate - numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) - this.maxRows = numRows; - printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); - for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows - calender += ""; - tbody = (!showWeek ? "" : ""); - for (dow = 0; dow < 7; dow++) { // create date picker days - daySettings = (beforeShowDay ? - beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]); - otherMonth = (printDate.getMonth() !== drawMonth); - unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || - (minDate && printDate < minDate) || (maxDate && printDate > maxDate); - tbody += ""; // display selectable date - printDate.setDate(printDate.getDate() + 1); - printDate = this._daylightSavingAdjust(printDate); - } - calender += tbody + ""; - } - drawMonth++; - if (drawMonth > 11) { - drawMonth = 0; - drawYear++; - } - calender += "
      " + this._get(inst, "weekHeader") + "
      " + - this._get(inst, "calculateWeek")(printDate) + "" + // actions - (otherMonth && !showOtherMonths ? " " : // display for other months - (unselectable ? "" + printDate.getDate() + "" : "" + printDate.getDate() + "")) + "
      " + (isMultiMonth ? "
      " + - ((numMonths[0] > 0 && col === numMonths[1]-1) ? "
      " : "") : ""); - group += calender; - } - html += group; - } - html += buttonPanel; - inst._keyEvent = false; - return html; - }, - - /* Generate the month and year header. */ - _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, - secondary, monthNames, monthNamesShort) { - - var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, - changeMonth = this._get(inst, "changeMonth"), - changeYear = this._get(inst, "changeYear"), - showMonthAfterYear = this._get(inst, "showMonthAfterYear"), - html = "
      ", - monthHtml = ""; - - // month selection - if (secondary || !changeMonth) { - monthHtml += "" + monthNames[drawMonth] + ""; - } else { - inMinYear = (minDate && minDate.getFullYear() === drawYear); - inMaxYear = (maxDate && maxDate.getFullYear() === drawYear); - monthHtml += ""; - } - - if (!showMonthAfterYear) { - html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : ""); - } - - // year selection - if ( !inst.yearshtml ) { - inst.yearshtml = ""; - if (secondary || !changeYear) { - html += "" + drawYear + ""; - } else { - // determine range of years to display - years = this._get(inst, "yearRange").split(":"); - thisYear = new Date().getFullYear(); - determineYear = function(value) { - var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) : - (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) : - parseInt(value, 10))); - return (isNaN(year) ? thisYear : year); - }; - year = determineYear(years[0]); - endYear = Math.max(year, determineYear(years[1] || "")); - year = (minDate ? Math.max(year, minDate.getFullYear()) : year); - endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); - inst.yearshtml += ""; - - html += inst.yearshtml; - inst.yearshtml = null; - } - } - - html += this._get(inst, "yearSuffix"); - if (showMonthAfterYear) { - html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml; - } - html += "
      "; // Close datepicker_header - return html; - }, - - /* Adjust one of the date sub-fields. */ - _adjustInstDate: function(inst, offset, period) { - var year = inst.drawYear + (period === "Y" ? offset : 0), - month = inst.drawMonth + (period === "M" ? offset : 0), - day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0), - date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day))); - - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - if (period === "M" || period === "Y") { - this._notifyChange(inst); - } - }, - - /* Ensure a date is within any min/max bounds. */ - _restrictMinMax: function(inst, date) { - var minDate = this._getMinMaxDate(inst, "min"), - maxDate = this._getMinMaxDate(inst, "max"), - newDate = (minDate && date < minDate ? minDate : date); - return (maxDate && newDate > maxDate ? maxDate : newDate); - }, - - /* Notify change of month/year. */ - _notifyChange: function(inst) { - var onChange = this._get(inst, "onChangeMonthYear"); - if (onChange) { - onChange.apply((inst.input ? inst.input[0] : null), - [inst.selectedYear, inst.selectedMonth + 1, inst]); - } - }, - - /* Determine the number of months to show. */ - _getNumberOfMonths: function(inst) { - var numMonths = this._get(inst, "numberOfMonths"); - return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths)); - }, - - /* Determine the current maximum date - ensure no time components are set. */ - _getMinMaxDate: function(inst, minMax) { - return this._determineDate(inst, this._get(inst, minMax + "Date"), null); - }, - - /* Find the number of days in a given month. */ - _getDaysInMonth: function(year, month) { - return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); - }, - - /* Find the day of the week of the first of a month. */ - _getFirstDayOfMonth: function(year, month) { - return new Date(year, month, 1).getDay(); - }, - - /* Determines if we should allow a "next/prev" month display change. */ - _canAdjustMonth: function(inst, offset, curYear, curMonth) { - var numMonths = this._getNumberOfMonths(inst), - date = this._daylightSavingAdjust(new Date(curYear, - curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); - - if (offset < 0) { - date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); - } - return this._isInRange(inst, date); - }, - - /* Is the given date in the accepted range? */ - _isInRange: function(inst, date) { - var yearSplit, currentYear, - minDate = this._getMinMaxDate(inst, "min"), - maxDate = this._getMinMaxDate(inst, "max"), - minYear = null, - maxYear = null, - years = this._get(inst, "yearRange"); - if (years){ - yearSplit = years.split(":"); - currentYear = new Date().getFullYear(); - minYear = parseInt(yearSplit[0], 10); - maxYear = parseInt(yearSplit[1], 10); - if ( yearSplit[0].match(/[+\-].*/) ) { - minYear += currentYear; - } - if ( yearSplit[1].match(/[+\-].*/) ) { - maxYear += currentYear; - } - } - - return ((!minDate || date.getTime() >= minDate.getTime()) && - (!maxDate || date.getTime() <= maxDate.getTime()) && - (!minYear || date.getFullYear() >= minYear) && - (!maxYear || date.getFullYear() <= maxYear)); - }, - - /* Provide the configuration settings for formatting/parsing. */ - _getFormatConfig: function(inst) { - var shortYearCutoff = this._get(inst, "shortYearCutoff"); - shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff : - new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); - return {shortYearCutoff: shortYearCutoff, - dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"), - monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")}; - }, - - /* Format the given date for display. */ - _formatDate: function(inst, day, month, year) { - if (!day) { - inst.currentDay = inst.selectedDay; - inst.currentMonth = inst.selectedMonth; - inst.currentYear = inst.selectedYear; - } - var date = (day ? (typeof day === "object" ? day : - this._daylightSavingAdjust(new Date(year, month, day))) : - this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); - return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst)); - } -}); - -/* - * Bind hover events for datepicker elements. - * Done via delegate so the binding only occurs once in the lifetime of the parent div. - * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. - */ -function bindHover(dpDiv) { - var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; - return dpDiv.delegate(selector, "mouseout", function() { - $(this).removeClass("ui-state-hover"); - if (this.className.indexOf("ui-datepicker-prev") !== -1) { - $(this).removeClass("ui-datepicker-prev-hover"); - } - if (this.className.indexOf("ui-datepicker-next") !== -1) { - $(this).removeClass("ui-datepicker-next-hover"); - } - }) - .delegate(selector, "mouseover", function(){ - if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) { - $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); - $(this).addClass("ui-state-hover"); - if (this.className.indexOf("ui-datepicker-prev") !== -1) { - $(this).addClass("ui-datepicker-prev-hover"); - } - if (this.className.indexOf("ui-datepicker-next") !== -1) { - $(this).addClass("ui-datepicker-next-hover"); - } - } - }); -} - -/* jQuery extend now ignores nulls! */ -function extendRemove(target, props) { - $.extend(target, props); - for (var name in props) { - if (props[name] == null) { - target[name] = props[name]; - } - } - return target; -} - -/* Invoke the datepicker functionality. - @param options string - a command, optionally followed by additional parameters or - Object - settings for attaching new datepicker functionality - @return jQuery object */ -$.fn.datepicker = function(options){ - - /* Verify an empty collection wasn't passed - Fixes #6976 */ - if ( !this.length ) { - return this; - } - - /* Initialise the date picker. */ - if (!$.datepicker.initialized) { - $(document).mousedown($.datepicker._checkExternalClick); - $.datepicker.initialized = true; - } - - /* Append datepicker main container to body if not exist. */ - if ($("#"+$.datepicker._mainDivId).length === 0) { - $("body").append($.datepicker.dpDiv); - } - - var otherArgs = Array.prototype.slice.call(arguments, 1); - if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) { - return $.datepicker["_" + options + "Datepicker"]. - apply($.datepicker, [this[0]].concat(otherArgs)); - } - if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") { - return $.datepicker["_" + options + "Datepicker"]. - apply($.datepicker, [this[0]].concat(otherArgs)); - } - return this.each(function() { - typeof options === "string" ? - $.datepicker["_" + options + "Datepicker"]. - apply($.datepicker, [this].concat(otherArgs)) : - $.datepicker._attachDatepicker(this, options); - }); -}; - -$.datepicker = new Datepicker(); // singleton instance -$.datepicker.initialized = false; -$.datepicker.uuid = new Date().getTime(); -$.datepicker.version = "1.10.3"; - -})(jQuery); diff --git a/extensions/yii/jui/assets/jquery.ui.dialog.js b/extensions/yii/jui/assets/jquery.ui.dialog.js deleted file mode 100644 index 3a01e0c..0000000 --- a/extensions/yii/jui/assets/jquery.ui.dialog.js +++ /dev/null @@ -1,808 +0,0 @@ -/*! - * jQuery UI Dialog 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/dialog/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.button.js - * jquery.ui.draggable.js - * jquery.ui.mouse.js - * jquery.ui.position.js - * jquery.ui.resizable.js - */ -(function( $, undefined ) { - -var sizeRelatedOptions = { - buttons: true, - height: true, - maxHeight: true, - maxWidth: true, - minHeight: true, - minWidth: true, - width: true - }, - resizableRelatedOptions = { - maxHeight: true, - maxWidth: true, - minHeight: true, - minWidth: true - }; - -$.widget( "ui.dialog", { - version: "1.10.3", - options: { - appendTo: "body", - autoOpen: true, - buttons: [], - closeOnEscape: true, - closeText: "close", - dialogClass: "", - draggable: true, - hide: null, - height: "auto", - maxHeight: null, - maxWidth: null, - minHeight: 150, - minWidth: 150, - modal: false, - position: { - my: "center", - at: "center", - of: window, - collision: "fit", - // Ensure the titlebar is always visible - using: function( pos ) { - var topOffset = $( this ).css( pos ).offset().top; - if ( topOffset < 0 ) { - $( this ).css( "top", pos.top - topOffset ); - } - } - }, - resizable: true, - show: null, - title: null, - width: 300, - - // callbacks - beforeClose: null, - close: null, - drag: null, - dragStart: null, - dragStop: null, - focus: null, - open: null, - resize: null, - resizeStart: null, - resizeStop: null - }, - - _create: function() { - this.originalCss = { - display: this.element[0].style.display, - width: this.element[0].style.width, - minHeight: this.element[0].style.minHeight, - maxHeight: this.element[0].style.maxHeight, - height: this.element[0].style.height - }; - this.originalPosition = { - parent: this.element.parent(), - index: this.element.parent().children().index( this.element ) - }; - this.originalTitle = this.element.attr("title"); - this.options.title = this.options.title || this.originalTitle; - - this._createWrapper(); - - this.element - .show() - .removeAttr("title") - .addClass("ui-dialog-content ui-widget-content") - .appendTo( this.uiDialog ); - - this._createTitlebar(); - this._createButtonPane(); - - if ( this.options.draggable && $.fn.draggable ) { - this._makeDraggable(); - } - if ( this.options.resizable && $.fn.resizable ) { - this._makeResizable(); - } - - this._isOpen = false; - }, - - _init: function() { - if ( this.options.autoOpen ) { - this.open(); - } - }, - - _appendTo: function() { - var element = this.options.appendTo; - if ( element && (element.jquery || element.nodeType) ) { - return $( element ); - } - return this.document.find( element || "body" ).eq( 0 ); - }, - - _destroy: function() { - var next, - originalPosition = this.originalPosition; - - this._destroyOverlay(); - - this.element - .removeUniqueId() - .removeClass("ui-dialog-content ui-widget-content") - .css( this.originalCss ) - // Without detaching first, the following becomes really slow - .detach(); - - this.uiDialog.stop( true, true ).remove(); - - if ( this.originalTitle ) { - this.element.attr( "title", this.originalTitle ); - } - - next = originalPosition.parent.children().eq( originalPosition.index ); - // Don't try to place the dialog next to itself (#8613) - if ( next.length && next[0] !== this.element[0] ) { - next.before( this.element ); - } else { - originalPosition.parent.append( this.element ); - } - }, - - widget: function() { - return this.uiDialog; - }, - - disable: $.noop, - enable: $.noop, - - close: function( event ) { - var that = this; - - if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) { - return; - } - - this._isOpen = false; - this._destroyOverlay(); - - if ( !this.opener.filter(":focusable").focus().length ) { - // Hiding a focused element doesn't trigger blur in WebKit - // so in case we have nothing to focus on, explicitly blur the active element - // https://bugs.webkit.org/show_bug.cgi?id=47182 - $( this.document[0].activeElement ).blur(); - } - - this._hide( this.uiDialog, this.options.hide, function() { - that._trigger( "close", event ); - }); - }, - - isOpen: function() { - return this._isOpen; - }, - - moveToTop: function() { - this._moveToTop(); - }, - - _moveToTop: function( event, silent ) { - var moved = !!this.uiDialog.nextAll(":visible").insertBefore( this.uiDialog ).length; - if ( moved && !silent ) { - this._trigger( "focus", event ); - } - return moved; - }, - - open: function() { - var that = this; - if ( this._isOpen ) { - if ( this._moveToTop() ) { - this._focusTabbable(); - } - return; - } - - this._isOpen = true; - this.opener = $( this.document[0].activeElement ); - - this._size(); - this._position(); - this._createOverlay(); - this._moveToTop( null, true ); - this._show( this.uiDialog, this.options.show, function() { - that._focusTabbable(); - that._trigger("focus"); - }); - - this._trigger("open"); - }, - - _focusTabbable: function() { - // Set focus to the first match: - // 1. First element inside the dialog matching [autofocus] - // 2. Tabbable element inside the content element - // 3. Tabbable element inside the buttonpane - // 4. The close button - // 5. The dialog itself - var hasFocus = this.element.find("[autofocus]"); - if ( !hasFocus.length ) { - hasFocus = this.element.find(":tabbable"); - } - if ( !hasFocus.length ) { - hasFocus = this.uiDialogButtonPane.find(":tabbable"); - } - if ( !hasFocus.length ) { - hasFocus = this.uiDialogTitlebarClose.filter(":tabbable"); - } - if ( !hasFocus.length ) { - hasFocus = this.uiDialog; - } - hasFocus.eq( 0 ).focus(); - }, - - _keepFocus: function( event ) { - function checkFocus() { - var activeElement = this.document[0].activeElement, - isActive = this.uiDialog[0] === activeElement || - $.contains( this.uiDialog[0], activeElement ); - if ( !isActive ) { - this._focusTabbable(); - } - } - event.preventDefault(); - checkFocus.call( this ); - // support: IE - // IE <= 8 doesn't prevent moving focus even with event.preventDefault() - // so we check again later - this._delay( checkFocus ); - }, - - _createWrapper: function() { - this.uiDialog = $("
      ") - .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " + - this.options.dialogClass ) - .hide() - .attr({ - // Setting tabIndex makes the div focusable - tabIndex: -1, - role: "dialog" - }) - .appendTo( this._appendTo() ); - - this._on( this.uiDialog, { - keydown: function( event ) { - if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && - event.keyCode === $.ui.keyCode.ESCAPE ) { - event.preventDefault(); - this.close( event ); - return; - } - - // prevent tabbing out of dialogs - if ( event.keyCode !== $.ui.keyCode.TAB ) { - return; - } - var tabbables = this.uiDialog.find(":tabbable"), - first = tabbables.filter(":first"), - last = tabbables.filter(":last"); - - if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) { - first.focus( 1 ); - event.preventDefault(); - } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) { - last.focus( 1 ); - event.preventDefault(); - } - }, - mousedown: function( event ) { - if ( this._moveToTop( event ) ) { - this._focusTabbable(); - } - } - }); - - // We assume that any existing aria-describedby attribute means - // that the dialog content is marked up properly - // otherwise we brute force the content as the description - if ( !this.element.find("[aria-describedby]").length ) { - this.uiDialog.attr({ - "aria-describedby": this.element.uniqueId().attr("id") - }); - } - }, - - _createTitlebar: function() { - var uiDialogTitle; - - this.uiDialogTitlebar = $("
      ") - .addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix") - .prependTo( this.uiDialog ); - this._on( this.uiDialogTitlebar, { - mousedown: function( event ) { - // Don't prevent click on close button (#8838) - // Focusing a dialog that is partially scrolled out of view - // causes the browser to scroll it into view, preventing the click event - if ( !$( event.target ).closest(".ui-dialog-titlebar-close") ) { - // Dialog isn't getting focus when dragging (#8063) - this.uiDialog.focus(); - } - } - }); - - this.uiDialogTitlebarClose = $("") - .button({ - label: this.options.closeText, - icons: { - primary: "ui-icon-closethick" - }, - text: false - }) - .addClass("ui-dialog-titlebar-close") - .appendTo( this.uiDialogTitlebar ); - this._on( this.uiDialogTitlebarClose, { - click: function( event ) { - event.preventDefault(); - this.close( event ); - } - }); - - uiDialogTitle = $("") - .uniqueId() - .addClass("ui-dialog-title") - .prependTo( this.uiDialogTitlebar ); - this._title( uiDialogTitle ); - - this.uiDialog.attr({ - "aria-labelledby": uiDialogTitle.attr("id") - }); - }, - - _title: function( title ) { - if ( !this.options.title ) { - title.html(" "); - } - title.text( this.options.title ); - }, - - _createButtonPane: function() { - this.uiDialogButtonPane = $("
      ") - .addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"); - - this.uiButtonSet = $("
      ") - .addClass("ui-dialog-buttonset") - .appendTo( this.uiDialogButtonPane ); - - this._createButtons(); - }, - - _createButtons: function() { - var that = this, - buttons = this.options.buttons; - - // if we already have a button pane, remove it - this.uiDialogButtonPane.remove(); - this.uiButtonSet.empty(); - - if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) { - this.uiDialog.removeClass("ui-dialog-buttons"); - return; - } - - $.each( buttons, function( name, props ) { - var click, buttonOptions; - props = $.isFunction( props ) ? - { click: props, text: name } : - props; - // Default to a non-submitting button - props = $.extend( { type: "button" }, props ); - // Change the context for the click callback to be the main element - click = props.click; - props.click = function() { - click.apply( that.element[0], arguments ); - }; - buttonOptions = { - icons: props.icons, - text: props.showText - }; - delete props.icons; - delete props.showText; - $( "", props ) - .button( buttonOptions ) - .appendTo( that.uiButtonSet ); - }); - this.uiDialog.addClass("ui-dialog-buttons"); - this.uiDialogButtonPane.appendTo( this.uiDialog ); - }, - - _makeDraggable: function() { - var that = this, - options = this.options; - - function filteredUi( ui ) { - return { - position: ui.position, - offset: ui.offset - }; - } - - this.uiDialog.draggable({ - cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", - handle: ".ui-dialog-titlebar", - containment: "document", - start: function( event, ui ) { - $( this ).addClass("ui-dialog-dragging"); - that._blockFrames(); - that._trigger( "dragStart", event, filteredUi( ui ) ); - }, - drag: function( event, ui ) { - that._trigger( "drag", event, filteredUi( ui ) ); - }, - stop: function( event, ui ) { - options.position = [ - ui.position.left - that.document.scrollLeft(), - ui.position.top - that.document.scrollTop() - ]; - $( this ).removeClass("ui-dialog-dragging"); - that._unblockFrames(); - that._trigger( "dragStop", event, filteredUi( ui ) ); - } - }); - }, - - _makeResizable: function() { - var that = this, - options = this.options, - handles = options.resizable, - // .ui-resizable has position: relative defined in the stylesheet - // but dialogs have to use absolute or fixed positioning - position = this.uiDialog.css("position"), - resizeHandles = typeof handles === "string" ? - handles : - "n,e,s,w,se,sw,ne,nw"; - - function filteredUi( ui ) { - return { - originalPosition: ui.originalPosition, - originalSize: ui.originalSize, - position: ui.position, - size: ui.size - }; - } - - this.uiDialog.resizable({ - cancel: ".ui-dialog-content", - containment: "document", - alsoResize: this.element, - maxWidth: options.maxWidth, - maxHeight: options.maxHeight, - minWidth: options.minWidth, - minHeight: this._minHeight(), - handles: resizeHandles, - start: function( event, ui ) { - $( this ).addClass("ui-dialog-resizing"); - that._blockFrames(); - that._trigger( "resizeStart", event, filteredUi( ui ) ); - }, - resize: function( event, ui ) { - that._trigger( "resize", event, filteredUi( ui ) ); - }, - stop: function( event, ui ) { - options.height = $( this ).height(); - options.width = $( this ).width(); - $( this ).removeClass("ui-dialog-resizing"); - that._unblockFrames(); - that._trigger( "resizeStop", event, filteredUi( ui ) ); - } - }) - .css( "position", position ); - }, - - _minHeight: function() { - var options = this.options; - - return options.height === "auto" ? - options.minHeight : - Math.min( options.minHeight, options.height ); - }, - - _position: function() { - // Need to show the dialog to get the actual offset in the position plugin - var isVisible = this.uiDialog.is(":visible"); - if ( !isVisible ) { - this.uiDialog.show(); - } - this.uiDialog.position( this.options.position ); - if ( !isVisible ) { - this.uiDialog.hide(); - } - }, - - _setOptions: function( options ) { - var that = this, - resize = false, - resizableOptions = {}; - - $.each( options, function( key, value ) { - that._setOption( key, value ); - - if ( key in sizeRelatedOptions ) { - resize = true; - } - if ( key in resizableRelatedOptions ) { - resizableOptions[ key ] = value; - } - }); - - if ( resize ) { - this._size(); - this._position(); - } - if ( this.uiDialog.is(":data(ui-resizable)") ) { - this.uiDialog.resizable( "option", resizableOptions ); - } - }, - - _setOption: function( key, value ) { - /*jshint maxcomplexity:15*/ - var isDraggable, isResizable, - uiDialog = this.uiDialog; - - if ( key === "dialogClass" ) { - uiDialog - .removeClass( this.options.dialogClass ) - .addClass( value ); - } - - if ( key === "disabled" ) { - return; - } - - this._super( key, value ); - - if ( key === "appendTo" ) { - this.uiDialog.appendTo( this._appendTo() ); - } - - if ( key === "buttons" ) { - this._createButtons(); - } - - if ( key === "closeText" ) { - this.uiDialogTitlebarClose.button({ - // Ensure that we always pass a string - label: "" + value - }); - } - - if ( key === "draggable" ) { - isDraggable = uiDialog.is(":data(ui-draggable)"); - if ( isDraggable && !value ) { - uiDialog.draggable("destroy"); - } - - if ( !isDraggable && value ) { - this._makeDraggable(); - } - } - - if ( key === "position" ) { - this._position(); - } - - if ( key === "resizable" ) { - // currently resizable, becoming non-resizable - isResizable = uiDialog.is(":data(ui-resizable)"); - if ( isResizable && !value ) { - uiDialog.resizable("destroy"); - } - - // currently resizable, changing handles - if ( isResizable && typeof value === "string" ) { - uiDialog.resizable( "option", "handles", value ); - } - - // currently non-resizable, becoming resizable - if ( !isResizable && value !== false ) { - this._makeResizable(); - } - } - - if ( key === "title" ) { - this._title( this.uiDialogTitlebar.find(".ui-dialog-title") ); - } - }, - - _size: function() { - // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content - // divs will both have width and height set, so we need to reset them - var nonContentHeight, minContentHeight, maxContentHeight, - options = this.options; - - // Reset content sizing - this.element.show().css({ - width: "auto", - minHeight: 0, - maxHeight: "none", - height: 0 - }); - - if ( options.minWidth > options.width ) { - options.width = options.minWidth; - } - - // reset wrapper sizing - // determine the height of all the non-content elements - nonContentHeight = this.uiDialog.css({ - height: "auto", - width: options.width - }) - .outerHeight(); - minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); - maxContentHeight = typeof options.maxHeight === "number" ? - Math.max( 0, options.maxHeight - nonContentHeight ) : - "none"; - - if ( options.height === "auto" ) { - this.element.css({ - minHeight: minContentHeight, - maxHeight: maxContentHeight, - height: "auto" - }); - } else { - this.element.height( Math.max( 0, options.height - nonContentHeight ) ); - } - - if (this.uiDialog.is(":data(ui-resizable)") ) { - this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); - } - }, - - _blockFrames: function() { - this.iframeBlocks = this.document.find( "iframe" ).map(function() { - var iframe = $( this ); - - return $( "
      " ) - .css({ - position: "absolute", - width: iframe.outerWidth(), - height: iframe.outerHeight() - }) - .appendTo( iframe.parent() ) - .offset( iframe.offset() )[0]; - }); - }, - - _unblockFrames: function() { - if ( this.iframeBlocks ) { - this.iframeBlocks.remove(); - delete this.iframeBlocks; - } - }, - - _allowInteraction: function( event ) { - if ( $( event.target ).closest(".ui-dialog").length ) { - return true; - } - - // TODO: Remove hack when datepicker implements - // the .ui-front logic (#8989) - return !!$( event.target ).closest(".ui-datepicker").length; - }, - - _createOverlay: function() { - if ( !this.options.modal ) { - return; - } - - var that = this, - widgetFullName = this.widgetFullName; - if ( !$.ui.dialog.overlayInstances ) { - // Prevent use of anchors and inputs. - // We use a delay in case the overlay is created from an - // event that we're going to be cancelling. (#2804) - this._delay(function() { - // Handle .dialog().dialog("close") (#4065) - if ( $.ui.dialog.overlayInstances ) { - this.document.bind( "focusin.dialog", function( event ) { - if ( !that._allowInteraction( event ) ) { - event.preventDefault(); - $(".ui-dialog:visible:last .ui-dialog-content") - .data( widgetFullName )._focusTabbable(); - } - }); - } - }); - } - - this.overlay = $("
      ") - .addClass("ui-widget-overlay ui-front") - .appendTo( this._appendTo() ); - this._on( this.overlay, { - mousedown: "_keepFocus" - }); - $.ui.dialog.overlayInstances++; - }, - - _destroyOverlay: function() { - if ( !this.options.modal ) { - return; - } - - if ( this.overlay ) { - $.ui.dialog.overlayInstances--; - - if ( !$.ui.dialog.overlayInstances ) { - this.document.unbind( "focusin.dialog" ); - } - this.overlay.remove(); - this.overlay = null; - } - } -}); - -$.ui.dialog.overlayInstances = 0; - -// DEPRECATED -if ( $.uiBackCompat !== false ) { - // position option with array notation - // just override with old implementation - $.widget( "ui.dialog", $.ui.dialog, { - _position: function() { - var position = this.options.position, - myAt = [], - offset = [ 0, 0 ], - isVisible; - - if ( position ) { - if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) { - myAt = position.split ? position.split(" ") : [ position[0], position[1] ]; - if ( myAt.length === 1 ) { - myAt[1] = myAt[0]; - } - - $.each( [ "left", "top" ], function( i, offsetPosition ) { - if ( +myAt[ i ] === myAt[ i ] ) { - offset[ i ] = myAt[ i ]; - myAt[ i ] = offsetPosition; - } - }); - - position = { - my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " + - myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]), - at: myAt.join(" ") - }; - } - - position = $.extend( {}, $.ui.dialog.prototype.options.position, position ); - } else { - position = $.ui.dialog.prototype.options.position; - } - - // need to show the dialog to get the actual offset in the position plugin - isVisible = this.uiDialog.is(":visible"); - if ( !isVisible ) { - this.uiDialog.show(); - } - this.uiDialog.position( position ); - if ( !isVisible ) { - this.uiDialog.hide(); - } - } - }); -} - -}( jQuery ) ); diff --git a/extensions/yii/jui/assets/jquery.ui.draggable.js b/extensions/yii/jui/assets/jquery.ui.draggable.js deleted file mode 100644 index a52519b..0000000 --- a/extensions/yii/jui/assets/jquery.ui.draggable.js +++ /dev/null @@ -1,958 +0,0 @@ -/*! - * jQuery UI Draggable 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/draggable/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -$.widget("ui.draggable", $.ui.mouse, { - version: "1.10.3", - widgetEventPrefix: "drag", - options: { - addClasses: true, - appendTo: "parent", - axis: false, - connectToSortable: false, - containment: false, - cursor: "auto", - cursorAt: false, - grid: false, - handle: false, - helper: "original", - iframeFix: false, - opacity: false, - refreshPositions: false, - revert: false, - revertDuration: 500, - scope: "default", - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - snap: false, - snapMode: "both", - snapTolerance: 20, - stack: false, - zIndex: false, - - // callbacks - drag: null, - start: null, - stop: null - }, - _create: function() { - - if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) { - this.element[0].style.position = "relative"; - } - if (this.options.addClasses){ - this.element.addClass("ui-draggable"); - } - if (this.options.disabled){ - this.element.addClass("ui-draggable-disabled"); - } - - this._mouseInit(); - - }, - - _destroy: function() { - this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); - this._mouseDestroy(); - }, - - _mouseCapture: function(event) { - - var o = this.options; - - // among others, prevent a drag on a resizable-handle - if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) { - return false; - } - - //Quit if we're not on a valid handle - this.handle = this._getHandle(event); - if (!this.handle) { - return false; - } - - $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { - $("
      ") - .css({ - width: this.offsetWidth+"px", height: this.offsetHeight+"px", - position: "absolute", opacity: "0.001", zIndex: 1000 - }) - .css($(this).offset()) - .appendTo("body"); - }); - - return true; - - }, - - _mouseStart: function(event) { - - var o = this.options; - - //Create and append the visible helper - this.helper = this._createHelper(event); - - this.helper.addClass("ui-draggable-dragging"); - - //Cache the helper size - this._cacheHelperProportions(); - - //If ddmanager is used for droppables, set the global draggable - if($.ui.ddmanager) { - $.ui.ddmanager.current = this; - } - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Store the helper's css position - this.cssPosition = this.helper.css( "position" ); - this.scrollParent = this.helper.scrollParent(); - this.offsetParent = this.helper.offsetParent(); - this.offsetParentCssPosition = this.offsetParent.css( "position" ); - - //The element's absolute position on the page minus margins - this.offset = this.positionAbs = this.element.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - //Reset scroll cache - this.offset.scroll = false; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - //Generate the original position - this.originalPosition = this.position = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if "cursorAt" is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Set a containment if given in the options - this._setContainment(); - - //Trigger event + callbacks - if(this._trigger("start", event) === false) { - this._clear(); - return false; - } - - //Recache the helper size - this._cacheHelperProportions(); - - //Prepare the droppable offsets - if ($.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - - - this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position - - //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) - if ( $.ui.ddmanager ) { - $.ui.ddmanager.dragStart(this, event); - } - - return true; - }, - - _mouseDrag: function(event, noPropagation) { - // reset any necessary cached properties (see #5009) - if ( this.offsetParentCssPosition === "fixed" ) { - this.offset.parent = this._getParentOffset(); - } - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - //Call plugins and callbacks and use the resulting position if something is returned - if (!noPropagation) { - var ui = this._uiHash(); - if(this._trigger("drag", event, ui) === false) { - this._mouseUp({}); - return false; - } - this.position = ui.position; - } - - if(!this.options.axis || this.options.axis !== "y") { - this.helper[0].style.left = this.position.left+"px"; - } - if(!this.options.axis || this.options.axis !== "x") { - this.helper[0].style.top = this.position.top+"px"; - } - if($.ui.ddmanager) { - $.ui.ddmanager.drag(this, event); - } - - return false; - }, - - _mouseStop: function(event) { - - //If we are using droppables, inform the manager about the drop - var that = this, - dropped = false; - if ($.ui.ddmanager && !this.options.dropBehaviour) { - dropped = $.ui.ddmanager.drop(this, event); - } - - //if a drop comes from outside (a sortable) - if(this.dropped) { - dropped = this.dropped; - this.dropped = false; - } - - //if the original element is no longer in the DOM don't bother to continue (see #8269) - if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) { - return false; - } - - if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { - $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { - if(that._trigger("stop", event) !== false) { - that._clear(); - } - }); - } else { - if(this._trigger("stop", event) !== false) { - this._clear(); - } - } - - return false; - }, - - _mouseUp: function(event) { - //Remove frame helpers - $("div.ui-draggable-iframeFix").each(function() { - this.parentNode.removeChild(this); - }); - - //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) - if( $.ui.ddmanager ) { - $.ui.ddmanager.dragStop(this, event); - } - - return $.ui.mouse.prototype._mouseUp.call(this, event); - }, - - cancel: function() { - - if(this.helper.is(".ui-draggable-dragging")) { - this._mouseUp({}); - } else { - this._clear(); - } - - return this; - - }, - - _getHandle: function(event) { - return this.options.handle ? - !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : - true; - }, - - _createHelper: function(event) { - - var o = this.options, - helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element); - - if(!helper.parents("body").length) { - helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo)); - } - - if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) { - helper.css("position", "absolute"); - } - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj === "string") { - obj = obj.split(" "); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ("left" in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ("right" in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ("top" in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ("bottom" in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - //Get the offsetParent and cache its position - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - //This needs to be actually done for all browsers, since pageX/pageY includes this information - //Ugly IE fix - if((this.offsetParent[0] === document.body) || - (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { - po = { top: 0, left: 0 }; - } - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition === "relative") { - var p = this.element.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.element.css("marginLeft"),10) || 0), - top: (parseInt(this.element.css("marginTop"),10) || 0), - right: (parseInt(this.element.css("marginRight"),10) || 0), - bottom: (parseInt(this.element.css("marginBottom"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var over, c, ce, - o = this.options; - - if ( !o.containment ) { - this.containment = null; - return; - } - - if ( o.containment === "window" ) { - this.containment = [ - $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left, - $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top, - $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left, - $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top - ]; - return; - } - - if ( o.containment === "document") { - this.containment = [ - 0, - 0, - $( document ).width() - this.helperProportions.width - this.margins.left, - ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top - ]; - return; - } - - if ( o.containment.constructor === Array ) { - this.containment = o.containment; - return; - } - - if ( o.containment === "parent" ) { - o.containment = this.helper[ 0 ].parentNode; - } - - c = $( o.containment ); - ce = c[ 0 ]; - - if( !ce ) { - return; - } - - over = c.css( "overflow" ) !== "hidden"; - - this.containment = [ - ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ), - ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) , - ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right, - ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top - this.margins.bottom - ]; - this.relative_container = c; - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) { - pos = this.position; - } - - var mod = d === "absolute" ? 1 : -1, - scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent; - - //Cache the scroll - if (!this.offset.scroll) { - this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()}; - } - - return { - top: ( - pos.top + // The absolute mouse position - this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod ) - ), - left: ( - pos.left + // The absolute mouse position - this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod ) - ) - }; - - }, - - _generatePosition: function(event) { - - var containment, co, top, left, - o = this.options, - scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent, - pageX = event.pageX, - pageY = event.pageY; - - //Cache the scroll - if (!this.offset.scroll) { - this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()}; - } - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - // If we are not dragging yet, we won't check for options - if ( this.originalPosition ) { - if ( this.containment ) { - if ( this.relative_container ){ - co = this.relative_container.offset(); - containment = [ - this.containment[ 0 ] + co.left, - this.containment[ 1 ] + co.top, - this.containment[ 2 ] + co.left, - this.containment[ 3 ] + co.top - ]; - } - else { - containment = this.containment; - } - - if(event.pageX - this.offset.click.left < containment[0]) { - pageX = containment[0] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top < containment[1]) { - pageY = containment[1] + this.offset.click.top; - } - if(event.pageX - this.offset.click.left > containment[2]) { - pageX = containment[2] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top > containment[3]) { - pageY = containment[3] + this.offset.click.top; - } - } - - if(o.grid) { - //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) - top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; - pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; - pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY - // The absolute mouse position - this.offset.click.top - // Click offset (relative to the element) - this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top + // The offsetParent's offset without borders (offset + border) - ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) - ), - left: ( - pageX - // The absolute mouse position - this.offset.click.left - // Click offset (relative to the element) - this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left + // The offsetParent's offset without borders (offset + border) - ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) - ) - }; - - }, - - _clear: function() { - this.helper.removeClass("ui-draggable-dragging"); - if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) { - this.helper.remove(); - } - this.helper = null; - this.cancelHelperRemoval = false; - }, - - // From now on bulk stuff - mainly helpers - - _trigger: function(type, event, ui) { - ui = ui || this._uiHash(); - $.ui.plugin.call(this, type, [event, ui]); - //The absolute position has to be recalculated after plugins - if(type === "drag") { - this.positionAbs = this._convertPositionTo("absolute"); - } - return $.Widget.prototype._trigger.call(this, type, event, ui); - }, - - plugins: {}, - - _uiHash: function() { - return { - helper: this.helper, - position: this.position, - originalPosition: this.originalPosition, - offset: this.positionAbs - }; - } - -}); - -$.ui.plugin.add("draggable", "connectToSortable", { - start: function(event, ui) { - - var inst = $(this).data("ui-draggable"), o = inst.options, - uiSortable = $.extend({}, ui, { item: inst.element }); - inst.sortables = []; - $(o.connectToSortable).each(function() { - var sortable = $.data(this, "ui-sortable"); - if (sortable && !sortable.options.disabled) { - inst.sortables.push({ - instance: sortable, - shouldRevert: sortable.options.revert - }); - sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page). - sortable._trigger("activate", event, uiSortable); - } - }); - - }, - stop: function(event, ui) { - - //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper - var inst = $(this).data("ui-draggable"), - uiSortable = $.extend({}, ui, { item: inst.element }); - - $.each(inst.sortables, function() { - if(this.instance.isOver) { - - this.instance.isOver = 0; - - inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance - this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) - - //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid" - if(this.shouldRevert) { - this.instance.options.revert = this.shouldRevert; - } - - //Trigger the stop of the sortable - this.instance._mouseStop(event); - - this.instance.options.helper = this.instance.options._helper; - - //If the helper has been the original item, restore properties in the sortable - if(inst.options.helper === "original") { - this.instance.currentItem.css({ top: "auto", left: "auto" }); - } - - } else { - this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance - this.instance._trigger("deactivate", event, uiSortable); - } - - }); - - }, - drag: function(event, ui) { - - var inst = $(this).data("ui-draggable"), that = this; - - $.each(inst.sortables, function() { - - var innermostIntersecting = false, - thisSortable = this; - - //Copy over some variables to allow calling the sortable's native _intersectsWith - this.instance.positionAbs = inst.positionAbs; - this.instance.helperProportions = inst.helperProportions; - this.instance.offset.click = inst.offset.click; - - if(this.instance._intersectsWith(this.instance.containerCache)) { - innermostIntersecting = true; - $.each(inst.sortables, function () { - this.instance.positionAbs = inst.positionAbs; - this.instance.helperProportions = inst.helperProportions; - this.instance.offset.click = inst.offset.click; - if (this !== thisSortable && - this.instance._intersectsWith(this.instance.containerCache) && - $.contains(thisSortable.instance.element[0], this.instance.element[0]) - ) { - innermostIntersecting = false; - } - return innermostIntersecting; - }); - } - - - if(innermostIntersecting) { - //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once - if(!this.instance.isOver) { - - this.instance.isOver = 1; - //Now we fake the start of dragging for the sortable instance, - //by cloning the list group item, appending it to the sortable and using it as inst.currentItem - //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) - this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true); - this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it - this.instance.options.helper = function() { return ui.helper[0]; }; - - event.target = this.instance.currentItem[0]; - this.instance._mouseCapture(event, true); - this.instance._mouseStart(event, true, true); - - //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes - this.instance.offset.click.top = inst.offset.click.top; - this.instance.offset.click.left = inst.offset.click.left; - this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; - this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; - - inst._trigger("toSortable", event); - inst.dropped = this.instance.element; //draggable revert needs that - //hack so receive/update callbacks work (mostly) - inst.currentItem = inst.element; - this.instance.fromOutside = inst; - - } - - //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable - if(this.instance.currentItem) { - this.instance._mouseDrag(event); - } - - } else { - - //If it doesn't intersect with the sortable, and it intersected before, - //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval - if(this.instance.isOver) { - - this.instance.isOver = 0; - this.instance.cancelHelperRemoval = true; - - //Prevent reverting on this forced stop - this.instance.options.revert = false; - - // The out event needs to be triggered independently - this.instance._trigger("out", event, this.instance._uiHash(this.instance)); - - this.instance._mouseStop(event, true); - this.instance.options.helper = this.instance.options._helper; - - //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size - this.instance.currentItem.remove(); - if(this.instance.placeholder) { - this.instance.placeholder.remove(); - } - - inst._trigger("fromSortable", event); - inst.dropped = false; //draggable revert needs that - } - - } - - }); - - } -}); - -$.ui.plugin.add("draggable", "cursor", { - start: function() { - var t = $("body"), o = $(this).data("ui-draggable").options; - if (t.css("cursor")) { - o._cursor = t.css("cursor"); - } - t.css("cursor", o.cursor); - }, - stop: function() { - var o = $(this).data("ui-draggable").options; - if (o._cursor) { - $("body").css("cursor", o._cursor); - } - } -}); - -$.ui.plugin.add("draggable", "opacity", { - start: function(event, ui) { - var t = $(ui.helper), o = $(this).data("ui-draggable").options; - if(t.css("opacity")) { - o._opacity = t.css("opacity"); - } - t.css("opacity", o.opacity); - }, - stop: function(event, ui) { - var o = $(this).data("ui-draggable").options; - if(o._opacity) { - $(ui.helper).css("opacity", o._opacity); - } - } -}); - -$.ui.plugin.add("draggable", "scroll", { - start: function() { - var i = $(this).data("ui-draggable"); - if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { - i.overflowOffset = i.scrollParent.offset(); - } - }, - drag: function( event ) { - - var i = $(this).data("ui-draggable"), o = i.options, scrolled = false; - - if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { - - if(!o.axis || o.axis !== "x") { - if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; - } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) { - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; - } - } - - if(!o.axis || o.axis !== "y") { - if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; - } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) { - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; - } - } - - } else { - - if(!o.axis || o.axis !== "x") { - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } - } - - if(!o.axis || o.axis !== "y") { - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - } - } - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(i, event); - } - - } -}); - -$.ui.plugin.add("draggable", "snap", { - start: function() { - - var i = $(this).data("ui-draggable"), - o = i.options; - - i.snapElements = []; - - $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() { - var $t = $(this), - $o = $t.offset(); - if(this !== i.element[0]) { - i.snapElements.push({ - item: this, - width: $t.outerWidth(), height: $t.outerHeight(), - top: $o.top, left: $o.left - }); - } - }); - - }, - drag: function(event, ui) { - - var ts, bs, ls, rs, l, r, t, b, i, first, - inst = $(this).data("ui-draggable"), - o = inst.options, - d = o.snapTolerance, - x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, - y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; - - for (i = inst.snapElements.length - 1; i >= 0; i--){ - - l = inst.snapElements[i].left; - r = l + inst.snapElements[i].width; - t = inst.snapElements[i].top; - b = t + inst.snapElements[i].height; - - if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) { - if(inst.snapElements[i].snapping) { - (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); - } - inst.snapElements[i].snapping = false; - continue; - } - - if(o.snapMode !== "inner") { - ts = Math.abs(t - y2) <= d; - bs = Math.abs(b - y1) <= d; - ls = Math.abs(l - x2) <= d; - rs = Math.abs(r - x1) <= d; - if(ts) { - ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - } - if(bs) { - ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; - } - if(ls) { - ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; - } - if(rs) { - ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; - } - } - - first = (ts || bs || ls || rs); - - if(o.snapMode !== "outer") { - ts = Math.abs(t - y1) <= d; - bs = Math.abs(b - y2) <= d; - ls = Math.abs(l - x1) <= d; - rs = Math.abs(r - x2) <= d; - if(ts) { - ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; - } - if(bs) { - ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - } - if(ls) { - ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; - } - if(rs) { - ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; - } - } - - if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) { - (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); - } - inst.snapElements[i].snapping = (ts || bs || ls || rs || first); - - } - - } -}); - -$.ui.plugin.add("draggable", "stack", { - start: function() { - var min, - o = this.data("ui-draggable").options, - group = $.makeArray($(o.stack)).sort(function(a,b) { - return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); - }); - - if (!group.length) { return; } - - min = parseInt($(group[0]).css("zIndex"), 10) || 0; - $(group).each(function(i) { - $(this).css("zIndex", min + i); - }); - this.css("zIndex", (min + group.length)); - } -}); - -$.ui.plugin.add("draggable", "zIndex", { - start: function(event, ui) { - var t = $(ui.helper), o = $(this).data("ui-draggable").options; - if(t.css("zIndex")) { - o._zIndex = t.css("zIndex"); - } - t.css("zIndex", o.zIndex); - }, - stop: function(event, ui) { - var o = $(this).data("ui-draggable").options; - if(o._zIndex) { - $(ui.helper).css("zIndex", o._zIndex); - } - } -}); - -})(jQuery); diff --git a/extensions/yii/jui/assets/jquery.ui.droppable.js b/extensions/yii/jui/assets/jquery.ui.droppable.js deleted file mode 100644 index 24337d0..0000000 --- a/extensions/yii/jui/assets/jquery.ui.droppable.js +++ /dev/null @@ -1,372 +0,0 @@ -/*! - * jQuery UI Droppable 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/droppable/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.mouse.js - * jquery.ui.draggable.js - */ -(function( $, undefined ) { - -function isOverAxis( x, reference, size ) { - return ( x > reference ) && ( x < ( reference + size ) ); -} - -$.widget("ui.droppable", { - version: "1.10.3", - widgetEventPrefix: "drop", - options: { - accept: "*", - activeClass: false, - addClasses: true, - greedy: false, - hoverClass: false, - scope: "default", - tolerance: "intersect", - - // callbacks - activate: null, - deactivate: null, - drop: null, - out: null, - over: null - }, - _create: function() { - - var o = this.options, - accept = o.accept; - - this.isover = false; - this.isout = true; - - this.accept = $.isFunction(accept) ? accept : function(d) { - return d.is(accept); - }; - - //Store the droppable's proportions - this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; - - // Add the reference and positions to the manager - $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || []; - $.ui.ddmanager.droppables[o.scope].push(this); - - (o.addClasses && this.element.addClass("ui-droppable")); - - }, - - _destroy: function() { - var i = 0, - drop = $.ui.ddmanager.droppables[this.options.scope]; - - for ( ; i < drop.length; i++ ) { - if ( drop[i] === this ) { - drop.splice(i, 1); - } - } - - this.element.removeClass("ui-droppable ui-droppable-disabled"); - }, - - _setOption: function(key, value) { - - if(key === "accept") { - this.accept = $.isFunction(value) ? value : function(d) { - return d.is(value); - }; - } - $.Widget.prototype._setOption.apply(this, arguments); - }, - - _activate: function(event) { - var draggable = $.ui.ddmanager.current; - if(this.options.activeClass) { - this.element.addClass(this.options.activeClass); - } - if(draggable){ - this._trigger("activate", event, this.ui(draggable)); - } - }, - - _deactivate: function(event) { - var draggable = $.ui.ddmanager.current; - if(this.options.activeClass) { - this.element.removeClass(this.options.activeClass); - } - if(draggable){ - this._trigger("deactivate", event, this.ui(draggable)); - } - }, - - _over: function(event) { - - var draggable = $.ui.ddmanager.current; - - // Bail if draggable and droppable are same element - if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { - return; - } - - if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.hoverClass) { - this.element.addClass(this.options.hoverClass); - } - this._trigger("over", event, this.ui(draggable)); - } - - }, - - _out: function(event) { - - var draggable = $.ui.ddmanager.current; - - // Bail if draggable and droppable are same element - if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { - return; - } - - if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.hoverClass) { - this.element.removeClass(this.options.hoverClass); - } - this._trigger("out", event, this.ui(draggable)); - } - - }, - - _drop: function(event,custom) { - - var draggable = custom || $.ui.ddmanager.current, - childrenIntersection = false; - - // Bail if draggable and droppable are same element - if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { - return false; - } - - this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() { - var inst = $.data(this, "ui-droppable"); - if( - inst.options.greedy && - !inst.options.disabled && - inst.options.scope === draggable.options.scope && - inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) && - $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) - ) { childrenIntersection = true; return false; } - }); - if(childrenIntersection) { - return false; - } - - if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.activeClass) { - this.element.removeClass(this.options.activeClass); - } - if(this.options.hoverClass) { - this.element.removeClass(this.options.hoverClass); - } - this._trigger("drop", event, this.ui(draggable)); - return this.element; - } - - return false; - - }, - - ui: function(c) { - return { - draggable: (c.currentItem || c.element), - helper: c.helper, - position: c.position, - offset: c.positionAbs - }; - } - -}); - -$.ui.intersect = function(draggable, droppable, toleranceMode) { - - if (!droppable.offset) { - return false; - } - - var draggableLeft, draggableTop, - x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, - y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height, - l = droppable.offset.left, r = l + droppable.proportions.width, - t = droppable.offset.top, b = t + droppable.proportions.height; - - switch (toleranceMode) { - case "fit": - return (l <= x1 && x2 <= r && t <= y1 && y2 <= b); - case "intersect": - return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half - x2 - (draggable.helperProportions.width / 2) < r && // Left Half - t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half - y2 - (draggable.helperProportions.height / 2) < b ); // Top Half - case "pointer": - draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left); - draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top); - return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width ); - case "touch": - return ( - (y1 >= t && y1 <= b) || // Top edge touching - (y2 >= t && y2 <= b) || // Bottom edge touching - (y1 < t && y2 > b) // Surrounded vertically - ) && ( - (x1 >= l && x1 <= r) || // Left edge touching - (x2 >= l && x2 <= r) || // Right edge touching - (x1 < l && x2 > r) // Surrounded horizontally - ); - default: - return false; - } - -}; - -/* - This manager tracks offsets of draggables and droppables -*/ -$.ui.ddmanager = { - current: null, - droppables: { "default": [] }, - prepareOffsets: function(t, event) { - - var i, j, - m = $.ui.ddmanager.droppables[t.options.scope] || [], - type = event ? event.type : null, // workaround for #2317 - list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack(); - - droppablesLoop: for (i = 0; i < m.length; i++) { - - //No disabled and non-accepted - if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) { - continue; - } - - // Filter out elements in the current dragged item - for (j=0; j < list.length; j++) { - if(list[j] === m[i].element[0]) { - m[i].proportions.height = 0; - continue droppablesLoop; - } - } - - m[i].visible = m[i].element.css("display") !== "none"; - if(!m[i].visible) { - continue; - } - - //Activate the droppable if used directly from draggables - if(type === "mousedown") { - m[i]._activate.call(m[i], event); - } - - m[i].offset = m[i].element.offset(); - m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; - - } - - }, - drop: function(draggable, event) { - - var dropped = false; - // Create a copy of the droppables in case the list changes during the drop (#9116) - $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() { - - if(!this.options) { - return; - } - if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) { - dropped = this._drop.call(this, event) || dropped; - } - - if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - this.isout = true; - this.isover = false; - this._deactivate.call(this, event); - } - - }); - return dropped; - - }, - dragStart: function( draggable, event ) { - //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) - draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { - if( !draggable.options.refreshPositions ) { - $.ui.ddmanager.prepareOffsets( draggable, event ); - } - }); - }, - drag: function(draggable, event) { - - //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. - if(draggable.options.refreshPositions) { - $.ui.ddmanager.prepareOffsets(draggable, event); - } - - //Run through all droppables and check their positions based on specific tolerance options - $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { - - if(this.options.disabled || this.greedyChild || !this.visible) { - return; - } - - var parentInstance, scope, parent, - intersects = $.ui.intersect(draggable, this, this.options.tolerance), - c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null); - if(!c) { - return; - } - - if (this.options.greedy) { - // find droppable parents with same scope - scope = this.options.scope; - parent = this.element.parents(":data(ui-droppable)").filter(function () { - return $.data(this, "ui-droppable").options.scope === scope; - }); - - if (parent.length) { - parentInstance = $.data(parent[0], "ui-droppable"); - parentInstance.greedyChild = (c === "isover"); - } - } - - // we just moved into a greedy child - if (parentInstance && c === "isover") { - parentInstance.isover = false; - parentInstance.isout = true; - parentInstance._out.call(parentInstance, event); - } - - this[c] = true; - this[c === "isout" ? "isover" : "isout"] = false; - this[c === "isover" ? "_over" : "_out"].call(this, event); - - // we just moved out of a greedy child - if (parentInstance && c === "isout") { - parentInstance.isout = false; - parentInstance.isover = true; - parentInstance._over.call(parentInstance, event); - } - }); - - }, - dragStop: function( draggable, event ) { - draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); - //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) - if( !draggable.options.refreshPositions ) { - $.ui.ddmanager.prepareOffsets( draggable, event ); - } - } -}; - -})(jQuery); diff --git a/extensions/yii/jui/assets/jquery.ui.effect-all.js b/extensions/yii/jui/assets/jquery.ui.effect-all.js deleted file mode 100755 index f5c6bc7..0000000 --- a/extensions/yii/jui/assets/jquery.ui.effect-all.js +++ /dev/null @@ -1,2261 +0,0 @@ -/*! jQuery UI - v1.10.3 - 2013-07-18 -* http://jqueryui.com -* Includes: jquery.ui.effect.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js -* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ - -(function($, undefined) { - -var dataSpace = "ui-effects-"; - -$.effects = { - effect: {} -}; - -/*! - * jQuery Color Animations v2.1.2 - * https://github.com/jquery/jquery-color - * - * Copyright 2013 jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * Date: Wed Jan 16 08:47:09 2013 -0600 - */ -(function( jQuery, undefined ) { - - var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", - - // plusequals test for += 100 -= 100 - rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, - // a set of RE's that can match strings and generate color tuples. - stringParsers = [{ - re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, - parse: function( execResult ) { - return [ - execResult[ 1 ], - execResult[ 2 ], - execResult[ 3 ], - execResult[ 4 ] - ]; - } - }, { - re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, - parse: function( execResult ) { - return [ - execResult[ 1 ] * 2.55, - execResult[ 2 ] * 2.55, - execResult[ 3 ] * 2.55, - execResult[ 4 ] - ]; - } - }, { - // this regex ignores A-F because it's compared against an already lowercased string - re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, - parse: function( execResult ) { - return [ - parseInt( execResult[ 1 ], 16 ), - parseInt( execResult[ 2 ], 16 ), - parseInt( execResult[ 3 ], 16 ) - ]; - } - }, { - // this regex ignores A-F because it's compared against an already lowercased string - re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, - parse: function( execResult ) { - return [ - parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), - parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), - parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) - ]; - } - }, { - re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, - space: "hsla", - parse: function( execResult ) { - return [ - execResult[ 1 ], - execResult[ 2 ] / 100, - execResult[ 3 ] / 100, - execResult[ 4 ] - ]; - } - }], - - // jQuery.Color( ) - color = jQuery.Color = function( color, green, blue, alpha ) { - return new jQuery.Color.fn.parse( color, green, blue, alpha ); - }, - spaces = { - rgba: { - props: { - red: { - idx: 0, - type: "byte" - }, - green: { - idx: 1, - type: "byte" - }, - blue: { - idx: 2, - type: "byte" - } - } - }, - - hsla: { - props: { - hue: { - idx: 0, - type: "degrees" - }, - saturation: { - idx: 1, - type: "percent" - }, - lightness: { - idx: 2, - type: "percent" - } - } - } - }, - propTypes = { - "byte": { - floor: true, - max: 255 - }, - "percent": { - max: 1 - }, - "degrees": { - mod: 360, - floor: true - } - }, - support = color.support = {}, - - // element for support tests - supportElem = jQuery( "

      " )[ 0 ], - - // colors = jQuery.Color.names - colors, - - // local aliases of functions called often - each = jQuery.each; - -// determine rgba support immediately -supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; -support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; - -// define cache name and alpha properties -// for rgba and hsla spaces -each( spaces, function( spaceName, space ) { - space.cache = "_" + spaceName; - space.props.alpha = { - idx: 3, - type: "percent", - def: 1 - }; -}); - -function clamp( value, prop, allowEmpty ) { - var type = propTypes[ prop.type ] || {}; - - if ( value == null ) { - return (allowEmpty || !prop.def) ? null : prop.def; - } - - // ~~ is an short way of doing floor for positive numbers - value = type.floor ? ~~value : parseFloat( value ); - - // IE will pass in empty strings as value for alpha, - // which will hit this case - if ( isNaN( value ) ) { - return prop.def; - } - - if ( type.mod ) { - // we add mod before modding to make sure that negatives values - // get converted properly: -10 -> 350 - return (value + type.mod) % type.mod; - } - - // for now all property types without mod have min and max - return 0 > value ? 0 : type.max < value ? type.max : value; -} - -function stringParse( string ) { - var inst = color(), - rgba = inst._rgba = []; - - string = string.toLowerCase(); - - each( stringParsers, function( i, parser ) { - var parsed, - match = parser.re.exec( string ), - values = match && parser.parse( match ), - spaceName = parser.space || "rgba"; - - if ( values ) { - parsed = inst[ spaceName ]( values ); - - // if this was an rgba parse the assignment might happen twice - // oh well.... - inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; - rgba = inst._rgba = parsed._rgba; - - // exit each( stringParsers ) here because we matched - return false; - } - }); - - // Found a stringParser that handled it - if ( rgba.length ) { - - // if this came from a parsed string, force "transparent" when alpha is 0 - // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) - if ( rgba.join() === "0,0,0,0" ) { - jQuery.extend( rgba, colors.transparent ); - } - return inst; - } - - // named colors - return colors[ string ]; -} - -color.fn = jQuery.extend( color.prototype, { - parse: function( red, green, blue, alpha ) { - if ( red === undefined ) { - this._rgba = [ null, null, null, null ]; - return this; - } - if ( red.jquery || red.nodeType ) { - red = jQuery( red ).css( green ); - green = undefined; - } - - var inst = this, - type = jQuery.type( red ), - rgba = this._rgba = []; - - // more than 1 argument specified - assume ( red, green, blue, alpha ) - if ( green !== undefined ) { - red = [ red, green, blue, alpha ]; - type = "array"; - } - - if ( type === "string" ) { - return this.parse( stringParse( red ) || colors._default ); - } - - if ( type === "array" ) { - each( spaces.rgba.props, function( key, prop ) { - rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); - }); - return this; - } - - if ( type === "object" ) { - if ( red instanceof color ) { - each( spaces, function( spaceName, space ) { - if ( red[ space.cache ] ) { - inst[ space.cache ] = red[ space.cache ].slice(); - } - }); - } else { - each( spaces, function( spaceName, space ) { - var cache = space.cache; - each( space.props, function( key, prop ) { - - // if the cache doesn't exist, and we know how to convert - if ( !inst[ cache ] && space.to ) { - - // if the value was null, we don't need to copy it - // if the key was alpha, we don't need to copy it either - if ( key === "alpha" || red[ key ] == null ) { - return; - } - inst[ cache ] = space.to( inst._rgba ); - } - - // this is the only case where we allow nulls for ALL properties. - // call clamp with alwaysAllowEmpty - inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); - }); - - // everything defined but alpha? - if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { - // use the default of 1 - inst[ cache ][ 3 ] = 1; - if ( space.from ) { - inst._rgba = space.from( inst[ cache ] ); - } - } - }); - } - return this; - } - }, - is: function( compare ) { - var is = color( compare ), - same = true, - inst = this; - - each( spaces, function( _, space ) { - var localCache, - isCache = is[ space.cache ]; - if (isCache) { - localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; - each( space.props, function( _, prop ) { - if ( isCache[ prop.idx ] != null ) { - same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); - return same; - } - }); - } - return same; - }); - return same; - }, - _space: function() { - var used = [], - inst = this; - each( spaces, function( spaceName, space ) { - if ( inst[ space.cache ] ) { - used.push( spaceName ); - } - }); - return used.pop(); - }, - transition: function( other, distance ) { - var end = color( other ), - spaceName = end._space(), - space = spaces[ spaceName ], - startColor = this.alpha() === 0 ? color( "transparent" ) : this, - start = startColor[ space.cache ] || space.to( startColor._rgba ), - result = start.slice(); - - end = end[ space.cache ]; - each( space.props, function( key, prop ) { - var index = prop.idx, - startValue = start[ index ], - endValue = end[ index ], - type = propTypes[ prop.type ] || {}; - - // if null, don't override start value - if ( endValue === null ) { - return; - } - // if null - use end - if ( startValue === null ) { - result[ index ] = endValue; - } else { - if ( type.mod ) { - if ( endValue - startValue > type.mod / 2 ) { - startValue += type.mod; - } else if ( startValue - endValue > type.mod / 2 ) { - startValue -= type.mod; - } - } - result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); - } - }); - return this[ spaceName ]( result ); - }, - blend: function( opaque ) { - // if we are already opaque - return ourself - if ( this._rgba[ 3 ] === 1 ) { - return this; - } - - var rgb = this._rgba.slice(), - a = rgb.pop(), - blend = color( opaque )._rgba; - - return color( jQuery.map( rgb, function( v, i ) { - return ( 1 - a ) * blend[ i ] + a * v; - })); - }, - toRgbaString: function() { - var prefix = "rgba(", - rgba = jQuery.map( this._rgba, function( v, i ) { - return v == null ? ( i > 2 ? 1 : 0 ) : v; - }); - - if ( rgba[ 3 ] === 1 ) { - rgba.pop(); - prefix = "rgb("; - } - - return prefix + rgba.join() + ")"; - }, - toHslaString: function() { - var prefix = "hsla(", - hsla = jQuery.map( this.hsla(), function( v, i ) { - if ( v == null ) { - v = i > 2 ? 1 : 0; - } - - // catch 1 and 2 - if ( i && i < 3 ) { - v = Math.round( v * 100 ) + "%"; - } - return v; - }); - - if ( hsla[ 3 ] === 1 ) { - hsla.pop(); - prefix = "hsl("; - } - return prefix + hsla.join() + ")"; - }, - toHexString: function( includeAlpha ) { - var rgba = this._rgba.slice(), - alpha = rgba.pop(); - - if ( includeAlpha ) { - rgba.push( ~~( alpha * 255 ) ); - } - - return "#" + jQuery.map( rgba, function( v ) { - - // default to 0 when nulls exist - v = ( v || 0 ).toString( 16 ); - return v.length === 1 ? "0" + v : v; - }).join(""); - }, - toString: function() { - return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); - } -}); -color.fn.parse.prototype = color.fn; - -// hsla conversions adapted from: -// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 - -function hue2rgb( p, q, h ) { - h = ( h + 1 ) % 1; - if ( h * 6 < 1 ) { - return p + (q - p) * h * 6; - } - if ( h * 2 < 1) { - return q; - } - if ( h * 3 < 2 ) { - return p + (q - p) * ((2/3) - h) * 6; - } - return p; -} - -spaces.hsla.to = function ( rgba ) { - if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { - return [ null, null, null, rgba[ 3 ] ]; - } - var r = rgba[ 0 ] / 255, - g = rgba[ 1 ] / 255, - b = rgba[ 2 ] / 255, - a = rgba[ 3 ], - max = Math.max( r, g, b ), - min = Math.min( r, g, b ), - diff = max - min, - add = max + min, - l = add * 0.5, - h, s; - - if ( min === max ) { - h = 0; - } else if ( r === max ) { - h = ( 60 * ( g - b ) / diff ) + 360; - } else if ( g === max ) { - h = ( 60 * ( b - r ) / diff ) + 120; - } else { - h = ( 60 * ( r - g ) / diff ) + 240; - } - - // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% - // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) - if ( diff === 0 ) { - s = 0; - } else if ( l <= 0.5 ) { - s = diff / add; - } else { - s = diff / ( 2 - add ); - } - return [ Math.round(h) % 360, s, l, a == null ? 1 : a ]; -}; - -spaces.hsla.from = function ( hsla ) { - if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { - return [ null, null, null, hsla[ 3 ] ]; - } - var h = hsla[ 0 ] / 360, - s = hsla[ 1 ], - l = hsla[ 2 ], - a = hsla[ 3 ], - q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, - p = 2 * l - q; - - return [ - Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), - Math.round( hue2rgb( p, q, h ) * 255 ), - Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), - a - ]; -}; - - -each( spaces, function( spaceName, space ) { - var props = space.props, - cache = space.cache, - to = space.to, - from = space.from; - - // makes rgba() and hsla() - color.fn[ spaceName ] = function( value ) { - - // generate a cache for this space if it doesn't exist - if ( to && !this[ cache ] ) { - this[ cache ] = to( this._rgba ); - } - if ( value === undefined ) { - return this[ cache ].slice(); - } - - var ret, - type = jQuery.type( value ), - arr = ( type === "array" || type === "object" ) ? value : arguments, - local = this[ cache ].slice(); - - each( props, function( key, prop ) { - var val = arr[ type === "object" ? key : prop.idx ]; - if ( val == null ) { - val = local[ prop.idx ]; - } - local[ prop.idx ] = clamp( val, prop ); - }); - - if ( from ) { - ret = color( from( local ) ); - ret[ cache ] = local; - return ret; - } else { - return color( local ); - } - }; - - // makes red() green() blue() alpha() hue() saturation() lightness() - each( props, function( key, prop ) { - // alpha is included in more than one space - if ( color.fn[ key ] ) { - return; - } - color.fn[ key ] = function( value ) { - var vtype = jQuery.type( value ), - fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ), - local = this[ fn ](), - cur = local[ prop.idx ], - match; - - if ( vtype === "undefined" ) { - return cur; - } - - if ( vtype === "function" ) { - value = value.call( this, cur ); - vtype = jQuery.type( value ); - } - if ( value == null && prop.empty ) { - return this; - } - if ( vtype === "string" ) { - match = rplusequals.exec( value ); - if ( match ) { - value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); - } - } - local[ prop.idx ] = value; - return this[ fn ]( local ); - }; - }); -}); - -// add cssHook and .fx.step function for each named hook. -// accept a space separated string of properties -color.hook = function( hook ) { - var hooks = hook.split( " " ); - each( hooks, function( i, hook ) { - jQuery.cssHooks[ hook ] = { - set: function( elem, value ) { - var parsed, curElem, - backgroundColor = ""; - - if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) { - value = color( parsed || value ); - if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { - curElem = hook === "backgroundColor" ? elem.parentNode : elem; - while ( - (backgroundColor === "" || backgroundColor === "transparent") && - curElem && curElem.style - ) { - try { - backgroundColor = jQuery.css( curElem, "backgroundColor" ); - curElem = curElem.parentNode; - } catch ( e ) { - } - } - - value = value.blend( backgroundColor && backgroundColor !== "transparent" ? - backgroundColor : - "_default" ); - } - - value = value.toRgbaString(); - } - try { - elem.style[ hook ] = value; - } catch( e ) { - // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' - } - } - }; - jQuery.fx.step[ hook ] = function( fx ) { - if ( !fx.colorInit ) { - fx.start = color( fx.elem, hook ); - fx.end = color( fx.end ); - fx.colorInit = true; - } - jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); - }; - }); - -}; - -color.hook( stepHooks ); - -jQuery.cssHooks.borderColor = { - expand: function( value ) { - var expanded = {}; - - each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) { - expanded[ "border" + part + "Color" ] = value; - }); - return expanded; - } -}; - -// Basic color names only. -// Usage of any of the other color names requires adding yourself or including -// jquery.color.svg-names.js. -colors = jQuery.Color.names = { - // 4.1. Basic color keywords - aqua: "#00ffff", - black: "#000000", - blue: "#0000ff", - fuchsia: "#ff00ff", - gray: "#808080", - green: "#008000", - lime: "#00ff00", - maroon: "#800000", - navy: "#000080", - olive: "#808000", - purple: "#800080", - red: "#ff0000", - silver: "#c0c0c0", - teal: "#008080", - white: "#ffffff", - yellow: "#ffff00", - - // 4.2.3. "transparent" color keyword - transparent: [ null, null, null, 0 ], - - _default: "#ffffff" -}; - -})( jQuery ); - - -/******************************************************************************/ -/****************************** CLASS ANIMATIONS ******************************/ -/******************************************************************************/ -(function() { - -var classAnimationActions = [ "add", "remove", "toggle" ], - shorthandStyles = { - border: 1, - borderBottom: 1, - borderColor: 1, - borderLeft: 1, - borderRight: 1, - borderTop: 1, - borderWidth: 1, - margin: 1, - padding: 1 - }; - -$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) { - $.fx.step[ prop ] = function( fx ) { - if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { - jQuery.style( fx.elem, prop, fx.end ); - fx.setAttr = true; - } - }; -}); - -function getElementStyles( elem ) { - var key, len, - style = elem.ownerDocument.defaultView ? - elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : - elem.currentStyle, - styles = {}; - - if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { - len = style.length; - while ( len-- ) { - key = style[ len ]; - if ( typeof style[ key ] === "string" ) { - styles[ $.camelCase( key ) ] = style[ key ]; - } - } - // support: Opera, IE <9 - } else { - for ( key in style ) { - if ( typeof style[ key ] === "string" ) { - styles[ key ] = style[ key ]; - } - } - } - - return styles; -} - - -function styleDifference( oldStyle, newStyle ) { - var diff = {}, - name, value; - - for ( name in newStyle ) { - value = newStyle[ name ]; - if ( oldStyle[ name ] !== value ) { - if ( !shorthandStyles[ name ] ) { - if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { - diff[ name ] = value; - } - } - } - } - - return diff; -} - -// support: jQuery <1.8 -if ( !$.fn.addBack ) { - $.fn.addBack = function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - }; -} - -$.effects.animateClass = function( value, duration, easing, callback ) { - var o = $.speed( duration, easing, callback ); - - return this.queue( function() { - var animated = $( this ), - baseClass = animated.attr( "class" ) || "", - applyClassChange, - allAnimations = o.children ? animated.find( "*" ).addBack() : animated; - - // map the animated objects to store the original styles. - allAnimations = allAnimations.map(function() { - var el = $( this ); - return { - el: el, - start: getElementStyles( this ) - }; - }); - - // apply class change - applyClassChange = function() { - $.each( classAnimationActions, function(i, action) { - if ( value[ action ] ) { - animated[ action + "Class" ]( value[ action ] ); - } - }); - }; - applyClassChange(); - - // map all animated objects again - calculate new styles and diff - allAnimations = allAnimations.map(function() { - this.end = getElementStyles( this.el[ 0 ] ); - this.diff = styleDifference( this.start, this.end ); - return this; - }); - - // apply original class - animated.attr( "class", baseClass ); - - // map all animated objects again - this time collecting a promise - allAnimations = allAnimations.map(function() { - var styleInfo = this, - dfd = $.Deferred(), - opts = $.extend({}, o, { - queue: false, - complete: function() { - dfd.resolve( styleInfo ); - } - }); - - this.el.animate( this.diff, opts ); - return dfd.promise(); - }); - - // once all animations have completed: - $.when.apply( $, allAnimations.get() ).done(function() { - - // set the final class - applyClassChange(); - - // for each animated element, - // clear all css properties that were animated - $.each( arguments, function() { - var el = this.el; - $.each( this.diff, function(key) { - el.css( key, "" ); - }); - }); - - // this is guarnteed to be there if you use jQuery.speed() - // it also handles dequeuing the next anim... - o.complete.call( animated[ 0 ] ); - }); - }); -}; - -$.fn.extend({ - addClass: (function( orig ) { - return function( classNames, speed, easing, callback ) { - return speed ? - $.effects.animateClass.call( this, - { add: classNames }, speed, easing, callback ) : - orig.apply( this, arguments ); - }; - })( $.fn.addClass ), - - removeClass: (function( orig ) { - return function( classNames, speed, easing, callback ) { - return arguments.length > 1 ? - $.effects.animateClass.call( this, - { remove: classNames }, speed, easing, callback ) : - orig.apply( this, arguments ); - }; - })( $.fn.removeClass ), - - toggleClass: (function( orig ) { - return function( classNames, force, speed, easing, callback ) { - if ( typeof force === "boolean" || force === undefined ) { - if ( !speed ) { - // without speed parameter - return orig.apply( this, arguments ); - } else { - return $.effects.animateClass.call( this, - (force ? { add: classNames } : { remove: classNames }), - speed, easing, callback ); - } - } else { - // without force parameter - return $.effects.animateClass.call( this, - { toggle: classNames }, force, speed, easing ); - } - }; - })( $.fn.toggleClass ), - - switchClass: function( remove, add, speed, easing, callback) { - return $.effects.animateClass.call( this, { - add: add, - remove: remove - }, speed, easing, callback ); - } -}); - -})(); - -/******************************************************************************/ -/*********************************** EFFECTS **********************************/ -/******************************************************************************/ - -(function() { - -$.extend( $.effects, { - version: "1.10.3", - - // Saves a set of properties in a data storage - save: function( element, set ) { - for( var i=0; i < set.length; i++ ) { - if ( set[ i ] !== null ) { - element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); - } - } - }, - - // Restores a set of previously saved properties from a data storage - restore: function( element, set ) { - var val, i; - for( i=0; i < set.length; i++ ) { - if ( set[ i ] !== null ) { - val = element.data( dataSpace + set[ i ] ); - // support: jQuery 1.6.2 - // http://bugs.jquery.com/ticket/9917 - // jQuery 1.6.2 incorrectly returns undefined for any falsy value. - // We can't differentiate between "" and 0 here, so we just assume - // empty string since it's likely to be a more common value... - if ( val === undefined ) { - val = ""; - } - element.css( set[ i ], val ); - } - } - }, - - setMode: function( el, mode ) { - if (mode === "toggle") { - mode = el.is( ":hidden" ) ? "show" : "hide"; - } - return mode; - }, - - // Translates a [top,left] array into a baseline value - // this should be a little more flexible in the future to handle a string & hash - getBaseline: function( origin, original ) { - var y, x; - switch ( origin[ 0 ] ) { - case "top": y = 0; break; - case "middle": y = 0.5; break; - case "bottom": y = 1; break; - default: y = origin[ 0 ] / original.height; - } - switch ( origin[ 1 ] ) { - case "left": x = 0; break; - case "center": x = 0.5; break; - case "right": x = 1; break; - default: x = origin[ 1 ] / original.width; - } - return { - x: x, - y: y - }; - }, - - // Wraps the element around a wrapper that copies position properties - createWrapper: function( element ) { - - // if the element is already wrapped, return it - if ( element.parent().is( ".ui-effects-wrapper" )) { - return element.parent(); - } - - // wrap the element - var props = { - width: element.outerWidth(true), - height: element.outerHeight(true), - "float": element.css( "float" ) - }, - wrapper = $( "

      " ) - .addClass( "ui-effects-wrapper" ) - .css({ - fontSize: "100%", - background: "transparent", - border: "none", - margin: 0, - padding: 0 - }), - // Store the size in case width/height are defined in % - Fixes #5245 - size = { - width: element.width(), - height: element.height() - }, - active = document.activeElement; - - // support: Firefox - // Firefox incorrectly exposes anonymous content - // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 - try { - active.id; - } catch( e ) { - active = document.body; - } - - element.wrap( wrapper ); - - // Fixes #7595 - Elements lose focus when wrapped. - if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { - $( active ).focus(); - } - - wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element - - // transfer positioning properties to the wrapper - if ( element.css( "position" ) === "static" ) { - wrapper.css({ position: "relative" }); - element.css({ position: "relative" }); - } else { - $.extend( props, { - position: element.css( "position" ), - zIndex: element.css( "z-index" ) - }); - $.each([ "top", "left", "bottom", "right" ], function(i, pos) { - props[ pos ] = element.css( pos ); - if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { - props[ pos ] = "auto"; - } - }); - element.css({ - position: "relative", - top: 0, - left: 0, - right: "auto", - bottom: "auto" - }); - } - element.css(size); - - return wrapper.css( props ).show(); - }, - - removeWrapper: function( element ) { - var active = document.activeElement; - - if ( element.parent().is( ".ui-effects-wrapper" ) ) { - element.parent().replaceWith( element ); - - // Fixes #7595 - Elements lose focus when wrapped. - if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { - $( active ).focus(); - } - } - - - return element; - }, - - setTransition: function( element, list, factor, value ) { - value = value || {}; - $.each( list, function( i, x ) { - var unit = element.cssUnit( x ); - if ( unit[ 0 ] > 0 ) { - value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; - } - }); - return value; - } -}); - -// return an effect options object for the given parameters: -function _normalizeArguments( effect, options, speed, callback ) { - - // allow passing all options as the first parameter - if ( $.isPlainObject( effect ) ) { - options = effect; - effect = effect.effect; - } - - // convert to an object - effect = { effect: effect }; - - // catch (effect, null, ...) - if ( options == null ) { - options = {}; - } - - // catch (effect, callback) - if ( $.isFunction( options ) ) { - callback = options; - speed = null; - options = {}; - } - - // catch (effect, speed, ?) - if ( typeof options === "number" || $.fx.speeds[ options ] ) { - callback = speed; - speed = options; - options = {}; - } - - // catch (effect, options, callback) - if ( $.isFunction( speed ) ) { - callback = speed; - speed = null; - } - - // add options to effect - if ( options ) { - $.extend( effect, options ); - } - - speed = speed || options.duration; - effect.duration = $.fx.off ? 0 : - typeof speed === "number" ? speed : - speed in $.fx.speeds ? $.fx.speeds[ speed ] : - $.fx.speeds._default; - - effect.complete = callback || options.complete; - - return effect; -} - -function standardAnimationOption( option ) { - // Valid standard speeds (nothing, number, named speed) - if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) { - return true; - } - - // Invalid strings - treat as "normal" speed - if ( typeof option === "string" && !$.effects.effect[ option ] ) { - return true; - } - - // Complete callback - if ( $.isFunction( option ) ) { - return true; - } - - // Options hash (but not naming an effect) - if ( typeof option === "object" && !option.effect ) { - return true; - } - - // Didn't match any standard API - return false; -} - -$.fn.extend({ - effect: function( /* effect, options, speed, callback */ ) { - var args = _normalizeArguments.apply( this, arguments ), - mode = args.mode, - queue = args.queue, - effectMethod = $.effects.effect[ args.effect ]; - - if ( $.fx.off || !effectMethod ) { - // delegate to the original method (e.g., .show()) if possible - if ( mode ) { - return this[ mode ]( args.duration, args.complete ); - } else { - return this.each( function() { - if ( args.complete ) { - args.complete.call( this ); - } - }); - } - } - - function run( next ) { - var elem = $( this ), - complete = args.complete, - mode = args.mode; - - function done() { - if ( $.isFunction( complete ) ) { - complete.call( elem[0] ); - } - if ( $.isFunction( next ) ) { - next(); - } - } - - // If the element already has the correct final state, delegate to - // the core methods so the internal tracking of "olddisplay" works. - if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { - elem[ mode ](); - done(); - } else { - effectMethod.call( elem[0], args, done ); - } - } - - return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); - }, - - show: (function( orig ) { - return function( option ) { - if ( standardAnimationOption( option ) ) { - return orig.apply( this, arguments ); - } else { - var args = _normalizeArguments.apply( this, arguments ); - args.mode = "show"; - return this.effect.call( this, args ); - } - }; - })( $.fn.show ), - - hide: (function( orig ) { - return function( option ) { - if ( standardAnimationOption( option ) ) { - return orig.apply( this, arguments ); - } else { - var args = _normalizeArguments.apply( this, arguments ); - args.mode = "hide"; - return this.effect.call( this, args ); - } - }; - })( $.fn.hide ), - - toggle: (function( orig ) { - return function( option ) { - if ( standardAnimationOption( option ) || typeof option === "boolean" ) { - return orig.apply( this, arguments ); - } else { - var args = _normalizeArguments.apply( this, arguments ); - args.mode = "toggle"; - return this.effect.call( this, args ); - } - }; - })( $.fn.toggle ), - - // helper functions - cssUnit: function(key) { - var style = this.css( key ), - val = []; - - $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { - if ( style.indexOf( unit ) > 0 ) { - val = [ parseFloat( style ), unit ]; - } - }); - return val; - } -}); - -})(); - -/******************************************************************************/ -/*********************************** EASING ***********************************/ -/******************************************************************************/ - -(function() { - -// based on easing equations from Robert Penner (http://www.robertpenner.com/easing) - -var baseEasings = {}; - -$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { - baseEasings[ name ] = function( p ) { - return Math.pow( p, i + 2 ); - }; -}); - -$.extend( baseEasings, { - Sine: function ( p ) { - return 1 - Math.cos( p * Math.PI / 2 ); - }, - Circ: function ( p ) { - return 1 - Math.sqrt( 1 - p * p ); - }, - Elastic: function( p ) { - return p === 0 || p === 1 ? p : - -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 ); - }, - Back: function( p ) { - return p * p * ( 3 * p - 2 ); - }, - Bounce: function ( p ) { - var pow2, - bounce = 4; - - while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} - return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); - } -}); - -$.each( baseEasings, function( name, easeIn ) { - $.easing[ "easeIn" + name ] = easeIn; - $.easing[ "easeOut" + name ] = function( p ) { - return 1 - easeIn( 1 - p ); - }; - $.easing[ "easeInOut" + name ] = function( p ) { - return p < 0.5 ? - easeIn( p * 2 ) / 2 : - 1 - easeIn( p * -2 + 2 ) / 2; - }; -}); - -})(); - -})(jQuery); -(function( $, undefined ) { - -var rvertical = /up|down|vertical/, - rpositivemotion = /up|left|vertical|horizontal/; - -$.effects.effect.blind = function( o, done ) { - // Create element - var el = $( this ), - props = [ "position", "top", "bottom", "left", "right", "height", "width" ], - mode = $.effects.setMode( el, o.mode || "hide" ), - direction = o.direction || "up", - vertical = rvertical.test( direction ), - ref = vertical ? "height" : "width", - ref2 = vertical ? "top" : "left", - motion = rpositivemotion.test( direction ), - animation = {}, - show = mode === "show", - wrapper, distance, margin; - - // if already wrapped, the wrapper's properties are my property. #6245 - if ( el.parent().is( ".ui-effects-wrapper" ) ) { - $.effects.save( el.parent(), props ); - } else { - $.effects.save( el, props ); - } - el.show(); - wrapper = $.effects.createWrapper( el ).css({ - overflow: "hidden" - }); - - distance = wrapper[ ref ](); - margin = parseFloat( wrapper.css( ref2 ) ) || 0; - - animation[ ref ] = show ? distance : 0; - if ( !motion ) { - el - .css( vertical ? "bottom" : "right", 0 ) - .css( vertical ? "top" : "left", "auto" ) - .css({ position: "absolute" }); - - animation[ ref2 ] = show ? margin : distance + margin; - } - - // start at 0 if we are showing - if ( show ) { - wrapper.css( ref, 0 ); - if ( ! motion ) { - wrapper.css( ref2, margin + distance ); - } - } - - // Animate - wrapper.animate( animation, { - duration: o.duration, - easing: o.easing, - queue: false, - complete: function() { - if ( mode === "hide" ) { - el.hide(); - } - $.effects.restore( el, props ); - $.effects.removeWrapper( el ); - done(); - } - }); - -}; - -})(jQuery); -(function( $, undefined ) { - -$.effects.effect.bounce = function( o, done ) { - var el = $( this ), - props = [ "position", "top", "bottom", "left", "right", "height", "width" ], - - // defaults: - mode = $.effects.setMode( el, o.mode || "effect" ), - hide = mode === "hide", - show = mode === "show", - direction = o.direction || "up", - distance = o.distance, - times = o.times || 5, - - // number of internal animations - anims = times * 2 + ( show || hide ? 1 : 0 ), - speed = o.duration / anims, - easing = o.easing, - - // utility: - ref = ( direction === "up" || direction === "down" ) ? "top" : "left", - motion = ( direction === "up" || direction === "left" ), - i, - upAnim, - downAnim, - - // we will need to re-assemble the queue to stack our animations in place - queue = el.queue(), - queuelen = queue.length; - - // Avoid touching opacity to prevent clearType and PNG issues in IE - if ( show || hide ) { - props.push( "opacity" ); - } - - $.effects.save( el, props ); - el.show(); - $.effects.createWrapper( el ); // Create Wrapper - - // default distance for the BIGGEST bounce is the outer Distance / 3 - if ( !distance ) { - distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3; - } - - if ( show ) { - downAnim = { opacity: 1 }; - downAnim[ ref ] = 0; - - // if we are showing, force opacity 0 and set the initial position - // then do the "first" animation - el.css( "opacity", 0 ) - .css( ref, motion ? -distance * 2 : distance * 2 ) - .animate( downAnim, speed, easing ); - } - - // start at the smallest distance if we are hiding - if ( hide ) { - distance = distance / Math.pow( 2, times - 1 ); - } - - downAnim = {}; - downAnim[ ref ] = 0; - // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here - for ( i = 0; i < times; i++ ) { - upAnim = {}; - upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; - - el.animate( upAnim, speed, easing ) - .animate( downAnim, speed, easing ); - - distance = hide ? distance * 2 : distance / 2; - } - - // Last Bounce when Hiding - if ( hide ) { - upAnim = { opacity: 0 }; - upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; - - el.animate( upAnim, speed, easing ); - } - - el.queue(function() { - if ( hide ) { - el.hide(); - } - $.effects.restore( el, props ); - $.effects.removeWrapper( el ); - done(); - }); - - // inject all the animations we just queued to be first in line (after "inprogress") - if ( queuelen > 1) { - queue.splice.apply( queue, - [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); - } - el.dequeue(); - -}; - -})(jQuery); -(function( $, undefined ) { - -$.effects.effect.clip = function( o, done ) { - // Create element - var el = $( this ), - props = [ "position", "top", "bottom", "left", "right", "height", "width" ], - mode = $.effects.setMode( el, o.mode || "hide" ), - show = mode === "show", - direction = o.direction || "vertical", - vert = direction === "vertical", - size = vert ? "height" : "width", - position = vert ? "top" : "left", - animation = {}, - wrapper, animate, distance; - - // Save & Show - $.effects.save( el, props ); - el.show(); - - // Create Wrapper - wrapper = $.effects.createWrapper( el ).css({ - overflow: "hidden" - }); - animate = ( el[0].tagName === "IMG" ) ? wrapper : el; - distance = animate[ size ](); - - // Shift - if ( show ) { - animate.css( size, 0 ); - animate.css( position, distance / 2 ); - } - - // Create Animation Object: - animation[ size ] = show ? distance : 0; - animation[ position ] = show ? 0 : distance / 2; - - // Animate - animate.animate( animation, { - queue: false, - duration: o.duration, - easing: o.easing, - complete: function() { - if ( !show ) { - el.hide(); - } - $.effects.restore( el, props ); - $.effects.removeWrapper( el ); - done(); - } - }); - -}; - -})(jQuery); -(function( $, undefined ) { - -$.effects.effect.drop = function( o, done ) { - - var el = $( this ), - props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ], - mode = $.effects.setMode( el, o.mode || "hide" ), - show = mode === "show", - direction = o.direction || "left", - ref = ( direction === "up" || direction === "down" ) ? "top" : "left", - motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg", - animation = { - opacity: show ? 1 : 0 - }, - distance; - - // Adjust - $.effects.save( el, props ); - el.show(); - $.effects.createWrapper( el ); - - distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2; - - if ( show ) { - el - .css( "opacity", 0 ) - .css( ref, motion === "pos" ? -distance : distance ); - } - - // Animation - animation[ ref ] = ( show ? - ( motion === "pos" ? "+=" : "-=" ) : - ( motion === "pos" ? "-=" : "+=" ) ) + - distance; - - // Animate - el.animate( animation, { - queue: false, - duration: o.duration, - easing: o.easing, - complete: function() { - if ( mode === "hide" ) { - el.hide(); - } - $.effects.restore( el, props ); - $.effects.removeWrapper( el ); - done(); - } - }); -}; - -})(jQuery); -(function( $, undefined ) { - -$.effects.effect.explode = function( o, done ) { - - var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3, - cells = rows, - el = $( this ), - mode = $.effects.setMode( el, o.mode || "hide" ), - show = mode === "show", - - // show and then visibility:hidden the element before calculating offset - offset = el.show().css( "visibility", "hidden" ).offset(), - - // width and height of a piece - width = Math.ceil( el.outerWidth() / cells ), - height = Math.ceil( el.outerHeight() / rows ), - pieces = [], - - // loop - i, j, left, top, mx, my; - - // children animate complete: - function childComplete() { - pieces.push( this ); - if ( pieces.length === rows * cells ) { - animComplete(); - } - } - - // clone the element for each row and cell. - for( i = 0; i < rows ; i++ ) { // ===> - top = offset.top + i * height; - my = i - ( rows - 1 ) / 2 ; - - for( j = 0; j < cells ; j++ ) { // ||| - left = offset.left + j * width; - mx = j - ( cells - 1 ) / 2 ; - - // Create a clone of the now hidden main element that will be absolute positioned - // within a wrapper div off the -left and -top equal to size of our pieces - el - .clone() - .appendTo( "body" ) - .wrap( "
      " ) - .css({ - position: "absolute", - visibility: "visible", - left: -j * width, - top: -i * height - }) - - // select the wrapper - make it overflow: hidden and absolute positioned based on - // where the original was located +left and +top equal to the size of pieces - .parent() - .addClass( "ui-effects-explode" ) - .css({ - position: "absolute", - overflow: "hidden", - width: width, - height: height, - left: left + ( show ? mx * width : 0 ), - top: top + ( show ? my * height : 0 ), - opacity: show ? 0 : 1 - }).animate({ - left: left + ( show ? 0 : mx * width ), - top: top + ( show ? 0 : my * height ), - opacity: show ? 1 : 0 - }, o.duration || 500, o.easing, childComplete ); - } - } - - function animComplete() { - el.css({ - visibility: "visible" - }); - $( pieces ).remove(); - if ( !show ) { - el.hide(); - } - done(); - } -}; - -})(jQuery); -(function( $, undefined ) { - -$.effects.effect.fade = function( o, done ) { - var el = $( this ), - mode = $.effects.setMode( el, o.mode || "toggle" ); - - el.animate({ - opacity: mode - }, { - queue: false, - duration: o.duration, - easing: o.easing, - complete: done - }); -}; - -})( jQuery ); -(function( $, undefined ) { - -$.effects.effect.fold = function( o, done ) { - - // Create element - var el = $( this ), - props = [ "position", "top", "bottom", "left", "right", "height", "width" ], - mode = $.effects.setMode( el, o.mode || "hide" ), - show = mode === "show", - hide = mode === "hide", - size = o.size || 15, - percent = /([0-9]+)%/.exec( size ), - horizFirst = !!o.horizFirst, - widthFirst = show !== horizFirst, - ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ], - duration = o.duration / 2, - wrapper, distance, - animation1 = {}, - animation2 = {}; - - $.effects.save( el, props ); - el.show(); - - // Create Wrapper - wrapper = $.effects.createWrapper( el ).css({ - overflow: "hidden" - }); - distance = widthFirst ? - [ wrapper.width(), wrapper.height() ] : - [ wrapper.height(), wrapper.width() ]; - - if ( percent ) { - size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ]; - } - if ( show ) { - wrapper.css( horizFirst ? { - height: 0, - width: size - } : { - height: size, - width: 0 - }); - } - - // Animation - animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size; - animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0; - - // Animate - wrapper - .animate( animation1, duration, o.easing ) - .animate( animation2, duration, o.easing, function() { - if ( hide ) { - el.hide(); - } - $.effects.restore( el, props ); - $.effects.removeWrapper( el ); - done(); - }); - -}; - -})(jQuery); -(function( $, undefined ) { - -$.effects.effect.highlight = function( o, done ) { - var elem = $( this ), - props = [ "backgroundImage", "backgroundColor", "opacity" ], - mode = $.effects.setMode( elem, o.mode || "show" ), - animation = { - backgroundColor: elem.css( "backgroundColor" ) - }; - - if (mode === "hide") { - animation.opacity = 0; - } - - $.effects.save( elem, props ); - - elem - .show() - .css({ - backgroundImage: "none", - backgroundColor: o.color || "#ffff99" - }) - .animate( animation, { - queue: false, - duration: o.duration, - easing: o.easing, - complete: function() { - if ( mode === "hide" ) { - elem.hide(); - } - $.effects.restore( elem, props ); - done(); - } - }); -}; - -})(jQuery); -(function( $, undefined ) { - -$.effects.effect.pulsate = function( o, done ) { - var elem = $( this ), - mode = $.effects.setMode( elem, o.mode || "show" ), - show = mode === "show", - hide = mode === "hide", - showhide = ( show || mode === "hide" ), - - // showing or hiding leaves of the "last" animation - anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ), - duration = o.duration / anims, - animateTo = 0, - queue = elem.queue(), - queuelen = queue.length, - i; - - if ( show || !elem.is(":visible")) { - elem.css( "opacity", 0 ).show(); - animateTo = 1; - } - - // anims - 1 opacity "toggles" - for ( i = 1; i < anims; i++ ) { - elem.animate({ - opacity: animateTo - }, duration, o.easing ); - animateTo = 1 - animateTo; - } - - elem.animate({ - opacity: animateTo - }, duration, o.easing); - - elem.queue(function() { - if ( hide ) { - elem.hide(); - } - done(); - }); - - // We just queued up "anims" animations, we need to put them next in the queue - if ( queuelen > 1 ) { - queue.splice.apply( queue, - [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); - } - elem.dequeue(); -}; - -})(jQuery); -(function( $, undefined ) { - -$.effects.effect.puff = function( o, done ) { - var elem = $( this ), - mode = $.effects.setMode( elem, o.mode || "hide" ), - hide = mode === "hide", - percent = parseInt( o.percent, 10 ) || 150, - factor = percent / 100, - original = { - height: elem.height(), - width: elem.width(), - outerHeight: elem.outerHeight(), - outerWidth: elem.outerWidth() - }; - - $.extend( o, { - effect: "scale", - queue: false, - fade: true, - mode: mode, - complete: done, - percent: hide ? percent : 100, - from: hide ? - original : - { - height: original.height * factor, - width: original.width * factor, - outerHeight: original.outerHeight * factor, - outerWidth: original.outerWidth * factor - } - }); - - elem.effect( o ); -}; - -$.effects.effect.scale = function( o, done ) { - - // Create element - var el = $( this ), - options = $.extend( true, {}, o ), - mode = $.effects.setMode( el, o.mode || "effect" ), - percent = parseInt( o.percent, 10 ) || - ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ), - direction = o.direction || "both", - origin = o.origin, - original = { - height: el.height(), - width: el.width(), - outerHeight: el.outerHeight(), - outerWidth: el.outerWidth() - }, - factor = { - y: direction !== "horizontal" ? (percent / 100) : 1, - x: direction !== "vertical" ? (percent / 100) : 1 - }; - - // We are going to pass this effect to the size effect: - options.effect = "size"; - options.queue = false; - options.complete = done; - - // Set default origin and restore for show/hide - if ( mode !== "effect" ) { - options.origin = origin || ["middle","center"]; - options.restore = true; - } - - options.from = o.from || ( mode === "show" ? { - height: 0, - width: 0, - outerHeight: 0, - outerWidth: 0 - } : original ); - options.to = { - height: original.height * factor.y, - width: original.width * factor.x, - outerHeight: original.outerHeight * factor.y, - outerWidth: original.outerWidth * factor.x - }; - - // Fade option to support puff - if ( options.fade ) { - if ( mode === "show" ) { - options.from.opacity = 0; - options.to.opacity = 1; - } - if ( mode === "hide" ) { - options.from.opacity = 1; - options.to.opacity = 0; - } - } - - // Animate - el.effect( options ); - -}; - -$.effects.effect.size = function( o, done ) { - - // Create element - var original, baseline, factor, - el = $( this ), - props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ], - - // Always restore - props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ], - - // Copy for children - props2 = [ "width", "height", "overflow" ], - cProps = [ "fontSize" ], - vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ], - hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ], - - // Set options - mode = $.effects.setMode( el, o.mode || "effect" ), - restore = o.restore || mode !== "effect", - scale = o.scale || "both", - origin = o.origin || [ "middle", "center" ], - position = el.css( "position" ), - props = restore ? props0 : props1, - zero = { - height: 0, - width: 0, - outerHeight: 0, - outerWidth: 0 - }; - - if ( mode === "show" ) { - el.show(); - } - original = { - height: el.height(), - width: el.width(), - outerHeight: el.outerHeight(), - outerWidth: el.outerWidth() - }; - - if ( o.mode === "toggle" && mode === "show" ) { - el.from = o.to || zero; - el.to = o.from || original; - } else { - el.from = o.from || ( mode === "show" ? zero : original ); - el.to = o.to || ( mode === "hide" ? zero : original ); - } - - // Set scaling factor - factor = { - from: { - y: el.from.height / original.height, - x: el.from.width / original.width - }, - to: { - y: el.to.height / original.height, - x: el.to.width / original.width - } - }; - - // Scale the css box - if ( scale === "box" || scale === "both" ) { - - // Vertical props scaling - if ( factor.from.y !== factor.to.y ) { - props = props.concat( vProps ); - el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from ); - el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to ); - } - - // Horizontal props scaling - if ( factor.from.x !== factor.to.x ) { - props = props.concat( hProps ); - el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from ); - el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to ); - } - } - - // Scale the content - if ( scale === "content" || scale === "both" ) { - - // Vertical props scaling - if ( factor.from.y !== factor.to.y ) { - props = props.concat( cProps ).concat( props2 ); - el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from ); - el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to ); - } - } - - $.effects.save( el, props ); - el.show(); - $.effects.createWrapper( el ); - el.css( "overflow", "hidden" ).css( el.from ); - - // Adjust - if (origin) { // Calculate baseline shifts - baseline = $.effects.getBaseline( origin, original ); - el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y; - el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x; - el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y; - el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x; - } - el.css( el.from ); // set top & left - - // Animate - if ( scale === "content" || scale === "both" ) { // Scale the children - - // Add margins/font-size - vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps); - hProps = hProps.concat([ "marginLeft", "marginRight" ]); - props2 = props0.concat(vProps).concat(hProps); - - el.find( "*[width]" ).each( function(){ - var child = $( this ), - c_original = { - height: child.height(), - width: child.width(), - outerHeight: child.outerHeight(), - outerWidth: child.outerWidth() - }; - if (restore) { - $.effects.save(child, props2); - } - - child.from = { - height: c_original.height * factor.from.y, - width: c_original.width * factor.from.x, - outerHeight: c_original.outerHeight * factor.from.y, - outerWidth: c_original.outerWidth * factor.from.x - }; - child.to = { - height: c_original.height * factor.to.y, - width: c_original.width * factor.to.x, - outerHeight: c_original.height * factor.to.y, - outerWidth: c_original.width * factor.to.x - }; - - // Vertical props scaling - if ( factor.from.y !== factor.to.y ) { - child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from ); - child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to ); - } - - // Horizontal props scaling - if ( factor.from.x !== factor.to.x ) { - child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from ); - child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to ); - } - - // Animate children - child.css( child.from ); - child.animate( child.to, o.duration, o.easing, function() { - - // Restore children - if ( restore ) { - $.effects.restore( child, props2 ); - } - }); - }); - } - - // Animate - el.animate( el.to, { - queue: false, - duration: o.duration, - easing: o.easing, - complete: function() { - if ( el.to.opacity === 0 ) { - el.css( "opacity", el.from.opacity ); - } - if( mode === "hide" ) { - el.hide(); - } - $.effects.restore( el, props ); - if ( !restore ) { - - // we need to calculate our new positioning based on the scaling - if ( position === "static" ) { - el.css({ - position: "relative", - top: el.to.top, - left: el.to.left - }); - } else { - $.each([ "top", "left" ], function( idx, pos ) { - el.css( pos, function( _, str ) { - var val = parseInt( str, 10 ), - toRef = idx ? el.to.left : el.to.top; - - // if original was "auto", recalculate the new value from wrapper - if ( str === "auto" ) { - return toRef + "px"; - } - - return val + toRef + "px"; - }); - }); - } - } - - $.effects.removeWrapper( el ); - done(); - } - }); - -}; - -})(jQuery); -(function( $, undefined ) { - -$.effects.effect.shake = function( o, done ) { - - var el = $( this ), - props = [ "position", "top", "bottom", "left", "right", "height", "width" ], - mode = $.effects.setMode( el, o.mode || "effect" ), - direction = o.direction || "left", - distance = o.distance || 20, - times = o.times || 3, - anims = times * 2 + 1, - speed = Math.round(o.duration/anims), - ref = (direction === "up" || direction === "down") ? "top" : "left", - positiveMotion = (direction === "up" || direction === "left"), - animation = {}, - animation1 = {}, - animation2 = {}, - i, - - // we will need to re-assemble the queue to stack our animations in place - queue = el.queue(), - queuelen = queue.length; - - $.effects.save( el, props ); - el.show(); - $.effects.createWrapper( el ); - - // Animation - animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance; - animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2; - animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2; - - // Animate - el.animate( animation, speed, o.easing ); - - // Shakes - for ( i = 1; i < times; i++ ) { - el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing ); - } - el - .animate( animation1, speed, o.easing ) - .animate( animation, speed / 2, o.easing ) - .queue(function() { - if ( mode === "hide" ) { - el.hide(); - } - $.effects.restore( el, props ); - $.effects.removeWrapper( el ); - done(); - }); - - // inject all the animations we just queued to be first in line (after "inprogress") - if ( queuelen > 1) { - queue.splice.apply( queue, - [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); - } - el.dequeue(); - -}; - -})(jQuery); -(function( $, undefined ) { - -$.effects.effect.slide = function( o, done ) { - - // Create element - var el = $( this ), - props = [ "position", "top", "bottom", "left", "right", "width", "height" ], - mode = $.effects.setMode( el, o.mode || "show" ), - show = mode === "show", - direction = o.direction || "left", - ref = (direction === "up" || direction === "down") ? "top" : "left", - positiveMotion = (direction === "up" || direction === "left"), - distance, - animation = {}; - - // Adjust - $.effects.save( el, props ); - el.show(); - distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ); - - $.effects.createWrapper( el ).css({ - overflow: "hidden" - }); - - if ( show ) { - el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance ); - } - - // Animation - animation[ ref ] = ( show ? - ( positiveMotion ? "+=" : "-=") : - ( positiveMotion ? "-=" : "+=")) + - distance; - - // Animate - el.animate( animation, { - queue: false, - duration: o.duration, - easing: o.easing, - complete: function() { - if ( mode === "hide" ) { - el.hide(); - } - $.effects.restore( el, props ); - $.effects.removeWrapper( el ); - done(); - } - }); -}; - -})(jQuery); -(function( $, undefined ) { - -$.effects.effect.transfer = function( o, done ) { - var elem = $( this ), - target = $( o.to ), - targetFixed = target.css( "position" ) === "fixed", - body = $("body"), - fixTop = targetFixed ? body.scrollTop() : 0, - fixLeft = targetFixed ? body.scrollLeft() : 0, - endPosition = target.offset(), - animation = { - top: endPosition.top - fixTop , - left: endPosition.left - fixLeft , - height: target.innerHeight(), - width: target.innerWidth() - }, - startPosition = elem.offset(), - transfer = $( "
      " ) - .appendTo( document.body ) - .addClass( o.className ) - .css({ - top: startPosition.top - fixTop , - left: startPosition.left - fixLeft , - height: elem.innerHeight(), - width: elem.innerWidth(), - position: targetFixed ? "fixed" : "absolute" - }) - .animate( animation, o.duration, o.easing, function() { - transfer.remove(); - done(); - }); -}; - -})(jQuery); diff --git a/extensions/yii/jui/assets/jquery.ui.menu.js b/extensions/yii/jui/assets/jquery.ui.menu.js deleted file mode 100644 index ace12e2..0000000 --- a/extensions/yii/jui/assets/jquery.ui.menu.js +++ /dev/null @@ -1,621 +0,0 @@ -/*! - * jQuery UI Menu 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/menu/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.position.js - */ -(function( $, undefined ) { - -$.widget( "ui.menu", { - version: "1.10.3", - defaultElement: "
        ", - delay: 300, - options: { - icons: { - submenu: "ui-icon-carat-1-e" - }, - menus: "ul", - position: { - my: "left top", - at: "right top" - }, - role: "menu", - - // callbacks - blur: null, - focus: null, - select: null - }, - - _create: function() { - this.activeMenu = this.element; - // flag used to prevent firing of the click handler - // as the event bubbles up through nested menus - this.mouseHandled = false; - this.element - .uniqueId() - .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) - .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ) - .attr({ - role: this.options.role, - tabIndex: 0 - }) - // need to catch all clicks on disabled menu - // not possible through _on - .bind( "click" + this.eventNamespace, $.proxy(function( event ) { - if ( this.options.disabled ) { - event.preventDefault(); - } - }, this )); - - if ( this.options.disabled ) { - this.element - .addClass( "ui-state-disabled" ) - .attr( "aria-disabled", "true" ); - } - - this._on({ - // Prevent focus from sticking to links inside menu after clicking - // them (focus should always stay on UL during navigation). - "mousedown .ui-menu-item > a": function( event ) { - event.preventDefault(); - }, - "click .ui-state-disabled > a": function( event ) { - event.preventDefault(); - }, - "click .ui-menu-item:has(a)": function( event ) { - var target = $( event.target ).closest( ".ui-menu-item" ); - if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) { - this.mouseHandled = true; - - this.select( event ); - // Open submenu on click - if ( target.has( ".ui-menu" ).length ) { - this.expand( event ); - } else if ( !this.element.is( ":focus" ) ) { - // Redirect focus to the menu - this.element.trigger( "focus", [ true ] ); - - // If the active item is on the top level, let it stay active. - // Otherwise, blur the active item since it is no longer visible. - if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) { - clearTimeout( this.timer ); - } - } - } - }, - "mouseenter .ui-menu-item": function( event ) { - var target = $( event.currentTarget ); - // Remove ui-state-active class from siblings of the newly focused menu item - // to avoid a jump caused by adjacent elements both having a class with a border - target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" ); - this.focus( event, target ); - }, - mouseleave: "collapseAll", - "mouseleave .ui-menu": "collapseAll", - focus: function( event, keepActiveItem ) { - // If there's already an active item, keep it active - // If not, activate the first item - var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 ); - - if ( !keepActiveItem ) { - this.focus( event, item ); - } - }, - blur: function( event ) { - this._delay(function() { - if ( !$.contains( this.element[0], this.document[0].activeElement ) ) { - this.collapseAll( event ); - } - }); - }, - keydown: "_keydown" - }); - - this.refresh(); - - // Clicks outside of a menu collapse any open menus - this._on( this.document, { - click: function( event ) { - if ( !$( event.target ).closest( ".ui-menu" ).length ) { - this.collapseAll( event ); - } - - // Reset the mouseHandled flag - this.mouseHandled = false; - } - }); - }, - - _destroy: function() { - // Destroy (sub)menus - this.element - .removeAttr( "aria-activedescendant" ) - .find( ".ui-menu" ).addBack() - .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" ) - .removeAttr( "role" ) - .removeAttr( "tabIndex" ) - .removeAttr( "aria-labelledby" ) - .removeAttr( "aria-expanded" ) - .removeAttr( "aria-hidden" ) - .removeAttr( "aria-disabled" ) - .removeUniqueId() - .show(); - - // Destroy menu items - this.element.find( ".ui-menu-item" ) - .removeClass( "ui-menu-item" ) - .removeAttr( "role" ) - .removeAttr( "aria-disabled" ) - .children( "a" ) - .removeUniqueId() - .removeClass( "ui-corner-all ui-state-hover" ) - .removeAttr( "tabIndex" ) - .removeAttr( "role" ) - .removeAttr( "aria-haspopup" ) - .children().each( function() { - var elem = $( this ); - if ( elem.data( "ui-menu-submenu-carat" ) ) { - elem.remove(); - } - }); - - // Destroy menu dividers - this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" ); - }, - - _keydown: function( event ) { - /*jshint maxcomplexity:20*/ - var match, prev, character, skip, regex, - preventDefault = true; - - function escape( value ) { - return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); - } - - switch ( event.keyCode ) { - case $.ui.keyCode.PAGE_UP: - this.previousPage( event ); - break; - case $.ui.keyCode.PAGE_DOWN: - this.nextPage( event ); - break; - case $.ui.keyCode.HOME: - this._move( "first", "first", event ); - break; - case $.ui.keyCode.END: - this._move( "last", "last", event ); - break; - case $.ui.keyCode.UP: - this.previous( event ); - break; - case $.ui.keyCode.DOWN: - this.next( event ); - break; - case $.ui.keyCode.LEFT: - this.collapse( event ); - break; - case $.ui.keyCode.RIGHT: - if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { - this.expand( event ); - } - break; - case $.ui.keyCode.ENTER: - case $.ui.keyCode.SPACE: - this._activate( event ); - break; - case $.ui.keyCode.ESCAPE: - this.collapse( event ); - break; - default: - preventDefault = false; - prev = this.previousFilter || ""; - character = String.fromCharCode( event.keyCode ); - skip = false; - - clearTimeout( this.filterTimer ); - - if ( character === prev ) { - skip = true; - } else { - character = prev + character; - } - - regex = new RegExp( "^" + escape( character ), "i" ); - match = this.activeMenu.children( ".ui-menu-item" ).filter(function() { - return regex.test( $( this ).children( "a" ).text() ); - }); - match = skip && match.index( this.active.next() ) !== -1 ? - this.active.nextAll( ".ui-menu-item" ) : - match; - - // If no matches on the current filter, reset to the last character pressed - // to move down the menu to the first item that starts with that character - if ( !match.length ) { - character = String.fromCharCode( event.keyCode ); - regex = new RegExp( "^" + escape( character ), "i" ); - match = this.activeMenu.children( ".ui-menu-item" ).filter(function() { - return regex.test( $( this ).children( "a" ).text() ); - }); - } - - if ( match.length ) { - this.focus( event, match ); - if ( match.length > 1 ) { - this.previousFilter = character; - this.filterTimer = this._delay(function() { - delete this.previousFilter; - }, 1000 ); - } else { - delete this.previousFilter; - } - } else { - delete this.previousFilter; - } - } - - if ( preventDefault ) { - event.preventDefault(); - } - }, - - _activate: function( event ) { - if ( !this.active.is( ".ui-state-disabled" ) ) { - if ( this.active.children( "a[aria-haspopup='true']" ).length ) { - this.expand( event ); - } else { - this.select( event ); - } - } - }, - - refresh: function() { - var menus, - icon = this.options.icons.submenu, - submenus = this.element.find( this.options.menus ); - - // Initialize nested menus - submenus.filter( ":not(.ui-menu)" ) - .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) - .hide() - .attr({ - role: this.options.role, - "aria-hidden": "true", - "aria-expanded": "false" - }) - .each(function() { - var menu = $( this ), - item = menu.prev( "a" ), - submenuCarat = $( "" ) - .addClass( "ui-menu-icon ui-icon " + icon ) - .data( "ui-menu-submenu-carat", true ); - - item - .attr( "aria-haspopup", "true" ) - .prepend( submenuCarat ); - menu.attr( "aria-labelledby", item.attr( "id" ) ); - }); - - menus = submenus.add( this.element ); - - // Don't refresh list items that are already adapted - menus.children( ":not(.ui-menu-item):has(a)" ) - .addClass( "ui-menu-item" ) - .attr( "role", "presentation" ) - .children( "a" ) - .uniqueId() - .addClass( "ui-corner-all" ) - .attr({ - tabIndex: -1, - role: this._itemRole() - }); - - // Initialize unlinked menu-items containing spaces and/or dashes only as dividers - menus.children( ":not(.ui-menu-item)" ).each(function() { - var item = $( this ); - // hyphen, em dash, en dash - if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) { - item.addClass( "ui-widget-content ui-menu-divider" ); - } - }); - - // Add aria-disabled attribute to any disabled menu item - menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); - - // If the active item has been removed, blur the menu - if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { - this.blur(); - } - }, - - _itemRole: function() { - return { - menu: "menuitem", - listbox: "option" - }[ this.options.role ]; - }, - - _setOption: function( key, value ) { - if ( key === "icons" ) { - this.element.find( ".ui-menu-icon" ) - .removeClass( this.options.icons.submenu ) - .addClass( value.submenu ); - } - this._super( key, value ); - }, - - focus: function( event, item ) { - var nested, focused; - this.blur( event, event && event.type === "focus" ); - - this._scrollIntoView( item ); - - this.active = item.first(); - focused = this.active.children( "a" ).addClass( "ui-state-focus" ); - // Only update aria-activedescendant if there's a role - // otherwise we assume focus is managed elsewhere - if ( this.options.role ) { - this.element.attr( "aria-activedescendant", focused.attr( "id" ) ); - } - - // Highlight active parent menu item, if any - this.active - .parent() - .closest( ".ui-menu-item" ) - .children( "a:first" ) - .addClass( "ui-state-active" ); - - if ( event && event.type === "keydown" ) { - this._close(); - } else { - this.timer = this._delay(function() { - this._close(); - }, this.delay ); - } - - nested = item.children( ".ui-menu" ); - if ( nested.length && ( /^mouse/.test( event.type ) ) ) { - this._startOpening(nested); - } - this.activeMenu = item.parent(); - - this._trigger( "focus", event, { item: item } ); - }, - - _scrollIntoView: function( item ) { - var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; - if ( this._hasScroll() ) { - borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0; - paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0; - offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; - scroll = this.activeMenu.scrollTop(); - elementHeight = this.activeMenu.height(); - itemHeight = item.height(); - - if ( offset < 0 ) { - this.activeMenu.scrollTop( scroll + offset ); - } else if ( offset + itemHeight > elementHeight ) { - this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight ); - } - } - }, - - blur: function( event, fromFocus ) { - if ( !fromFocus ) { - clearTimeout( this.timer ); - } - - if ( !this.active ) { - return; - } - - this.active.children( "a" ).removeClass( "ui-state-focus" ); - this.active = null; - - this._trigger( "blur", event, { item: this.active } ); - }, - - _startOpening: function( submenu ) { - clearTimeout( this.timer ); - - // Don't open if already open fixes a Firefox bug that caused a .5 pixel - // shift in the submenu position when mousing over the carat icon - if ( submenu.attr( "aria-hidden" ) !== "true" ) { - return; - } - - this.timer = this._delay(function() { - this._close(); - this._open( submenu ); - }, this.delay ); - }, - - _open: function( submenu ) { - var position = $.extend({ - of: this.active - }, this.options.position ); - - clearTimeout( this.timer ); - this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) ) - .hide() - .attr( "aria-hidden", "true" ); - - submenu - .show() - .removeAttr( "aria-hidden" ) - .attr( "aria-expanded", "true" ) - .position( position ); - }, - - collapseAll: function( event, all ) { - clearTimeout( this.timer ); - this.timer = this._delay(function() { - // If we were passed an event, look for the submenu that contains the event - var currentMenu = all ? this.element : - $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); - - // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway - if ( !currentMenu.length ) { - currentMenu = this.element; - } - - this._close( currentMenu ); - - this.blur( event ); - this.activeMenu = currentMenu; - }, this.delay ); - }, - - // With no arguments, closes the currently active menu - if nothing is active - // it closes all menus. If passed an argument, it will search for menus BELOW - _close: function( startMenu ) { - if ( !startMenu ) { - startMenu = this.active ? this.active.parent() : this.element; - } - - startMenu - .find( ".ui-menu" ) - .hide() - .attr( "aria-hidden", "true" ) - .attr( "aria-expanded", "false" ) - .end() - .find( "a.ui-state-active" ) - .removeClass( "ui-state-active" ); - }, - - collapse: function( event ) { - var newItem = this.active && - this.active.parent().closest( ".ui-menu-item", this.element ); - if ( newItem && newItem.length ) { - this._close(); - this.focus( event, newItem ); - } - }, - - expand: function( event ) { - var newItem = this.active && - this.active - .children( ".ui-menu " ) - .children( ".ui-menu-item" ) - .first(); - - if ( newItem && newItem.length ) { - this._open( newItem.parent() ); - - // Delay so Firefox will not hide activedescendant change in expanding submenu from AT - this._delay(function() { - this.focus( event, newItem ); - }); - } - }, - - next: function( event ) { - this._move( "next", "first", event ); - }, - - previous: function( event ) { - this._move( "prev", "last", event ); - }, - - isFirstItem: function() { - return this.active && !this.active.prevAll( ".ui-menu-item" ).length; - }, - - isLastItem: function() { - return this.active && !this.active.nextAll( ".ui-menu-item" ).length; - }, - - _move: function( direction, filter, event ) { - var next; - if ( this.active ) { - if ( direction === "first" || direction === "last" ) { - next = this.active - [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ) - .eq( -1 ); - } else { - next = this.active - [ direction + "All" ]( ".ui-menu-item" ) - .eq( 0 ); - } - } - if ( !next || !next.length || !this.active ) { - next = this.activeMenu.children( ".ui-menu-item" )[ filter ](); - } - - this.focus( event, next ); - }, - - nextPage: function( event ) { - var item, base, height; - - if ( !this.active ) { - this.next( event ); - return; - } - if ( this.isLastItem() ) { - return; - } - if ( this._hasScroll() ) { - base = this.active.offset().top; - height = this.element.height(); - this.active.nextAll( ".ui-menu-item" ).each(function() { - item = $( this ); - return item.offset().top - base - height < 0; - }); - - this.focus( event, item ); - } else { - this.focus( event, this.activeMenu.children( ".ui-menu-item" ) - [ !this.active ? "first" : "last" ]() ); - } - }, - - previousPage: function( event ) { - var item, base, height; - if ( !this.active ) { - this.next( event ); - return; - } - if ( this.isFirstItem() ) { - return; - } - if ( this._hasScroll() ) { - base = this.active.offset().top; - height = this.element.height(); - this.active.prevAll( ".ui-menu-item" ).each(function() { - item = $( this ); - return item.offset().top - base + height > 0; - }); - - this.focus( event, item ); - } else { - this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() ); - } - }, - - _hasScroll: function() { - return this.element.outerHeight() < this.element.prop( "scrollHeight" ); - }, - - select: function( event ) { - // TODO: It should never be possible to not have an active item at this - // point, but the tests don't trigger mouseenter before click. - this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); - var ui = { item: this.active }; - if ( !this.active.has( ".ui-menu" ).length ) { - this.collapseAll( event, true ); - } - this._trigger( "select", event, ui ); - } -}); - -}( jQuery )); diff --git a/extensions/yii/jui/assets/jquery.ui.mouse.js b/extensions/yii/jui/assets/jquery.ui.mouse.js deleted file mode 100644 index 62022ce..0000000 --- a/extensions/yii/jui/assets/jquery.ui.mouse.js +++ /dev/null @@ -1,169 +0,0 @@ -/*! - * jQuery UI Mouse 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/mouse/ - * - * Depends: - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -var mouseHandled = false; -$( document ).mouseup( function() { - mouseHandled = false; -}); - -$.widget("ui.mouse", { - version: "1.10.3", - options: { - cancel: "input,textarea,button,select,option", - distance: 1, - delay: 0 - }, - _mouseInit: function() { - var that = this; - - this.element - .bind("mousedown."+this.widgetName, function(event) { - return that._mouseDown(event); - }) - .bind("click."+this.widgetName, function(event) { - if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { - $.removeData(event.target, that.widgetName + ".preventClickEvent"); - event.stopImmediatePropagation(); - return false; - } - }); - - this.started = false; - }, - - // TODO: make sure destroying one instance of mouse doesn't mess with - // other instances of mouse - _mouseDestroy: function() { - this.element.unbind("."+this.widgetName); - if ( this._mouseMoveDelegate ) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - } - }, - - _mouseDown: function(event) { - // don't let more than one widget handle mouseStart - if( mouseHandled ) { return; } - - // we may have missed mouseup (out of window) - (this._mouseStarted && this._mouseUp(event)); - - this._mouseDownEvent = event; - - var that = this, - btnIsLeft = (event.which === 1), - // event.target.nodeName works around a bug in IE 8 with - // disabled inputs (#7620) - elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); - if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { - return true; - } - - this.mouseDelayMet = !this.options.delay; - if (!this.mouseDelayMet) { - this._mouseDelayTimer = setTimeout(function() { - that.mouseDelayMet = true; - }, this.options.delay); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = (this._mouseStart(event) !== false); - if (!this._mouseStarted) { - event.preventDefault(); - return true; - } - } - - // Click event may never have fired (Gecko & Opera) - if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { - $.removeData(event.target, this.widgetName + ".preventClickEvent"); - } - - // these delegates are required to keep context - this._mouseMoveDelegate = function(event) { - return that._mouseMove(event); - }; - this._mouseUpDelegate = function(event) { - return that._mouseUp(event); - }; - $(document) - .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .bind("mouseup."+this.widgetName, this._mouseUpDelegate); - - event.preventDefault(); - - mouseHandled = true; - return true; - }, - - _mouseMove: function(event) { - // IE mouseup check - mouseup happened when mouse was out of window - if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { - return this._mouseUp(event); - } - - if (this._mouseStarted) { - this._mouseDrag(event); - return event.preventDefault(); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = - (this._mouseStart(this._mouseDownEvent, event) !== false); - (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); - } - - return !this._mouseStarted; - }, - - _mouseUp: function(event) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - - if (this._mouseStarted) { - this._mouseStarted = false; - - if (event.target === this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + ".preventClickEvent", true); - } - - this._mouseStop(event); - } - - return false; - }, - - _mouseDistanceMet: function(event) { - return (Math.max( - Math.abs(this._mouseDownEvent.pageX - event.pageX), - Math.abs(this._mouseDownEvent.pageY - event.pageY) - ) >= this.options.distance - ); - }, - - _mouseDelayMet: function(/* event */) { - return this.mouseDelayMet; - }, - - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(/* event */) {}, - _mouseDrag: function(/* event */) {}, - _mouseStop: function(/* event */) {}, - _mouseCapture: function(/* event */) { return true; } -}); - -})(jQuery); diff --git a/extensions/yii/jui/assets/jquery.ui.position.js b/extensions/yii/jui/assets/jquery.ui.position.js deleted file mode 100644 index 3fcdf25..0000000 --- a/extensions/yii/jui/assets/jquery.ui.position.js +++ /dev/null @@ -1,497 +0,0 @@ -/*! - * jQuery UI Position 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/position/ - */ -(function( $, undefined ) { - -$.ui = $.ui || {}; - -var cachedScrollbarWidth, - max = Math.max, - abs = Math.abs, - round = Math.round, - rhorizontal = /left|center|right/, - rvertical = /top|center|bottom/, - roffset = /[\+\-]\d+(\.[\d]+)?%?/, - rposition = /^\w+/, - rpercent = /%$/, - _position = $.fn.position; - -function getOffsets( offsets, width, height ) { - return [ - parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), - parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) - ]; -} - -function parseCss( element, property ) { - return parseInt( $.css( element, property ), 10 ) || 0; -} - -function getDimensions( elem ) { - var raw = elem[0]; - if ( raw.nodeType === 9 ) { - return { - width: elem.width(), - height: elem.height(), - offset: { top: 0, left: 0 } - }; - } - if ( $.isWindow( raw ) ) { - return { - width: elem.width(), - height: elem.height(), - offset: { top: elem.scrollTop(), left: elem.scrollLeft() } - }; - } - if ( raw.preventDefault ) { - return { - width: 0, - height: 0, - offset: { top: raw.pageY, left: raw.pageX } - }; - } - return { - width: elem.outerWidth(), - height: elem.outerHeight(), - offset: elem.offset() - }; -} - -$.position = { - scrollbarWidth: function() { - if ( cachedScrollbarWidth !== undefined ) { - return cachedScrollbarWidth; - } - var w1, w2, - div = $( "
        " ), - innerDiv = div.children()[0]; - - $( "body" ).append( div ); - w1 = innerDiv.offsetWidth; - div.css( "overflow", "scroll" ); - - w2 = innerDiv.offsetWidth; - - if ( w1 === w2 ) { - w2 = div[0].clientWidth; - } - - div.remove(); - - return (cachedScrollbarWidth = w1 - w2); - }, - getScrollInfo: function( within ) { - var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ), - overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ), - hasOverflowX = overflowX === "scroll" || - ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), - hasOverflowY = overflowY === "scroll" || - ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); - return { - width: hasOverflowY ? $.position.scrollbarWidth() : 0, - height: hasOverflowX ? $.position.scrollbarWidth() : 0 - }; - }, - getWithinInfo: function( element ) { - var withinElement = $( element || window ), - isWindow = $.isWindow( withinElement[0] ); - return { - element: withinElement, - isWindow: isWindow, - offset: withinElement.offset() || { left: 0, top: 0 }, - scrollLeft: withinElement.scrollLeft(), - scrollTop: withinElement.scrollTop(), - width: isWindow ? withinElement.width() : withinElement.outerWidth(), - height: isWindow ? withinElement.height() : withinElement.outerHeight() - }; - } -}; - -$.fn.position = function( options ) { - if ( !options || !options.of ) { - return _position.apply( this, arguments ); - } - - // make a copy, we don't want to modify arguments - options = $.extend( {}, options ); - - var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, - target = $( options.of ), - within = $.position.getWithinInfo( options.within ), - scrollInfo = $.position.getScrollInfo( within ), - collision = ( options.collision || "flip" ).split( " " ), - offsets = {}; - - dimensions = getDimensions( target ); - if ( target[0].preventDefault ) { - // force left top to allow flipping - options.at = "left top"; - } - targetWidth = dimensions.width; - targetHeight = dimensions.height; - targetOffset = dimensions.offset; - // clone to reuse original targetOffset later - basePosition = $.extend( {}, targetOffset ); - - // force my and at to have valid horizontal and vertical positions - // if a value is missing or invalid, it will be converted to center - $.each( [ "my", "at" ], function() { - var pos = ( options[ this ] || "" ).split( " " ), - horizontalOffset, - verticalOffset; - - if ( pos.length === 1) { - pos = rhorizontal.test( pos[ 0 ] ) ? - pos.concat( [ "center" ] ) : - rvertical.test( pos[ 0 ] ) ? - [ "center" ].concat( pos ) : - [ "center", "center" ]; - } - pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; - pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; - - // calculate offsets - horizontalOffset = roffset.exec( pos[ 0 ] ); - verticalOffset = roffset.exec( pos[ 1 ] ); - offsets[ this ] = [ - horizontalOffset ? horizontalOffset[ 0 ] : 0, - verticalOffset ? verticalOffset[ 0 ] : 0 - ]; - - // reduce to just the positions without the offsets - options[ this ] = [ - rposition.exec( pos[ 0 ] )[ 0 ], - rposition.exec( pos[ 1 ] )[ 0 ] - ]; - }); - - // normalize collision option - if ( collision.length === 1 ) { - collision[ 1 ] = collision[ 0 ]; - } - - if ( options.at[ 0 ] === "right" ) { - basePosition.left += targetWidth; - } else if ( options.at[ 0 ] === "center" ) { - basePosition.left += targetWidth / 2; - } - - if ( options.at[ 1 ] === "bottom" ) { - basePosition.top += targetHeight; - } else if ( options.at[ 1 ] === "center" ) { - basePosition.top += targetHeight / 2; - } - - atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); - basePosition.left += atOffset[ 0 ]; - basePosition.top += atOffset[ 1 ]; - - return this.each(function() { - var collisionPosition, using, - elem = $( this ), - elemWidth = elem.outerWidth(), - elemHeight = elem.outerHeight(), - marginLeft = parseCss( this, "marginLeft" ), - marginTop = parseCss( this, "marginTop" ), - collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, - collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, - position = $.extend( {}, basePosition ), - myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); - - if ( options.my[ 0 ] === "right" ) { - position.left -= elemWidth; - } else if ( options.my[ 0 ] === "center" ) { - position.left -= elemWidth / 2; - } - - if ( options.my[ 1 ] === "bottom" ) { - position.top -= elemHeight; - } else if ( options.my[ 1 ] === "center" ) { - position.top -= elemHeight / 2; - } - - position.left += myOffset[ 0 ]; - position.top += myOffset[ 1 ]; - - // if the browser doesn't support fractions, then round for consistent results - if ( !$.support.offsetFractions ) { - position.left = round( position.left ); - position.top = round( position.top ); - } - - collisionPosition = { - marginLeft: marginLeft, - marginTop: marginTop - }; - - $.each( [ "left", "top" ], function( i, dir ) { - if ( $.ui.position[ collision[ i ] ] ) { - $.ui.position[ collision[ i ] ][ dir ]( position, { - targetWidth: targetWidth, - targetHeight: targetHeight, - elemWidth: elemWidth, - elemHeight: elemHeight, - collisionPosition: collisionPosition, - collisionWidth: collisionWidth, - collisionHeight: collisionHeight, - offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], - my: options.my, - at: options.at, - within: within, - elem : elem - }); - } - }); - - if ( options.using ) { - // adds feedback as second argument to using callback, if present - using = function( props ) { - var left = targetOffset.left - position.left, - right = left + targetWidth - elemWidth, - top = targetOffset.top - position.top, - bottom = top + targetHeight - elemHeight, - feedback = { - target: { - element: target, - left: targetOffset.left, - top: targetOffset.top, - width: targetWidth, - height: targetHeight - }, - element: { - element: elem, - left: position.left, - top: position.top, - width: elemWidth, - height: elemHeight - }, - horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", - vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" - }; - if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { - feedback.horizontal = "center"; - } - if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { - feedback.vertical = "middle"; - } - if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { - feedback.important = "horizontal"; - } else { - feedback.important = "vertical"; - } - options.using.call( this, props, feedback ); - }; - } - - elem.offset( $.extend( position, { using: using } ) ); - }); -}; - -$.ui.position = { - fit: { - left: function( position, data ) { - var within = data.within, - withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, - outerWidth = within.width, - collisionPosLeft = position.left - data.collisionPosition.marginLeft, - overLeft = withinOffset - collisionPosLeft, - overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, - newOverRight; - - // element is wider than within - if ( data.collisionWidth > outerWidth ) { - // element is initially over the left side of within - if ( overLeft > 0 && overRight <= 0 ) { - newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; - position.left += overLeft - newOverRight; - // element is initially over right side of within - } else if ( overRight > 0 && overLeft <= 0 ) { - position.left = withinOffset; - // element is initially over both left and right sides of within - } else { - if ( overLeft > overRight ) { - position.left = withinOffset + outerWidth - data.collisionWidth; - } else { - position.left = withinOffset; - } - } - // too far left -> align with left edge - } else if ( overLeft > 0 ) { - position.left += overLeft; - // too far right -> align with right edge - } else if ( overRight > 0 ) { - position.left -= overRight; - // adjust based on position and margin - } else { - position.left = max( position.left - collisionPosLeft, position.left ); - } - }, - top: function( position, data ) { - var within = data.within, - withinOffset = within.isWindow ? within.scrollTop : within.offset.top, - outerHeight = data.within.height, - collisionPosTop = position.top - data.collisionPosition.marginTop, - overTop = withinOffset - collisionPosTop, - overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, - newOverBottom; - - // element is taller than within - if ( data.collisionHeight > outerHeight ) { - // element is initially over the top of within - if ( overTop > 0 && overBottom <= 0 ) { - newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; - position.top += overTop - newOverBottom; - // element is initially over bottom of within - } else if ( overBottom > 0 && overTop <= 0 ) { - position.top = withinOffset; - // element is initially over both top and bottom of within - } else { - if ( overTop > overBottom ) { - position.top = withinOffset + outerHeight - data.collisionHeight; - } else { - position.top = withinOffset; - } - } - // too far up -> align with top - } else if ( overTop > 0 ) { - position.top += overTop; - // too far down -> align with bottom edge - } else if ( overBottom > 0 ) { - position.top -= overBottom; - // adjust based on position and margin - } else { - position.top = max( position.top - collisionPosTop, position.top ); - } - } - }, - flip: { - left: function( position, data ) { - var within = data.within, - withinOffset = within.offset.left + within.scrollLeft, - outerWidth = within.width, - offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, - collisionPosLeft = position.left - data.collisionPosition.marginLeft, - overLeft = collisionPosLeft - offsetLeft, - overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, - myOffset = data.my[ 0 ] === "left" ? - -data.elemWidth : - data.my[ 0 ] === "right" ? - data.elemWidth : - 0, - atOffset = data.at[ 0 ] === "left" ? - data.targetWidth : - data.at[ 0 ] === "right" ? - -data.targetWidth : - 0, - offset = -2 * data.offset[ 0 ], - newOverRight, - newOverLeft; - - if ( overLeft < 0 ) { - newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; - if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { - position.left += myOffset + atOffset + offset; - } - } - else if ( overRight > 0 ) { - newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; - if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { - position.left += myOffset + atOffset + offset; - } - } - }, - top: function( position, data ) { - var within = data.within, - withinOffset = within.offset.top + within.scrollTop, - outerHeight = within.height, - offsetTop = within.isWindow ? within.scrollTop : within.offset.top, - collisionPosTop = position.top - data.collisionPosition.marginTop, - overTop = collisionPosTop - offsetTop, - overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, - top = data.my[ 1 ] === "top", - myOffset = top ? - -data.elemHeight : - data.my[ 1 ] === "bottom" ? - data.elemHeight : - 0, - atOffset = data.at[ 1 ] === "top" ? - data.targetHeight : - data.at[ 1 ] === "bottom" ? - -data.targetHeight : - 0, - offset = -2 * data.offset[ 1 ], - newOverTop, - newOverBottom; - if ( overTop < 0 ) { - newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; - if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) { - position.top += myOffset + atOffset + offset; - } - } - else if ( overBottom > 0 ) { - newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; - if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) { - position.top += myOffset + atOffset + offset; - } - } - } - }, - flipfit: { - left: function() { - $.ui.position.flip.left.apply( this, arguments ); - $.ui.position.fit.left.apply( this, arguments ); - }, - top: function() { - $.ui.position.flip.top.apply( this, arguments ); - $.ui.position.fit.top.apply( this, arguments ); - } - } -}; - -// fraction support test -(function () { - var testElement, testElementParent, testElementStyle, offsetLeft, i, - body = document.getElementsByTagName( "body" )[ 0 ], - div = document.createElement( "div" ); - - //Create a "fake body" for testing based on method used in jQuery.support - testElement = document.createElement( body ? "div" : "body" ); - testElementStyle = { - visibility: "hidden", - width: 0, - height: 0, - border: 0, - margin: 0, - background: "none" - }; - if ( body ) { - $.extend( testElementStyle, { - position: "absolute", - left: "-1000px", - top: "-1000px" - }); - } - for ( i in testElementStyle ) { - testElement.style[ i ] = testElementStyle[ i ]; - } - testElement.appendChild( div ); - testElementParent = body || document.documentElement; - testElementParent.insertBefore( testElement, testElementParent.firstChild ); - - div.style.cssText = "position: absolute; left: 10.7432222px;"; - - offsetLeft = $( div ).offset().left; - $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11; - - testElement.innerHTML = ""; - testElementParent.removeChild( testElement ); -})(); - -}( jQuery ) ); diff --git a/extensions/yii/jui/assets/jquery.ui.progressbar.js b/extensions/yii/jui/assets/jquery.ui.progressbar.js deleted file mode 100644 index 70d716e..0000000 --- a/extensions/yii/jui/assets/jquery.ui.progressbar.js +++ /dev/null @@ -1,145 +0,0 @@ -/*! - * jQuery UI Progressbar 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/progressbar/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -$.widget( "ui.progressbar", { - version: "1.10.3", - options: { - max: 100, - value: 0, - - change: null, - complete: null - }, - - min: 0, - - _create: function() { - // Constrain initial value - this.oldValue = this.options.value = this._constrainedValue(); - - this.element - .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) - .attr({ - // Only set static values, aria-valuenow and aria-valuemax are - // set inside _refreshValue() - role: "progressbar", - "aria-valuemin": this.min - }); - - this.valueDiv = $( "
        " ) - .appendTo( this.element ); - - this._refreshValue(); - }, - - _destroy: function() { - this.element - .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) - .removeAttr( "role" ) - .removeAttr( "aria-valuemin" ) - .removeAttr( "aria-valuemax" ) - .removeAttr( "aria-valuenow" ); - - this.valueDiv.remove(); - }, - - value: function( newValue ) { - if ( newValue === undefined ) { - return this.options.value; - } - - this.options.value = this._constrainedValue( newValue ); - this._refreshValue(); - }, - - _constrainedValue: function( newValue ) { - if ( newValue === undefined ) { - newValue = this.options.value; - } - - this.indeterminate = newValue === false; - - // sanitize value - if ( typeof newValue !== "number" ) { - newValue = 0; - } - - return this.indeterminate ? false : - Math.min( this.options.max, Math.max( this.min, newValue ) ); - }, - - _setOptions: function( options ) { - // Ensure "value" option is set after other values (like max) - var value = options.value; - delete options.value; - - this._super( options ); - - this.options.value = this._constrainedValue( value ); - this._refreshValue(); - }, - - _setOption: function( key, value ) { - if ( key === "max" ) { - // Don't allow a max less than min - value = Math.max( this.min, value ); - } - - this._super( key, value ); - }, - - _percentage: function() { - return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min ); - }, - - _refreshValue: function() { - var value = this.options.value, - percentage = this._percentage(); - - this.valueDiv - .toggle( this.indeterminate || value > this.min ) - .toggleClass( "ui-corner-right", value === this.options.max ) - .width( percentage.toFixed(0) + "%" ); - - this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate ); - - if ( this.indeterminate ) { - this.element.removeAttr( "aria-valuenow" ); - if ( !this.overlayDiv ) { - this.overlayDiv = $( "
        " ).appendTo( this.valueDiv ); - } - } else { - this.element.attr({ - "aria-valuemax": this.options.max, - "aria-valuenow": value - }); - if ( this.overlayDiv ) { - this.overlayDiv.remove(); - this.overlayDiv = null; - } - } - - if ( this.oldValue !== value ) { - this.oldValue = value; - this._trigger( "change" ); - } - if ( value === this.options.max ) { - this._trigger( "complete" ); - } - } -}); - -})( jQuery ); diff --git a/extensions/yii/jui/assets/jquery.ui.resizable.js b/extensions/yii/jui/assets/jquery.ui.resizable.js deleted file mode 100644 index f007732..0000000 --- a/extensions/yii/jui/assets/jquery.ui.resizable.js +++ /dev/null @@ -1,968 +0,0 @@ -/*! - * jQuery UI Resizable 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/resizable/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -function num(v) { - return parseInt(v, 10) || 0; -} - -function isNumber(value) { - return !isNaN(parseInt(value, 10)); -} - -$.widget("ui.resizable", $.ui.mouse, { - version: "1.10.3", - widgetEventPrefix: "resize", - options: { - alsoResize: false, - animate: false, - animateDuration: "slow", - animateEasing: "swing", - aspectRatio: false, - autoHide: false, - containment: false, - ghost: false, - grid: false, - handles: "e,s,se", - helper: false, - maxHeight: null, - maxWidth: null, - minHeight: 10, - minWidth: 10, - // See #7960 - zIndex: 90, - - // callbacks - resize: null, - start: null, - stop: null - }, - _create: function() { - - var n, i, handle, axis, hname, - that = this, - o = this.options; - this.element.addClass("ui-resizable"); - - $.extend(this, { - _aspectRatio: !!(o.aspectRatio), - aspectRatio: o.aspectRatio, - originalElement: this.element, - _proportionallyResizeElements: [], - _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null - }); - - //Wrap the element if it cannot hold child nodes - if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { - - //Create a wrapper element and set the wrapper to the new current internal element - this.element.wrap( - $("
        ").css({ - position: this.element.css("position"), - width: this.element.outerWidth(), - height: this.element.outerHeight(), - top: this.element.css("top"), - left: this.element.css("left") - }) - ); - - //Overwrite the original this.element - this.element = this.element.parent().data( - "ui-resizable", this.element.data("ui-resizable") - ); - - this.elementIsWrapper = true; - - //Move margins to the wrapper - this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); - this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); - - //Prevent Safari textarea resize - this.originalResizeStyle = this.originalElement.css("resize"); - this.originalElement.css("resize", "none"); - - //Push the actual element to our proportionallyResize internal array - this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" })); - - // avoid IE jump (hard set the margin) - this.originalElement.css({ margin: this.originalElement.css("margin") }); - - // fix handlers offset - this._proportionallyResize(); - - } - - this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" }); - if(this.handles.constructor === String) { - - if ( this.handles === "all") { - this.handles = "n,e,s,w,se,sw,ne,nw"; - } - - n = this.handles.split(","); - this.handles = {}; - - for(i = 0; i < n.length; i++) { - - handle = $.trim(n[i]); - hname = "ui-resizable-"+handle; - axis = $("
        "); - - // Apply zIndex to all handles - see #7960 - axis.css({ zIndex: o.zIndex }); - - //TODO : What's going on here? - if ("se" === handle) { - axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se"); - } - - //Insert into internal handles object and append to element - this.handles[handle] = ".ui-resizable-"+handle; - this.element.append(axis); - } - - } - - this._renderAxis = function(target) { - - var i, axis, padPos, padWrapper; - - target = target || this.element; - - for(i in this.handles) { - - if(this.handles[i].constructor === String) { - this.handles[i] = $(this.handles[i], this.element).show(); - } - - //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) - if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { - - axis = $(this.handles[i], this.element); - - //Checking the correct pad and border - padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); - - //The padding type i have to apply... - padPos = [ "padding", - /ne|nw|n/.test(i) ? "Top" : - /se|sw|s/.test(i) ? "Bottom" : - /^e$/.test(i) ? "Right" : "Left" ].join(""); - - target.css(padPos, padWrapper); - - this._proportionallyResize(); - - } - - //TODO: What's that good for? There's not anything to be executed left - if(!$(this.handles[i]).length) { - continue; - } - } - }; - - //TODO: make renderAxis a prototype function - this._renderAxis(this.element); - - this._handles = $(".ui-resizable-handle", this.element) - .disableSelection(); - - //Matching axis name - this._handles.mouseover(function() { - if (!that.resizing) { - if (this.className) { - axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); - } - //Axis, default = se - that.axis = axis && axis[1] ? axis[1] : "se"; - } - }); - - //If we want to auto hide the elements - if (o.autoHide) { - this._handles.hide(); - $(this.element) - .addClass("ui-resizable-autohide") - .mouseenter(function() { - if (o.disabled) { - return; - } - $(this).removeClass("ui-resizable-autohide"); - that._handles.show(); - }) - .mouseleave(function(){ - if (o.disabled) { - return; - } - if (!that.resizing) { - $(this).addClass("ui-resizable-autohide"); - that._handles.hide(); - } - }); - } - - //Initialize the mouse interaction - this._mouseInit(); - - }, - - _destroy: function() { - - this._mouseDestroy(); - - var wrapper, - _destroy = function(exp) { - $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") - .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove(); - }; - - //TODO: Unwrap at same DOM position - if (this.elementIsWrapper) { - _destroy(this.element); - wrapper = this.element; - this.originalElement.css({ - position: wrapper.css("position"), - width: wrapper.outerWidth(), - height: wrapper.outerHeight(), - top: wrapper.css("top"), - left: wrapper.css("left") - }).insertAfter( wrapper ); - wrapper.remove(); - } - - this.originalElement.css("resize", this.originalResizeStyle); - _destroy(this.originalElement); - - return this; - }, - - _mouseCapture: function(event) { - var i, handle, - capture = false; - - for (i in this.handles) { - handle = $(this.handles[i])[0]; - if (handle === event.target || $.contains(handle, event.target)) { - capture = true; - } - } - - return !this.options.disabled && capture; - }, - - _mouseStart: function(event) { - - var curleft, curtop, cursor, - o = this.options, - iniPos = this.element.position(), - el = this.element; - - this.resizing = true; - - // bugfix for http://dev.jquery.com/ticket/1749 - if ( (/absolute/).test( el.css("position") ) ) { - el.css({ position: "absolute", top: el.css("top"), left: el.css("left") }); - } else if (el.is(".ui-draggable")) { - el.css({ position: "absolute", top: iniPos.top, left: iniPos.left }); - } - - this._renderProxy(); - - curleft = num(this.helper.css("left")); - curtop = num(this.helper.css("top")); - - if (o.containment) { - curleft += $(o.containment).scrollLeft() || 0; - curtop += $(o.containment).scrollTop() || 0; - } - - //Store needed variables - this.offset = this.helper.offset(); - this.position = { left: curleft, top: curtop }; - this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; - this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; - this.originalPosition = { left: curleft, top: curtop }; - this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; - this.originalMousePosition = { left: event.pageX, top: event.pageY }; - - //Aspect Ratio - this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); - - cursor = $(".ui-resizable-" + this.axis).css("cursor"); - $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor); - - el.addClass("ui-resizable-resizing"); - this._propagate("start", event); - return true; - }, - - _mouseDrag: function(event) { - - //Increase performance, avoid regex - var data, - el = this.helper, props = {}, - smp = this.originalMousePosition, - a = this.axis, - prevTop = this.position.top, - prevLeft = this.position.left, - prevWidth = this.size.width, - prevHeight = this.size.height, - dx = (event.pageX-smp.left)||0, - dy = (event.pageY-smp.top)||0, - trigger = this._change[a]; - - if (!trigger) { - return false; - } - - // Calculate the attrs that will be change - data = trigger.apply(this, [event, dx, dy]); - - // Put this in the mouseDrag handler since the user can start pressing shift while resizing - this._updateVirtualBoundaries(event.shiftKey); - if (this._aspectRatio || event.shiftKey) { - data = this._updateRatio(data, event); - } - - data = this._respectSize(data, event); - - this._updateCache(data); - - // plugins callbacks need to be called first - this._propagate("resize", event); - - if (this.position.top !== prevTop) { - props.top = this.position.top + "px"; - } - if (this.position.left !== prevLeft) { - props.left = this.position.left + "px"; - } - if (this.size.width !== prevWidth) { - props.width = this.size.width + "px"; - } - if (this.size.height !== prevHeight) { - props.height = this.size.height + "px"; - } - el.css(props); - - if (!this._helper && this._proportionallyResizeElements.length) { - this._proportionallyResize(); - } - - // Call the user callback if the element was resized - if ( ! $.isEmptyObject(props) ) { - this._trigger("resize", event, this.ui()); - } - - return false; - }, - - _mouseStop: function(event) { - - this.resizing = false; - var pr, ista, soffseth, soffsetw, s, left, top, - o = this.options, that = this; - - if(this._helper) { - - pr = this._proportionallyResizeElements; - ista = pr.length && (/textarea/i).test(pr[0].nodeName); - soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height; - soffsetw = ista ? 0 : that.sizeDiff.width; - - s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) }; - left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null; - top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; - - if (!o.animate) { - this.element.css($.extend(s, { top: top, left: left })); - } - - that.helper.height(that.size.height); - that.helper.width(that.size.width); - - if (this._helper && !o.animate) { - this._proportionallyResize(); - } - } - - $("body").css("cursor", "auto"); - - this.element.removeClass("ui-resizable-resizing"); - - this._propagate("stop", event); - - if (this._helper) { - this.helper.remove(); - } - - return false; - - }, - - _updateVirtualBoundaries: function(forceAspectRatio) { - var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, - o = this.options; - - b = { - minWidth: isNumber(o.minWidth) ? o.minWidth : 0, - maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity, - minHeight: isNumber(o.minHeight) ? o.minHeight : 0, - maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity - }; - - if(this._aspectRatio || forceAspectRatio) { - // We want to create an enclosing box whose aspect ration is the requested one - // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension - pMinWidth = b.minHeight * this.aspectRatio; - pMinHeight = b.minWidth / this.aspectRatio; - pMaxWidth = b.maxHeight * this.aspectRatio; - pMaxHeight = b.maxWidth / this.aspectRatio; - - if(pMinWidth > b.minWidth) { - b.minWidth = pMinWidth; - } - if(pMinHeight > b.minHeight) { - b.minHeight = pMinHeight; - } - if(pMaxWidth < b.maxWidth) { - b.maxWidth = pMaxWidth; - } - if(pMaxHeight < b.maxHeight) { - b.maxHeight = pMaxHeight; - } - } - this._vBoundaries = b; - }, - - _updateCache: function(data) { - this.offset = this.helper.offset(); - if (isNumber(data.left)) { - this.position.left = data.left; - } - if (isNumber(data.top)) { - this.position.top = data.top; - } - if (isNumber(data.height)) { - this.size.height = data.height; - } - if (isNumber(data.width)) { - this.size.width = data.width; - } - }, - - _updateRatio: function( data ) { - - var cpos = this.position, - csize = this.size, - a = this.axis; - - if (isNumber(data.height)) { - data.width = (data.height * this.aspectRatio); - } else if (isNumber(data.width)) { - data.height = (data.width / this.aspectRatio); - } - - if (a === "sw") { - data.left = cpos.left + (csize.width - data.width); - data.top = null; - } - if (a === "nw") { - data.top = cpos.top + (csize.height - data.height); - data.left = cpos.left + (csize.width - data.width); - } - - return data; - }, - - _respectSize: function( data ) { - - var o = this._vBoundaries, - a = this.axis, - ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), - isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height), - dw = this.originalPosition.left + this.originalSize.width, - dh = this.position.top + this.size.height, - cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); - if (isminw) { - data.width = o.minWidth; - } - if (isminh) { - data.height = o.minHeight; - } - if (ismaxw) { - data.width = o.maxWidth; - } - if (ismaxh) { - data.height = o.maxHeight; - } - - if (isminw && cw) { - data.left = dw - o.minWidth; - } - if (ismaxw && cw) { - data.left = dw - o.maxWidth; - } - if (isminh && ch) { - data.top = dh - o.minHeight; - } - if (ismaxh && ch) { - data.top = dh - o.maxHeight; - } - - // fixing jump error on top/left - bug #2330 - if (!data.width && !data.height && !data.left && data.top) { - data.top = null; - } else if (!data.width && !data.height && !data.top && data.left) { - data.left = null; - } - - return data; - }, - - _proportionallyResize: function() { - - if (!this._proportionallyResizeElements.length) { - return; - } - - var i, j, borders, paddings, prel, - element = this.helper || this.element; - - for ( i=0; i < this._proportionallyResizeElements.length; i++) { - - prel = this._proportionallyResizeElements[i]; - - if (!this.borderDif) { - this.borderDif = []; - borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")]; - paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")]; - - for ( j = 0; j < borders.length; j++ ) { - this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 ); - } - } - - prel.css({ - height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, - width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 - }); - - } - - }, - - _renderProxy: function() { - - var el = this.element, o = this.options; - this.elementOffset = el.offset(); - - if(this._helper) { - - this.helper = this.helper || $("
        "); - - this.helper.addClass(this._helper).css({ - width: this.element.outerWidth() - 1, - height: this.element.outerHeight() - 1, - position: "absolute", - left: this.elementOffset.left +"px", - top: this.elementOffset.top +"px", - zIndex: ++o.zIndex //TODO: Don't modify option - }); - - this.helper - .appendTo("body") - .disableSelection(); - - } else { - this.helper = this.element; - } - - }, - - _change: { - e: function(event, dx) { - return { width: this.originalSize.width + dx }; - }, - w: function(event, dx) { - var cs = this.originalSize, sp = this.originalPosition; - return { left: sp.left + dx, width: cs.width - dx }; - }, - n: function(event, dx, dy) { - var cs = this.originalSize, sp = this.originalPosition; - return { top: sp.top + dy, height: cs.height - dy }; - }, - s: function(event, dx, dy) { - return { height: this.originalSize.height + dy }; - }, - se: function(event, dx, dy) { - return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); - }, - sw: function(event, dx, dy) { - return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); - }, - ne: function(event, dx, dy) { - return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); - }, - nw: function(event, dx, dy) { - return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); - } - }, - - _propagate: function(n, event) { - $.ui.plugin.call(this, n, [event, this.ui()]); - (n !== "resize" && this._trigger(n, event, this.ui())); - }, - - plugins: {}, - - ui: function() { - return { - originalElement: this.originalElement, - element: this.element, - helper: this.helper, - position: this.position, - size: this.size, - originalSize: this.originalSize, - originalPosition: this.originalPosition - }; - } - -}); - -/* - * Resizable Extensions - */ - -$.ui.plugin.add("resizable", "animate", { - - stop: function( event ) { - var that = $(this).data("ui-resizable"), - o = that.options, - pr = that._proportionallyResizeElements, - ista = pr.length && (/textarea/i).test(pr[0].nodeName), - soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height, - soffsetw = ista ? 0 : that.sizeDiff.width, - style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, - left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null, - top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; - - that.element.animate( - $.extend(style, top && left ? { top: top, left: left } : {}), { - duration: o.animateDuration, - easing: o.animateEasing, - step: function() { - - var data = { - width: parseInt(that.element.css("width"), 10), - height: parseInt(that.element.css("height"), 10), - top: parseInt(that.element.css("top"), 10), - left: parseInt(that.element.css("left"), 10) - }; - - if (pr && pr.length) { - $(pr[0]).css({ width: data.width, height: data.height }); - } - - // propagating resize, and updating values for each animation step - that._updateCache(data); - that._propagate("resize", event); - - } - } - ); - } - -}); - -$.ui.plugin.add("resizable", "containment", { - - start: function() { - var element, p, co, ch, cw, width, height, - that = $(this).data("ui-resizable"), - o = that.options, - el = that.element, - oc = o.containment, - ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; - - if (!ce) { - return; - } - - that.containerElement = $(ce); - - if (/document/.test(oc) || oc === document) { - that.containerOffset = { left: 0, top: 0 }; - that.containerPosition = { left: 0, top: 0 }; - - that.parentData = { - element: $(document), left: 0, top: 0, - width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight - }; - } - - // i'm a node, so compute top, left, right, bottom - else { - element = $(ce); - p = []; - $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); - - that.containerOffset = element.offset(); - that.containerPosition = element.position(); - that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; - - co = that.containerOffset; - ch = that.containerSize.height; - cw = that.containerSize.width; - width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ); - height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); - - that.parentData = { - element: ce, left: co.left, top: co.top, width: width, height: height - }; - } - }, - - resize: function( event ) { - var woset, hoset, isParent, isOffsetRelative, - that = $(this).data("ui-resizable"), - o = that.options, - co = that.containerOffset, cp = that.position, - pRatio = that._aspectRatio || event.shiftKey, - cop = { top:0, left:0 }, ce = that.containerElement; - - if (ce[0] !== document && (/static/).test(ce.css("position"))) { - cop = co; - } - - if (cp.left < (that._helper ? co.left : 0)) { - that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left)); - if (pRatio) { - that.size.height = that.size.width / that.aspectRatio; - } - that.position.left = o.helper ? co.left : 0; - } - - if (cp.top < (that._helper ? co.top : 0)) { - that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top); - if (pRatio) { - that.size.width = that.size.height * that.aspectRatio; - } - that.position.top = that._helper ? co.top : 0; - } - - that.offset.left = that.parentData.left+that.position.left; - that.offset.top = that.parentData.top+that.position.top; - - woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ); - hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height ); - - isParent = that.containerElement.get(0) === that.element.parent().get(0); - isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position")); - - if(isParent && isOffsetRelative) { - woset -= that.parentData.left; - } - - if (woset + that.size.width >= that.parentData.width) { - that.size.width = that.parentData.width - woset; - if (pRatio) { - that.size.height = that.size.width / that.aspectRatio; - } - } - - if (hoset + that.size.height >= that.parentData.height) { - that.size.height = that.parentData.height - hoset; - if (pRatio) { - that.size.width = that.size.height * that.aspectRatio; - } - } - }, - - stop: function(){ - var that = $(this).data("ui-resizable"), - o = that.options, - co = that.containerOffset, - cop = that.containerPosition, - ce = that.containerElement, - helper = $(that.helper), - ho = helper.offset(), - w = helper.outerWidth() - that.sizeDiff.width, - h = helper.outerHeight() - that.sizeDiff.height; - - if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) { - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); - } - - if (that._helper && !o.animate && (/static/).test(ce.css("position"))) { - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); - } - - } -}); - -$.ui.plugin.add("resizable", "alsoResize", { - - start: function () { - var that = $(this).data("ui-resizable"), - o = that.options, - _store = function (exp) { - $(exp).each(function() { - var el = $(this); - el.data("ui-resizable-alsoresize", { - width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), - left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10) - }); - }); - }; - - if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) { - if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } - else { $.each(o.alsoResize, function (exp) { _store(exp); }); } - }else{ - _store(o.alsoResize); - } - }, - - resize: function (event, ui) { - var that = $(this).data("ui-resizable"), - o = that.options, - os = that.originalSize, - op = that.originalPosition, - delta = { - height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0, - top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0 - }, - - _alsoResize = function (exp, c) { - $(exp).each(function() { - var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {}, - css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"]; - - $.each(css, function (i, prop) { - var sum = (start[prop]||0) + (delta[prop]||0); - if (sum && sum >= 0) { - style[prop] = sum || null; - } - }); - - el.css(style); - }); - }; - - if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) { - $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); - }else{ - _alsoResize(o.alsoResize); - } - }, - - stop: function () { - $(this).removeData("resizable-alsoresize"); - } -}); - -$.ui.plugin.add("resizable", "ghost", { - - start: function() { - - var that = $(this).data("ui-resizable"), o = that.options, cs = that.size; - - that.ghost = that.originalElement.clone(); - that.ghost - .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) - .addClass("ui-resizable-ghost") - .addClass(typeof o.ghost === "string" ? o.ghost : ""); - - that.ghost.appendTo(that.helper); - - }, - - resize: function(){ - var that = $(this).data("ui-resizable"); - if (that.ghost) { - that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width }); - } - }, - - stop: function() { - var that = $(this).data("ui-resizable"); - if (that.ghost && that.helper) { - that.helper.get(0).removeChild(that.ghost.get(0)); - } - } - -}); - -$.ui.plugin.add("resizable", "grid", { - - resize: function() { - var that = $(this).data("ui-resizable"), - o = that.options, - cs = that.size, - os = that.originalSize, - op = that.originalPosition, - a = that.axis, - grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid, - gridX = (grid[0]||1), - gridY = (grid[1]||1), - ox = Math.round((cs.width - os.width) / gridX) * gridX, - oy = Math.round((cs.height - os.height) / gridY) * gridY, - newWidth = os.width + ox, - newHeight = os.height + oy, - isMaxWidth = o.maxWidth && (o.maxWidth < newWidth), - isMaxHeight = o.maxHeight && (o.maxHeight < newHeight), - isMinWidth = o.minWidth && (o.minWidth > newWidth), - isMinHeight = o.minHeight && (o.minHeight > newHeight); - - o.grid = grid; - - if (isMinWidth) { - newWidth = newWidth + gridX; - } - if (isMinHeight) { - newHeight = newHeight + gridY; - } - if (isMaxWidth) { - newWidth = newWidth - gridX; - } - if (isMaxHeight) { - newHeight = newHeight - gridY; - } - - if (/^(se|s|e)$/.test(a)) { - that.size.width = newWidth; - that.size.height = newHeight; - } else if (/^(ne)$/.test(a)) { - that.size.width = newWidth; - that.size.height = newHeight; - that.position.top = op.top - oy; - } else if (/^(sw)$/.test(a)) { - that.size.width = newWidth; - that.size.height = newHeight; - that.position.left = op.left - ox; - } else { - that.size.width = newWidth; - that.size.height = newHeight; - that.position.top = op.top - oy; - that.position.left = op.left - ox; - } - } - -}); - -})(jQuery); diff --git a/extensions/yii/jui/assets/jquery.ui.selectable.js b/extensions/yii/jui/assets/jquery.ui.selectable.js deleted file mode 100644 index e99ecb6..0000000 --- a/extensions/yii/jui/assets/jquery.ui.selectable.js +++ /dev/null @@ -1,277 +0,0 @@ -/*! - * jQuery UI Selectable 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/selectable/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -$.widget("ui.selectable", $.ui.mouse, { - version: "1.10.3", - options: { - appendTo: "body", - autoRefresh: true, - distance: 0, - filter: "*", - tolerance: "touch", - - // callbacks - selected: null, - selecting: null, - start: null, - stop: null, - unselected: null, - unselecting: null - }, - _create: function() { - var selectees, - that = this; - - this.element.addClass("ui-selectable"); - - this.dragged = false; - - // cache selectee children based on filter - this.refresh = function() { - selectees = $(that.options.filter, that.element[0]); - selectees.addClass("ui-selectee"); - selectees.each(function() { - var $this = $(this), - pos = $this.offset(); - $.data(this, "selectable-item", { - element: this, - $element: $this, - left: pos.left, - top: pos.top, - right: pos.left + $this.outerWidth(), - bottom: pos.top + $this.outerHeight(), - startselected: false, - selected: $this.hasClass("ui-selected"), - selecting: $this.hasClass("ui-selecting"), - unselecting: $this.hasClass("ui-unselecting") - }); - }); - }; - this.refresh(); - - this.selectees = selectees.addClass("ui-selectee"); - - this._mouseInit(); - - this.helper = $("
        "); - }, - - _destroy: function() { - this.selectees - .removeClass("ui-selectee") - .removeData("selectable-item"); - this.element - .removeClass("ui-selectable ui-selectable-disabled"); - this._mouseDestroy(); - }, - - _mouseStart: function(event) { - var that = this, - options = this.options; - - this.opos = [event.pageX, event.pageY]; - - if (this.options.disabled) { - return; - } - - this.selectees = $(options.filter, this.element[0]); - - this._trigger("start", event); - - $(options.appendTo).append(this.helper); - // position helper (lasso) - this.helper.css({ - "left": event.pageX, - "top": event.pageY, - "width": 0, - "height": 0 - }); - - if (options.autoRefresh) { - this.refresh(); - } - - this.selectees.filter(".ui-selected").each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.startselected = true; - if (!event.metaKey && !event.ctrlKey) { - selectee.$element.removeClass("ui-selected"); - selectee.selected = false; - selectee.$element.addClass("ui-unselecting"); - selectee.unselecting = true; - // selectable UNSELECTING callback - that._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - }); - - $(event.target).parents().addBack().each(function() { - var doSelect, - selectee = $.data(this, "selectable-item"); - if (selectee) { - doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected"); - selectee.$element - .removeClass(doSelect ? "ui-unselecting" : "ui-selected") - .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); - selectee.unselecting = !doSelect; - selectee.selecting = doSelect; - selectee.selected = doSelect; - // selectable (UN)SELECTING callback - if (doSelect) { - that._trigger("selecting", event, { - selecting: selectee.element - }); - } else { - that._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - return false; - } - }); - - }, - - _mouseDrag: function(event) { - - this.dragged = true; - - if (this.options.disabled) { - return; - } - - var tmp, - that = this, - options = this.options, - x1 = this.opos[0], - y1 = this.opos[1], - x2 = event.pageX, - y2 = event.pageY; - - if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; } - if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; } - this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); - - this.selectees.each(function() { - var selectee = $.data(this, "selectable-item"), - hit = false; - - //prevent helper from being selected if appendTo: selectable - if (!selectee || selectee.element === that.element[0]) { - return; - } - - if (options.tolerance === "touch") { - hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); - } else if (options.tolerance === "fit") { - hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); - } - - if (hit) { - // SELECT - if (selectee.selected) { - selectee.$element.removeClass("ui-selected"); - selectee.selected = false; - } - if (selectee.unselecting) { - selectee.$element.removeClass("ui-unselecting"); - selectee.unselecting = false; - } - if (!selectee.selecting) { - selectee.$element.addClass("ui-selecting"); - selectee.selecting = true; - // selectable SELECTING callback - that._trigger("selecting", event, { - selecting: selectee.element - }); - } - } else { - // UNSELECT - if (selectee.selecting) { - if ((event.metaKey || event.ctrlKey) && selectee.startselected) { - selectee.$element.removeClass("ui-selecting"); - selectee.selecting = false; - selectee.$element.addClass("ui-selected"); - selectee.selected = true; - } else { - selectee.$element.removeClass("ui-selecting"); - selectee.selecting = false; - if (selectee.startselected) { - selectee.$element.addClass("ui-unselecting"); - selectee.unselecting = true; - } - // selectable UNSELECTING callback - that._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - } - if (selectee.selected) { - if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { - selectee.$element.removeClass("ui-selected"); - selectee.selected = false; - - selectee.$element.addClass("ui-unselecting"); - selectee.unselecting = true; - // selectable UNSELECTING callback - that._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - } - } - }); - - return false; - }, - - _mouseStop: function(event) { - var that = this; - - this.dragged = false; - - $(".ui-unselecting", this.element[0]).each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass("ui-unselecting"); - selectee.unselecting = false; - selectee.startselected = false; - that._trigger("unselected", event, { - unselected: selectee.element - }); - }); - $(".ui-selecting", this.element[0]).each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass("ui-selecting").addClass("ui-selected"); - selectee.selecting = false; - selectee.selected = true; - selectee.startselected = true; - that._trigger("selected", event, { - selected: selectee.element - }); - }); - this._trigger("stop", event); - - this.helper.remove(); - - return false; - } - -}); - -})(jQuery); diff --git a/extensions/yii/jui/assets/jquery.ui.slider.js b/extensions/yii/jui/assets/jquery.ui.slider.js deleted file mode 100644 index b2c4aa3..0000000 --- a/extensions/yii/jui/assets/jquery.ui.slider.js +++ /dev/null @@ -1,672 +0,0 @@ -/*! - * jQuery UI Slider 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/slider/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -// number of pages in a slider -// (how many times can you page up/down to go through the whole range) -var numPages = 5; - -$.widget( "ui.slider", $.ui.mouse, { - version: "1.10.3", - widgetEventPrefix: "slide", - - options: { - animate: false, - distance: 0, - max: 100, - min: 0, - orientation: "horizontal", - range: false, - step: 1, - value: 0, - values: null, - - // callbacks - change: null, - slide: null, - start: null, - stop: null - }, - - _create: function() { - this._keySliding = false; - this._mouseSliding = false; - this._animateOff = true; - this._handleIndex = null; - this._detectOrientation(); - this._mouseInit(); - - this.element - .addClass( "ui-slider" + - " ui-slider-" + this.orientation + - " ui-widget" + - " ui-widget-content" + - " ui-corner-all"); - - this._refresh(); - this._setOption( "disabled", this.options.disabled ); - - this._animateOff = false; - }, - - _refresh: function() { - this._createRange(); - this._createHandles(); - this._setupEvents(); - this._refreshValue(); - }, - - _createHandles: function() { - var i, handleCount, - options = this.options, - existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), - handle = "", - handles = []; - - handleCount = ( options.values && options.values.length ) || 1; - - if ( existingHandles.length > handleCount ) { - existingHandles.slice( handleCount ).remove(); - existingHandles = existingHandles.slice( 0, handleCount ); - } - - for ( i = existingHandles.length; i < handleCount; i++ ) { - handles.push( handle ); - } - - this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); - - this.handle = this.handles.eq( 0 ); - - this.handles.each(function( i ) { - $( this ).data( "ui-slider-handle-index", i ); - }); - }, - - _createRange: function() { - var options = this.options, - classes = ""; - - if ( options.range ) { - if ( options.range === true ) { - if ( !options.values ) { - options.values = [ this._valueMin(), this._valueMin() ]; - } else if ( options.values.length && options.values.length !== 2 ) { - options.values = [ options.values[0], options.values[0] ]; - } else if ( $.isArray( options.values ) ) { - options.values = options.values.slice(0); - } - } - - if ( !this.range || !this.range.length ) { - this.range = $( "
        " ) - .appendTo( this.element ); - - classes = "ui-slider-range" + - // note: this isn't the most fittingly semantic framework class for this element, - // but worked best visually with a variety of themes - " ui-widget-header ui-corner-all"; - } else { - this.range.removeClass( "ui-slider-range-min ui-slider-range-max" ) - // Handle range switching from true to min/max - .css({ - "left": "", - "bottom": "" - }); - } - - this.range.addClass( classes + - ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) ); - } else { - this.range = $([]); - } - }, - - _setupEvents: function() { - var elements = this.handles.add( this.range ).filter( "a" ); - this._off( elements ); - this._on( elements, this._handleEvents ); - this._hoverable( elements ); - this._focusable( elements ); - }, - - _destroy: function() { - this.handles.remove(); - this.range.remove(); - - this.element - .removeClass( "ui-slider" + - " ui-slider-horizontal" + - " ui-slider-vertical" + - " ui-widget" + - " ui-widget-content" + - " ui-corner-all" ); - - this._mouseDestroy(); - }, - - _mouseCapture: function( event ) { - var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, - that = this, - o = this.options; - - if ( o.disabled ) { - return false; - } - - this.elementSize = { - width: this.element.outerWidth(), - height: this.element.outerHeight() - }; - this.elementOffset = this.element.offset(); - - position = { x: event.pageX, y: event.pageY }; - normValue = this._normValueFromMouse( position ); - distance = this._valueMax() - this._valueMin() + 1; - this.handles.each(function( i ) { - var thisDistance = Math.abs( normValue - that.values(i) ); - if (( distance > thisDistance ) || - ( distance === thisDistance && - (i === that._lastChangedValue || that.values(i) === o.min ))) { - distance = thisDistance; - closestHandle = $( this ); - index = i; - } - }); - - allowed = this._start( event, index ); - if ( allowed === false ) { - return false; - } - this._mouseSliding = true; - - this._handleIndex = index; - - closestHandle - .addClass( "ui-state-active" ) - .focus(); - - offset = closestHandle.offset(); - mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" ); - this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { - left: event.pageX - offset.left - ( closestHandle.width() / 2 ), - top: event.pageY - offset.top - - ( closestHandle.height() / 2 ) - - ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - - ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + - ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) - }; - - if ( !this.handles.hasClass( "ui-state-hover" ) ) { - this._slide( event, index, normValue ); - } - this._animateOff = true; - return true; - }, - - _mouseStart: function() { - return true; - }, - - _mouseDrag: function( event ) { - var position = { x: event.pageX, y: event.pageY }, - normValue = this._normValueFromMouse( position ); - - this._slide( event, this._handleIndex, normValue ); - - return false; - }, - - _mouseStop: function( event ) { - this.handles.removeClass( "ui-state-active" ); - this._mouseSliding = false; - - this._stop( event, this._handleIndex ); - this._change( event, this._handleIndex ); - - this._handleIndex = null; - this._clickOffset = null; - this._animateOff = false; - - return false; - }, - - _detectOrientation: function() { - this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; - }, - - _normValueFromMouse: function( position ) { - var pixelTotal, - pixelMouse, - percentMouse, - valueTotal, - valueMouse; - - if ( this.orientation === "horizontal" ) { - pixelTotal = this.elementSize.width; - pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); - } else { - pixelTotal = this.elementSize.height; - pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); - } - - percentMouse = ( pixelMouse / pixelTotal ); - if ( percentMouse > 1 ) { - percentMouse = 1; - } - if ( percentMouse < 0 ) { - percentMouse = 0; - } - if ( this.orientation === "vertical" ) { - percentMouse = 1 - percentMouse; - } - - valueTotal = this._valueMax() - this._valueMin(); - valueMouse = this._valueMin() + percentMouse * valueTotal; - - return this._trimAlignValue( valueMouse ); - }, - - _start: function( event, index ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - return this._trigger( "start", event, uiHash ); - }, - - _slide: function( event, index, newVal ) { - var otherVal, - newValues, - allowed; - - if ( this.options.values && this.options.values.length ) { - otherVal = this.values( index ? 0 : 1 ); - - if ( ( this.options.values.length === 2 && this.options.range === true ) && - ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) - ) { - newVal = otherVal; - } - - if ( newVal !== this.values( index ) ) { - newValues = this.values(); - newValues[ index ] = newVal; - // A slide can be canceled by returning false from the slide callback - allowed = this._trigger( "slide", event, { - handle: this.handles[ index ], - value: newVal, - values: newValues - } ); - otherVal = this.values( index ? 0 : 1 ); - if ( allowed !== false ) { - this.values( index, newVal, true ); - } - } - } else { - if ( newVal !== this.value() ) { - // A slide can be canceled by returning false from the slide callback - allowed = this._trigger( "slide", event, { - handle: this.handles[ index ], - value: newVal - } ); - if ( allowed !== false ) { - this.value( newVal ); - } - } - } - }, - - _stop: function( event, index ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - - this._trigger( "stop", event, uiHash ); - }, - - _change: function( event, index ) { - if ( !this._keySliding && !this._mouseSliding ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - - //store the last changed value index for reference when handles overlap - this._lastChangedValue = index; - - this._trigger( "change", event, uiHash ); - } - }, - - value: function( newValue ) { - if ( arguments.length ) { - this.options.value = this._trimAlignValue( newValue ); - this._refreshValue(); - this._change( null, 0 ); - return; - } - - return this._value(); - }, - - values: function( index, newValue ) { - var vals, - newValues, - i; - - if ( arguments.length > 1 ) { - this.options.values[ index ] = this._trimAlignValue( newValue ); - this._refreshValue(); - this._change( null, index ); - return; - } - - if ( arguments.length ) { - if ( $.isArray( arguments[ 0 ] ) ) { - vals = this.options.values; - newValues = arguments[ 0 ]; - for ( i = 0; i < vals.length; i += 1 ) { - vals[ i ] = this._trimAlignValue( newValues[ i ] ); - this._change( null, i ); - } - this._refreshValue(); - } else { - if ( this.options.values && this.options.values.length ) { - return this._values( index ); - } else { - return this.value(); - } - } - } else { - return this._values(); - } - }, - - _setOption: function( key, value ) { - var i, - valsLength = 0; - - if ( key === "range" && this.options.range === true ) { - if ( value === "min" ) { - this.options.value = this._values( 0 ); - this.options.values = null; - } else if ( value === "max" ) { - this.options.value = this._values( this.options.values.length-1 ); - this.options.values = null; - } - } - - if ( $.isArray( this.options.values ) ) { - valsLength = this.options.values.length; - } - - $.Widget.prototype._setOption.apply( this, arguments ); - - switch ( key ) { - case "orientation": - this._detectOrientation(); - this.element - .removeClass( "ui-slider-horizontal ui-slider-vertical" ) - .addClass( "ui-slider-" + this.orientation ); - this._refreshValue(); - break; - case "value": - this._animateOff = true; - this._refreshValue(); - this._change( null, 0 ); - this._animateOff = false; - break; - case "values": - this._animateOff = true; - this._refreshValue(); - for ( i = 0; i < valsLength; i += 1 ) { - this._change( null, i ); - } - this._animateOff = false; - break; - case "min": - case "max": - this._animateOff = true; - this._refreshValue(); - this._animateOff = false; - break; - case "range": - this._animateOff = true; - this._refresh(); - this._animateOff = false; - break; - } - }, - - //internal value getter - // _value() returns value trimmed by min and max, aligned by step - _value: function() { - var val = this.options.value; - val = this._trimAlignValue( val ); - - return val; - }, - - //internal values getter - // _values() returns array of values trimmed by min and max, aligned by step - // _values( index ) returns single value trimmed by min and max, aligned by step - _values: function( index ) { - var val, - vals, - i; - - if ( arguments.length ) { - val = this.options.values[ index ]; - val = this._trimAlignValue( val ); - - return val; - } else if ( this.options.values && this.options.values.length ) { - // .slice() creates a copy of the array - // this copy gets trimmed by min and max and then returned - vals = this.options.values.slice(); - for ( i = 0; i < vals.length; i+= 1) { - vals[ i ] = this._trimAlignValue( vals[ i ] ); - } - - return vals; - } else { - return []; - } - }, - - // returns the step-aligned value that val is closest to, between (inclusive) min and max - _trimAlignValue: function( val ) { - if ( val <= this._valueMin() ) { - return this._valueMin(); - } - if ( val >= this._valueMax() ) { - return this._valueMax(); - } - var step = ( this.options.step > 0 ) ? this.options.step : 1, - valModStep = (val - this._valueMin()) % step, - alignValue = val - valModStep; - - if ( Math.abs(valModStep) * 2 >= step ) { - alignValue += ( valModStep > 0 ) ? step : ( -step ); - } - - // Since JavaScript has problems with large floats, round - // the final value to 5 digits after the decimal point (see #4124) - return parseFloat( alignValue.toFixed(5) ); - }, - - _valueMin: function() { - return this.options.min; - }, - - _valueMax: function() { - return this.options.max; - }, - - _refreshValue: function() { - var lastValPercent, valPercent, value, valueMin, valueMax, - oRange = this.options.range, - o = this.options, - that = this, - animate = ( !this._animateOff ) ? o.animate : false, - _set = {}; - - if ( this.options.values && this.options.values.length ) { - this.handles.each(function( i ) { - valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100; - _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; - $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); - if ( that.options.range === true ) { - if ( that.orientation === "horizontal" ) { - if ( i === 0 ) { - that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); - } - if ( i === 1 ) { - that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } else { - if ( i === 0 ) { - that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); - } - if ( i === 1 ) { - that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } - } - lastValPercent = valPercent; - }); - } else { - value = this.value(); - valueMin = this._valueMin(); - valueMax = this._valueMax(); - valPercent = ( valueMax !== valueMin ) ? - ( value - valueMin ) / ( valueMax - valueMin ) * 100 : - 0; - _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; - this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); - - if ( oRange === "min" && this.orientation === "horizontal" ) { - this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); - } - if ( oRange === "max" && this.orientation === "horizontal" ) { - this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - if ( oRange === "min" && this.orientation === "vertical" ) { - this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); - } - if ( oRange === "max" && this.orientation === "vertical" ) { - this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } - }, - - _handleEvents: { - keydown: function( event ) { - /*jshint maxcomplexity:25*/ - var allowed, curVal, newVal, step, - index = $( event.target ).data( "ui-slider-handle-index" ); - - switch ( event.keyCode ) { - case $.ui.keyCode.HOME: - case $.ui.keyCode.END: - case $.ui.keyCode.PAGE_UP: - case $.ui.keyCode.PAGE_DOWN: - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - event.preventDefault(); - if ( !this._keySliding ) { - this._keySliding = true; - $( event.target ).addClass( "ui-state-active" ); - allowed = this._start( event, index ); - if ( allowed === false ) { - return; - } - } - break; - } - - step = this.options.step; - if ( this.options.values && this.options.values.length ) { - curVal = newVal = this.values( index ); - } else { - curVal = newVal = this.value(); - } - - switch ( event.keyCode ) { - case $.ui.keyCode.HOME: - newVal = this._valueMin(); - break; - case $.ui.keyCode.END: - newVal = this._valueMax(); - break; - case $.ui.keyCode.PAGE_UP: - newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) ); - break; - case $.ui.keyCode.PAGE_DOWN: - newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) ); - break; - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - if ( curVal === this._valueMax() ) { - return; - } - newVal = this._trimAlignValue( curVal + step ); - break; - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - if ( curVal === this._valueMin() ) { - return; - } - newVal = this._trimAlignValue( curVal - step ); - break; - } - - this._slide( event, index, newVal ); - }, - click: function( event ) { - event.preventDefault(); - }, - keyup: function( event ) { - var index = $( event.target ).data( "ui-slider-handle-index" ); - - if ( this._keySliding ) { - this._keySliding = false; - this._stop( event, index ); - this._change( event, index ); - $( event.target ).removeClass( "ui-state-active" ); - } - } - } - -}); - -}(jQuery)); diff --git a/extensions/yii/jui/assets/jquery.ui.sortable.js b/extensions/yii/jui/assets/jquery.ui.sortable.js deleted file mode 100644 index c9f2c90..0000000 --- a/extensions/yii/jui/assets/jquery.ui.sortable.js +++ /dev/null @@ -1,1285 +0,0 @@ -/*! - * jQuery UI Sortable 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/sortable/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -/*jshint loopfunc: true */ - -function isOverAxis( x, reference, size ) { - return ( x > reference ) && ( x < ( reference + size ) ); -} - -function isFloating(item) { - return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); -} - -$.widget("ui.sortable", $.ui.mouse, { - version: "1.10.3", - widgetEventPrefix: "sort", - ready: false, - options: { - appendTo: "parent", - axis: false, - connectWith: false, - containment: false, - cursor: "auto", - cursorAt: false, - dropOnEmpty: true, - forcePlaceholderSize: false, - forceHelperSize: false, - grid: false, - handle: false, - helper: "original", - items: "> *", - opacity: false, - placeholder: false, - revert: false, - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - scope: "default", - tolerance: "intersect", - zIndex: 1000, - - // callbacks - activate: null, - beforeStop: null, - change: null, - deactivate: null, - out: null, - over: null, - receive: null, - remove: null, - sort: null, - start: null, - stop: null, - update: null - }, - _create: function() { - - var o = this.options; - this.containerCache = {}; - this.element.addClass("ui-sortable"); - - //Get the items - this.refresh(); - - //Let's determine if the items are being displayed horizontally - this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false; - - //Let's determine the parent's offset - this.offset = this.element.offset(); - - //Initialize mouse events for interaction - this._mouseInit(); - - //We're ready to go - this.ready = true; - - }, - - _destroy: function() { - this.element - .removeClass("ui-sortable ui-sortable-disabled"); - this._mouseDestroy(); - - for ( var i = this.items.length - 1; i >= 0; i-- ) { - this.items[i].item.removeData(this.widgetName + "-item"); - } - - return this; - }, - - _setOption: function(key, value){ - if ( key === "disabled" ) { - this.options[ key ] = value; - - this.widget().toggleClass( "ui-sortable-disabled", !!value ); - } else { - // Don't call widget base _setOption for disable as it adds ui-state-disabled class - $.Widget.prototype._setOption.apply(this, arguments); - } - }, - - _mouseCapture: function(event, overrideHandle) { - var currentItem = null, - validHandle = false, - that = this; - - if (this.reverting) { - return false; - } - - if(this.options.disabled || this.options.type === "static") { - return false; - } - - //We have to refresh the items data once first - this._refreshItems(event); - - //Find out if the clicked node (or one of its parents) is a actual item in this.items - $(event.target).parents().each(function() { - if($.data(this, that.widgetName + "-item") === that) { - currentItem = $(this); - return false; - } - }); - if($.data(event.target, that.widgetName + "-item") === that) { - currentItem = $(event.target); - } - - if(!currentItem) { - return false; - } - if(this.options.handle && !overrideHandle) { - $(this.options.handle, currentItem).find("*").addBack().each(function() { - if(this === event.target) { - validHandle = true; - } - }); - if(!validHandle) { - return false; - } - } - - this.currentItem = currentItem; - this._removeCurrentsFromItems(); - return true; - - }, - - _mouseStart: function(event, overrideHandle, noActivation) { - - var i, body, - o = this.options; - - this.currentContainer = this; - - //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture - this.refreshPositions(); - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Get the next scrolling parent - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.currentItem.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - // Only after we got the offset, we can change the helper's position to absolute - // TODO: Still need to figure out a way to make relative sorting possible - this.helper.css("position", "absolute"); - this.cssPosition = this.helper.css("position"); - - //Generate the original position - this.originalPosition = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if "cursorAt" is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Cache the former DOM position - this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; - - //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] !== this.currentItem[0]) { - this.currentItem.hide(); - } - - //Create the placeholder - this._createPlaceholder(); - - //Set a containment if given in the options - if(o.containment) { - this._setContainment(); - } - - if( o.cursor && o.cursor !== "auto" ) { // cursor option - body = this.document.find( "body" ); - - // support: IE - this.storedCursor = body.css( "cursor" ); - body.css( "cursor", o.cursor ); - - this.storedStylesheet = $( "" ).appendTo( body ); - } - - if(o.opacity) { // opacity option - if (this.helper.css("opacity")) { - this._storedOpacity = this.helper.css("opacity"); - } - this.helper.css("opacity", o.opacity); - } - - if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) { - this._storedZIndex = this.helper.css("zIndex"); - } - this.helper.css("zIndex", o.zIndex); - } - - //Prepare scrolling - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - this.overflowOffset = this.scrollParent.offset(); - } - - //Call callbacks - this._trigger("start", event, this._uiHash()); - - //Recache the helper size - if(!this._preserveHelperProportions) { - this._cacheHelperProportions(); - } - - - //Post "activate" events to possible containers - if( !noActivation ) { - for ( i = this.containers.length - 1; i >= 0; i-- ) { - this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); - } - } - - //Prepare possible droppables - if($.ui.ddmanager) { - $.ui.ddmanager.current = this; - } - - if ($.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - - this.dragging = true; - - this.helper.addClass("ui-sortable-helper"); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - - }, - - _mouseDrag: function(event) { - var i, item, itemElement, intersection, - o = this.options, - scrolled = false; - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; - } - - //Do scrolling - if(this.options.scroll) { - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; - } - - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; - } - - } else { - - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } - - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - } - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - } - - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); - - //Set the helper position - if(!this.options.axis || this.options.axis !== "y") { - this.helper[0].style.left = this.position.left+"px"; - } - if(!this.options.axis || this.options.axis !== "x") { - this.helper[0].style.top = this.position.top+"px"; - } - - //Rearrange - for (i = this.items.length - 1; i >= 0; i--) { - - //Cache variables and intersection, continue if no intersection - item = this.items[i]; - itemElement = item.item[0]; - intersection = this._intersectsWithPointer(item); - if (!intersection) { - continue; - } - - // Only put the placeholder inside the current Container, skip all - // items form other containers. This works because when moving - // an item from one container to another the - // currentContainer is switched before the placeholder is moved. - // - // Without this moving items in "sub-sortables" can cause the placeholder to jitter - // beetween the outer and inner container. - if (item.instance !== this.currentContainer) { - continue; - } - - // cannot intersect with itself - // no useless actions that have been done before - // no action if the item moved is the parent of the item checked - if (itemElement !== this.currentItem[0] && - this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && - !$.contains(this.placeholder[0], itemElement) && - (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) - ) { - - this.direction = intersection === 1 ? "down" : "up"; - - if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { - break; - } - - this._trigger("change", event, this._uiHash()); - break; - } - } - - //Post events to containers - this._contactContainers(event); - - //Interconnect with droppables - if($.ui.ddmanager) { - $.ui.ddmanager.drag(this, event); - } - - //Call callbacks - this._trigger("sort", event, this._uiHash()); - - this.lastPositionAbs = this.positionAbs; - return false; - - }, - - _mouseStop: function(event, noPropagation) { - - if(!event) { - return; - } - - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) { - $.ui.ddmanager.drop(this, event); - } - - if(this.options.revert) { - var that = this, - cur = this.placeholder.offset(), - axis = this.options.axis, - animation = {}; - - if ( !axis || axis === "x" ) { - animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); - } - if ( !axis || axis === "y" ) { - animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); - } - this.reverting = true; - $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { - that._clear(event); - }); - } else { - this._clear(event, noPropagation); - } - - return false; - - }, - - cancel: function() { - - if(this.dragging) { - - this._mouseUp({ target: null }); - - if(this.options.helper === "original") { - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, this._uiHash(this)); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - if (this.placeholder) { - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) { - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - } - if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { - this.helper.remove(); - } - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); - - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); - } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - } - - return this; - - }, - - serialize: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - str = []; - o = o || {}; - - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); - if (res) { - str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); - } - }); - - if(!str.length && o.key) { - str.push(o.key + "="); - } - - return str.join("&"); - - }, - - toArray: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - ret = []; - - o = o || {}; - - items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); - return ret; - - }, - - /* Be careful with the following core functions */ - _intersectsWith: function(item) { - - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height, - l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height, - dyClick = this.offset.click.top, - dxClick = this.offset.click.left, - isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ), - isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ), - isOverElement = isOverElementHeight && isOverElementWidth; - - if ( this.options.tolerance === "pointer" || - this.options.forcePointerForContainers || - (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) - ) { - return isOverElement; - } else { - - return (l < x1 + (this.helperProportions.width / 2) && // Right Half - x2 - (this.helperProportions.width / 2) < r && // Left Half - t < y1 + (this.helperProportions.height / 2) && // Bottom Half - y2 - (this.helperProportions.height / 2) < b ); // Top Half - - } - }, - - _intersectsWithPointer: function(item) { - - var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), - isOverElement = isOverElementHeight && isOverElementWidth, - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (!isOverElement) { - return false; - } - - return this.floating ? - ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); - - }, - - _intersectsWithSides: function(item) { - - var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (this.floating && horizontalDirection) { - return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); - } else { - return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); - } - - }, - - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta !== 0 && (delta > 0 ? "down" : "up"); - }, - - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta !== 0 && (delta > 0 ? "right" : "left"); - }, - - refresh: function(event) { - this._refreshItems(event); - this.refreshPositions(); - return this; - }, - - _connectWith: function() { - var options = this.options; - return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; - }, - - _getItemsAsjQuery: function(connected) { - - var i, j, cur, inst, - items = [], - queries = [], - connectWith = this._connectWith(); - - if(connectWith && connected) { - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for ( j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); - } - } - } - } - - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); - - for (i = queries.length - 1; i >= 0; i--){ - queries[i][0].each(function() { - items.push(this); - }); - } - - return $(items); - - }, - - _removeCurrentsFromItems: function() { - - var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); - - this.items = $.grep(this.items, function (item) { - for (var j=0; j < list.length; j++) { - if(list[j] === item.item[0]) { - return false; - } - } - return true; - }); - - }, - - _refreshItems: function(event) { - - this.items = []; - this.containers = [this]; - - var i, j, cur, inst, targetData, _queries, item, queriesLength, - items = this.items, - queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], - connectWith = this._connectWith(); - - if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for (j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); - this.containers.push(inst); - } - } - } - } - - for (i = queries.length - 1; i >= 0; i--) { - targetData = queries[i][1]; - _queries = queries[i][0]; - - for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { - item = $(_queries[j]); - - item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) - - items.push({ - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - }); - } - } - - }, - - refreshPositions: function(fast) { - - //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change - if(this.offsetParent && this.helper) { - this.offset.parent = this._getParentOffset(); - } - - var i, item, t, p; - - for (i = this.items.length - 1; i >= 0; i--){ - item = this.items[i]; - - //We ignore calculating positions of all connected containers when we're not over them - if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { - continue; - } - - t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; - - if (!fast) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } - - p = t.offset(); - item.left = p.left; - item.top = p.top; - } - - if(this.options.custom && this.options.custom.refreshContainers) { - this.options.custom.refreshContainers.call(this); - } else { - for (i = this.containers.length - 1; i >= 0; i--){ - p = this.containers[i].element.offset(); - this.containers[i].containerCache.left = p.left; - this.containers[i].containerCache.top = p.top; - this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); - this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - } - } - - return this; - }, - - _createPlaceholder: function(that) { - that = that || this; - var className, - o = that.options; - - if(!o.placeholder || o.placeholder.constructor === String) { - className = o.placeholder; - o.placeholder = { - element: function() { - - var nodeName = that.currentItem[0].nodeName.toLowerCase(), - element = $( "<" + nodeName + ">", that.document[0] ) - .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") - .removeClass("ui-sortable-helper"); - - if ( nodeName === "tr" ) { - that.currentItem.children().each(function() { - $( " ", that.document[0] ) - .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) - .appendTo( element ); - }); - } else if ( nodeName === "img" ) { - element.attr( "src", that.currentItem.attr( "src" ) ); - } - - if ( !className ) { - element.css( "visibility", "hidden" ); - } - - return element; - }, - update: function(container, p) { - - // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) { - return; - } - - //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } - if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } - } - }; - } - - //Create the placeholder - that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); - - //Append it after the actual current item - that.currentItem.after(that.placeholder); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update(that, that.placeholder); - - }, - - _contactContainers: function(event) { - var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating, - innermostContainer = null, - innermostIndex = null; - - // get innermost container that intersects with item - for (i = this.containers.length - 1; i >= 0; i--) { - - // never consider a container that's located within the item itself - if($.contains(this.currentItem[0], this.containers[i].element[0])) { - continue; - } - - if(this._intersectsWith(this.containers[i].containerCache)) { - - // if we've already found a container and it's more "inner" than this, then continue - if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { - continue; - } - - innermostContainer = this.containers[i]; - innermostIndex = i; - - } else { - // container doesn't intersect. trigger "out" event if necessary - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - // if no intersecting containers found, return - if(!innermostContainer) { - return; - } - - // move the item into the container if it's not there already - if(this.containers.length === 1) { - if (!this.containers[innermostIndex].containerCache.over) { - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - } else { - - //When entering a new container, we will find the item with the least distance and append our item near it - dist = 10000; - itemWithLeastDistance = null; - floating = innermostContainer.floating || isFloating(this.currentItem); - posProperty = floating ? "left" : "top"; - sizeProperty = floating ? "width" : "height"; - base = this.positionAbs[posProperty] + this.offset.click[posProperty]; - for (j = this.items.length - 1; j >= 0; j--) { - if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { - continue; - } - if(this.items[j].item[0] === this.currentItem[0]) { - continue; - } - if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) { - continue; - } - cur = this.items[j].item.offset()[posProperty]; - nearBottom = false; - if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ - nearBottom = true; - cur += this.items[j][sizeProperty]; - } - - if(Math.abs(cur - base) < dist) { - dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; - this.direction = nearBottom ? "up": "down"; - } - } - - //Check if dropOnEmpty is enabled - if(!itemWithLeastDistance && !this.options.dropOnEmpty) { - return; - } - - if(this.currentContainer === this.containers[innermostIndex]) { - return; - } - - itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); - this._trigger("change", event, this._uiHash()); - this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); - this.currentContainer = this.containers[innermostIndex]; - - //Update the placeholder - this.options.placeholder.update(this.currentContainer, this.placeholder); - - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - - - }, - - _createHelper: function(event) { - - var o = this.options, - helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); - - //Add the helper to the DOM if that didn't happen already - if(!helper.parents("body").length) { - $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); - } - - if(helper[0] === this.currentItem[0]) { - this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; - } - - if(!helper[0].style.width || o.forceHelperSize) { - helper.width(this.currentItem.width()); - } - if(!helper[0].style.height || o.forceHelperSize) { - helper.height(this.currentItem.height()); - } - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj === "string") { - obj = obj.split(" "); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ("left" in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ("right" in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ("top" in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ("bottom" in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - // This needs to be actually done for all browsers, since pageX/pageY includes this information - // with an ugly IE fix - if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { - po = { top: 0, left: 0 }; - } - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition === "relative") { - var p = this.currentItem.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), - top: (parseInt(this.currentItem.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var ce, co, over, - o = this.options; - if(o.containment === "parent") { - o.containment = this.helper[0].parentNode; - } - if(o.containment === "document" || o.containment === "window") { - this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - } - - if(!(/^(document|window|parent)$/).test(o.containment)) { - ce = $(o.containment)[0]; - co = $(o.containment).offset(); - over = ($(ce).css("overflow") !== "hidden"); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) { - pos = this.position; - } - var mod = d === "absolute" ? 1 : -1, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, - scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top + // The absolute mouse position - this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left + // The absolute mouse position - this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var top, left, - o = this.options, - pageX = event.pageX, - pageY = event.pageY, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) { - pageX = this.containment[0] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top < this.containment[1]) { - pageY = this.containment[1] + this.offset.click.top; - } - if(event.pageX - this.offset.click.left > this.containment[2]) { - pageX = this.containment[2] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top > this.containment[3]) { - pageY = this.containment[3] + this.offset.click.top; - } - } - - if(o.grid) { - top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY - // The absolute mouse position - this.offset.click.top - // Click offset (relative to the element) - this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX - // The absolute mouse position - this.offset.click.left - // Click offset (relative to the element) - this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _rearrange: function(event, i, a, hardRefresh) { - - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); - - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var counter = this.counter; - - this._delay(function() { - if(counter === this.counter) { - this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove - } - }); - - }, - - _clear: function(event, noPropagation) { - - this.reverting = false; - // We delay all events that have to be triggered to after the point where the placeholder has been removed and - // everything else normalized again - var i, - delayedTriggers = []; - - // We first have to update the dom position of the actual currentItem - // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) - if(!this._noFinalSort && this.currentItem.parent().length) { - this.placeholder.before(this.currentItem); - } - this._noFinalSort = null; - - if(this.helper[0] === this.currentItem[0]) { - for(i in this._storedCSS) { - if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { - this._storedCSS[i] = ""; - } - } - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - if(this.fromOutside && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); - } - if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed - } - - // Check if the items Container has Changed and trigger appropriate - // events. - if (this !== this.currentContainer) { - if(!noPropagation) { - delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); - delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - } - } - - - //Post events to containers - for (i = this.containers.length - 1; i >= 0; i--){ - if(!noPropagation) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - } - if(this.containers[i].containerCache.over) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - this.containers[i].containerCache.over = 0; - } - } - - //Do what was originally in plugins - if ( this.storedCursor ) { - this.document.find( "body" ).css( "cursor", this.storedCursor ); - this.storedStylesheet.remove(); - } - if(this._storedOpacity) { - this.helper.css("opacity", this._storedOpacity); - } - if(this._storedZIndex) { - this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); - } - - this.dragging = false; - if(this.cancelHelperRemoval) { - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return false; - } - - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - } - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - - if(this.helper[0] !== this.currentItem[0]) { - this.helper.remove(); - } - this.helper = null; - - if(!noPropagation) { - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return true; - - }, - - _trigger: function() { - if ($.Widget.prototype._trigger.apply(this, arguments) === false) { - this.cancel(); - } - }, - - _uiHash: function(_inst) { - var inst = _inst || this; - return { - helper: inst.helper, - placeholder: inst.placeholder || $([]), - position: inst.position, - originalPosition: inst.originalPosition, - offset: inst.positionAbs, - item: inst.currentItem, - sender: _inst ? _inst.element : null - }; - } - -}); - -})(jQuery); diff --git a/extensions/yii/jui/assets/jquery.ui.spinner.js b/extensions/yii/jui/assets/jquery.ui.spinner.js deleted file mode 100644 index 5bfbb27..0000000 --- a/extensions/yii/jui/assets/jquery.ui.spinner.js +++ /dev/null @@ -1,493 +0,0 @@ -/*! - * jQuery UI Spinner 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/spinner/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.button.js - */ -(function( $ ) { - -function modifier( fn ) { - return function() { - var previous = this.element.val(); - fn.apply( this, arguments ); - this._refresh(); - if ( previous !== this.element.val() ) { - this._trigger( "change" ); - } - }; -} - -$.widget( "ui.spinner", { - version: "1.10.3", - defaultElement: "", - widgetEventPrefix: "spin", - options: { - culture: null, - icons: { - down: "ui-icon-triangle-1-s", - up: "ui-icon-triangle-1-n" - }, - incremental: true, - max: null, - min: null, - numberFormat: null, - page: 10, - step: 1, - - change: null, - spin: null, - start: null, - stop: null - }, - - _create: function() { - // handle string values that need to be parsed - this._setOption( "max", this.options.max ); - this._setOption( "min", this.options.min ); - this._setOption( "step", this.options.step ); - - // format the value, but don't constrain - this._value( this.element.val(), true ); - - this._draw(); - this._on( this._events ); - this._refresh(); - - // turning off autocomplete prevents the browser from remembering the - // value when navigating through history, so we re-enable autocomplete - // if the page is unloaded before the widget is destroyed. #7790 - this._on( this.window, { - beforeunload: function() { - this.element.removeAttr( "autocomplete" ); - } - }); - }, - - _getCreateOptions: function() { - var options = {}, - element = this.element; - - $.each( [ "min", "max", "step" ], function( i, option ) { - var value = element.attr( option ); - if ( value !== undefined && value.length ) { - options[ option ] = value; - } - }); - - return options; - }, - - _events: { - keydown: function( event ) { - if ( this._start( event ) && this._keydown( event ) ) { - event.preventDefault(); - } - }, - keyup: "_stop", - focus: function() { - this.previous = this.element.val(); - }, - blur: function( event ) { - if ( this.cancelBlur ) { - delete this.cancelBlur; - return; - } - - this._stop(); - this._refresh(); - if ( this.previous !== this.element.val() ) { - this._trigger( "change", event ); - } - }, - mousewheel: function( event, delta ) { - if ( !delta ) { - return; - } - if ( !this.spinning && !this._start( event ) ) { - return false; - } - - this._spin( (delta > 0 ? 1 : -1) * this.options.step, event ); - clearTimeout( this.mousewheelTimer ); - this.mousewheelTimer = this._delay(function() { - if ( this.spinning ) { - this._stop( event ); - } - }, 100 ); - event.preventDefault(); - }, - "mousedown .ui-spinner-button": function( event ) { - var previous; - - // We never want the buttons to have focus; whenever the user is - // interacting with the spinner, the focus should be on the input. - // If the input is focused then this.previous is properly set from - // when the input first received focus. If the input is not focused - // then we need to set this.previous based on the value before spinning. - previous = this.element[0] === this.document[0].activeElement ? - this.previous : this.element.val(); - function checkFocus() { - var isActive = this.element[0] === this.document[0].activeElement; - if ( !isActive ) { - this.element.focus(); - this.previous = previous; - // support: IE - // IE sets focus asynchronously, so we need to check if focus - // moved off of the input because the user clicked on the button. - this._delay(function() { - this.previous = previous; - }); - } - } - - // ensure focus is on (or stays on) the text field - event.preventDefault(); - checkFocus.call( this ); - - // support: IE - // IE doesn't prevent moving focus even with event.preventDefault() - // so we set a flag to know when we should ignore the blur event - // and check (again) if focus moved off of the input. - this.cancelBlur = true; - this._delay(function() { - delete this.cancelBlur; - checkFocus.call( this ); - }); - - if ( this._start( event ) === false ) { - return; - } - - this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); - }, - "mouseup .ui-spinner-button": "_stop", - "mouseenter .ui-spinner-button": function( event ) { - // button will add ui-state-active if mouse was down while mouseleave and kept down - if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { - return; - } - - if ( this._start( event ) === false ) { - return false; - } - this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); - }, - // TODO: do we really want to consider this a stop? - // shouldn't we just stop the repeater and wait until mouseup before - // we trigger the stop event? - "mouseleave .ui-spinner-button": "_stop" - }, - - _draw: function() { - var uiSpinner = this.uiSpinner = this.element - .addClass( "ui-spinner-input" ) - .attr( "autocomplete", "off" ) - .wrap( this._uiSpinnerHtml() ) - .parent() - // add buttons - .append( this._buttonHtml() ); - - this.element.attr( "role", "spinbutton" ); - - // button bindings - this.buttons = uiSpinner.find( ".ui-spinner-button" ) - .attr( "tabIndex", -1 ) - .button() - .removeClass( "ui-corner-all" ); - - // IE 6 doesn't understand height: 50% for the buttons - // unless the wrapper has an explicit height - if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) && - uiSpinner.height() > 0 ) { - uiSpinner.height( uiSpinner.height() ); - } - - // disable spinner if element was already disabled - if ( this.options.disabled ) { - this.disable(); - } - }, - - _keydown: function( event ) { - var options = this.options, - keyCode = $.ui.keyCode; - - switch ( event.keyCode ) { - case keyCode.UP: - this._repeat( null, 1, event ); - return true; - case keyCode.DOWN: - this._repeat( null, -1, event ); - return true; - case keyCode.PAGE_UP: - this._repeat( null, options.page, event ); - return true; - case keyCode.PAGE_DOWN: - this._repeat( null, -options.page, event ); - return true; - } - - return false; - }, - - _uiSpinnerHtml: function() { - return ""; - }, - - _buttonHtml: function() { - return "" + - "" + - "" + - "" + - "" + - "" + - ""; - }, - - _start: function( event ) { - if ( !this.spinning && this._trigger( "start", event ) === false ) { - return false; - } - - if ( !this.counter ) { - this.counter = 1; - } - this.spinning = true; - return true; - }, - - _repeat: function( i, steps, event ) { - i = i || 500; - - clearTimeout( this.timer ); - this.timer = this._delay(function() { - this._repeat( 40, steps, event ); - }, i ); - - this._spin( steps * this.options.step, event ); - }, - - _spin: function( step, event ) { - var value = this.value() || 0; - - if ( !this.counter ) { - this.counter = 1; - } - - value = this._adjustValue( value + step * this._increment( this.counter ) ); - - if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) { - this._value( value ); - this.counter++; - } - }, - - _increment: function( i ) { - var incremental = this.options.incremental; - - if ( incremental ) { - return $.isFunction( incremental ) ? - incremental( i ) : - Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 ); - } - - return 1; - }, - - _precision: function() { - var precision = this._precisionOf( this.options.step ); - if ( this.options.min !== null ) { - precision = Math.max( precision, this._precisionOf( this.options.min ) ); - } - return precision; - }, - - _precisionOf: function( num ) { - var str = num.toString(), - decimal = str.indexOf( "." ); - return decimal === -1 ? 0 : str.length - decimal - 1; - }, - - _adjustValue: function( value ) { - var base, aboveMin, - options = this.options; - - // make sure we're at a valid step - // - find out where we are relative to the base (min or 0) - base = options.min !== null ? options.min : 0; - aboveMin = value - base; - // - round to the nearest step - aboveMin = Math.round(aboveMin / options.step) * options.step; - // - rounding is based on 0, so adjust back to our base - value = base + aboveMin; - - // fix precision from bad JS floating point math - value = parseFloat( value.toFixed( this._precision() ) ); - - // clamp the value - if ( options.max !== null && value > options.max) { - return options.max; - } - if ( options.min !== null && value < options.min ) { - return options.min; - } - - return value; - }, - - _stop: function( event ) { - if ( !this.spinning ) { - return; - } - - clearTimeout( this.timer ); - clearTimeout( this.mousewheelTimer ); - this.counter = 0; - this.spinning = false; - this._trigger( "stop", event ); - }, - - _setOption: function( key, value ) { - if ( key === "culture" || key === "numberFormat" ) { - var prevValue = this._parse( this.element.val() ); - this.options[ key ] = value; - this.element.val( this._format( prevValue ) ); - return; - } - - if ( key === "max" || key === "min" || key === "step" ) { - if ( typeof value === "string" ) { - value = this._parse( value ); - } - } - if ( key === "icons" ) { - this.buttons.first().find( ".ui-icon" ) - .removeClass( this.options.icons.up ) - .addClass( value.up ); - this.buttons.last().find( ".ui-icon" ) - .removeClass( this.options.icons.down ) - .addClass( value.down ); - } - - this._super( key, value ); - - if ( key === "disabled" ) { - if ( value ) { - this.element.prop( "disabled", true ); - this.buttons.button( "disable" ); - } else { - this.element.prop( "disabled", false ); - this.buttons.button( "enable" ); - } - } - }, - - _setOptions: modifier(function( options ) { - this._super( options ); - this._value( this.element.val() ); - }), - - _parse: function( val ) { - if ( typeof val === "string" && val !== "" ) { - val = window.Globalize && this.options.numberFormat ? - Globalize.parseFloat( val, 10, this.options.culture ) : +val; - } - return val === "" || isNaN( val ) ? null : val; - }, - - _format: function( value ) { - if ( value === "" ) { - return ""; - } - return window.Globalize && this.options.numberFormat ? - Globalize.format( value, this.options.numberFormat, this.options.culture ) : - value; - }, - - _refresh: function() { - this.element.attr({ - "aria-valuemin": this.options.min, - "aria-valuemax": this.options.max, - // TODO: what should we do with values that can't be parsed? - "aria-valuenow": this._parse( this.element.val() ) - }); - }, - - // update the value without triggering change - _value: function( value, allowAny ) { - var parsed; - if ( value !== "" ) { - parsed = this._parse( value ); - if ( parsed !== null ) { - if ( !allowAny ) { - parsed = this._adjustValue( parsed ); - } - value = this._format( parsed ); - } - } - this.element.val( value ); - this._refresh(); - }, - - _destroy: function() { - this.element - .removeClass( "ui-spinner-input" ) - .prop( "disabled", false ) - .removeAttr( "autocomplete" ) - .removeAttr( "role" ) - .removeAttr( "aria-valuemin" ) - .removeAttr( "aria-valuemax" ) - .removeAttr( "aria-valuenow" ); - this.uiSpinner.replaceWith( this.element ); - }, - - stepUp: modifier(function( steps ) { - this._stepUp( steps ); - }), - _stepUp: function( steps ) { - if ( this._start() ) { - this._spin( (steps || 1) * this.options.step ); - this._stop(); - } - }, - - stepDown: modifier(function( steps ) { - this._stepDown( steps ); - }), - _stepDown: function( steps ) { - if ( this._start() ) { - this._spin( (steps || 1) * -this.options.step ); - this._stop(); - } - }, - - pageUp: modifier(function( pages ) { - this._stepUp( (pages || 1) * this.options.page ); - }), - - pageDown: modifier(function( pages ) { - this._stepDown( (pages || 1) * this.options.page ); - }), - - value: function( newVal ) { - if ( !arguments.length ) { - return this._parse( this.element.val() ); - } - modifier( this._value ).call( this, newVal ); - }, - - widget: function() { - return this.uiSpinner; - } -}); - -}( jQuery ) ); diff --git a/extensions/yii/jui/assets/jquery.ui.tabs.js b/extensions/yii/jui/assets/jquery.ui.tabs.js deleted file mode 100644 index b37858e..0000000 --- a/extensions/yii/jui/assets/jquery.ui.tabs.js +++ /dev/null @@ -1,846 +0,0 @@ -/*! - * jQuery UI Tabs 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/tabs/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -var tabId = 0, - rhash = /#.*$/; - -function getNextTabId() { - return ++tabId; -} - -function isLocal( anchor ) { - return anchor.hash.length > 1 && - decodeURIComponent( anchor.href.replace( rhash, "" ) ) === - decodeURIComponent( location.href.replace( rhash, "" ) ); -} - -$.widget( "ui.tabs", { - version: "1.10.3", - delay: 300, - options: { - active: null, - collapsible: false, - event: "click", - heightStyle: "content", - hide: null, - show: null, - - // callbacks - activate: null, - beforeActivate: null, - beforeLoad: null, - load: null - }, - - _create: function() { - var that = this, - options = this.options; - - this.running = false; - - this.element - .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ) - .toggleClass( "ui-tabs-collapsible", options.collapsible ) - // Prevent users from focusing disabled tabs via click - .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) { - if ( $( this ).is( ".ui-state-disabled" ) ) { - event.preventDefault(); - } - }) - // support: IE <9 - // Preventing the default action in mousedown doesn't prevent IE - // from focusing the element, so if the anchor gets focused, blur. - // We don't have to worry about focusing the previously focused - // element since clicking on a non-focusable element should focus - // the body anyway. - .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() { - if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) { - this.blur(); - } - }); - - this._processTabs(); - options.active = this._initialActive(); - - // Take disabling tabs via class attribute from HTML - // into account and update option properly. - if ( $.isArray( options.disabled ) ) { - options.disabled = $.unique( options.disabled.concat( - $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { - return that.tabs.index( li ); - }) - ) ).sort(); - } - - // check for length avoids error when initializing empty list - if ( this.options.active !== false && this.anchors.length ) { - this.active = this._findActive( options.active ); - } else { - this.active = $(); - } - - this._refresh(); - - if ( this.active.length ) { - this.load( options.active ); - } - }, - - _initialActive: function() { - var active = this.options.active, - collapsible = this.options.collapsible, - locationHash = location.hash.substring( 1 ); - - if ( active === null ) { - // check the fragment identifier in the URL - if ( locationHash ) { - this.tabs.each(function( i, tab ) { - if ( $( tab ).attr( "aria-controls" ) === locationHash ) { - active = i; - return false; - } - }); - } - - // check for a tab marked active via a class - if ( active === null ) { - active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); - } - - // no active tab, set to false - if ( active === null || active === -1 ) { - active = this.tabs.length ? 0 : false; - } - } - - // handle numbers: negative, out of range - if ( active !== false ) { - active = this.tabs.index( this.tabs.eq( active ) ); - if ( active === -1 ) { - active = collapsible ? false : 0; - } - } - - // don't allow collapsible: false and active: false - if ( !collapsible && active === false && this.anchors.length ) { - active = 0; - } - - return active; - }, - - _getCreateEventData: function() { - return { - tab: this.active, - panel: !this.active.length ? $() : this._getPanelForTab( this.active ) - }; - }, - - _tabKeydown: function( event ) { - /*jshint maxcomplexity:15*/ - var focusedTab = $( this.document[0].activeElement ).closest( "li" ), - selectedIndex = this.tabs.index( focusedTab ), - goingForward = true; - - if ( this._handlePageNav( event ) ) { - return; - } - - switch ( event.keyCode ) { - case $.ui.keyCode.RIGHT: - case $.ui.keyCode.DOWN: - selectedIndex++; - break; - case $.ui.keyCode.UP: - case $.ui.keyCode.LEFT: - goingForward = false; - selectedIndex--; - break; - case $.ui.keyCode.END: - selectedIndex = this.anchors.length - 1; - break; - case $.ui.keyCode.HOME: - selectedIndex = 0; - break; - case $.ui.keyCode.SPACE: - // Activate only, no collapsing - event.preventDefault(); - clearTimeout( this.activating ); - this._activate( selectedIndex ); - return; - case $.ui.keyCode.ENTER: - // Toggle (cancel delayed activation, allow collapsing) - event.preventDefault(); - clearTimeout( this.activating ); - // Determine if we should collapse or activate - this._activate( selectedIndex === this.options.active ? false : selectedIndex ); - return; - default: - return; - } - - // Focus the appropriate tab, based on which key was pressed - event.preventDefault(); - clearTimeout( this.activating ); - selectedIndex = this._focusNextTab( selectedIndex, goingForward ); - - // Navigating with control key will prevent automatic activation - if ( !event.ctrlKey ) { - // Update aria-selected immediately so that AT think the tab is already selected. - // Otherwise AT may confuse the user by stating that they need to activate the tab, - // but the tab will already be activated by the time the announcement finishes. - focusedTab.attr( "aria-selected", "false" ); - this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); - - this.activating = this._delay(function() { - this.option( "active", selectedIndex ); - }, this.delay ); - } - }, - - _panelKeydown: function( event ) { - if ( this._handlePageNav( event ) ) { - return; - } - - // Ctrl+up moves focus to the current tab - if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { - event.preventDefault(); - this.active.focus(); - } - }, - - // Alt+page up/down moves focus to the previous/next tab (and activates) - _handlePageNav: function( event ) { - if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { - this._activate( this._focusNextTab( this.options.active - 1, false ) ); - return true; - } - if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { - this._activate( this._focusNextTab( this.options.active + 1, true ) ); - return true; - } - }, - - _findNextTab: function( index, goingForward ) { - var lastTabIndex = this.tabs.length - 1; - - function constrain() { - if ( index > lastTabIndex ) { - index = 0; - } - if ( index < 0 ) { - index = lastTabIndex; - } - return index; - } - - while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { - index = goingForward ? index + 1 : index - 1; - } - - return index; - }, - - _focusNextTab: function( index, goingForward ) { - index = this._findNextTab( index, goingForward ); - this.tabs.eq( index ).focus(); - return index; - }, - - _setOption: function( key, value ) { - if ( key === "active" ) { - // _activate() will handle invalid values and update this.options - this._activate( value ); - return; - } - - if ( key === "disabled" ) { - // don't use the widget factory's disabled handling - this._setupDisabled( value ); - return; - } - - this._super( key, value); - - if ( key === "collapsible" ) { - this.element.toggleClass( "ui-tabs-collapsible", value ); - // Setting collapsible: false while collapsed; open first panel - if ( !value && this.options.active === false ) { - this._activate( 0 ); - } - } - - if ( key === "event" ) { - this._setupEvents( value ); - } - - if ( key === "heightStyle" ) { - this._setupHeightStyle( value ); - } - }, - - _tabId: function( tab ) { - return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId(); - }, - - _sanitizeSelector: function( hash ) { - return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : ""; - }, - - refresh: function() { - var options = this.options, - lis = this.tablist.children( ":has(a[href])" ); - - // get disabled tabs from class attribute from HTML - // this will get converted to a boolean if needed in _refresh() - options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { - return lis.index( tab ); - }); - - this._processTabs(); - - // was collapsed or no tabs - if ( options.active === false || !this.anchors.length ) { - options.active = false; - this.active = $(); - // was active, but active tab is gone - } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { - // all remaining tabs are disabled - if ( this.tabs.length === options.disabled.length ) { - options.active = false; - this.active = $(); - // activate previous tab - } else { - this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); - } - // was active, active tab still exists - } else { - // make sure active index is correct - options.active = this.tabs.index( this.active ); - } - - this._refresh(); - }, - - _refresh: function() { - this._setupDisabled( this.options.disabled ); - this._setupEvents( this.options.event ); - this._setupHeightStyle( this.options.heightStyle ); - - this.tabs.not( this.active ).attr({ - "aria-selected": "false", - tabIndex: -1 - }); - this.panels.not( this._getPanelForTab( this.active ) ) - .hide() - .attr({ - "aria-expanded": "false", - "aria-hidden": "true" - }); - - // Make sure one tab is in the tab order - if ( !this.active.length ) { - this.tabs.eq( 0 ).attr( "tabIndex", 0 ); - } else { - this.active - .addClass( "ui-tabs-active ui-state-active" ) - .attr({ - "aria-selected": "true", - tabIndex: 0 - }); - this._getPanelForTab( this.active ) - .show() - .attr({ - "aria-expanded": "true", - "aria-hidden": "false" - }); - } - }, - - _processTabs: function() { - var that = this; - - this.tablist = this._getList() - .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) - .attr( "role", "tablist" ); - - this.tabs = this.tablist.find( "> li:has(a[href])" ) - .addClass( "ui-state-default ui-corner-top" ) - .attr({ - role: "tab", - tabIndex: -1 - }); - - this.anchors = this.tabs.map(function() { - return $( "a", this )[ 0 ]; - }) - .addClass( "ui-tabs-anchor" ) - .attr({ - role: "presentation", - tabIndex: -1 - }); - - this.panels = $(); - - this.anchors.each(function( i, anchor ) { - var selector, panel, panelId, - anchorId = $( anchor ).uniqueId().attr( "id" ), - tab = $( anchor ).closest( "li" ), - originalAriaControls = tab.attr( "aria-controls" ); - - // inline tab - if ( isLocal( anchor ) ) { - selector = anchor.hash; - panel = that.element.find( that._sanitizeSelector( selector ) ); - // remote tab - } else { - panelId = that._tabId( tab ); - selector = "#" + panelId; - panel = that.element.find( selector ); - if ( !panel.length ) { - panel = that._createPanel( panelId ); - panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); - } - panel.attr( "aria-live", "polite" ); - } - - if ( panel.length) { - that.panels = that.panels.add( panel ); - } - if ( originalAriaControls ) { - tab.data( "ui-tabs-aria-controls", originalAriaControls ); - } - tab.attr({ - "aria-controls": selector.substring( 1 ), - "aria-labelledby": anchorId - }); - panel.attr( "aria-labelledby", anchorId ); - }); - - this.panels - .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) - .attr( "role", "tabpanel" ); - }, - - // allow overriding how to find the list for rare usage scenarios (#7715) - _getList: function() { - return this.element.find( "ol,ul" ).eq( 0 ); - }, - - _createPanel: function( id ) { - return $( "
        " ) - .attr( "id", id ) - .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) - .data( "ui-tabs-destroy", true ); - }, - - _setupDisabled: function( disabled ) { - if ( $.isArray( disabled ) ) { - if ( !disabled.length ) { - disabled = false; - } else if ( disabled.length === this.anchors.length ) { - disabled = true; - } - } - - // disable tabs - for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) { - if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { - $( li ) - .addClass( "ui-state-disabled" ) - .attr( "aria-disabled", "true" ); - } else { - $( li ) - .removeClass( "ui-state-disabled" ) - .removeAttr( "aria-disabled" ); - } - } - - this.options.disabled = disabled; - }, - - _setupEvents: function( event ) { - var events = { - click: function( event ) { - event.preventDefault(); - } - }; - if ( event ) { - $.each( event.split(" "), function( index, eventName ) { - events[ eventName ] = "_eventHandler"; - }); - } - - this._off( this.anchors.add( this.tabs ).add( this.panels ) ); - this._on( this.anchors, events ); - this._on( this.tabs, { keydown: "_tabKeydown" } ); - this._on( this.panels, { keydown: "_panelKeydown" } ); - - this._focusable( this.tabs ); - this._hoverable( this.tabs ); - }, - - _setupHeightStyle: function( heightStyle ) { - var maxHeight, - parent = this.element.parent(); - - if ( heightStyle === "fill" ) { - maxHeight = parent.height(); - maxHeight -= this.element.outerHeight() - this.element.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.element.children().not( this.panels ).each(function() { - maxHeight -= $( this ).outerHeight( true ); - }); - - this.panels.each(function() { - $( this ).height( Math.max( 0, maxHeight - - $( this ).innerHeight() + $( this ).height() ) ); - }) - .css( "overflow", "auto" ); - } else if ( heightStyle === "auto" ) { - maxHeight = 0; - this.panels.each(function() { - maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); - }).height( maxHeight ); - } - }, - - _eventHandler: function( event ) { - var options = this.options, - active = this.active, - anchor = $( event.currentTarget ), - tab = anchor.closest( "li" ), - clickedIsActive = tab[ 0 ] === active[ 0 ], - collapsing = clickedIsActive && options.collapsible, - toShow = collapsing ? $() : this._getPanelForTab( tab ), - toHide = !active.length ? $() : this._getPanelForTab( active ), - eventData = { - oldTab: active, - oldPanel: toHide, - newTab: collapsing ? $() : tab, - newPanel: toShow - }; - - event.preventDefault(); - - if ( tab.hasClass( "ui-state-disabled" ) || - // tab is already loading - tab.hasClass( "ui-tabs-loading" ) || - // can't switch durning an animation - this.running || - // 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.tabs.index( tab ); - - this.active = clickedIsActive ? $() : tab; - if ( this.xhr ) { - this.xhr.abort(); - } - - if ( !toHide.length && !toShow.length ) { - $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); - } - - if ( toShow.length ) { - this.load( this.tabs.index( tab ), event ); - } - this._toggle( event, eventData ); - }, - - // handles show/hide for selecting tabs - _toggle: function( event, eventData ) { - var that = this, - toShow = eventData.newPanel, - toHide = eventData.oldPanel; - - this.running = true; - - function complete() { - that.running = false; - that._trigger( "activate", event, eventData ); - } - - function show() { - eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" ); - - if ( toShow.length && that.options.show ) { - that._show( toShow, that.options.show, complete ); - } else { - toShow.show(); - complete(); - } - } - - // start out by hiding, then showing, then completing - if ( toHide.length && this.options.hide ) { - this._hide( toHide, this.options.hide, function() { - eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); - show(); - }); - } else { - eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); - toHide.hide(); - show(); - } - - toHide.attr({ - "aria-expanded": "false", - "aria-hidden": "true" - }); - eventData.oldTab.attr( "aria-selected", "false" ); - // If we're switching tabs, remove the old tab from the tab order. - // If we're opening from collapsed state, remove the previous tab from the tab order. - // If we're collapsing, then keep the collapsing tab in the tab order. - if ( toShow.length && toHide.length ) { - eventData.oldTab.attr( "tabIndex", -1 ); - } else if ( toShow.length ) { - this.tabs.filter(function() { - return $( this ).attr( "tabIndex" ) === 0; - }) - .attr( "tabIndex", -1 ); - } - - toShow.attr({ - "aria-expanded": "true", - "aria-hidden": "false" - }); - eventData.newTab.attr({ - "aria-selected": "true", - tabIndex: 0 - }); - }, - - _activate: function( index ) { - var anchor, - active = this._findActive( index ); - - // trying to activate the already active panel - if ( active[ 0 ] === this.active[ 0 ] ) { - return; - } - - // trying to collapse, simulate a click on the current active header - if ( !active.length ) { - active = this.active; - } - - anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; - this._eventHandler({ - target: anchor, - currentTarget: anchor, - preventDefault: $.noop - }); - }, - - _findActive: function( index ) { - return index === false ? $() : this.tabs.eq( index ); - }, - - _getIndex: function( index ) { - // meta-function to give users option to provide a href string instead of a numerical index. - if ( typeof index === "string" ) { - index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) ); - } - - return index; - }, - - _destroy: function() { - if ( this.xhr ) { - this.xhr.abort(); - } - - this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ); - - this.tablist - .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) - .removeAttr( "role" ); - - this.anchors - .removeClass( "ui-tabs-anchor" ) - .removeAttr( "role" ) - .removeAttr( "tabIndex" ) - .removeUniqueId(); - - this.tabs.add( this.panels ).each(function() { - if ( $.data( this, "ui-tabs-destroy" ) ) { - $( this ).remove(); - } else { - $( this ) - .removeClass( "ui-state-default ui-state-active ui-state-disabled " + - "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" ) - .removeAttr( "tabIndex" ) - .removeAttr( "aria-live" ) - .removeAttr( "aria-busy" ) - .removeAttr( "aria-selected" ) - .removeAttr( "aria-labelledby" ) - .removeAttr( "aria-hidden" ) - .removeAttr( "aria-expanded" ) - .removeAttr( "role" ); - } - }); - - this.tabs.each(function() { - var li = $( this ), - prev = li.data( "ui-tabs-aria-controls" ); - if ( prev ) { - li - .attr( "aria-controls", prev ) - .removeData( "ui-tabs-aria-controls" ); - } else { - li.removeAttr( "aria-controls" ); - } - }); - - this.panels.show(); - - if ( this.options.heightStyle !== "content" ) { - this.panels.css( "height", "" ); - } - }, - - enable: function( index ) { - var disabled = this.options.disabled; - if ( disabled === false ) { - return; - } - - if ( index === undefined ) { - disabled = false; - } else { - index = this._getIndex( index ); - if ( $.isArray( disabled ) ) { - disabled = $.map( disabled, function( num ) { - return num !== index ? num : null; - }); - } else { - disabled = $.map( this.tabs, function( li, num ) { - return num !== index ? num : null; - }); - } - } - this._setupDisabled( disabled ); - }, - - disable: function( index ) { - var disabled = this.options.disabled; - if ( disabled === true ) { - return; - } - - if ( index === undefined ) { - disabled = true; - } else { - index = this._getIndex( index ); - if ( $.inArray( index, disabled ) !== -1 ) { - return; - } - if ( $.isArray( disabled ) ) { - disabled = $.merge( [ index ], disabled ).sort(); - } else { - disabled = [ index ]; - } - } - this._setupDisabled( disabled ); - }, - - load: function( index, event ) { - index = this._getIndex( index ); - var that = this, - tab = this.tabs.eq( index ), - anchor = tab.find( ".ui-tabs-anchor" ), - panel = this._getPanelForTab( tab ), - eventData = { - tab: tab, - panel: panel - }; - - // not remote - if ( isLocal( anchor[ 0 ] ) ) { - return; - } - - this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); - - // support: jQuery <1.8 - // jQuery <1.8 returns false if the request is canceled in beforeSend, - // but as of 1.8, $.ajax() always returns a jqXHR object. - if ( this.xhr && this.xhr.statusText !== "canceled" ) { - tab.addClass( "ui-tabs-loading" ); - panel.attr( "aria-busy", "true" ); - - this.xhr - .success(function( response ) { - // support: jQuery <1.8 - // http://bugs.jquery.com/ticket/11778 - setTimeout(function() { - panel.html( response ); - that._trigger( "load", event, eventData ); - }, 1 ); - }) - .complete(function( jqXHR, status ) { - // support: jQuery <1.8 - // http://bugs.jquery.com/ticket/11778 - setTimeout(function() { - if ( status === "abort" ) { - that.panels.stop( false, true ); - } - - tab.removeClass( "ui-tabs-loading" ); - panel.removeAttr( "aria-busy" ); - - if ( jqXHR === that.xhr ) { - delete that.xhr; - } - }, 1 ); - }); - } - }, - - _ajaxSettings: function( anchor, event, eventData ) { - var that = this; - return { - url: anchor.attr( "href" ), - beforeSend: function( jqXHR, settings ) { - return that._trigger( "beforeLoad", event, - $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) ); - } - }; - }, - - _getPanelForTab: function( tab ) { - var id = $( tab ).attr( "aria-controls" ); - return this.element.find( this._sanitizeSelector( "#" + id ) ); - } -}); - -})( jQuery ); diff --git a/extensions/yii/jui/assets/jquery.ui.tooltip.js b/extensions/yii/jui/assets/jquery.ui.tooltip.js deleted file mode 100644 index 8ebf7b3..0000000 --- a/extensions/yii/jui/assets/jquery.ui.tooltip.js +++ /dev/null @@ -1,402 +0,0 @@ -/*! - * jQuery UI Tooltip 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/tooltip/ - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.position.js - */ -(function( $ ) { - -var increments = 0; - -function addDescribedBy( elem, id ) { - var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ); - describedby.push( id ); - elem - .data( "ui-tooltip-id", id ) - .attr( "aria-describedby", $.trim( describedby.join( " " ) ) ); -} - -function removeDescribedBy( elem ) { - var id = elem.data( "ui-tooltip-id" ), - describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ), - index = $.inArray( id, describedby ); - if ( index !== -1 ) { - describedby.splice( index, 1 ); - } - - elem.removeData( "ui-tooltip-id" ); - describedby = $.trim( describedby.join( " " ) ); - if ( describedby ) { - elem.attr( "aria-describedby", describedby ); - } else { - elem.removeAttr( "aria-describedby" ); - } -} - -$.widget( "ui.tooltip", { - version: "1.10.3", - options: { - content: function() { - // support: IE<9, Opera in jQuery <1.7 - // .text() can't accept undefined, so coerce to a string - var title = $( this ).attr( "title" ) || ""; - // Escape title, since we're going from an attribute to raw HTML - return $( "" ).text( title ).html(); - }, - hide: true, - // Disabled elements have inconsistent behavior across browsers (#8661) - items: "[title]:not([disabled])", - position: { - my: "left top+15", - at: "left bottom", - collision: "flipfit flip" - }, - show: true, - tooltipClass: null, - track: false, - - // callbacks - close: null, - open: null - }, - - _create: function() { - this._on({ - mouseover: "open", - focusin: "open" - }); - - // IDs of generated tooltips, needed for destroy - this.tooltips = {}; - // IDs of parent tooltips where we removed the title attribute - this.parents = {}; - - if ( this.options.disabled ) { - this._disable(); - } - }, - - _setOption: function( key, value ) { - var that = this; - - if ( key === "disabled" ) { - this[ value ? "_disable" : "_enable" ](); - this.options[ key ] = value; - // disable element style changes - return; - } - - this._super( key, value ); - - if ( key === "content" ) { - $.each( this.tooltips, function( id, element ) { - that._updateContent( element ); - }); - } - }, - - _disable: function() { - var that = this; - - // close open tooltips - $.each( this.tooltips, function( id, element ) { - var event = $.Event( "blur" ); - event.target = event.currentTarget = element[0]; - that.close( event, true ); - }); - - // remove title attributes to prevent native tooltips - this.element.find( this.options.items ).addBack().each(function() { - var element = $( this ); - if ( element.is( "[title]" ) ) { - element - .data( "ui-tooltip-title", element.attr( "title" ) ) - .attr( "title", "" ); - } - }); - }, - - _enable: function() { - // restore title attributes - this.element.find( this.options.items ).addBack().each(function() { - var element = $( this ); - if ( element.data( "ui-tooltip-title" ) ) { - element.attr( "title", element.data( "ui-tooltip-title" ) ); - } - }); - }, - - open: function( event ) { - var that = this, - target = $( event ? event.target : this.element ) - // we need closest here due to mouseover bubbling, - // but always pointing at the same event target - .closest( this.options.items ); - - // No element to show a tooltip for or the tooltip is already open - if ( !target.length || target.data( "ui-tooltip-id" ) ) { - return; - } - - if ( target.attr( "title" ) ) { - target.data( "ui-tooltip-title", target.attr( "title" ) ); - } - - target.data( "ui-tooltip-open", true ); - - // kill parent tooltips, custom or native, for hover - if ( event && event.type === "mouseover" ) { - target.parents().each(function() { - var parent = $( this ), - blurEvent; - if ( parent.data( "ui-tooltip-open" ) ) { - blurEvent = $.Event( "blur" ); - blurEvent.target = blurEvent.currentTarget = this; - that.close( blurEvent, true ); - } - if ( parent.attr( "title" ) ) { - parent.uniqueId(); - that.parents[ this.id ] = { - element: this, - title: parent.attr( "title" ) - }; - parent.attr( "title", "" ); - } - }); - } - - this._updateContent( target, event ); - }, - - _updateContent: function( target, event ) { - var content, - contentOption = this.options.content, - that = this, - eventType = event ? event.type : null; - - if ( typeof contentOption === "string" ) { - return this._open( event, target, contentOption ); - } - - content = contentOption.call( target[0], function( response ) { - // ignore async response if tooltip was closed already - if ( !target.data( "ui-tooltip-open" ) ) { - return; - } - // IE may instantly serve a cached response for ajax requests - // delay this call to _open so the other call to _open runs first - that._delay(function() { - // jQuery creates a special event for focusin when it doesn't - // exist natively. To improve performance, the native event - // object is reused and the type is changed. Therefore, we can't - // rely on the type being correct after the event finished - // bubbling, so we set it back to the previous value. (#8740) - if ( event ) { - event.type = eventType; - } - this._open( event, target, response ); - }); - }); - if ( content ) { - this._open( event, target, content ); - } - }, - - _open: function( event, target, content ) { - var tooltip, events, delayedShow, - positionOption = $.extend( {}, this.options.position ); - - if ( !content ) { - return; - } - - // Content can be updated multiple times. If the tooltip already - // exists, then just update the content and bail. - tooltip = this._find( target ); - if ( tooltip.length ) { - tooltip.find( ".ui-tooltip-content" ).html( content ); - return; - } - - // if we have a title, clear it to prevent the native tooltip - // we have to check first to avoid defining a title if none exists - // (we don't want to cause an element to start matching [title]) - // - // We use removeAttr only for key events, to allow IE to export the correct - // accessible attributes. For mouse events, set to empty string to avoid - // native tooltip showing up (happens only when removing inside mouseover). - if ( target.is( "[title]" ) ) { - if ( event && event.type === "mouseover" ) { - target.attr( "title", "" ); - } else { - target.removeAttr( "title" ); - } - } - - tooltip = this._tooltip( target ); - addDescribedBy( target, tooltip.attr( "id" ) ); - tooltip.find( ".ui-tooltip-content" ).html( content ); - - function position( event ) { - positionOption.of = event; - if ( tooltip.is( ":hidden" ) ) { - return; - } - tooltip.position( positionOption ); - } - if ( this.options.track && event && /^mouse/.test( event.type ) ) { - this._on( this.document, { - mousemove: position - }); - // trigger once to override element-relative positioning - position( event ); - } else { - tooltip.position( $.extend({ - of: target - }, this.options.position ) ); - } - - tooltip.hide(); - - this._show( tooltip, this.options.show ); - // Handle tracking tooltips that are shown with a delay (#8644). As soon - // as the tooltip is visible, position the tooltip using the most recent - // event. - if ( this.options.show && this.options.show.delay ) { - delayedShow = this.delayedShow = setInterval(function() { - if ( tooltip.is( ":visible" ) ) { - position( positionOption.of ); - clearInterval( delayedShow ); - } - }, $.fx.interval ); - } - - this._trigger( "open", event, { tooltip: tooltip } ); - - events = { - keyup: function( event ) { - if ( event.keyCode === $.ui.keyCode.ESCAPE ) { - var fakeEvent = $.Event(event); - fakeEvent.currentTarget = target[0]; - this.close( fakeEvent, true ); - } - }, - remove: function() { - this._removeTooltip( tooltip ); - } - }; - if ( !event || event.type === "mouseover" ) { - events.mouseleave = "close"; - } - if ( !event || event.type === "focusin" ) { - events.focusout = "close"; - } - this._on( true, target, events ); - }, - - close: function( event ) { - var that = this, - target = $( event ? event.currentTarget : this.element ), - tooltip = this._find( target ); - - // disabling closes the tooltip, so we need to track when we're closing - // to avoid an infinite loop in case the tooltip becomes disabled on close - if ( this.closing ) { - return; - } - - // Clear the interval for delayed tracking tooltips - clearInterval( this.delayedShow ); - - // only set title if we had one before (see comment in _open()) - if ( target.data( "ui-tooltip-title" ) ) { - target.attr( "title", target.data( "ui-tooltip-title" ) ); - } - - removeDescribedBy( target ); - - tooltip.stop( true ); - this._hide( tooltip, this.options.hide, function() { - that._removeTooltip( $( this ) ); - }); - - target.removeData( "ui-tooltip-open" ); - this._off( target, "mouseleave focusout keyup" ); - // Remove 'remove' binding only on delegated targets - if ( target[0] !== this.element[0] ) { - this._off( target, "remove" ); - } - this._off( this.document, "mousemove" ); - - if ( event && event.type === "mouseleave" ) { - $.each( this.parents, function( id, parent ) { - $( parent.element ).attr( "title", parent.title ); - delete that.parents[ id ]; - }); - } - - this.closing = true; - this._trigger( "close", event, { tooltip: tooltip } ); - this.closing = false; - }, - - _tooltip: function( element ) { - var id = "ui-tooltip-" + increments++, - tooltip = $( "
        " ) - .attr({ - id: id, - role: "tooltip" - }) - .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " + - ( this.options.tooltipClass || "" ) ); - $( "
        " ) - .addClass( "ui-tooltip-content" ) - .appendTo( tooltip ); - tooltip.appendTo( this.document[0].body ); - this.tooltips[ id ] = element; - return tooltip; - }, - - _find: function( target ) { - var id = target.data( "ui-tooltip-id" ); - return id ? $( "#" + id ) : $(); - }, - - _removeTooltip: function( tooltip ) { - tooltip.remove(); - delete this.tooltips[ tooltip.attr( "id" ) ]; - }, - - _destroy: function() { - var that = this; - - // close open tooltips - $.each( this.tooltips, function( id, element ) { - // Delegate to close method to handle common cleanup - var event = $.Event( "blur" ); - event.target = event.currentTarget = element[0]; - that.close( event, true ); - - // Remove immediately; destroying an open tooltip doesn't use the - // hide animation - $( "#" + id ).remove(); - - // Restore the title - if ( element.data( "ui-tooltip-title" ) ) { - element.attr( "title", element.data( "ui-tooltip-title" ) ); - element.removeData( "ui-tooltip-title" ); - } - }); - } -}); - -}( jQuery ) ); diff --git a/extensions/yii/jui/assets/jquery.ui.widget.js b/extensions/yii/jui/assets/jquery.ui.widget.js deleted file mode 100644 index 916a6ad..0000000 --- a/extensions/yii/jui/assets/jquery.ui.widget.js +++ /dev/null @@ -1,521 +0,0 @@ -/*! - * jQuery UI Widget 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/jQuery.widget/ - */ -(function( $, undefined ) { - -var uuid = 0, - slice = Array.prototype.slice, - _cleanData = $.cleanData; -$.cleanData = function( elems ) { - for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { - try { - $( elem ).triggerHandler( "remove" ); - // http://bugs.jquery.com/ticket/8235 - } catch( e ) {} - } - _cleanData( elems ); -}; - -$.widget = function( name, base, prototype ) { - var fullName, existingConstructor, constructor, basePrototype, - // proxiedPrototype allows the provided prototype to remain unmodified - // so that it can be used as a mixin for multiple widgets (#8876) - proxiedPrototype = {}, - namespace = name.split( "." )[ 0 ]; - - name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; - - if ( !prototype ) { - prototype = base; - base = $.Widget; - } - - // create selector for plugin - $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { - return !!$.data( elem, fullName ); - }; - - $[ namespace ] = $[ namespace ] || {}; - existingConstructor = $[ namespace ][ name ]; - constructor = $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without "new" keyword - if ( !this._createWidget ) { - return new constructor( options, element ); - } - - // allow instantiation without initializing for simple inheritance - // must use "new" keyword (the code above always passes args) - if ( arguments.length ) { - this._createWidget( options, element ); - } - }; - // extend with the existing constructor to carry over any static properties - $.extend( constructor, existingConstructor, { - version: prototype.version, - // copy the object used to create the prototype in case we need to - // redefine the widget later - _proto: $.extend( {}, prototype ), - // track widgets that inherit from this widget in case this widget is - // redefined after a widget inherits from it - _childConstructors: [] - }); - - basePrototype = new base(); - // we need to make the options hash a property directly on the new instance - // otherwise we'll modify the options hash on the prototype that we're - // inheriting from - basePrototype.options = $.widget.extend( {}, basePrototype.options ); - $.each( prototype, function( prop, value ) { - if ( !$.isFunction( value ) ) { - proxiedPrototype[ prop ] = value; - return; - } - proxiedPrototype[ prop ] = (function() { - var _super = function() { - return base.prototype[ prop ].apply( this, arguments ); - }, - _superApply = function( args ) { - return base.prototype[ prop ].apply( this, args ); - }; - return function() { - var __super = this._super, - __superApply = this._superApply, - returnValue; - - this._super = _super; - this._superApply = _superApply; - - returnValue = value.apply( this, arguments ); - - this._super = __super; - this._superApply = __superApply; - - return returnValue; - }; - })(); - }); - constructor.prototype = $.widget.extend( basePrototype, { - // TODO: remove support for widgetEventPrefix - // always use the name + a colon as the prefix, e.g., draggable:start - // don't prefix for widgets that aren't DOM-based - widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name - }, proxiedPrototype, { - constructor: constructor, - namespace: namespace, - widgetName: name, - widgetFullName: fullName - }); - - // If this widget is being redefined then we need to find all widgets that - // are inheriting from it and redefine all of them so that they inherit from - // the new version of this widget. We're essentially trying to replace one - // level in the prototype chain. - if ( existingConstructor ) { - $.each( existingConstructor._childConstructors, function( i, child ) { - var childPrototype = child.prototype; - - // redefine the child widget using the same prototype that was - // originally used, but inherit from the new version of the base - $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); - }); - // remove the list of existing child constructors from the old constructor - // so the old child constructors can be garbage collected - delete existingConstructor._childConstructors; - } else { - base._childConstructors.push( constructor ); - } - - $.widget.bridge( name, constructor ); -}; - -$.widget.extend = function( target ) { - var input = slice.call( arguments, 1 ), - inputIndex = 0, - inputLength = input.length, - key, - value; - for ( ; inputIndex < inputLength; inputIndex++ ) { - for ( key in input[ inputIndex ] ) { - value = input[ inputIndex ][ key ]; - if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { - // Clone objects - if ( $.isPlainObject( value ) ) { - target[ key ] = $.isPlainObject( target[ key ] ) ? - $.widget.extend( {}, target[ key ], value ) : - // Don't extend strings, arrays, etc. with objects - $.widget.extend( {}, value ); - // Copy everything else by reference - } else { - target[ key ] = value; - } - } - } - } - return target; -}; - -$.widget.bridge = function( name, object ) { - var fullName = object.prototype.widgetFullName || name; - $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = slice.call( arguments, 1 ), - returnValue = this; - - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.widget.extend.apply( null, [ options ].concat(args) ) : - options; - - if ( isMethodCall ) { - this.each(function() { - var methodValue, - instance = $.data( this, fullName ); - if ( !instance ) { - return $.error( "cannot call methods on " + name + " prior to initialization; " + - "attempted to call method '" + options + "'" ); - } - if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { - return $.error( "no such method '" + options + "' for " + name + " widget instance" ); - } - methodValue = instance[ options ].apply( instance, args ); - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue && methodValue.jquery ? - returnValue.pushStack( methodValue.get() ) : - methodValue; - return false; - } - }); - } else { - this.each(function() { - var instance = $.data( this, fullName ); - if ( instance ) { - instance.option( options || {} )._init(); - } else { - $.data( this, fullName, new object( options, this ) ); - } - }); - } - - return returnValue; - }; -}; - -$.Widget = function( /* options, element */ ) {}; -$.Widget._childConstructors = []; - -$.Widget.prototype = { - widgetName: "widget", - widgetEventPrefix: "", - defaultElement: "
        ", - options: { - disabled: false, - - // callbacks - create: null - }, - _createWidget: function( options, element ) { - element = $( element || this.defaultElement || this )[ 0 ]; - this.element = $( element ); - this.uuid = uuid++; - this.eventNamespace = "." + this.widgetName + this.uuid; - this.options = $.widget.extend( {}, - this.options, - this._getCreateOptions(), - options ); - - this.bindings = $(); - this.hoverable = $(); - this.focusable = $(); - - if ( element !== this ) { - $.data( element, this.widgetFullName, this ); - this._on( true, this.element, { - remove: function( event ) { - if ( event.target === element ) { - this.destroy(); - } - } - }); - this.document = $( element.style ? - // element within the document - element.ownerDocument : - // element is window or document - element.document || element ); - this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); - } - - this._create(); - this._trigger( "create", null, this._getCreateEventData() ); - this._init(); - }, - _getCreateOptions: $.noop, - _getCreateEventData: $.noop, - _create: $.noop, - _init: $.noop, - - destroy: function() { - this._destroy(); - // we can probably remove the unbind calls in 2.0 - // all event bindings should go through this._on() - this.element - .unbind( this.eventNamespace ) - // 1.9 BC for #7810 - // TODO remove dual storage - .removeData( this.widgetName ) - .removeData( this.widgetFullName ) - // support: jquery <1.6.3 - // http://bugs.jquery.com/ticket/9413 - .removeData( $.camelCase( this.widgetFullName ) ); - this.widget() - .unbind( this.eventNamespace ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetFullName + "-disabled " + - "ui-state-disabled" ); - - // clean up events and states - this.bindings.unbind( this.eventNamespace ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - }, - _destroy: $.noop, - - widget: function() { - return this.element; - }, - - option: function( key, value ) { - var options = key, - parts, - curOption, - i; - - if ( arguments.length === 0 ) { - // don't return a reference to the internal hash - return $.widget.extend( {}, this.options ); - } - - if ( typeof key === "string" ) { - // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } - options = {}; - parts = key.split( "." ); - key = parts.shift(); - if ( parts.length ) { - curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); - for ( i = 0; i < parts.length - 1; i++ ) { - curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; - curOption = curOption[ parts[ i ] ]; - } - key = parts.pop(); - if ( value === undefined ) { - return curOption[ key ] === undefined ? null : curOption[ key ]; - } - curOption[ key ] = value; - } else { - if ( value === undefined ) { - return this.options[ key ] === undefined ? null : this.options[ key ]; - } - options[ key ] = value; - } - } - - this._setOptions( options ); - - return this; - }, - _setOptions: function( options ) { - var key; - - for ( key in options ) { - this._setOption( key, options[ key ] ); - } - - return this; - }, - _setOption: function( key, value ) { - this.options[ key ] = value; - - if ( key === "disabled" ) { - this.widget() - .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) - .attr( "aria-disabled", value ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - } - - return this; - }, - - enable: function() { - return this._setOption( "disabled", false ); - }, - disable: function() { - return this._setOption( "disabled", true ); - }, - - _on: function( suppressDisabledCheck, element, handlers ) { - var delegateElement, - instance = this; - - // no suppressDisabledCheck flag, shuffle arguments - if ( typeof suppressDisabledCheck !== "boolean" ) { - handlers = element; - element = suppressDisabledCheck; - suppressDisabledCheck = false; - } - - // no element argument, shuffle and use this.element - if ( !handlers ) { - handlers = element; - element = this.element; - delegateElement = this.widget(); - } else { - // accept selectors, DOM elements - element = delegateElement = $( element ); - this.bindings = this.bindings.add( element ); - } - - $.each( handlers, function( event, handler ) { - function handlerProxy() { - // allow widgets to customize the disabled handling - // - disabled as an array instead of boolean - // - disabled class as method for disabling individual parts - if ( !suppressDisabledCheck && - ( instance.options.disabled === true || - $( this ).hasClass( "ui-state-disabled" ) ) ) { - return; - } - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - - // copy the guid so direct unbinding works - if ( typeof handler !== "string" ) { - handlerProxy.guid = handler.guid = - handler.guid || handlerProxy.guid || $.guid++; - } - - var match = event.match( /^(\w+)\s*(.*)$/ ), - eventName = match[1] + instance.eventNamespace, - selector = match[2]; - if ( selector ) { - delegateElement.delegate( selector, eventName, handlerProxy ); - } else { - element.bind( eventName, handlerProxy ); - } - }); - }, - - _off: function( element, eventName ) { - eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; - element.unbind( eventName ).undelegate( eventName ); - }, - - _delay: function( handler, delay ) { - function handlerProxy() { - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - var instance = this; - return setTimeout( handlerProxy, delay || 0 ); - }, - - _hoverable: function( element ) { - this.hoverable = this.hoverable.add( element ); - this._on( element, { - mouseenter: function( event ) { - $( event.currentTarget ).addClass( "ui-state-hover" ); - }, - mouseleave: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-hover" ); - } - }); - }, - - _focusable: function( element ) { - this.focusable = this.focusable.add( element ); - this._on( element, { - focusin: function( event ) { - $( event.currentTarget ).addClass( "ui-state-focus" ); - }, - focusout: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-focus" ); - } - }); - }, - - _trigger: function( type, event, data ) { - var prop, orig, - callback = this.options[ type ]; - - data = data || {}; - event = $.Event( event ); - event.type = ( type === this.widgetEventPrefix ? - type : - this.widgetEventPrefix + type ).toLowerCase(); - // the original event may come from any element - // so we need to reset the target on the new event - event.target = this.element[ 0 ]; - - // copy original event properties over to the new event - orig = event.originalEvent; - if ( orig ) { - for ( prop in orig ) { - if ( !( prop in event ) ) { - event[ prop ] = orig[ prop ]; - } - } - } - - this.element.trigger( event, data ); - return !( $.isFunction( callback ) && - callback.apply( this.element[0], [ event ].concat( data ) ) === false || - event.isDefaultPrevented() ); - } -}; - -$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { - $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { - if ( typeof options === "string" ) { - options = { effect: options }; - } - var hasOptions, - effectName = !options ? - method : - options === true || typeof options === "number" ? - defaultEffect : - options.effect || defaultEffect; - options = options || {}; - if ( typeof options === "number" ) { - options = { duration: options }; - } - hasOptions = !$.isEmptyObject( options ); - options.complete = callback; - if ( options.delay ) { - element.delay( options.delay ); - } - if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { - element[ method ]( options ); - } else if ( effectName !== method && element[ effectName ] ) { - element[ effectName ]( options.duration, options.easing, callback ); - } else { - element.queue(function( next ) { - $( this )[ method ](); - if ( callback ) { - callback.call( element[ 0 ] ); - } - next(); - }); - } - }; -}); - -})( jQuery ); diff --git a/extensions/yii/jui/assets/theme/images/animated-overlay.gif b/extensions/yii/jui/assets/theme/images/animated-overlay.gif deleted file mode 100755 index d441f75..0000000 Binary files a/extensions/yii/jui/assets/theme/images/animated-overlay.gif and /dev/null differ diff --git a/extensions/yii/jui/assets/theme/images/ui-bg_flat_0_aaaaaa_40x100.png b/extensions/yii/jui/assets/theme/images/ui-bg_flat_0_aaaaaa_40x100.png deleted file mode 100755 index 414803b..0000000 Binary files a/extensions/yii/jui/assets/theme/images/ui-bg_flat_0_aaaaaa_40x100.png and /dev/null differ diff --git a/extensions/yii/jui/assets/theme/images/ui-bg_flat_75_ffffff_40x100.png b/extensions/yii/jui/assets/theme/images/ui-bg_flat_75_ffffff_40x100.png deleted file mode 100755 index 462409f..0000000 Binary files a/extensions/yii/jui/assets/theme/images/ui-bg_flat_75_ffffff_40x100.png and /dev/null differ diff --git a/extensions/yii/jui/assets/theme/images/ui-bg_glass_55_fbf9ee_1x400.png b/extensions/yii/jui/assets/theme/images/ui-bg_glass_55_fbf9ee_1x400.png deleted file mode 100755 index 6b78278..0000000 Binary files a/extensions/yii/jui/assets/theme/images/ui-bg_glass_55_fbf9ee_1x400.png and /dev/null differ diff --git a/extensions/yii/jui/assets/theme/images/ui-bg_glass_65_ffffff_1x400.png b/extensions/yii/jui/assets/theme/images/ui-bg_glass_65_ffffff_1x400.png deleted file mode 100755 index b706fba..0000000 Binary files a/extensions/yii/jui/assets/theme/images/ui-bg_glass_65_ffffff_1x400.png and /dev/null differ diff --git a/extensions/yii/jui/assets/theme/images/ui-bg_glass_75_dadada_1x400.png b/extensions/yii/jui/assets/theme/images/ui-bg_glass_75_dadada_1x400.png deleted file mode 100755 index b650a7c..0000000 Binary files a/extensions/yii/jui/assets/theme/images/ui-bg_glass_75_dadada_1x400.png and /dev/null differ diff --git a/extensions/yii/jui/assets/theme/images/ui-bg_glass_75_e6e6e6_1x400.png b/extensions/yii/jui/assets/theme/images/ui-bg_glass_75_e6e6e6_1x400.png deleted file mode 100755 index e70ab8f..0000000 Binary files a/extensions/yii/jui/assets/theme/images/ui-bg_glass_75_e6e6e6_1x400.png and /dev/null differ diff --git a/extensions/yii/jui/assets/theme/images/ui-bg_glass_95_fef1ec_1x400.png b/extensions/yii/jui/assets/theme/images/ui-bg_glass_95_fef1ec_1x400.png deleted file mode 100755 index 6e86fb1..0000000 Binary files a/extensions/yii/jui/assets/theme/images/ui-bg_glass_95_fef1ec_1x400.png and /dev/null differ diff --git a/extensions/yii/jui/assets/theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/extensions/yii/jui/assets/theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png deleted file mode 100755 index 93ad9a6..0000000 Binary files a/extensions/yii/jui/assets/theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png and /dev/null differ diff --git a/extensions/yii/jui/assets/theme/images/ui-icons_222222_256x240.png b/extensions/yii/jui/assets/theme/images/ui-icons_222222_256x240.png deleted file mode 100755 index c1cb117..0000000 Binary files a/extensions/yii/jui/assets/theme/images/ui-icons_222222_256x240.png and /dev/null differ diff --git a/extensions/yii/jui/assets/theme/images/ui-icons_2e83ff_256x240.png b/extensions/yii/jui/assets/theme/images/ui-icons_2e83ff_256x240.png deleted file mode 100755 index 84b601b..0000000 Binary files a/extensions/yii/jui/assets/theme/images/ui-icons_2e83ff_256x240.png and /dev/null differ diff --git a/extensions/yii/jui/assets/theme/images/ui-icons_454545_256x240.png b/extensions/yii/jui/assets/theme/images/ui-icons_454545_256x240.png deleted file mode 100755 index b6db1ac..0000000 Binary files a/extensions/yii/jui/assets/theme/images/ui-icons_454545_256x240.png and /dev/null differ diff --git a/extensions/yii/jui/assets/theme/images/ui-icons_888888_256x240.png b/extensions/yii/jui/assets/theme/images/ui-icons_888888_256x240.png deleted file mode 100755 index feea0e2..0000000 Binary files a/extensions/yii/jui/assets/theme/images/ui-icons_888888_256x240.png and /dev/null differ diff --git a/extensions/yii/jui/assets/theme/images/ui-icons_cd0a0a_256x240.png b/extensions/yii/jui/assets/theme/images/ui-icons_cd0a0a_256x240.png deleted file mode 100755 index ed5b6b0..0000000 Binary files a/extensions/yii/jui/assets/theme/images/ui-icons_cd0a0a_256x240.png and /dev/null differ diff --git a/extensions/yii/jui/assets/theme/jquery.ui.css b/extensions/yii/jui/assets/theme/jquery.ui.css deleted file mode 100755 index 105197e..0000000 --- a/extensions/yii/jui/assets/theme/jquery.ui.css +++ /dev/null @@ -1,1177 +0,0 @@ -/*! jQuery UI - v1.10.3 - 2013-07-18 -* http://jqueryui.com -* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css -* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px -* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ - -/* Layout helpers -----------------------------------*/ -.ui-helper-hidden { - display: none; -} -.ui-helper-hidden-accessible { - border: 0; - clip: rect(0 0 0 0); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - width: 1px; -} -.ui-helper-reset { - margin: 0; - padding: 0; - border: 0; - outline: 0; - line-height: 1.3; - text-decoration: none; - font-size: 100%; - list-style: none; -} -.ui-helper-clearfix:before, -.ui-helper-clearfix:after { - content: ""; - display: table; - border-collapse: collapse; -} -.ui-helper-clearfix:after { - clear: both; -} -.ui-helper-clearfix { - min-height: 0; /* support: IE7 */ -} -.ui-helper-zfix { - width: 100%; - height: 100%; - top: 0; - left: 0; - position: absolute; - opacity: 0; - filter:Alpha(Opacity=0); -} - -.ui-front { - z-index: 100; -} - - -/* Interaction Cues -----------------------------------*/ -.ui-state-disabled { - cursor: default !important; -} - - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { - display: block; - text-indent: -99999px; - overflow: hidden; - background-repeat: no-repeat; -} - - -/* Misc visuals -----------------------------------*/ - -/* Overlays */ -.ui-widget-overlay { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; -} -.ui-resizable { - position: relative; -} -.ui-resizable-handle { - position: absolute; - font-size: 0.1px; - display: block; -} -.ui-resizable-disabled .ui-resizable-handle, -.ui-resizable-autohide .ui-resizable-handle { - display: none; -} -.ui-resizable-n { - cursor: n-resize; - height: 7px; - width: 100%; - top: -5px; - left: 0; -} -.ui-resizable-s { - cursor: s-resize; - height: 7px; - width: 100%; - bottom: -5px; - left: 0; -} -.ui-resizable-e { - cursor: e-resize; - width: 7px; - right: -5px; - top: 0; - height: 100%; -} -.ui-resizable-w { - cursor: w-resize; - width: 7px; - left: -5px; - top: 0; - height: 100%; -} -.ui-resizable-se { - cursor: se-resize; - width: 12px; - height: 12px; - right: 1px; - bottom: 1px; -} -.ui-resizable-sw { - cursor: sw-resize; - width: 9px; - height: 9px; - left: -5px; - bottom: -5px; -} -.ui-resizable-nw { - cursor: nw-resize; - width: 9px; - height: 9px; - left: -5px; - top: -5px; -} -.ui-resizable-ne { - cursor: ne-resize; - width: 9px; - height: 9px; - right: -5px; - top: -5px; -} -.ui-selectable-helper { - position: absolute; - z-index: 100; - border: 1px dotted black; -} -.ui-accordion .ui-accordion-header { - display: block; - cursor: pointer; - position: relative; - margin-top: 2px; - padding: .5em .5em .5em .7em; - min-height: 0; /* support: IE7 */ -} -.ui-accordion .ui-accordion-icons { - padding-left: 2.2em; -} -.ui-accordion .ui-accordion-noicons { - padding-left: .7em; -} -.ui-accordion .ui-accordion-icons .ui-accordion-icons { - padding-left: 2.2em; -} -.ui-accordion .ui-accordion-header .ui-accordion-header-icon { - position: absolute; - left: .5em; - top: 50%; - margin-top: -8px; -} -.ui-accordion .ui-accordion-content { - padding: 1em 2.2em; - border-top: 0; - overflow: auto; -} -.ui-autocomplete { - position: absolute; - top: 0; - left: 0; - cursor: default; -} -.ui-button { - display: inline-block; - position: relative; - padding: 0; - line-height: normal; - margin-right: .1em; - cursor: pointer; - vertical-align: middle; - text-align: center; - overflow: visible; /* removes extra width in IE */ -} -.ui-button, -.ui-button:link, -.ui-button:visited, -.ui-button:hover, -.ui-button:active { - text-decoration: none; -} -/* to make room for the icon, a width needs to be set here */ -.ui-button-icon-only { - width: 2.2em; -} -/* button elements seem to need a little more width */ -button.ui-button-icon-only { - width: 2.4em; -} -.ui-button-icons-only { - width: 3.4em; -} -button.ui-button-icons-only { - width: 3.7em; -} - -/* button text element */ -.ui-button .ui-button-text { - display: block; - line-height: normal; -} -.ui-button-text-only .ui-button-text { - padding: .4em 1em; -} -.ui-button-icon-only .ui-button-text, -.ui-button-icons-only .ui-button-text { - padding: .4em; - text-indent: -9999999px; -} -.ui-button-text-icon-primary .ui-button-text, -.ui-button-text-icons .ui-button-text { - padding: .4em 1em .4em 2.1em; -} -.ui-button-text-icon-secondary .ui-button-text, -.ui-button-text-icons .ui-button-text { - padding: .4em 2.1em .4em 1em; -} -.ui-button-text-icons .ui-button-text { - padding-left: 2.1em; - padding-right: 2.1em; -} -/* no icon support for input elements, provide padding by default */ -input.ui-button { - padding: .4em 1em; -} - -/* button icon element(s) */ -.ui-button-icon-only .ui-icon, -.ui-button-text-icon-primary .ui-icon, -.ui-button-text-icon-secondary .ui-icon, -.ui-button-text-icons .ui-icon, -.ui-button-icons-only .ui-icon { - position: absolute; - top: 50%; - margin-top: -8px; -} -.ui-button-icon-only .ui-icon { - left: 50%; - margin-left: -8px; -} -.ui-button-text-icon-primary .ui-button-icon-primary, -.ui-button-text-icons .ui-button-icon-primary, -.ui-button-icons-only .ui-button-icon-primary { - left: .5em; -} -.ui-button-text-icon-secondary .ui-button-icon-secondary, -.ui-button-text-icons .ui-button-icon-secondary, -.ui-button-icons-only .ui-button-icon-secondary { - right: .5em; -} - -/* button sets */ -.ui-buttonset { - margin-right: 7px; -} -.ui-buttonset .ui-button { - margin-left: 0; - margin-right: -.3em; -} - -/* workarounds */ -/* reset extra padding in Firefox, see h5bp.com/l */ -input.ui-button::-moz-focus-inner, -button.ui-button::-moz-focus-inner { - border: 0; - padding: 0; -} -.ui-datepicker { - width: 17em; - padding: .2em .2em 0; - display: none; -} -.ui-datepicker .ui-datepicker-header { - position: relative; - padding: .2em 0; -} -.ui-datepicker .ui-datepicker-prev, -.ui-datepicker .ui-datepicker-next { - position: absolute; - top: 2px; - width: 1.8em; - height: 1.8em; -} -.ui-datepicker .ui-datepicker-prev-hover, -.ui-datepicker .ui-datepicker-next-hover { - top: 1px; -} -.ui-datepicker .ui-datepicker-prev { - left: 2px; -} -.ui-datepicker .ui-datepicker-next { - right: 2px; -} -.ui-datepicker .ui-datepicker-prev-hover { - left: 1px; -} -.ui-datepicker .ui-datepicker-next-hover { - right: 1px; -} -.ui-datepicker .ui-datepicker-prev span, -.ui-datepicker .ui-datepicker-next span { - display: block; - position: absolute; - left: 50%; - margin-left: -8px; - top: 50%; - margin-top: -8px; -} -.ui-datepicker .ui-datepicker-title { - margin: 0 2.3em; - line-height: 1.8em; - text-align: center; -} -.ui-datepicker .ui-datepicker-title select { - font-size: 1em; - margin: 1px 0; -} -.ui-datepicker select.ui-datepicker-month-year { - width: 100%; -} -.ui-datepicker select.ui-datepicker-month, -.ui-datepicker select.ui-datepicker-year { - width: 49%; -} -.ui-datepicker table { - width: 100%; - font-size: .9em; - border-collapse: collapse; - margin: 0 0 .4em; -} -.ui-datepicker th { - padding: .7em .3em; - text-align: center; - font-weight: bold; - border: 0; -} -.ui-datepicker td { - border: 0; - padding: 1px; -} -.ui-datepicker td span, -.ui-datepicker td a { - display: block; - padding: .2em; - text-align: right; - text-decoration: none; -} -.ui-datepicker .ui-datepicker-buttonpane { - background-image: none; - margin: .7em 0 0 0; - padding: 0 .2em; - border-left: 0; - border-right: 0; - border-bottom: 0; -} -.ui-datepicker .ui-datepicker-buttonpane button { - float: right; - margin: .5em .2em .4em; - cursor: pointer; - padding: .2em .6em .3em .6em; - width: auto; - overflow: visible; -} -.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { - float: left; -} - -/* with multiple calendars */ -.ui-datepicker.ui-datepicker-multi { - width: auto; -} -.ui-datepicker-multi .ui-datepicker-group { - float: left; -} -.ui-datepicker-multi .ui-datepicker-group table { - width: 95%; - margin: 0 auto .4em; -} -.ui-datepicker-multi-2 .ui-datepicker-group { - width: 50%; -} -.ui-datepicker-multi-3 .ui-datepicker-group { - width: 33.3%; -} -.ui-datepicker-multi-4 .ui-datepicker-group { - width: 25%; -} -.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header, -.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { - border-left-width: 0; -} -.ui-datepicker-multi .ui-datepicker-buttonpane { - clear: left; -} -.ui-datepicker-row-break { - clear: both; - width: 100%; - font-size: 0; -} - -/* RTL support */ -.ui-datepicker-rtl { - direction: rtl; -} -.ui-datepicker-rtl .ui-datepicker-prev { - right: 2px; - left: auto; -} -.ui-datepicker-rtl .ui-datepicker-next { - left: 2px; - right: auto; -} -.ui-datepicker-rtl .ui-datepicker-prev:hover { - right: 1px; - left: auto; -} -.ui-datepicker-rtl .ui-datepicker-next:hover { - left: 1px; - right: auto; -} -.ui-datepicker-rtl .ui-datepicker-buttonpane { - clear: right; -} -.ui-datepicker-rtl .ui-datepicker-buttonpane button { - float: left; -} -.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current, -.ui-datepicker-rtl .ui-datepicker-group { - float: right; -} -.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header, -.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { - border-right-width: 0; - border-left-width: 1px; -} -.ui-dialog { - position: absolute; - top: 0; - left: 0; - padding: .2em; - outline: 0; -} -.ui-dialog .ui-dialog-titlebar { - padding: .4em 1em; - position: relative; -} -.ui-dialog .ui-dialog-title { - float: left; - margin: .1em 0; - white-space: nowrap; - width: 90%; - overflow: hidden; - text-overflow: ellipsis; -} -.ui-dialog .ui-dialog-titlebar-close { - position: absolute; - right: .3em; - top: 50%; - width: 21px; - margin: -10px 0 0 0; - padding: 1px; - height: 20px; -} -.ui-dialog .ui-dialog-content { - position: relative; - border: 0; - padding: .5em 1em; - background: none; - overflow: auto; -} -.ui-dialog .ui-dialog-buttonpane { - text-align: left; - border-width: 1px 0 0 0; - background-image: none; - margin-top: .5em; - padding: .3em 1em .5em .4em; -} -.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { - float: right; -} -.ui-dialog .ui-dialog-buttonpane button { - margin: .5em .4em .5em 0; - cursor: pointer; -} -.ui-dialog .ui-resizable-se { - width: 12px; - height: 12px; - right: -5px; - bottom: -5px; - background-position: 16px 16px; -} -.ui-draggable .ui-dialog-titlebar { - cursor: move; -} -.ui-menu { - list-style: none; - padding: 2px; - margin: 0; - display: block; - outline: none; -} -.ui-menu .ui-menu { - margin-top: -3px; - position: absolute; -} -.ui-menu .ui-menu-item { - margin: 0; - padding: 0; - width: 100%; - /* support: IE10, see #8844 */ - list-style-image: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); -} -.ui-menu .ui-menu-divider { - margin: 5px -2px 5px -2px; - height: 0; - font-size: 0; - line-height: 0; - border-width: 1px 0 0 0; -} -.ui-menu .ui-menu-item a { - text-decoration: none; - display: block; - padding: 2px .4em; - line-height: 1.5; - min-height: 0; /* support: IE7 */ - font-weight: normal; -} -.ui-menu .ui-menu-item a.ui-state-focus, -.ui-menu .ui-menu-item a.ui-state-active { - font-weight: normal; - margin: -1px; -} - -.ui-menu .ui-state-disabled { - font-weight: normal; - margin: .4em 0 .2em; - line-height: 1.5; -} -.ui-menu .ui-state-disabled a { - cursor: default; -} - -/* icon support */ -.ui-menu-icons { - position: relative; -} -.ui-menu-icons .ui-menu-item a { - position: relative; - padding-left: 2em; -} - -/* left-aligned */ -.ui-menu .ui-icon { - position: absolute; - top: .2em; - left: .2em; -} - -/* right-aligned */ -.ui-menu .ui-menu-icon { - position: static; - float: right; -} -.ui-progressbar { - height: 2em; - text-align: left; - overflow: hidden; -} -.ui-progressbar .ui-progressbar-value { - margin: -1px; - height: 100%; -} -.ui-progressbar .ui-progressbar-overlay { - background: url("images/animated-overlay.gif"); - height: 100%; - filter: alpha(opacity=25); - opacity: 0.25; -} -.ui-progressbar-indeterminate .ui-progressbar-value { - background-image: none; -} -.ui-slider { - position: relative; - text-align: left; -} -.ui-slider .ui-slider-handle { - position: absolute; - z-index: 2; - width: 1.2em; - height: 1.2em; - cursor: default; -} -.ui-slider .ui-slider-range { - position: absolute; - z-index: 1; - font-size: .7em; - display: block; - border: 0; - background-position: 0 0; -} - -/* For IE8 - See #6727 */ -.ui-slider.ui-state-disabled .ui-slider-handle, -.ui-slider.ui-state-disabled .ui-slider-range { - filter: inherit; -} - -.ui-slider-horizontal { - height: .8em; -} -.ui-slider-horizontal .ui-slider-handle { - top: -.3em; - margin-left: -.6em; -} -.ui-slider-horizontal .ui-slider-range { - top: 0; - height: 100%; -} -.ui-slider-horizontal .ui-slider-range-min { - left: 0; -} -.ui-slider-horizontal .ui-slider-range-max { - right: 0; -} - -.ui-slider-vertical { - width: .8em; - height: 100px; -} -.ui-slider-vertical .ui-slider-handle { - left: -.3em; - margin-left: 0; - margin-bottom: -.6em; -} -.ui-slider-vertical .ui-slider-range { - left: 0; - width: 100%; -} -.ui-slider-vertical .ui-slider-range-min { - bottom: 0; -} -.ui-slider-vertical .ui-slider-range-max { - top: 0; -} -.ui-spinner { - position: relative; - display: inline-block; - overflow: hidden; - padding: 0; - vertical-align: middle; -} -.ui-spinner-input { - border: none; - background: none; - color: inherit; - padding: 0; - margin: .2em 0; - vertical-align: middle; - margin-left: .4em; - margin-right: 22px; -} -.ui-spinner-button { - width: 16px; - height: 50%; - font-size: .5em; - padding: 0; - margin: 0; - text-align: center; - position: absolute; - cursor: default; - display: block; - overflow: hidden; - right: 0; -} -/* more specificity required here to overide default borders */ -.ui-spinner a.ui-spinner-button { - border-top: none; - border-bottom: none; - border-right: none; -} -/* vertical centre icon */ -.ui-spinner .ui-icon { - position: absolute; - margin-top: -8px; - top: 50%; - left: 0; -} -.ui-spinner-up { - top: 0; -} -.ui-spinner-down { - bottom: 0; -} - -/* TR overrides */ -.ui-spinner .ui-icon-triangle-1-s { - /* need to fix icons sprite */ - background-position: -65px -16px; -} -.ui-tabs { - position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ - padding: .2em; -} -.ui-tabs .ui-tabs-nav { - margin: 0; - padding: .2em .2em 0; -} -.ui-tabs .ui-tabs-nav li { - list-style: none; - float: left; - position: relative; - top: 0; - margin: 1px .2em 0 0; - border-bottom-width: 0; - padding: 0; - white-space: nowrap; -} -.ui-tabs .ui-tabs-nav li a { - float: left; - padding: .5em 1em; - text-decoration: none; -} -.ui-tabs .ui-tabs-nav li.ui-tabs-active { - margin-bottom: -1px; - padding-bottom: 1px; -} -.ui-tabs .ui-tabs-nav li.ui-tabs-active a, -.ui-tabs .ui-tabs-nav li.ui-state-disabled a, -.ui-tabs .ui-tabs-nav li.ui-tabs-loading a { - cursor: text; -} -.ui-tabs .ui-tabs-nav li a, /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ -.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { - cursor: pointer; -} -.ui-tabs .ui-tabs-panel { - display: block; - border-width: 0; - padding: 1em 1.4em; - background: none; -} -.ui-tooltip { - padding: 8px; - position: absolute; - z-index: 9999; - max-width: 300px; - -webkit-box-shadow: 0 0 5px #aaa; - box-shadow: 0 0 5px #aaa; -} -body .ui-tooltip { - border-width: 2px; -} - -/* Component containers -----------------------------------*/ -.ui-widget { - font-family: Verdana,Arial,sans-serif; - font-size: 1.1em; -} -.ui-widget .ui-widget { - font-size: 1em; -} -.ui-widget input, -.ui-widget select, -.ui-widget textarea, -.ui-widget button { - font-family: Verdana,Arial,sans-serif; - font-size: 1em; -} -.ui-widget-content { - border: 1px solid #aaaaaa; - background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; - color: #222222; -} -.ui-widget-content a { - color: #222222; -} -.ui-widget-header { - border: 1px solid #aaaaaa; - background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; - color: #222222; - font-weight: bold; -} -.ui-widget-header a { - color: #222222; -} - -/* Interaction states -----------------------------------*/ -.ui-state-default, -.ui-widget-content .ui-state-default, -.ui-widget-header .ui-state-default { - border: 1px solid #d3d3d3; - background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; - font-weight: normal; - color: #555555; -} -.ui-state-default a, -.ui-state-default a:link, -.ui-state-default a:visited { - color: #555555; - text-decoration: none; -} -.ui-state-hover, -.ui-widget-content .ui-state-hover, -.ui-widget-header .ui-state-hover, -.ui-state-focus, -.ui-widget-content .ui-state-focus, -.ui-widget-header .ui-state-focus { - border: 1px solid #999999; - background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; - font-weight: normal; - color: #212121; -} -.ui-state-hover a, -.ui-state-hover a:hover, -.ui-state-hover a:link, -.ui-state-hover a:visited { - color: #212121; - text-decoration: none; -} -.ui-state-active, -.ui-widget-content .ui-state-active, -.ui-widget-header .ui-state-active { - border: 1px solid #aaaaaa; - background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; - font-weight: normal; - color: #212121; -} -.ui-state-active a, -.ui-state-active a:link, -.ui-state-active a:visited { - color: #212121; - text-decoration: none; -} - -/* Interaction Cues -----------------------------------*/ -.ui-state-highlight, -.ui-widget-content .ui-state-highlight, -.ui-widget-header .ui-state-highlight { - border: 1px solid #fcefa1; - background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; - color: #363636; -} -.ui-state-highlight a, -.ui-widget-content .ui-state-highlight a, -.ui-widget-header .ui-state-highlight a { - color: #363636; -} -.ui-state-error, -.ui-widget-content .ui-state-error, -.ui-widget-header .ui-state-error { - border: 1px solid #cd0a0a; - background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; - color: #cd0a0a; -} -.ui-state-error a, -.ui-widget-content .ui-state-error a, -.ui-widget-header .ui-state-error a { - color: #cd0a0a; -} -.ui-state-error-text, -.ui-widget-content .ui-state-error-text, -.ui-widget-header .ui-state-error-text { - color: #cd0a0a; -} -.ui-priority-primary, -.ui-widget-content .ui-priority-primary, -.ui-widget-header .ui-priority-primary { - font-weight: bold; -} -.ui-priority-secondary, -.ui-widget-content .ui-priority-secondary, -.ui-widget-header .ui-priority-secondary { - opacity: .7; - filter:Alpha(Opacity=70); - font-weight: normal; -} -.ui-state-disabled, -.ui-widget-content .ui-state-disabled, -.ui-widget-header .ui-state-disabled { - opacity: .35; - filter:Alpha(Opacity=35); - background-image: none; -} -.ui-state-disabled .ui-icon { - filter:Alpha(Opacity=35); /* For IE8 - See #6059 */ -} - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { - width: 16px; - height: 16px; -} -.ui-icon, -.ui-widget-content .ui-icon { - background-image: url(images/ui-icons_222222_256x240.png); -} -.ui-widget-header .ui-icon { - background-image: url(images/ui-icons_222222_256x240.png); -} -.ui-state-default .ui-icon { - background-image: url(images/ui-icons_888888_256x240.png); -} -.ui-state-hover .ui-icon, -.ui-state-focus .ui-icon { - background-image: url(images/ui-icons_454545_256x240.png); -} -.ui-state-active .ui-icon { - background-image: url(images/ui-icons_454545_256x240.png); -} -.ui-state-highlight .ui-icon { - background-image: url(images/ui-icons_2e83ff_256x240.png); -} -.ui-state-error .ui-icon, -.ui-state-error-text .ui-icon { - background-image: url(images/ui-icons_cd0a0a_256x240.png); -} - -/* positioning */ -.ui-icon-blank { background-position: 16px 16px; } -.ui-icon-carat-1-n { background-position: 0 0; } -.ui-icon-carat-1-ne { background-position: -16px 0; } -.ui-icon-carat-1-e { background-position: -32px 0; } -.ui-icon-carat-1-se { background-position: -48px 0; } -.ui-icon-carat-1-s { background-position: -64px 0; } -.ui-icon-carat-1-sw { background-position: -80px 0; } -.ui-icon-carat-1-w { background-position: -96px 0; } -.ui-icon-carat-1-nw { background-position: -112px 0; } -.ui-icon-carat-2-n-s { background-position: -128px 0; } -.ui-icon-carat-2-e-w { background-position: -144px 0; } -.ui-icon-triangle-1-n { background-position: 0 -16px; } -.ui-icon-triangle-1-ne { background-position: -16px -16px; } -.ui-icon-triangle-1-e { background-position: -32px -16px; } -.ui-icon-triangle-1-se { background-position: -48px -16px; } -.ui-icon-triangle-1-s { background-position: -64px -16px; } -.ui-icon-triangle-1-sw { background-position: -80px -16px; } -.ui-icon-triangle-1-w { background-position: -96px -16px; } -.ui-icon-triangle-1-nw { background-position: -112px -16px; } -.ui-icon-triangle-2-n-s { background-position: -128px -16px; } -.ui-icon-triangle-2-e-w { background-position: -144px -16px; } -.ui-icon-arrow-1-n { background-position: 0 -32px; } -.ui-icon-arrow-1-ne { background-position: -16px -32px; } -.ui-icon-arrow-1-e { background-position: -32px -32px; } -.ui-icon-arrow-1-se { background-position: -48px -32px; } -.ui-icon-arrow-1-s { background-position: -64px -32px; } -.ui-icon-arrow-1-sw { background-position: -80px -32px; } -.ui-icon-arrow-1-w { background-position: -96px -32px; } -.ui-icon-arrow-1-nw { background-position: -112px -32px; } -.ui-icon-arrow-2-n-s { background-position: -128px -32px; } -.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } -.ui-icon-arrow-2-e-w { background-position: -160px -32px; } -.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } -.ui-icon-arrowstop-1-n { background-position: -192px -32px; } -.ui-icon-arrowstop-1-e { background-position: -208px -32px; } -.ui-icon-arrowstop-1-s { background-position: -224px -32px; } -.ui-icon-arrowstop-1-w { background-position: -240px -32px; } -.ui-icon-arrowthick-1-n { background-position: 0 -48px; } -.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } -.ui-icon-arrowthick-1-e { background-position: -32px -48px; } -.ui-icon-arrowthick-1-se { background-position: -48px -48px; } -.ui-icon-arrowthick-1-s { background-position: -64px -48px; } -.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } -.ui-icon-arrowthick-1-w { background-position: -96px -48px; } -.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } -.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } -.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } -.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } -.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } -.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } -.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } -.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } -.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } -.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } -.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } -.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } -.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } -.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } -.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } -.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } -.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } -.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } -.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } -.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } -.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } -.ui-icon-arrow-4 { background-position: 0 -80px; } -.ui-icon-arrow-4-diag { background-position: -16px -80px; } -.ui-icon-extlink { background-position: -32px -80px; } -.ui-icon-newwin { background-position: -48px -80px; } -.ui-icon-refresh { background-position: -64px -80px; } -.ui-icon-shuffle { background-position: -80px -80px; } -.ui-icon-transfer-e-w { background-position: -96px -80px; } -.ui-icon-transferthick-e-w { background-position: -112px -80px; } -.ui-icon-folder-collapsed { background-position: 0 -96px; } -.ui-icon-folder-open { background-position: -16px -96px; } -.ui-icon-document { background-position: -32px -96px; } -.ui-icon-document-b { background-position: -48px -96px; } -.ui-icon-note { background-position: -64px -96px; } -.ui-icon-mail-closed { background-position: -80px -96px; } -.ui-icon-mail-open { background-position: -96px -96px; } -.ui-icon-suitcase { background-position: -112px -96px; } -.ui-icon-comment { background-position: -128px -96px; } -.ui-icon-person { background-position: -144px -96px; } -.ui-icon-print { background-position: -160px -96px; } -.ui-icon-trash { background-position: -176px -96px; } -.ui-icon-locked { background-position: -192px -96px; } -.ui-icon-unlocked { background-position: -208px -96px; } -.ui-icon-bookmark { background-position: -224px -96px; } -.ui-icon-tag { background-position: -240px -96px; } -.ui-icon-home { background-position: 0 -112px; } -.ui-icon-flag { background-position: -16px -112px; } -.ui-icon-calendar { background-position: -32px -112px; } -.ui-icon-cart { background-position: -48px -112px; } -.ui-icon-pencil { background-position: -64px -112px; } -.ui-icon-clock { background-position: -80px -112px; } -.ui-icon-disk { background-position: -96px -112px; } -.ui-icon-calculator { background-position: -112px -112px; } -.ui-icon-zoomin { background-position: -128px -112px; } -.ui-icon-zoomout { background-position: -144px -112px; } -.ui-icon-search { background-position: -160px -112px; } -.ui-icon-wrench { background-position: -176px -112px; } -.ui-icon-gear { background-position: -192px -112px; } -.ui-icon-heart { background-position: -208px -112px; } -.ui-icon-star { background-position: -224px -112px; } -.ui-icon-link { background-position: -240px -112px; } -.ui-icon-cancel { background-position: 0 -128px; } -.ui-icon-plus { background-position: -16px -128px; } -.ui-icon-plusthick { background-position: -32px -128px; } -.ui-icon-minus { background-position: -48px -128px; } -.ui-icon-minusthick { background-position: -64px -128px; } -.ui-icon-close { background-position: -80px -128px; } -.ui-icon-closethick { background-position: -96px -128px; } -.ui-icon-key { background-position: -112px -128px; } -.ui-icon-lightbulb { background-position: -128px -128px; } -.ui-icon-scissors { background-position: -144px -128px; } -.ui-icon-clipboard { background-position: -160px -128px; } -.ui-icon-copy { background-position: -176px -128px; } -.ui-icon-contact { background-position: -192px -128px; } -.ui-icon-image { background-position: -208px -128px; } -.ui-icon-video { background-position: -224px -128px; } -.ui-icon-script { background-position: -240px -128px; } -.ui-icon-alert { background-position: 0 -144px; } -.ui-icon-info { background-position: -16px -144px; } -.ui-icon-notice { background-position: -32px -144px; } -.ui-icon-help { background-position: -48px -144px; } -.ui-icon-check { background-position: -64px -144px; } -.ui-icon-bullet { background-position: -80px -144px; } -.ui-icon-radio-on { background-position: -96px -144px; } -.ui-icon-radio-off { background-position: -112px -144px; } -.ui-icon-pin-w { background-position: -128px -144px; } -.ui-icon-pin-s { background-position: -144px -144px; } -.ui-icon-play { background-position: 0 -160px; } -.ui-icon-pause { background-position: -16px -160px; } -.ui-icon-seek-next { background-position: -32px -160px; } -.ui-icon-seek-prev { background-position: -48px -160px; } -.ui-icon-seek-end { background-position: -64px -160px; } -.ui-icon-seek-start { background-position: -80px -160px; } -/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ -.ui-icon-seek-first { background-position: -80px -160px; } -.ui-icon-stop { background-position: -96px -160px; } -.ui-icon-eject { background-position: -112px -160px; } -.ui-icon-volume-off { background-position: -128px -160px; } -.ui-icon-volume-on { background-position: -144px -160px; } -.ui-icon-power { background-position: 0 -176px; } -.ui-icon-signal-diag { background-position: -16px -176px; } -.ui-icon-signal { background-position: -32px -176px; } -.ui-icon-battery-0 { background-position: -48px -176px; } -.ui-icon-battery-1 { background-position: -64px -176px; } -.ui-icon-battery-2 { background-position: -80px -176px; } -.ui-icon-battery-3 { background-position: -96px -176px; } -.ui-icon-circle-plus { background-position: 0 -192px; } -.ui-icon-circle-minus { background-position: -16px -192px; } -.ui-icon-circle-close { background-position: -32px -192px; } -.ui-icon-circle-triangle-e { background-position: -48px -192px; } -.ui-icon-circle-triangle-s { background-position: -64px -192px; } -.ui-icon-circle-triangle-w { background-position: -80px -192px; } -.ui-icon-circle-triangle-n { background-position: -96px -192px; } -.ui-icon-circle-arrow-e { background-position: -112px -192px; } -.ui-icon-circle-arrow-s { background-position: -128px -192px; } -.ui-icon-circle-arrow-w { background-position: -144px -192px; } -.ui-icon-circle-arrow-n { background-position: -160px -192px; } -.ui-icon-circle-zoomin { background-position: -176px -192px; } -.ui-icon-circle-zoomout { background-position: -192px -192px; } -.ui-icon-circle-check { background-position: -208px -192px; } -.ui-icon-circlesmall-plus { background-position: 0 -208px; } -.ui-icon-circlesmall-minus { background-position: -16px -208px; } -.ui-icon-circlesmall-close { background-position: -32px -208px; } -.ui-icon-squaresmall-plus { background-position: -48px -208px; } -.ui-icon-squaresmall-minus { background-position: -64px -208px; } -.ui-icon-squaresmall-close { background-position: -80px -208px; } -.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } -.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } -.ui-icon-grip-solid-vertical { background-position: -32px -224px; } -.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } -.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } -.ui-icon-grip-diagonal-se { background-position: -80px -224px; } - - -/* Misc visuals -----------------------------------*/ - -/* Corner radius */ -.ui-corner-all, -.ui-corner-top, -.ui-corner-left, -.ui-corner-tl { - border-top-left-radius: 4px; -} -.ui-corner-all, -.ui-corner-top, -.ui-corner-right, -.ui-corner-tr { - border-top-right-radius: 4px; -} -.ui-corner-all, -.ui-corner-bottom, -.ui-corner-left, -.ui-corner-bl { - border-bottom-left-radius: 4px; -} -.ui-corner-all, -.ui-corner-bottom, -.ui-corner-right, -.ui-corner-br { - border-bottom-right-radius: 4px; -} - -/* Overlays */ -.ui-widget-overlay { - background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; - opacity: .3; - filter: Alpha(Opacity=30); -} -.ui-widget-shadow { - margin: -8px 0 0 -8px; - padding: 8px; - background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; - opacity: .3; - filter: Alpha(Opacity=30); - border-radius: 8px; -} diff --git a/extensions/yii/jui/composer.json b/extensions/yii/jui/composer.json deleted file mode 100644 index a8b9559..0000000 --- a/extensions/yii/jui/composer.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "yiisoft/yii2-jui", - "description": "The Jquery UI extension for the Yii framework", - "keywords": ["yii", "Jquery UI", "renderer"], - "type": "yii2-extension", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?labels=ext%3Ajui", - "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": "*" - }, - "autoload": { - "psr-0": { "yii\\jui\\": "" } - }, - "target-dir": "yii/jui" -} diff --git a/extensions/yii/mongodb/ActiveQuery.php b/extensions/yii/mongodb/ActiveQuery.php deleted file mode 100644 index 53a8aaa..0000000 --- a/extensions/yii/mongodb/ActiveQuery.php +++ /dev/null @@ -1,109 +0,0 @@ -with('orders')->asArray()->all(); - * ~~~ - * - * @property Collection $collection Collection instance. This property is read-only. - * - * @author Paul Klimov - * @since 2.0 - */ -class ActiveQuery extends Query implements ActiveQueryInterface -{ - use ActiveQueryTrait; - - /** - * Executes query and returns all results as an array. - * @param Connection $db the Mongo connection used to execute the query. - * If null, the Mongo 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) - { - $cursor = $this->buildCursor($db); - $rows = $this->fetchRows($cursor); - if (!empty($rows)) { - $models = $this->createModels($rows); - if (!empty($this->with)) { - $this->findWith($this->with, $models); - } - return $models; - } else { - return []; - } - } - - /** - * Executes query and returns a single row of result. - * @param Connection $db the Mongo connection used to execute the query. - * If null, the Mongo 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) - { - $row = parent::one($db); - if ($row !== false) { - if ($this->asArray) { - $model = $row; - } else { - /** @var ActiveRecord $class */ - $class = $this->modelClass; - $model = $class::create($row); - } - if (!empty($this->with)) { - $models = [$model]; - $this->findWith($this->with, $models); - $model = $models[0]; - } - return $model; - } else { - return null; - } - } - - /** - * Returns the Mongo collection for this query. - * @param Connection $db Mongo connection. - * @return Collection collection instance. - */ - public function getCollection($db = null) - { - /** @var ActiveRecord $modelClass */ - $modelClass = $this->modelClass; - if ($db === null) { - $db = $modelClass::getDb(); - } - if ($this->from === null) { - $this->from = $modelClass::collectionName(); - } - return $db->getCollection($this->from); - } -} \ No newline at end of file diff --git a/extensions/yii/mongodb/ActiveRecord.php b/extensions/yii/mongodb/ActiveRecord.php deleted file mode 100644 index d2178ea..0000000 --- a/extensions/yii/mongodb/ActiveRecord.php +++ /dev/null @@ -1,353 +0,0 @@ - - * @since 2.0 - */ -abstract class ActiveRecord extends BaseActiveRecord -{ - /** - * Returns the Mongo connection used by this AR class. - * By default, the "mongodb" application component is used as the Mongo 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('mongodb'); - } - - /** - * Updates all documents in the collection using the provided attribute values and conditions. - * For example, to change the status to be 1 for all customers whose status is 2: - * - * ~~~ - * Customer::updateAll(['status' => 1], ['status' = 2]); - * ~~~ - * - * @param array $attributes attribute values (name-value pairs) to be saved into the collection - * @param array $condition description of the objects to update. - * Please refer to [[Query::where()]] on how to specify this parameter. - * @param array $options list of options in format: optionName => optionValue. - * @return integer the number of documents updated. - */ - public static function updateAll($attributes, $condition = [], $options = []) - { - return static::getCollection()->update($condition, $attributes, $options); - } - - /** - * Updates all documents in the collection 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 array $condition description of the objects to update. - * Please refer to [[Query::where()]] on how to specify this parameter. - * @param array $options list of options in format: optionName => optionValue. - * @return integer the number of documents updated. - */ - public static function updateAllCounters($counters, $condition = [], $options = []) - { - return static::getCollection()->update($condition, ['$inc' => $counters], $options); - } - - /** - * Deletes documents in the collection using the provided conditions. - * WARNING: If you do not specify any condition, this method will delete documents rows in the collection. - * - * For example, to delete all customers whose status is 3: - * - * ~~~ - * Customer::deleteAll('status = 3'); - * ~~~ - * - * @param array $condition description of the objects to delete. - * Please refer to [[Query::where()]] on how to specify this parameter. - * @param array $options list of options in format: optionName => optionValue. - * @return integer the number of documents deleted. - */ - public static function deleteAll($condition = [], $options = []) - { - $options['w'] = 1; - if (!array_key_exists('multiple', $options)) { - $options['multiple'] = true; - } - return static::getCollection()->remove($condition, $options); - } - - /** - * Creates an [[ActiveQuery]] instance. - * This method is called by [[find()]] to start a "find" command. - * You may override this method to return a customized query (e.g. `CustomerQuery` specified - * written for querying `Customer` purpose.) - * @return ActiveQuery the newly created [[ActiveQuery]] instance. - */ - public static function createQuery() - { - return new ActiveQuery(['modelClass' => get_called_class()]); - } - - /** - * Declares the name of the Mongo collection associated with this AR class. - * Collection name can be either a string or array: - * - if string considered as the name of the collection inside the default database. - * - if array - first element considered as the name of the database, second - as - * name of collection inside that database - * By default this method returns the class name as the collection name by calling [[Inflector::camel2id()]]. - * For example, 'Customer' becomes 'customer', and 'OrderItem' becomes - * 'order_item'. You may override this method if the table is not named after this convention. - * @return string|array the collection name - */ - public static function collectionName() - { - return Inflector::camel2id(StringHelper::basename(get_called_class()), '_'); - } - - /** - * Return the Mongo collection instance for this AR class. - * @return Collection collection instance. - */ - public static function getCollection() - { - return static::getDb()->getCollection(static::collectionName()); - } - - /** - * Returns the primary key name(s) for this AR class. - * The default implementation will return ['_id']. - * - * Note that an array should be returned even for a collection with single primary key. - * - * @return string[] the primary keys of the associated Mongo collection. - */ - public static function primaryKey() - { - return ['_id']; - } - - /** - * Creates an [[ActiveRelation]] instance. - * This method is called by [[hasOne()]] and [[hasMany()]] to create a relation instance. - * You may override this method to return a customized relation. - * @param array $config the configuration passed to the ActiveRelation class. - * @return ActiveRelation the newly created [[ActiveRelation]] instance. - */ - public static function createActiveRelation($config = []) - { - return new ActiveRelation($config); - } - - /** - * Returns the list of all attribute names of the model. - * This method must be overridden by child classes to define available attributes. - * Note: primary key attribute "_id" should be always present in returned array. - * For example: - * ~~~ - * public function attributes() - * { - * return ['_id', 'name', 'address', 'status']; - * } - * ~~~ - * @return array list of attribute names. - */ - public function attributes() - { - throw new InvalidConfigException('The attributes() method of mongodb ActiveRecord has to be implemented by child classes.'); - } - - /** - * Inserts a row into the associated Mongo collection 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 collection. 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 primary key is null during insertion, it will be populated with the actual - * value 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 collection. - * @param array $attributes list of attributes that need to be saved. Defaults to null, - * meaning all attributes that are loaded will be saved. - * @return boolean whether the attributes are valid and the record is inserted successfully. - * @throws \Exception in case insert failed. - */ - public function insert($runValidation = true, $attributes = null) - { - if ($runValidation && !$this->validate($attributes)) { - return false; - } - $result = $this->insertInternal($attributes); - return $result; - } - - /** - * @see ActiveRecord::insert() - */ - protected function insertInternal($attributes = null) - { - if (!$this->beforeSave(true)) { - return false; - } - $values = $this->getDirtyAttributes($attributes); - if (empty($values)) { - $currentAttributes = $this->getAttributes(); - foreach ($this->primaryKey() as $key) { - $values[$key] = isset($currentAttributes[$key]) ? $currentAttributes[$key] : null; - } - } - $collection = static::getCollection(); - $newId = $collection->insert($values); - $this->setAttribute('_id', $newId); - foreach ($values as $name => $value) { - $this->setOldAttribute($name, $value); - } - $this->afterSave(true); - return true; - } - - /** - * @see ActiveRecord::update() - * @throws StaleObjectException - */ - protected function updateInternal($attributes = null) - { - if (!$this->beforeSave(false)) { - return false; - } - $values = $this->getDirtyAttributes($attributes); - if (empty($values)) { - $this->afterSave(false); - return 0; - } - $condition = $this->getOldPrimaryKey(true); - $lock = $this->optimisticLock(); - if ($lock !== null) { - if (!isset($values[$lock])) { - $values[$lock] = $this->$lock + 1; - } - $condition[$lock] = $this->$lock; - } - // We do not check the return value of update() because it's possible - // that it doesn't change anything and thus returns 0. - $rows = static::getCollection()->update($condition, $values); - - if ($lock !== null && !$rows) { - throw new StaleObjectException('The object being updated is outdated.'); - } - - foreach ($values as $name => $value) { - $this->setOldAttribute($name, $this->getAttribute($name)); - } - $this->afterSave(false); - return $rows; - } - - /** - * Deletes the document corresponding to this active record from the collection. - * - * This method performs the following steps in order: - * - * 1. call [[beforeDelete()]]. If the method returns false, it will skip the - * rest of the steps; - * 2. delete the document from the collection; - * 3. call [[afterDelete()]]. - * - * In the above step 1 and 3, events named [[EVENT_BEFORE_DELETE]] and [[EVENT_AFTER_DELETE]] - * will be raised by the corresponding methods. - * - * @return integer|boolean the number of documents deleted, or false if the deletion is unsuccessful for some reason. - * Note that it is possible the number of documents deleted is 0, even though the deletion execution is successful. - * @throws StaleObjectException if [[optimisticLock|optimistic locking]] is enabled and the data - * being deleted is outdated. - * @throws \Exception in case delete failed. - */ - public function delete() - { - $result = false; - if ($this->beforeDelete()) { - $result = $this->deleteInternal(); - $this->afterDelete(); - } - return $result; - } - - /** - * @see ActiveRecord::delete() - * @throws StaleObjectException - */ - protected function deleteInternal() - { - // we do not check the return value of deleteAll() because it's possible - // the record is already deleted in the database and thus the method will return 0 - $condition = $this->getOldPrimaryKey(true); - $lock = $this->optimisticLock(); - if ($lock !== null) { - $condition[$lock] = $this->$lock; - } - $result = static::getCollection()->remove($condition); - if ($lock !== null && !$result) { - throw new StaleObjectException('The object being deleted is outdated.'); - } - $this->setOldAttributes(null); - return $result; - } - - /** - * Returns a value indicating whether the given active record is the same as the current one. - * The comparison is made by comparing the table names and the primary key values of the two active records. - * If one of the records [[isNewRecord|is new]] they are also considered not equal. - * @param ActiveRecord $record record to compare to - * @return boolean whether the two active records refer to the same row in the same Mongo collection. - */ - public function equals($record) - { - if ($this->isNewRecord || $record->isNewRecord) { - return false; - } - return $this->collectionName() === $record->collectionName() && (string)$this->getPrimaryKey() === (string)$record->getPrimaryKey(); - } -} \ No newline at end of file diff --git a/extensions/yii/mongodb/ActiveRelation.php b/extensions/yii/mongodb/ActiveRelation.php deleted file mode 100644 index 785b701..0000000 --- a/extensions/yii/mongodb/ActiveRelation.php +++ /dev/null @@ -1,53 +0,0 @@ - - * @since 2.0 - */ -class ActiveRelation extends ActiveQuery implements ActiveRelationInterface -{ - use ActiveRelationTrait; - - /** - * @inheritdoc - */ - protected function buildCursor($db = null) - { - if ($this->primaryModel !== null) { - // lazy loading - if ($this->via instanceof self) { - // via pivot collection - $viaModels = $this->via->findPivotRows([$this->primaryModel]); - $this->filterByModels($viaModels); - } elseif (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::buildCursor($db); - } -} \ No newline at end of file diff --git a/extensions/yii/mongodb/CHANGELOG.md b/extensions/yii/mongodb/CHANGELOG.md deleted file mode 100644 index ab31546..0000000 --- a/extensions/yii/mongodb/CHANGELOG.md +++ /dev/null @@ -1,7 +0,0 @@ -Yii Framework 2 mongodb extension Change Log -============================================ - -2.0.0 beta under development ----------------------------- - -- Initial release. diff --git a/extensions/yii/mongodb/Collection.php b/extensions/yii/mongodb/Collection.php deleted file mode 100644 index 9a1b68a..0000000 --- a/extensions/yii/mongodb/Collection.php +++ /dev/null @@ -1,894 +0,0 @@ -mongo->getCollection('customer'); - * $collection->insert(['name' => 'John Smith', 'status' => 1]); - * ~~~ - * - * To perform "find" queries, please use [[Query]] instead. - * - * Mongo uses JSON format to specify query conditions with quite specific syntax. - * However Collection class provides the ability of "translating" common condition format used "yii\db\*" - * into Mongo condition. - * For example: - * ~~~ - * $condition = [ - * [ - * 'OR', - * ['AND', ['first_name' => 'John'], ['last_name' => 'Smith']], - * ['status' => [1, 2, 3]] - * ], - * ]; - * print_r($collection->buildCondition($condition)); - * // outputs : - * [ - * '$or' => [ - * [ - * 'first_name' => 'John', - * 'last_name' => 'John', - * ], - * [ - * 'status' => ['$in' => [1, 2, 3]], - * ] - * ] - * ] - * ~~~ - * - * Note: condition values for the key '_id' will be automatically cast to [[\MongoId]] instance, - * even if they are plain strings. However if you have other columns, containing [[\MongoId]], you - * should take care of possible typecast on your own. - * - * @property string $fullName Full name of this collection, including database name. This property is - * read-only. - * @property array $lastError Last error information. This property is read-only. - * @property string $name Name of this collection. This property is read-only. - * - * @author Paul Klimov - * @since 2.0 - */ -class Collection extends Object -{ - /** - * @var \MongoCollection Mongo collection instance. - */ - public $mongoCollection; - - /** - * @return string name of this collection. - */ - public function getName() - { - return $this->mongoCollection->getName(); - } - - /** - * @return string full name of this collection, including database name. - */ - public function getFullName() - { - return $this->mongoCollection->__toString(); - } - - /** - * @return array last error information. - */ - public function getLastError() - { - return $this->mongoCollection->db->lastError(); - } - - /** - * Composes log/profile token. - * @param string $command command name - * @param array $arguments command arguments. - * @return string token. - */ - protected function composeLogToken($command, $arguments = []) - { - $parts = []; - foreach ($arguments as $argument) { - $parts[] = is_scalar($argument) ? $argument : Json::encode($argument); - } - return $this->getFullName() . '.' . $command . '(' . implode(', ', $parts) . ')'; - } - - /** - * Drops this collection. - * @throws Exception on failure. - * @return boolean whether the operation successful. - */ - public function drop() - { - $token = $this->composeLogToken('drop'); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $result = $this->mongoCollection->drop(); - $this->tryResultError($result); - Yii::endProfile($token, __METHOD__); - return true; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Creates an index on the collection and the specified fields. - * @param array|string $columns column name or list of column names. - * If array is given, each element in the array has as key the field name, and as - * value either 1 for ascending sort, or -1 for descending sort. - * You can specify field using native numeric key with the field name as a value, - * in this case ascending sort will be used. - * For example: - * ~~~ - * [ - * 'name', - * 'status' => -1, - * ] - * ~~~ - * @param array $options list of options in format: optionName => optionValue. - * @throws Exception on failure. - * @return boolean whether the operation successful. - */ - public function createIndex($columns, $options = []) - { - if (!is_array($columns)) { - $columns = [$columns]; - } - $keys = $this->normalizeIndexKeys($columns); - $token = $this->composeLogToken('createIndex', [$keys, $options]); - $options = array_merge(['w' => 1], $options); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $result = $this->mongoCollection->ensureIndex($keys, $options); - $this->tryResultError($result); - Yii::endProfile($token, __METHOD__); - return true; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Drop indexes for specified column(s). - * @param string|array $columns column name or list of column names. - * If array is given, each element in the array has as key the field name, and as - * value either 1 for ascending sort, or -1 for descending sort. - * Use value 'text' to specify text index. - * You can specify field using native numeric key with the field name as a value, - * in this case ascending sort will be used. - * For example: - * ~~~ - * [ - * 'name', - * 'status' => -1, - * 'description' => 'text', - * ] - * ~~~ - * @throws Exception on failure. - * @return boolean whether the operation successful. - */ - public function dropIndex($columns) - { - if (!is_array($columns)) { - $columns = [$columns]; - } - $keys = $this->normalizeIndexKeys($columns); - $token = $this->composeLogToken('dropIndex', [$keys]); - Yii::info($token, __METHOD__); - try { - $result = $this->mongoCollection->deleteIndex($keys); - $this->tryResultError($result); - return true; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Compose index keys from given columns/keys list. - * @param array $columns raw columns/keys list. - * @return array normalizes index keys array. - */ - protected function normalizeIndexKeys($columns) - { - $keys = []; - foreach ($columns as $key => $value) { - if (is_numeric($key)) { - $keys[$value] = \MongoCollection::ASCENDING; - } else { - $keys[$key] = $value; - } - } - return $keys; - } - - /** - * Drops all indexes for this collection. - * @throws Exception on failure. - * @return integer count of dropped indexes. - */ - public function dropAllIndexes() - { - $token = $this->composeLogToken('dropIndexes'); - Yii::info($token, __METHOD__); - try { - $result = $this->mongoCollection->deleteIndexes(); - $this->tryResultError($result); - return $result['nIndexesWas']; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Returns a cursor for the search results. - * In order to perform "find" queries use [[Query]] class. - * @param array $condition query condition - * @param array $fields fields to be selected - * @return \MongoCursor cursor for the search results - * @see Query - */ - public function find($condition = [], $fields = []) - { - return $this->mongoCollection->find($this->buildCondition($condition), $fields); - } - - /** - * Inserts new data into collection. - * @param array|object $data data to be inserted. - * @param array $options list of options in format: optionName => optionValue. - * @return \MongoId new record id instance. - * @throws Exception on failure. - */ - public function insert($data, $options = []) - { - $token = $this->composeLogToken('insert', [$data]); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $options = array_merge(['w' => 1], $options); - $this->tryResultError($this->mongoCollection->insert($data, $options)); - Yii::endProfile($token, __METHOD__); - return is_array($data) ? $data['_id'] : $data->_id; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Inserts several new rows into collection. - * @param array $rows array of arrays or objects to be inserted. - * @param array $options list of options in format: optionName => optionValue. - * @return array inserted data, each row will have "_id" key assigned to it. - * @throws Exception on failure. - */ - public function batchInsert($rows, $options = []) - { - $token = $this->composeLogToken('batchInsert', [$rows]); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $options = array_merge(['w' => 1], $options); - $this->tryResultError($this->mongoCollection->batchInsert($rows, $options)); - Yii::endProfile($token, __METHOD__); - return $rows; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Updates the rows, which matches given criteria by given data. - * Note: for "multiple" mode Mongo requires explicit strategy "$set" or "$inc" - * to be specified for the "newData". If no strategy is passed "$set" will be used. - * @param array $condition description of the objects to update. - * @param array $newData the object with which to update the matching records. - * @param array $options list of options in format: optionName => optionValue. - * @return integer|boolean number of updated documents or whether operation was successful. - * @throws Exception on failure. - */ - public function update($condition, $newData, $options = []) - { - $condition = $this->buildCondition($condition); - $options = array_merge(['w' => 1, 'multiple' => true], $options); - if ($options['multiple']) { - $keys = array_keys($newData); - if (!empty($keys) && strncmp('$', $keys[0], 1) !== 0) { - $newData = ['$set' => $newData]; - } - } - $token = $this->composeLogToken('update', [$condition, $newData, $options]); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $result = $this->mongoCollection->update($condition, $newData, $options); - $this->tryResultError($result); - Yii::endProfile($token, __METHOD__); - if (is_array($result) && array_key_exists('n', $result)) { - return $result['n']; - } else { - return true; - } - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Update the existing database data, otherwise insert this data - * @param array|object $data data to be updated/inserted. - * @param array $options list of options in format: optionName => optionValue. - * @return \MongoId updated/new record id instance. - * @throws Exception on failure. - */ - public function save($data, $options = []) - { - $token = $this->composeLogToken('save', [$data]); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $options = array_merge(['w' => 1], $options); - $this->tryResultError($this->mongoCollection->save($data, $options)); - Yii::endProfile($token, __METHOD__); - return is_array($data) ? $data['_id'] : $data->_id; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Removes data from the collection. - * @param array $condition description of records to remove. - * @param array $options list of options in format: optionName => optionValue. - * @return integer|boolean number of updated documents or whether operation was successful. - * @throws Exception on failure. - */ - public function remove($condition = [], $options = []) - { - $condition = $this->buildCondition($condition); - $options = array_merge(['w' => 1, 'multiple' => true], $options); - $token = $this->composeLogToken('remove', [$condition, $options]); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $result = $this->mongoCollection->remove($condition, $options); - $this->tryResultError($result); - Yii::endProfile($token, __METHOD__); - if (is_array($result) && array_key_exists('n', $result)) { - return $result['n']; - } else { - return true; - } - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Returns a list of distinct values for the given column across a collection. - * @param string $column column to use. - * @param array $condition query parameters. - * @return array|boolean array of distinct values, or "false" on failure. - * @throws Exception on failure. - */ - public function distinct($column, $condition = []) - { - $condition = $this->buildCondition($condition); - $token = $this->composeLogToken('distinct', [$column, $condition]); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $result = $this->mongoCollection->distinct($column, $condition); - Yii::endProfile($token, __METHOD__); - return $result; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Performs aggregation using Mongo Aggregation Framework. - * @param array $pipeline list of pipeline operators, or just the first operator - * @param array $pipelineOperator additional pipeline operator. You can specify additional - * pipelines via third argument, fourth argument etc. - * @return array the result of the aggregation. - * @throws Exception on failure. - * @see http://docs.mongodb.org/manual/applications/aggregation/ - */ - public function aggregate($pipeline, $pipelineOperator = []) - { - $args = func_get_args(); - $token = $this->composeLogToken('aggregate', $args); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $result = call_user_func_array([$this->mongoCollection, 'aggregate'], $args); - $this->tryResultError($result); - Yii::endProfile($token, __METHOD__); - return $result['result']; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Performs aggregation using Mongo "group" command. - * @param mixed $keys fields to group by. If an array or non-code object is passed, - * it will be the key used to group results. If instance of [[\MongoCode]] passed, - * it will be treated as a function that returns the key to group by. - * @param array $initial Initial value of the aggregation counter object. - * @param \MongoCode|string $reduce function that takes two arguments (the current - * document and the aggregation to this point) and does the aggregation. - * Argument will be automatically cast to [[\MongoCode]]. - * @param array $options optional parameters to the group command. Valid options include: - * - condition - criteria for including a document in the aggregation. - * - finalize - function called once per unique key that takes the final output of the reduce function. - * @return array the result of the aggregation. - * @throws Exception on failure. - * @see http://docs.mongodb.org/manual/reference/command/group/ - */ - public function group($keys, $initial, $reduce, $options = []) - { - if (!($reduce instanceof \MongoCode)) { - $reduce = new \MongoCode((string)$reduce); - } - if (array_key_exists('condition', $options)) { - $options['condition'] = $this->buildCondition($options['condition']); - } - if (array_key_exists('finalize', $options)) { - if (!($options['finalize'] instanceof \MongoCode)) { - $options['finalize'] = new \MongoCode((string)$options['finalize']); - } - } - $token = $this->composeLogToken('group', [$keys, $initial, $reduce, $options]); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - // Avoid possible E_DEPRECATED for $options: - if (empty($options)) { - $result = $this->mongoCollection->group($keys, $initial, $reduce); - } else { - $result = $this->mongoCollection->group($keys, $initial, $reduce, $options); - } - $this->tryResultError($result); - - Yii::endProfile($token, __METHOD__); - if (array_key_exists('retval', $result)) { - return $result['retval']; - } else { - return []; - } - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Performs aggregation using Mongo "map reduce" mechanism. - * Note: this function will not return the aggregation result, instead it will - * write it inside the another Mongo collection specified by "out" parameter. - * For example: - * - * ~~~ - * $customerCollection = Yii::$app->mongo->getCollection('customer'); - * $resultCollectionName = $customerCollection->mapReduce( - * 'function () {emit(this.status, this.amount)}', - * 'function (key, values) {return Array.sum(values)}', - * 'mapReduceOut', - * ['status' => 3] - * ); - * $query = new Query(); - * $results = $query->from($resultCollectionName)->all(); - * ~~~ - * - * @param \MongoCode|string $map function, which emits map data from collection. - * Argument will be automatically cast to [[\MongoCode]]. - * @param \MongoCode|string $reduce function that takes two arguments (the map key - * and the map values) and does the aggregation. - * Argument will be automatically cast to [[\MongoCode]]. - * @param string|array $out output collection name. It could be a string for simple output - * ('outputCollection'), or an array for parametrized output (['merge' => 'outputCollection']) - * @param array $condition criteria for including a document in the aggregation. - * @param array $options additional optional parameters to the mapReduce command. Valid options include: - * - sort - array - key to sort the input documents. The sort key must be in an existing index for this collection. - * - limit - the maximum number of documents to return in the collection. - * - finalize - function, which follows the reduce method and modifies the output. - * - scope - array - specifies global variables that are accessible in the map, reduce and finalize functions. - * - jsMode - boolean -Specifies whether to convert intermediate data into BSON format between the execution of the map and reduce functions. - * - verbose - boolean - specifies whether to include the timing information in the result information. - * @return string the map reduce output collection name. - * @throws Exception on failure. - */ - public function mapReduce($map, $reduce, $out, $condition = [], $options = []) - { - if (!($map instanceof \MongoCode)) { - $map = new \MongoCode((string)$map); - } - if (!($reduce instanceof \MongoCode)) { - $reduce = new \MongoCode((string)$reduce); - } - $command = [ - 'mapReduce' => $this->getName(), - 'map' => $map, - 'reduce' => $reduce, - 'out' => $out - ]; - if (!empty($condition)) { - $command['query'] = $this->buildCondition($condition); - } - if (array_key_exists('finalize', $options)) { - if (!($options['finalize'] instanceof \MongoCode)) { - $options['finalize'] = new \MongoCode((string)$options['finalize']); - } - } - if (!empty($options)) { - $command = array_merge($command, $options); - } - $token = $this->composeLogToken('mapReduce', [$map, $reduce, $out]); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $command = array_merge(['mapReduce' => $this->getName()], $command); - $result = $this->mongoCollection->db->command($command); - $this->tryResultError($result); - Yii::endProfile($token, __METHOD__); - return $result['result']; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Performs full text search. - * @param string $search string of terms that MongoDB parses and uses to query the text index. - * @param array $condition criteria for filtering a results list. - * @param array $fields list of fields to be returned in result. - * @param array $options additional optional parameters to the mapReduce command. Valid options include: - * - limit - the maximum number of documents to include in the response (by default 100). - * - language - the language that determines the list of stop words for the search - * and the rules for the stemmer and tokenizer. If not specified, the search uses the default - * language of the index. - * @return array the highest scoring documents, in descending order by score. - * @throws Exception on failure. - */ - public function fullTextSearch($search, $condition = [], $fields = [], $options = []) { - $command = [ - 'search' => $search - ]; - if (!empty($condition)) { - $command['filter'] = $this->buildCondition($condition); - } - if (!empty($fields)) { - $command['project'] = $fields; - } - if (!empty($options)) { - $command = array_merge($command, $options); - } - $token = $this->composeLogToken('text', $command); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $command = array_merge(['text' => $this->getName()], $command); - $result = $this->mongoCollection->db->command($command); - $this->tryResultError($result); - Yii::endProfile($token, __METHOD__); - return $result['results']; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Checks if command execution result ended with an error. - * @param mixed $result raw command execution result. - * @throws Exception if an error occurred. - */ - protected function tryResultError($result) - { - if (is_array($result)) { - if (!empty($result['errmsg'])) { - $errorMessage = $result['errmsg']; - } elseif (!empty($result['err'])) { - $errorMessage = $result['err']; - } - if (isset($errorMessage)) { - if (array_key_exists('code', $result)) { - $errorCode = (int)$result['code']; - } elseif (array_key_exists('ok', $result)) { - $errorCode = (int)$result['ok']; - } else { - $errorCode = 0; - } - throw new Exception($errorMessage, $errorCode); - } - } elseif (!$result) { - throw new Exception('Unknown error, use "w=1" option to enable error tracking'); - } - } - - /** - * Throws an exception if there was an error on the last operation. - * @throws Exception if an error occurred. - */ - protected function tryLastError() - { - $this->tryResultError($this->getLastError()); - } - - /** - * Converts "\yii\db\*" quick condition keyword into actual Mongo condition keyword. - * @param string $key raw condition key. - * @return string actual key. - */ - protected function normalizeConditionKeyword($key) - { - static $map = [ - 'OR' => '$or', - 'IN' => '$in', - 'NOT IN' => '$nin', - ]; - $matchKey = strtoupper($key); - if (array_key_exists($matchKey, $map)) { - return $map[$matchKey]; - } else { - return $key; - } - } - - /** - * Converts given value into [[MongoId]] instance. - * If array given, each element of it will be processed. - * @param mixed $rawId raw id(s). - * @return array|\MongoId normalized id(s). - */ - protected function ensureMongoId($rawId) - { - if (is_array($rawId)) { - $result = []; - foreach ($rawId as $key => $value) { - $result[$key] = $this->ensureMongoId($value); - } - return $result; - } elseif (is_object($rawId)) { - if ($rawId instanceof \MongoId) { - return $rawId; - } else { - $rawId = (string)$rawId; - } - } - return new \MongoId($rawId); - } - - /** - * Parses the condition specification and generates the corresponding Mongo condition. - * @param array $condition the condition specification. Please refer to [[Query::where()]] - * on how to specify a condition. - * @return array the generated Mongo condition - * @throws InvalidParamException if the condition is in bad format - */ - public function buildCondition($condition) - { - static $builders = [ - 'AND' => 'buildAndCondition', - 'OR' => 'buildOrCondition', - 'BETWEEN' => 'buildBetweenCondition', - 'NOT BETWEEN' => 'buildBetweenCondition', - 'IN' => 'buildInCondition', - 'NOT IN' => 'buildInCondition', - 'LIKE' => 'buildLikeCondition', - ]; - - if (!is_array($condition)) { - throw new InvalidParamException('Condition should be an array.'); - } elseif (empty($condition)) { - return []; - } - if (isset($condition[0])) { // operator format: operator, operand 1, operand 2, ... - $operator = strtoupper($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); - } - } - - /** - * Creates a condition based on column-value pairs. - * @param array $condition the condition specification. - * @return array the generated Mongo condition. - */ - public function buildHashCondition($condition) - { - $result = []; - foreach ($condition as $name => $value) { - if (strncmp('$', $name, 1) === 0) { - // Native Mongo condition: - $result[$name] = $value; - } else { - if (is_array($value)) { - if (array_key_exists(0, $value)) { - // Quick IN condition: - $result = array_merge($result, $this->buildInCondition('IN', [$name, $value])); - } else { - // Mongo complex condition: - $result[$name] = $value; - } - } else { - // Direct match: - if ($name == '_id') { - $value = $this->ensureMongoId($value); - } - $result[$name] = $value; - } - } - } - return $result; - } - - /** - * Connects two or more conditions with the `AND` operator. - * @param string $operator the operator to use for connecting the given operands - * @param array $operands the Mongo conditions to connect. - * @return array the generated Mongo condition. - */ - public function buildAndCondition($operator, $operands) - { - $result = []; - foreach ($operands as $operand) { - $condition = $this->buildCondition($operand); - $result = array_merge_recursive($result, $condition); - } - return $result; - } - - /** - * Connects two or more conditions with the `OR` operator. - * @param string $operator the operator to use for connecting the given operands - * @param array $operands the Mongo conditions to connect. - * @return array the generated Mongo condition. - */ - public function buildOrCondition($operator, $operands) - { - $operator = $this->normalizeConditionKeyword($operator); - $parts = []; - foreach ($operands as $operand) { - $parts[] = $this->buildCondition($operand); - } - return [$operator => $parts]; - } - - /** - * Creates an Mongo condition, which emulates the `BETWEEN` operator. - * @param string $operator the operator to use - * @param array $operands the first operand is the column name. The second and third operands - * describe the interval that column value should be in. - * @return array the generated Mongo condition. - * @throws InvalidParamException if wrong number of operands have been given. - */ - public 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 (strncmp('NOT', $operator, 3) === 0) { - return [ - $column => [ - '$lt' => $value1, - '$gt' => $value2, - ] - ]; - } else { - return [ - $column => [ - '$gte' => $value1, - '$lte' => $value2, - ] - ]; - } - } - - /** - * Creates an Mongo condition with the `IN` operator. - * @param string $operator the operator to use (e.g. `IN` or `NOT IN`) - * @param array $operands the first operand is the column name. If it is an array - * a composite IN condition will be generated. - * The second operand is an array of values that column value should be among. - * @return array the generated Mongo condition. - * @throws InvalidParamException if wrong number of operands have been given. - */ - public 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 (!is_array($column)) { - $columns = [$column]; - $values = [$column => $values]; - } elseif (count($column) < 2) { - $columns = $column; - $values = [$column[0] => $values]; - } else { - $columns = $column; - } - - $operator = $this->normalizeConditionKeyword($operator); - $result = []; - foreach ($columns as $column) { - if ($column == '_id') { - $inValues = $this->ensureMongoId($values[$column]); - } else { - $inValues = $values[$column]; - } - $result[$column][$operator] = $inValues; - } - return $result; - } - - /** - * Creates a Mongo condition, which emulates the `LIKE` operator. - * @param string $operator the operator to use - * @param array $operands the first operand is the column name. - * The second operand is a single value that column value should be compared with. - * @return array the generated Mongo condition. - * @throws InvalidParamException if wrong number of operands have been given. - */ - public function buildLikeCondition($operator, $operands) - { - if (!isset($operands[0], $operands[1])) { - throw new InvalidParamException("Operator '$operator' requires two operands."); - } - list($column, $value) = $operands; - if (!($value instanceof \MongoRegex)) { - $value = new \MongoRegex($value); - } - return [$column => $value]; - } -} \ No newline at end of file diff --git a/extensions/yii/mongodb/Connection.php b/extensions/yii/mongodb/Connection.php deleted file mode 100644 index ab8e30f..0000000 --- a/extensions/yii/mongodb/Connection.php +++ /dev/null @@ -1,256 +0,0 @@ - $dsn, - * ]); - * $connection->open(); - * ~~~ - * - * After the Mongo connection is established, one can access Mongo databases and collections: - * - * ~~~ - * $database = $connection->getDatabase('my_mongo_db'); - * $collection = $database->getCollection('customer'); - * $collection->insert(['name' => 'John Smith', 'status' => 1]); - * ~~~ - * - * You can work with several different databases at the same server using this class. - * However, while it is unlikely your application will actually need it, the Connection class - * provides ability to use [[defaultDatabaseName]] as well as a shortcut method [[getCollection()]] - * to retrieve a particular collection instance: - * - * ~~~ - * // get collection 'customer' from default database: - * $collection = $connection->getCollection('customer'); - * // get collection 'customer' from database 'mydatabase': - * $collection = $connection->getCollection(['mydatabase', 'customer']); - * ~~~ - * - * Connection is often used as an application component and configured in the application - * configuration like the following: - * - * ~~~ - * [ - * 'components' => [ - * 'mongodb' => [ - * 'class' => '\yii\mongodb\Connection', - * 'dsn' => 'mongodb://developer:password@localhost:27017/mydatabase', - * ], - * ], - * ] - * ~~~ - * - * @property Database $database Database instance. This property is read-only. - * @property file\Collection $fileCollection Mongo GridFS collection instance. This property is read-only. - * @property boolean $isActive Whether the Mongo connection is established. This property is read-only. - * - * @author Paul Klimov - * @since 2.0 - */ -class Connection extends Component -{ - /** - * @var string host:port - * - * Correct syntax is: - * mongodb://[username:password@]host1[:port1][,host2[:port2:],...][/dbname] - * For example: - * mongodb://localhost:27017 - * mongodb://developer:password@localhost:27017 - * mongodb://developer:password@localhost:27017/mydatabase - */ - public $dsn; - /** - * @var array connection options. - * for example: - * - * ~~~ - * [ - * 'socketTimeoutMS' => 1000, // how long a send or receive on a socket can take before timing out - * 'journal' => true // block write operations until the journal be flushed the to disk - * ] - * ~~~ - * - * @see http://www.php.net/manual/en/mongoclient.construct.php - */ - public $options = []; - /** - * @var string name of the Mongo database to use by default. - * If this field left blank, connection instance will attempt to determine it from - * [[options]] and [[dsn]] automatically, if needed. - */ - public $defaultDatabaseName; - /** - * @var \MongoClient Mongo client instance. - */ - public $mongoClient; - /** - * @var Database[] list of Mongo databases - */ - private $_databases = []; - - /** - * Returns the Mongo collection with the given name. - * @param string|null $name collection name, if null default one will be used. - * @param boolean $refresh whether to reestablish the database connection even if it is found in the cache. - * @return Database database instance. - */ - public function getDatabase($name = null, $refresh = false) - { - if ($name === null) { - $name = $this->fetchDefaultDatabaseName(); - } - if ($refresh || !array_key_exists($name, $this->_databases)) { - $this->_databases[$name] = $this->selectDatabase($name); - } - return $this->_databases[$name]; - } - - /** - * Returns [[defaultDatabaseName]] value, if it is not set, - * attempts to determine it from [[dsn]] value. - * @return string default database name - * @throws \yii\base\InvalidConfigException if unable to determine default database name. - */ - protected function fetchDefaultDatabaseName() - { - if ($this->defaultDatabaseName === null) { - if (isset($this->options['db'])) { - $this->defaultDatabaseName = $this->options['db']; - } elseif (preg_match('/^mongodb:\\/\\/.+\\/(.+)$/s', $this->dsn, $matches)) { - $this->defaultDatabaseName = $matches[1]; - } else { - throw new InvalidConfigException("Unable to determine default database name from dsn."); - } - } - return $this->defaultDatabaseName; - } - - /** - * Selects the database with given name. - * @param string $name database name. - * @return Database database instance. - */ - protected function selectDatabase($name) - { - $this->open(); - return Yii::createObject([ - 'class' => 'yii\mongodb\Database', - 'mongoDb' => $this->mongoClient->selectDB($name) - ]); - } - - /** - * Returns the Mongo collection with the given name. - * @param string|array $name collection name. If string considered as the name of the collection - * inside the default database. If array - first element considered as the name of the database, - * second - as name of collection inside that database - * @param boolean $refresh whether to reload the collection instance even if it is found in the cache. - * @return Collection Mongo collection instance. - */ - public function getCollection($name, $refresh = false) - { - if (is_array($name)) { - list ($dbName, $collectionName) = $name; - return $this->getDatabase($dbName)->getCollection($collectionName, $refresh); - } else { - return $this->getDatabase()->getCollection($name, $refresh); - } - } - - /** - * Returns the Mongo GridFS collection. - * @param string|array $prefix collection prefix. If string considered as the prefix of the GridFS - * collection inside the default database. If array - first element considered as the name of the database, - * second - as prefix of the GridFS collection inside that database, if no second element present - * default "fs" prefix will be used. - * @param boolean $refresh whether to reload the collection instance even if it is found in the cache. - * @return file\Collection Mongo GridFS collection instance. - */ - public function getFileCollection($prefix = 'fs', $refresh = false) - { - if (is_array($prefix)) { - list ($dbName, $collectionPrefix) = $prefix; - if (!isset($collectionPrefix)) { - $collectionPrefix = 'fs'; - } - return $this->getDatabase($dbName)->getFileCollection($collectionPrefix, $refresh); - } else { - return $this->getDatabase()->getFileCollection($prefix, $refresh); - } - } - - /** - * Returns a value indicating whether the Mongo connection is established. - * @return boolean whether the Mongo connection is established - */ - public function getIsActive() - { - return is_object($this->mongoClient) && $this->mongoClient->connected; - } - - /** - * Establishes a Mongo connection. - * It does nothing if a Mongo connection has already been established. - * @throws Exception if connection fails - */ - public function open() - { - if ($this->mongoClient === null) { - if (empty($this->dsn)) { - throw new InvalidConfigException($this->className() . '::dsn cannot be empty.'); - } - $token = 'Opening MongoDB connection: ' . $this->dsn; - try { - Yii::trace($token, __METHOD__); - Yii::beginProfile($token, __METHOD__); - $options = $this->options; - $options['connect'] = true; - if ($this->defaultDatabaseName !== null) { - $options['db'] = $this->defaultDatabaseName; - } - $this->mongoClient = new \MongoClient($this->dsn, $options); - Yii::endProfile($token, __METHOD__); - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - } - - /** - * Closes the currently active DB connection. - * It does nothing if the connection is already closed. - */ - public function close() - { - if ($this->mongoClient !== null) { - Yii::trace('Closing MongoDB connection: ' . $this->dsn, __METHOD__); - $this->mongoClient = null; - $this->_databases = []; - } - } -} \ No newline at end of file diff --git a/extensions/yii/mongodb/Database.php b/extensions/yii/mongodb/Database.php deleted file mode 100644 index 5c53e50..0000000 --- a/extensions/yii/mongodb/Database.php +++ /dev/null @@ -1,173 +0,0 @@ - - * @since 2.0 - */ -class Database extends Object -{ - /** - * @var \MongoDB Mongo database instance. - */ - public $mongoDb; - /** - * @var Collection[] list of collections. - */ - private $_collections = []; - /** - * @var file\Collection[] list of GridFS collections. - */ - private $_fileCollections = []; - - /** - * @return string name of this database. - */ - public function getName() - { - return $this->mongoDb->__toString(); - } - - /** - * Returns the Mongo collection with the given name. - * @param string $name collection name - * @param boolean $refresh whether to reload the collection instance even if it is found in the cache. - * @return Collection Mongo collection instance. - */ - public function getCollection($name, $refresh = false) - { - if ($refresh || !array_key_exists($name, $this->_collections)) { - $this->_collections[$name] = $this->selectCollection($name); - } - return $this->_collections[$name]; - } - - /** - * Returns Mongo GridFS collection with given prefix. - * @param string $prefix collection prefix. - * @param boolean $refresh whether to reload the collection instance even if it is found in the cache. - * @return file\Collection Mongo GridFS collection. - */ - public function getFileCollection($prefix = 'fs', $refresh = false) - { - if ($refresh || !array_key_exists($prefix, $this->_fileCollections)) { - $this->_fileCollections[$prefix] = $this->selectFileCollection($prefix); - } - return $this->_fileCollections[$prefix]; - } - - /** - * Selects collection with given name. - * @param string $name collection name. - * @return Collection collection instance. - */ - protected function selectCollection($name) - { - return Yii::createObject([ - 'class' => 'yii\mongodb\Collection', - 'mongoCollection' => $this->mongoDb->selectCollection($name) - ]); - } - - /** - * Selects GridFS collection with given prefix. - * @param string $prefix file collection prefix. - * @return file\Collection file collection instance. - */ - protected function selectFileCollection($prefix) - { - return Yii::createObject([ - 'class' => 'yii\mongodb\file\Collection', - 'mongoCollection' => $this->mongoDb->getGridFS($prefix) - ]); - } - - /** - * Creates new collection. - * Note: Mongo creates new collections automatically on the first demand, - * this method makes sense only for the migration script or for the case - * you need to create collection with the specific options. - * @param string $name name of the collection - * @param array $options collection options in format: "name" => "value" - * @return \MongoCollection new Mongo collection instance. - * @throws Exception on failure. - */ - public function createCollection($name, $options = []) - { - $token = $this->getName() . '.create(' . $name . ', ' . Json::encode($options) . ')'; - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $result = $this->mongoDb->createCollection($name, $options); - Yii::endProfile($token, __METHOD__); - return $result; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Executes Mongo command. - * @param array $command command specification. - * @param array $options options in format: "name" => "value" - * @return array database response. - * @throws Exception on failure. - */ - public function executeCommand($command, $options = []) - { - $token = $this->getName() . '.$cmd(' . Json::encode($command) . ', ' . Json::encode($options) . ')'; - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $result = $this->mongoDb->command($command, $options); - $this->tryResultError($result); - Yii::endProfile($token, __METHOD__); - return $result; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Checks if command execution result ended with an error. - * @param mixed $result raw command execution result. - * @throws Exception if an error occurred. - */ - protected function tryResultError($result) - { - if (is_array($result)) { - if (!empty($result['errmsg'])) { - $errorMessage = $result['errmsg']; - } elseif (!empty($result['err'])) { - $errorMessage = $result['err']; - } - if (isset($errorMessage)) { - if (array_key_exists('ok', $result)) { - $errorCode = (int)$result['ok']; - } else { - $errorCode = 0; - } - throw new Exception($errorMessage, $errorCode); - } - } elseif (!$result) { - throw new Exception('Unknown error, use "w=1" option to enable error tracking'); - } - } -} \ No newline at end of file diff --git a/extensions/yii/mongodb/Exception.php b/extensions/yii/mongodb/Exception.php deleted file mode 100644 index 9e3a148..0000000 --- a/extensions/yii/mongodb/Exception.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class Exception extends \yii\base\Exception -{ - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return 'MongoDB Exception'; - } -} \ No newline at end of file diff --git a/extensions/yii/mongodb/LICENSE.md b/extensions/yii/mongodb/LICENSE.md deleted file mode 100644 index 0bb1a8d..0000000 --- a/extensions/yii/mongodb/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/mongodb/Query.php b/extensions/yii/mongodb/Query.php deleted file mode 100644 index 1ecea39..0000000 --- a/extensions/yii/mongodb/Query.php +++ /dev/null @@ -1,346 +0,0 @@ -select(['name', 'status']) - * ->from('customer') - * ->limit(10); - * // execute the query - * $rows = $query->all(); - * ~~~ - * - * @property Collection $collection Collection instance. This property is read-only. - * - * @author Paul Klimov - * @since 2.0 - */ -class Query extends Component implements QueryInterface -{ - use QueryTrait; - - /** - * @var array the fields of the results to return. For example, `['name', 'group_id']`. - * The "_id" field is always returned. If not set, if means selecting all columns. - * @see select() - */ - public $select = []; - /** - * @var string|array the collection to be selected from. If string considered as the name of the collection - * inside the default database. If array - first element considered as the name of the database, - * second - as name of collection inside that database - * @see from() - */ - public $from; - - /** - * Returns the Mongo collection for this query. - * @param Connection $db Mongo connection. - * @return Collection collection instance. - */ - public function getCollection($db = null) - { - if ($db === null) { - $db = Yii::$app->getComponent('mongodb'); - } - return $db->getCollection($this->from); - } - - /** - * Sets the list of fields of the results to return. - * @param array $fields fields of the results to return. - * @return static the query object itself. - */ - public function select(array $fields) - { - $this->select = $fields; - return $this; - } - - /** - * Sets the collection to be selected from. - * @param string|array the collection to be selected from. If string considered as the name of the collection - * inside the default database. If array - first element considered as the name of the database, - * second - as name of collection inside that database - * @return static the query object itself. - */ - public function from($collection) - { - $this->from = $collection; - return $this; - } - - /** - * Builds the Mongo cursor for this query. - * @param Connection $db the database connection used to execute the query. - * @return \MongoCursor mongo cursor instance. - */ - protected function buildCursor($db = null) - { - if ($this->where === null) { - $where = []; - } else { - $where = $this->where; - } - $selectFields = []; - if (!empty($this->select)) { - foreach ($this->select as $fieldName) { - $selectFields[$fieldName] = true; - } - } - $cursor = $this->getCollection($db)->find($where, $selectFields); - if (!empty($this->orderBy)) { - $sort = []; - foreach ($this->orderBy as $fieldName => $sortOrder) { - $sort[$fieldName] = $sortOrder === SORT_DESC ? \MongoCollection::DESCENDING : \MongoCollection::ASCENDING; - } - $cursor->sort($sort); - } - $cursor->limit($this->limit); - $cursor->skip($this->offset); - return $cursor; - } - - /** - * Fetches rows from the given Mongo cursor. - * @param \MongoCursor $cursor Mongo cursor instance to fetch data from. - * @param boolean $all whether to fetch all rows or only first one. - * @param string|callable $indexBy the column name or PHP callback, - * by which the query results should be indexed by. - * @throws Exception on failure. - * @return array|boolean result. - */ - protected function fetchRows($cursor, $all = true, $indexBy = null) - { - $token = 'find(' . Json::encode($cursor->info()) . ')'; - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $result = $this->fetchRowsInternal($cursor, $all, $indexBy); - Yii::endProfile($token, __METHOD__); - return $result; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * @param \MongoCursor $cursor Mongo cursor instance to fetch data from. - * @param boolean $all whether to fetch all rows or only first one. - * @param string|callable $indexBy value to index by. - * @return array|boolean result. - * @see Query::fetchRows() - */ - protected function fetchRowsInternal($cursor, $all, $indexBy) - { - $result = []; - if ($all) { - foreach ($cursor as $row) { - if ($indexBy !== null) { - if (is_string($indexBy)) { - $key = $row[$indexBy]; - } else { - $key = call_user_func($indexBy, $row); - } - $result[$key] = $row; - } else { - $result[] = $row; - } - } - } else { - if ($cursor->hasNext()) { - $result = $cursor->getNext(); - } else { - $result = false; - } - } - return $result; - } - - /** - * Executes the query and returns all results as an array. - * @param Connection $db the Mongo connection used to execute the query. - * If this parameter is not given, the `mongodb` 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) - { - $cursor = $this->buildCursor($db); - return $this->fetchRows($cursor, true, $this->indexBy); - } - - /** - * Executes the query and returns a single row of result. - * @param Connection $db the Mongo connection used to execute the query. - * If this parameter is not given, the `mongodb` 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) - { - $cursor = $this->buildCursor($db); - return $this->fetchRows($cursor, false); - } - - /** - * Returns the number of records. - * @param string $q kept to match [[QueryInterface]], its value is ignored. - * @param Connection $db the Mongo connection used to execute the query. - * If this parameter is not given, the `mongodb` application component will be used. - * @return integer number of records - * @throws Exception on failure. - */ - public function count($q = '*', $db = null) - { - $cursor = $this->buildCursor($db); - $token = 'find.count(' . Json::encode($cursor->info()) . ')'; - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $result = $cursor->count(); - Yii::endProfile($token, __METHOD__); - return $result; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Returns a value indicating whether the query result contains any row of data. - * @param Connection $db the Mongo connection used to execute the query. - * If this parameter is not given, the `mongodb` application component will be used. - * @return boolean whether the query result contains any row of data. - */ - public function exists($db = null) - { - return $this->one($db) !== null; - } - - /** - * Returns the sum of the specified column values. - * @param string $q the column name. - * Make sure you properly quote column names in the expression. - * @param Connection $db the Mongo connection used to execute the query. - * If this parameter is not given, the `mongodb` application component will be used. - * @return integer the sum of the specified column values - */ - public function sum($q, $db = null) - { - return $this->aggregate($q, 'sum', $db); - } - - /** - * Returns the average of the specified column values. - * @param string $q the column name. - * Make sure you properly quote column names in the expression. - * @param Connection $db the Mongo connection used to execute the query. - * If this parameter is not given, the `mongodb` application component will be used. - * @return integer the average of the specified column values. - */ - public function average($q, $db = null) - { - return $this->aggregate($q, 'avg', $db); - } - - /** - * Returns the minimum of the specified column values. - * @param string $q the column name. - * Make sure you properly quote column names in the expression. - * @param Connection $db the database connection used to generate the SQL statement. - * If this parameter is not given, the `db` application component will be used. - * @return integer the minimum of the specified column values. - */ - public function min($q, $db = null) - { - return $this->aggregate($q, 'min', $db); - } - - /** - * Returns the maximum of the specified column values. - * @param string $q the column name. - * Make sure you properly quote column names in the expression. - * @param Connection $db the Mongo connection used to execute the query. - * If this parameter is not given, the `mongodb` application component will be used. - * @return integer the maximum of the specified column values. - */ - public function max($q, $db = null) - { - return $this->aggregate($q, 'max', $db); - } - - /** - * Performs the aggregation for the given column. - * @param string $column column name. - * @param string $operator aggregation operator. - * @param Connection $db the database connection used to execute the query. - * @return integer aggregation result. - */ - protected function aggregate($column, $operator, $db) - { - $collection = $this->getCollection($db); - $pipelines = []; - if ($this->where !== null) { - $pipelines[] = ['$match' => $collection->buildCondition($this->where)]; - } - $pipelines[] = [ - '$group' => [ - '_id' => '1', - 'total' => [ - '$' . $operator => '$' . $column - ], - ] - ]; - $result = $collection->aggregate($pipelines); - if (array_key_exists(0, $result)) { - return $result[0]['total']; - } else { - return 0; - } - } - - /** - * Returns a list of distinct values for the given column across a collection. - * @param string $q column to use. - * @param Connection $db the Mongo connection used to execute the query. - * If this parameter is not given, the `mongodb` application component will be used. - * @return array array of distinct values - */ - public function distinct($q, $db = null) - { - $collection = $this->getCollection($db); - if ($this->where !== null) { - $condition = $this->where; - } else { - $condition = []; - } - $result = $collection->distinct($q, $condition); - if ($result === false) { - return []; - } else { - return $result; - } - } -} \ No newline at end of file diff --git a/extensions/yii/mongodb/README.md b/extensions/yii/mongodb/README.md deleted file mode 100644 index b6f64b3..0000000 --- a/extensions/yii/mongodb/README.md +++ /dev/null @@ -1,111 +0,0 @@ -MongoDb Extension for Yii 2 -=========================== - -This extension provides the [MongoDB](http://www.mongodb.org/) integration for the Yii2 framework. - - -Installation ------------- - -This extension requires [MongoDB PHP Extension](http://us1.php.net/manual/en/book.mongo.php) version 1.3.0 or higher. - -The preferred way to install this extension is through [composer](http://getcomposer.org/download/). - -Either run - -``` -php composer.phar require --prefer-dist yiisoft/yii2-mongodb "*" -``` - -or add - -``` -"yiisoft/yii2-mongodb": "*" -``` - -to the require section of your composer.json. - - -Usage & Documentation ---------------------- - -To use this extension, simply add the following code in your application configuration: - -```php -return [ - //.... - 'components' => [ - 'mongodb' => [ - 'class' => '\yii\mongodb\Connection', - 'dsn' => 'mongodb://developer:password@localhost:27017/mydatabase', - ], - ], -]; -``` - -This extension provides ActiveRecord solution similar ot the [[\yii\db\ActiveRecord]]. -To declare an ActiveRecord class you need to extend [[\yii\mongodb\ActiveRecord]] and -implement the `collectionName` and 'attributes' methods: - -```php -use yii\mongodb\ActiveRecord; - -class Customer extends ActiveRecord -{ - /** - * @return string the name of the index associated with this ActiveRecord class. - */ - public static function collectionName() - { - return 'customer'; - } - - /** - * @return array list of attribute names. - */ - public function attributes() - { - return ['_id', 'name', 'email', 'address', 'status']; - } -} -``` - -Note: collection primary key name ('_id') should be always explicitly setup as an attribute. - -You can use [[\yii\data\ActiveDataProvider]] with [[\yii\mongodb\Query]] and [[\yii\mongodb\ActiveQuery]]: - -```php -use yii\data\ActiveDataProvider; -use yii\mongodb\Query; - -$query = new Query; -$query->from('customer')->where(['status' => 2]); -$provider = new ActiveDataProvider([ - 'query' => $query, - 'pagination' => [ - 'pageSize' => 10, - ] -]); -$models = $provider->getModels(); -``` - -```php -use yii\data\ActiveDataProvider; -use app\models\Customer; - -$provider = new ActiveDataProvider([ - 'query' => Customer::find(), - 'pagination' => [ - 'pageSize' => 10, - ] -]); -$models = $provider->getModels(); -``` - -This extension supports [MongoGridFS](http://docs.mongodb.org/manual/core/gridfs/) via -classes under namespace "\yii\mongodb\file". - -This extension supports logging and profiling, however log messages does not contain -actual text of the performed queries, they contains only a “close approximation” of it -composed on the values which can be extracted from PHP Mongo extension classes. -If you need to see actual query text, you should use specific tools for that. \ No newline at end of file diff --git a/extensions/yii/mongodb/composer.json b/extensions/yii/mongodb/composer.json deleted file mode 100644 index fc850b2..0000000 --- a/extensions/yii/mongodb/composer.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "yiisoft/yii2-mongodb", - "description": "MongoDb extension for the Yii framework", - "keywords": ["yii", "mongo", "mongodb", "active-record"], - "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-mongo": ">=1.3.0" - }, - "autoload": { - "psr-0": { "yii\\mongodb\\": "" } - }, - "target-dir": "yii/mongodb" -} diff --git a/extensions/yii/mongodb/file/ActiveQuery.php b/extensions/yii/mongodb/file/ActiveQuery.php deleted file mode 100644 index 96fc979..0000000 --- a/extensions/yii/mongodb/file/ActiveQuery.php +++ /dev/null @@ -1,109 +0,0 @@ -with('tags')->asArray()->all(); - * ~~~ - * - * @property Collection $collection Collection instance. This property is read-only. - * - * @author Paul Klimov - * @since 2.0 - */ -class ActiveQuery extends Query implements ActiveQueryInterface -{ - use ActiveQueryTrait; - - /** - * Executes query and returns all results as an array. - * @param \yii\mongodb\Connection $db the Mongo connection used to execute the query. - * If null, the Mongo 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) - { - $cursor = $this->buildCursor($db); - $rows = $this->fetchRows($cursor); - if (!empty($rows)) { - $models = $this->createModels($rows); - if (!empty($this->with)) { - $this->findWith($this->with, $models); - } - return $models; - } else { - return []; - } - } - - /** - * Executes query and returns a single row of result. - * @param \yii\mongodb\Connection $db the Mongo connection used to execute the query. - * If null, the Mongo 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) - { - $row = parent::one($db); - if ($row !== false) { - if ($this->asArray) { - $model = $row; - } else { - /** @var ActiveRecord $class */ - $class = $this->modelClass; - $model = $class::create($row); - } - if (!empty($this->with)) { - $models = [$model]; - $this->findWith($this->with, $models); - $model = $models[0]; - } - return $model; - } else { - return null; - } - } - - /** - * Returns the Mongo collection for this query. - * @param \yii\mongo\Connection $db Mongo connection. - * @return Collection collection instance. - */ - public function getCollection($db = null) - { - /** @var ActiveRecord $modelClass */ - $modelClass = $this->modelClass; - if ($db === null) { - $db = $modelClass::getDb(); - } - if ($this->from === null) { - $this->from = $modelClass::collectionName(); - } - return $db->getFileCollection($this->from); - } -} \ No newline at end of file diff --git a/extensions/yii/mongodb/file/ActiveRecord.php b/extensions/yii/mongodb/file/ActiveRecord.php deleted file mode 100644 index 03f7d79..0000000 --- a/extensions/yii/mongodb/file/ActiveRecord.php +++ /dev/null @@ -1,334 +0,0 @@ -file = '/path/to/some/file.jpg'; - * $record->save(); - * ~~~ - * - * You can also specify file content via [[newFileContent]] attribute: - * - * ~~~ - * $record = new ImageFile(); - * $record->newFileContent = 'New file content'; - * $record->save(); - * ~~~ - * - * Note: [[newFileContent]] always takes precedence over [[file]]. - * - * @property null|string $fileContent File content. This property is read-only. - * @property resource $fileResource File stream resource. This property is read-only. - * - * @author Paul Klimov - * @since 2.0 - */ -abstract class ActiveRecord extends \yii\mongodb\ActiveRecord -{ - /** - * Creates an [[ActiveQuery]] instance. - * This method is called by [[find()]] to start a "find" command. - * You may override this method to return a customized query (e.g. `ImageFileQuery` specified - * written for querying `ImageFile` purpose.) - * @return ActiveQuery the newly created [[ActiveQuery]] instance. - */ - public static function createQuery() - { - return new ActiveQuery(['modelClass' => get_called_class()]); - } - - /** - * Return the Mongo GridFS collection instance for this AR class. - * @return Collection collection instance. - */ - public static function getCollection() - { - return static::getDb()->getFileCollection(static::collectionName()); - } - - /** - * Creates an [[ActiveRelation]] instance. - * This method is called by [[hasOne()]] and [[hasMany()]] to create a relation instance. - * You may override this method to return a customized relation. - * @param array $config the configuration passed to the ActiveRelation class. - * @return ActiveRelation the newly created [[ActiveRelation]] instance. - */ - public static function createActiveRelation($config = []) - { - return new ActiveRelation($config); - } - - /** - * Returns the list of all attribute names of the model. - * This method could be overridden by child classes to define available attributes. - * Note: all attributes defined in base Active Record class should be always present - * in returned array. - * For example: - * ~~~ - * public function attributes() - * { - * return array_merge( - * parent::attributes(), - * ['tags', 'status'] - * ); - * } - * ~~~ - * @return array list of attribute names. - */ - public function attributes() - { - return [ - '_id', - 'filename', - 'uploadDate', - 'length', - 'chunkSize', - 'md5', - 'file', - 'newFileContent' - ]; - } - - /** - * @see ActiveRecord::insert() - */ - protected function insertInternal($attributes = null) - { - if (!$this->beforeSave(true)) { - return false; - } - $values = $this->getDirtyAttributes($attributes); - if (empty($values)) { - $currentAttributes = $this->getAttributes(); - foreach ($this->primaryKey() as $key) { - $values[$key] = isset($currentAttributes[$key]) ? $currentAttributes[$key] : null; - } - } - $collection = static::getCollection(); - if (isset($values['newFileContent'])) { - $newFileContent = $values['newFileContent']; - unset($values['newFileContent']); - } - if (isset($values['file'])) { - $newFile = $values['file']; - unset($values['file']); - } - if (isset($newFileContent)) { - $newId = $collection->insertFileContent($newFileContent, $values); - } elseif (isset($newFile)) { - $fileName = $this->extractFileName($newFile); - $newId = $collection->insertFile($fileName, $values); - } else { - $newId = $collection->insert($values); - } - $this->setAttribute('_id', $newId); - foreach ($values as $name => $value) { - $this->setOldAttribute($name, $value); - } - $this->afterSave(true); - return true; - } - - /** - * @see ActiveRecord::update() - * @throws StaleObjectException - */ - protected function updateInternal($attributes = null) - { - if (!$this->beforeSave(false)) { - return false; - } - $values = $this->getDirtyAttributes($attributes); - if (empty($values)) { - $this->afterSave(false); - return 0; - } - - $collection = static::getCollection(); - if (isset($values['newFileContent'])) { - $newFileContent = $values['newFileContent']; - unset($values['newFileContent']); - } - if (isset($values['file'])) { - $newFile = $values['file']; - unset($values['file']); - } - if (isset($newFileContent) || isset($newFile)) { - $rows = $this->deleteInternal(); - $insertValues = $values; - $insertValues['_id'] = $this->getAttribute('_id'); - if (isset($newFileContent)) { - $collection->insertFileContent($newFileContent, $insertValues); - } else { - $fileName = $this->extractFileName($newFile); - $collection->insertFile($fileName, $insertValues); - } - $this->setAttribute('newFileContent', null); - $this->setAttribute('file', null); - } else { - $condition = $this->getOldPrimaryKey(true); - $lock = $this->optimisticLock(); - if ($lock !== null) { - if (!isset($values[$lock])) { - $values[$lock] = $this->$lock + 1; - } - $condition[$lock] = $this->$lock; - } - // We do not check the return value of update() because it's possible - // that it doesn't change anything and thus returns 0. - $rows = $collection->update($condition, $values); - if ($lock !== null && !$rows) { - throw new StaleObjectException('The object being updated is outdated.'); - } - } - - foreach ($values as $name => $value) { - $this->setOldAttribute($name, $this->getAttribute($name)); - } - $this->afterSave(false); - return $rows; - } - - /** - * Extracts filename from given raw file value. - * @param mixed $file raw file value. - * @return string file name. - * @throws \yii\base\InvalidParamException on invalid file value. - */ - protected function extractFileName($file) - { - if ($file instanceof UploadedFile) { - return $file->tempName; - } elseif (is_string($file)) { - if (file_exists($file)) { - return $file; - } else { - throw new InvalidParamException("File '{$file}' does not exist."); - } - } else { - throw new InvalidParamException('Unsupported type of "file" attribute.'); - } - } - - /** - * Refreshes the [[file]] attribute from file collection, using current primary key. - * @return \MongoGridFSFile|null refreshed file value. - */ - public function refreshFile() - { - $mongoFile = $this->getCollection()->get($this->getPrimaryKey()); - $this->setAttribute('file', $mongoFile); - return $mongoFile; - } - - /** - * Returns the associated file content. - * @return null|string file content. - * @throws \yii\base\InvalidParamException on invalid file attribute value. - */ - public function getFileContent() - { - $file = $this->getAttribute('file'); - if (empty($file) && !$this->getIsNewRecord()) { - $file = $this->refreshFile(); - } - if (empty($file)) { - return null; - } elseif ($file instanceof \MongoGridFSFile) { - $fileSize = $file->getSize(); - if (empty($fileSize)) { - return null; - } else { - return $file->getBytes(); - } - } elseif ($file instanceof UploadedFile) { - return file_get_contents($file->tempName); - } elseif (is_string($file)) { - if (file_exists($file)) { - return file_get_contents($file); - } else { - throw new InvalidParamException("File '{$file}' does not exist."); - } - } else { - throw new InvalidParamException('Unsupported type of "file" attribute.'); - } - } - - /** - * Writes the the internal file content into the given filename. - * @param string $filename full filename to be written. - * @return boolean whether the operation was successful. - * @throws \yii\base\InvalidParamException on invalid file attribute value. - */ - public function writeFile($filename) - { - $file = $this->getAttribute('file'); - if (empty($file) && !$this->getIsNewRecord()) { - $file = $this->refreshFile(); - } - if (empty($file)) { - throw new InvalidParamException('There is no file associated with this object.'); - } elseif ($file instanceof \MongoGridFSFile) { - return ($file->write($filename) == $file->getSize()); - } elseif ($file instanceof UploadedFile) { - return copy($file->tempName, $filename); - } elseif (is_string($file)) { - if (file_exists($file)) { - return copy($file, $filename); - } else { - throw new InvalidParamException("File '{$file}' does not exist."); - } - } else { - throw new InvalidParamException('Unsupported type of "file" attribute.'); - } - } - - /** - * This method returns a stream resource that can be used with all file functions in PHP, - * which deal with reading files. The contents of the file are pulled out of MongoDB on the fly, - * so that the whole file does not have to be loaded into memory first. - * @return resource file stream resource. - * @throws \yii\base\InvalidParamException on invalid file attribute value. - */ - public function getFileResource() - { - $file = $this->getAttribute('file'); - if (empty($file) && !$this->getIsNewRecord()) { - $file = $this->refreshFile(); - } - if (empty($file)) { - throw new InvalidParamException('There is no file associated with this object.'); - } elseif ($file instanceof \MongoGridFSFile) { - return $file->getResource(); - } elseif ($file instanceof UploadedFile) { - return fopen($file->tempName, 'r'); - } elseif (is_string($file)) { - if (file_exists($file)) { - return fopen($file, 'r'); - } else { - throw new InvalidParamException("File '{$file}' does not exist."); - } - } else { - throw new InvalidParamException('Unsupported type of "file" attribute.'); - } - } -} \ No newline at end of file diff --git a/extensions/yii/mongodb/file/ActiveRelation.php b/extensions/yii/mongodb/file/ActiveRelation.php deleted file mode 100644 index ea1f7e6..0000000 --- a/extensions/yii/mongodb/file/ActiveRelation.php +++ /dev/null @@ -1,22 +0,0 @@ - - * @since 2.0 - */ -class ActiveRelation extends ActiveQuery implements ActiveRelationInterface -{ - use ActiveRelationTrait; -} \ No newline at end of file diff --git a/extensions/yii/mongodb/file/Collection.php b/extensions/yii/mongodb/file/Collection.php deleted file mode 100644 index 2efdef1..0000000 --- a/extensions/yii/mongodb/file/Collection.php +++ /dev/null @@ -1,185 +0,0 @@ - - * @since 2.0 - */ -class Collection extends \yii\mongodb\Collection -{ - /** - * @var \MongoGridFS Mongo GridFS collection instance. - */ - public $mongoCollection; - /** - * @var \yii\mongodb\Collection file chunks Mongo collection. - */ - private $_chunkCollection; - - /** - * Returns the Mongo collection for the file chunks. - * @param boolean $refresh whether to reload the collection instance even if it is found in the cache. - * @return \yii\mongodb\Collection mongo collection instance. - */ - public function getChunkCollection($refresh = false) - { - if ($refresh || !is_object($this->_chunkCollection)) { - $this->_chunkCollection = Yii::createObject([ - 'class' => 'yii\mongodb\Collection', - 'mongoCollection' => $this->mongoCollection->chunks - ]); - } - return $this->_chunkCollection; - } - - /** - * Removes data from the collection. - * @param array $condition description of records to remove. - * @param array $options list of options in format: optionName => optionValue. - * @return integer|boolean number of updated documents or whether operation was successful. - * @throws Exception on failure. - */ - public function remove($condition = [], $options = []) - { - $result = parent::remove($condition, $options); - $this->tryLastError(); // MongoGridFS::remove will return even if the remove failed - return $result; - } - - /** - * Creates new file in GridFS collection from given local filesystem file. - * Additional attributes can be added file document using $metadata. - * @param string $filename name of the file to store. - * @param array $metadata other metadata fields to include in the file document. - * @param array $options list of options in format: optionName => optionValue - * @return mixed the "_id" of the saved file document. This will be a generated [[\MongoId]] - * unless an "_id" was explicitly specified in the metadata. - * @throws Exception on failure. - */ - public function insertFile($filename, $metadata = [], $options = []) - { - $token = 'Inserting file into ' . $this->getFullName(); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $options = array_merge(['w' => 1], $options); - $result = $this->mongoCollection->storeFile($filename, $metadata, $options); - Yii::endProfile($token, __METHOD__); - return $result; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Creates new file in GridFS collection with specified content. - * Additional attributes can be added file document using $metadata. - * @param string $bytes string of bytes to store. - * @param array $metadata other metadata fields to include in the file document. - * @param array $options list of options in format: optionName => optionValue - * @return mixed the "_id" of the saved file document. This will be a generated [[\MongoId]] - * unless an "_id" was explicitly specified in the metadata. - * @throws Exception on failure. - */ - public function insertFileContent($bytes, $metadata = [], $options = []) - { - $token = 'Inserting file content into ' . $this->getFullName(); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $options = array_merge(['w' => 1], $options); - $result = $this->mongoCollection->storeBytes($bytes, $metadata, $options); - Yii::endProfile($token, __METHOD__); - return $result; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Creates new file in GridFS collection from uploaded file. - * Additional attributes can be added file document using $metadata. - * @param string $name name of the uploaded file to store. This should correspond to - * the file field's name attribute in the HTML form. - * @param array $metadata other metadata fields to include in the file document. - * @return mixed the "_id" of the saved file document. This will be a generated [[\MongoId]] - * unless an "_id" was explicitly specified in the metadata. - * @throws Exception on failure. - */ - public function insertUploads($name, $metadata = []) - { - $token = 'Inserting file uploads into ' . $this->getFullName(); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $result = $this->mongoCollection->storeUpload($name, $metadata); - Yii::endProfile($token, __METHOD__); - return $result; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Retrieves the file with given _id. - * @param mixed $id _id of the file to find. - * @return \MongoGridFSFile|null found file, or null if file does not exist - * @throws Exception on failure. - */ - public function get($id) - { - $token = 'Inserting file uploads into ' . $this->getFullName(); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $result = $this->mongoCollection->get($id); - Yii::endProfile($token, __METHOD__); - return $result; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } - - /** - * Deletes the file with given _id. - * @param mixed $id _id of the file to find. - * @return boolean whether the operation was successful. - * @throws Exception on failure. - */ - public function delete($id) - { - $token = 'Inserting file uploads into ' . $this->getFullName(); - Yii::info($token, __METHOD__); - try { - Yii::beginProfile($token, __METHOD__); - $result = $this->mongoCollection->delete($id); - $this->tryResultError($result); - Yii::endProfile($token, __METHOD__); - return true; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), (int)$e->getCode(), $e); - } - } -} \ No newline at end of file diff --git a/extensions/yii/mongodb/file/Query.php b/extensions/yii/mongodb/file/Query.php deleted file mode 100644 index 435dcc7..0000000 --- a/extensions/yii/mongodb/file/Query.php +++ /dev/null @@ -1,75 +0,0 @@ - - * @since 2.0 - */ -class Query extends \yii\mongodb\Query -{ - /** - * Returns the Mongo collection for this query. - * @param \yii\mongodb\Connection $db Mongo connection. - * @return Collection collection instance. - */ - public function getCollection($db = null) - { - if ($db === null) { - $db = Yii::$app->getComponent('mongodb'); - } - return $db->getFileCollection($this->from); - } - - /** - * @param \MongoGridFSCursor $cursor Mongo cursor instance to fetch data from. - * @param boolean $all whether to fetch all rows or only first one. - * @param string|callable $indexBy value to index by. - * @return array|boolean result. - * @see Query::fetchRows() - */ - protected function fetchRowsInternal($cursor, $all, $indexBy) - { - $result = []; - if ($all) { - foreach ($cursor as $file) { - $row = $file->file; - $row['file'] = $file; - if ($indexBy !== null) { - if (is_string($indexBy)) { - $key = $row[$indexBy]; - } else { - $key = call_user_func($indexBy, $row); - } - $result[$key] = $row; - } else { - $result[] = $row; - } - } - } else { - if ($cursor->hasNext()) { - $file = $cursor->getNext(); - $result = $file->file; - $result['file'] = $file; - } else { - $result = false; - } - } - return $result; - } -} \ No newline at end of file diff --git a/extensions/yii/redis/ActiveQuery.php b/extensions/yii/redis/ActiveQuery.php deleted file mode 100644 index b64beba..0000000 --- a/extensions/yii/redis/ActiveQuery.php +++ /dev/null @@ -1,388 +0,0 @@ -with('orders')->asArray()->all(); - * ~~~ - * - * @author Carsten Brandt - * @since 2.0 - */ -class ActiveQuery extends \yii\base\Component implements ActiveQueryInterface -{ - use QueryTrait; - use ActiveQueryTrait; - - /** - * 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 `db` application component will be used. - * @return array|ActiveRecord[] the query results. If the query results in nothing, an empty array will be returned. - */ - public function all($db = null) - { - // TODO add support for orderBy - $data = $this->executeScript($db, 'All'); - $rows = []; - foreach($data as $dataRow) { - $row = []; - $c = count($dataRow); - for($i = 0; $i < $c; ) { - $row[$dataRow[$i++]] = $dataRow[$i++]; - } - $rows[] = $row; - } - if (!empty($rows)) { - $models = $this->createModels($rows); - if (!empty($this->with)) { - $this->findWith($this->with, $models); - } - return $models; - } else { - return []; - } - } - - /** - * 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 `db` application component 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) - { - // TODO add support for orderBy - $data = $this->executeScript($db, 'One'); - if (empty($data)) { - return null; - } - $row = []; - $c = count($data); - for($i = 0; $i < $c; ) { - $row[$data[$i++]] = $data[$i++]; - } - if ($this->asArray) { - $model = $row; - } else { - /** @var ActiveRecord $class */ - $class = $this->modelClass; - $model = $class::create($row); - } - if (!empty($this->with)) { - $models = [$model]; - $this->findWith($this->with, $models); - $model = $models[0]; - } - return $model; - } - - /** - * 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 `db` application component will be used. - * @return integer number of records - */ - public function count($q = '*', $db = null) - { - if ($this->where === null) { - /** @var ActiveRecord $modelClass */ - $modelClass = $this->modelClass; - if ($db === null) { - $db = $modelClass::getDb(); - } - return $db->executeCommand('LLEN', [$modelClass::keyPrefix()]); - } else { - return $this->executeScript($db, 'Count'); - } - } - - /** - * 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 `db` application component will be used. - * @return boolean whether the query result contains any row of data. - */ - public function exists($db = null) - { - return $this->one($db) !== null; - } - - /** - * Executes the query and returns the first column of the result. - * @param string $column name of the column to select - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `db` 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($column, $db = null) - { - // TODO add support for orderBy - return $this->executeScript($db, 'Column', $column); - } - - /** - * Returns the number of records. - * @param string $column the column to sum up - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `db` application component will be used. - * @return integer number of records - */ - public function sum($column, $db = null) - { - return $this->executeScript($db, 'Sum', $column); - } - - /** - * Returns the average of the specified column values. - * @param string $column the column name or expression. - * Make sure you properly quote column names in the expression. - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `db` application component will be used. - * @return integer the average of the specified column values. - */ - public function average($column, $db = null) - { - return $this->executeScript($db, 'Average', $column); - } - - /** - * Returns the minimum of the specified column values. - * @param string $column the column name or expression. - * Make sure you properly quote column names in the expression. - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `db` application component will be used. - * @return integer the minimum of the specified column values. - */ - public function min($column, $db = null) - { - return $this->executeScript($db, 'Min', $column); - } - - /** - * Returns the maximum of the specified column values. - * @param string $column the column name or expression. - * Make sure you properly quote column names in the expression. - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `db` application component will be used. - * @return integer the maximum of the specified column values. - */ - public function max($column, $db = null) - { - return $this->executeScript($db, 'Max', $column); - } - - /** - * Returns the query result as a scalar value. - * The value returned will be the specified attribute in the first record of the query results. - * @param string $attribute name of the attribute to select - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `db` 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. - */ - public function scalar($attribute, $db = null) - { - $record = $this->one($db); - if ($record !== null) { - return $record->hasAttribute($attribute) ? $record->$attribute : null; - } else { - return null; - } - } - - - /** - * Executes a script created by [[LuaScriptBuilder]] - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `db` application component will be used. - * @param string $type the type of the script to generate - * @param string $columnName - * @return array|bool|null|string - */ - protected function executeScript($db, $type, $columnName = null) - { - if (!empty($this->orderBy)) { - throw new NotSupportedException('orderBy is currently not supported by redis ActiveRecord.'); - } - - /** @var ActiveRecord $modelClass */ - $modelClass = $this->modelClass; - - if ($db === null) { - $db = $modelClass::getDb(); - } - - // find by primary key if possible. This is much faster than scanning all records - if (is_array($this->where) && !isset($this->where[0]) && $modelClass::isPrimaryKey(array_keys($this->where))) { - return $this->findByPk($db, $type, $columnName); - } - - $method = 'build' . $type; - $script = $db->getLuaScriptBuilder()->$method($this, $columnName); - return $db->executeCommand('EVAL', [$script, 0]); - } - - /** - * Fetch by pk if possible as this is much faster - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `db` application component will be used. - * @param string $type the type of the script to generate - * @param string $columnName - * @return array|bool|null|string - * @throws \yii\base\InvalidParamException - * @throws \yii\base\NotSupportedException - */ - private function findByPk($db, $type, $columnName = null) - { - if (count($this->where) == 1) { - $pks = (array) reset($this->where); - } else { - foreach($this->where as $column => $values) { - if (is_array($values)) { - // TODO support composite IN for composite PK - throw new NotSupportedException('Find by composite PK is not supported by redis ActiveRecord.'); - } - } - $pks = [$this->where]; - } - - /** @var ActiveRecord $modelClass */ - $modelClass = $this->modelClass; - - if ($type == 'Count') { - $start = 0; - $limit = null; - } else { - $start = $this->offset === null ? 0 : $this->offset; - $limit = $this->limit; - } - $i = 0; - $data = []; - foreach($pks as $pk) { - if (++$i > $start && ($limit === null || $i <= $start + $limit)) { - $key = $modelClass::keyPrefix() . ':a:' . $modelClass::buildKey($pk); - $result = $db->executeCommand('HGETALL', [$key]); - if (!empty($result)) { - $data[] = $result; - if ($type === 'One' && $this->orderBy === null) { - break; - } - } - } - } - // TODO support orderBy - - switch($type) { - case 'All': - return $data; - case 'One': - return reset($data); - case 'Count': - return count($data); - case 'Column': - $column = []; - foreach($data as $dataRow) { - $row = []; - $c = count($dataRow); - for($i = 0; $i < $c; ) { - $row[$dataRow[$i++]] = $dataRow[$i++]; - } - $column[] = $row[$columnName]; - } - return $column; - case 'Sum': - $sum = 0; - foreach($data as $dataRow) { - $c = count($dataRow); - for($i = 0; $i < $c; ) { - if ($dataRow[$i++] == $columnName) { - $sum += $dataRow[$i]; - break; - } - } - } - return $sum; - case 'Average': - $sum = 0; - $count = 0; - foreach($data as $dataRow) { - $count++; - $c = count($dataRow); - for($i = 0; $i < $c; ) { - if ($dataRow[$i++] == $columnName) { - $sum += $dataRow[$i]; - break; - } - } - } - return $sum / $count; - case 'Min': - $min = null; - foreach($data as $dataRow) { - $c = count($dataRow); - for($i = 0; $i < $c; ) { - if ($dataRow[$i++] == $columnName && ($min == null || $dataRow[$i] < $min)) { - $min = $dataRow[$i]; - break; - } - } - } - return $min; - case 'Max': - $max = null; - foreach($data as $dataRow) { - $c = count($dataRow); - for($i = 0; $i < $c; ) { - if ($dataRow[$i++] == $columnName && ($max == null || $dataRow[$i] > $max)) { - $max = $dataRow[$i]; - break; - } - } - } - return $max; - } - throw new InvalidParamException('Unknown fetch type: ' . $type); - } -} diff --git a/extensions/yii/redis/ActiveRecord.php b/extensions/yii/redis/ActiveRecord.php deleted file mode 100644 index 2e2bcbb..0000000 --- a/extensions/yii/redis/ActiveRecord.php +++ /dev/null @@ -1,305 +0,0 @@ - - * @since 2.0 - */ -class ActiveRecord extends BaseActiveRecord -{ - /** - * Returns the database connection used by this AR class. - * By default, the "redis" 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('redis'); - } - - /** - * @inheritdoc - */ - public static function createQuery() - { - return new ActiveQuery(['modelClass' => get_called_class()]); - } - - /** - * @inheritdoc - */ - public static function createActiveRelation($config = []) - { - return new ActiveRelation($config); - } - - /** - * Returns the primary key name(s) for this AR class. - * This method should be overridden by child classes to define the primary key. - * - * Note that an array should be returned even when it is a single primary key. - * - * @return string[] the primary keys of this record. - */ - 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. - * @return array list of attribute names. - */ - public function attributes() - { - throw new InvalidConfigException('The attributes() method of redis ActiveRecord has to be implemented by child classes.'); - } - - /** - * Declares prefix of the key that represents the keys that store this records in redis. - * By default this method returns the class name as the table name by calling [[Inflector::camel2id()]]. - * For example, 'Customer' becomes 'customer', and 'OrderItem' becomes - * 'order_item'. You may override this method if you want different key naming. - * @return string the prefix to apply to all AR keys - */ - public static function keyPrefix() - { - return Inflector::camel2id(StringHelper::basename(get_called_class()), '_'); - } - - /** - * @inheritdoc - */ - public function insert($runValidation = true, $attributes = null) - { - if ($runValidation && !$this->validate($attributes)) { - return false; - } - if ($this->beforeSave(true)) { - $db = static::getDb(); - $values = $this->getDirtyAttributes($attributes); - $pk = []; -// if ($values === []) { - foreach ($this->primaryKey() as $key) { - $pk[$key] = $values[$key] = $this->getAttribute($key); - if ($pk[$key] === null) { - $pk[$key] = $values[$key] = $db->executeCommand('INCR', [static::keyPrefix() . ':s:' . $key]); - $this->setAttribute($key, $values[$key]); - } - } -// } - // save pk in a findall pool - $db->executeCommand('RPUSH', [static::keyPrefix(), static::buildKey($pk)]); - - $key = static::keyPrefix() . ':a:' . static::buildKey($pk); - // save attributes - $args = [$key]; - foreach($values as $attribute => $value) { - $args[] = $attribute; - $args[] = $value; - } - $db->executeCommand('HMSET', $args); - - $this->setOldAttributes($values); - $this->afterSave(true); - return true; - } - return false; - } - - /** - * Updates the whole table using the provided attribute values and conditions. - * For example, to change the status to be 1 for all customers whose status is 2: - * - * ~~~ - * Customer::updateAll(['status' => 1], ['id' => 2]); - * ~~~ - * - * @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 = null) - { - if (empty($attributes)) { - return 0; - } - $db = static::getDb(); - $n=0; - foreach(static::fetchPks($condition) as $pk) { - $newPk = $pk; - $pk = static::buildKey($pk); - $key = static::keyPrefix() . ':a:' . $pk; - // save attributes - $args = [$key]; - foreach($attributes as $attribute => $value) { - if (isset($newPk[$attribute])) { - $newPk[$attribute] = $value; - } - $args[] = $attribute; - $args[] = $value; - } - $newPk = static::buildKey($newPk); - $newKey = static::keyPrefix() . ':a:' . $newPk; - // rename index if pk changed - if ($newPk != $pk) { - $db->executeCommand('MULTI'); - $db->executeCommand('HMSET', $args); - $db->executeCommand('LINSERT', [static::keyPrefix(), 'AFTER', $pk, $newPk]); - $db->executeCommand('LREM', [static::keyPrefix(), 0, $pk]); - $db->executeCommand('RENAME', [$key, $newKey]); - $db->executeCommand('EXEC'); - } else { - $db->executeCommand('HMSET', $args); - } - $n++; - } - return $n; - } - - /** - * Updates the whole table 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 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 updateAllCounters($counters, $condition = null) - { - if (empty($counters)) { - return 0; - } - $db = static::getDb(); - $n=0; - foreach(static::fetchPks($condition) as $pk) { - $key = static::keyPrefix() . ':a:' . static::buildKey($pk); - foreach($counters as $attribute => $value) { - $db->executeCommand('HINCRBY', [$key, $attribute, $value]); - } - $n++; - } - return $n; - } - - /** - * Deletes rows in the table using the provided conditions. - * WARNING: If you do not specify any condition, this method will delete ALL rows in the table. - * - * For example, to delete all customers whose status is 3: - * - * ~~~ - * Customer::deleteAll(['status' => 3]); - * ~~~ - * - * @param array $condition the conditions that will be put in the WHERE part of the DELETE SQL. - * Please refer to [[ActiveQuery::where()]] on how to specify this parameter. - * @return integer the number of rows deleted - */ - public static function deleteAll($condition = null) - { - $db = static::getDb(); - $attributeKeys = []; - $pks = static::fetchPks($condition); - $db->executeCommand('MULTI'); - foreach($pks as $pk) { - $pk = static::buildKey($pk); - $db->executeCommand('LREM', [static::keyPrefix(), 0, $pk]); - $attributeKeys[] = static::keyPrefix() . ':a:' . $pk; - } - if (empty($attributeKeys)) { - $db->executeCommand('EXEC'); - return 0; - } - $db->executeCommand('DEL', $attributeKeys); - $result = $db->executeCommand('EXEC'); - return end($result); - } - - private static function fetchPks($condition) - { - $query = static::createQuery(); - $query->where($condition); - $records = $query->asArray()->all(); // TODO limit fetched columns to pk - $primaryKey = static::primaryKey(); - - $pks = []; - foreach($records as $record) { - $pk = []; - foreach($primaryKey as $key) { - $pk[$key] = $record[$key]; - } - $pks[] = $pk; - } - return $pks; - } - - /** - * Builds a normalized key from a given primary key value. - * - * @param mixed $key the key to be normalized - * @return string the generated key - */ - public static function buildKey($key) - { - if (is_numeric($key)) { - return $key; - } elseif (is_string($key)) { - return ctype_alnum($key) && StringHelper::byteLength($key) <= 32 ? $key : md5($key); - } elseif (is_array($key)) { - if (count($key) == 1) { - return self::buildKey(reset($key)); - } - ksort($key); // ensure order is always the same - $isNumeric = true; - foreach($key as $value) { - if (!is_numeric($value)) { - $isNumeric = false; - } - } - if ($isNumeric) { - return implode('-', $key); - } - } - return md5(json_encode($key)); - } -} diff --git a/extensions/yii/redis/ActiveRelation.php b/extensions/yii/redis/ActiveRelation.php deleted file mode 100644 index b2f5cea..0000000 --- a/extensions/yii/redis/ActiveRelation.php +++ /dev/null @@ -1,67 +0,0 @@ - - * @since 2.0 - */ -class ActiveRelation extends ActiveQuery implements ActiveRelationInterface -{ - use ActiveRelationTrait; - - /** - * Executes a script created by [[LuaScriptBuilder]] - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `db` application component will be used. - * @param string $type the type of the script to generate - * @param null $column - * @return array|bool|null|string - */ - protected function executeScript($db, $type, $column=null) - { - if ($this->primaryModel !== null) { - // lazy loading - if ($this->via instanceof self) { - // via pivot table - $viaModels = $this->via->findPivotRows([$this->primaryModel]); - $this->filterByModels($viaModels); - } elseif (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::executeScript($db, $type, $column); - } -} diff --git a/extensions/yii/redis/CHANGELOG.md b/extensions/yii/redis/CHANGELOG.md deleted file mode 100644 index f68bc4b..0000000 --- a/extensions/yii/redis/CHANGELOG.md +++ /dev/null @@ -1,12 +0,0 @@ -Yii Framework 2 redis extension Change Log -========================================== - -2.0.0 beta under development ----------------------------- - -- Enh #1773: keyPrefix property of Session and Cache is not restricted to alnum characters anymore (cebe) - -2.0.0 alpha, December 1, 2013 ------------------------------ - -- Initial release. diff --git a/extensions/yii/redis/Cache.php b/extensions/yii/redis/Cache.php deleted file mode 100644 index 0722b9d..0000000 --- a/extensions/yii/redis/Cache.php +++ /dev/null @@ -1,204 +0,0 @@ - [ - * 'cache' => [ - * 'class' => 'yii\redis\Cache', - * 'redis' => [ - * 'hostname' => 'localhost', - * 'port' => 6379, - * 'database' => 0, - * ] - * ], - * ], - * ] - * ~~~ - * - * Or if you have configured the redis [[Connection]] as an application component, the following is sufficient: - * - * ~~~ - * [ - * 'components' => [ - * 'cache' => [ - * 'class' => 'yii\redis\Cache', - * // 'redis' => 'redis' // id of the connection application component - * ], - * ], - * ] - * ~~~ - * - * @author Carsten Brandt - * @since 2.0 - */ -class Cache extends \yii\caching\Cache -{ - /** - * @var Connection|string|array the Redis [[Connection]] object or the application component ID of the Redis [[Connection]]. - * This can also be an array that is used to create a redis [[Connection]] instance in case you do not want do configure - * redis connection as an application component. - * After the Cache object is created, if you want to change this property, you should only assign it - * with a Redis [[Connection]] object. - */ - public $redis = 'redis'; - - - /** - * Initializes the redis Cache component. - * This method will initialize the [[redis]] property to make sure it refers to a valid redis connection. - * @throws InvalidConfigException if [[redis]] is invalid. - */ - public function init() - { - parent::init(); - if (is_string($this->redis)) { - $this->redis = Yii::$app->getComponent($this->redis); - } else if (is_array($this->redis)) { - if (!isset($this->redis['class'])) { - $this->redis['class'] = Connection::className(); - } - $this->redis = Yii::createObject($this->redis); - } - if (!$this->redis instanceof Connection) { - throw new InvalidConfigException("Cache::redis must be either a Redis connection instance or the application component ID of a Redis connection."); - } - } - - /** - * Checks whether a specified key exists in the cache. - * This can be faster than getting the value from the cache if the data is big. - * Note that this method does not check whether the dependency associated - * with the cached data, if there is any, has changed. So a call to [[get]] - * may return false while exists returns true. - * @param mixed $key a key identifying the cached value. This can be a simple string or - * a complex data structure consisting of factors representing the key. - * @return boolean true if a value exists in cache, false if the value is not in the cache or expired. - */ - public function exists($key) - { - return (bool) $this->redis->executeCommand('EXISTS', [$this->buildKey($key)]); - } - - /** - * @inheritdoc - */ - protected function getValue($key) - { - return $this->redis->executeCommand('GET', [$key]); - } - - /** - * @inheritdoc - */ - protected function getValues($keys) - { - $response = $this->redis->executeCommand('MGET', $keys); - $result = []; - $i = 0; - foreach ($keys as $key) { - $result[$key] = $response[$i++]; - } - return $result; - } - - /** - * @inheritdoc - */ - protected function setValue($key, $value, $expire) - { - if ($expire == 0) { - return (bool) $this->redis->executeCommand('SET', [$key, $value]); - } else { - $expire = (int) ($expire * 1000); - return (bool) $this->redis->executeCommand('SET', [$key, $value, 'PX', $expire]); - } - } - - /** - * @inheritdoc - */ - protected function setValues($data, $expire) - { - $args = []; - foreach($data as $key => $value) { - $args[] = $key; - $args[] = $value; - } - - $failedKeys = []; - if ($expire == 0) { - $this->redis->executeCommand('MSET', $args); - } else { - $expire = (int) ($expire * 1000); - $this->redis->executeCommand('MULTI'); - $this->redis->executeCommand('MSET', $args); - $index = []; - foreach ($data as $key => $value) { - $this->redis->executeCommand('PEXPIRE', [$key, $expire]); - $index[] = $key; - } - $result = $this->redis->executeCommand('EXEC'); - array_shift($result); - foreach($result as $i => $r) { - if ($r != 1) { - $failedKeys[] = $index[$i]; - } - } - } - return $failedKeys; - } - - /** - * @inheritdoc - */ - protected function addValue($key, $value, $expire) - { - if ($expire == 0) { - return (bool) $this->redis->executeCommand('SET', [$key, $value, 'NX']); - } else { - $expire = (int) ($expire * 1000); - return (bool) $this->redis->executeCommand('SET', [$key, $value, 'PX', $expire, 'NX']); - } - } - - /** - * @inheritdoc - */ - protected function deleteValue($key) - { - return (bool) $this->redis->executeCommand('DEL', [$key]); - } - - /** - * @inheritdoc - */ - protected function flushValues() - { - return $this->redis->executeCommand('FLUSHDB'); - } -} diff --git a/extensions/yii/redis/Connection.php b/extensions/yii/redis/Connection.php deleted file mode 100644 index b05223d..0000000 --- a/extensions/yii/redis/Connection.php +++ /dev/null @@ -1,406 +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 string the hostname or ip address to use for connecting to the redis server. Defaults to 'localhost'. - */ - public $hostname = 'localhost'; - /** - * @var int the port to use for connecting to the redis server. Default port is 6379. - */ - public $port = 6379; - /** - * @var string the password for establishing DB connection. Defaults to null meaning no AUTH command is send. - * See http://redis.io/commands/auth - */ - public $password; - /** - * @var int the redis database to use. This is an integer value starting from 0. Defaults to 0. - */ - public $database = 0; - /** - * @var float timeout to use for connection to redis. If not set the timeout set in php.ini will be used: ini_get("default_socket_timeout") - */ - public $connectionTimeout = null; - /** - * @var float timeout to use for redis socket when reading and writing data. If not set the php default value will be used. - */ - public $dataTimeout = null; - - /** - * @var array List of available redis commands http://redis.io/commands - */ - public $redisCommands = [ - 'BRPOP', // key [key ...] timeout Remove and get the last element in a list, or block until one is available - 'BRPOPLPUSH', // source destination timeout Pop a value from a list, push it to another list and return it; or block until one is available - 'CLIENT KILL', // ip:port Kill the connection of a client - 'CLIENT LIST', // Get the list of client connections - 'CLIENT GETNAME', // Get the current connection name - 'CLIENT SETNAME', // connection-name Set the current connection name - 'CONFIG GET', // parameter Get the value of a configuration parameter - 'CONFIG SET', // parameter value Set a configuration parameter to the given value - 'CONFIG RESETSTAT', // Reset the stats returned by INFO - 'DBSIZE', // Return the number of keys in the selected database - 'DEBUG OBJECT', // key Get debugging information about a key - 'DEBUG SEGFAULT', // Make the server crash - 'DECR', // key Decrement the integer value of a key by one - 'DECRBY', // key decrement Decrement the integer value of a key by the given number - 'DEL', // key [key ...] Delete a key - 'DISCARD', // Discard all commands issued after MULTI - 'DUMP', // key Return a serialized version of the value stored at the specified key. - 'ECHO', // message Echo the given string - 'EVAL', // script numkeys key [key ...] arg [arg ...] Execute a Lua script server side - 'EVALSHA', // sha1 numkeys key [key ...] arg [arg ...] Execute a Lua script server side - 'EXEC', // Execute all commands issued after MULTI - 'EXISTS', // key Determine if a key exists - 'EXPIRE', // key seconds Set a key's time to live in seconds - 'EXPIREAT', // key timestamp Set the expiration for a key as a UNIX timestamp - 'FLUSHALL', // Remove all keys from all databases - 'FLUSHDB', // Remove all keys from the current database - 'GET', // key Get the value of a key - 'GETBIT', // key offset Returns the bit value at offset in the string value stored at key - 'GETRANGE', // key start end Get a substring of the string stored at a key - 'GETSET', // key value Set the string value of a key and return its old value - 'HDEL', // key field [field ...] Delete one or more hash fields - 'HEXISTS', // key field Determine if a hash field exists - 'HGET', // key field Get the value of a hash field - 'HGETALL', // key Get all the fields and values in a hash - 'HINCRBY', // key field increment Increment the integer value of a hash field by the given number - 'HINCRBYFLOAT', // key field increment Increment the float value of a hash field by the given amount - 'HKEYS', // key Get all the fields in a hash - 'HLEN', // key Get the number of fields in a hash - 'HMGET', // key field [field ...] Get the values of all the given hash fields - 'HMSET', // key field value [field value ...] Set multiple hash fields to multiple values - 'HSET', // key field value Set the string value of a hash field - 'HSETNX', // key field value Set the value of a hash field, only if the field does not exist - 'HVALS', // key Get all the values in a hash - 'INCR', // key Increment the integer value of a key by one - 'INCRBY', // key increment Increment the integer value of a key by the given amount - 'INCRBYFLOAT', // key increment Increment the float value of a key by the given amount - 'INFO', // [section] Get information and statistics about the server - 'KEYS', // pattern Find all keys matching the given pattern - 'LASTSAVE', // Get the UNIX time stamp of the last successful save to disk - 'LINDEX', // key index Get an element from a list by its index - 'LINSERT', // key BEFORE|AFTER pivot value Insert an element before or after another element in a list - 'LLEN', // key Get the length of a list - 'LPOP', // key Remove and get the first element in a list - 'LPUSH', // key value [value ...] Prepend one or multiple values to a list - 'LPUSHX', // key value Prepend a value to a list, only if the list exists - 'LRANGE', // key start stop Get a range of elements from a list - 'LREM', // key count value Remove elements from a list - 'LSET', // key index value Set the value of an element in a list by its index - 'LTRIM', // key start stop Trim a list to the specified range - 'MGET', // key [key ...] Get the values of all the given keys - 'MIGRATE', // host port key destination-db timeout Atomically transfer a key from a Redis instance to another one. - 'MONITOR', // Listen for all requests received by the server in real time - 'MOVE', // key db Move a key to another database - 'MSET', // key value [key value ...] Set multiple keys to multiple values - 'MSETNX', // key value [key value ...] Set multiple keys to multiple values, only if none of the keys exist - 'MULTI', // Mark the start of a transaction block - 'OBJECT', // subcommand [arguments [arguments ...]] Inspect the internals of Redis objects - 'PERSIST', // key Remove the expiration from a key - 'PEXPIRE', // key milliseconds Set a key's time to live in milliseconds - 'PEXPIREAT', // key milliseconds-timestamp Set the expiration for a key as a UNIX timestamp specified in milliseconds - 'PING', // Ping the server - 'PSETEX', // key milliseconds value Set the value and expiration in milliseconds of a key - 'PSUBSCRIBE', // pattern [pattern ...] Listen for messages published to channels matching the given patterns - 'PTTL', // key Get the time to live for a key in milliseconds - 'PUBLISH', // channel message Post a message to a channel - 'PUNSUBSCRIBE', // [pattern [pattern ...]] Stop listening for messages posted to channels matching the given patterns - 'QUIT', // Close the connection - 'RANDOMKEY', // Return a random key from the keyspace - 'RENAME', // key newkey Rename a key - 'RENAMENX', // key newkey Rename a key, only if the new key does not exist - 'RESTORE', // key ttl serialized-value Create a key using the provided serialized value, previously obtained using DUMP. - 'RPOP', // key Remove and get the last element in a list - 'RPOPLPUSH', // source destination Remove the last element in a list, append it to another list and return it - 'RPUSH', // key value [value ...] Append one or multiple values to a list - 'RPUSHX', // key value Append a value to a list, only if the list exists - 'SADD', // key member [member ...] Add one or more members to a set - 'SAVE', // Synchronously save the dataset to disk - 'SCARD', // key Get the number of members in a set - 'SCRIPT EXISTS', // script [script ...] Check existence of scripts in the script cache. - 'SCRIPT FLUSH', // Remove all the scripts from the script cache. - 'SCRIPT KILL', // Kill the script currently in execution. - 'SCRIPT LOAD', // script Load the specified Lua script into the script cache. - 'SDIFF', // key [key ...] Subtract multiple sets - 'SDIFFSTORE', // destination key [key ...] Subtract multiple sets and store the resulting set in a key - 'SELECT', // index Change the selected database for the current connection - 'SET', // key value Set the string value of a key - 'SETBIT', // key offset value Sets or clears the bit at offset in the string value stored at key - 'SETEX', // key seconds value Set the value and expiration of a key - 'SETNX', // key value Set the value of a key, only if the key does not exist - 'SETRANGE', // key offset value Overwrite part of a string at key starting at the specified offset - 'SHUTDOWN', // [NOSAVE] [SAVE] Synchronously save the dataset to disk and then shut down the server - 'SINTER', // key [key ...] Intersect multiple sets - 'SINTERSTORE', // destination key [key ...] Intersect multiple sets and store the resulting set in a key - 'SISMEMBER', // key member Determine if a given value is a member of a set - 'SLAVEOF', // host port Make the server a slave of another instance, or promote it as master - 'SLOWLOG', // subcommand [argument] Manages the Redis slow queries log - 'SMEMBERS', // key Get all the members in a set - 'SMOVE', // source destination member Move a member from one set to another - 'SORT', // key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination] Sort the elements in a list, set or sorted set - 'SPOP', // key Remove and return a random member from a set - 'SRANDMEMBER', // key [count] Get one or multiple random members from a set - 'SREM', // key member [member ...] Remove one or more members from a set - 'STRLEN', // key Get the length of the value stored in a key - 'SUBSCRIBE', // channel [channel ...] Listen for messages published to the given channels - 'SUNION', // key [key ...] Add multiple sets - 'SUNIONSTORE', // destination key [key ...] Add multiple sets and store the resulting set in a key - 'SYNC', // Internal command used for replication - 'TIME', // Return the current server time - 'TTL', // key Get the time to live for a key - 'TYPE', // key Determine the type stored at key - 'UNSUBSCRIBE', // [channel [channel ...]] Stop listening for messages posted to the given channels - 'UNWATCH', // Forget about all watched keys - 'WATCH', // key [key ...] Watch the given keys to determine execution of the MULTI/EXEC block - 'ZADD', // key score member [score member ...] Add one or more members to a sorted set, or update its score if it already exists - 'ZCARD', // key Get the number of members in a sorted set - 'ZCOUNT', // key min max Count the members in a sorted set with scores within the given values - 'ZINCRBY', // key increment member Increment the score of a member in a sorted set - 'ZINTERSTORE', // destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] Intersect multiple sorted sets and store the resulting sorted set in a new key - 'ZRANGE', // key start stop [WITHSCORES] Return a range of members in a sorted set, by index - 'ZRANGEBYSCORE', // key min max [WITHSCORES] [LIMIT offset count] Return a range of members in a sorted set, by score - 'ZRANK', // key member Determine the index of a member in a sorted set - 'ZREM', // key member [member ...] Remove one or more members from a sorted set - 'ZREMRANGEBYRANK', // key start stop Remove all members in a sorted set within the given indexes - 'ZREMRANGEBYSCORE', // key min max Remove all members in a sorted set within the given scores - 'ZREVRANGE', // key start stop [WITHSCORES] Return a range of members in a sorted set, by index, with scores ordered from high to low - 'ZREVRANGEBYSCORE', // key max min [WITHSCORES] [LIMIT offset count] Return a range of members in a sorted set, by score, with scores ordered from high to low - 'ZREVRANK', // key member Determine the index of a member in a sorted set, with scores ordered from high to low - 'ZSCORE', // key member Get the score associated with the given member in a sorted set - 'ZUNIONSTORE', // destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] Add multiple sorted sets and store the resulting sorted set in a new key - ]; - /** - * @var resource redis socket connection - */ - private $_socket; - - /** - * 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->_socket !== 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->_socket !== null) { - return; - } - $connection = $this->hostname . ':' . $this->port . ', database=' . $this->database; - \Yii::trace('Opening redis DB connection: ' . $connection, __CLASS__); - $this->_socket = @stream_socket_client( - 'tcp://' . $this->hostname . ':' . $this->port, - $errorNumber, - $errorDescription, - $this->connectionTimeout ? $this->connectionTimeout : ini_get("default_socket_timeout") - ); - if ($this->_socket) { - if ($this->dataTimeout !== null) { - stream_set_timeout($this->_socket, $timeout=(int)$this->dataTimeout, (int) (($this->dataTimeout - $timeout) * 1000000)); - } - if ($this->password !== null) { - $this->executeCommand('AUTH', [$this->password]); - } - $this->executeCommand('SELECT', [$this->database]); - $this->initConnection(); - } else { - \Yii::error("Failed to open redis DB connection ($connection): $errorNumber - $errorDescription", __CLASS__); - $message = YII_DEBUG ? "Failed to open redis DB connection ($connection): $errorNumber - $errorDescription" : 'Failed to open DB connection.'; - throw new Exception($message, $errorDescription, (int)$errorNumber); - } - } - - /** - * Closes the currently active DB connection. - * It does nothing if the connection is already closed. - */ - public function close() - { - if ($this->_socket !== null) { - $connection = $this->hostname . ':' . $this->port . ', database=' . $this->database; - \Yii::trace('Closing DB connection: ' . $connection, __CLASS__); - $this->executeCommand('QUIT'); - stream_socket_shutdown($this->_socket, STREAM_SHUT_RDWR); - $this->_socket = 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 'redis'; - } - - /** - * @return LuaScriptBuilder - */ - public function getLuaScriptBuilder() - { - return new LuaScriptBuilder(); - } - - /** - * - * @param string $name - * @param array $params - * @return mixed - */ - public function __call($name, $params) - { - $redisCommand = strtoupper(Inflector::camel2words($name, false)); - if (in_array($redisCommand, $this->redisCommands)) { - return $this->executeCommand($name, $params); - } else { - return parent::__call($name, $params); - } - } - - /** - * Executes a redis command. - * For a list of available commands and their parameters see http://redis.io/commands. - * - * @param string $name the name of the command - * @param array $params list of parameters for the command - * @return array|bool|null|string Dependend on the executed command this method - * will return different data types: - * - * - `true` for commands that return "status reply". - * - `string` for commands that return "integer reply" - * as the value is in the range of a signed 64 bit integer. - * - `string` or `null` for commands that return "bulk reply". - * - `array` for commands that return "Multi-bulk replies". - * - * See [redis protocol description](http://redis.io/topics/protocol) - * for details on the mentioned reply types. - * @trows Exception for commands that return [error reply](http://redis.io/topics/protocol#error-reply). - */ - public function executeCommand($name, $params=[]) - { - $this->open(); - - array_unshift($params, $name); - $command = '*' . count($params) . "\r\n"; - foreach($params as $arg) { - $command .= '$' . mb_strlen($arg, '8bit') . "\r\n" . $arg . "\r\n"; - } - - \Yii::trace("Executing Redis Command: {$name}", __CLASS__); - fwrite($this->_socket, $command); - - return $this->parseResponse(implode(' ', $params)); - } - - private function parseResponse($command) - { - if (($line = fgets($this->_socket)) === false) { - throw new Exception("Failed to read from socket.\nRedis command was: " . $command); - } - $type = $line[0]; - $line = mb_substr($line, 1, -2, '8bit'); - switch($type) - { - case '+': // Status reply - return true; - case '-': // Error reply - throw new Exception("Redis error: " . $line . "\nRedis command was: " . $command); - case ':': // Integer reply - // no cast to int as it is in the range of a signed 64 bit integer - return $line; - case '$': // Bulk replies - if ($line == '-1') { - return null; - } - $length = $line + 2; - $data = ''; - while ($length > 0) { - if (($block = fread($this->_socket, $line + 2)) === false) { - throw new Exception("Failed to read from socket.\nRedis command was: " . $command); - } - $data .= $block; - $length -= mb_strlen($block, '8bit'); - } - return mb_substr($data, 0, -2, '8bit'); - case '*': // Multi-bulk replies - $count = (int) $line; - $data = []; - for ($i = 0; $i < $count; $i++) { - $data[] = $this->parseResponse($command); - } - return $data; - default: - throw new Exception('Received illegal data from redis: ' . $line . "\nRedis command was: " . $command); - } - } -} diff --git a/extensions/yii/redis/LICENSE.md b/extensions/yii/redis/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/extensions/yii/redis/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/redis/LuaScriptBuilder.php b/extensions/yii/redis/LuaScriptBuilder.php deleted file mode 100644 index f49189e..0000000 --- a/extensions/yii/redis/LuaScriptBuilder.php +++ /dev/null @@ -1,379 +0,0 @@ - - * @since 2.0 - */ -class LuaScriptBuilder extends \yii\base\Object -{ - /** - * Builds a Lua script for finding a list of records - * @param ActiveQuery $query the query used to build the script - * @return string - */ - public function buildAll($query) - { - // TODO add support for orderBy - /** @var ActiveRecord $modelClass */ - $modelClass = $query->modelClass; - $key = $this->quoteValue($modelClass::keyPrefix() . ':a:'); - return $this->build($query, "n=n+1 pks[n]=redis.call('HGETALL',$key .. pk)", 'pks'); - } - - /** - * Builds a Lua script for finding one record - * @param ActiveQuery $query the query used to build the script - * @return string - */ - public function buildOne($query) - { - // TODO add support for orderBy - /** @var ActiveRecord $modelClass */ - $modelClass = $query->modelClass; - $key = $this->quoteValue($modelClass::keyPrefix() . ':a:'); - return $this->build($query, "do return redis.call('HGETALL',$key .. pk) end", 'pks'); - } - - /** - * Builds a Lua script for finding a column - * @param ActiveQuery $query the query used to build the script - * @param string $column name of the column - * @return string - */ - public function buildColumn($query, $column) - { - // TODO add support for orderBy and indexBy - /** @var ActiveRecord $modelClass */ - $modelClass = $query->modelClass; - $key = $this->quoteValue($modelClass::keyPrefix() . ':a:'); - return $this->build($query, "n=n+1 pks[n]=redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ")", 'pks'); - } - - /** - * Builds a Lua script for getting count of records - * @param ActiveQuery $query the query used to build the script - * @return string - */ - public function buildCount($query) - { - return $this->build($query, 'n=n+1', 'n'); - } - - /** - * Builds a Lua script for finding the sum of a column - * @param ActiveQuery $query the query used to build the script - * @param string $column name of the column - * @return string - */ - public function buildSum($query, $column) - { - /** @var ActiveRecord $modelClass */ - $modelClass = $query->modelClass; - $key = $this->quoteValue($modelClass::keyPrefix() . ':a:'); - return $this->build($query, "n=n+redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ")", 'n'); - } - - /** - * Builds a Lua script for finding the average of a column - * @param ActiveQuery $query the query used to build the script - * @param string $column name of the column - * @return string - */ - public function buildAverage($query, $column) - { - /** @var ActiveRecord $modelClass */ - $modelClass = $query->modelClass; - $key = $this->quoteValue($modelClass::keyPrefix() . ':a:'); - return $this->build($query, "n=n+1 if v==nil then v=0 end v=v+redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ")", 'v/n'); - } - - /** - * Builds a Lua script for finding the min value of a column - * @param ActiveQuery $query the query used to build the script - * @param string $column name of the column - * @return string - */ - public function buildMin($query, $column) - { - /** @var ActiveRecord $modelClass */ - $modelClass = $query->modelClass; - $key = $this->quoteValue($modelClass::keyPrefix() . ':a:'); - return $this->build($query, "n=redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ") if v==nil or nmodelClass; - $key = $this->quoteValue($modelClass::keyPrefix() . ':a:'); - return $this->build($query, "n=redis.call('HGET',$key .. pk," . $this->quoteValue($column) . ") if v==nil or n>v then v=n end", 'v'); - } - - /** - * @param ActiveQuery $query the query used to build the script - * @param string $buildResult the lua script for building the result - * @param string $return the lua variable that should be returned - * @return string - */ - private function build($query, $buildResult, $return) - { - if (!empty($query->orderBy)) { - throw new NotSupportedException('orderBy is currently not supported by redis ActiveRecord.'); - } - - $columns = []; - if ($query->where !== null) { - $condition = $this->buildCondition($query->where, $columns); - } else { - $condition = 'true'; - } - - $start = $query->offset === null ? 0 : $query->offset; - $limitCondition = 'i>' . $start . ($query->limit === null ? '' : ' and i<=' . ($start + $query->limit)); - - /** @var ActiveRecord $modelClass */ - $modelClass = $query->modelClass; - $key = $this->quoteValue($modelClass::keyPrefix()); - $loadColumnValues = ''; - foreach($columns as $column => $alias) { - $loadColumnValues .= "local $alias=redis.call('HGET',$key .. ':a:' .. pk, '$column')\n"; - } - - return << '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 (!is_array($condition)) { - throw new NotSupportedException('Where condition must be an array in redis ActiveRecord.'); - } - 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, $columns); - } else { - throw new Exception('Found unknown operator in query: ' . $operator); - } - } else { // hash format: 'column1' => 'value1', 'column2' => 'value2', ... - return $this->buildHashCondition($condition, $columns); - } - } - - private function buildHashCondition($condition, &$columns) - { - $parts = []; - foreach ($condition as $column => $value) { - if (is_array($value)) { // IN condition - $parts[] = $this->buildInCondition('in', [$column, $value], $columns); - } else { - $column = $this->addColumn($column, $columns); - if ($value === null) { - $parts[] = "$column==nil"; - } elseif ($value instanceof Expression) { - $parts[] = "$column==" . $value->expression; - } else { - $value = $this->quoteValue($value); - $parts[] = "$column==$value"; - } - } - } - return count($parts) === 1 ? $parts[0] : '(' . implode(') 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 "!($operand)"; - } - - private function buildAndCondition($operator, $operands, &$columns) - { - $parts = []; - foreach ($operands as $operand) { - if (is_array($operand)) { - $operand = $this->buildCondition($operand, $columns); - } - if ($operand !== '') { - $parts[] = $operand; - } - } - if (!empty($parts)) { - return '(' . implode(") $operator (", $parts) . ')'; - } else { - return ''; - } - } - - private function buildBetweenCondition($operator, $operands, &$columns) - { - if (!isset($operands[0], $operands[1], $operands[2])) { - throw new Exception("Operator '$operator' requires three operands."); - } - - list($column, $value1, $value2) = $operands; - - $value1 = $this->quoteValue($value1); - $value2 = $this->quoteValue($value2); - $column = $this->addColumn($column, $columns); - return "$column >= $value1 and $column <= $value2"; - } - - private function buildInCondition($operator, $operands, &$columns) - { - if (!isset($operands[0], $operands[1])) { - throw new Exception("Operator '$operator' requires two operands."); - } - - list($column, $values) = $operands; - - $values = (array)$values; - - if (empty($values) || $column === []) { - return $operator === 'in' ? 'false' : 'true'; - } - - if (count($column) > 1) { - return $this->buildCompositeInCondition($operator, $column, $values, $columns); - } elseif (is_array($column)) { - $column = reset($column); - } - $columnAlias = $this->addColumn($column, $columns); - $parts = []; - foreach ($values as $i => $value) { - if (is_array($value)) { - $value = isset($value[$column]) ? $value[$column] : null; - } - if ($value === null) { - $parts[] = "$columnAlias==nil"; - } elseif ($value instanceof Expression) { - $parts[] = "$columnAlias==" . $value->expression; - } else { - $value = $this->quoteValue($value); - $parts[] = "$columnAlias==$value"; - } - } - $operator = $operator === 'in' ? '' : 'not '; - return "$operator(" . implode(' or ', $parts) . ')'; - } - - protected function buildCompositeInCondition($operator, $inColumns, $values, &$columns) - { - $vss = []; - foreach ($values as $value) { - $vs = []; - foreach ($inColumns as $column) { - $column = $this->addColumn($column, $columns); - if (isset($value[$column])) { - $vs[] = "$column==" . $this->quoteValue($value[$column]); - } else { - $vs[] = "$column==nil"; - } - } - $vss[] = '(' . implode(' and ', $vs) . ')'; - } - $operator = $operator === 'in' ? '' : 'not '; - return "$operator(" . implode(' or ', $vss) . ')'; - } - - private function buildLikeCondition($operator, $operands, &$columns) - { - throw new NotSupportedException('LIKE conditions are not suppoerted by redis ActiveRecord.'); - } -} diff --git a/extensions/yii/redis/README.md b/extensions/yii/redis/README.md deleted file mode 100644 index 21d14a2..0000000 --- a/extensions/yii/redis/README.md +++ /dev/null @@ -1,184 +0,0 @@ -Redis Cache, Session and ActiveRecord for Yii 2 -=============================================== - -This extension provides the [redis](http://redis.io/) key-value store support for the Yii2 framework. -It includes a `Cache` and `Session` storage handler and implents the `ActiveRecord` pattern that allows -you to store active records in redis. - -To use this extension, you have to configure the Connection class in your application configuration: - -```php -return [ - //.... - 'components' => [ - 'redis' => [ - 'class' => 'yii\redis\Connection', - 'hostname' => 'localhost', - 'port' => 6379, - 'database' => 0, - ], - ] -]; -``` - -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-redis "*" -``` - -or add - -```json -"yiisoft/yii2-redis": "*" -``` - -to the require section of your composer.json. - - -Using the Cache component -------------------------- - -To use the `Cache` component, in addtition to configuring the connection as described above, -you also have to configure the `cache` component to be `yii\redis\Cache`: - -```php -return [ - //.... - 'components' => [ - // ... - 'cache' => [ - 'class' => 'yii\redis\Cache', - ], - ] -]; -``` - -If you only use the redis cache, you can also configure the parameters of the connection within the -cache component (no connection application component needs to be configured in this case): - -```php -return [ - //.... - 'components' => [ - // ... - 'cache' => [ - 'class' => 'yii\redis\Cache', - 'redis' => [ - 'hostname' => 'localhost', - 'port' => 6379, - 'database' => 0, - ], - ], - ] -]; -``` - -Using the Session component ---------------------------- - -To use the `Session` component, in addtition to configuring the connection as described above, -you also have to configure the `session` component to be `yii\redis\Session`: - -```php -return [ - //.... - 'components' => [ - // ... - 'session' => [ - 'class' => 'yii\redis\Session', - ], - ] -]; -``` - -If you only use the redis session, you can also configure the parameters of the connection within the -cache component (no connection application component needs to be configured in this case): - -```php -return [ - //.... - 'components' => [ - // ... - 'session' => [ - 'class' => 'yii\redis\Session', - 'redis' => [ - 'hostname' => 'localhost', - 'port' => 6379, - 'database' => 0, - ], - ], - ] -]; -``` - - -Using the redis 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 a redis ActiveRecord class your record class needs to extend from `yii\redis\ActiveRecord` and -implement at least the `attributes()` method to define the attributes of the record. -A primary key can be defined via [[primaryKey()]] which defaults to `id` if not specified. -The primaryKey needs to be part of the attributes so make sure you have an `id` attribute defined if you do -not specify your own primary key. - -The following is an example model called `Customer`: - -```php -class Customer extends \yii\redis\ActiveRecord -{ - /** - * @return array the list of attributes for this record - */ - public function attributes() - { - return ['id', 'name', 'address', 'registration_date']; - } - - /** - * @return ActiveRelation defines a relation to the Order record (can be in other database, e.g. elasticsearch or sql) - */ - public function getOrders() - { - return $this->hasMany(Order::className(), ['customer_id' => '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)); - } -} -``` - -The general usage of redis 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: - -- As redis does not support SQL the query API is limited to the following methods: - `where()`, `limit()`, `offset()`, `orderBy()` and `indexBy()`. - (orderBy() is not yet implemented: [#1305](https://github.com/yiisoft/yii2/issues/1305)) -- `via`-relations can not be defined via a table as there are not tables in redis. You can only define relations via other records. - -It is also possible to define relations from redis ActiveRecords to normal ActiveRecord classes and vice versa. - -Usage example: - -```php -$customer = new Customer(); -$customer->attributes = ['name' => 'test']; -$customer->save(); -echo $customer->id; // id will automatically be incremented if not set explicitly - -$customer = Customer::find()->where(['name' => 'test'])->one(); // find by query -$customer = Customer::find()->active()->all(); // find all by query (using the `active` scope) -``` diff --git a/extensions/yii/redis/Session.php b/extensions/yii/redis/Session.php deleted file mode 100644 index 04e9074..0000000 --- a/extensions/yii/redis/Session.php +++ /dev/null @@ -1,153 +0,0 @@ - [ - * 'session' => [ - * 'class' => 'yii\redis\Session', - * 'redis' => [ - * 'hostname' => 'localhost', - * 'port' => 6379, - * 'database' => 0, - * ] - * ], - * ], - * ] - * ~~~ - * - * Or if you have configured the redis [[Connection]] as an application component, the following is sufficient: - * - * ~~~ - * [ - * 'components' => [ - * 'session' => [ - * 'class' => 'yii\redis\Session', - * // 'redis' => 'redis' // id of the connection application component - * ], - * ], - * ] - * ~~~ - * - * @property boolean $useCustomStorage Whether to use custom storage. This property is read-only. - * - * @author Carsten Brandt - * @since 2.0 - */ -class Session extends \yii\web\Session -{ - /** - * @var Connection|string|array the Redis [[Connection]] object or the application component ID of the Redis [[Connection]]. - * This can also be an array that is used to create a redis [[Connection]] instance in case you do not want do configure - * redis connection as an application component. - * After the Session object is created, if you want to change this property, you should only assign it - * with a Redis [[Connection]] object. - */ - public $redis = 'redis'; - /** - * @var string a string prefixed to every cache key so that it is unique. If not set, - * it will use a prefix generated from [[Application::id]]. You may set this property to be an empty string - * if you don't want to use key prefix. It is recommended that you explicitly set this property to some - * static value if the cached data needs to be shared among multiple applications. - */ - public $keyPrefix; - - - /** - * Initializes the redis Session component. - * This method will initialize the [[redis]] property to make sure it refers to a valid redis connection. - * @throws InvalidConfigException if [[redis]] is invalid. - */ - public function init() - { - if (is_string($this->redis)) { - $this->redis = Yii::$app->getComponent($this->redis); - } else if (is_array($this->redis)) { - if (!isset($this->redis['class'])) { - $this->redis['class'] = Connection::className(); - } - $this->redis = Yii::createObject($this->redis); - } - if (!$this->redis instanceof Connection) { - throw new InvalidConfigException("Session::redis must be either a Redis connection instance or the application component ID of a Redis connection."); - } - if ($this->keyPrefix === null) { - $this->keyPrefix = substr(md5(Yii::$app->id), 0, 5); - } - parent::init(); - } - - /** - * Returns a value indicating whether to use custom session storage. - * This method overrides the parent implementation and always returns true. - * @return boolean whether to use custom storage. - */ - public function getUseCustomStorage() - { - return true; - } - - /** - * Session read handler. - * Do not call this method directly. - * @param string $id session ID - * @return string the session data - */ - public function readSession($id) - { - $data = $this->redis->executeCommand('GET', [$this->calculateKey($id)]); - return $data === false ? '' : $data; - } - - /** - * Session write handler. - * Do not call this method directly. - * @param string $id session ID - * @param string $data session data - * @return boolean whether session write is successful - */ - public function writeSession($id, $data) - { - return (bool) $this->redis->executeCommand('SET', [$this->calculateKey($id), $data, 'EX', $this->getTimeout()]); - } - - /** - * Session destroy handler. - * Do not call this method directly. - * @param string $id session ID - * @return boolean whether session is destroyed successfully - */ - public function destroySession($id) - { - return (bool) $this->redis->executeCommand('DEL', [$this->calculateKey($id)]); - } - - /** - * Generates a unique key used for storing session data in cache. - * @param string $id session variable name - * @return string a safe cache key associated with the session variable name - */ - protected function calculateKey($id) - { - return $this->keyPrefix . md5(json_encode([__CLASS__, $id])); - } -} diff --git a/extensions/yii/redis/composer.json b/extensions/yii/redis/composer.json deleted file mode 100644 index 16807ae..0000000 --- a/extensions/yii/redis/composer.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "yiisoft/yii2-redis", - "description": "Redis Cache, Session and ActiveRecord for the Yii framework", - "keywords": ["yii", "redis", "active-record", "cache", "session"], - "type": "yii2-extension", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?labels=ext%3Aredis", - "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": "*" - }, - "autoload": { - "psr-0": { "yii\\redis\\": "" } - }, - "target-dir": "yii/redis" -} diff --git a/extensions/yii/smarty/CHANGELOG.md b/extensions/yii/smarty/CHANGELOG.md deleted file mode 100644 index 6037962..0000000 --- a/extensions/yii/smarty/CHANGELOG.md +++ /dev/null @@ -1,12 +0,0 @@ -Yii Framework 2 smarty extension Change Log -=========================================== - -2.0.0 beta under development ----------------------------- - -- no changes in this release. - -2.0.0 alpha, December 1, 2013 ------------------------------ - -- Initial release. diff --git a/extensions/yii/smarty/LICENSE.md b/extensions/yii/smarty/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/extensions/yii/smarty/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/smarty/README.md b/extensions/yii/smarty/README.md deleted file mode 100644 index 3aaf449..0000000 --- a/extensions/yii/smarty/README.md +++ /dev/null @@ -1,41 +0,0 @@ -Smarty Extension for Yii 2 -========================== - -This extension provides a `ViewRender` that would allow you to use Smarty view template engine. - -To use this extension, simply add the following code in your application configuration: - -```php -return [ - //.... - 'components' => [ - 'view' => [ - 'renderers' => [ - 'tpl' => [ - 'class' => 'yii\smarty\ViewRenderer', - //'cachePath' => '@runtime/Smarty/cache', - ], - ], - ], - ], -]; -``` - -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-smarty "*" -``` - -or add - -```json -"yiisoft/yii2-smarty": "*" -``` - -to the require section of your composer.json. diff --git a/extensions/yii/smarty/ViewRenderer.php b/extensions/yii/smarty/ViewRenderer.php deleted file mode 100644 index 2cfb216..0000000 --- a/extensions/yii/smarty/ViewRenderer.php +++ /dev/null @@ -1,98 +0,0 @@ - - * @since 2.0 - */ -class ViewRenderer extends BaseViewRenderer -{ - /** - * @var string the directory or path alias pointing to where Smarty cache will be stored. - */ - public $cachePath = '@runtime/Smarty/cache'; - - /** - * @var string the directory or path alias pointing to where Smarty compiled templates will be stored. - */ - public $compilePath = '@runtime/Smarty/compile'; - - /** - * @var Smarty - */ - public $smarty; - - public function init() - { - $this->smarty = new Smarty(); - $this->smarty->setCompileDir(Yii::getAlias($this->compilePath)); - $this->smarty->setCacheDir(Yii::getAlias($this->cachePath)); - - $this->smarty->registerPlugin('function', 'path', [$this, 'smarty_function_path']); - } - - /** - * Smarty template function to get a path for using in links - * - * Usage is the following: - * - * {path route='blog/view' alias=$post.alias user=$user.id} - * - * where route is Yii route and the rest of parameters are passed as is. - * - * @param $params - * @param \Smarty_Internal_Template $template - * - * @return string - */ - public function smarty_function_path($params, \Smarty_Internal_Template $template) - { - if (!isset($params['route'])) { - trigger_error("path: missing 'route' parameter"); - } - - array_unshift($params, $params['route']) ; - unset($params['route']); - - return Html::url($params); - } - - /** - * Renders a view file. - * - * This method is invoked by [[View]] whenever it tries to render a view. - * Child classes must implement this method to render the given view file. - * - * @param View $view the view object used for rendering the file. - * @param string $file the view file. - * @param array $params the parameters to be passed to the view file. - * - * @return string the rendering result - */ - public function render($view, $file, $params) - { - /** @var \Smarty_Internal_Template $template */ - $template = $this->smarty->createTemplate($file, null, null, $params, true); - - $template->assign('app', \Yii::$app); - $template->assign('this', $view); - - return $template->fetch(); - } -} diff --git a/extensions/yii/smarty/composer.json b/extensions/yii/smarty/composer.json deleted file mode 100644 index a3a8254..0000000 --- a/extensions/yii/smarty/composer.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "yiisoft/yii2-smarty", - "description": "The Smarty integration for the Yii framework", - "keywords": ["yii", "smarty", "renderer"], - "type": "yii2-extension", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?labels=ext%3Asmarty", - "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": "Alexander Makarov", - "email": "sam@rmcreative.ru" - } - ], - "require": { - "yiisoft/yii2": "*", - "smarty/smarty": "*" - }, - "autoload": { - "psr-0": { "yii\\smarty\\": "" } - }, - "target-dir": "yii/smarty" -} diff --git a/extensions/yii/sphinx/ActiveQuery.php b/extensions/yii/sphinx/ActiveQuery.php deleted file mode 100644 index 3533c35..0000000 --- a/extensions/yii/sphinx/ActiveQuery.php +++ /dev/null @@ -1,204 +0,0 @@ -with('source')->asArray()->all(); - * ~~~ - * - * ActiveQuery allows to build the snippets using sources provided by ActiveRecord. - * You can use [[snippetByModel()]] method to enable this. - * For example: - * - * ~~~ - * class Article extends ActiveRecord - * { - * public function getSource() - * { - * return $this->hasOne('db', ArticleDb::className(), ['id' => 'id']); - * } - * - * public function getSnippetSource() - * { - * return $this->source->content; - * } - * - * ... - * } - * - * $articles = Article::find()->with('source')->snippetByModel()->all(); - * ~~~ - * - * @author Paul Klimov - * @since 2.0 - */ -class ActiveQuery extends Query implements ActiveQueryInterface -{ - use ActiveQueryTrait; - - /** - * @var string the SQL statement to be executed for retrieving AR records. - * This is set by [[ActiveRecord::findBySql()]]. - */ - public $sql; - - /** - * Sets the [[snippetCallback]] to [[fetchSnippetSourceFromModels()]], which allows to - * fetch the snippet source strings from the Active Record models, using method - * [[ActiveRecord::getSnippetSource()]]. - * For example: - * - * ~~~ - * class Article extends ActiveRecord - * { - * public function getSnippetSource() - * { - * return file_get_contents('/path/to/source/files/' . $this->id . '.txt');; - * } - * } - * - * $articles = Article::find()->snippetByModel()->all(); - * ~~~ - * - * Warning: this option should NOT be used with [[asArray]] at the same time! - * @return static the query object itself - */ - public function snippetByModel() - { - $this->snippetCallback([$this, 'fetchSnippetSourceFromModels']); - return $this; - } - - /** - * 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) - { - $command = $this->createCommand($db); - $rows = $command->queryAll(); - if (!empty($rows)) { - $models = $this->createModels($rows); - if (!empty($this->with)) { - $this->findWith($this->with, $models); - } - $models = $this->fillUpSnippets($models); - return $models; - } else { - return []; - } - } - - /** - * 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) - { - $command = $this->createCommand($db); - $row = $command->queryOne(); - if ($row !== false) { - if ($this->asArray) { - $model = $row; - } else { - /** @var $class ActiveRecord */ - $class = $this->modelClass; - $model = $class::create($row); - } - if (!empty($this->with)) { - $models = [$model]; - $this->findWith($this->with, $models); - $model = $models[0]; - } - list ($model) = $this->fillUpSnippets([$model]); - return $model; - } else { - return null; - } - } - - /** - * 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 $modelClass ActiveRecord */ - $modelClass = $this->modelClass; - $this->setConnection($db); - $db = $this->getConnection(); - - $params = $this->params; - if ($this->sql === null) { - if ($this->from === null) { - $tableName = $modelClass::indexName(); - if ($this->select === null && !empty($this->join)) { - $this->select = ["$tableName.*"]; - } - $this->from = [$tableName]; - } - list ($this->sql, $params) = $db->getQueryBuilder()->build($this); - } - return $db->createCommand($this->sql, $params); - } - - /** - * @inheritdoc - */ - protected function defaultConnection() - { - $modelClass = $this->modelClass; - return $modelClass::getDb(); - } - - /** - * Fetches the source for the snippets using [[ActiveRecord::getSnippetSource()]] method. - * @param ActiveRecord[] $models raw query result rows. - * @throws \yii\base\InvalidCallException if [[asArray]] enabled. - * @return array snippet source strings - */ - protected function fetchSnippetSourceFromModels($models) - { - if ($this->asArray) { - throw new InvalidCallException('"' . __METHOD__ . '" unable to determine snippet source from plain array. Either disable "asArray" option or use regular "snippetCallback"'); - } - $result = []; - foreach ($models as $model) { - $result[] = $model->getSnippetSource(); - } - return $result; - } -} diff --git a/extensions/yii/sphinx/ActiveRecord.php b/extensions/yii/sphinx/ActiveRecord.php deleted file mode 100644 index 0a4f6d3..0000000 --- a/extensions/yii/sphinx/ActiveRecord.php +++ /dev/null @@ -1,659 +0,0 @@ - - * @since 2.0 - */ -abstract class ActiveRecord extends BaseActiveRecord -{ - /** - * The insert operation. This is mainly used when overriding [[transactions()]] to specify which operations are transactional. - */ - const OP_INSERT = 0x01; - /** - * The update operation. This is mainly used when overriding [[transactions()]] to specify which operations are transactional. - */ - const OP_UPDATE = 0x02; - /** - * The delete operation. This is mainly used when overriding [[transactions()]] to specify which operations are transactional. - */ - const OP_DELETE = 0x04; - /** - * All three operations: insert, update, delete. - * This is a shortcut of the expression: OP_INSERT | OP_UPDATE | OP_DELETE. - */ - const OP_ALL = 0x07; - - /** - * @var string current snippet value for this Active Record instance. - * It will be filled up automatically when instance found using [[Query::snippetCallback]] - * or [[ActiveQuery::snippetByModel()]]. - */ - private $_snippet; - - /** - * Returns the Sphinx connection used by this AR class. - * By default, the "sphinx" application component is used as the Sphinx connection. - * You may override this method if you want to use a different Sphinx connection. - * @return Connection the Sphinx connection used by this AR class. - */ - public static function getDb() - { - return \Yii::$app->getComponent('sphinx'); - } - - /** - * Creates an [[ActiveQuery]] instance with a given SQL statement. - * - * Note that because the SQL statement is already specified, calling additional - * query modification methods (such as `where()`, `order()`) on the created [[ActiveQuery]] - * instance will have no effect. However, calling `with()`, `asArray()` or `indexBy()` is - * still fine. - * - * Below is an example: - * - * ~~~ - * $customers = Article::findBySql("SELECT * FROM `idx_article` WHERE MATCH('development')")->all(); - * ~~~ - * - * @param string $sql the SQL statement to be executed - * @param array $params parameters to be bound to the SQL statement during execution. - * @return ActiveQuery the newly created [[ActiveQuery]] instance - */ - public static function findBySql($sql, $params = []) - { - $query = static::createQuery(); - $query->sql = $sql; - return $query->params($params); - } - - /** - * Updates the whole table using the provided attribute values and conditions. - * For example, to change the status to be 1 for all articles which status is 2: - * - * ~~~ - * Article::updateAll(['status' => 1], 'status = 2'); - * ~~~ - * - * @param array $attributes attribute values (name-value pairs) to be saved into the table - * @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. - * @param array $params the parameters (name => value) to be bound to the query. - * @return integer the number of rows updated - */ - public static function updateAll($attributes, $condition = '', $params = []) - { - $command = static::getDb()->createCommand(); - $command->update(static::indexName(), $attributes, $condition, $params); - return $command->execute(); - } - - /** - * Deletes rows in the index using the provided conditions. - * - * For example, to delete all articles whose status is 3: - * - * ~~~ - * Article::deleteAll('status = 3'); - * ~~~ - * - * @param string|array $condition the conditions that will be put in the WHERE part of the DELETE SQL. - * Please refer to [[Query::where()]] on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query. - * @return integer the number of rows deleted - */ - public static function deleteAll($condition = '', $params = []) - { - $command = static::getDb()->createCommand(); - $command->delete(static::indexName(), $condition, $params); - return $command->execute(); - } - - /** - * Creates an [[ActiveQuery]] instance. - * This method is called by [[find()]], [[findBySql()]] and [[count()]] to start a SELECT query. - * You may override this method to return a customized query (e.g. `ArticleQuery` specified - * written for querying `Article` purpose.) - * @return ActiveQuery the newly created [[ActiveQuery]] instance. - */ - public static function createQuery() - { - return new ActiveQuery(['modelClass' => get_called_class()]); - } - - /** - * Declares the name of the Sphinx index associated with this AR class. - * By default this method returns the class name as the index name by calling [[Inflector::camel2id()]]. - * For example, 'Article' becomes 'article', and 'StockItem' becomes - * 'stock_item'. You may override this method if the index is not named after this convention. - * @return string the index name - */ - public static function indexName() - { - return Inflector::camel2id(StringHelper::basename(get_called_class()), '_'); - } - - /** - * Returns the schema information of the Sphinx index associated with this AR class. - * @return IndexSchema the schema information of the Sphinx index associated with this AR class. - * @throws InvalidConfigException if the index for the AR class does not exist. - */ - public static function getIndexSchema() - { - $schema = static::getDb()->getIndexSchema(static::indexName()); - if ($schema !== null) { - return $schema; - } else { - throw new InvalidConfigException("The index does not exist: " . static::indexName()); - } - } - - /** - * Returns the primary key name for this AR class. - * The default implementation will return the primary key as declared - * in the Sphinx index, which is associated with this AR class. - * - * Note that an array should be returned even for a table with single primary key. - * - * @return string[] the primary keys of the associated Sphinx index. - */ - public static function primaryKey() - { - return [static::getIndexSchema()->primaryKey]; - } - - /** - * Builds a snippet from provided data and query, using specified index settings. - * @param string|array $source is the source data to extract a snippet from. - * It could be either a single string or array of strings. - * @param string $match the full-text query to build snippets for. - * @param array $options list of options in format: optionName => optionValue - * @return string|array built snippet in case "source" is a string, list of built snippets - * in case "source" is an array. - */ - public static function callSnippets($source, $match, $options = []) - { - $command = static::getDb()->createCommand(); - $command->callSnippets(static::indexName(), $source, $match, $options); - if (is_array($source)) { - return $command->queryColumn(); - } else { - return $command->queryScalar(); - } - } - - /** - * Returns tokenized and normalized forms of the keywords, and, optionally, keyword statistics. - * @param string $text the text to break down to keywords. - * @param boolean $fetchStatistic whether to return document and hit occurrence statistics - * @return array keywords and statistics - */ - public static function callKeywords($text, $fetchStatistic = false) - { - $command = static::getDb()->createCommand(); - $command->callKeywords(static::indexName(), $text, $fetchStatistic); - return $command->queryAll(); - } - - /** - * @param string $snippet - */ - public function setSnippet($snippet) - { - $this->_snippet = $snippet; - } - - /** - * Returns current snippet value or generates new one from given match. - * @param string $match snippet source query - * @param array $options list of options in format: optionName => optionValue - * @return string snippet value - */ - public function getSnippet($match = null, $options = []) - { - if ($match !== null) { - $this->_snippet = $this->fetchSnippet($match, $options); - } - return $this->_snippet; - } - - /** - * Builds up the snippet value from the given query. - * @param string $match the full-text query to build snippets for. - * @param array $options list of options in format: optionName => optionValue - * @return string snippet value. - */ - protected function fetchSnippet($match, $options = []) - { - return static::callSnippets($this->getSnippetSource(), $match, $options); - } - - /** - * Returns the string, which should be used as a source to create snippet for this - * Active Record instance. - * Child classes must implement this method to return the actual snippet source text. - * For example: - * ~~~ - * public function getSnippetSource() - * { - * return $this->snippetSourceRelation->content; - * } - * ~~~ - * @return string snippet source string. - * @throws \yii\base\NotSupportedException if this is not supported by the Active Record class - */ - public function getSnippetSource() - { - throw new NotSupportedException($this->className() . ' does not provide snippet source.'); - } - - /** - * Declares which operations should be performed within a transaction in different scenarios. - * The supported DB operations are: [[OP_INSERT]], [[OP_UPDATE]] and [[OP_DELETE]], - * which correspond to the [[insert()]], [[update()]] and [[delete()]] methods, respectively. - * By default, these methods are NOT enclosed in a transaction. - * - * In some scenarios, to ensure data consistency, you may want to enclose some or all of them - * in transactions. You can do so by overriding this method and returning the operations - * that need to be transactional. For example, - * - * ~~~ - * return [ - * 'admin' => self::OP_INSERT, - * 'api' => self::OP_INSERT | self::OP_UPDATE | self::OP_DELETE, - * // the above is equivalent to the following: - * // 'api' => self::OP_ALL, - * - * ]; - * ~~~ - * - * The above declaration specifies that in the "admin" scenario, the insert operation ([[insert()]]) - * should be done in a transaction; and in the "api" scenario, all the operations should be done - * in a transaction. - * - * @return array the declarations of transactional operations. The array keys are scenarios names, - * and the array values are the corresponding transaction operations. - */ - public function transactions() - { - return []; - } - - /** - * Creates an [[ActiveRelationInterface]] instance. - * This method is called by [[hasOne()]] and [[hasMany()]] to create a relation instance. - * You may override this method to return a customized relation. - * @param array $config the configuration passed to the ActiveRelation class. - * @return ActiveRelationInterface the newly created [[ActiveRelation]] instance. - */ - public static function createActiveRelation($config = []) - { - return new ActiveRelation($config); - } - - /** - * Returns the list of all attribute names of the model. - * The default implementation will return all column names of the table associated with this AR class. - * @return array list of attribute names. - */ - public function attributes() - { - return array_keys(static::getIndexSchema()->columns); - } - - /** - * Inserts a row into the associated Sphinx 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 index. 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 [[changedAttributes|changed attribute values]] will be inserted. - * - * For example, to insert an article record: - * - * ~~~ - * $article = new Article; - * $article->id = $id; - * $article->genre_id = $genreId; - * $article->content = $content; - * $article->insert(); - * ~~~ - * - * @param boolean $runValidation whether to perform validation before saving the record. - * If the validation fails, the record will not be inserted. - * @param array $attributes list of attributes that need to be saved. Defaults to null, - * meaning all attributes that are loaded from index will be saved. - * @return boolean whether the attributes are valid and the record is inserted successfully. - * @throws \Exception in case insert failed. - */ - public function insert($runValidation = true, $attributes = null) - { - if ($runValidation && !$this->validate($attributes)) { - return false; - } - $db = static::getDb(); - if ($this->isTransactional(self::OP_INSERT) && $db->getTransaction() === null) { - $transaction = $db->beginTransaction(); - try { - $result = $this->insertInternal($attributes); - if ($result === false) { - $transaction->rollback(); - } else { - $transaction->commit(); - } - } catch (\Exception $e) { - $transaction->rollback(); - throw $e; - } - } else { - $result = $this->insertInternal($attributes); - } - return $result; - } - - /** - * @see ActiveRecord::insert() - */ - private function insertInternal($attributes = null) - { - if (!$this->beforeSave(true)) { - return false; - } - $values = $this->getDirtyAttributes($attributes); - if (empty($values)) { - foreach ($this->getPrimaryKey(true) as $key => $value) { - $values[$key] = $value; - } - } - $db = static::getDb(); - $command = $db->createCommand()->insert($this->indexName(), $values); - if (!$command->execute()) { - return false; - } - foreach ($values as $name => $value) { - $this->setOldAttribute($name, $value); - } - $this->afterSave(true); - return true; - } - - /** - * Saves the changes to this active record into the associated Sphinx index. - * - * 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. save the record into index. 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_UPDATE]], [[EVENT_AFTER_UPDATE]] and [[EVENT_AFTER_VALIDATE]] - * will be raised by the corresponding methods. - * - * Only the [[changedAttributes|changed attribute values]] will be saved into database. - * - * For example, to update an article record: - * - * ~~~ - * $article = Article::find(['id' => $id]); - * $article->genre_id = $genreId; - * $article->group_id = $groupId; - * $article->update(); - * ~~~ - * - * Note that it is possible the update does not affect any row in the table. - * In this case, this method will return 0. For this reason, you should use the following - * code to check if update() is successful or not: - * - * ~~~ - * if ($this->update() !== false) { - * // update successful - * } else { - * // update failed - * } - * ~~~ - * - * @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 that are loaded from DB will be saved. - * @return integer|boolean the number of rows affected, or false if validation fails - * or [[beforeSave()]] stops the updating process. - * @throws StaleObjectException if [[optimisticLock|optimistic locking]] is enabled and the data - * being updated is outdated. - * @throws \Exception in case update failed. - */ - public function update($runValidation = true, $attributes = null) - { - if ($runValidation && !$this->validate($attributes)) { - return false; - } - $db = static::getDb(); - if ($this->isTransactional(self::OP_UPDATE) && $db->getTransaction() === null) { - $transaction = $db->beginTransaction(); - try { - $result = $this->updateInternal($attributes); - if ($result === false) { - $transaction->rollback(); - } else { - $transaction->commit(); - } - } catch (\Exception $e) { - $transaction->rollback(); - throw $e; - } - } else { - $result = $this->updateInternal($attributes); - } - return $result; - } - - /** - * @see CActiveRecord::update() - * @throws StaleObjectException - */ - protected function updateInternal($attributes = null) - { - if (!$this->beforeSave(false)) { - return false; - } - $values = $this->getDirtyAttributes($attributes); - if (empty($values)) { - $this->afterSave(false); - return 0; - } - - // Replace is supported only by runtime indexes and necessary only for field update - $useReplace = false; - $indexSchema = $this->getIndexSchema(); - if ($this->getIndexSchema()->isRuntime) { - foreach ($values as $name => $value) { - $columnSchema = $indexSchema->getColumn($name); - if ($columnSchema->isField) { - $useReplace = true; - break; - } - } - } - - if ($useReplace) { - $values = array_merge($values, $this->getOldPrimaryKey(true)); - $command = static::getDb()->createCommand(); - $command->replace(static::indexName(), $values); - // We do not check the return value of replace because it's possible - // that the REPLACE statement doesn't change anything and thus returns 0. - $rows = $command->execute(); - } else { - $condition = $this->getOldPrimaryKey(true); - $lock = $this->optimisticLock(); - if ($lock !== null) { - if (!isset($values[$lock])) { - $values[$lock] = $this->$lock + 1; - } - $condition[$lock] = $this->$lock; - } - // We do not check the return value of updateAll() because it's possible - // that the UPDATE statement doesn't change anything and thus returns 0. - $rows = $this->updateAll($values, $condition); - - if ($lock !== null && !$rows) { - throw new StaleObjectException('The object being updated is outdated.'); - } - } - - foreach ($values as $name => $value) { - $this->setOldAttribute($name, $this->getAttribute($name)); - } - $this->afterSave(false); - return $rows; - } - - /** - * Deletes the index entry corresponding to this active record. - * - * This method performs the following steps in order: - * - * 1. call [[beforeDelete()]]. If the method returns false, it will skip the - * rest of the steps; - * 2. delete the record from the index; - * 3. call [[afterDelete()]]. - * - * In the above step 1 and 3, events named [[EVENT_BEFORE_DELETE]] and [[EVENT_AFTER_DELETE]] - * will be raised by the corresponding methods. - * - * @return integer|boolean the number of rows deleted, or false if the deletion is unsuccessful for some reason. - * Note that it is possible the number of rows deleted is 0, even though the deletion execution is successful. - * @throws StaleObjectException if [[optimisticLock|optimistic locking]] is enabled and the data - * being deleted is outdated. - * @throws \Exception in case delete failed. - */ - public function delete() - { - $db = static::getDb(); - $transaction = $this->isTransactional(self::OP_DELETE) && $db->getTransaction() === null ? $db->beginTransaction() : null; - try { - $result = false; - if ($this->beforeDelete()) { - // we do not check the return value of deleteAll() because it's possible - // the record is already deleted in the database and thus the method will return 0 - $condition = $this->getOldPrimaryKey(true); - $lock = $this->optimisticLock(); - if ($lock !== null) { - $condition[$lock] = $this->$lock; - } - $result = $this->deleteAll($condition); - if ($lock !== null && !$result) { - throw new StaleObjectException('The object being deleted is outdated.'); - } - $this->setOldAttributes(null); - $this->afterDelete(); - } - if ($transaction !== null) { - if ($result === false) { - $transaction->rollback(); - } else { - $transaction->commit(); - } - } - } catch (\Exception $e) { - if ($transaction !== null) { - $transaction->rollback(); - } - throw $e; - } - return $result; - } - - /** - * Returns a value indicating whether the given active record is the same as the current one. - * The comparison is made by comparing the index names and the primary key values of the two active records. - * If one of the records [[isNewRecord|is new]] they are also considered not equal. - * @param ActiveRecord $record record to compare to - * @return boolean whether the two active records refer to the same row in the same index. - */ - public function equals($record) - { - if ($this->isNewRecord || $record->isNewRecord) { - return false; - } - return $this->indexName() === $record->indexName() && $this->getPrimaryKey() === $record->getPrimaryKey(); - } - - /** - * 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 = static::instantiate($row); - $columns = static::getIndexSchema()->columns; - foreach ($row as $name => $value) { - if (isset($columns[$name])) { - $column = $columns[$name]; - if ($column->isMva) { - $value = explode(',', $value); - } - $record->setAttribute($name, $value); - } else { - $record->$name = $value; - } - } - $record->setOldAttributes($record->getAttributes()); - $record->afterFind(); - return $record; - } - - /** - * Returns a value indicating whether the specified operation is transactional in the current [[scenario]]. - * @param integer $operation the operation to check. Possible values are [[OP_INSERT]], [[OP_UPDATE]] and [[OP_DELETE]]. - * @return boolean whether the specified operation is transactional in the current [[scenario]]. - */ - public function isTransactional($operation) - { - $scenario = $this->getScenario(); - $transactions = $this->transactions(); - return isset($transactions[$scenario]) && ($transactions[$scenario] & $operation); - } -} diff --git a/extensions/yii/sphinx/ActiveRelation.php b/extensions/yii/sphinx/ActiveRelation.php deleted file mode 100644 index 71939e0..0000000 --- a/extensions/yii/sphinx/ActiveRelation.php +++ /dev/null @@ -1,53 +0,0 @@ - - * @since 2.0 - */ -class ActiveRelation extends ActiveQuery implements ActiveRelationInterface -{ - use ActiveRelationTrait; - - /** - * @inheritdoc - */ - public function createCommand($db = null) - { - if ($this->primaryModel !== null) { - // lazy loading - if ($this->via instanceof self) { - // via pivot index - $viaModels = $this->via->findPivotRows([$this->primaryModel]); - $this->filterByModels($viaModels); - } elseif (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); - } -} \ No newline at end of file diff --git a/extensions/yii/sphinx/CHANGELOG.md b/extensions/yii/sphinx/CHANGELOG.md deleted file mode 100644 index 58509de..0000000 --- a/extensions/yii/sphinx/CHANGELOG.md +++ /dev/null @@ -1,12 +0,0 @@ -Yii Framework 2 sphinx extension Change Log -=========================================== - -2.0.0 beta under development ----------------------------- - -- Enh #1398: Refactor ActiveRecord to use BaseActiveRecord class of the framework (klimov-paul) - -2.0.0 alpha, December 1, 2013 ------------------------------ - -- Initial release. diff --git a/extensions/yii/sphinx/ColumnSchema.php b/extensions/yii/sphinx/ColumnSchema.php deleted file mode 100644 index 5edca85..0000000 --- a/extensions/yii/sphinx/ColumnSchema.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @since 2.0 - */ -class ColumnSchema extends Object -{ - /** - * @var string name of this column (without quotes). - */ - public $name; - /** - * @var string abstract type of this column. Possible abstract types include: - * string, text, boolean, smallint, integer, bigint, float, decimal, datetime, - * timestamp, time, date, binary, and money. - */ - public $type; - /** - * @var string the PHP type of this column. Possible PHP types include: - * string, boolean, integer, double. - */ - public $phpType; - /** - * @var string the DB type of this column. Possible DB types vary according to the type of DBMS. - */ - public $dbType; - /** - * @var boolean whether this column is a primary key - */ - public $isPrimaryKey; - /** - * @var boolean whether this column is an attribute - */ - public $isAttribute; - /** - * @var boolean whether this column is a indexed field - */ - public $isField; - /** - * @var boolean whether this column is a multi value attribute (MVA) - */ - public $isMva; - - /** - * Converts the input value according to [[phpType]]. - * If the value is null or an [[Expression]], it will not be converted. - * @param mixed $value input value - * @return mixed converted value - */ - public function typecast($value) - { - if ($value === null || gettype($value) === $this->phpType || $value instanceof Expression) { - return $value; - } - if ($value === '' && $this->type !== Schema::TYPE_STRING) { - return null; - } - switch ($this->phpType) { - case 'string': - return (string)$value; - case 'integer': - return (integer)$value; - case 'boolean': - return (boolean)$value; - } - return $value; - } -} \ No newline at end of file diff --git a/extensions/yii/sphinx/Command.php b/extensions/yii/sphinx/Command.php deleted file mode 100644 index 9197b67..0000000 --- a/extensions/yii/sphinx/Command.php +++ /dev/null @@ -1,326 +0,0 @@ -createCommand("SELECT * FROM `idx_article` WHERE MATCH('programming')")->queryAll(); - * ~~~ - * - * Command supports SQL statement preparation and parameter binding just as [[\yii\db\Command]] does. - * - * Command also supports building SQL statements by providing methods such as [[insert()]], - * [[update()]], etc. For example, - * - * ~~~ - * $connection->createCommand()->update('idx_article', [ - * 'genre_id' => 15, - * 'author_id' => 157, - * ])->execute(); - * ~~~ - * - * To build SELECT SQL statements, please use [[Query]] and [[QueryBuilder]] instead. - * - * @author Paul Klimov - * @since 2.0 - */ -class Command extends \yii\db\Command -{ - /** - * @var \yii\sphinx\Connection the Sphinx connection that this command is associated with. - */ - public $db; - - /** - * Creates a batch INSERT command. - * For example, - * - * ~~~ - * $connection->createCommand()->batchInsert('idx_user', ['name', 'age'], [ - * ['Tom', 30], - * ['Jane', 20], - * ['Linda', 25], - * ])->execute(); - * ~~~ - * - * Note that the values in each row must match the corresponding column names. - * - * @param string $index the index that new rows will be inserted into. - * @param array $columns the column names - * @param array $rows the rows to be batch inserted into the index - * @return static the command object itself - */ - public function batchInsert($index, $columns, $rows) - { - $params = []; - $sql = $this->db->getQueryBuilder()->batchInsert($index, $columns, $rows, $params); - return $this->setSql($sql)->bindValues($params); - } - - /** - * Creates an REPLACE command. - * For example, - * - * ~~~ - * $connection->createCommand()->insert('idx_user', [ - * 'name' => 'Sam', - * 'age' => 30, - * ])->execute(); - * ~~~ - * - * The method will properly escape the column names, and bind the values to be replaced. - * - * Note that the created command is not executed until [[execute()]] is called. - * - * @param string $index the index that new rows will be replaced into. - * @param array $columns the column data (name => value) to be replaced into the index. - * @return static the command object itself - */ - public function replace($index, $columns) - { - $params = []; - $sql = $this->db->getQueryBuilder()->replace($index, $columns, $params); - return $this->setSql($sql)->bindValues($params); - } - - /** - * Creates a batch REPLACE command. - * For example, - * - * ~~~ - * $connection->createCommand()->batchInsert('idx_user', ['name', 'age'], [ - * ['Tom', 30], - * ['Jane', 20], - * ['Linda', 25], - * ])->execute(); - * ~~~ - * - * Note that the values in each row must match the corresponding column names. - * - * @param string $index the index that new rows will be replaced. - * @param array $columns the column names - * @param array $rows the rows to be batch replaced in the index - * @return static the command object itself - */ - public function batchReplace($index, $columns, $rows) - { - $params = []; - $sql = $this->db->getQueryBuilder()->batchReplace($index, $columns, $rows, $params); - return $this->setSql($sql)->bindValues($params); - } - - /** - * Creates an UPDATE command. - * For example, - * - * ~~~ - * $connection->createCommand()->update('tbl_user', ['status' => 1], 'age > 30')->execute(); - * ~~~ - * - * The method will properly escape the column names and bind the values to be updated. - * - * Note that the created command is not executed until [[execute()]] is called. - * - * @param string $index the index to be updated. - * @param array $columns the column data (name => value) to be updated. - * @param string|array $condition the condition that will be put in the WHERE part. Please - * refer to [[Query::where()]] on how to specify condition. - * @param array $params the parameters to be bound to the command - * @param array $options list of options in format: optionName => optionValue - * @return static the command object itself - */ - public function update($index, $columns, $condition = '', $params = [], $options = []) - { - $sql = $this->db->getQueryBuilder()->update($index, $columns, $condition, $params, $options); - return $this->setSql($sql)->bindValues($params); - } - - /** - * Creates a SQL command for truncating a runtime index. - * @param string $index the index to be truncated. The name will be properly quoted by the method. - * @return static the command object itself - */ - public function truncateIndex($index) - { - $sql = $this->db->getQueryBuilder()->truncateIndex($index); - return $this->setSql($sql); - } - - /** - * Builds a snippet from provided data and query, using specified index settings. - * @param string $index name of the index, from which to take the text processing settings. - * @param string|array $source is the source data to extract a snippet from. - * It could be either a single string or array of strings. - * @param string $match the full-text query to build snippets for. - * @param array $options list of options in format: optionName => optionValue - * @return static the command object itself - */ - public function callSnippets($index, $source, $match, $options = []) - { - $params = []; - $sql = $this->db->getQueryBuilder()->callSnippets($index, $source, $match, $options, $params); - return $this->setSql($sql)->bindValues($params); - } - - /** - * Returns tokenized and normalized forms of the keywords, and, optionally, keyword statistics. - * @param string $index the name of the index from which to take the text processing settings - * @param string $text the text to break down to keywords. - * @param boolean $fetchStatistic whether to return document and hit occurrence statistics - * @return string the SQL statement for call keywords. - */ - public function callKeywords($index, $text, $fetchStatistic = false) - { - $params = []; - $sql = $this->db->getQueryBuilder()->callKeywords($index, $text, $fetchStatistic, $params); - return $this->setSql($sql)->bindValues($params); - } - - // Not Supported : - - /** - * @inheritdoc - */ - public function createTable($table, $columns, $options = null) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function renameTable($table, $newName) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function dropTable($table) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function truncateTable($table) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function addColumn($table, $column, $type) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function dropColumn($table, $column) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function renameColumn($table, $oldName, $newName) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function alterColumn($table, $column, $type) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function addPrimaryKey($name, $table, $columns) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function dropPrimaryKey($name, $table) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete = null, $update = null) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function dropForeignKey($name, $table) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function createIndex($name, $table, $columns, $unique = false) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function dropIndex($name, $table) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function resetSequence($table, $value = null) - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } - - /** - * @inheritdoc - */ - public function checkIntegrity($check = true, $schema = '', $table = '') - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } -} diff --git a/extensions/yii/sphinx/Connection.php b/extensions/yii/sphinx/Connection.php deleted file mode 100644 index b732d97..0000000 --- a/extensions/yii/sphinx/Connection.php +++ /dev/null @@ -1,129 +0,0 @@ - 'mysql:host=127.0.0.1;port=9306;', - * 'username' => $username, - * 'password' => $password, - * ]); - * $connection->open(); - * ~~~ - * - * After the Sphinx connection is established, one can execute SQL statements like the following: - * ~~~ - * $command = $connection->createCommand("SELECT * FROM idx_article WHERE MATCH('programming')"); - * $articles = $command->queryAll(); - * $command = $connection->createCommand('UPDATE idx_article SET status=2 WHERE id=1'); - * $command->execute(); - * ~~~ - * - * For more information about how to perform various DB queries, please refer to [[Command]]. - * - * This class supports transactions exactly as "yii\db\Connection". - * - * Note: while this class extends "yii\db\Connection" some of its methods are not supported. - * - * @method \yii\sphinx\Schema getSchema() The schema information for this Sphinx connection - * @method \yii\sphinx\QueryBuilder getQueryBuilder() the query builder for this Sphinx connection - * - * @property string $lastInsertID The row ID of the last row inserted, or the last value retrieved from the - * sequence object. This property is read-only. - * - * @author Paul Klimov - * @since 2.0 - */ -class Connection extends \yii\db\Connection -{ - /** - * @inheritdoc - */ - public $schemaMap = [ - 'mysqli' => 'yii\sphinx\Schema', // MySQL - 'mysql' => 'yii\sphinx\Schema', // MySQL - ]; - - /** - * Obtains the schema information for the named index. - * @param string $name index name. - * @param boolean $refresh whether to reload the table schema even if it is found in the cache. - * @return IndexSchema index schema information. Null if the named index does not exist. - */ - public function getIndexSchema($name, $refresh = false) - { - return $this->getSchema()->getIndexSchema($name, $refresh); - } - - /** - * Quotes a index name for use in a query. - * If the index name contains schema prefix, the prefix will also be properly quoted. - * If the index name is already quoted or contains special characters including '(', '[[' and '{{', - * then this method will do nothing. - * @param string $name index name - * @return string the properly quoted index name - */ - public function quoteIndexName($name) - { - return $this->getSchema()->quoteIndexName($name); - } - - /** - * Alias of [[quoteIndexName()]]. - * @param string $name table name - * @return string the properly quoted table name - */ - public function quoteTableName($name) - { - return $this->quoteIndexName($name); - } - - /** - * Creates a command for execution. - * @param string $sql the SQL statement to be executed - * @param array $params the parameters to be bound to the SQL statement - * @return Command the Sphinx command - */ - public function createCommand($sql = null, $params = []) - { - $this->open(); - $command = new Command([ - 'db' => $this, - 'sql' => $sql, - ]); - return $command->bindValues($params); - } - - /** - * This method is not supported by Sphinx. - * @param string $sequenceName name of the sequence object - * @return string the row ID of the last row inserted, or the last value retrieved from the sequence object - * @throws \yii\base\NotSupportedException always. - */ - public function getLastInsertID($sequenceName = '') - { - throw new NotSupportedException('"' . __METHOD__ . '" is not supported.'); - } -} diff --git a/extensions/yii/sphinx/IndexSchema.php b/extensions/yii/sphinx/IndexSchema.php deleted file mode 100644 index 2908e82..0000000 --- a/extensions/yii/sphinx/IndexSchema.php +++ /dev/null @@ -1,63 +0,0 @@ - - * @since 2.0 - */ -class IndexSchema extends Object -{ - /** - * @var string name of this index. - */ - public $name; - /** - * @var string type of the index. - */ - public $type; - /** - * @var boolean whether this index is a runtime index. - */ - public $isRuntime; - /** - * @var string primary key of this index. - */ - public $primaryKey; - /** - * @var ColumnSchema[] column metadata of this index. Each array element is a [[ColumnSchema]] object, indexed by column names. - */ - public $columns = []; - - /** - * Gets the named column metadata. - * This is a convenient method for retrieving a named column even if it does not exist. - * @param string $name column name - * @return ColumnSchema metadata of the named column. Null if the named column does not exist. - */ - public function getColumn($name) - { - return isset($this->columns[$name]) ? $this->columns[$name] : null; - } - - /** - * Returns the names of all columns in this table. - * @return array list of column names - */ - public function getColumnNames() - { - return array_keys($this->columns); - } -} \ No newline at end of file diff --git a/extensions/yii/sphinx/LICENSE.md b/extensions/yii/sphinx/LICENSE.md deleted file mode 100644 index 0bb1a8d..0000000 --- a/extensions/yii/sphinx/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/sphinx/Query.php b/extensions/yii/sphinx/Query.php deleted file mode 100644 index 2a51996..0000000 --- a/extensions/yii/sphinx/Query.php +++ /dev/null @@ -1,705 +0,0 @@ -select('id, groupd_id') - * ->from('idx_item') - * ->limit(10); - * // build and execute the query - * $command = $query->createCommand(); - * // $command->sql returns the actual SQL - * $rows = $command->queryAll(); - * ~~~ - * - * Since Sphinx does not store the original indexed text, the snippets for the rows in query result - * should be build separately via another query. You can simplify this workflow using [[snippetCallback]]. - * - * Warning: even if you do not set any query limit, implicit LIMIT 0,20 is present by default! - * - * @property Connection $connection Sphinx connection instance. - * - * @author Paul Klimov - * @since 2.0 - */ -class Query extends Component implements QueryInterface -{ - use QueryTrait; - - /** - * @var array the columns being selected. For example, `['id', 'group_id']`. - * This is used to construct the SELECT clause in a SQL statement. If not set, if means selecting all columns. - * @see select() - */ - public $select; - /** - * @var string additional option that should be appended to the 'SELECT' keyword. - */ - public $selectOption; - /** - * @var boolean whether to select distinct rows of data only. If this is set true, - * the SELECT clause would be changed to SELECT DISTINCT. - */ - public $distinct; - /** - * @var array the index(es) to be selected from. For example, `['idx_user', 'idx_user_delta']`. - * This is used to construct the FROM clause in a SQL statement. - * @see from() - */ - public $from; - /** - * @var string text, which should be searched in fulltext mode. - * This value will be composed into MATCH operator inside the WHERE clause. - */ - public $match; - /** - * @var array how to group the query results. For example, `['company', 'department']`. - * This is used to construct the GROUP BY clause in a SQL statement. - */ - public $groupBy; - /** - * @var string WITHIN GROUP ORDER BY clause. This is a Sphinx specific extension - * that lets you control how the best row within a group will to be selected. - * The possible value matches the [[orderBy]] one. - */ - public $within; - /** - * @var array per-query options in format: optionName => optionValue - * They will compose OPTION clause. This is a Sphinx specific extension - * that lets you control a number of per-query options. - */ - public $options; - /** - * @var array list of query parameter values indexed by parameter placeholders. - * For example, `[':name' => 'Dan', ':age' => 31]`. - */ - public $params; - /** - * @var callback PHP callback, which should be used to fetch source data for the snippets. - * Such callback will receive array of query result rows as an argument and must return the - * array of snippet source strings in the order, which match one of incoming rows. - * For example: - * ~~~ - * $query = new Query; - * $query->from('idx_item') - * ->match('pencil') - * ->snippetCallback(function ($rows) { - * $result = []; - * foreach ($rows as $row) { - * $result[] = file_get_contents('/path/to/index/files/' . $row['id'] . '.txt'); - * } - * return $result; - * }) - * ->all(); - * ~~~ - */ - public $snippetCallback; - /** - * @var array query options for the call snippet. - */ - public $snippetOptions; - /** - * @var Connection the Sphinx connection used to generate the SQL statements. - */ - private $_connection; - - /** - * @param Connection $connection Sphinx connection instance - * @return static the query object itself - */ - public function setConnection($connection) - { - $this->_connection = $connection; - return $this; - } - - /** - * @return Connection Sphinx connection instance - */ - public function getConnection() - { - if ($this->_connection === null) { - $this->_connection = $this->defaultConnection(); - } - return $this->_connection; - } - - /** - * @return Connection default connection value. - */ - protected function defaultConnection() - { - return Yii::$app->getComponent('sphinx'); - } - - /** - * Creates a Sphinx command that can be used to execute this query. - * @param Connection $connection the Sphinx connection used to generate the SQL statement. - * If this parameter is not given, the `sphinx` application component will be used. - * @return Command the created Sphinx command instance. - */ - public function createCommand($connection = null) - { - $this->setConnection($connection); - $connection = $this->getConnection(); - list ($sql, $params) = $connection->getQueryBuilder()->build($this); - return $connection->createCommand($sql, $params); - } - - /** - * Executes the query and returns all results as an array. - * @param Connection $db the Sphinx connection used to generate the SQL statement. - * If this parameter is not given, the `sphinx` 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) - { - $rows = $this->createCommand($db)->queryAll(); - $rows = $this->fillUpSnippets($rows); - if ($this->indexBy === null) { - return $rows; - } - $result = []; - foreach ($rows as $row) { - if (is_string($this->indexBy)) { - $key = $row[$this->indexBy]; - } else { - $key = call_user_func($this->indexBy, $row); - } - $result[$key] = $row; - } - return $result; - } - - /** - * Executes the query and returns a single row of result. - * @param Connection $db the Sphinx connection used to generate the SQL statement. - * If this parameter is not given, the `sphinx` 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) - { - $row = $this->createCommand($db)->queryOne(); - if ($row !== false) { - list ($row) = $this->fillUpSnippets([$row]); - } - return $row; - } - - /** - * Returns the query result as a scalar value. - * The value returned will be the first column in the first row of the query results. - * @param Connection $db the Sphinx connection used to generate the SQL statement. - * If this parameter is not given, the `sphinx` application component will be used. - * @return string|boolean the value of the first column in the first row of the query result. - * False is returned if the query result is empty. - */ - public function scalar($db = null) - { - return $this->createCommand($db)->queryScalar(); - } - - /** - * Executes the query and returns the first column of the result. - * @param Connection $db the Sphinx connection used to generate the SQL statement. - * If this parameter is not given, the `sphinx` 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($db = null) - { - return $this->createCommand($db)->queryColumn(); - } - - /** - * Returns the number of records. - * @param string $q the COUNT expression. Defaults to '*'. - * Make sure you properly quote column names in the expression. - * @param Connection $db the Sphinx connection used to generate the SQL statement. - * If this parameter is not given, the `sphinx` application component will be used. - * @return integer number of records - */ - public function count($q = '*', $db = null) - { - $this->select = ["COUNT($q)"]; - return $this->createCommand($db)->queryScalar(); - } - - /** - * Returns the sum of the specified column values. - * @param string $q the column name or expression. - * Make sure you properly quote column names in the expression. - * @param Connection $db the Sphinx connection used to generate the SQL statement. - * If this parameter is not given, the `sphinx` application component will be used. - * @return integer the sum of the specified column values - */ - public function sum($q, $db = null) - { - $this->select = ["SUM($q)"]; - return $this->createCommand($db)->queryScalar(); - } - - /** - * Returns the average of the specified column values. - * @param string $q the column name or expression. - * Make sure you properly quote column names in the expression. - * @param Connection $db the Sphinx connection used to generate the SQL statement. - * If this parameter is not given, the `sphinx` application component will be used. - * @return integer the average of the specified column values. - */ - public function average($q, $db = null) - { - $this->select = ["AVG($q)"]; - return $this->createCommand($db)->queryScalar(); - } - - /** - * Returns the minimum of the specified column values. - * @param string $q the column name or expression. - * Make sure you properly quote column names in the expression. - * @param Connection $db the Sphinx connection used to generate the SQL statement. - * If this parameter is not given, the `sphinx` application component will be used. - * @return integer the minimum of the specified column values. - */ - public function min($q, $db = null) - { - $this->select = ["MIN($q)"]; - return $this->createCommand($db)->queryScalar(); - } - - /** - * Returns the maximum of the specified column values. - * @param string $q the column name or expression. - * Make sure you properly quote column names in the expression. - * @param Connection $db the Sphinx connection used to generate the SQL statement. - * If this parameter is not given, the `sphinx` application component will be used. - * @return integer the maximum of the specified column values. - */ - public function max($q, $db = null) - { - $this->select = ["MAX($q)"]; - return $this->createCommand($db)->queryScalar(); - } - - /** - * Returns a value indicating whether the query result contains any row of data. - * @param Connection $db the Sphinx connection used to generate the SQL statement. - * If this parameter is not given, the `sphinx` application component will be used. - * @return boolean whether the query result contains any row of data. - */ - public function exists($db = null) - { - $this->select = [new Expression('1')]; - return $this->scalar($db) !== false; - } - - /** - * Sets the SELECT part of the query. - * @param string|array $columns the columns to be selected. - * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. ['id', 'name']). - * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a Sphinx expression). - * @param string $option additional option that should be appended to the 'SELECT' keyword. - * @return static the query object itself - */ - public function select($columns, $option = null) - { - if (!is_array($columns)) { - $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); - } - $this->select = $columns; - $this->selectOption = $option; - return $this; - } - - /** - * Sets the value indicating whether to SELECT DISTINCT or not. - * @param bool $value whether to SELECT DISTINCT or not. - * @return static the query object itself - */ - public function distinct($value = true) - { - $this->distinct = $value; - return $this; - } - - /** - * Sets the FROM part of the query. - * @param string|array $tables the table(s) to be selected from. This can be either a string (e.g. `'idx_user'`) - * or an array (e.g. `['idx_user', 'idx_user_delta']`) specifying one or several index names. - * The method will automatically quote the table names unless it contains some parenthesis - * (which means the table is given as a sub-query or Sphinx expression). - * @return static the query object itself - */ - public function from($tables) - { - if (!is_array($tables)) { - $tables = preg_split('/\s*,\s*/', trim($tables), -1, PREG_SPLIT_NO_EMPTY); - } - $this->from = $tables; - return $this; - } - - /** - * Sets the fulltext query text. This text will be composed into - * MATCH operator inside the WHERE clause. - * @param string $query fulltext query text. - * @return static the query object itself - */ - public function match($query) - { - $this->match = $query; - return $this; - } - - /** - * Sets the WHERE part of the query. - * - * The method requires a $condition parameter, and optionally a $params parameter - * specifying the values to be bound to the query. - * - * The $condition parameter should be either a string (e.g. 'id=1') or an array. - * If the latter, it must be in one of the following two formats: - * - * - hash format: `['column1' => value1, 'column2' => value2, ...]` - * - operator format: `[operator, operand1, operand2, ...]` - * - * A condition in hash format represents the following SQL expression in general: - * `column1=value1 AND column2=value2 AND ...`. In case when a value is an array, - * an `IN` expression will be generated. And if a value is null, `IS NULL` will be used - * in the generated expression. Below are some examples: - * - * - `['type' => 1, 'status' => 2]` generates `(type = 1) AND (status = 2)`. - * - `['id' => [1, 2, 3], 'status' => 2]` generates `(id IN (1, 2, 3)) AND (status = 2)`. - * - `['status' => null] generates `status IS NULL`. - * - * A condition in operator format generates the SQL expression according to the specified operator, which - * can be one of the followings: - * - * - `and`: the operands should be concatenated together using `AND`. For example, - * `['and', 'id=1', 'id=2']` will generate `id=1 AND id=2`. If an operand is an array, - * it will be converted into a string using the rules described here. For example, - * `['and', 'type=1', ['or', 'id=1', 'id=2']]` will generate `type=1 AND (id=1 OR id=2)`. - * The method will NOT do any quoting or escaping. - * - * - `or`: similar to the `and` operator except that the operands are concatenated using `OR`. - * - * - `between`: operand 1 should be the column name, and operand 2 and 3 should be the - * starting and ending values of the range that the column is in. - * For example, `['between', 'id', 1, 10]` will generate `id BETWEEN 1 AND 10`. - * - * - `not between`: similar to `between` except the `BETWEEN` is replaced with `NOT BETWEEN` - * in the generated condition. - * - * - `in`: operand 1 should be a column or DB expression, and operand 2 be an array representing - * the range of the values that the column or DB expression should be in. For example, - * `['in', 'id', [1, 2, 3]]` will generate `id IN (1, 2, 3)`. - * The method will properly quote the column name and escape values in the range. - * - * - `not in`: similar to the `in` operator except that `IN` is replaced with `NOT IN` in the generated condition. - * - * - `like`: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing - * the values that the column or DB expression should be like. - * For example, `['like', 'name', '%tester%']` will generate `name LIKE '%tester%'`. - * When the value range is given as an array, multiple `LIKE` predicates will be generated and concatenated - * using `AND`. For example, `['like', 'name', ['%test%', '%sample%']]` will generate - * `name LIKE '%test%' AND name LIKE '%sample%'`. - * The method will properly quote the column name and escape values in the range. - * Sometimes, you may want to add the percentage characters to the matching value by yourself, you may supply - * a third operand `false` to do so. For example, `['like', 'name', '%tester', false]` will generate `name LIKE '%tester'`. - * - * - `or like`: similar to the `like` operator except that `OR` is used to concatenate the `LIKE` - * predicates when operand 2 is an array. - * - * - `not like`: similar to the `like` operator except that `LIKE` is replaced with `NOT LIKE` - * in the generated condition. - * - * - `or not like`: similar to the `not like` operator except that `OR` is used to concatenate - * the `NOT LIKE` predicates. - * - * @param string|array $condition the conditions that should be put in the WHERE part. - * @param array $params the parameters (name => value) to be bound to the query. - * @return static the query object itself - * @see andWhere() - * @see orWhere() - */ - public function where($condition, $params = []) - { - $this->where = $condition; - $this->addParams($params); - return $this; - } - - /** - * Adds an additional WHERE condition to the existing one. - * The new condition and the existing one will be joined using the 'AND' operator. - * @param string|array $condition the new WHERE condition. Please refer to [[where()]] - * on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query. - * @return static the query object itself - * @see where() - * @see orWhere() - */ - public function andWhere($condition, $params = []) - { - if ($this->where === null) { - $this->where = $condition; - } else { - $this->where = ['and', $this->where, $condition]; - } - $this->addParams($params); - return $this; - } - - /** - * Adds an additional WHERE condition to the existing one. - * The new condition and the existing one will be joined using the 'OR' operator. - * @param string|array $condition the new WHERE condition. Please refer to [[where()]] - * on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query. - * @return static the query object itself - * @see where() - * @see andWhere() - */ - public function orWhere($condition, $params = []) - { - if ($this->where === null) { - $this->where = $condition; - } else { - $this->where = ['or', $this->where, $condition]; - } - $this->addParams($params); - return $this; - } - - /** - * Sets the GROUP BY part of the query. - * @param string|array $columns the columns to be grouped by. - * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. ['id', 'name']). - * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a DB expression). - * @return static the query object itself - * @see addGroupBy() - */ - public function groupBy($columns) - { - if (!is_array($columns)) { - $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); - } - $this->groupBy = $columns; - return $this; - } - - /** - * Adds additional group-by columns to the existing ones. - * @param string|array $columns additional columns to be grouped by. - * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. ['id', 'name']). - * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a DB expression). - * @return static the query object itself - * @see groupBy() - */ - public function addGroupBy($columns) - { - if (!is_array($columns)) { - $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); - } - if ($this->groupBy === null) { - $this->groupBy = $columns; - } else { - $this->groupBy = array_merge($this->groupBy, $columns); - } - return $this; - } - - /** - * Sets the parameters to be bound to the query. - * @param array $params list of query parameter values indexed by parameter placeholders. - * For example, `[':name' => 'Dan', ':age' => 31]`. - * @return static the query object itself - * @see addParams() - */ - public function params($params) - { - $this->params = $params; - return $this; - } - - /** - * Adds additional parameters to be bound to the query. - * @param array $params list of query parameter values indexed by parameter placeholders. - * For example, `[':name' => 'Dan', ':age' => 31]`. - * @return static the query object itself - * @see params() - */ - public function addParams($params) - { - if (!empty($params)) { - if ($this->params === null) { - $this->params = $params; - } else { - foreach ($params as $name => $value) { - if (is_integer($name)) { - $this->params[] = $value; - } else { - $this->params[$name] = $value; - } - } - } - } - return $this; - } - - /** - * Sets the query options. - * @param array $options query options in format: optionName => optionValue - * @return static the query object itself - * @see addOptions() - */ - public function options($options) - { - $this->options = $options; - return $this; - } - - /** - * Adds additional query options. - * @param array $options query options in format: optionName => optionValue - * @return static the query object itself - * @see options() - */ - public function addOptions($options) - { - if (is_array($this->options)) { - $this->options = array_merge($this->options, $options); - } else { - $this->options = $options; - } - return $this; - } - - /** - * Sets the WITHIN GROUP ORDER BY part of the query. - * @param string|array $columns the columns (and the directions) to find best row within a group. - * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array - * (e.g. `['id' => Query::SORT_ASC, 'name' => Query::SORT_DESC]`). - * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a DB expression). - * @return static the query object itself - * @see addWithin() - */ - public function within($columns) - { - $this->within = $this->normalizeOrderBy($columns); - return $this; - } - - /** - * Adds additional WITHIN GROUP ORDER BY columns to the query. - * @param string|array $columns the columns (and the directions) to find best row within a group. - * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array - * (e.g. `['id' => Query::SORT_ASC, 'name' => Query::SORT_DESC]`). - * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a DB expression). - * @return static the query object itself - * @see within() - */ - public function addWithin($columns) - { - $columns = $this->normalizeOrderBy($columns); - if ($this->within === null) { - $this->within = $columns; - } else { - $this->within = array_merge($this->within, $columns); - } - return $this; - } - - /** - * Sets the PHP callback, which should be used to retrieve the source data - * for the snippets building. - * @param callback $callback PHP callback, which should be used to fetch source data for the snippets. - * @return static the query object itself - * @see snippetCallback - */ - public function snippetCallback($callback) - { - $this->snippetCallback = $callback; - return $this; - } - - /** - * Sets the call snippets query options. - * @param array $options call snippet options in format: option_name => option_value - * @return static the query object itself - * @see snippetCallback - */ - public function snippetOptions($options) - { - $this->snippetOptions = $options; - return $this; - } - - /** - * Fills the query result rows with the snippets built from source determined by - * [[snippetCallback]] result. - * @param array $rows raw query result rows. - * @return array query result rows with filled up snippets. - */ - protected function fillUpSnippets($rows) - { - if ($this->snippetCallback === null) { - return $rows; - } - $snippetSources = call_user_func($this->snippetCallback, $rows); - $snippets = $this->callSnippets($snippetSources); - $snippetKey = 0; - foreach ($rows as $key => $row) { - $rows[$key]['snippet'] = $snippets[$snippetKey]; - $snippetKey++; - } - return $rows; - } - - /** - * Builds a snippets from provided source data. - * @param array $source the source data to extract a snippet from. - * @throws InvalidCallException in case [[match]] is not specified. - * @return array snippets list. - */ - protected function callSnippets(array $source) - { - $connection = $this->getConnection(); - $match = $this->match; - if ($match === null) { - throw new InvalidCallException('Unable to call snippets: "' . $this->className() . '::match" should be specified.'); - } - return $connection->createCommand() - ->callSnippets($this->from[0], $source, $match, $this->snippetOptions) - ->queryColumn(); - } -} diff --git a/extensions/yii/sphinx/QueryBuilder.php b/extensions/yii/sphinx/QueryBuilder.php deleted file mode 100644 index 6bd6d0c..0000000 --- a/extensions/yii/sphinx/QueryBuilder.php +++ /dev/null @@ -1,916 +0,0 @@ - - * @since 2.0 - */ -class QueryBuilder extends Object -{ - /** - * The prefix for automatically generated query binding parameters. - */ - const PARAM_PREFIX = ':qp'; - - /** - * @var Connection the Sphinx connection. - */ - public $db; - /** - * @var string the separator between different fragments of a SQL statement. - * Defaults to an empty space. This is mainly used by [[build()]] when generating a SQL statement. - */ - public $separator = " "; - - /** - * Constructor. - * @param Connection $connection the Sphinx 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 a SELECT SQL statement from a [[Query]] object. - * @param Query $query the [[Query]] object from which the SQL statement 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) - { - $params = $query->params; - if ($query->match !== null) { - $phName = self::PARAM_PREFIX . count($params); - $params[$phName] = (string)$query->match; - $query->andWhere('MATCH(' . $phName . ')'); - } - $clauses = [ - $this->buildSelect($query->select, $query->distinct, $query->selectOption), - $this->buildFrom($query->from), - $this->buildWhere($query->from, $query->where, $params), - $this->buildGroupBy($query->groupBy), - $this->buildWithin($query->within), - $this->buildOrderBy($query->orderBy), - $this->buildLimit($query->limit, $query->offset), - $this->buildOption($query->options, $params), - ]; - return [implode($this->separator, array_filter($clauses)), $params]; - } - - /** - * Creates an INSERT SQL statement. - * For example, - * - * ~~~ - * $sql = $queryBuilder->insert('idx_user', [ - * 'name' => 'Sam', - * 'age' => 30, - * 'id' => 10, - * ], $params); - * ~~~ - * - * The method will properly escape the index and column names. - * - * @param string $index the index that new rows will be inserted into. - * @param array $columns the column data (name => value) to be inserted into the index. - * @param array $params the binding parameters that will be generated by this method. - * They should be bound to the Sphinx command later. - * @return string the INSERT SQL - */ - public function insert($index, $columns, &$params) - { - return $this->generateInsertReplace('INSERT', $index, $columns, $params); - } - - /** - * Creates an REPLACE SQL statement. - * For example, - * - * ~~~ - * $sql = $queryBuilder->replace('idx_user', [ - * 'name' => 'Sam', - * 'age' => 30, - * 'id' => 10, - * ], $params); - * ~~~ - * - * The method will properly escape the index and column names. - * - * @param string $index the index that new rows will be replaced. - * @param array $columns the column data (name => value) to be replaced in the index. - * @param array $params the binding parameters that will be generated by this method. - * They should be bound to the Sphinx command later. - * @return string the INSERT SQL - */ - public function replace($index, $columns, &$params) - { - return $this->generateInsertReplace('REPLACE', $index, $columns, $params); - } - - /** - * Generates INSERT/REPLACE SQL statement. - * @param string $statement statement ot be generated. - * @param string $index the affected index name. - * @param array $columns the column data (name => value). - * @param array $params the binding parameters that will be generated by this method. - * @return string generated SQL - */ - protected function generateInsertReplace($statement, $index, $columns, &$params) - { - if (($indexSchema = $this->db->getIndexSchema($index)) !== null) { - $indexSchemas = [$indexSchema]; - } else { - $indexSchemas = []; - } - $names = []; - $placeholders = []; - foreach ($columns as $name => $value) { - $names[] = $this->db->quoteColumnName($name); - $placeholders[] = $this->composeColumnValue($indexSchemas, $name, $value, $params); - } - return $statement . ' INTO ' . $this->db->quoteIndexName($index) - . ' (' . implode(', ', $names) . ') VALUES (' - . implode(', ', $placeholders) . ')'; - } - - /** - * Generates a batch INSERT SQL statement. - * For example, - * - * ~~~ - * $connection->createCommand()->batchInsert('idx_user', ['id', 'name', 'age'], [ - * [1, 'Tom', 30], - * [2, 'Jane', 20], - * [3, 'Linda', 25], - * ])->execute(); - * ~~~ - * - * Note that the values in each row must match the corresponding column names. - * - * @param string $index the index that new rows will be inserted into. - * @param array $columns the column names - * @param array $rows the rows to be batch inserted into the index - * @param array $params the binding parameters that will be generated by this method. - * They should be bound to the Sphinx command later. - * @return string the batch INSERT SQL statement - */ - public function batchInsert($index, $columns, $rows, &$params) - { - return $this->generateBatchInsertReplace('INSERT', $index, $columns, $rows, $params); - } - - /** - * Generates a batch REPLACE SQL statement. - * For example, - * - * ~~~ - * $connection->createCommand()->batchReplace('idx_user', ['id', 'name', 'age'], [ - * [1, 'Tom', 30], - * [2, 'Jane', 20], - * [3, 'Linda', 25], - * ])->execute(); - * ~~~ - * - * Note that the values in each row must match the corresponding column names. - * - * @param string $index the index that new rows will be replaced. - * @param array $columns the column names - * @param array $rows the rows to be batch replaced in the index - * @param array $params the binding parameters that will be generated by this method. - * They should be bound to the Sphinx command later. - * @return string the batch INSERT SQL statement - */ - public function batchReplace($index, $columns, $rows, &$params) - { - return $this->generateBatchInsertReplace('REPLACE', $index, $columns, $rows, $params); - } - - /** - * Generates a batch INSERT/REPLACE SQL statement. - * @param string $statement statement ot be generated. - * @param string $index the affected index name. - * @param array $columns the column data (name => value). - * @param array $rows the rows to be batch inserted into the index - * @param array $params the binding parameters that will be generated by this method. - * @return string generated SQL - */ - protected function generateBatchInsertReplace($statement, $index, $columns, $rows, &$params) - { - if (($indexSchema = $this->db->getIndexSchema($index)) !== null) { - $indexSchemas = [$indexSchema]; - } else { - $indexSchemas = []; - } - - foreach ($columns as $i => $name) { - $columns[$i] = $this->db->quoteColumnName($name); - } - - $values = []; - foreach ($rows as $row) { - $vs = []; - foreach ($row as $i => $value) { - $vs[] = $this->composeColumnValue($indexSchemas, $columns[$i], $value, $params); - } - $values[] = '(' . implode(', ', $vs) . ')'; - } - - return $statement . ' INTO ' . $this->db->quoteIndexName($index) - . ' (' . implode(', ', $columns) . ') VALUES ' . implode(', ', $values); - } - - /** - * Creates an UPDATE SQL statement. - * For example, - * - * ~~~ - * $params = []; - * $sql = $queryBuilder->update('idx_user', ['status' => 1], 'age > 30', $params); - * ~~~ - * - * The method will properly escape the index and column names. - * - * @param string $index the index to be updated. - * @param array $columns the column data (name => value) to be updated. - * @param array|string $condition the condition that will be put in the WHERE part. Please - * refer to [[Query::where()]] on how to specify condition. - * @param array $params the binding parameters that will be modified by this method - * so that they can be bound to the Sphinx command later. - * @param array $options list of options in format: optionName => optionValue - * @return string the UPDATE SQL - */ - public function update($index, $columns, $condition, &$params, $options) - { - if (($indexSchema = $this->db->getIndexSchema($index)) !== null) { - $indexSchemas = [$indexSchema]; - } else { - $indexSchemas = []; - } - - $lines = []; - foreach ($columns as $name => $value) { - $lines[] = $this->db->quoteColumnName($name) . '=' . $this->composeColumnValue($indexSchemas, $name, $value, $params); - } - - $sql = 'UPDATE ' . $this->db->quoteIndexName($index) . ' SET ' . implode(', ', $lines); - $where = $this->buildWhere([$index], $condition, $params); - if ($where !== '') { - $sql = $sql . ' ' . $where; - } - $option = $this->buildOption($options, $params); - if ($option !== '') { - $sql = $sql . ' ' . $option; - } - return $sql; - } - - /** - * Creates a DELETE SQL statement. - * For example, - * - * ~~~ - * $sql = $queryBuilder->delete('idx_user', 'status = 0'); - * ~~~ - * - * The method will properly escape the index and column names. - * - * @param string $index the index where the data will be deleted from. - * @param array|string $condition the condition that will be put in the WHERE part. Please - * refer to [[Query::where()]] on how to specify condition. - * @param array $params the binding parameters that will be modified by this method - * so that they can be bound to the Sphinx command later. - * @return string the DELETE SQL - */ - public function delete($index, $condition, &$params) - { - $sql = 'DELETE FROM ' . $this->db->quoteIndexName($index); - $where = $this->buildWhere([$index], $condition, $params); - return $where === '' ? $sql : $sql . ' ' . $where; - } - - /** - * Builds a SQL statement for truncating an index. - * @param string $index the index to be truncated. The name will be properly quoted by the method. - * @return string the SQL statement for truncating an index. - */ - public function truncateIndex($index) - { - return 'TRUNCATE RTINDEX ' . $this->db->quoteIndexName($index); - } - - /** - * Builds a SQL statement for call snippet from provided data and query, using specified index settings. - * @param string $index name of the index, from which to take the text processing settings. - * @param string|array $source is the source data to extract a snippet from. - * It could be either a single string or array of strings. - * @param string $match the full-text query to build snippets for. - * @param array $options list of options in format: optionName => optionValue - * @param array $params the binding parameters that will be modified by this method - * so that they can be bound to the Sphinx command later. - * @return string the SQL statement for call snippets. - */ - public function callSnippets($index, $source, $match, $options, &$params) - { - if (is_array($source)) { - $dataSqlParts = []; - foreach ($source as $sourceRow) { - $phName = self::PARAM_PREFIX . count($params); - $params[$phName] = $sourceRow; - $dataSqlParts[] = $phName; - } - $dataSql = '(' . implode(',', $dataSqlParts) . ')'; - } else { - $phName = self::PARAM_PREFIX . count($params); - $params[$phName] = $source; - $dataSql = $phName; - } - $indexParamName = self::PARAM_PREFIX . count($params); - $params[$indexParamName] = $index; - $matchParamName = self::PARAM_PREFIX . count($params); - $params[$matchParamName] = $match; - if (!empty($options)) { - $optionParts = []; - foreach ($options as $name => $value) { - if ($value instanceof Expression) { - $actualValue = $value->expression; - } else { - $actualValue = self::PARAM_PREFIX . count($params); - $params[$actualValue] = $value; - } - $optionParts[] = $actualValue . ' AS ' . $name; - } - $optionSql = ', ' . implode(', ', $optionParts); - } else { - $optionSql = ''; - } - return 'CALL SNIPPETS(' . $dataSql. ', ' . $indexParamName . ', ' . $matchParamName . $optionSql. ')'; - } - - /** - * Builds a SQL statement for returning tokenized and normalized forms of the keywords, and, - * optionally, keyword statistics. - * @param string $index the name of the index from which to take the text processing settings - * @param string $text the text to break down to keywords. - * @param boolean $fetchStatistic whether to return document and hit occurrence statistics - * @param array $params the binding parameters that will be modified by this method - * so that they can be bound to the Sphinx command later. - * @return string the SQL statement for call keywords. - */ - public function callKeywords($index, $text, $fetchStatistic, &$params) - { - $indexParamName = self::PARAM_PREFIX . count($params); - $params[$indexParamName] = $index; - $textParamName = self::PARAM_PREFIX . count($params); - $params[$textParamName] = $text; - return 'CALL KEYWORDS(' . $textParamName . ', ' . $indexParamName . ($fetchStatistic ? ', 1' : '') . ')'; - } - - /** - * @param array $columns - * @param boolean $distinct - * @param string $selectOption - * @return string the SELECT clause built from [[query]]. - */ - public function buildSelect($columns, $distinct = false, $selectOption = null) - { - $select = $distinct ? 'SELECT DISTINCT' : 'SELECT'; - if ($selectOption !== null) { - $select .= ' ' . $selectOption; - } - - if (empty($columns)) { - return $select . ' *'; - } - - foreach ($columns as $i => $column) { - if (is_object($column)) { - $columns[$i] = (string)$column; - } elseif (strpos($column, '(') === false) { - if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)([\w\-_\.]+)$/', $column, $matches)) { - $columns[$i] = $this->db->quoteColumnName($matches[1]) . ' AS ' . $this->db->quoteColumnName($matches[2]); - } else { - $columns[$i] = $this->db->quoteColumnName($column); - } - } - } - - if (is_array($columns)) { - $columns = implode(', ', $columns); - } - - return $select . ' ' . $columns; - } - - /** - * @param array $indexes - * @return string the FROM clause built from [[query]]. - */ - public function buildFrom($indexes) - { - if (empty($indexes)) { - return ''; - } - - foreach ($indexes as $i => $index) { - if (strpos($index, '(') === false) { - if (preg_match('/^(.*?)(?i:\s+as|)\s+([^ ]+)$/', $index, $matches)) { // with alias - $indexes[$i] = $this->db->quoteIndexName($matches[1]) . ' ' . $this->db->quoteIndexName($matches[2]); - } else { - $indexes[$i] = $this->db->quoteIndexName($index); - } - } - } - - if (is_array($indexes)) { - $indexes = implode(', ', $indexes); - } - - return 'FROM ' . $indexes; - } - - /** - * @param string[] $indexes list of index names, which affected by query - * @param string|array $condition - * @param array $params the binding parameters to be populated - * @return string the WHERE clause built from [[query]]. - */ - public function buildWhere($indexes, $condition, &$params) - { - if (empty($condition)) { - return ''; - } - $indexSchemas = []; - if (!empty($indexes)) { - foreach ($indexes as $indexName) { - $index = $this->db->getIndexSchema($indexName); - if ($index !== null) { - $indexSchemas[] = $index; - } - } - } - $where = $this->buildCondition($indexSchemas, $condition, $params); - return $where === '' ? '' : 'WHERE ' . $where; - } - - /** - * @param array $columns - * @return string the GROUP BY clause - */ - public function buildGroupBy($columns) - { - return empty($columns) ? '' : 'GROUP BY ' . $this->buildColumns($columns); - } - - /** - * @param array $columns - * @return string the ORDER BY clause built from [[query]]. - */ - public function buildOrderBy($columns) - { - if (empty($columns)) { - return ''; - } - $orders = []; - foreach ($columns as $name => $direction) { - if (is_object($direction)) { - $orders[] = (string)$direction; - } else { - $orders[] = $this->db->quoteColumnName($name) . ($direction === SORT_DESC ? ' DESC' : 'ASC'); - } - } - - return 'ORDER BY ' . implode(', ', $orders); - } - - /** - * @param integer $limit - * @param integer $offset - * @return string the LIMIT and OFFSET clauses built from [[query]]. - */ - public function buildLimit($limit, $offset) - { - $sql = ''; - if ($limit !== null && $limit >= 0) { - $sql = 'LIMIT ' . (int)$limit; - } - if ($offset > 0) { - $sql .= ' OFFSET ' . (int)$offset; - } - return ltrim($sql); - } - - /** - * Processes columns and properly quote them if necessary. - * It will join all columns into a string with comma as separators. - * @param string|array $columns the columns to be processed - * @return string the processing result - */ - public function buildColumns($columns) - { - if (!is_array($columns)) { - if (strpos($columns, '(') !== false) { - return $columns; - } else { - $columns = preg_split('/\s*,\s*/', $columns, -1, PREG_SPLIT_NO_EMPTY); - } - } - foreach ($columns as $i => $column) { - if (is_object($column)) { - $columns[$i] = (string)$column; - } elseif (strpos($column, '(') === false) { - $columns[$i] = $this->db->quoteColumnName($column); - } - } - return is_array($columns) ? implode(', ', $columns) : $columns; - } - - /** - * Parses the condition specification and generates the corresponding SQL expression. - * @param IndexSchema[] $indexes list of indexes, which affected by query - * @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($indexes, $condition, &$params) - { - static $builders = [ - '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 (!is_array($condition)) { - return (string)$condition; - } elseif (empty($condition)) { - return ''; - } - if (isset($condition[0])) { // operator format: operator, operand 1, operand 2, ... - $operator = strtoupper($condition[0]); - if (isset($builders[$operator])) { - $method = $builders[$operator]; - array_shift($condition); - return $this->$method($indexes, $operator, $condition, $params); - } else { - throw new Exception('Found unknown operator in query: ' . $operator); - } - } else { // hash format: 'column1' => 'value1', 'column2' => 'value2', ... - return $this->buildHashCondition($indexes, $condition, $params); - } - } - - /** - * Creates a condition based on column-value pairs. - * @param IndexSchema[] $indexes list of indexes, which affected by query - * @param array $condition the condition specification. - * @param array $params the binding parameters to be populated - * @return string the generated SQL expression - */ - public function buildHashCondition($indexes, $condition, &$params) - { - $parts = []; - foreach ($condition as $column => $value) { - if (is_array($value)) { // IN condition - $parts[] = $this->buildInCondition($indexes, 'IN', [$column, $value], $params); - } else { - if (strpos($column, '(') === false) { - $quotedColumn = $this->db->quoteColumnName($column); - } else { - $quotedColumn = $column; - } - if ($value === null) { - $parts[] = "$quotedColumn IS NULL"; - } else { - $parts[] = $quotedColumn . '=' . $this->composeColumnValue($indexes, $column, $value, $params); - } - } - } - return count($parts) === 1 ? $parts[0] : '(' . implode(') AND (', $parts) . ')'; - } - - /** - * Connects two or more SQL expressions with the `AND` or `OR` operator. - * @param IndexSchema[] $indexes list of indexes, which affected by query - * @param string $operator the operator to use for connecting the given operands - * @param array $operands the SQL expressions to connect. - * @param array $params the binding parameters to be populated - * @return string the generated SQL expression - */ - public function buildAndCondition($indexes, $operator, $operands, &$params) - { - $parts = []; - foreach ($operands as $operand) { - if (is_array($operand)) { - $operand = $this->buildCondition($indexes, $operand, $params); - } - if ($operand !== '') { - $parts[] = $operand; - } - } - if (!empty($parts)) { - return '(' . implode(") $operator (", $parts) . ')'; - } else { - return ''; - } - } - - /** - * Creates an SQL expressions with the `BETWEEN` operator. - * @param IndexSchema[] $indexes list of indexes, which affected by query - * @param string $operator the operator to use (e.g. `BETWEEN` or `NOT BETWEEN`) - * @param array $operands the first operand is the column name. The second and third operands - * describe the interval that column value should be in. - * @param array $params the binding parameters to be populated - * @return string the generated SQL expression - * @throws Exception if wrong number of operands have been given. - */ - public function buildBetweenCondition($indexes, $operator, $operands, &$params) - { - if (!isset($operands[0], $operands[1], $operands[2])) { - throw new Exception("Operator '$operator' requires three operands."); - } - - list($column, $value1, $value2) = $operands; - - if (strpos($column, '(') === false) { - $quotedColumn = $this->db->quoteColumnName($column); - } else { - $quotedColumn = $column; - } - $phName1 = $this->composeColumnValue($indexes, $column, $value1, $params); - $phName2 = $this->composeColumnValue($indexes, $column, $value2, $params); - - return "$quotedColumn $operator $phName1 AND $phName2"; - } - - /** - * Creates an SQL expressions with the `IN` operator. - * @param IndexSchema[] $indexes list of indexes, which affected by query - * @param string $operator the operator to use (e.g. `IN` or `NOT IN`) - * @param array $operands the first operand is the column name. If it is an array - * a composite IN condition will be generated. - * The second operand is an array of values that column value should be among. - * If it is an empty array the generated expression will be a `false` value if - * operator is `IN` and empty if operator is `NOT IN`. - * @param array $params the binding parameters to be populated - * @return string the generated SQL expression - * @throws Exception if wrong number of operands have been given. - */ - public function buildInCondition($indexes, $operator, $operands, &$params) - { - if (!isset($operands[0], $operands[1])) { - throw new Exception("Operator '$operator' requires two operands."); - } - - list($column, $values) = $operands; - - $values = (array)$values; - - if (empty($values) || $column === []) { - return $operator === 'IN' ? '0=1' : ''; - } - - if (count($column) > 1) { - return $this->buildCompositeInCondition($indexes, $operator, $column, $values, $params); - } elseif (is_array($column)) { - $column = reset($column); - } - foreach ($values as $i => $value) { - if (is_array($value)) { - $value = isset($value[$column]) ? $value[$column] : null; - } - $values[$i] = $this->composeColumnValue($indexes, $column, $value, $params); - } - if (strpos($column, '(') === false) { - $column = $this->db->quoteColumnName($column); - } - - if (count($values) > 1) { - return "$column $operator (" . implode(', ', $values) . ')'; - } else { - $operator = $operator === 'IN' ? '=' : '<>'; - return "$column$operator{$values[0]}"; - } - } - - /** - * @param IndexSchema[] $indexes list of indexes, which affected by query - * @param string $operator the operator to use (e.g. `IN` or `NOT IN`) - * @param array $columns - * @param array $values - * @param array $params the binding parameters to be populated - * @return string the generated SQL expression - */ - protected function buildCompositeInCondition($indexes, $operator, $columns, $values, &$params) - { - $vss = []; - foreach ($values as $value) { - $vs = []; - foreach ($columns as $column) { - if (isset($value[$column])) { - $vs[] = $this->composeColumnValue($indexes, $column, $value[$column], $params); - } else { - $vs[] = 'NULL'; - } - } - $vss[] = '(' . implode(', ', $vs) . ')'; - } - foreach ($columns as $i => $column) { - if (strpos($column, '(') === false) { - $columns[$i] = $this->db->quoteColumnName($column); - } - } - return '(' . implode(', ', $columns) . ") $operator (" . implode(', ', $vss) . ')'; - } - - /** - * Creates an SQL expressions with the `LIKE` operator. - * @param IndexSchema[] $indexes list of indexes, which affected by query - * @param string $operator the operator to use (e.g. `LIKE`, `NOT LIKE`, `OR LIKE` or `OR NOT LIKE`) - * @param array $operands an array of two or three operands - * - * - The first operand is the column name. - * - The second operand is a single value or an array of values that column value - * should be compared with. If it is an empty array the generated expression will - * be a `false` value if operator is `LIKE` or `OR LIKE`, and empty if operator - * is `NOT LIKE` or `OR NOT LIKE`. - * - An optional third operand can also be provided to specify how to escape special characters - * in the value(s). The operand should be an array of mappings from the special characters to their - * escaped counterparts. If this operand is not provided, a default escape mapping will be used. - * You may use `false` or an empty array to indicate the values are already escaped and no escape - * should be applied. Note that when using an escape mapping (or the third operand is not provided), - * the values will be automatically enclosed within a pair of percentage characters. - * @param array $params the binding parameters to be populated - * @return string the generated SQL expression - * @throws InvalidParamException if wrong number of operands have been given. - */ - public function buildLikeCondition($indexes, $operator, $operands, &$params) - { - if (!isset($operands[0], $operands[1])) { - throw new InvalidParamException("Operator '$operator' requires two operands."); - } - - $escape = isset($operands[2]) ? $operands[2] : ['%'=>'\%', '_'=>'\_', '\\'=>'\\\\']; - unset($operands[2]); - - list($column, $values) = $operands; - - $values = (array)$values; - - if (empty($values)) { - return $operator === 'LIKE' || $operator === 'OR LIKE' ? '0=1' : ''; - } - - if ($operator === 'LIKE' || $operator === 'NOT LIKE') { - $andor = ' AND '; - } else { - $andor = ' OR '; - $operator = $operator === 'OR LIKE' ? 'LIKE' : 'NOT LIKE'; - } - - if (strpos($column, '(') === false) { - $column = $this->db->quoteColumnName($column); - } - - $parts = []; - foreach ($values as $value) { - $phName = self::PARAM_PREFIX . count($params); - $params[$phName] = empty($escape) ? $value : ('%' . strtr($value, $escape) . '%'); - $parts[] = "$column $operator $phName"; - } - - return implode($andor, $parts); - } - - /** - * @param array $columns - * @return string the ORDER BY clause built from [[query]]. - */ - public function buildWithin($columns) - { - if (empty($columns)) { - return ''; - } - $orders = []; - foreach ($columns as $name => $direction) { - if (is_object($direction)) { - $orders[] = (string)$direction; - } else { - $orders[] = $this->db->quoteColumnName($name) . ($direction === SORT_DESC ? ' DESC' : ''); - } - } - return 'WITHIN GROUP ORDER BY ' . implode(', ', $orders); - } - - /** - * @param array $options query options in format: optionName => optionValue - * @param array $params the binding parameters to be populated - * @return string the OPTION clause build from [[query]] - */ - public function buildOption($options, &$params) - { - if (empty($options)) { - return ''; - } - $optionLines = []; - foreach ($options as $name => $value) { - if ($value instanceof Expression) { - $actualValue = $value->expression; - } else { - if (is_array($value)) { - $actualValueParts = []; - foreach ($value as $key => $valuePart) { - if (is_numeric($key)) { - $actualValuePart = ''; - } else { - $actualValuePart = $key . ' = '; - } - if ($valuePart instanceof Expression) { - $actualValuePart .= $valuePart->expression; - } else { - $phName = self::PARAM_PREFIX . count($params); - $params[$phName] = $valuePart; - $actualValuePart .= $phName; - } - $actualValueParts[] = $actualValuePart; - } - $actualValue = '(' . implode(', ', $actualValueParts) . ')'; - } else { - $actualValue = self::PARAM_PREFIX . count($params); - $params[$actualValue] = $value; - } - } - $optionLines[] = $name . ' = ' . $actualValue; - } - return 'OPTION ' . implode(', ', $optionLines); - } - - /** - * Composes column value for SQL, taking in account the column type. - * @param IndexSchema[] $indexes list of indexes, which affected by query - * @param string $columnName name of the column - * @param mixed $value raw column value - * @param array $params the binding parameters to be populated - * @return string SQL expression, which represents column value - */ - protected function composeColumnValue($indexes, $columnName, $value, &$params) { - if ($value === null) { - return 'NULL'; - } elseif ($value instanceof Expression) { - $params = array_merge($params, $value->params); - return $value->expression; - } - foreach ($indexes as $index) { - $columnSchema = $index->getColumn($columnName); - if ($columnSchema !== null) { - break; - } - } - if (is_array($value)) { - // MVA : - $lineParts = []; - foreach ($value as $subValue) { - if ($subValue instanceof Expression) { - $params = array_merge($params, $subValue->params); - $lineParts[] = $subValue->expression; - } else { - $phName = self::PARAM_PREFIX . count($params); - $lineParts[] = $phName; - $params[$phName] = (isset($columnSchema)) ? $columnSchema->typecast($subValue) : $subValue; - } - } - return '(' . implode(',', $lineParts) . ')'; - } else { - $phName = self::PARAM_PREFIX . count($params); - $params[$phName] = (isset($columnSchema)) ? $columnSchema->typecast($value) : $value; - return $phName; - } - } -} diff --git a/extensions/yii/sphinx/README.md b/extensions/yii/sphinx/README.md deleted file mode 100644 index 36e8afd..0000000 --- a/extensions/yii/sphinx/README.md +++ /dev/null @@ -1,108 +0,0 @@ -Sphinx Extension for Yii 2 -========================== - -This extension adds [Sphinx](http://sphinxsearch.com/docs) full text search engine extension 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-sphinx "*" -``` - -or add - -```json -"yiisoft/yii2-sphinx": "*" -``` - -to the require section of your composer.json. - - -Usage & Documentation ---------------------- - -This extension interacts with Sphinx search daemon using MySQL protocol and [SphinxQL](http://sphinxsearch.com/docs/current.html#sphinxql) query language. -In order to setup Sphinx "searchd" to support MySQL protocol following configuration should be added: - -``` -searchd -{ - listen = localhost:9306:mysql41 - ... -} -``` - -This extension supports all Sphinx features including [Runtime Indexes](http://sphinxsearch.com/docs/current.html#rt-indexes). -Since this extension uses MySQL protocol to access Sphinx, it shares base approach and much code from the -regular "yii\db" package. - -To use this extension, simply add the following code in your application configuration: - -```php -return [ - //.... - 'components' => [ - 'sphinx' => [ - 'class' => 'yii\sphinx\Connection', - 'dsn' => 'mysql:host=127.0.0.1;port=9306;', - 'username' => '', - 'password' => '', - ], - ], -]; -``` - -This extension provides ActiveRecord solution similar ot the [[\yii\db\ActiveRecord]]. -To declare an ActiveRecord class you need to extend [[\yii\sphinx\ActiveRecord]] and -implement the `indexName` method: - -```php -use yii\sphinx\ActiveRecord; - -class Article extends ActiveRecord -{ - /** - * @return string the name of the index associated with this ActiveRecord class. - */ - public static function indexName() - { - return 'idx_article'; - } -} -``` - -You can use [[\yii\data\ActiveDataProvider]] with the [[\yii\sphinx\Query]] and [[\yii\sphinx\ActiveQuery]]: - -```php -use yii\data\ActiveDataProvider; -use yii\sphinx\Query; - -$query = new Query; -$query->from('yii2_test_article_index')->match('development'); -$provider = new ActiveDataProvider([ - 'query' => $query, - 'pagination' => [ - 'pageSize' => 10, - ] -]); -$models = $provider->getModels(); -``` - -```php -use yii\data\ActiveDataProvider; -use app\models\Article; - -$provider = new ActiveDataProvider([ - 'query' => Article::find(), - 'pagination' => [ - 'pageSize' => 10, - ] -]); -$models = $provider->getModels(); -``` diff --git a/extensions/yii/sphinx/Schema.php b/extensions/yii/sphinx/Schema.php deleted file mode 100644 index 5515865..0000000 --- a/extensions/yii/sphinx/Schema.php +++ /dev/null @@ -1,489 +0,0 @@ - index type. This - * property is read-only. - * @property QueryBuilder $queryBuilder The query builder for this connection. This property is read-only. - * - * @author Paul Klimov - * @since 2.0 - */ -class Schema extends Object -{ - /** - * The followings are the supported abstract column data types. - */ - const TYPE_PK = 'pk'; - const TYPE_STRING = 'string'; - const TYPE_INTEGER = 'integer'; - const TYPE_BIGINT = 'bigint'; - const TYPE_FLOAT = 'float'; - const TYPE_TIMESTAMP = 'timestamp'; - const TYPE_BOOLEAN = 'boolean'; - - /** - * @var Connection the Sphinx connection - */ - public $db; - /** - * @var array list of ALL index names in the Sphinx - */ - private $_indexNames; - /** - * @var array list of ALL index types in the Sphinx (index name => index type) - */ - private $_indexTypes; - /** - * @var array list of loaded index metadata (index name => IndexSchema) - */ - private $_indexes = []; - /** - * @var QueryBuilder the query builder for this Sphinx connection - */ - private $_builder; - - /** - * @var array mapping from physical column types (keys) to abstract column types (values) - */ - public $typeMap = [ - 'field' => self::TYPE_STRING, - 'string' => self::TYPE_STRING, - 'ordinal' => self::TYPE_STRING, - 'integer' => self::TYPE_INTEGER, - 'int' => self::TYPE_INTEGER, - 'uint' => self::TYPE_INTEGER, - 'bigint' => self::TYPE_BIGINT, - 'timestamp' => self::TYPE_TIMESTAMP, - 'bool' => self::TYPE_BOOLEAN, - 'float' => self::TYPE_FLOAT, - 'mva' => self::TYPE_INTEGER, - ]; - - /** - * Loads the metadata for the specified index. - * @param string $name index name - * @return IndexSchema driver dependent index metadata. Null if the index does not exist. - */ - protected function loadIndexSchema($name) - { - $index = new IndexSchema; - $this->resolveIndexNames($index, $name); - $this->resolveIndexType($index); - - if ($this->findColumns($index)) { - return $index; - } else { - return null; - } - } - - /** - * Resolves the index name. - * @param IndexSchema $index the index metadata object - * @param string $name the index name - */ - protected function resolveIndexNames($index, $name) - { - $index->name = str_replace('`', '', $name); - } - - /** - * Resolves the index name. - * @param IndexSchema $index the index metadata object - */ - protected function resolveIndexType($index) - { - $indexTypes = $this->getIndexTypes(); - $index->type = array_key_exists($index->name, $indexTypes) ? $indexTypes[$index->name] : 'unknown'; - $index->isRuntime = ($index->type == 'rt'); - } - - /** - * Obtains the metadata for the named index. - * @param string $name index name. The index name may contain schema name if any. Do not quote the index name. - * @param boolean $refresh whether to reload the index schema even if it is found in the cache. - * @return IndexSchema index metadata. Null if the named index does not exist. - */ - public function getIndexSchema($name, $refresh = false) - { - if (isset($this->_indexes[$name]) && !$refresh) { - return $this->_indexes[$name]; - } - - $db = $this->db; - $realName = $this->getRawIndexName($name); - - if ($db->enableSchemaCache && !in_array($name, $db->schemaCacheExclude, true)) { - /** @var $cache Cache */ - $cache = is_string($db->schemaCache) ? Yii::$app->getComponent($db->schemaCache) : $db->schemaCache; - if ($cache instanceof Cache) { - $key = $this->getCacheKey($name); - if ($refresh || ($index = $cache->get($key)) === false) { - $index = $this->loadIndexSchema($realName); - if ($index !== null) { - $cache->set($key, $index, $db->schemaCacheDuration, new GroupDependency([ - 'group' => $this->getCacheGroup(), - ])); - } - } - return $this->_indexes[$name] = $index; - } - } - return $this->_indexes[$name] = $index = $this->loadIndexSchema($realName); - } - - /** - * Returns the cache key for the specified index name. - * @param string $name the index name - * @return mixed the cache key - */ - protected function getCacheKey($name) - { - return [ - __CLASS__, - $this->db->dsn, - $this->db->username, - $name, - ]; - } - - /** - * Returns the cache group name. - * This allows [[refresh()]] to invalidate all cached index schemas. - * @return string the cache group name - */ - protected function getCacheGroup() - { - return md5(serialize([ - __CLASS__, - $this->db->dsn, - $this->db->username, - ])); - } - - /** - * Returns the metadata for all indexes in the database. - * @param boolean $refresh whether to fetch the latest available index schemas. If this is false, - * cached data may be returned if available. - * @return IndexSchema[] the metadata for all indexes in the Sphinx. - * Each array element is an instance of [[IndexSchema]] or its child class. - */ - public function getIndexSchemas($refresh = false) - { - $indexes = []; - foreach ($this->getIndexNames($refresh) as $name) { - if (($index = $this->getIndexSchema($name, $refresh)) !== null) { - $indexes[] = $index; - } - } - return $indexes; - } - - /** - * Returns all index names in the Sphinx. - * @param boolean $refresh whether to fetch the latest available index names. If this is false, - * index names fetched previously (if available) will be returned. - * @return string[] all index names in the Sphinx. - */ - public function getIndexNames($refresh = false) - { - if (!isset($this->_indexNames) || $refresh) { - $this->initIndexesInfo(); - } - return $this->_indexNames; - } - - /** - * Returns all index types in the Sphinx. - * @param boolean $refresh whether to fetch the latest available index types. If this is false, - * index types fetched previously (if available) will be returned. - * @return array all index types in the Sphinx in format: index name => index type. - */ - public function getIndexTypes($refresh = false) - { - if (!isset($this->_indexTypes) || $refresh) { - $this->initIndexesInfo(); - } - return $this->_indexTypes; - } - - /** - * Initializes information about name and type of all index in the Sphinx. - */ - protected function initIndexesInfo() - { - $this->_indexNames = []; - $this->_indexTypes = []; - $indexes = $this->findIndexes(); - foreach ($indexes as $index) { - $indexName = $index['Index']; - $this->_indexNames[] = $indexName; - $this->_indexTypes[$indexName] = $index['Type']; - } - } - - /** - * Returns all index names in the Sphinx. - * @return array all index names in the Sphinx. - */ - protected function findIndexes() - { - $sql = 'SHOW TABLES'; - return $this->db->createCommand($sql)->queryAll(); - } - - /** - * @return QueryBuilder the query builder for this connection. - */ - public function getQueryBuilder() - { - if ($this->_builder === null) { - $this->_builder = $this->createQueryBuilder(); - } - return $this->_builder; - } - - /** - * Determines the PDO type for the given PHP data value. - * @param mixed $data the data whose PDO type is to be determined - * @return integer the PDO type - * @see http://www.php.net/manual/en/pdo.constants.php - */ - public function getPdoType($data) - { - static $typeMap = [ - // php type => PDO type - 'boolean' => \PDO::PARAM_BOOL, - 'integer' => \PDO::PARAM_INT, - 'string' => \PDO::PARAM_STR, - 'resource' => \PDO::PARAM_LOB, - 'NULL' => \PDO::PARAM_NULL, - ]; - $type = gettype($data); - return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR; - } - - /** - * Refreshes the schema. - * This method cleans up all cached index schemas so that they can be re-created later - * to reflect the Sphinx schema change. - */ - public function refresh() - { - /** @var $cache Cache */ - $cache = is_string($this->db->schemaCache) ? Yii::$app->getComponent($this->db->schemaCache) : $this->db->schemaCache; - if ($this->db->enableSchemaCache && $cache instanceof Cache) { - GroupDependency::invalidate($cache, $this->getCacheGroup()); - } - $this->_indexNames = []; - $this->_indexes = []; - } - - /** - * Creates a query builder for the Sphinx. - * @return QueryBuilder query builder instance - */ - public function createQueryBuilder() - { - return new QueryBuilder($this->db); - } - - /** - * Quotes a string value for use in a query. - * Note that if the parameter is not a string, it will be returned without change. - * @param string $str string to be quoted - * @return string the properly quoted string - * @see http://www.php.net/manual/en/function.PDO-quote.php - */ - public function quoteValue($str) - { - if (!is_string($str)) { - return $str; - } - $this->db->open(); - return $this->db->pdo->quote($str); - } - - /** - * Quotes a index name for use in a query. - * If the index name contains schema prefix, the prefix will also be properly quoted. - * If the index name is already quoted or contains '(' or '{{', - * then this method will do nothing. - * @param string $name index name - * @return string the properly quoted index name - * @see quoteSimpleTableName - */ - public function quoteIndexName($name) - { - if (strpos($name, '(') !== false || strpos($name, '{{') !== false) { - return $name; - } - return $this->quoteSimpleIndexName($name); - } - - /** - * Quotes a column name for use in a query. - * If the column name contains prefix, the prefix will also be properly quoted. - * If the column name is already quoted or contains '(', '[[' or '{{', - * then this method will do nothing. - * @param string $name column name - * @return string the properly quoted column name - * @see quoteSimpleColumnName - */ - public function quoteColumnName($name) - { - if (strpos($name, '(') !== false || strpos($name, '[[') !== false || strpos($name, '{{') !== false) { - return $name; - } - if (($pos = strrpos($name, '.')) !== false) { - $prefix = $this->quoteIndexName(substr($name, 0, $pos)) . '.'; - $name = substr($name, $pos + 1); - } else { - $prefix = ''; - } - return $prefix . $this->quoteSimpleColumnName($name); - } - - /** - * Quotes a index name for use in a query. - * A simple index name has no schema prefix. - * @param string $name index name - * @return string the properly quoted index name - */ - public function quoteSimpleIndexName($name) - { - return strpos($name, "`") !== false ? $name : "`" . $name . "`"; - } - - /** - * Quotes a column name for use in a query. - * A simple column name has no prefix. - * @param string $name column name - * @return string the properly quoted column name - */ - public function quoteSimpleColumnName($name) - { - return strpos($name, '`') !== false || $name === '*' ? $name : '`' . $name . '`'; - } - - /** - * Returns the actual name of a given index name. - * This method will strip off curly brackets from the given index name - * and replace the percentage character '%' with [[Connection::indexPrefix]]. - * @param string $name the index name to be converted - * @return string the real name of the given index name - */ - public function getRawIndexName($name) - { - if (strpos($name, '{{') !== false) { - $name = preg_replace('/\\{\\{(.*?)\\}\\}/', '\1', $name); - return str_replace('%', $this->db->tablePrefix, $name); - } else { - return $name; - } - } - - /** - * Extracts the PHP type from abstract DB type. - * @param ColumnSchema $column the column schema information - * @return string PHP type name - */ - protected function getColumnPhpType($column) - { - static $typeMap = [ // abstract type => php type - 'smallint' => 'integer', - 'integer' => 'integer', - 'bigint' => 'integer', - 'boolean' => 'boolean', - 'float' => 'double', - ]; - if (isset($typeMap[$column->type])) { - if ($column->type === 'bigint') { - return PHP_INT_SIZE == 8 ? 'integer' : 'string'; - } elseif ($column->type === 'integer') { - return PHP_INT_SIZE == 4 ? 'string' : 'integer'; - } else { - return $typeMap[$column->type]; - } - } else { - return 'string'; - } - } - - /** - * Collects the metadata of index columns. - * @param IndexSchema $index the index metadata - * @return boolean whether the index exists in the database - * @throws \Exception if DB query fails - */ - protected function findColumns($index) - { - $sql = 'DESCRIBE ' . $this->quoteSimpleIndexName($index->name); - try { - $columns = $this->db->createCommand($sql)->queryAll(); - } catch (\Exception $e) { - $previous = $e->getPrevious(); - if ($previous instanceof \PDOException && $previous->getCode() == '42S02') { - // index does not exist - return false; - } - throw $e; - } - foreach ($columns as $info) { - $column = $this->loadColumnSchema($info); - $index->columns[$column->name] = $column; - if ($column->isPrimaryKey) { - $index->primaryKey = $column->name; - } - } - return true; - } - - /** - * Loads the column information into a [[ColumnSchema]] object. - * @param array $info column information - * @return ColumnSchema the column schema object - */ - protected function loadColumnSchema($info) - { - $column = new ColumnSchema; - - $column->name = $info['Field']; - $column->dbType = $info['Type']; - - $column->isPrimaryKey = ($column->name == 'id'); - - $type = $info['Type']; - if (isset($this->typeMap[$type])) { - $column->type = $this->typeMap[$type]; - } else { - $column->type = self::TYPE_STRING; - } - - $column->isField = ($type == 'field'); - $column->isAttribute = !$column->isField; - - $column->isMva = ($type == 'mva'); - - $column->phpType = $this->getColumnPhpType($column); - - return $column; - } -} \ No newline at end of file diff --git a/extensions/yii/sphinx/composer.json b/extensions/yii/sphinx/composer.json deleted file mode 100644 index 6026022..0000000 --- a/extensions/yii/sphinx/composer.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "yiisoft/yii2-sphinx", - "description": "Sphinx full text search engine extension for the Yii framework", - "keywords": ["yii", "sphinx", "active-record", "search", "fulltext"], - "type": "yii2-extension", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?labels=ext%3Asphinx", - "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-pdo": "*", - "ext-pdo_mysql": "*" - }, - "autoload": { - "psr-0": { "yii\\sphinx\\": "" } - }, - "target-dir": "yii/sphinx" -} diff --git a/extensions/yii/swiftmailer/LICENSE.md b/extensions/yii/swiftmailer/LICENSE.md deleted file mode 100644 index 0bb1a8d..0000000 --- a/extensions/yii/swiftmailer/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/swiftmailer/README.md b/extensions/yii/swiftmailer/README.md deleted file mode 100644 index e21998d..0000000 --- a/extensions/yii/swiftmailer/README.md +++ /dev/null @@ -1,49 +0,0 @@ -SwiftMailer Extension for Yii 2 -=============================== - -This extension provides a `SwiftMailer` mail solution for Yii 2. - -To use this extension, simply add the following code in your application configuration: - -```php -return [ - //.... - 'components' => [ - 'mail' => [ - 'class' => 'yii\swiftmailer\Mailer', - ], - ], -]; -``` - -You can then send an email as follows: - -```php -Yii::$app->mail->compose('contact/html') - ->setFrom('from@domain.com') - ->setTo($form->email) - ->setSubject($form->subject) - ->send(); -``` - -For further instructions refer to the related section in the Yii Definitive Guide. - - -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-swiftmailer "*" -``` - -or add - -```json -"yiisoft/yii2-swiftmailer": "*" -``` - -to the require section of your composer.json. diff --git a/extensions/yii/swiftmailer/composer.json b/extensions/yii/swiftmailer/composer.json deleted file mode 100644 index 0d0953b..0000000 --- a/extensions/yii/swiftmailer/composer.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "yiisoft/yii2-swiftmailer", - "description": "The SwiftMailer integration for the Yii framework", - "keywords": ["yii", "swift", "swiftmailer", "mail", "email", "mailer"], - "type": "yii2-extension", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?labels=ext%3Aswiftmailer", - "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": "*", - "swiftmailer/swiftmailer": "*" - }, - "autoload": { - "psr-0": { "yii\\swiftmailer\\": "" } - }, - "target-dir": "yii/swiftmailer" -} diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md deleted file mode 100644 index 274da89..0000000 --- a/framework/CHANGELOG.md +++ /dev/null @@ -1,107 +0,0 @@ -Yii Framework 2 Change Log -========================== - -2.0.0 beta under development ----------------------------- - -- Bug #1446: Logging while logs are processed causes infinite loop (qiangxue) -- Bug #1497: Localized view files are not correctly returned (mintao) -- Bug #1500: Log messages exported to files are not separated by newlines (omnilight, qiangxue) -- Bug #1504: Debug toolbar isn't loaded successfully in some environments when xdebug is enabled (qiangxue) -- Bug #1509: The SQL for creating Postgres RBAC tables is incorrect (qiangxue) -- Bug #1545: It was not possible to execute db Query twice, params where missing (cebe) -- Bug #1550: fixed the issue that JUI input widgets did not property input IDs. -- Bug #1654: Fixed the issue that a new message source object is generated for every new message being translated (qiangxue) -- Bug #1582: Error messages shown via client-side validation should not be double encoded (qiangxue) -- Bug #1591: StringValidator is accessing undefined property (qiangxue) -- Bug #1597: Added `enableAutoLogin` to basic and advanced application templates so "remember me" now works properly (samdark) -- Bug #1631: Charset is now explicitly set to UTF-8 when serving JSON (samdark) -- Bug #1635: `yii\jui\SliderInput` wasn't properly initialized (samdark) -- Bug #1686: ActiveForm is creating duplicated messages in error summary (qiangxue) -- Bug #1704: Incorrect regexp is used in `Inflector::camelize()` (qiangxue) -- Bug #1710: OpenId auth client does not request required attributes correctly (klimov-paul) -- Bug #1733: Incorrect code about `$_modelClasses` in `DbFixtureManager` (qiangxue) -- Bug #1798: Fixed label attributes for array fields (zhuravljov) -- Bug #1800: Better check for `$_SERVER['HTTPS']` in `yii\web\Request::getIsSecureConnection()` (ginus, samdark) -- Bug #1827: Debugger toolbar is loaded twice if an action is calling `run()` to execute another action (qiangxue) -- Bug: Fixed `Call to a member function registerAssetFiles() on a non-object` in case of wrong `sourcePath` for an asset bundle (samdark) -- Bug: Fixed incorrect event name for `yii\jui\Spinner` (samdark) -- Bug: Json::encode() did not handle objects that implement JsonSerializable interface correctly (cebe) -- Bug: Fixed issue with tabular input on ActiveField::radio() and ActiveField::checkbox() (jom) -- Bug: Fixed the issue that query cache returns the same data for the same SQL but different query methods (qiangxue) -- Bug: Fixed URL parsing so it's now properly giving 404 for URLs like `http://example.com//////site/about` (samdark) -- Enh #46: Added Image extension based on [Imagine library](http://imagine.readthedocs.org) (tonydspaniard) -- Enh #364: Improve Inflector::slug with `intl` transliteration. Improved transliteration char map. (tonydspaniard) -- Enh #797: Added support for validating multiple columns by `UniqueValidator` and `ExistValidator` (qiangxue) -- Enh #802: Added support for retrieving sub-array element or child object property through `ArrayHelper::getValue()` (qiangxue, cebe) -- Enh #1293: Replaced Console::showProgress() with a better approach. See Console::startProgress() for details (cebe) -- Enh #1406: DB Schema support for Oracle Database (p0larbeer, qiangxue) -- Enh #1437: Added ListView::viewParams (qiangxue) -- Enh #1469: ActiveRecord::find() now works with default conditions (default scope) applied by createQuery (cebe) -- Enh #1476: Add yii\web\Session::handler property (nineinchnick) -- Enh #1499: Added `ActionColumn::controller` property to support customizing the controller for handling GridView actions (qiangxue) -- Enh #1523: Query conditions now allow to use the NOT operator (cebe) -- Enh #1552: It is now possible to use multiple bootstrap NavBar in a single page (Alex-Code) -- Enh #1572: Added `yii\web\Controller::createAbsoluteUrl()` (samdark) -- Enh #1579: throw exception when the given AR relation name does not match in a case sensitive manner (qiangxue) -- Enh #1581: Added `ActiveQuery::joinWith()` and `ActiveQuery::innerJoinWith()` to support joining with relations (qiangxue) -- Enh #1601: Added support for tagName and encodeLabel parameters in ButtonDropdown (omnilight) -- Enh #1611: Added `BaseActiveRecord::markAttributeDirty()` (qiangxue) -- Enh #1633: Advanced application template now works with MongoDB by default (samdark) -- Enh #1634: Use masked CSRF tokens to prevent BREACH exploits (qiangxue) -- Enh #1641: Added `BaseActiveRecord::updateAttributes()` (qiangxue) -- Enh #1646: Added postgresql `QueryBuilder::checkIntegrity` and `QueryBuilder::resetSequence` (Ragazzo) -- Enh #1645: Added `Connection::$pdoClass` property (Ragazzo) -- Enh #1681: Added support for automatically adjusting the "for" attribute of label generated by `ActiveField::label()` (qiangxue) -- Enh #1706: Added support for registering a single JS/CSS file with dependency (qiangxue) -- Enh #1773: keyPrefix property of Cache is not restricted to alnum characters anymore, however it is still recommended (cebe) -- Enh #1852: ActiveRecord::tableName() now returns table name using DbConnection::tablePrefix (creocoder) -- Enh: Added `favicon.ico` and `robots.txt` to default application templates (samdark) -- Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue) -- Enh: Support for file aliases in console command 'message' (omnilight) -- Enh: Sort and Pagination can now create absolute URLs (cebe) -- Enh: Added support for using array-typed arguments for console commands (qiangxue) -- Enh: Added support for installing packages conforming to PSR-4 standard (qiangxue) -- Enh: Better exception message when class cannot be loaded (samdark) -- Enh #1839: Added support for getting file extension and basename from uploaded file (anfrantic) -- Chg #1519: `yii\web\User::loginRequired()` now returns the `Response` object instead of exiting the application (qiangxue) -- Chg #1586: `QueryBuilder::buildLikeCondition()` will now escape special characters and use percentage characters by default (qiangxue) -- Chg #1610: `Html::activeCheckboxList()` and `Html::activeRadioList()` will submit an empty string if no checkbox/radio is selected (qiangxue) -- Chg #1643: Added default value for `Captcha::options` (qiangxue) -- Chg #1796: Removed `yii\base\Controller::getActionParams()` (samdark) -- Chg #1835: `CheckboxColumn` now renders checkboxes whose values are the corresponding data key values (qiangxue) -- Chg #1821: Changed default values for yii\db\Connection username and password to null (cebe) -- Chg #1844: `Response::sendFile()` and other file sending methods will not send the response (qiangxue) -- Chg #1852: DbConnection::tablePrefix default value now 'tbl_' (creocoder) -- Chg: Renamed `yii\jui\Widget::clientEventsMap` to `clientEventMap` (qiangxue) -- Chg: Renamed `ActiveRecord::getPopulatedRelations()` to `getRelatedRecords()` (qiangxue) -- Chg: Renamed `attributeName` and `className` to `targetAttribute` and `targetClass` for `UniqueValidator` and `ExistValidator` (qiangxue) -- Chg: Added `yii\widgets\InputWidget::options` (qiangxue) -- Chg: Changed the signature of `urlCreator` and button creators for `yii\gridview\ActionColumn` (qiangxue) -- Chg: Updated HTMLPurified dependency to `4.6.*`. -- Chg: Changed Yii autoloader to support loading PSR-4 classes only (i.e. PEAR-styled classes not supported anymore) (qiangxue) -- Chg: Advanced app template: moved database connection DSN, login and password to `-local` config not to expose it to VCS (samdark) -- New #66: [Auth client library](https://github.com/yiisoft/yii2-authclient) OpenId, OAuth1, OAuth2 clients (klimov-paul) -- New #1393: [Codeception testing framework integration](https://github.com/yiisoft/yii2-codeception) (Ragazzo) -- New #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul) -- New: Yii framework now comes with message translation for various languages including (de, de, es, it, pl, pt-BR, ro, ru, zh_cn) - -2.0.0 alpha, December 1, 2013 ---------------------------- - -- Initial release. -- Official extensions released in this version: - - [Twitter bootstrap 3.0](https://github.com/yiisoft/yii2-bootstrap) - - [Jquery UI](https://github.com/yiisoft/yii2-jui) - - - [Debug Toolbar](https://github.com/yiisoft/yii2-debug) - - [Gii code generator](https://github.com/yiisoft/yii2-gii) - - - [Elasticsearch integration](https://github.com/yiisoft/yii2-elasticsearch): ActiveRecord and Query - - [Redis integration](https://github.com/yiisoft/yii2-redis): ActiveRecord, Cache and Session - - [Sphinx integration](https://github.com/yiisoft/yii2-sphinx): ActiveRecord and Query - - - [Swiftmailer](https://github.com/yiisoft/yii2-swiftmailer) - - - [Smarty View Renderer](https://github.com/yiisoft/yii2-smarty) - - [Twig View Renderer](https://github.com/yiisoft/yii2-twig) diff --git a/framework/LICENSE.md b/framework/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/framework/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/framework/README.md b/framework/README.md deleted file mode 100644 index 2e39742..0000000 --- a/framework/README.md +++ /dev/null @@ -1,24 +0,0 @@ -Yii PHP Framework Version 2 -=========================== - -This is the core framework code of [Yii 2](https://github.com/yiisoft/yii2). - - -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 *" -``` - -or add - -```json -"yiisoft/yii2": "*" -``` - -to the require section of your composer.json. diff --git a/framework/UPGRADE.md b/framework/UPGRADE.md deleted file mode 100644 index 99aced0..0000000 --- a/framework/UPGRADE.md +++ /dev/null @@ -1,9 +0,0 @@ -Upgrading Instructions for Yii Framework v2 -=========================================== - -!!!IMPORTANT!!! - -The following upgrading instructions are cumulative. That is, -if you want to upgrade from version A to version C and there is -version B between A and C, you need to following the instructions -for both A and B. diff --git a/framework/composer.json b/framework/composer.json deleted file mode 100644 index d3ed7e7..0000000 --- a/framework/composer.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "name": "yiisoft/yii2", - "description": "Yii PHP Framework Version 2", - "keywords": ["yii", "framework"], - "homepage": "http://www.yiiframework.com/", - "type": "library", - "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", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "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.*" - }, - "autoload": { - "psr-0": { "yii\\": "" } - } -} diff --git a/framework/yii/.gitignore b/framework/yii/.gitignore deleted file mode 100644 index 6f84e8f..0000000 --- a/framework/yii/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -phpunit.xml -composer.lock - diff --git a/framework/yii/.htaccess b/framework/yii/.htaccess deleted file mode 100644 index 8d2f256..0000000 --- a/framework/yii/.htaccess +++ /dev/null @@ -1 +0,0 @@ -deny from all diff --git a/framework/yii/BaseYii.php b/framework/yii/BaseYii.php deleted file mode 100644 index decffe0..0000000 --- a/framework/yii/BaseYii.php +++ /dev/null @@ -1,533 +0,0 @@ - - * @since 2.0 - */ -class BaseYii -{ - /** - * @var array class map used by the Yii autoloading mechanism. - * The array keys are the class names (without leading backslashes), and the array values - * are the corresponding class file paths (or path aliases). This property mainly affects - * how [[autoload()]] works. - * @see autoload() - */ - public static $classMap = []; - /** - * @var \yii\console\Application|\yii\web\Application the application instance - */ - public static $app; - /** - * @var array registered path aliases - * @see getAlias() - * @see setAlias() - */ - public static $aliases = ['@yii' => __DIR__]; - /** - * @var array initial property values that will be applied to objects newly created via [[createObject]]. - * The array keys are class names without leading backslashes "\", and the array values are the corresponding - * name-value pairs for initializing the created class instances. For example, - * - * ~~~ - * [ - * 'Bar' => [ - * 'prop1' => 'value1', - * 'prop2' => 'value2', - * ], - * 'mycompany\foo\Car' => [ - * 'prop1' => 'value1', - * 'prop2' => 'value2', - * ], - * ] - * ~~~ - * - * @see createObject() - */ - public static $objectConfig = []; - - - /** - * @return string the version of Yii framework - */ - public static function getVersion() - { - return '2.0.0-dev'; - } - - /** - * Translates a path alias into an actual path. - * - * The translation is done according to the following procedure: - * - * 1. If the given alias does not start with '@', it is returned back without change; - * 2. Otherwise, look for the longest registered alias that matches the beginning part - * of the given alias. If it exists, replace the matching part of the given alias with - * the corresponding registered path. - * 3. Throw an exception or return false, depending on the `$throwException` parameter. - * - * For example, by default '@yii' is registered as the alias to the Yii framework directory, - * say '/path/to/yii'. The alias '@yii/web' would then be translated into '/path/to/yii/web'. - * - * If you have registered two aliases '@foo' and '@foo/bar'. Then translating '@foo/bar/config' - * would replace the part '@foo/bar' (instead of '@foo') with the corresponding registered path. - * This is because the longest alias takes precedence. - * - * However, if the alias to be translated is '@foo/barbar/config', then '@foo' will be replaced - * instead of '@foo/bar', because '/' serves as the boundary character. - * - * Note, this method does not check if the returned path exists or not. - * - * @param string $alias the alias to be translated. - * @param boolean $throwException whether to throw an exception if the given alias is invalid. - * If this is false and an invalid alias is given, false will be returned by this method. - * @return string|boolean the path corresponding to the alias, false if the root alias is not previously registered. - * @throws InvalidParamException if the alias is invalid while $throwException is true. - * @see setAlias() - */ - public static function getAlias($alias, $throwException = true) - { - if (strncmp($alias, '@', 1)) { - // not an alias - return $alias; - } - - $pos = strpos($alias, '/'); - $root = $pos === false ? $alias : substr($alias, 0, $pos); - - if (isset(static::$aliases[$root])) { - if (is_string(static::$aliases[$root])) { - return $pos === false ? static::$aliases[$root] : static::$aliases[$root] . substr($alias, $pos); - } else { - foreach (static::$aliases[$root] as $name => $path) { - if (strpos($alias . '/', $name . '/') === 0) { - return $path . substr($alias, strlen($name)); - } - } - } - } - - if ($throwException) { - throw new InvalidParamException("Invalid path alias: $alias"); - } else { - return false; - } - } - - /** - * Returns the root alias part of a given alias. - * A root alias is an alias that has been registered via [[setAlias()]] previously. - * If a given alias matches multiple root aliases, the longest one will be returned. - * @param string $alias the alias - * @return string|boolean the root alias, or false if no root alias is found - */ - public static function getRootAlias($alias) - { - $pos = strpos($alias, '/'); - $root = $pos === false ? $alias : substr($alias, 0, $pos); - - if (isset(static::$aliases[$root])) { - if (is_string(static::$aliases[$root])) { - return $root; - } else { - foreach (static::$aliases[$root] as $name => $path) { - if (strpos($alias . '/', $name . '/') === 0) { - return $name; - } - } - } - } - return false; - } - - /** - * Registers a path alias. - * - * A path alias is a short name representing a long path (a file path, a URL, etc.) - * For example, we use '@yii' as the alias of the path to the Yii framework directory. - * - * A path alias must start with the character '@' so that it can be easily differentiated - * from non-alias paths. - * - * Note that this method does not check if the given path exists or not. All it does is - * to associate the alias with the path. - * - * Any trailing '/' and '\' characters in the given path will be trimmed. - * - * @param string $alias the alias name (e.g. "@yii"). It must start with a '@' character. - * It may contain the forward slash '/' which serves as boundary character when performing - * alias translation by [[getAlias()]]. - * @param string $path the path corresponding to the alias. Trailing '/' and '\' characters - * will be trimmed. This can be - * - * - a directory or a file path (e.g. `/tmp`, `/tmp/main.txt`) - * - a URL (e.g. `http://www.yiiframework.com`) - * - a path alias (e.g. `@yii/base`). In this case, the path alias will be converted into the - * actual path first by calling [[getAlias()]]. - * - * @throws InvalidParamException if $path is an invalid alias. - * @see getAlias() - */ - public static function setAlias($alias, $path) - { - if (strncmp($alias, '@', 1)) { - $alias = '@' . $alias; - } - $pos = strpos($alias, '/'); - $root = $pos === false ? $alias : substr($alias, 0, $pos); - if ($path !== null) { - $path = strncmp($path, '@', 1) ? rtrim($path, '\\/') : static::getAlias($path); - if (!isset(static::$aliases[$root])) { - if ($pos === false) { - static::$aliases[$root] = $path; - } else { - static::$aliases[$root] = [$alias => $path]; - } - } elseif (is_string(static::$aliases[$root])) { - if ($pos === false) { - static::$aliases[$root] = $path; - } else { - static::$aliases[$root] = [ - $alias => $path, - $root => static::$aliases[$root], - ]; - } - } else { - static::$aliases[$root][$alias] = $path; - krsort(static::$aliases[$root]); - } - } elseif (isset(static::$aliases[$root])) { - if (is_array(static::$aliases[$root])) { - unset(static::$aliases[$root][$alias]); - } elseif ($pos === false) { - unset(static::$aliases[$root]); - } - } - } - - /** - * Class autoload loader. - * This method is invoked automatically when PHP sees an unknown class. - * The method will attempt to include the class file according to the following procedure: - * - * 1. Search in [[classMap]]; - * 2. If the class is namespaced (e.g. `yii\base\Component`), it will attempt - * to include the file associated with the corresponding path alias - * (e.g. `@yii/base/Component.php`); - * - * This autoloader allows loading classes that follow the [PSR-4 standard](http://www.php-fig.org/psr/psr-4/) - * and have its top-level namespace or sub-namespaces defined as path aliases. - * - * Example: When aliases `@yii` and `@yii/bootstrap` are defined, classes in the `yii\bootstrap` namespace - * will be loaded using the `@yii/bootstrap` alias which points to the directory where bootstrap extension - * files are installed and all classes from other `yii` namespaces will be loaded from the yii framework directory. - * - * @param string $className the fully qualified class name without a leading backslash "\" - * @throws UnknownClassException if the class does not exist in the class file - */ - public static function autoload($className) - { - if (isset(static::$classMap[$className])) { - $classFile = static::$classMap[$className]; - if ($classFile[0] === '@') { - $classFile = static::getAlias($classFile); - } - } elseif (strpos($className, '\\') !== false) { - $classFile = static::getAlias('@' . str_replace('\\', '/', $className) . '.php', false); - if ($classFile === false || !is_file($classFile)) { - return; - } - } else { - return; - } - - include($classFile); - - if (YII_DEBUG && !class_exists($className, false) && !interface_exists($className, false) && !trait_exists($className, false)) { - throw new UnknownClassException("Unable to find '$className' in file: $classFile. Namespace missing?"); - } - } - - /** - * Creates a new object using the given configuration. - * - * The configuration can be either a string or an array. - * If a string, it is treated as the *object class*; if an array, - * it must contain a `class` element specifying the *object class*, and - * the rest of the name-value pairs in the array will be used to initialize - * the corresponding object properties. - * - * Below are some usage examples: - * - * ~~~ - * $object = \Yii::createObject('app\components\GoogleMap'); - * $object = \Yii::createObject([ - * 'class' => 'app\components\GoogleMap', - * 'apiKey' => 'xyz', - * ]); - * ~~~ - * - * This method can be used to create any object as long as the object's constructor is - * defined like the following: - * - * ~~~ - * public function __construct(..., $config = []) { - * } - * ~~~ - * - * The method will pass the given configuration as the last parameter of the constructor, - * and any additional parameters to this method will be passed as the rest of the constructor parameters. - * - * @param string|array $config the configuration. It can be either a string representing the class name - * or an array representing the object configuration. - * @return mixed the created object - * @throws InvalidConfigException if the configuration is invalid. - */ - public static function createObject($config) - { - static $reflections = []; - - if (is_string($config)) { - $class = $config; - $config = []; - } elseif (isset($config['class'])) { - $class = $config['class']; - unset($config['class']); - } else { - throw new InvalidConfigException('Object configuration must be an array containing a "class" element.'); - } - - $class = ltrim($class, '\\'); - - if (isset(static::$objectConfig[$class])) { - $config = array_merge(static::$objectConfig[$class], $config); - } - - if (($n = func_num_args()) > 1) { - /** @var \ReflectionClass $reflection */ - if (isset($reflections[$class])) { - $reflection = $reflections[$class]; - } else { - $reflection = $reflections[$class] = new \ReflectionClass($class); - } - $args = func_get_args(); - array_shift($args); // remove $config - if (!empty($config)) { - $args[] = $config; - } - return $reflection->newInstanceArgs($args); - } else { - return empty($config) ? new $class : new $class($config); - } - } - - /** - * Logs a trace message. - * Trace messages are logged mainly for development purpose to see - * the execution work flow of some code. - * @param string $message the message to be logged. - * @param string $category the category of the message. - */ - public static function trace($message, $category = 'application') - { - if (YII_DEBUG) { - static::$app->getLog()->log($message, Logger::LEVEL_TRACE, $category); - } - } - - /** - * Logs an error message. - * An error message is typically logged when an unrecoverable error occurs - * during the execution of an application. - * @param string $message the message to be logged. - * @param string $category the category of the message. - */ - public static function error($message, $category = 'application') - { - static::$app->getLog()->log($message, Logger::LEVEL_ERROR, $category); - } - - /** - * Logs a warning message. - * A warning message is typically logged when an error occurs while the execution - * can still continue. - * @param string $message the message to be logged. - * @param string $category the category of the message. - */ - public static function warning($message, $category = 'application') - { - static::$app->getLog()->log($message, Logger::LEVEL_WARNING, $category); - } - - /** - * Logs an informative message. - * An informative message is typically logged by an application to keep record of - * something important (e.g. an administrator logs in). - * @param string $message the message to be logged. - * @param string $category the category of the message. - */ - public static function info($message, $category = 'application') - { - static::$app->getLog()->log($message, Logger::LEVEL_INFO, $category); - } - - /** - * Marks the beginning of a code block for profiling. - * This has to be matched with a call to [[endProfile]] with the same category name. - * The begin- and end- calls must also be properly nested. For example, - * - * ~~~ - * \Yii::beginProfile('block1'); - * // some code to be profiled - * \Yii::beginProfile('block2'); - * // some other code to be profiled - * \Yii::endProfile('block2'); - * \Yii::endProfile('block1'); - * ~~~ - * @param string $token token for the code block - * @param string $category the category of this log message - * @see endProfile() - */ - public static function beginProfile($token, $category = 'application') - { - static::$app->getLog()->log($token, Logger::LEVEL_PROFILE_BEGIN, $category); - } - - /** - * Marks the end of a code block for profiling. - * This has to be matched with a previous call to [[beginProfile]] with the same category name. - * @param string $token token for the code block - * @param string $category the category of this log message - * @see beginProfile() - */ - public static function endProfile($token, $category = 'application') - { - static::$app->getLog()->log($token, Logger::LEVEL_PROFILE_END, $category); - } - - /** - * Returns an HTML hyperlink that can be displayed on your Web page showing Powered by Yii" information. - * @return string an HTML hyperlink that can be displayed on your Web page showing Powered by Yii" information - */ - public static function powered() - { - return 'Powered by Yii Framework'; - } - - /** - * Translates a message to the specified language. - * - * This is a shortcut method of [[\yii\i18n\I18N::translate()]]. - * - * The translation will be conducted according to the message category and the target language will be used. - * - * In case when a translated message has different plural forms (separated by "|"), this method - * will also attempt to choose an appropriate one according to a given numeric value which is - * specified as the first parameter (indexed by 0) in `$params`. - * - * For example, if a translated message is "I have an apple.|I have {n} apples.", and the first - * parameter is 2, the message returned will be "I have 2 apples.". Note that the placeholder "{n}" - * will be replaced with the given number. - * - * For more details on how plural rules are applied, please refer to: - * - * - * @param string $category the message category. - * @param string $message the message to be translated. - * @param array $params the parameters that will be used to replace the corresponding placeholders in the message. - * @param string $language the language code (e.g. `en-US`, `en`). If this is null, the current - * [[\yii\base\Application::language|application language]] will be used. - * @return string the translated message. - */ - public static function t($category, $message, $params = [], $language = null) - { - if (static::$app !== null) { - return static::$app->getI18n()->translate($category, $message, $params, $language ?: static::$app->language); - } else { - $p = []; - foreach ((array) $params as $name => $value) { - $p['{' . $name . '}'] = $value; - } - return ($p === []) ? $message : strtr($message, $p); - } - } - - /** - * Configures an object with the initial property values. - * @param object $object the object to be configured - * @param array $properties the property initial values given in terms of name-value pairs. - * @return object the object itself - */ - public static function configure($object, $properties) - { - foreach ($properties as $name => $value) { - $object->$name = $value; - } - return $object; - } - - /** - * Returns the public member variables of an object. - * This method is provided such that we can get the public member variables of an object. - * It is different from "get_object_vars()" because the latter will return private - * and protected variables if it is called within the object itself. - * @param object $object the object to be handled - * @return array the public member variables of the object - */ - public static function getObjectVars($object) - { - return get_object_vars($object); - } -} diff --git a/framework/yii/Yii.php b/framework/yii/Yii.php deleted file mode 100644 index b095c17..0000000 --- a/framework/yii/Yii.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @since 2.0 - */ -class Yii extends \yii\BaseYii -{ -} - -spl_autoload_register(['Yii', 'autoload'], true, true); -Yii::$classMap = include(__DIR__ . '/classes.php'); diff --git a/framework/yii/assets/jquery.maskedinput.js b/framework/yii/assets/jquery.maskedinput.js deleted file mode 100644 index 902b5d3..0000000 --- a/framework/yii/assets/jquery.maskedinput.js +++ /dev/null @@ -1,338 +0,0 @@ -/* - Masked Input plugin for jQuery - Copyright (c) 2007-2013 Josh Bush (digitalbush.com) - Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license) - Version: 1.3.1 -*/ -(function($) { - function getPasteEvent() { - var el = document.createElement('input'), - name = 'onpaste'; - el.setAttribute(name, ''); - return (typeof el[name] === 'function')?'paste':'input'; -} - -var pasteEventName = getPasteEvent() + ".mask", - ua = navigator.userAgent, - iPhone = /iphone/i.test(ua), - android=/android/i.test(ua), - caretTimeoutId; - -$.mask = { - //Predefined character definitions - definitions: { - '9': "[0-9]", - 'a': "[A-Za-z]", - '*': "[A-Za-z0-9]" - }, - dataName: "rawMaskFn", - placeholder: '_', -}; - -$.fn.extend({ - //Helper Function for Caret positioning - caret: function(begin, end) { - var range; - - if (this.length === 0 || this.is(":hidden")) { - return; - } - - if (typeof begin == 'number') { - end = (typeof end === 'number') ? end : begin; - return this.each(function() { - if (this.setSelectionRange) { - this.setSelectionRange(begin, end); - } else if (this.createTextRange) { - range = this.createTextRange(); - range.collapse(true); - range.moveEnd('character', end); - range.moveStart('character', begin); - range.select(); - } - }); - } else { - if (this[0].setSelectionRange) { - begin = this[0].selectionStart; - end = this[0].selectionEnd; - } else if (document.selection && document.selection.createRange) { - range = document.selection.createRange(); - begin = 0 - range.duplicate().moveStart('character', -100000); - end = begin + range.text.length; - } - return { begin: begin, end: end }; - } - }, - unmask: function() { - return this.trigger("unmask"); - }, - mask: function(mask, settings) { - var input, - defs, - tests, - partialPosition, - firstNonMaskPos, - len; - - if (!mask && this.length > 0) { - input = $(this[0]); - return input.data($.mask.dataName)(); - } - settings = $.extend({ - placeholder: $.mask.placeholder, // Load default placeholder - completed: null - }, settings); - - - defs = $.mask.definitions; - tests = []; - partialPosition = len = mask.length; - firstNonMaskPos = null; - - $.each(mask.split(""), function(i, c) { - if (c == '?') { - len--; - partialPosition = i; - } else if (defs[c]) { - tests.push(new RegExp(defs[c])); - if (firstNonMaskPos === null) { - firstNonMaskPos = tests.length - 1; - } - } else { - tests.push(null); - } - }); - - return this.trigger("unmask").each(function() { - var input = $(this), - buffer = $.map( - mask.split(""), - function(c, i) { - if (c != '?') { - return defs[c] ? settings.placeholder : c; - } - }), - focusText = input.val(); - - function seekNext(pos) { - while (++pos < len && !tests[pos]); - return pos; - } - - function seekPrev(pos) { - while (--pos >= 0 && !tests[pos]); - return pos; - } - - function shiftL(begin,end) { - var i, - j; - - if (begin<0) { - return; - } - - for (i = begin, j = seekNext(end); i < len; i++) { - if (tests[i]) { - if (j < len && tests[i].test(buffer[j])) { - buffer[i] = buffer[j]; - buffer[j] = settings.placeholder; - } else { - break; - } - - j = seekNext(j); - } - } - writeBuffer(); - input.caret(Math.max(firstNonMaskPos, begin)); - } - - function shiftR(pos) { - var i, - c, - j, - t; - - for (i = pos, c = settings.placeholder; i < len; i++) { - if (tests[i]) { - j = seekNext(i); - t = buffer[i]; - buffer[i] = c; - if (j < len && tests[j].test(t)) { - c = t; - } else { - break; - } - } - } - } - - function keydownEvent(e) { - var k = e.which, - pos, - begin, - end; - - //backspace, delete, and escape get special treatment - if (k === 8 || k === 46 || (iPhone && k === 127)) { - pos = input.caret(); - begin = pos.begin; - end = pos.end; - - if (end - begin === 0) { - begin=k!==46?seekPrev(begin):(end=seekNext(begin-1)); - end=k===46?seekNext(end):end; - } - clearBuffer(begin, end); - shiftL(begin, end - 1); - - e.preventDefault(); - } else if (k == 27) {//escape - input.val(focusText); - input.caret(0, checkVal()); - e.preventDefault(); - } - } - - function keypressEvent(e) { - var k = e.which, - pos = input.caret(), - p, - c, - next; - - if (e.ctrlKey || e.altKey || e.metaKey || k < 32) {//Ignore - return; - } else if (k) { - if (pos.end - pos.begin !== 0){ - clearBuffer(pos.begin, pos.end); - shiftL(pos.begin, pos.end-1); - } - - p = seekNext(pos.begin - 1); - if (p < len) { - c = String.fromCharCode(k); - if (tests[p].test(c)) { - shiftR(p); - - buffer[p] = c; - writeBuffer(); - next = seekNext(p); - - if(android){ - setTimeout($.proxy($.fn.caret,input,next),0); - }else{ - input.caret(next); - } - - if (settings.completed && next >= len) { - settings.completed.call(input); - } - } - } - e.preventDefault(); - } - } - - function clearBuffer(start, end) { - var i; - for (i = start; i < end && i < len; i++) { - if (tests[i]) { - buffer[i] = settings.placeholder; - } - } - } - - function writeBuffer() { input.val(buffer.join('')); } - - function checkVal(allow) { - //try to place characters where they belong - var test = input.val(), - lastMatch = -1, - i, - c; - - for (i = 0, pos = 0; i < len; i++) { - if (tests[i]) { - buffer[i] = settings.placeholder; - while (pos++ < test.length) { - c = test.charAt(pos - 1); - if (tests[i].test(c)) { - buffer[i] = c; - lastMatch = i; - break; - } - } - if (pos > test.length) { - break; - } - } else if (buffer[i] === test.charAt(pos) && i !== partialPosition) { - pos++; - lastMatch = i; - } - } - if (allow) { - writeBuffer(); - } else if (lastMatch + 1 < partialPosition) { - input.val(""); - clearBuffer(0, len); - } else { - writeBuffer(); - input.val(input.val().substring(0, lastMatch + 1)); - } - return (partialPosition ? i : firstNonMaskPos); - } - - input.data($.mask.dataName,function(){ - return $.map(buffer, function(c, i) { - return tests[i]&&c!=settings.placeholder ? c : null; - }).join(''); - }); - - if (!input.attr("readonly")) - input - .one("unmask", function() { - input - .unbind(".mask") - .removeData($.mask.dataName); - }) - .bind("focus.mask", function() { - clearTimeout(caretTimeoutId); - var pos, - moveCaret; - - focusText = input.val(); - pos = checkVal(); - - caretTimeoutId = setTimeout(function(){ - writeBuffer(); - if (pos == mask.length) { - input.caret(0, pos); - } else { - input.caret(pos); - } - }, 10); - }) - .bind("blur.mask", function() { - checkVal(); - if (input.val() != focusText) - input.change(); - }) - .bind("keydown.mask", keydownEvent) - .bind("keypress.mask", keypressEvent) - .bind(pasteEventName, function() { - setTimeout(function() { - var pos=checkVal(true); - input.caret(pos); - if (settings.completed && pos == input.val().length) - settings.completed.call(input); - }, 0); - }); - checkVal(); //Perform initial check for existing values - }); - } -}); - - -})(jQuery); \ No newline at end of file diff --git a/framework/yii/assets/punycode/LICENSE-GPL.txt b/framework/yii/assets/punycode/LICENSE-GPL.txt deleted file mode 100644 index 11dddd0..0000000 --- a/framework/yii/assets/punycode/LICENSE-GPL.txt +++ /dev/null @@ -1,278 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. diff --git a/framework/yii/assets/punycode/LICENSE-MIT.txt b/framework/yii/assets/punycode/LICENSE-MIT.txt deleted file mode 100644 index 97067e5..0000000 --- a/framework/yii/assets/punycode/LICENSE-MIT.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright Mathias Bynens - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/framework/yii/assets/punycode/punycode.js b/framework/yii/assets/punycode/punycode.js deleted file mode 100644 index 6242382..0000000 --- a/framework/yii/assets/punycode/punycode.js +++ /dev/null @@ -1,502 +0,0 @@ -/*! http://mths.be/punycode v1.2.1 by @mathias */ -;(function(root) { - - /** Detect free variables */ - var freeExports = typeof exports == 'object' && exports; - var freeModule = typeof module == 'object' && module && - module.exports == freeExports && module; - var freeGlobal = typeof global == 'object' && global; - if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { - root = freeGlobal; - } - - /** - * The `punycode` object. - * @name punycode - * @type Object - */ - var punycode, - - /** Highest positive signed 32-bit float value */ - maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1 - - /** Bootstring parameters */ - base = 36, - tMin = 1, - tMax = 26, - skew = 38, - damp = 700, - initialBias = 72, - initialN = 128, // 0x80 - delimiter = '-', // '\x2D' - - /** Regular expressions */ - regexPunycode = /^xn--/, - regexNonASCII = /[^ -~]/, // unprintable ASCII chars + non-ASCII chars - regexSeparators = /\x2E|\u3002|\uFF0E|\uFF61/g, // RFC 3490 separators - - /** Error messages */ - errors = { - 'overflow': 'Overflow: input needs wider integers to process', - 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', - 'invalid-input': 'Invalid input' - }, - - /** Convenience shortcuts */ - baseMinusTMin = base - tMin, - floor = Math.floor, - stringFromCharCode = String.fromCharCode, - - /** Temporary variable */ - key; - - /*--------------------------------------------------------------------------*/ - - /** - * A generic error utility function. - * @private - * @param {String} type The error type. - * @returns {Error} Throws a `RangeError` with the applicable error message. - */ - function error(type) { - throw RangeError(errors[type]); - } - - /** - * A generic `Array#map` utility function. - * @private - * @param {Array} array The array to iterate over. - * @param {Function} callback The function that gets called for every array - * item. - * @returns {Array} A new array of values returned by the callback function. - */ - function map(array, fn) { - var length = array.length; - while (length--) { - array[length] = fn(array[length]); - } - return array; - } - - /** - * A simple `Array#map`-like wrapper to work with domain name strings. - * @private - * @param {String} domain The domain name. - * @param {Function} callback The function that gets called for every - * character. - * @returns {Array} A new string of characters returned by the callback - * function. - */ - function mapDomain(string, fn) { - return map(string.split(regexSeparators), fn).join('.'); - } - - /** - * Creates an array containing the decimal code points of each Unicode - * character in the string. While JavaScript uses UCS-2 internally, - * this function will convert a pair of surrogate halves (each of which - * UCS-2 exposes as separate characters) into a single code point, - * matching UTF-16. - * @see `punycode.ucs2.encode` - * @see - * @memberOf punycode.ucs2 - * @name decode - * @param {String} string The Unicode input string (UCS-2). - * @returns {Array} The new array of code points. - */ - function ucs2decode(string) { - var output = [], - counter = 0, - length = string.length, - value, - extra; - while (counter < length) { - value = string.charCodeAt(counter++); - if ((value & 0xF800) == 0xD800 && counter < length) { - // high surrogate, and there is a next character - extra = string.charCodeAt(counter++); - if ((extra & 0xFC00) == 0xDC00) { // low surrogate - output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); - } else { - output.push(value, extra); - } - } else { - output.push(value); - } - } - return output; - } - - /** - * Creates a string based on an array of decimal code points. - * @see `punycode.ucs2.decode` - * @memberOf punycode.ucs2 - * @name encode - * @param {Array} codePoints The array of decimal code points. - * @returns {String} The new Unicode string (UCS-2). - */ - function ucs2encode(array) { - return map(array, function(value) { - var output = ''; - if (value > 0xFFFF) { - value -= 0x10000; - output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); - value = 0xDC00 | value & 0x3FF; - } - output += stringFromCharCode(value); - return output; - }).join(''); - } - - /** - * Converts a basic code point into a digit/integer. - * @see `digitToBasic()` - * @private - * @param {Number} codePoint The basic (decimal) code point. - * @returns {Number} The numeric value of a basic code point (for use in - * representing integers) in the range `0` to `base - 1`, or `base` if - * the code point does not represent a value. - */ - function basicToDigit(codePoint) { - return codePoint - 48 < 10 - ? codePoint - 22 - : codePoint - 65 < 26 - ? codePoint - 65 - : codePoint - 97 < 26 - ? codePoint - 97 - : base; - } - - /** - * Converts a digit/integer into a basic code point. - * @see `basicToDigit()` - * @private - * @param {Number} digit The numeric value of a basic code point. - * @returns {Number} The basic code point whose value (when used for - * representing integers) is `digit`, which needs to be in the range - * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is - * used; else, the lowercase form is used. The behavior is undefined - * if flag is non-zero and `digit` has no uppercase form. - */ - function digitToBasic(digit, flag) { - // 0..25 map to ASCII a..z or A..Z - // 26..35 map to ASCII 0..9 - return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); - } - - /** - * Bias adaptation function as per section 3.4 of RFC 3492. - * http://tools.ietf.org/html/rfc3492#section-3.4 - * @private - */ - function adapt(delta, numPoints, firstTime) { - var k = 0; - delta = firstTime ? floor(delta / damp) : delta >> 1; - delta += floor(delta / numPoints); - for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { - delta = floor(delta / baseMinusTMin); - } - return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); - } - - /** - * Converts a Punycode string of ASCII code points to a string of Unicode - * code points. - * @memberOf punycode - * @param {String} input The Punycode string of ASCII code points. - * @returns {String} The resulting string of Unicode code points. - */ - function decode(input) { - // Don't use UCS-2 - var output = [], - inputLength = input.length, - out, - i = 0, - n = initialN, - bias = initialBias, - basic, - j, - index, - oldi, - w, - k, - digit, - t, - length, - /** Cached calculation results */ - baseMinusT; - - // Handle the basic code points: let `basic` be the number of input code - // points before the last delimiter, or `0` if there is none, then copy - // the first basic code points to the output. - - basic = input.lastIndexOf(delimiter); - if (basic < 0) { - basic = 0; - } - - for (j = 0; j < basic; ++j) { - // if it's not a basic code point - if (input.charCodeAt(j) >= 0x80) { - error('not-basic'); - } - output.push(input.charCodeAt(j)); - } - - // Main decoding loop: start just after the last delimiter if any basic code - // points were copied; start at the beginning otherwise. - - for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { - - // `index` is the index of the next character to be consumed. - // Decode a generalized variable-length integer into `delta`, - // which gets added to `i`. The overflow checking is easier - // if we increase `i` as we go, then subtract off its starting - // value at the end to obtain `delta`. - for (oldi = i, w = 1, k = base; /* no condition */; k += base) { - - if (index >= inputLength) { - error('invalid-input'); - } - - digit = basicToDigit(input.charCodeAt(index++)); - - if (digit >= base || digit > floor((maxInt - i) / w)) { - error('overflow'); - } - - i += digit * w; - t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); - - if (digit < t) { - break; - } - - baseMinusT = base - t; - if (w > floor(maxInt / baseMinusT)) { - error('overflow'); - } - - w *= baseMinusT; - - } - - out = output.length + 1; - bias = adapt(i - oldi, out, oldi == 0); - - // `i` was supposed to wrap around from `out` to `0`, - // incrementing `n` each time, so we'll fix that now: - if (floor(i / out) > maxInt - n) { - error('overflow'); - } - - n += floor(i / out); - i %= out; - - // Insert `n` at position `i` of the output - output.splice(i++, 0, n); - - } - - return ucs2encode(output); - } - - /** - * Converts a string of Unicode code points to a Punycode string of ASCII - * code points. - * @memberOf punycode - * @param {String} input The string of Unicode code points. - * @returns {String} The resulting Punycode string of ASCII code points. - */ - function encode(input) { - var n, - delta, - handledCPCount, - basicLength, - bias, - j, - m, - q, - k, - t, - currentValue, - output = [], - /** `inputLength` will hold the number of code points in `input`. */ - inputLength, - /** Cached calculation results */ - handledCPCountPlusOne, - baseMinusT, - qMinusT; - - // Convert the input in UCS-2 to Unicode - input = ucs2decode(input); - - // Cache the length - inputLength = input.length; - - // Initialize the state - n = initialN; - delta = 0; - bias = initialBias; - - // Handle the basic code points - for (j = 0; j < inputLength; ++j) { - currentValue = input[j]; - if (currentValue < 0x80) { - output.push(stringFromCharCode(currentValue)); - } - } - - handledCPCount = basicLength = output.length; - - // `handledCPCount` is the number of code points that have been handled; - // `basicLength` is the number of basic code points. - - // Finish the basic string - if it is not empty - with a delimiter - if (basicLength) { - output.push(delimiter); - } - - // Main encoding loop: - while (handledCPCount < inputLength) { - - // All non-basic code points < n have been handled already. Find the next - // larger one: - for (m = maxInt, j = 0; j < inputLength; ++j) { - currentValue = input[j]; - if (currentValue >= n && currentValue < m) { - m = currentValue; - } - } - - // Increase `delta` enough to advance the decoder's state to , - // but guard against overflow - handledCPCountPlusOne = handledCPCount + 1; - if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { - error('overflow'); - } - - delta += (m - n) * handledCPCountPlusOne; - n = m; - - for (j = 0; j < inputLength; ++j) { - currentValue = input[j]; - - if (currentValue < n && ++delta > maxInt) { - error('overflow'); - } - - if (currentValue == n) { - // Represent delta as a generalized variable-length integer - for (q = delta, k = base; /* no condition */; k += base) { - t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); - if (q < t) { - break; - } - qMinusT = q - t; - baseMinusT = base - t; - output.push( - stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) - ); - q = floor(qMinusT / baseMinusT); - } - - output.push(stringFromCharCode(digitToBasic(q, 0))); - bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); - delta = 0; - ++handledCPCount; - } - } - - ++delta; - ++n; - - } - return output.join(''); - } - - /** - * Converts a Punycode string representing a domain name to Unicode. Only the - * Punycoded parts of the domain name will be converted, i.e. it doesn't - * matter if you call it on a string that has already been converted to - * Unicode. - * @memberOf punycode - * @param {String} domain The Punycode domain name to convert to Unicode. - * @returns {String} The Unicode representation of the given Punycode - * string. - */ - function toUnicode(domain) { - return mapDomain(domain, function(string) { - return regexPunycode.test(string) - ? decode(string.slice(4).toLowerCase()) - : string; - }); - } - - /** - * Converts a Unicode string representing a domain name to Punycode. Only the - * non-ASCII parts of the domain name will be converted, i.e. it doesn't - * matter if you call it with a domain that's already in ASCII. - * @memberOf punycode - * @param {String} domain The domain name to convert, as a Unicode string. - * @returns {String} The Punycode representation of the given domain name. - */ - function toASCII(domain) { - return mapDomain(domain, function(string) { - return regexNonASCII.test(string) - ? 'xn--' + encode(string) - : string; - }); - } - - /*--------------------------------------------------------------------------*/ - - /** Define the public API */ - punycode = { - /** - * A string representing the current Punycode.js version number. - * @memberOf punycode - * @type String - */ - 'version': '1.2.1', - /** - * An object of methods to convert from JavaScript's internal character - * representation (UCS-2) to decimal Unicode code points, and back. - * @see - * @memberOf punycode - * @type Object - */ - 'ucs2': { - 'decode': ucs2decode, - 'encode': ucs2encode - }, - 'decode': decode, - 'encode': encode, - 'toASCII': toASCII, - 'toUnicode': toUnicode - }; - - /** Expose `punycode` */ - // Some AMD build optimizers, like r.js, check for specific condition patterns - // like the following: - if ( - typeof define == 'function' && - typeof define.amd == 'object' && - define.amd - ) { - define(function() { - return punycode; - }); - } else if (freeExports && !freeExports.nodeType) { - if (freeModule) { // in Node.js or RingoJS v0.8.0+ - freeModule.exports = punycode; - } else { // in Narwhal or RingoJS v0.7.0- - for (key in punycode) { - punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); - } - } - } else { // in Rhino or a web browser - root.punycode = punycode; - } - -}(this)); diff --git a/framework/yii/assets/punycode/punycode.min.js b/framework/yii/assets/punycode/punycode.min.js deleted file mode 100644 index a61badf..0000000 --- a/framework/yii/assets/punycode/punycode.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! http://mths.be/punycode v1.2.1 by @mathias */ -(function(o){function e(o){throw RangeError(L[o])}function n(o,e){for(var n=o.length;n--;)o[n]=e(o[n]);return o}function t(o,e){return n(o.split(S),e).join(".")}function r(o){for(var e,n,t=[],r=0,u=o.length;u>r;)e=o.charCodeAt(r++),55296==(63488&e)&&u>r?(n=o.charCodeAt(r++),56320==(64512&n)?t.push(((1023&e)<<10)+(1023&n)+65536):t.push(e,n)):t.push(e);return t}function u(o){return n(o,function(o){var e="";return o>65535&&(o-=65536,e+=R(55296|1023&o>>>10),o=56320|1023&o),e+=R(o)}).join("")}function i(o){return 10>o-48?o-22:26>o-65?o-65:26>o-97?o-97:x}function f(o,e){return o+22+75*(26>o)-((0!=e)<<5)}function c(o,e,n){var t=0;for(o=n?P(o/m):o>>1,o+=P(o/e);o>M*y>>1;t+=x)o=P(o/M);return P(t+(M+1)*o/(o+j))}function l(o){var n,t,r,f,l,d,s,a,p,h,v=[],g=o.length,w=0,j=I,m=A;for(t=o.lastIndexOf(F),0>t&&(t=0),r=0;t>r;++r)o.charCodeAt(r)>=128&&e("not-basic"),v.push(o.charCodeAt(r));for(f=t>0?t+1:0;g>f;){for(l=w,d=1,s=x;f>=g&&e("invalid-input"),a=i(o.charCodeAt(f++)),(a>=x||a>P((b-w)/d))&&e("overflow"),w+=a*d,p=m>=s?C:s>=m+y?y:s-m,!(p>a);s+=x)h=x-p,d>P(b/h)&&e("overflow"),d*=h;n=v.length+1,m=c(w-l,n,0==l),P(w/n)>b-j&&e("overflow"),j+=P(w/n),w%=n,v.splice(w++,0,j)}return u(v)}function d(o){var n,t,u,i,l,d,s,a,p,h,v,g,w,j,m,E=[];for(o=r(o),g=o.length,n=I,t=0,l=A,d=0;g>d;++d)v=o[d],128>v&&E.push(R(v));for(u=i=E.length,i&&E.push(F);g>u;){for(s=b,d=0;g>d;++d)v=o[d],v>=n&&s>v&&(s=v);for(w=u+1,s-n>P((b-t)/w)&&e("overflow"),t+=(s-n)*w,n=s,d=0;g>d;++d)if(v=o[d],n>v&&++t>b&&e("overflow"),v==n){for(a=t,p=x;h=l>=p?C:p>=l+y?y:p-l,!(h>a);p+=x)m=a-h,j=x-h,E.push(R(f(h+m%j,0))),a=P(m/j);E.push(R(f(a,0))),l=c(t,w,u==i),t=0,++u}++t,++n}return E.join("")}function s(o){return t(o,function(o){return E.test(o)?l(o.slice(4).toLowerCase()):o})}function a(o){return t(o,function(o){return O.test(o)?"xn--"+d(o):o})}var p="object"==typeof exports&&exports,h="object"==typeof module&&module&&module.exports==p&&module,v="object"==typeof global&&global;(v.global===v||v.window===v)&&(o=v);var g,w,b=2147483647,x=36,C=1,y=26,j=38,m=700,A=72,I=128,F="-",E=/^xn--/,O=/[^ -~]/,S=/\x2E|\u3002|\uFF0E|\uFF61/g,L={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},M=x-C,P=Math.floor,R=String.fromCharCode;if(g={version:"1.2.1",ucs2:{decode:r,encode:u},decode:l,encode:d,toASCII:a,toUnicode:s},"function"==typeof define&&"object"==typeof define.amd&&define.amd)define(function(){return g});else if(p&&!p.nodeType)if(h)h.exports=g;else for(w in g)g.hasOwnProperty(w)&&(p[w]=g[w]);else o.punycode=g})(this); \ No newline at end of file diff --git a/framework/yii/assets/yii.activeForm.js b/framework/yii/assets/yii.activeForm.js deleted file mode 100644 index d4fc877..0000000 --- a/framework/yii/assets/yii.activeForm.js +++ /dev/null @@ -1,400 +0,0 @@ -/** - * Yii form widget. - * - * This is the JavaScript widget used by the yii\widgets\ActiveForm widget. - * - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - * @author Qiang Xue - * @since 2.0 - */ -(function ($) { - - $.fn.yiiActiveForm = function (method) { - if (methods[method]) { - return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); - } else if (typeof method === 'object' || !method) { - return methods.init.apply(this, arguments); - } else { - $.error('Method ' + method + ' does not exist on jQuery.yiiActiveForm'); - return false; - } - }; - - var defaults = { - // the jQuery selector for the error summary - errorSummary: undefined, - // whether to perform validation before submitting the form. - validateOnSubmit: true, - // the container CSS class representing the corresponding attribute has validation error - errorCssClass: 'error', - // the container CSS class representing the corresponding attribute passes validation - successCssClass: 'success', - // the container CSS class representing the corresponding attribute is being validated - validatingCssClass: 'validating', - // the URL for performing AJAX-based validation. If not set, it will use the the form's action - validationUrl: undefined, - // a callback that is called before submitting the form. The signature of the callback should be: - // function ($form) { ...return false to cancel submission...} - beforeSubmit: undefined, - // a callback that is called before validating each attribute. The signature of the callback should be: - // function ($form, attribute, messages) { ...return false to cancel the validation...} - beforeValidate: undefined, - // a callback that is called after an attribute is validated. The signature of the callback should be: - // function ($form, attribute, messages) - afterValidate: undefined, - // the GET parameter name indicating an AJAX-based validation - ajaxVar: 'ajax' - }; - - var attributeDefaults = { - // attribute name or expression (e.g. "[0]content" for tabular input) - name: undefined, - // the jQuery selector of the container of the input field - container: undefined, - // the jQuery selector of the input field - input: undefined, - // the jQuery selector of the error tag - error: undefined, - // whether to perform validation when a change is detected on the input - validateOnChange: false, - // whether to perform validation when the user is typing. - validateOnType: false, - // number of milliseconds that the validation should be delayed when a user is typing in the input field. - validationDelay: 200, - // whether to enable AJAX-based validation. - enableAjaxValidation: false, - // function (attribute, value, messages), the client-side validation function. - validate: undefined, - // status of the input field, 0: empty, not entered before, 1: validated, 2: pending validation, 3: validating - status: 0, - // the value of the input - value: undefined - }; - - var methods = { - init: function (attributes, options) { - return this.each(function () { - var $form = $(this); - if ($form.data('yiiActiveForm')) { - return; - } - - var settings = $.extend({}, defaults, options || {}); - if (settings.validationUrl === undefined) { - settings.validationUrl = $form.prop('action'); - } - $.each(attributes, function (i) { - attributes[i] = $.extend({value: getValue($form, this)}, attributeDefaults, this); - }); - $form.data('yiiActiveForm', { - settings: settings, - attributes: attributes, - submitting: false, - validated: false - }); - - watchAttributes($form, attributes); - - /** - * Clean up error status when the form is reset. - * Note that $form.on('reset', ...) does work because the "reset" event does not bubble on IE. - */ - $form.bind('reset.yiiActiveForm', methods.resetForm); - - if (settings.validateOnSubmit) { - $form.on('mouseup.yiiActiveForm keyup.yiiActiveForm', ':submit', function () { - $form.data('yiiActiveForm').submitObject = $(this); - }); - $form.on('submit', methods.submitForm); - } - }); - }, - - destroy: function () { - return this.each(function () { - $(window).unbind('.yiiActiveForm'); - $(this).removeData('yiiActiveForm'); - }); - }, - - data: function() { - return this.data('yiiActiveForm'); - }, - - submitForm: function () { - var $form = $(this), - data = $form.data('yiiActiveForm'); - if (data.validated) { - // continue submitting the form since validation passes - return true; - } - - if (data.settings.timer !== undefined) { - clearTimeout(data.settings.timer); - } - data.submitting = true; - if (!data.settings.beforeSubmit || data.settings.beforeSubmit($form)) { - validate($form, function (messages) { - var errors = []; - $.each(data.attributes, function () { - if (updateInput($form, this, messages)) { - errors.push(this.input); - } - }); - updateSummary($form, messages); - if (errors.length) { - var top = $form.find(errors.join(',')).first().offset().top; - var wtop = $(window).scrollTop(); - if (top < wtop || top > wtop + $(window).height) { - $(window).scrollTop(top); - } - } else { - data.validated = true; - var $button = data.submitObject || $form.find(':submit:first'); - // TODO: if the submission is caused by "change" event, it will not work - if ($button.length) { - $button.click(); - } else { - // no submit button in the form - $form.submit(); - } - return; - } - data.submitting = false; - }, function () { - data.submitting = false; - }); - } else { - data.submitting = false; - } - return false; - }, - - resetForm: function () { - var $form = $(this); - var data = $form.data('yiiActiveForm'); - // Because we bind directly to a form reset event instead of a reset button (that may not exist), - // when this function is executed form input values have not been reset yet. - // Therefore we do the actual reset work through setTimeout. - setTimeout(function () { - $.each(data.attributes, function () { - // Without setTimeout() we would get the input values that are not reset yet. - this.value = getValue($form, this); - this.status = 0; - var $container = $form.find(this.container); - $container.removeClass( - data.settings.validatingCssClass + ' ' + - data.settings.errorCssClass + ' ' + - data.settings.successCssClass - ); - $container.find(this.error).html(''); - }); - $form.find(data.settings.summary).hide().find('ul').html(''); - }, 1); - } - }; - - var watchAttributes = function ($form, attributes) { - $.each(attributes, function (i, attribute) { - var $input = findInput($form, attribute); - if (attribute.validateOnChange) { - $input.on('change.yiiActiveForm', function () { - validateAttribute($form, attribute, false); - }).on('blur.yiiActiveForm', function () { - if (attribute.status == 0 || attribute.status == 1) { - validateAttribute($form, attribute, !attribute.status); - } - }); - } - if (attribute.validateOnType) { - $input.on('keyup.yiiActiveForm', function () { - if (attribute.value !== getValue($form, attribute)) { - validateAttribute($form, attribute, false); - } - }); - } - }); - }; - - var validateAttribute = function ($form, attribute, forceValidate) { - var data = $form.data('yiiActiveForm'); - - if (forceValidate) { - attribute.status = 2; - } - $.each(data.attributes, function () { - if (this.value !== getValue($form, this)) { - this.status = 2; - forceValidate = true; - } - }); - if (!forceValidate) { - return; - } - - if (data.settings.timer !== undefined) { - clearTimeout(data.settings.timer); - } - data.settings.timer = setTimeout(function () { - if (data.submitting || $form.is(':hidden')) { - return; - } - $.each(data.attributes, function () { - if (this.status === 2) { - this.status = 3; - $form.find(this.container).addClass(data.settings.validatingCssClass); - } - }); - validate($form, function (messages) { - var hasError = false; - $.each(data.attributes, function () { - if (this.status === 2 || this.status === 3) { - hasError = updateInput($form, this, messages) || hasError; - } - }); - }); - }, data.settings.validationDelay); - }; - - /** - * Performs validation. - * @param $form jQuery the jquery representation of the form - * @param successCallback function the function to be invoked if the validation completes - * @param errorCallback function the function to be invoked if the ajax validation request fails - */ - var validate = function ($form, successCallback, errorCallback) { - var data = $form.data('yiiActiveForm'), - needAjaxValidation = false, - messages = {}; - - $.each(data.attributes, function () { - if (data.submitting || this.status === 2 || this.status === 3) { - var msg = []; - if (!data.settings.beforeValidate || data.settings.beforeValidate($form, this, msg)) { - if (this.validate) { - this.validate(this, getValue($form, this), msg); - } - if (msg.length) { - messages[this.name] = msg; - } else if (this.enableAjaxValidation) { - needAjaxValidation = true; - } - } - } - }); - - if (needAjaxValidation && (!data.submitting || $.isEmptyObject(messages))) { - // Perform ajax validation when at least one input needs it. - // If the validation is triggered by form submission, ajax validation - // should be done only when all inputs pass client validation - var $button = data.submitObject, - extData = '&' + data.settings.ajaxVar + '=' + $form.prop('id'); - if ($button && $button.length && $button.prop('name')) { - extData += '&' + $button.prop('name') + '=' + $button.prop('value'); - } - $.ajax({ - url: data.settings.validationUrl, - type: $form.prop('method'), - data: $form.serialize() + extData, - dataType: 'json', - success: function (msgs) { - if (msgs !== null && typeof msgs === 'object') { - $.each(data.attributes, function () { - if (!this.enableAjaxValidation) { - delete msgs[this.name]; - } - }); - successCallback($.extend({}, messages, msgs)); - } else { - successCallback(messages); - } - }, - error: errorCallback - }); - } else if (data.submitting) { - // delay callback so that the form can be submitted without problem - setTimeout(function () { - successCallback(messages); - }, 200); - } else { - successCallback(messages); - } - }; - - /** - * Updates the error message and the input container for a particular attribute. - * @param $form the form jQuery object - * @param attribute object the configuration for a particular attribute. - * @param messages array the validation error messages - * @return boolean whether there is a validation error for the specified attribute - */ - var updateInput = function ($form, attribute, messages) { - var data = $form.data('yiiActiveForm'), - $input = findInput($form, attribute), - hasError = false; - - if (data.settings.afterValidate) { - data.settings.afterValidate($form, attribute, messages); - } - attribute.status = 1; - if ($input.length) { - hasError = messages && $.isArray(messages[attribute.name]) && messages[attribute.name].length; - var $container = $form.find(attribute.container); - var $error = $container.find(attribute.error); - if (hasError) { - $error.text(messages[attribute.name][0]); - $container.removeClass(data.settings.validatingCssClass + ' ' + data.settings.successCssClass) - .addClass(data.settings.errorCssClass); - } else { - $error.text(''); - $container.removeClass(data.settings.validatingCssClass + ' ' + data.settings.errorCssClass + ' ') - .addClass(data.settings.successCssClass); - } - attribute.value = getValue($form, attribute); - } - return hasError; - }; - - /** - * Updates the error summary. - * @param $form the form jQuery object - * @param messages array the validation error messages - */ - var updateSummary = function ($form, messages) { - var data = $form.data('yiiActiveForm'), - $summary = $form.find(data.settings.errorSummary), - $ul = $summary.find('ul').html(''); - - if ($summary.length && messages) { - $.each(data.attributes, function () { - if ($.isArray(messages[this.name]) && messages[this.name].length) { - $ul.append($('
      • ').text(messages[this.name][0])); - } - }); - $summary.toggle($ul.find('li').length > 0); - } - }; - - var getValue = function ($form, attribute) { - var $input = findInput($form, attribute); - var type = $input.prop('type'); - if (type === 'checkbox' || type === 'radio') { - return $input.filter(':checked').val(); - } else { - return $input.val(); - } - }; - - var findInput = function ($form, attribute) { - var $input = $form.find(attribute.input); - if ($input.length && $input[0].tagName.toLowerCase() === 'div') { - // checkbox list or radio list - return $input.find('input'); - } else { - return $input; - } - }; - -})(window.jQuery); diff --git a/framework/yii/assets/yii.captcha.js b/framework/yii/assets/yii.captcha.js deleted file mode 100644 index af14faa..0000000 --- a/framework/yii/assets/yii.captcha.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Yii Captcha widget. - * - * This is the JavaScript widget used by the yii\captcha\Captcha widget. - * - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - * @author Qiang Xue - * @since 2.0 - */ -(function ($) { - $.fn.yiiCaptcha = function (method) { - if (methods[method]) { - return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); - } else if (typeof method === 'object' || !method) { - return methods.init.apply(this, arguments); - } else { - $.error('Method ' + method + ' does not exist on jQuery.yiiCaptcha'); - return false; - } - }; - - var defaults = { - refreshUrl: undefined, - hashKey: undefined - }; - - var methods = { - init: function (options) { - return this.each(function () { - var $e = $(this); - var settings = $.extend({}, defaults, options || {}); - $e.data('yiiCaptcha', { - settings: settings - }); - - $e.on('click.yiiCaptcha', function() { - methods.refresh.apply($e); - return false; - }); - - }); - }, - - refresh: function () { - var $e = this, - settings = this.data('yiiCaptcha').settings; - $.ajax({ - url: $e.data('yiiCaptcha').settings.refreshUrl, - dataType: 'json', - cache: false, - success: function(data) { - $e.attr('src', data.url); - $('body').data(settings.hashKey, [data.hash1, data.hash2]); - } - }); - }, - - destroy: function () { - return this.each(function () { - $(window).unbind('.yiiCaptcha'); - $(this).removeData('yiiCaptcha'); - }); - }, - - data: function() { - return this.data('yiiCaptcha'); - } - }; -})(window.jQuery); - diff --git a/framework/yii/assets/yii.gridView.js b/framework/yii/assets/yii.gridView.js deleted file mode 100644 index a452c17..0000000 --- a/framework/yii/assets/yii.gridView.js +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Yii GridView widget. - * - * This is the JavaScript widget used by the yii\grid\GridView widget. - * - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - * @author Qiang Xue - * @since 2.0 - */ -(function ($) { - $.fn.yiiGridView = function (method) { - if (methods[method]) { - return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); - } else if (typeof method === 'object' || !method) { - return methods.init.apply(this, arguments); - } else { - $.error('Method ' + method + ' does not exist on jQuery.yiiGridView'); - return false; - } - }; - - var defaults = { - filterUrl: undefined, - filterSelector: undefined - }; - - var methods = { - init: function (options) { - return this.each(function () { - var $e = $(this); - var settings = $.extend({}, defaults, options || {}); - $e.data('yiiGridView', { - settings: settings - }); - - var enterPressed = false; - $(document).on('change.yiiGridView keydown.yiiGridView', settings.filterSelector, function (event) { - if (event.type === 'keydown') { - if (event.keyCode !== 13) { - return; // only react to enter key - } else { - enterPressed = true; - } - } else { - // prevent processing for both keydown and change events - if (enterPressed) { - enterPressed = false; - return; - } - } - var data = $(settings.filterSelector).serialize(); - var url = settings.filterUrl; - if (url.indexOf('?') >= 0) { - url += '&' + data; - } else { - url += '?' + data; - } - window.location.href = url; - return false; - }); - }); - }, - - setSelectionColumn: function (options) { - var $grid = $(this); - var data = $grid.data('yiiGridView'); - data.selectionColumn = options.name; - if (!options.multiple) { - return; - } - $grid.on('click.yiiGridView', "input[name='" + options.checkAll + "']", function () { - $grid.find("input[name='" + options.name + "']:enabled").prop('checked', this.checked); - }); - $grid.on('click.yiiGridView', "input[name='" + options.name + "']:enabled", function () { - var all = $grid.find("input[name='" + options.name + "']").length == $grid.find("input[name='" + options.name + "']:checked").length; - $grid.find("input[name='" + options.checkAll + "']").prop('checked', all); - }); - }, - - getSelectedRows: function () { - var $grid = $(this); - var data = $grid.data('yiiGridView'); - var keys = []; - if (data.selectionColumn) { - $grid.find("input[name='" + data.selectionColumn + "']:checked").each(function () { - keys.push($(this).parent().closest('tr').data('key')); - }); - } - return keys; - }, - - destroy: function () { - return this.each(function () { - $(window).unbind('.yiiGridView'); - $(this).removeData('yiiGridView'); - }); - }, - - data: function() { - return this.data('yiiGridView'); - } - }; - - var enterPressed = false; - - var filterChanged = function (event) { - if (event.type === 'keydown') { - if (event.keyCode !== 13) { - return; // only react to enter key - } else { - enterPressed = true; - } - } else { - // prevent processing for both keydown and change events - if (enterPressed) { - enterPressed = false; - return; - } - } - var data = $(settings.filterSelector).serialize(); - if (settings.pageVar !== undefined) { - data += '&' + settings.pageVar + '=1'; - } - if (settings.enableHistory && settings.ajaxUpdate !== false && window.History.enabled) { - // Ajaxify this link - var url = $('#' + id).yiiGridView('getUrl'), - params = $.deparam.querystring($.param.querystring(url, data)); - - delete params[settings.ajaxVar]; - window.History.pushState(null, document.title, decodeURIComponent($.param.querystring(url.substr(0, url.indexOf('?')), params))); - } else { - $('#' + id).yiiGridView('update', {data: data}); - } - return false; - }; -})(window.jQuery); - diff --git a/framework/yii/assets/yii.js b/framework/yii/assets/yii.js deleted file mode 100644 index c5904a1..0000000 --- a/framework/yii/assets/yii.js +++ /dev/null @@ -1,245 +0,0 @@ -/** - * Yii JavaScript module. - * - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - * @author Qiang Xue - * @since 2.0 - */ - -/** - * yii is the root module for all Yii JavaScript modules. - * It implements a mechanism of organizing JavaScript code in modules through the function "yii.initModule()". - * - * Each module should be named as "x.y.z", where "x" stands for the root module (for the Yii core code, this is "yii"). - * - * A module may be structured as follows: - * - * ~~~ - * yii.sample = (function($) { - * var pub = { - * // whether this module is currently active. If false, init() will not be called for this module - * // it will also not be called for all its child modules. If this property is undefined, it means true. - * isActive: true, - * init: function() { - * // ... module initialization code go here ... - * }, - * - * // ... other public functions and properties go here ... - * }; - * - * // ... private functions and properties go here ... - * - * return pub; - * })(jQuery); - * ~~~ - * - * Using this structure, you can define public and private functions/properties for a module. - * Private functions/properties are only visible within the module, while public functions/properties - * may be accessed outside of the module. For example, you can access "yii.sample.isActive". - * - * You must call "yii.initModule()" once for the root module of all your modules. - */ -yii = (function ($) { - var pub = { - /** - * List of scripts that can be loaded multiple times via AJAX requests. Each script can be represented - * as either an absolute URL or a relative one. - */ - reloadableScripts: [], - /** - * The selector for clickable elements that need to support confirmation and form submission. - */ - clickableSelector: 'a, button, input[type="submit"], input[type="button"], input[type="reset"], input[type="image"]', - /** - * The selector for changeable elements that need to support confirmation and form submission. - */ - changeableSelector: 'select, input, textarea', - - /** - * @return string|undefined the CSRF variable name. Undefined is returned if CSRF validation is not enabled. - */ - getCsrfVar: function () { - return $('meta[name=csrf-var]').prop('content'); - }, - - /** - * @return string|undefined the CSRF token. Undefined is returned if CSRF validation is not enabled. - */ - getCsrfToken: function () { - return $('meta[name=csrf-token]').prop('content'); - }, - - /** - * Displays a confirmation dialog. - * The default implementation simply displays a js confirmation dialog. - * You may override this by setting `yii.confirm`. - * @param message the confirmation message. - * @return boolean whether the user confirms with the message in the dialog - */ - confirm: function (message) { - return confirm(message); - }, - - /** - * Returns a value indicating whether to allow executing the action defined for the specified element. - * This method recognizes the `data-confirm` attribute of the element and uses it - * as the message in a confirmation dialog. The method will return true if this special attribute - * is not defined or if the user confirms the message. - * @param $e the jQuery representation of the element - * @return boolean whether to allow executing the action defined for the specified element. - */ - allowAction: function ($e) { - var message = $e.data('confirm'); - return message === undefined || pub.confirm(message); - }, - - /** - * Handles the action triggered by user. - * This method recognizes the `data-method` attribute of the element. If the attribute exists, - * the method will submit the form containing this element. If there is no containing form, a form - * will be created and submitted using the method given by this attribute value (e.g. "post", "put"). - * For hyperlinks, the form action will take the value of the "href" attribute of the link. - * For other elements, either the containing form action or the current page URL will be used - * as the form action URL. - * - * If the `data-method` attribute is not defined, the default element action will be performed. - * - * @param $e the jQuery representation of the element - * @return boolean whether to execute the default action for the element. - */ - handleAction: function ($e) { - var method = $e.data('method'); - if (method === undefined) { - return true; - } - - var $form = $e.closest('form'); - var newForm = !$form.length; - if (newForm) { - var action = $e.prop('href'); - if (!action || !action.match(/(^\/|:\/\/)/)) { - action = window.location.href; - } - $form = $('
        '); - var target = $e.prop('target'); - if (target) { - $form.attr('target', target); - } - if (!method.match(/(get|post)/i)) { - $form.append(''); - } - var csrfVar = pub.getCsrfVar(); - if (csrfVar) { - $form.append(''); - } - $form.hide().appendTo('body'); - } - - var activeFormData = $form.data('yiiActiveForm'); - if (activeFormData) { - // remember who triggers the form submission. This is used by yii.activeForm.js - activeFormData.submitObject = $e; - } - - $form.trigger('submit'); - - if (newForm) { - $form.remove(); - } - - return false; - }, - - initModule: function (module) { - if (module.isActive === undefined || module.isActive) { - if ($.isFunction(module.init)) { - module.init(); - } - $.each(module, function () { - if ($.isPlainObject(this)) { - pub.initModule(this); - } - }); - } - }, - - init: function () { - initCsrfHandler(); - initRedirectHandler(); - initScriptFilter(); - initDataMethods(); - } - }; - - function initRedirectHandler() { - // handle AJAX redirection - $(document).ajaxComplete(function (event, xhr, settings) { - var url = xhr.getResponseHeader('X-Redirect'); - if (url) { - window.location = url; - } - }); - } - - function initCsrfHandler() { - // automatically send CSRF token for all AJAX requests - $.ajaxPrefilter(function (options, originalOptions, xhr) { - if (!options.crossDomain && pub.getCsrfVar()) { - xhr.setRequestHeader('X-CSRF-Token', pub.getCsrfToken()); - } - }); - } - - function initDataMethods() { - var $document = $(document); - // handle data-confirm and data-method for clickable elements - $document.on('click.yii', pub.clickableSelector, function (event) { - var $this = $(this); - if (pub.allowAction($this)) { - return pub.handleAction($this); - } else { - event.stopImmediatePropagation(); - return false; - } - }); - - // handle data-confirm and data-method for changeable elements - $document.on('change.yii', pub.changeableSelector, function (event) { - var $this = $(this); - if (pub.allowAction($this)) { - return pub.handleAction($this); - } else { - event.stopImmediatePropagation(); - return false; - } - }); - } - - function initScriptFilter() { - var hostInfo = location.protocol + '//' + location.host; - var loadedScripts = $('script[src]').map(function () { - return this.src.charAt(0) === '/' ? hostInfo + this.src : this.src; - }).toArray(); - $.ajaxPrefilter('script', function (options, originalOptions, xhr) { - var url = options.url.charAt(0) === '/' ? hostInfo + options.url : options.url; - if ($.inArray(url, loadedScripts) === -1) { - loadedScripts.push(url); - } else { - var found = $.inArray(url, $.map(pub.reloadableScripts, function (script) { - return script.charAt(0) === '/' ? hostInfo + script : script; - })) !== -1; - if (!found) { - xhr.abort(); - } - } - }); - } - - return pub; -})(jQuery); - -jQuery(document).ready(function () { - yii.initModule(yii); -}); diff --git a/framework/yii/assets/yii.validation.js b/framework/yii/assets/yii.validation.js deleted file mode 100644 index 97074ac..0000000 --- a/framework/yii/assets/yii.validation.js +++ /dev/null @@ -1,227 +0,0 @@ -/** - * Yii validation module. - * - * This JavaScript module provides the validation methods for the built-in validators. - * - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - * @author Qiang Xue - * @since 2.0 - */ - -yii.validation = (function ($) { - var isEmpty = function (value, trim) { - return value === null || value === undefined || value == [] - || value === '' || trim && $.trim(value) === ''; - }; - - var addMessage = function (messages, message, value) { - messages.push(message.replace(/\{value\}/g, value)); - }; - - return { - required: function (value, messages, options) { - var valid = false; - if (options.requiredValue === undefined) { - if (options.strict && value !== undefined || !options.strict && !isEmpty(value, true)) { - valid = true; - } - } else if (!options.strict && value == options.requiredValue || options.strict && value === options.requiredValue) { - valid = true; - } - - if (!valid) { - addMessage(messages, options.message, value); - } - }, - - boolean: function (value, messages, options) { - if (options.skipOnEmpty && isEmpty(value)) { - return; - } - var valid = !options.strict && (value == options.trueValue || value == options.falseValue) - || options.strict && (value === options.trueValue || value === options.falseValue); - - if (!valid) { - addMessage(messages, options.message, value); - } - }, - - string: function (value, messages, options) { - if (options.skipOnEmpty && isEmpty(value)) { - return; - } - - if (typeof value !== 'string') { - addMessage(messages, options.message, value); - return; - } - - if (options.min !== undefined && value.length < options.min) { - addMessage(messages, options.tooShort, value); - } - if (options.max !== undefined && value.length > options.max) { - addMessage(messages, options.tooLong, value); - } - if (options.is !== undefined && value.length != options.is) { - addMessage(messages, options.is, value); - } - }, - - number: function (value, messages, options) { - if (options.skipOnEmpty && isEmpty(value)) { - return; - } - - if (typeof value === 'string' && !value.match(options.pattern)) { - addMessage(messages, options.message, value); - return; - } - - if (options.min !== undefined && value < options.min) { - addMessage(messages, options.tooSmall, value); - } - if (options.max !== undefined && value > options.max) { - addMessage(messages, options.tooBig, value); - } - }, - - range: function (value, messages, options) { - if (options.skipOnEmpty && isEmpty(value)) { - return; - } - var valid = !options.not && $.inArray(value, options.range) > -1 - || options.not && $.inArray(value, options.range) == -1; - - if (!valid) { - addMessage(messages, options.message, value); - } - }, - - regularExpression: function (value, messages, options) { - if (options.skipOnEmpty && isEmpty(value)) { - return; - } - - if (!options.not && !value.match(options.pattern) || options.not && value.match(options.pattern)) { - addMessage(messages, options.message, value); - } - }, - - email: function (value, messages, options) { - if (options.skipOnEmpty && isEmpty(value)) { - return; - } - - var valid = true; - - if (options.enableIDN) { - var regexp = /^(.*?)$/, - matches = regexp.exec(value); - if (matches === null) { - valid = false; - } else { - value = matches[1] + punycode.toASCII(matches[2]) + '@' + punycode.toASCII(matches[3]) + matches[4]; - } - } - - if (!valid || !(value.match(options.pattern) || (options.allowName && value.match(options.fullPattern)))) { - addMessage(messages, options.message, value); - } - }, - - url: function (value, messages, options) { - if (options.skipOnEmpty && isEmpty(value)) { - return; - } - - if (options.defaultScheme && !value.match(/:\/\//)) { - value = options.defaultScheme + '://' + value; - } - - var valid = true; - - if (options.enableIDN) { - var regexp = /^([^:]+):\/\/([^\/]+)(.*)$/, - matches = regexp.exec(value); - if (matches === null) { - valid = false; - } else { - value = matches[1] + '://' + punycode.toASCII(matches[2]) + matches[3]; - } - } - - if (!valid || !value.match(options.pattern)) { - addMessage(messages, options.message, value); - } - }, - - captcha: function (value, messages, options) { - if (options.skipOnEmpty && isEmpty(value)) { - return; - } - - // CAPTCHA may be updated via AJAX and the updated hash is stored in body data - var hash = $('body').data(options.hashKey); - if (hash == null) { - hash = options.hash; - } else { - hash = hash[options.caseSensitive ? 0 : 1]; - } - var v = options.caseSensitive ? value : value.toLowerCase(); - for (var i = v.length - 1, h = 0; i >= 0; --i) { - h += v.charCodeAt(i); - } - if (h != hash) { - addMessage(messages, options.message, value); - } - }, - - compare: function (value, messages, options) { - if (options.skipOnEmpty && isEmpty(value)) { - return; - } - - var compareValue, valid = true; - if (options.compareAttribute === undefined) { - compareValue = options.compareValue; - } else { - compareValue = $('#' + options.compareAttribute).val(); - } - switch (options.operator) { - case '==': - valid = value == compareValue; - break; - case '===': - valid = value === compareValue; - break; - case '!=': - valid = value != compareValue; - break; - case '!==': - valid = value !== compareValue; - break; - case '>': - valid = value > compareValue; - break; - case '>=': - valid = value >= compareValue; - break; - case '<': - valid = value < compareValue; - break; - case '<=': - valid = value <= compareValue; - break; - default: - valid = false; - break; - } - - if (!valid) { - addMessage(messages, options.message, value); - } - } - }; -})(jQuery); diff --git a/framework/yii/base/Action.php b/framework/yii/base/Action.php deleted file mode 100644 index 56b1c45..0000000 --- a/framework/yii/base/Action.php +++ /dev/null @@ -1,89 +0,0 @@ - 1]`. - * Then the `run()` method will be invoked as `run(1)` automatically. - * - * @property string $uniqueId The unique ID of this action among the whole application. This property is - * read-only. - * - * @author Qiang Xue - * @since 2.0 - */ -class Action extends Component -{ - /** - * @var string ID of the action - */ - public $id; - /** - * @var Controller the controller that owns this action - */ - public $controller; - - /** - * Constructor. - * @param string $id the ID of this action - * @param Controller $controller the controller that owns this action - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($id, $controller, $config = []) - { - $this->id = $id; - $this->controller = $controller; - parent::__construct($config); - } - - /** - * Returns the unique ID of this action among the whole application. - * @return string the unique ID of this action among the whole application. - */ - public function getUniqueId() - { - return $this->controller->getUniqueId() . '/' . $this->id; - } - - /** - * Runs this action with the specified parameters. - * This method is mainly invoked by the controller. - * @param array $params the parameters to be bound to the action's run() method. - * @return mixed the result of the action - * @throws InvalidConfigException if the action class does not have a run() method - */ - public function runWithParams($params) - { - if (!method_exists($this, 'run')) { - throw new InvalidConfigException(get_class($this) . ' must define a "run()" method.'); - } - $args = $this->controller->bindActionParams($this, $params); - Yii::trace('Running action: ' . get_class($this) . '::run()', __METHOD__); - if (Yii::$app->requestedParams === null) { - Yii::$app->requestedParams = $args; - } - return call_user_func_array([$this, 'run'], $args); - } -} diff --git a/framework/yii/base/ActionEvent.php b/framework/yii/base/ActionEvent.php deleted file mode 100644 index 6e123a0..0000000 --- a/framework/yii/base/ActionEvent.php +++ /dev/null @@ -1,45 +0,0 @@ - - * @since 2.0 - */ -class ActionEvent extends Event -{ - /** - * @var Action the action currently being executed - */ - public $action; - /** - * @var mixed the action result. Event handlers may modify this property to change the action result. - */ - public $result; - /** - * @var boolean whether to continue running the action. Event handlers of - * [[Controller::EVENT_BEFORE_ACTION]] may set this property to decide whether - * to continue running the current action. - */ - public $isValid = true; - - /** - * Constructor. - * @param Action $action the action associated with this action event. - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($action, $config = []) - { - $this->action = $action; - parent::__construct($config); - } -} diff --git a/framework/yii/base/ActionFilter.php b/framework/yii/base/ActionFilter.php deleted file mode 100644 index 648211c..0000000 --- a/framework/yii/base/ActionFilter.php +++ /dev/null @@ -1,99 +0,0 @@ - - * @since 2.0 - */ -class ActionFilter extends Behavior -{ - /** - * @var array list of action IDs that this filter should apply to. If this property is not set, - * then the filter applies to all actions, unless they are listed in [[except]]. - * If an action ID appears in both [[only]] and [[except]], this filter will NOT apply to it. - * @see except - */ - public $only; - /** - * @var array list of action IDs that this filter should not apply to. - * @see only - */ - public $except = []; - - /** - * Declares event handlers for the [[owner]]'s events. - * @return array events (array keys) and the corresponding event handler methods (array values). - */ - public function events() - { - return [ - Controller::EVENT_BEFORE_ACTION => 'beforeFilter', - Controller::EVENT_AFTER_ACTION => 'afterFilter', - ]; - } - - /** - * @param ActionEvent $event - * @return boolean - */ - public function beforeFilter($event) - { - if ($this->isActive($event->action)) { - $event->isValid = $this->beforeAction($event->action); - } - return $event->isValid; - } - - /** - * @param ActionEvent $event - * @return boolean - */ - public function afterFilter($event) - { - if ($this->isActive($event->action)) { - $this->afterAction($event->action, $event->result); - } - } - - /** - * This method is invoked right before an action is to be executed (after all possible filters.) - * You may override this method to do last-minute preparation for the action. - * @param Action $action the action to be executed. - * @return boolean whether the action should continue to be executed. - */ - public function beforeAction($action) - { - return true; - } - - /** - * This method is invoked right after an action is executed. - * You may override this method to do some postprocessing for the action. - * @param Action $action the action just executed. - * @param mixed $result the action execution result - */ - public function afterAction($action, &$result) - { - } - - /** - * Returns a value indicating whether the filer is active for the given action. - * @param Action $action the action being filtered - * @return boolean whether the filer is active for the given action. - */ - protected function isActive($action) - { - return !in_array($action->id, $this->except, true) && (empty($this->only) || in_array($action->id, $this->only, true)); - } -} diff --git a/framework/yii/base/Application.php b/framework/yii/base/Application.php deleted file mode 100644 index 72afa69..0000000 --- a/framework/yii/base/Application.php +++ /dev/null @@ -1,646 +0,0 @@ - - * @since 2.0 - */ -abstract class Application extends Module -{ - /** - * @event Event an event raised before the application starts to handle a request. - */ - const EVENT_BEFORE_REQUEST = 'beforeRequest'; - /** - * @event Event an event raised after the application successfully handles a request (before the response is sent out). - */ - const EVENT_AFTER_REQUEST = 'afterRequest'; - /** - * @event ActionEvent an event raised before executing a controller action. - * You may set [[ActionEvent::isValid]] to be false to cancel the action execution. - */ - const EVENT_BEFORE_ACTION = 'beforeAction'; - /** - * @event ActionEvent an event raised after executing a controller action. - */ - const EVENT_AFTER_ACTION = 'afterAction'; - - /** - * @var string the namespace that controller classes are in. If not set, - * it will use the "app\controllers" namespace. - */ - public $controllerNamespace = 'app\\controllers'; - - /** - * @var string the application name. - */ - public $name = 'My Application'; - /** - * @var string the version of this application. - */ - public $version = '1.0'; - /** - * @var string the charset currently used for the application. - */ - public $charset = 'UTF-8'; - /** - * @var string the language that is meant to be used for end users. - * @see sourceLanguage - */ - public $language = 'en-US'; - /** - * @var string the language that the application is written in. This mainly refers to - * the language that the messages and view files are written in. - * @see language - */ - public $sourceLanguage = 'en-US'; - /** - * @var Controller the currently active controller instance - */ - public $controller; - /** - * @var string|boolean the layout that should be applied for views in this application. Defaults to 'main'. - * If this is false, layout will be disabled. - */ - public $layout = 'main'; - /** - * @var integer the size of the reserved memory. A portion of memory is pre-allocated so that - * when an out-of-memory issue occurs, the error handler is able to handle the error with - * the help of this reserved memory. If you set this value to be 0, no memory will be reserved. - * Defaults to 256KB. - */ - public $memoryReserveSize = 262144; - /** - * @var string the requested route - */ - public $requestedRoute; - /** - * @var Action the requested Action. If null, it means the request cannot be resolved into an action. - */ - public $requestedAction; - /** - * @var array the parameters supplied to the requested action. - */ - public $requestedParams; - /** - * @var array list of installed Yii extensions. Each array element represents a single extension - * with the following structure: - * - * ~~~ - * [ - * 'name' => 'extension name', - * 'version' => 'version number', - * 'bootstrap' => 'BootstrapClassName', - * ] - * ~~~ - */ - public $extensions = []; - /** - * @var \Exception the exception that is being handled currently. When this is not null, - * it means the application is handling some exception and extra care should be taken. - */ - public $exception; - - /** - * @var string Used to reserve memory for fatal error handler. - */ - private $_memoryReserve; - - /** - * Constructor. - * @param array $config name-value pairs that will be used to initialize the object properties. - * Note that the configuration must contain both [[id]] and [[basePath]]. - * @throws InvalidConfigException if either [[id]] or [[basePath]] configuration is missing. - */ - public function __construct($config = []) - { - Yii::$app = $this; - - $this->preInit($config); - $this->registerErrorHandlers(); - $this->registerCoreComponents(); - - Component::__construct($config); - } - - /** - * Pre-initializes the application. - * This method is called at the beginning of the application constructor. - * It initializes several important application properties. - * If you override this method, please make sure you call the parent implementation. - * @param array $config the application configuration - * @throws InvalidConfigException if either [[id]] or [[basePath]] configuration is missing. - */ - public function preInit(&$config) - { - if (!isset($config['id'])) { - throw new InvalidConfigException('The "id" configuration is required.'); - } - if (isset($config['basePath'])) { - $this->setBasePath($config['basePath']); - unset($config['basePath']); - } else { - throw new InvalidConfigException('The "basePath" configuration is required.'); - } - - if (isset($config['vendorPath'])) { - $this->setVendorPath($config['vendorPath']); - unset($config['vendorPath']); - } else { - // set "@vendor" - $this->getVendorPath(); - } - if (isset($config['runtimePath'])) { - $this->setRuntimePath($config['runtimePath']); - unset($config['runtimePath']); - } else { - // set "@runtime" - $this->getRuntimePath(); - } - - if (isset($config['timeZone'])) { - $this->setTimeZone($config['timeZone']); - unset($config['timeZone']); - } elseif (!ini_get('date.timezone')) { - $this->setTimeZone('UTC'); - } - } - - /** - * @inheritdoc - */ - public function init() - { - $this->initExtensions($this->extensions); - parent::init(); - } - - /** - * Initializes the extensions. - * @param array $extensions the extensions to be initialized. Please refer to [[extensions]] - * for the structure of the extension array. - */ - protected function initExtensions($extensions) - { - foreach ($extensions as $extension) { - if (!empty($extension['alias'])) { - foreach ($extension['alias'] as $name => $path) { - Yii::setAlias($name, $path); - } - } - if (isset($extension['bootstrap'])) { - /** @var Extension $class */ - $class = $extension['bootstrap']; - $class::init(); - } - } - } - - /** - * Loads components that are declared in [[preload]]. - * @throws InvalidConfigException if a component or module to be preloaded is unknown - */ - public function preloadComponents() - { - $this->getComponent('log'); - parent::preloadComponents(); - } - - /** - * Registers error handlers. - */ - public function registerErrorHandlers() - { - if (YII_ENABLE_ERROR_HANDLER) { - ini_set('display_errors', 0); - set_exception_handler([$this, 'handleException']); - set_error_handler([$this, 'handleError'], error_reporting()); - if ($this->memoryReserveSize > 0) { - $this->_memoryReserve = str_repeat('x', $this->memoryReserveSize); - } - register_shutdown_function([$this, 'handleFatalError']); - } - } - - /** - * Returns an ID that uniquely identifies this module among all modules within the current application. - * Since this is an application instance, it will always return an empty string. - * @return string the unique ID of the module. - */ - public function getUniqueId() - { - return ''; - } - - /** - * Sets the root directory of the application and the @app alias. - * This method can only be invoked at the beginning of the constructor. - * @param string $path the root directory of the application. - * @property string the root directory of the application. - * @throws InvalidParamException if the directory does not exist. - */ - public function setBasePath($path) - { - parent::setBasePath($path); - Yii::setAlias('@app', $this->getBasePath()); - } - - /** - * Runs the application. - * This is the main entrance of an application. - * @return integer the exit status (0 means normal, non-zero values mean abnormal) - */ - public function run() - { - $this->trigger(self::EVENT_BEFORE_REQUEST); - $response = $this->handleRequest($this->getRequest()); - $this->trigger(self::EVENT_AFTER_REQUEST); - $response->send(); - return $response->exitStatus; - } - - /** - * Handles the specified request. - * - * This method should return an instance of [[Response]] or its child class - * which represents the handling result of the request. - * - * @param Request $request the request to be handled - * @return Response the resulting response - */ - abstract public function handleRequest($request); - - - private $_runtimePath; - - /** - * Returns the directory that stores runtime files. - * @return string the directory that stores runtime files. - * Defaults to the "runtime" subdirectory under [[basePath]]. - */ - public function getRuntimePath() - { - if ($this->_runtimePath === null) { - $this->setRuntimePath($this->getBasePath() . DIRECTORY_SEPARATOR . 'runtime'); - } - return $this->_runtimePath; - } - - /** - * Sets the directory that stores runtime files. - * @param string $path the directory that stores runtime files. - */ - public function setRuntimePath($path) - { - $this->_runtimePath = Yii::getAlias($path); - Yii::setAlias('@runtime', $this->_runtimePath); - } - - private $_vendorPath; - - /** - * Returns the directory that stores vendor files. - * @return string the directory that stores vendor files. - * Defaults to "vendor" directory under [[basePath]]. - */ - public function getVendorPath() - { - if ($this->_vendorPath === null) { - $this->setVendorPath($this->getBasePath() . DIRECTORY_SEPARATOR . 'vendor'); - } - return $this->_vendorPath; - } - - /** - * Sets the directory that stores vendor files. - * @param string $path the directory that stores vendor files. - */ - public function setVendorPath($path) - { - $this->_vendorPath = Yii::getAlias($path); - Yii::setAlias('@vendor', $this->_vendorPath); - } - - /** - * Returns the time zone used by this application. - * This is a simple wrapper of PHP function date_default_timezone_get(). - * If time zone is not configured in php.ini or application config, - * it will be set to UTC by default. - * @return string the time zone used by this application. - * @see http://php.net/manual/en/function.date-default-timezone-get.php - */ - public function getTimeZone() - { - return date_default_timezone_get(); - } - - /** - * Sets the time zone used by this application. - * This is a simple wrapper of PHP function date_default_timezone_set(). - * Refer to the [php manual](http://www.php.net/manual/en/timezones.php) for available timezones. - * @param string $value the time zone used by this application. - * @see http://php.net/manual/en/function.date-default-timezone-set.php - */ - public function setTimeZone($value) - { - date_default_timezone_set($value); - } - - /** - * Returns the database connection component. - * @return \yii\db\Connection the database connection - */ - public function getDb() - { - return $this->getComponent('db'); - } - - /** - * Returns the log component. - * @return \yii\log\Logger the log component - */ - public function getLog() - { - return $this->getComponent('log'); - } - - /** - * Returns the error handler component. - * @return ErrorHandler the error handler application component. - */ - public function getErrorHandler() - { - return $this->getComponent('errorHandler'); - } - - /** - * Returns the cache component. - * @return \yii\caching\Cache the cache application component. Null if the component is not enabled. - */ - public function getCache() - { - return $this->getComponent('cache'); - } - - /** - * Returns the formatter component. - * @return \yii\base\Formatter the formatter application component. - */ - public function getFormatter() - { - return $this->getComponent('formatter'); - } - - /** - * Returns the request component. - * @return \yii\web\Request|\yii\console\Request the request component - */ - public function getRequest() - { - return $this->getComponent('request'); - } - - /** - * Returns the view object. - * @return View|\yii\web\View the view object that is used to render various view files. - */ - public function getView() - { - return $this->getComponent('view'); - } - - /** - * Returns the URL manager for this application. - * @return \yii\web\UrlManager the URL manager for this application. - */ - public function getUrlManager() - { - return $this->getComponent('urlManager'); - } - - /** - * Returns the internationalization (i18n) component - * @return \yii\i18n\I18N the internationalization component - */ - public function getI18n() - { - return $this->getComponent('i18n'); - } - - /** - * Returns the mailer component. - * @return \yii\mail\MailerInterface the mailer interface - */ - public function getMail() - { - return $this->getComponent('mail'); - } - - /** - * Returns the auth manager for this application. - * @return \yii\rbac\Manager the auth manager for this application. - */ - public function getAuthManager() - { - return $this->getComponent('authManager'); - } - - /** - * Registers the core application components. - * @see setComponents - */ - public function registerCoreComponents() - { - $this->setComponents([ - 'log' => ['class' => 'yii\log\Logger'], - 'errorHandler' => ['class' => 'yii\base\ErrorHandler'], - 'formatter' => ['class' => 'yii\base\Formatter'], - 'i18n' => ['class' => 'yii\i18n\I18N'], - 'mail' => ['class' => 'yii\swiftmailer\Mailer'], - 'urlManager' => ['class' => 'yii\web\UrlManager'], - 'view' => ['class' => 'yii\web\View'], - ]); - } - - /** - * Handles uncaught PHP exceptions. - * - * This method is implemented as a PHP exception handler. - * - * @param \Exception $exception the exception that is not caught - */ - public function handleException($exception) - { - $this->exception = $exception; - - // disable error capturing to avoid recursive errors while handling exceptions - restore_error_handler(); - restore_exception_handler(); - try { - $this->logException($exception); - if (($handler = $this->getErrorHandler()) !== null) { - $handler->handle($exception); - } else { - echo $this->renderException($exception); - } - } catch (\Exception $e) { - // exception could be thrown in ErrorHandler::handle() - $msg = (string)$e; - $msg .= "\nPrevious exception:\n"; - $msg .= (string)$exception; - if (YII_DEBUG) { - if (PHP_SAPI === 'cli') { - echo $msg . "\n"; - } else { - echo '
        ' . htmlspecialchars($msg, ENT_QUOTES, $this->charset) . '
        '; - } - } - $msg .= "\n\$_SERVER = " . var_export($_SERVER, true); - error_log($msg); - exit(1); - } - } - - /** - * Handles PHP execution errors such as warnings, notices. - * - * This method is used as a PHP error handler. It will simply raise an `ErrorException`. - * - * @param integer $code the level of the error raised - * @param string $message the error message - * @param string $file the filename that the error was raised in - * @param integer $line the line number the error was raised at - * - * @throws ErrorException - */ - public function handleError($code, $message, $file, $line) - { - if (error_reporting() !== 0) { - // load ErrorException manually here because autoloading them will not work - // when error occurs while autoloading a class - if (!class_exists('\\yii\\base\\Exception', false)) { - require_once(__DIR__ . '/Exception.php'); - } - if (!class_exists('\\yii\\base\\ErrorException', false)) { - require_once(__DIR__ . '/ErrorException.php'); - } - $exception = new ErrorException($message, $code, $code, $file, $line); - - // in case error appeared in __toString method we can't throw any exception - $trace = debug_backtrace(false); - array_shift($trace); - foreach ($trace as $frame) { - if ($frame['function'] == '__toString') { - $this->handleException($exception); - exit(1); - } - } - - throw $exception; - } - } - - /** - * Handles fatal PHP errors - */ - public function handleFatalError() - { - unset($this->_memoryReserve); - - // load ErrorException manually here because autoloading them will not work - // when error occurs while autoloading a class - if (!class_exists('\\yii\\base\\Exception', false)) { - require_once(__DIR__ . '/Exception.php'); - } - if (!class_exists('\\yii\\base\\ErrorException', false)) { - require_once(__DIR__ . '/ErrorException.php'); - } - - $error = error_get_last(); - - if (ErrorException::isFatalError($error)) { - $exception = new ErrorException($error['message'], $error['type'], $error['type'], $error['file'], $error['line']); - $this->exception = $exception; - // use error_log because it's too late to use Yii log - error_log($exception); - - if (($handler = $this->getErrorHandler()) !== null) { - $handler->handle($exception); - } else { - echo $this->renderException($exception); - } - - exit(1); - } - } - - /** - * Renders an exception without using rich format. - * @param \Exception $exception the exception to be rendered. - * @return string the rendering result - */ - public function renderException($exception) - { - if ($exception instanceof Exception && ($exception instanceof UserException || !YII_DEBUG)) { - $message = $exception->getName() . ': ' . $exception->getMessage(); - if (Yii::$app->controller instanceof \yii\console\Controller) { - $message = Yii::$app->controller->ansiFormat($message, Console::FG_RED); - } - } else { - $message = YII_DEBUG ? (string)$exception : 'Error: ' . $exception->getMessage(); - } - if (PHP_SAPI === 'cli') { - return $message . "\n"; - } else { - return '
        ' . htmlspecialchars($message, ENT_QUOTES, $this->charset) . '
        '; - } - } - - /** - * Logs the given exception - * @param \Exception $exception the exception to be logged - */ - protected function logException($exception) - { - $category = get_class($exception); - if ($exception instanceof HttpException) { - $category = 'yii\\web\\HttpException:' . $exception->statusCode; - } elseif ($exception instanceof \ErrorException) { - $category .= ':' . $exception->getSeverity(); - } - Yii::error((string)$exception, $category); - } -} diff --git a/framework/yii/base/Arrayable.php b/framework/yii/base/Arrayable.php deleted file mode 100644 index 1822e51..0000000 --- a/framework/yii/base/Arrayable.php +++ /dev/null @@ -1,23 +0,0 @@ - - * @since 2.0 - */ -interface Arrayable -{ - /** - * Converts the object into an array. - * @return array the array representation of this object - */ - public function toArray(); -} diff --git a/framework/yii/base/Behavior.php b/framework/yii/base/Behavior.php deleted file mode 100644 index 0b1786d..0000000 --- a/framework/yii/base/Behavior.php +++ /dev/null @@ -1,91 +0,0 @@ - - * @since 2.0 - */ -class Behavior extends \yii\base\Object -{ - /** - * @var Component the owner of this behavior - */ - public $owner; - - /** - * Declares event handlers for the [[owner]]'s events. - * - * Child classes may override this method to declare what PHP callbacks should - * be attached to the events of the [[owner]] component. - * - * The callbacks will be attached to the [[owner]]'s events when the behavior is - * attached to the owner; and they will be detached from the events when - * the behavior is detached from the component. - * - * The callbacks can be any of the followings: - * - * - method in this behavior: `'handleClick'`, equivalent to `[$this, 'handleClick']` - * - object method: `[$object, 'handleClick']` - * - static method: `['Page', 'handleClick']` - * - anonymous function: `function($event) { ... }` - * - * The following is an example: - * - * ~~~ - * [ - * Model::EVENT_BEFORE_VALIDATE => 'myBeforeValidate', - * Model::EVENT_AFTER_VALIDATE => 'myAfterValidate', - * ] - * ~~~ - * - * @return array events (array keys) and the corresponding event handler methods (array values). - */ - public function events() - { - return []; - } - - /** - * Attaches the behavior object to the component. - * The default implementation will set the [[owner]] property - * and attach event handlers as declared in [[events]]. - * Make sure you call the parent implementation if you override this method. - * @param Component $owner the component that this behavior is to be attached to. - */ - public function attach($owner) - { - $this->owner = $owner; - foreach ($this->events() as $event => $handler) { - $owner->on($event, is_string($handler) ? [$this, $handler] : $handler); - } - } - - /** - * Detaches the behavior object from the component. - * The default implementation will unset the [[owner]] property - * and detach event handlers declared in [[events]]. - * Make sure you call the parent implementation if you override this method. - */ - public function detach() - { - if ($this->owner) { - foreach ($this->events() as $event => $handler) { - $this->owner->off($event, is_string($handler) ? [$this, $handler] : $handler); - } - $this->owner = null; - } - } -} diff --git a/framework/yii/base/Component.php b/framework/yii/base/Component.php deleted file mode 100644 index 92577c9..0000000 --- a/framework/yii/base/Component.php +++ /dev/null @@ -1,581 +0,0 @@ - - * @since 2.0 - */ -class Component extends Object -{ - /** - * @var array the attached event handlers (event name => handlers) - */ - private $_events = []; - /** - * @var Behavior[] the attached behaviors (behavior name => behavior) - */ - private $_behaviors; - - /** - * Returns the value of a component property. - * This method will check in the following order and act accordingly: - * - * - a property defined by a getter: return the getter result - * - a property of a behavior: return the behavior property value - * - * Do not call this method directly as it is a PHP magic method that - * will be implicitly called when executing `$value = $component->property;`. - * @param string $name the property name - * @return mixed the property value or the value of a behavior's property - * @throws UnknownPropertyException if the property is not defined - * @throws InvalidCallException if the property is write-only. - * @see __set() - */ - public function __get($name) - { - $getter = 'get' . $name; - if (method_exists($this, $getter)) { - // read property, e.g. getName() - return $this->$getter(); - } else { - // behavior property - $this->ensureBehaviors(); - foreach ($this->_behaviors as $behavior) { - if ($behavior->canGetProperty($name)) { - return $behavior->$name; - } - } - } - if (method_exists($this, 'set' . $name)) { - throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name); - } else { - throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name); - } - } - - /** - * Sets the value of a component property. - * This method will check in the following order and act accordingly: - * - * - a property defined by a setter: set the property value - * - an event in the format of "on xyz": attach the handler to the event "xyz" - * - a behavior in the format of "as xyz": attach the behavior named as "xyz" - * - a property of a behavior: set the behavior property value - * - * Do not call this method directly as it is a PHP magic method that - * will be implicitly called when executing `$component->property = $value;`. - * @param string $name the property name or the event name - * @param mixed $value the property value - * @throws UnknownPropertyException if the property is not defined - * @throws InvalidCallException if the property is read-only. - * @see __get() - */ - public function __set($name, $value) - { - $setter = 'set' . $name; - if (method_exists($this, $setter)) { - // set property - $this->$setter($value); - return; - } elseif (strncmp($name, 'on ', 3) === 0) { - // on event: attach event handler - $this->on(trim(substr($name, 3)), $value); - return; - } elseif (strncmp($name, 'as ', 3) === 0) { - // as behavior: attach behavior - $name = trim(substr($name, 3)); - $this->attachBehavior($name, $value instanceof Behavior ? $value : Yii::createObject($value)); - return; - } else { - // behavior property - $this->ensureBehaviors(); - foreach ($this->_behaviors as $behavior) { - if ($behavior->canSetProperty($name)) { - $behavior->$name = $value; - return; - } - } - } - if (method_exists($this, 'get' . $name)) { - throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name); - } else { - throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name); - } - } - - /** - * Checks if a property value is null. - * This method will check in the following order and act accordingly: - * - * - a property defined by a setter: return whether the property value is null - * - a property of a behavior: return whether the property value is null - * - * Do not call this method directly as it is a PHP magic method that - * will be implicitly called when executing `isset($component->property)`. - * @param string $name the property name or the event name - * @return boolean whether the named property is null - */ - public function __isset($name) - { - $getter = 'get' . $name; - if (method_exists($this, $getter)) { - return $this->$getter() !== null; - } else { - // behavior property - $this->ensureBehaviors(); - foreach ($this->_behaviors as $behavior) { - if ($behavior->canGetProperty($name)) { - return $behavior->$name !== null; - } - } - } - return false; - } - - /** - * Sets a component property to be null. - * This method will check in the following order and act accordingly: - * - * - a property defined by a setter: set the property value to be null - * - a property of a behavior: set the property value to be null - * - * Do not call this method directly as it is a PHP magic method that - * will be implicitly called when executing `unset($component->property)`. - * @param string $name the property name - * @throws InvalidCallException if the property is read only. - */ - public function __unset($name) - { - $setter = 'set' . $name; - if (method_exists($this, $setter)) { - $this->$setter(null); - return; - } else { - // behavior property - $this->ensureBehaviors(); - foreach ($this->_behaviors as $behavior) { - if ($behavior->canSetProperty($name)) { - $behavior->$name = null; - return; - } - } - } - if (method_exists($this, 'get' . $name)) { - throw new InvalidCallException('Unsetting read-only property: ' . get_class($this) . '.' . $name); - } - } - - /** - * Calls the named method which is not a class method. - * - * This method will check if any attached behavior has - * the named method and will execute it if available. - * - * Do not call this method directly as it is a PHP magic method that - * will be implicitly called when an unknown method is being invoked. - * @param string $name the method name - * @param array $params method parameters - * @return mixed the method return value - * @throws UnknownMethodException when calling unknown method - */ - public function __call($name, $params) - { - $this->ensureBehaviors(); - foreach ($this->_behaviors as $object) { - if ($object->hasMethod($name)) { - return call_user_func_array([$object, $name], $params); - } - } - - throw new UnknownMethodException('Calling unknown method: ' . get_class($this) . "::$name()"); - } - - /** - * This method is called after the object is created by cloning an existing one. - * It removes all behaviors because they are attached to the old object. - */ - public function __clone() - { - $this->_events = []; - $this->_behaviors = null; - } - - /** - * Returns a value indicating whether a property is defined for this component. - * A property is defined if: - * - * - the class has a getter or setter method associated with the specified name - * (in this case, property name is case-insensitive); - * - the class has a member variable with the specified name (when `$checkVars` is true); - * - an attached behavior has a property of the given name (when `$checkBehaviors` is true). - * - * @param string $name the property name - * @param boolean $checkVars whether to treat member variables as properties - * @param boolean $checkBehaviors whether to treat behaviors' properties as properties of this component - * @return boolean whether the property is defined - * @see canGetProperty() - * @see canSetProperty() - */ - public function hasProperty($name, $checkVars = true, $checkBehaviors = true) - { - return $this->canGetProperty($name, $checkVars, $checkBehaviors) || $this->canSetProperty($name, false, $checkBehaviors); - } - - /** - * Returns a value indicating whether a property can be read. - * A property can be read if: - * - * - the class has a getter method associated with the specified name - * (in this case, property name is case-insensitive); - * - the class has a member variable with the specified name (when `$checkVars` is true); - * - an attached behavior has a readable property of the given name (when `$checkBehaviors` is true). - * - * @param string $name the property name - * @param boolean $checkVars whether to treat member variables as properties - * @param boolean $checkBehaviors whether to treat behaviors' properties as properties of this component - * @return boolean whether the property can be read - * @see canSetProperty() - */ - public function canGetProperty($name, $checkVars = true, $checkBehaviors = true) - { - if (method_exists($this, 'get' . $name) || $checkVars && property_exists($this, $name)) { - return true; - } elseif ($checkBehaviors) { - $this->ensureBehaviors(); - foreach ($this->_behaviors as $behavior) { - if ($behavior->canGetProperty($name, $checkVars)) { - return true; - } - } - } - return false; - } - - /** - * Returns a value indicating whether a property can be set. - * A property can be written if: - * - * - the class has a setter method associated with the specified name - * (in this case, property name is case-insensitive); - * - the class has a member variable with the specified name (when `$checkVars` is true); - * - an attached behavior has a writable property of the given name (when `$checkBehaviors` is true). - * - * @param string $name the property name - * @param boolean $checkVars whether to treat member variables as properties - * @param boolean $checkBehaviors whether to treat behaviors' properties as properties of this component - * @return boolean whether the property can be written - * @see canGetProperty() - */ - public function canSetProperty($name, $checkVars = true, $checkBehaviors = true) - { - if (method_exists($this, 'set' . $name) || $checkVars && property_exists($this, $name)) { - return true; - } elseif ($checkBehaviors) { - $this->ensureBehaviors(); - foreach ($this->_behaviors as $behavior) { - if ($behavior->canSetProperty($name, $checkVars)) { - return true; - } - } - } - return false; - } - - /** - * Returns a value indicating whether a method is defined. - * A method is defined if: - * - * - the class has a method with the specified name - * - an attached behavior has a method with the given name (when `$checkBehaviors` is true). - * - * @param string $name the property name - * @param boolean $checkBehaviors whether to treat behaviors' methods as methods of this component - * @return boolean whether the property is defined - */ - public function hasMethod($name, $checkBehaviors = true) - { - if (method_exists($this, $name)) { - return true; - } elseif ($checkBehaviors) { - $this->ensureBehaviors(); - foreach ($this->_behaviors as $behavior) { - if ($behavior->hasMethod($name)) { - return true; - } - } - } - return false; - } - - /** - * Returns a list of behaviors that this component should behave as. - * - * Child classes may override this method to specify the behaviors they want to behave as. - * - * The return value of this method should be an array of behavior objects or configurations - * indexed by behavior names. A behavior configuration can be either a string specifying - * the behavior class or an array of the following structure: - * - * ~~~ - * 'behaviorName' => [ - * 'class' => 'BehaviorClass', - * 'property1' => 'value1', - * 'property2' => 'value2', - * ] - * ~~~ - * - * Note that a behavior class must extend from [[Behavior]]. Behavior names can be strings - * or integers. If the former, they uniquely identify the behaviors. If the latter, the corresponding - * behaviors are anonymous and their properties and methods will NOT be made available via the component - * (however, the behaviors can still respond to the component's events). - * - * Behaviors declared in this method will be attached to the component automatically (on demand). - * - * @return array the behavior configurations. - */ - public function behaviors() - { - return []; - } - - /** - * Returns a value indicating whether there is any handler attached to the named event. - * @param string $name the event name - * @return boolean whether there is any handler attached to the event. - */ - public function hasEventHandlers($name) - { - $this->ensureBehaviors(); - return !empty($this->_events[$name]) || Event::hasHandlers($this, $name); - } - - /** - * Attaches an event handler to an event. - * - * The event handler must be a valid PHP callback. The followings are - * some examples: - * - * ~~~ - * function ($event) { ... } // anonymous function - * [$object, 'handleClick'] // $object->handleClick() - * ['Page', 'handleClick'] // Page::handleClick() - * 'handleClick' // global function handleClick() - * ~~~ - * - * The event handler must be defined with the following signature, - * - * ~~~ - * function ($event) - * ~~~ - * - * where `$event` is an [[Event]] object which includes parameters associated with the event. - * - * @param string $name the event name - * @param callback $handler the event handler - * @param mixed $data the data to be passed to the event handler when the event is triggered. - * When the event handler is invoked, this data can be accessed via [[Event::data]]. - * @see off() - */ - public function on($name, $handler, $data = null) - { - $this->ensureBehaviors(); - $this->_events[$name][] = [$handler, $data]; - } - - /** - * Detaches an existing event handler from this component. - * This method is the opposite of [[on()]]. - * @param string $name event name - * @param callback $handler the event handler to be removed. - * If it is null, all handlers attached to the named event will be removed. - * @return boolean if a handler is found and detached - * @see on() - */ - public function off($name, $handler = null) - { - $this->ensureBehaviors(); - if (empty($this->_events[$name])) { - return false; - } - if ($handler === null) { - unset($this->_events[$name]); - return true; - } else { - $removed = false; - foreach ($this->_events[$name] as $i => $event) { - if ($event[0] === $handler) { - unset($this->_events[$name][$i]); - $removed = true; - } - } - if ($removed) { - $this->_events[$name] = array_values($this->_events[$name]); - } - return $removed; - } - } - - /** - * Triggers an event. - * This method represents the happening of an event. It invokes - * all attached handlers for the event including class-level handlers. - * @param string $name the event name - * @param Event $event the event parameter. If not set, a default [[Event]] object will be created. - */ - public function trigger($name, Event $event = null) - { - $this->ensureBehaviors(); - if (!empty($this->_events[$name])) { - if ($event === null) { - $event = new Event; - } - if ($event->sender === null) { - $event->sender = $this; - } - $event->handled = false; - $event->name = $name; - foreach ($this->_events[$name] as $handler) { - $event->data = $handler[1]; - call_user_func($handler[0], $event); - // stop further handling if the event is handled - if ($event->handled) { - return; - } - } - } - // invoke class-level attached handlers - Event::trigger($this, $name, $event); - } - - /** - * Returns the named behavior object. - * @param string $name the behavior name - * @return Behavior the behavior object, or null if the behavior does not exist - */ - public function getBehavior($name) - { - $this->ensureBehaviors(); - return isset($this->_behaviors[$name]) ? $this->_behaviors[$name] : null; - } - - /** - * Returns all behaviors attached to this component. - * @return Behavior[] list of behaviors attached to this component - */ - public function getBehaviors() - { - $this->ensureBehaviors(); - return $this->_behaviors; - } - - /** - * Attaches a behavior to this component. - * This method will create the behavior object based on the given - * configuration. After that, the behavior object will be attached to - * this component by calling the [[Behavior::attach()]] method. - * @param string $name the name of the behavior. - * @param string|array|Behavior $behavior the behavior configuration. This can be one of the following: - * - * - a [[Behavior]] object - * - a string specifying the behavior class - * - an object configuration array that will be passed to [[Yii::createObject()]] to create the behavior object. - * - * @return Behavior the behavior object - * @see detachBehavior() - */ - public function attachBehavior($name, $behavior) - { - $this->ensureBehaviors(); - return $this->attachBehaviorInternal($name, $behavior); - } - - /** - * Attaches a list of behaviors to the component. - * Each behavior is indexed by its name and should be a [[Behavior]] object, - * a string specifying the behavior class, or an configuration array for creating the behavior. - * @param array $behaviors list of behaviors to be attached to the component - * @see attachBehavior() - */ - public function attachBehaviors($behaviors) - { - $this->ensureBehaviors(); - foreach ($behaviors as $name => $behavior) { - $this->attachBehaviorInternal($name, $behavior); - } - } - - /** - * Detaches a behavior from the component. - * The behavior's [[Behavior::detach()]] method will be invoked. - * @param string $name the behavior's name. - * @return Behavior the detached behavior. Null if the behavior does not exist. - */ - public function detachBehavior($name) - { - $this->ensureBehaviors(); - if (isset($this->_behaviors[$name])) { - $behavior = $this->_behaviors[$name]; - unset($this->_behaviors[$name]); - $behavior->detach(); - return $behavior; - } else { - return null; - } - } - - /** - * Detaches all behaviors from the component. - */ - public function detachBehaviors() - { - $this->ensureBehaviors(); - foreach ($this->_behaviors as $name => $behavior) { - $this->detachBehavior($name); - } - } - - /** - * Makes sure that the behaviors declared in [[behaviors()]] are attached to this component. - */ - public function ensureBehaviors() - { - if ($this->_behaviors === null) { - $this->_behaviors = []; - foreach ($this->behaviors() as $name => $behavior) { - $this->attachBehaviorInternal($name, $behavior); - } - } - } - - /** - * Attaches a behavior to this component. - * @param string $name the name of the behavior. - * @param string|array|Behavior $behavior the behavior to be attached - * @return Behavior the attached behavior. - */ - private function attachBehaviorInternal($name, $behavior) - { - if (!($behavior instanceof Behavior)) { - $behavior = Yii::createObject($behavior); - } - if (isset($this->_behaviors[$name])) { - $this->_behaviors[$name]->detach(); - } - $behavior->attach($this); - return $this->_behaviors[$name] = $behavior; - } -} diff --git a/framework/yii/base/Controller.php b/framework/yii/base/Controller.php deleted file mode 100644 index 9b5464f..0000000 --- a/framework/yii/base/Controller.php +++ /dev/null @@ -1,417 +0,0 @@ - - * @since 2.0 - */ -class Controller extends Component implements ViewContextInterface -{ - /** - * @event ActionEvent an event raised right before executing a controller action. - * You may set [[ActionEvent::isValid]] to be false to cancel the action execution. - */ - const EVENT_BEFORE_ACTION = 'beforeAction'; - /** - * @event ActionEvent an event raised right after executing a controller action. - */ - const EVENT_AFTER_ACTION = 'afterAction'; - /** - * @var string the ID of this controller. - */ - public $id; - /** - * @var Module $module the module that this controller belongs to. - */ - public $module; - /** - * @var string the ID of the action that is used when the action ID is not specified - * in the request. Defaults to 'index'. - */ - public $defaultAction = 'index'; - /** - * @var string|boolean the name of the layout to be applied to this controller's views. - * This property mainly affects the behavior of [[render()]]. - * Defaults to null, meaning the actual layout value should inherit that from [[module]]'s layout value. - * If false, no layout will be applied. - */ - public $layout; - /** - * @var Action the action that is currently being executed. This property will be set - * by [[run()]] when it is called by [[Application]] to run an action. - */ - public $action; - /** - * @var View the view object that can be used to render views or view files. - */ - private $_view; - - - /** - * @param string $id the ID of this controller. - * @param Module $module the module that this controller belongs to. - * @param array $config name-value pairs that will be used to initialize the object properties. - */ - public function __construct($id, $module, $config = []) - { - $this->id = $id; - $this->module = $module; - parent::__construct($config); - } - - /** - * Declares external actions for the controller. - * This method is meant to be overwritten to declare external actions for the controller. - * It should return an array, with array keys being action IDs, and array values the corresponding - * action class names or action configuration arrays. For example, - * - * ~~~ - * return [ - * 'action1' => 'app\components\Action1', - * 'action2' => [ - * 'class' => 'app\components\Action2', - * 'property1' => 'value1', - * 'property2' => 'value2', - * ], - * ]; - * ~~~ - * - * [[\Yii::createObject()]] will be used later to create the requested action - * using the configuration provided here. - */ - public function actions() - { - return []; - } - - /** - * Runs an action within this controller with the specified action ID and parameters. - * If the action ID is empty, the method will use [[defaultAction]]. - * @param string $id the ID of the action to be executed. - * @param array $params the parameters (name-value pairs) to be passed to the action. - * @return mixed the result of the action. - * @throws InvalidRouteException if the requested action ID cannot be resolved into an action successfully. - * @see createAction() - */ - public function runAction($id, $params = []) - { - $action = $this->createAction($id); - if ($action !== null) { - Yii::trace("Route to run: " . $action->getUniqueId(), __METHOD__); - if (Yii::$app->requestedAction === null) { - Yii::$app->requestedAction = $action; - } - $oldAction = $this->action; - $this->action = $action; - $result = null; - $event = new ActionEvent($action); - Yii::$app->trigger(Application::EVENT_BEFORE_ACTION, $event); - if ($event->isValid && $this->module->beforeAction($action) && $this->beforeAction($action)) { - $result = $action->runWithParams($params); - $this->afterAction($action, $result); - $this->module->afterAction($action, $result); - $event = new ActionEvent($action); - $event->result = &$result; - Yii::$app->trigger(Application::EVENT_AFTER_ACTION, $event); - } - $this->action = $oldAction; - return $result; - } else { - throw new InvalidRouteException('Unable to resolve the request: ' . $this->getUniqueId() . '/' . $id); - } - } - - /** - * Runs a request specified in terms of a route. - * The route can be either an ID of an action within this controller or a complete route consisting - * of module IDs, controller ID and action ID. If the route starts with a slash '/', the parsing of - * the route will start from the application; otherwise, it will start from the parent module of this controller. - * @param string $route the route to be handled, e.g., 'view', 'comment/view', '/admin/comment/view'. - * @param array $params the parameters to be passed to the action. - * @return mixed the result of the action. - * @see runAction() - */ - public function run($route, $params = []) - { - $pos = strpos($route, '/'); - if ($pos === false) { - return $this->runAction($route, $params); - } elseif ($pos > 0) { - return $this->module->runAction($route, $params); - } else { - return Yii::$app->runAction(ltrim($route, '/'), $params); - } - } - - /** - * Binds the parameters to the action. - * This method is invoked by [[Action]] when it begins to run with the given parameters. - * @param Action $action the action to be bound with parameters. - * @param array $params the parameters to be bound to the action. - * @return array the valid parameters that the action can run with. - */ - public function bindActionParams($action, $params) - { - return []; - } - - /** - * Creates an action based on the given action ID. - * The method first checks if the action ID has been declared in [[actions()]]. If so, - * it will use the configuration declared there to create the action object. - * If not, it will look for a controller method whose name is in the format of `actionXyz` - * where `Xyz` stands for the action ID. If found, an [[InlineAction]] representing that - * method will be created and returned. - * @param string $id the action ID. - * @return Action the newly created action instance. Null if the ID doesn't resolve into any action. - */ - public function createAction($id) - { - if ($id === '') { - $id = $this->defaultAction; - } - - $actionMap = $this->actions(); - if (isset($actionMap[$id])) { - return Yii::createObject($actionMap[$id], $id, $this); - } elseif (preg_match('/^[a-z0-9\\-_]+$/', $id) && strpos($id, '--') === false && trim($id, '-') === $id) { - $methodName = 'action' . str_replace(' ', '', ucwords(implode(' ', explode('-', $id)))); - if (method_exists($this, $methodName)) { - $method = new \ReflectionMethod($this, $methodName); - if ($method->getName() === $methodName) { - return new InlineAction($id, $this, $methodName); - } - } - } - return null; - } - - /** - * This method is invoked right before an action is to be executed (after all possible filters). - * You may override this method to do last-minute preparation for the action. - * If you override this method, please make sure you call the parent implementation first. - * @param Action $action the action to be executed. - * @return boolean whether the action should continue to be executed. - */ - public function beforeAction($action) - { - $event = new ActionEvent($action); - $this->trigger(self::EVENT_BEFORE_ACTION, $event); - return $event->isValid; - } - - /** - * This method is invoked right after an action is executed. - * You may override this method to do some postprocessing for the action. - * If you override this method, please make sure you call the parent implementation first. - * @param Action $action the action just executed. - * @param mixed $result the action return result. - */ - public function afterAction($action, &$result) - { - $event = new ActionEvent($action); - $event->result = &$result; - $this->trigger(self::EVENT_AFTER_ACTION, $event); - } - - /** - * @return string the controller ID that is prefixed with the module ID (if any). - */ - public function getUniqueId() - { - return $this->module instanceof Application ? $this->id : $this->module->getUniqueId() . '/' . $this->id; - } - - /** - * Returns the route of the current request. - * @return string the route (module ID, controller ID and action ID) of the current request. - */ - public function getRoute() - { - return $this->action !== null ? $this->action->getUniqueId() : $this->getUniqueId(); - } - - /** - * Renders a view and applies layout if available. - * - * The view to be rendered can be specified in one of the following formats: - * - * - path alias (e.g. "@app/views/site/index"); - * - absolute path within application (e.g. "//site/index"): the view name starts with double slashes. - * The actual view file will be looked for under the [[Application::viewPath|view path]] of the application. - * - absolute path within module (e.g. "/site/index"): the view name starts with a single slash. - * The actual view file will be looked for under the [[Module::viewPath|view path]] of [[module]]. - * - relative path (e.g. "index"): the actual view file will be looked for under [[viewPath]]. - * - * To determine which layout should be applied, the following two steps are conducted: - * - * 1. In the first step, it determines the layout name and the context module: - * - * - If [[layout]] is specified as a string, use it as the layout name and [[module]] as the context module; - * - If [[layout]] is null, search through all ancestor modules of this controller and find the first - * module whose [[Module::layout|layout]] is not null. The layout and the corresponding module - * are used as the layout name and the context module, respectively. If such a module is not found - * or the corresponding layout is not a string, it will return false, meaning no applicable layout. - * - * 2. In the second step, it determines the actual layout file according to the previously found layout name - * and context module. The layout name can be: - * - * - a path alias (e.g. "@app/views/layouts/main"); - * - an absolute path (e.g. "/main"): the layout name starts with a slash. The actual layout file will be - * looked for under the [[Application::layoutPath|layout path]] of the application; - * - a relative path (e.g. "main"): the actual layout layout file will be looked for under the - * [[Module::layoutPath|layout path]] of the context module. - * - * If the layout name does not contain a file extension, it will use the default one `.php`. - * - * @param string $view the view name. Please refer to [[findViewFile()]] on how to specify a view name. - * @param array $params the parameters (name-value pairs) that should be made available in the view. - * These parameters will not be available in the layout. - * @return string the rendering result. - * @throws InvalidParamException if the view file or the layout file does not exist. - */ - public function render($view, $params = []) - { - $output = $this->getView()->render($view, $params, $this); - $layoutFile = $this->findLayoutFile($this->getView()); - if ($layoutFile !== false) { - return $this->getView()->renderFile($layoutFile, ['content' => $output], $this); - } else { - return $output; - } - } - - /** - * Renders a view. - * This method differs from [[render()]] in that it does not apply any layout. - * @param string $view the view name. Please refer to [[render()]] on how to specify a view name. - * @param array $params the parameters (name-value pairs) that should be made available in the view. - * @return string the rendering result. - * @throws InvalidParamException if the view file does not exist. - */ - public function renderPartial($view, $params = []) - { - return $this->getView()->render($view, $params, $this); - } - - /** - * Renders a view file. - * @param string $file the view file to be rendered. This can be either a file path or a path alias. - * @param array $params the parameters (name-value pairs) that should be made available in the view. - * @return string the rendering result. - * @throws InvalidParamException if the view file does not exist. - */ - public function renderFile($file, $params = []) - { - return $this->getView()->renderFile($file, $params, $this); - } - - /** - * Returns the view object that can be used to render views or view files. - * The [[render()]], [[renderPartial()]] and [[renderFile()]] methods will use - * this view object to implement the actual view rendering. - * If not set, it will default to the "view" application component. - * @return View the view object that can be used to render views or view files. - */ - public function getView() - { - if ($this->_view === null) { - $this->_view = Yii::$app->getView(); - } - return $this->_view; - } - - /** - * Sets the view object to be used by this controller. - * @param View $view the view object that can be used to render views or view files. - */ - public function setView($view) - { - $this->_view = $view; - } - - /** - * Returns the directory containing view files for this controller. - * The default implementation returns the directory named as controller [[id]] under the [[module]]'s - * [[viewPath]] directory. - * @return string the directory containing the view files for this controller. - */ - public function getViewPath() - { - return $this->module->getViewPath() . DIRECTORY_SEPARATOR . $this->id; - } - - /** - * Finds the view file based on the given view name. - * @param string $view the view name or the path alias of the view file. Please refer to [[render()]] - * on how to specify this parameter. - * @return string the view file path. Note that the file may not exist. - */ - public function findViewFile($view) - { - return $this->getViewPath() . DIRECTORY_SEPARATOR . $view; - } - - /** - * Finds the applicable layout file. - * @param View $view the view object to render the layout file. - * @return string|boolean the layout file path, or false if layout is not needed. - * Please refer to [[render()]] on how to specify this parameter. - * @throws InvalidParamException if an invalid path alias is used to specify the layout. - */ - protected function findLayoutFile($view) - { - $module = $this->module; - if (is_string($this->layout)) { - $layout = $this->layout; - } elseif ($this->layout === null) { - while ($module !== null && $module->layout === null) { - $module = $module->module; - } - if ($module !== null && is_string($module->layout)) { - $layout = $module->layout; - } - } - - if (!isset($layout)) { - return false; - } - - if (strncmp($layout, '@', 1) === 0) { - $file = Yii::getAlias($layout); - } elseif (strncmp($layout, '/', 1) === 0) { - $file = Yii::$app->getLayoutPath() . DIRECTORY_SEPARATOR . $layout; - } else { - $file = $module->getLayoutPath() . DIRECTORY_SEPARATOR . $layout; - } - - if (pathinfo($file, PATHINFO_EXTENSION) !== '') { - return $file; - } - $path = $file . '.' . $view->defaultExtension; - if ($view->defaultExtension !== 'php' && !is_file($path)) { - $path = $file . '.php'; - } - return $path; - } -} diff --git a/framework/yii/base/ErrorException.php b/framework/yii/base/ErrorException.php deleted file mode 100644 index b89ca49..0000000 --- a/framework/yii/base/ErrorException.php +++ /dev/null @@ -1,108 +0,0 @@ - - * @since 2.0 - */ -class ErrorException extends Exception -{ - protected $severity; - - /** - * Constructs the exception. - * @link http://php.net/manual/en/errorexception.construct.php - * @param $message [optional] - * @param $code [optional] - * @param $severity [optional] - * @param $filename [optional] - * @param $lineno [optional] - * @param $previous [optional] - */ - public function __construct($message = '', $code = 0, $severity = 1, $filename = __FILE__, $lineno = __LINE__, \Exception $previous = null) - { - parent::__construct($message, $code, $previous); - $this->severity = $severity; - $this->file = $filename; - $this->line = $lineno; - - if (function_exists('xdebug_get_function_stack')) { - $trace = array_slice(array_reverse(xdebug_get_function_stack()), 3, -1); - foreach ($trace as &$frame) { - if (!isset($frame['function'])) { - $frame['function'] = 'unknown'; - } - - // XDebug < 2.1.1: http://bugs.xdebug.org/view.php?id=695 - if (!isset($frame['type']) || $frame['type'] === 'static') { - $frame['type'] = '::'; - } elseif ($frame['type'] === 'dynamic') { - $frame['type'] = '->'; - } - - // XDebug has a different key name - if (isset($frame['params']) && !isset($frame['args'])) { - $frame['args'] = $frame['params']; - } - } - - $ref = new \ReflectionProperty('Exception', 'trace'); - $ref->setAccessible(true); - $ref->setValue($this, $trace); - } - } - - /** - * Returns if error is one of fatal type. - * - * @param array $error error got from error_get_last() - * @return bool if error is one of fatal type - */ - public static function isFatalError($error) - { - return isset($error['type']) && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING]); - } - - /** - * Gets the exception severity. - * @link http://php.net/manual/en/errorexception.getseverity.php - * @return int the severity level of the exception. - */ - final public function getSeverity() - { - return $this->severity; - } - - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - $names = [ - E_ERROR => 'PHP Fatal Error', - E_PARSE => 'PHP Parse Error', - E_CORE_ERROR => 'PHP Core Error', - E_COMPILE_ERROR => 'PHP Compile Error', - E_USER_ERROR => 'PHP User Error', - E_WARNING => 'PHP Warning', - E_CORE_WARNING => 'PHP Core Warning', - E_COMPILE_WARNING => 'PHP Compile Warning', - E_USER_WARNING => 'PHP User Warning', - E_STRICT => 'PHP Strict Warning', - E_NOTICE => 'PHP Notice', - E_RECOVERABLE_ERROR => 'PHP Recoverable Error', - E_DEPRECATED => 'PHP Deprecated Warning', - ]; - return isset($names[$this->getCode()]) ? $names[$this->getCode()] : 'Error'; - } -} diff --git a/framework/yii/base/ErrorHandler.php b/framework/yii/base/ErrorHandler.php deleted file mode 100644 index 1014f71..0000000 --- a/framework/yii/base/ErrorHandler.php +++ /dev/null @@ -1,331 +0,0 @@ -errorHandler`. - * - * @author Qiang Xue - * @author Timur Ruziev - * @since 2.0 - */ -class ErrorHandler extends Component -{ - /** - * @var integer maximum number of source code lines to be displayed. Defaults to 25. - */ - public $maxSourceLines = 25; - /** - * @var integer maximum number of trace source code lines to be displayed. Defaults to 10. - */ - public $maxTraceSourceLines = 10; - /** - * @var boolean whether to discard any existing page output before error display. Defaults to true. - */ - public $discardExistingOutput = true; - /** - * @var string the route (e.g. 'site/error') to the controller action that will be used - * to display external errors. Inside the action, it can retrieve the error information - * by Yii::$app->exception. This property defaults to null, meaning ErrorHandler - * will handle the error display. - */ - public $errorAction; - /** - * @var string the path of the view file for rendering exceptions without call stack information. - */ - public $errorView = '@yii/views/errorHandler/error.php'; - /** - * @var string the path of the view file for rendering exceptions. - */ - public $exceptionView = '@yii/views/errorHandler/exception.php'; - /** - * @var string the path of the view file for rendering exceptions and errors call stack element. - */ - public $callStackItemView = '@yii/views/errorHandler/callStackItem.php'; - /** - * @var string the path of the view file for rendering previous exceptions. - */ - public $previousExceptionView = '@yii/views/errorHandler/previousException.php'; - /** - * @var \Exception the exception that is being handled currently. - */ - public $exception; - - - /** - * Handles exception. - * @param \Exception $exception to be handled. - */ - public function handle($exception) - { - $this->exception = $exception; - if ($this->discardExistingOutput) { - $this->clearOutput(); - } - $this->renderException($exception); - } - - /** - * Renders the exception. - * @param \Exception $exception the exception to be handled. - */ - protected function renderException($exception) - { - if (Yii::$app instanceof \yii\console\Application || YII_ENV_TEST) { - echo Yii::$app->renderException($exception); - return; - } - - $useErrorView = !YII_DEBUG || $exception instanceof UserException; - - $response = Yii::$app->getResponse(); - $response->getHeaders()->removeAll(); - - if ($useErrorView && $this->errorAction !== null) { - $result = Yii::$app->runAction($this->errorAction); - if ($result instanceof Response) { - $response = $result; - } else { - $response->data = $result; - } - } elseif ($response->format === \yii\web\Response::FORMAT_HTML) { - if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') { - // AJAX request - $response->data = Yii::$app->renderException($exception); - } else { - // if there is an error during error rendering it's useful to - // display PHP error in debug mode instead of a blank screen - if (YII_DEBUG) { - ini_set('display_errors', 1); - } - $file = $useErrorView ? $this->errorView : $this->exceptionView; - $response->data = $this->renderFile($file, [ - 'exception' => $exception, - ]); - } - } elseif ($exception instanceof Arrayable) { - $response->data = $exception; - } else { - $response->data = [ - 'type' => get_class($exception), - 'name' => 'Exception', - 'message' => $exception->getMessage(), - 'code' => $exception->getCode(), - ]; - } - - if ($exception instanceof HttpException) { - $response->setStatusCode($exception->statusCode); - } else { - $response->setStatusCode(500); - } - - $response->send(); - } - - /** - * Converts special characters to HTML entities. - * @param string $text to encode. - * @return string encoded original text. - */ - public function htmlEncode($text) - { - return htmlspecialchars($text, ENT_QUOTES, Yii::$app->charset); - } - - /** - * Removes all output echoed before calling this method. - */ - public function clearOutput() - { - // the following manual level counting is to deal with zlib.output_compression set to On - for ($level = ob_get_level(); $level > 0; --$level) { - if (!@ob_end_clean()) { - ob_clean(); - } - } - } - - /** - * Adds informational links to the given PHP type/class. - * @param string $code type/class name to be linkified. - * @return string linkified with HTML type/class name. - */ - public function addTypeLinks($code) - { - $html = ''; - if (strpos($code, '\\') !== false) { - // namespaced class - foreach (explode('\\', $code) as $part) { - $html .= '' . $this->htmlEncode($part) . '\\'; - } - $html = rtrim($html, '\\'); - } elseif (strpos($code, '()') !== false) { - // method/function call - $html = preg_replace_callback('/^(.*)\(\)$/', function ($matches) { - return '' . - $this->htmlEncode($matches[1]) . '()'; - }, $code); - } - return $html; - } - - /** - * Renders a view file as a PHP script. - * @param string $_file_ the view file. - * @param array $_params_ the parameters (name-value pairs) that will be extracted and made available in the view file. - * @return string the rendering result - */ - public function renderFile($_file_, $_params_) - { - $_params_['handler'] = $this; - if ($this->exception instanceof ErrorException) { - ob_start(); - ob_implicit_flush(false); - extract($_params_, EXTR_OVERWRITE); - require(Yii::getAlias($_file_)); - return ob_get_clean(); - } else { - return Yii::$app->getView()->renderFile($_file_, $_params_, $this); - } - } - - /** - * Renders the previous exception stack for a given Exception. - * @param \Exception $exception the exception whose precursors should be rendered. - * @return string HTML content of the rendered previous exceptions. - * Empty string if there are none. - */ - public function renderPreviousExceptions($exception) - { - if (($previous = $exception->getPrevious()) !== null) { - return $this->renderFile($this->previousExceptionView, ['exception' => $previous]); - } else { - return ''; - } - } - - /** - * Renders a single call stack element. - * @param string|null $file name where call has happened. - * @param integer|null $line number on which call has happened. - * @param string|null $class called class name. - * @param string|null $method called function/method name. - * @param integer $index number of the call stack element. - * @return string HTML content of the rendered call stack element. - */ - public function renderCallStackItem($file, $line, $class, $method, $index) - { - $lines = []; - $begin = $end = 0; - if ($file !== null && $line !== null) { - $line--; // adjust line number from one-based to zero-based - $lines = @file($file); - if ($line < 0 || $lines === false || ($lineCount = count($lines)) < $line + 1) { - return ''; - } - - $half = (int)(($index == 0 ? $this->maxSourceLines : $this->maxTraceSourceLines) / 2); - $begin = $line - $half > 0 ? $line - $half : 0; - $end = $line + $half < $lineCount ? $line + $half : $lineCount - 1; - } - - return $this->renderFile($this->callStackItemView, [ - 'file' => $file, - 'line' => $line, - 'class' => $class, - 'method' => $method, - 'index' => $index, - 'lines' => $lines, - 'begin' => $begin, - 'end' => $end, - ]); - } - - /** - * Renders the request information. - * @return string the rendering result - */ - public function renderRequest() - { - $request = ''; - foreach (['_GET', '_POST', '_SERVER', '_FILES', '_COOKIE', '_SESSION', '_ENV'] as $name) { - if (!empty($GLOBALS[$name])) { - $request .= '$' . $name . ' = ' . var_export($GLOBALS[$name], true) . ";\n\n"; - } - } - return '
        ' . rtrim($request, "\n") . '
        '; - } - - /** - * Determines whether given name of the file belongs to the framework. - * @param string $file name to be checked. - * @return boolean whether given name of the file belongs to the framework. - */ - public function isCoreFile($file) - { - return $file === null || strpos(realpath($file), YII_PATH . DIRECTORY_SEPARATOR) === 0; - } - - /** - * Creates HTML containing link to the page with the information on given HTTP status code. - * @param integer $statusCode to be used to generate information link. - * @param string $statusDescription Description to display after the the status code. - * @return string generated HTML with HTTP status code information. - */ - public function createHttpStatusLink($statusCode, $statusDescription) - { - return 'HTTP ' . (int)$statusCode . ' – ' . $statusDescription . ''; - } - - /** - * Creates string containing HTML link which refers to the home page of determined web-server software - * and its full name. - * @return string server software information hyperlink. - */ - public function createServerInformationLink() - { - static $serverUrls = [ - 'http://httpd.apache.org/' => ['apache'], - 'http://nginx.org/' => ['nginx'], - 'http://lighttpd.net/' => ['lighttpd'], - 'http://gwan.com/' => ['g-wan', 'gwan'], - 'http://iis.net/' => ['iis', 'services'], - 'http://php.net/manual/en/features.commandline.webserver.php' => ['development'], - ]; - if (isset($_SERVER['SERVER_SOFTWARE'])) { - foreach ($serverUrls as $url => $keywords) { - foreach ($keywords as $keyword) { - if (stripos($_SERVER['SERVER_SOFTWARE'], $keyword) !== false) { - return '' . $this->htmlEncode($_SERVER['SERVER_SOFTWARE']) . ''; - } - } - } - } - return ''; - } - - /** - * Creates string containing HTML link which refers to the page with the current version - * of the framework and version number text. - * @return string framework version information hyperlink. - */ - public function createFrameworkVersionLink() - { - return '' . $this->htmlEncode(Yii::getVersion()) . ''; - } -} diff --git a/framework/yii/base/Event.php b/framework/yii/base/Event.php deleted file mode 100644 index 9845c77..0000000 --- a/framework/yii/base/Event.php +++ /dev/null @@ -1,185 +0,0 @@ - - * @since 2.0 - */ -class Event extends Object -{ - /** - * @var string the event name. This property is set by [[Component::trigger()]] and [[trigger()]]. - * Event handlers may use this property to check what event it is handling. - */ - public $name; - /** - * @var object the sender of this event. If not set, this property will be - * set as the object whose "trigger()" method is called. - * This property may also be a `null` when this event is a - * class-level event which is triggered in a static context. - */ - public $sender; - /** - * @var boolean whether the event is handled. Defaults to false. - * When a handler sets this to be true, the event processing will stop and - * ignore the rest of the uninvoked event handlers. - */ - public $handled = false; - /** - * @var mixed the data that is passed to [[Component::on()]] when attaching an event handler. - * Note that this varies according to which event handler is currently executing. - */ - public $data; - - private static $_events = []; - - /** - * Attaches an event handler to a class-level event. - * - * When a class-level event is triggered, event handlers attached - * to that class and all parent classes will be invoked. - * - * For example, the following code attaches an event handler to `ActiveRecord`'s - * `afterInsert` event: - * - * ~~~ - * Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) { - * Yii::trace(get_class($event->sender) . ' is inserted.'); - * }); - * ~~~ - * - * The handler will be invoked for EVERY successful ActiveRecord insertion. - * - * For more details about how to declare an event handler, please refer to [[Component::on()]]. - * - * @param string $class the fully qualified class name to which the event handler needs to attach. - * @param string $name the event name. - * @param callback $handler the event handler. - * @param mixed $data the data to be passed to the event handler when the event is triggered. - * When the event handler is invoked, this data can be accessed via [[Event::data]]. - * @see off() - */ - public static function on($class, $name, $handler, $data = null) - { - self::$_events[$name][ltrim($class, '\\')][] = [$handler, $data]; - } - - /** - * Detaches an event handler from a class-level event. - * - * This method is the opposite of [[on()]]. - * - * @param string $class the fully qualified class name from which the event handler needs to be detached. - * @param string $name the event name. - * @param callback $handler the event handler to be removed. - * If it is null, all handlers attached to the named event will be removed. - * @return boolean whether a handler is found and detached. - * @see on() - */ - public static function off($class, $name, $handler = null) - { - $class = ltrim($class, '\\'); - if (empty(self::$_events[$name][$class])) { - return false; - } - if ($handler === null) { - unset(self::$_events[$name][$class]); - return true; - } else { - $removed = false; - foreach (self::$_events[$name][$class] as $i => $event) { - if ($event[0] === $handler) { - unset(self::$_events[$name][$class][$i]); - $removed = true; - } - } - if ($removed) { - self::$_events[$name][$class] = array_values(self::$_events[$name][$class]); - } - return $removed; - } - } - - /** - * Returns a value indicating whether there is any handler attached to the specified class-level event. - * Note that this method will also check all parent classes to see if there is any handler attached - * to the named event. - * @param string|object $class the object or the fully qualified class name specifying the class-level event. - * @param string $name the event name. - * @return boolean whether there is any handler attached to the event. - */ - public static function hasHandlers($class, $name) - { - if (empty(self::$_events[$name])) { - return false; - } - if (is_object($class)) { - $class = get_class($class); - } else { - $class = ltrim($class, '\\'); - } - do { - if (!empty(self::$_events[$name][$class])) { - return true; - } - } while (($class = get_parent_class($class)) !== false); - return false; - } - - /** - * Triggers a class-level event. - * This method will cause invocation of event handlers that are attached to the named event - * for the specified class and all its parent classes. - * @param string|object $class the object or the fully qualified class name specifying the class-level event. - * @param string $name the event name. - * @param Event $event the event parameter. If not set, a default [[Event]] object will be created. - */ - public static function trigger($class, $name, $event = null) - { - if (empty(self::$_events[$name])) { - return; - } - if ($event === null) { - $event = new static; - } - $event->handled = false; - $event->name = $name; - - if (is_object($class)) { - if ($event->sender === null) { - $event->sender = $class; - } - $class = get_class($class); - } else { - $class = ltrim($class, '\\'); - } - do { - if (!empty(self::$_events[$name][$class])) { - foreach (self::$_events[$name][$class] as $handler) { - $event->data = $handler[1]; - call_user_func($handler[0], $event); - if ($event->handled) { - return; - } - } - } - } while (($class = get_parent_class($class)) !== false); - } -} diff --git a/framework/yii/base/Exception.php b/framework/yii/base/Exception.php deleted file mode 100644 index a5b2b99..0000000 --- a/framework/yii/base/Exception.php +++ /dev/null @@ -1,53 +0,0 @@ - - * @since 2.0 - */ -class Exception extends \Exception implements Arrayable -{ - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return 'Exception'; - } - - /** - * Returns the array representation of this object. - * @return array the array representation of this object. - */ - public function toArray() - { - return $this->toArrayRecursive($this); - } - - /** - * Returns the array representation of the exception and all previous exceptions recursively. - * @param \Exception $exception object - * @return array the array representation of the exception. - */ - protected function toArrayRecursive($exception) - { - $array = [ - 'type' => get_class($exception), - 'name' => $exception instanceof self ? $exception->getName() : 'Exception', - 'message' => $exception->getMessage(), - 'code' => $exception->getCode(), - ]; - if (($prev = $exception->getPrevious()) !== null) { - $array['previous'] = $this->toArrayRecursive($prev); - } - return $array; - } -} diff --git a/framework/yii/base/Extension.php b/framework/yii/base/Extension.php deleted file mode 100644 index c25a043..0000000 --- a/framework/yii/base/Extension.php +++ /dev/null @@ -1,29 +0,0 @@ - - * @since 2.0 - */ -class Extension -{ - /** - * Initializes the extension. - * This method is invoked at the end of [[Application::init()]]. - */ - public static function init() - { - } -} diff --git a/framework/yii/base/Formatter.php b/framework/yii/base/Formatter.php deleted file mode 100644 index bfc1e36..0000000 --- a/framework/yii/base/Formatter.php +++ /dev/null @@ -1,384 +0,0 @@ -formatter`. - * - * @author Qiang Xue - * @since 2.0 - */ -class Formatter extends Component -{ - /** - * @var string the default format string to be used to format a date using PHP date() function. - */ - public $dateFormat = 'Y/m/d'; - /** - * @var string the default format string to be used to format a time using PHP date() function. - */ - public $timeFormat = 'h:i:s A'; - /** - * @var string the default format string to be used to format a date and time using PHP date() function. - */ - public $datetimeFormat = 'Y/m/d h:i:s A'; - /** - * @var string the text to be displayed when formatting a null. Defaults to '(not set)'. - */ - public $nullDisplay; - /** - * @var array the text to be displayed when formatting a boolean value. The first element corresponds - * to the text display for false, the second element for true. Defaults to `['No', 'Yes']`. - */ - public $booleanFormat; - /** - * @var string the character displayed as the decimal point when formatting a number. - * If not set, "." will be used. - */ - public $decimalSeparator; - /** - * @var string the character displayed as the thousands separator character when formatting a number. - * If not set, "," will be used. - */ - public $thousandSeparator; - - - /** - * Initializes the component. - */ - public function init() - { - if (empty($this->booleanFormat)) { - $this->booleanFormat = [Yii::t('yii', 'No'), Yii::t('yii', 'Yes')]; - } - if ($this->nullDisplay === null) { - $this->nullDisplay = '' . Yii::t('yii', '(not set)') . ''; - } - } - - /** - * Formats the value based on the given format type. - * This method will call one of the "as" methods available in this class to do the formatting. - * For type "xyz", the method "asXyz" will be used. For example, if the format is "html", - * then [[asHtml()]] will be used. Format names are case insensitive. - * @param mixed $value the value to be formatted - * @param string|array $format the format of the value, e.g., "html", "text". To specify additional - * parameters of the formatting method, you may use an array. The first element of the array - * specifies the format name, while the rest of the elements will be used as the parameters to the formatting - * method. For example, a format of `['date', 'Y-m-d']` will cause the invocation of `asDate($value, 'Y-m-d')`. - * @return string the formatting result - * @throws InvalidParamException if the type is not supported by this class. - */ - public function format($value, $format) - { - if (is_array($format)) { - if (!isset($format[0])) { - throw new InvalidParamException('The $format array must contain at least one element.'); - } - $f = $format[0]; - $format[0] = $value; - $params = $format; - $format = $f; - } else { - $params = [$value]; - } - $method = 'as' . $format; - if (method_exists($this, $method)) { - return call_user_func_array([$this, $method], $params); - } else { - throw new InvalidParamException("Unknown type: $format"); - } - } - - /** - * Formats the value as is without any formatting. - * This method simply returns back the parameter without any format. - * @param mixed $value the value to be formatted - * @return string the formatted result - */ - public function asRaw($value) - { - if ($value === null) { - return $this->nullDisplay; - } - return $value; - } - - /** - * Formats the value as an HTML-encoded plain text. - * @param mixed $value the value to be formatted - * @return string the formatted result - */ - public function asText($value) - { - if ($value === null) { - return $this->nullDisplay; - } - return Html::encode($value); - } - - /** - * Formats the value as an HTML-encoded plain text with newlines converted into breaks. - * @param mixed $value the value to be formatted - * @return string the formatted result - */ - public function asNtext($value) - { - if ($value === null) { - return $this->nullDisplay; - } - return nl2br(Html::encode($value)); - } - - /** - * Formats the value as HTML-encoded text paragraphs. - * Each text paragraph is enclosed within a `

        ` tag. - * One or multiple consecutive empty lines divide two paragraphs. - * @param mixed $value the value to be formatted - * @return string the formatted result - */ - public function asParagraphs($value) - { - if ($value === null) { - return $this->nullDisplay; - } - return str_replace('

        ', '', - '

        ' . preg_replace('/[\r\n]{2,}/', "

        \n

        ", Html::encode($value)) . '

        ' - ); - } - - /** - * Formats the value as HTML text. - * The value will be purified using [[HtmlPurifier]] to avoid XSS attacks. - * Use [[asRaw()]] if you do not want any purification of the value. - * @param mixed $value the value to be formatted - * @param array|null $config the configuration for the HTMLPurifier class. - * @return string the formatted result - */ - public function asHtml($value, $config = null) - { - if ($value === null) { - return $this->nullDisplay; - } - return HtmlPurifier::process($value, $config); - } - - /** - * Formats the value as a mailto link. - * @param mixed $value the value to be formatted - * @return string the formatted result - */ - public function asEmail($value) - { - if ($value === null) { - return $this->nullDisplay; - } - return Html::mailto(Html::encode($value), $value); - } - - /** - * Formats the value as an image tag. - * @param mixed $value the value to be formatted - * @return string the formatted result - */ - public function asImage($value) - { - if ($value === null) { - return $this->nullDisplay; - } - return Html::img($value); - } - - /** - * Formats the value as a hyperlink. - * @param mixed $value the value to be formatted - * @return string the formatted result - */ - public function asUrl($value) - { - if ($value === null) { - return $this->nullDisplay; - } - $url = $value; - if (strpos($url, 'http://') !== 0 && strpos($url, 'https://') !== 0) { - $url = 'http://' . $url; - } - return Html::a(Html::encode($value), $url); - } - - /** - * Formats the value as a boolean. - * @param mixed $value the value to be formatted - * @return string the formatted result - * @see booleanFormat - */ - public function asBoolean($value) - { - if ($value === null) { - return $this->nullDisplay; - } - return $value ? $this->booleanFormat[1] : $this->booleanFormat[0]; - } - - /** - * Formats the value as a date. - * @param integer|string|DateTime $value the value to be formatted. The following - * types of value are supported: - * - * - an integer representing a UNIX timestamp - * - a string that can be parsed into a UNIX timestamp via `strtotime()` - * - a PHP DateTime object - * - * @param string $format the format used to convert the value into a date string. - * If null, [[dateFormat]] will be used. The format string should be one - * that can be recognized by the PHP `date()` function. - * @return string the formatted result - * @see dateFormat - */ - public function asDate($value, $format = null) - { - if ($value === null) { - return $this->nullDisplay; - } - $value = $this->normalizeDatetimeValue($value); - return date($format === null ? $this->dateFormat : $format, $value); - } - - /** - * Formats the value as a time. - * @param integer|string|DateTime $value the value to be formatted. The following - * types of value are supported: - * - * - an integer representing a UNIX timestamp - * - a string that can be parsed into a UNIX timestamp via `strtotime()` - * - a PHP DateTime object - * - * @param string $format the format used to convert the value into a date string. - * If null, [[timeFormat]] will be used. The format string should be one - * that can be recognized by the PHP `date()` function. - * @return string the formatted result - * @see timeFormat - */ - public function asTime($value, $format = null) - { - if ($value === null) { - return $this->nullDisplay; - } - $value = $this->normalizeDatetimeValue($value); - return date($format === null ? $this->timeFormat : $format, $value); - } - - /** - * Formats the value as a datetime. - * @param integer|string|DateTime $value the value to be formatted. The following - * types of value are supported: - * - * - an integer representing a UNIX timestamp - * - a string that can be parsed into a UNIX timestamp via `strtotime()` - * - a PHP DateTime object - * - * @param string $format the format used to convert the value into a date string. - * If null, [[datetimeFormat]] will be used. The format string should be one - * that can be recognized by the PHP `date()` function. - * @return string the formatted result - * @see datetimeFormat - */ - public function asDatetime($value, $format = null) - { - if ($value === null) { - return $this->nullDisplay; - } - $value = $this->normalizeDatetimeValue($value); - return date($format === null ? $this->datetimeFormat : $format, $value); - } - - /** - * Normalizes the given datetime value as one that can be taken by various date/time formatting methods. - * @param mixed $value the datetime value to be normalized. - * @return integer the normalized datetime value - */ - protected function normalizeDatetimeValue($value) - { - if (is_string($value)) { - return is_numeric($value) || $value === '' ? (int)$value : strtotime($value); - } elseif ($value instanceof DateTime) { - return $value->getTimestamp(); - } else { - return (int)$value; - } - } - - /** - * Formats the value as an integer. - * @param mixed $value the value to be formatted - * @return string the formatting result. - */ - public function asInteger($value) - { - if ($value === null) { - return $this->nullDisplay; - } - if (is_string($value) && preg_match('/^(-?\d+)/', $value, $matches)) { - return $matches[1]; - } else { - $value = (int)$value; - return "$value"; - } - } - - /** - * Formats the value as a double number. - * Property [[decimalSeparator]] will be used to represent the decimal point. - * @param mixed $value the value to be formatted - * @param integer $decimals the number of digits after the decimal point - * @return string the formatting result. - * @see decimalSeparator - */ - public function asDouble($value, $decimals = 2) - { - if ($value === null) { - return $this->nullDisplay; - } - if ($this->decimalSeparator === null) { - return sprintf("%.{$decimals}f", $value); - } else { - return str_replace('.', $this->decimalSeparator, sprintf("%.{$decimals}f", $value)); - } - } - - /** - * Formats the value as a number with decimal and thousand separators. - * This method calls the PHP number_format() function to do the formatting. - * @param mixed $value the value to be formatted - * @param integer $decimals the number of digits after the decimal point - * @return string the formatted result - * @see decimalSeparator - * @see thousandSeparator - */ - public function asNumber($value, $decimals = 0) - { - if ($value === null) { - return $this->nullDisplay; - } - $ds = isset($this->decimalSeparator) ? $this->decimalSeparator: '.'; - $ts = isset($this->thousandSeparator) ? $this->thousandSeparator: ','; - return number_format($value, $decimals, $ds, $ts); - } -} diff --git a/framework/yii/base/InlineAction.php b/framework/yii/base/InlineAction.php deleted file mode 100644 index 412b357..0000000 --- a/framework/yii/base/InlineAction.php +++ /dev/null @@ -1,55 +0,0 @@ - - * @since 2.0 - */ -class InlineAction extends Action -{ - /** - * @var string the controller method that this inline action is associated with - */ - public $actionMethod; - - /** - * @param string $id the ID of this action - * @param Controller $controller the controller that owns this action - * @param string $actionMethod the controller method that this inline action is associated with - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($id, $controller, $actionMethod, $config = []) - { - $this->actionMethod = $actionMethod; - parent::__construct($id, $controller, $config); - } - - /** - * Runs this action with the specified parameters. - * This method is mainly invoked by the controller. - * @param array $params action parameters - * @return mixed the result of the action - */ - public function runWithParams($params) - { - $args = $this->controller->bindActionParams($this, $params); - Yii::trace('Running action: ' . get_class($this->controller) . '::' . $this->actionMethod . '()', __METHOD__); - if (Yii::$app->requestedParams === null) { - Yii::$app->requestedParams = $args; - } - return call_user_func_array([$this->controller, $this->actionMethod], $args); - } -} diff --git a/framework/yii/base/InvalidCallException.php b/framework/yii/base/InvalidCallException.php deleted file mode 100644 index bc46ca4..0000000 --- a/framework/yii/base/InvalidCallException.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class InvalidCallException extends Exception -{ - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return 'Invalid Call'; - } -} diff --git a/framework/yii/base/InvalidConfigException.php b/framework/yii/base/InvalidConfigException.php deleted file mode 100644 index 1fb0b4a..0000000 --- a/framework/yii/base/InvalidConfigException.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class InvalidConfigException extends Exception -{ - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return 'Invalid Configuration'; - } -} diff --git a/framework/yii/base/InvalidParamException.php b/framework/yii/base/InvalidParamException.php deleted file mode 100644 index b2f9191..0000000 --- a/framework/yii/base/InvalidParamException.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class InvalidParamException extends Exception -{ - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return 'Invalid Parameter'; - } -} diff --git a/framework/yii/base/InvalidRouteException.php b/framework/yii/base/InvalidRouteException.php deleted file mode 100644 index b94fab6..0000000 --- a/framework/yii/base/InvalidRouteException.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class InvalidRouteException extends UserException -{ - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return 'Invalid Route'; - } -} diff --git a/framework/yii/base/MailEvent.php b/framework/yii/base/MailEvent.php deleted file mode 100644 index 6e9da2e..0000000 --- a/framework/yii/base/MailEvent.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @since 2.0 - */ -class MailEvent extends Event -{ - - /** - * @var \yii\mail\MessageInterface mail message being send - */ - public $message; - /** - * @var boolean if message send was successful - */ - public $isSuccessful; - /** - * @var boolean whether to continue send. Event handlers of - * [[\yii\mail\BaseMailer::EVENT_BEFORE_SEND]] may set this property to decide whether - * to continue send or not. - */ - public $isValid = true; -} diff --git a/framework/yii/base/Model.php b/framework/yii/base/Model.php deleted file mode 100644 index ba51ec7..0000000 --- a/framework/yii/base/Model.php +++ /dev/null @@ -1,858 +0,0 @@ - value). - * @property array $errors An array of errors for all attributes. Empty array is returned if no error. The - * result is a two-dimensional array. See [[getErrors()]] for detailed description. This property is read-only. - * @property array $firstErrors The first errors. An empty array will be returned if there is no error. This - * property is read-only. - * @property ArrayIterator $iterator An iterator for traversing the items in the list. This property is - * read-only. - * @property string $scenario The scenario that this model is in. Defaults to [[DEFAULT_SCENARIO]]. - * @property ArrayObject|\yii\validators\Validator[] $validators All the validators declared in the model. - * This property is read-only. - * - * @author Qiang Xue - * @since 2.0 - */ -class Model extends Component implements IteratorAggregate, ArrayAccess -{ - /** - * The name of the default scenario. - */ - const DEFAULT_SCENARIO = 'default'; - - /** - * @event ModelEvent an event raised at the beginning of [[validate()]]. You may set - * [[ModelEvent::isValid]] to be false to stop the validation. - */ - const EVENT_BEFORE_VALIDATE = 'beforeValidate'; - /** - * @event Event an event raised at the end of [[validate()]] - */ - const EVENT_AFTER_VALIDATE = 'afterValidate'; - - /** - * @var array validation errors (attribute name => array of errors) - */ - private $_errors; - /** - * @var ArrayObject list of validators - */ - private $_validators; - /** - * @var string current scenario - */ - private $_scenario = self::DEFAULT_SCENARIO; - - /** - * Returns the validation rules for attributes. - * - * Validation rules are used by [[validate()]] to check if attribute values are valid. - * Child classes may override this method to declare different validation rules. - * - * Each rule is an array with the following structure: - * - * ~~~ - * [ - * ['attribute1', 'attribute2'], - * 'validator type', - * 'on' => ['scenario1', 'scenario2'], - * ...other parameters... - * ] - * ~~~ - * - * where - * - * - attribute list: required, specifies the attributes array to be validated, for single attribute you can pass string; - * - validator type: required, specifies the validator to be used. It can be the name of a model - * class method, the name of a built-in validator, or a validator class name (or its path alias). - * - on: optional, specifies the [[scenario|scenarios]] array when the validation - * rule can be applied. If this option is not set, the rule will apply to all scenarios. - * - additional name-value pairs can be specified to initialize the corresponding validator properties. - * Please refer to individual validator class API for possible properties. - * - * A validator can be either an object of a class extending [[Validator]], or a model class method - * (called *inline validator*) that has the following signature: - * - * ~~~ - * // $params refers to validation parameters given in the rule - * function validatorName($attribute, $params) - * ~~~ - * - * In the above `$attribute` refers to currently validated attribute name while `$params` contains an array of - * validator configuration options such as `max` in case of `string` validator. Currently validate attribute value - * can be accessed as `$this->[$attribute]`. - * - * Yii also provides a set of [[Validator::builtInValidators|built-in validators]]. - * They each has an alias name which can be used when specifying a validation rule. - * - * Below are some examples: - * - * ~~~ - * [ - * // built-in "required" validator - * [['username', 'password'], 'required'], - * // built-in "string" validator customized with "min" and "max" properties - * ['username', 'string', 'min' => 3, 'max' => 12], - * // built-in "compare" validator that is used in "register" scenario only - * ['password', 'compare', 'compareAttribute' => 'password2', 'on' => 'register'], - * // an inline validator defined via the "authenticate()" method in the model class - * ['password', 'authenticate', 'on' => 'login'], - * // a validator of class "DateRangeValidator" - * ['dateRange', 'DateRangeValidator'], - * ]; - * ~~~ - * - * Note, in order to inherit rules defined in the parent class, a child class needs to - * merge the parent rules with child rules using functions such as `array_merge()`. - * - * @return array validation rules - * @see scenarios() - */ - public function rules() - { - return []; - } - - /** - * Returns a list of scenarios and the corresponding active attributes. - * An active attribute is one that is subject to validation in the current scenario. - * The returned array should be in the following format: - * - * ~~~ - * [ - * 'scenario1' => ['attribute11', 'attribute12', ...], - * 'scenario2' => ['attribute21', 'attribute22', ...], - * ... - * ] - * ~~~ - * - * By default, an active attribute is considered safe and can be massively assigned. - * If an attribute should NOT be massively assigned (thus considered unsafe), - * please prefix the attribute with an exclamation character (e.g. '!rank'). - * - * The default implementation of this method will return all scenarios found in the [[rules()]] - * declaration. A special scenario named [[DEFAULT_SCENARIO]] will contain all attributes - * found in the [[rules()]]. Each scenario will be associated with the attributes that - * are being validated by the validation rules that apply to the scenario. - * - * @return array a list of scenarios and the corresponding active attributes. - */ - public function scenarios() - { - $scenarios = [self::DEFAULT_SCENARIO => []]; - foreach ($this->getValidators() as $validator) { - foreach ($validator->on as $scenario) { - $scenarios[$scenario] = []; - } - foreach ($validator->except as $scenario) { - $scenarios[$scenario] = []; - } - } - $names = array_keys($scenarios); - - foreach ($this->getValidators() as $validator) { - if (empty($validator->on) && empty($validator->except)) { - foreach ($names as $name) { - foreach ($validator->attributes as $attribute) { - $scenarios[$name][$attribute] = true; - } - } - } elseif (empty($validator->on)) { - foreach ($names as $name) { - if (!in_array($name, $validator->except, true)) { - foreach ($validator->attributes as $attribute) { - $scenarios[$name][$attribute] = true; - } - } - } - } else { - foreach ($validator->on as $name) { - foreach ($validator->attributes as $attribute) { - $scenarios[$name][$attribute] = true; - } - } - } - } - - foreach ($scenarios as $scenario => $attributes) { - if (empty($attributes) && $scenario !== self::DEFAULT_SCENARIO) { - unset($scenarios[$scenario]); - } else { - $scenarios[$scenario] = array_keys($attributes); - } - } - - return $scenarios; - } - - /** - * Returns the form name that this model class should use. - * - * The form name is mainly used by [[\yii\web\ActiveForm]] to determine how to name - * the input fields for the attributes in a model. If the form name is "A" and an attribute - * name is "b", then the corresponding input name would be "A[b]". If the form name is - * an empty string, then the input name would be "b". - * - * By default, this method returns the model class name (without the namespace part) - * as the form name. You may override it when the model is used in different forms. - * - * @return string the form name of this model class. - */ - public function formName() - { - $reflector = new ReflectionClass($this); - return $reflector->getShortName(); - } - - /** - * Returns the list of attribute names. - * By default, this method returns all public non-static properties of the class. - * You may override this method to change the default behavior. - * @return array list of attribute names. - */ - public function attributes() - { - $class = new ReflectionClass($this); - $names = []; - foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) { - if (!$property->isStatic()) { - $names[] = $property->getName(); - } - } - return $names; - } - - /** - * Returns the attribute labels. - * - * Attribute labels are mainly used for display purpose. For example, given an attribute - * `firstName`, we can declare a label `First Name` which is more user-friendly and can - * be displayed to end users. - * - * By default an attribute label is generated using [[generateAttributeLabel()]]. - * This method allows you to explicitly specify attribute labels. - * - * Note, in order to inherit labels defined in the parent class, a child class needs to - * merge the parent labels with child labels using functions such as `array_merge()`. - * - * @return array attribute labels (name => label) - * @see generateAttributeLabel() - */ - public function attributeLabels() - { - return []; - } - - /** - * Performs the data validation. - * - * This method executes the validation rules applicable to the current [[scenario]]. - * The following criteria are used to determine whether a rule is currently applicable: - * - * - the rule must be associated with the attributes relevant to the current scenario; - * - the rules must be effective for the current scenario. - * - * This method will call [[beforeValidate()]] and [[afterValidate()]] before and - * after the actual validation, respectively. If [[beforeValidate()]] returns false, - * the validation will be cancelled and [[afterValidate()]] will not be called. - * - * Errors found during the validation can be retrieved via [[getErrors()]], - * [[getFirstErrors()]] and [[getFirstError()]]. - * - * @param array $attributes list of attributes that should be validated. - * If this parameter is empty, it means any attribute listed in the applicable - * validation rules should be validated. - * @param boolean $clearErrors whether to call [[clearErrors()]] before performing validation - * @return boolean whether the validation is successful without any error. - * @throws InvalidParamException if the current scenario is unknown. - */ - public function validate($attributes = null, $clearErrors = true) - { - $scenarios = $this->scenarios(); - $scenario = $this->getScenario(); - if (!isset($scenarios[$scenario])) { - throw new InvalidParamException("Unknown scenario: $scenario"); - } - - if ($clearErrors) { - $this->clearErrors(); - } - if ($attributes === null) { - $attributes = $this->activeAttributes(); - } - if ($this->beforeValidate()) { - foreach ($this->getActiveValidators() as $validator) { - $validator->validateAttributes($this, $attributes); - } - $this->afterValidate(); - return !$this->hasErrors(); - } - return false; - } - - /** - * This method is invoked before validation starts. - * The default implementation raises a `beforeValidate` event. - * You may override this method to do preliminary checks before validation. - * Make sure the parent implementation is invoked so that the event can be raised. - * @return boolean whether the validation should be executed. Defaults to true. - * If false is returned, the validation will stop and the model is considered invalid. - */ - public function beforeValidate() - { - $event = new ModelEvent; - $this->trigger(self::EVENT_BEFORE_VALIDATE, $event); - return $event->isValid; - } - - /** - * This method is invoked after validation ends. - * The default implementation raises an `afterValidate` event. - * You may override this method to do postprocessing after validation. - * Make sure the parent implementation is invoked so that the event can be raised. - */ - public function afterValidate() - { - $this->trigger(self::EVENT_AFTER_VALIDATE); - } - - /** - * Returns all the validators declared in [[rules()]]. - * - * This method differs from [[getActiveValidators()]] in that the latter - * only returns the validators applicable to the current [[scenario]]. - * - * Because this method returns an ArrayObject object, you may - * manipulate it by inserting or removing validators (useful in model behaviors). - * For example, - * - * ~~~ - * $model->validators[] = $newValidator; - * ~~~ - * - * @return ArrayObject|\yii\validators\Validator[] all the validators declared in the model. - */ - public function getValidators() - { - if ($this->_validators === null) { - $this->_validators = $this->createValidators(); - } - return $this->_validators; - } - - /** - * Returns the validators applicable to the current [[scenario]]. - * @param string $attribute the name of the attribute whose applicable validators should be returned. - * If this is null, the validators for ALL attributes in the model will be returned. - * @return \yii\validators\Validator[] the validators applicable to the current [[scenario]]. - */ - public function getActiveValidators($attribute = null) - { - $validators = []; - $scenario = $this->getScenario(); - foreach ($this->getValidators() as $validator) { - if ($validator->isActive($scenario) && ($attribute === null || in_array($attribute, $validator->attributes, true))) { - $validators[] = $validator; - } - } - return $validators; - } - - /** - * Creates validator objects based on the validation rules specified in [[rules()]]. - * Unlike [[getValidators()]], each time this method is called, a new list of validators will be returned. - * @return ArrayObject validators - * @throws InvalidConfigException if any validation rule configuration is invalid - */ - public function createValidators() - { - $validators = new ArrayObject; - foreach ($this->rules() as $rule) { - if ($rule instanceof Validator) { - $validators->append($rule); - } elseif (is_array($rule) && isset($rule[0], $rule[1])) { // attributes, validator type - $validator = Validator::createValidator($rule[1], $this, (array) $rule[0], array_slice($rule, 2)); - $validators->append($validator); - } else { - throw new InvalidConfigException('Invalid validation rule: a rule must specify both attribute names and validator type.'); - } - } - return $validators; - } - - /** - * Returns a value indicating whether the attribute is required. - * This is determined by checking if the attribute is associated with a - * [[\yii\validators\RequiredValidator|required]] validation rule in the - * current [[scenario]]. - * @param string $attribute attribute name - * @return boolean whether the attribute is required - */ - public function isAttributeRequired($attribute) - { - foreach ($this->getActiveValidators($attribute) as $validator) { - if ($validator instanceof RequiredValidator) { - return true; - } - } - return false; - } - - /** - * Returns a value indicating whether the attribute is safe for massive assignments. - * @param string $attribute attribute name - * @return boolean whether the attribute is safe for massive assignments - * @see safeAttributes() - */ - public function isAttributeSafe($attribute) - { - return in_array($attribute, $this->safeAttributes(), true); - } - - /** - * Returns a value indicating whether the attribute is active in the current scenario. - * @param string $attribute attribute name - * @return boolean whether the attribute is active in the current scenario - * @see activeAttributes() - */ - public function isAttributeActive($attribute) - { - return in_array($attribute, $this->activeAttributes(), true); - } - - /** - * Returns the text label for the specified attribute. - * @param string $attribute the attribute name - * @return string the attribute label - * @see generateAttributeLabel() - * @see attributeLabels() - */ - public function getAttributeLabel($attribute) - { - $labels = $this->attributeLabels(); - return isset($labels[$attribute]) ? $labels[$attribute] : $this->generateAttributeLabel($attribute); - } - - /** - * Returns a value indicating whether there is any validation error. - * @param string|null $attribute attribute name. Use null to check all attributes. - * @return boolean whether there is any error. - */ - public function hasErrors($attribute = null) - { - return $attribute === null ? !empty($this->_errors) : isset($this->_errors[$attribute]); - } - - /** - * Returns the errors for all attribute or a single attribute. - * @param string $attribute attribute name. Use null to retrieve errors for all attributes. - * @property array An array of errors for all attributes. Empty array is returned if no error. - * The result is a two-dimensional array. See [[getErrors()]] for detailed description. - * @return array errors for all attributes or the specified attribute. Empty array is returned if no error. - * Note that when returning errors for all attributes, the result is a two-dimensional array, like the following: - * - * ~~~ - * [ - * 'username' => [ - * 'Username is required.', - * 'Username must contain only word characters.', - * ], - * 'email' => [ - * 'Email address is invalid.', - * ] - * ] - * ~~~ - * - * @see getFirstErrors() - * @see getFirstError() - */ - public function getErrors($attribute = null) - { - if ($attribute === null) { - return $this->_errors === null ? [] : $this->_errors; - } else { - return isset($this->_errors[$attribute]) ? $this->_errors[$attribute] : []; - } - } - - /** - * Returns the first error of every attribute in the model. - * @return array the first errors. An empty array will be returned if there is no error. - * @see getErrors() - * @see getFirstError() - */ - public function getFirstErrors() - { - if (empty($this->_errors)) { - return []; - } else { - $errors = []; - foreach ($this->_errors as $attributeErrors) { - if (isset($attributeErrors[0])) { - $errors[] = $attributeErrors[0]; - } - } - } - return $errors; - } - - /** - * Returns the first error of the specified attribute. - * @param string $attribute attribute name. - * @return string the error message. Null is returned if no error. - * @see getErrors() - * @see getFirstErrors() - */ - public function getFirstError($attribute) - { - return isset($this->_errors[$attribute]) ? reset($this->_errors[$attribute]) : null; - } - - /** - * Adds a new error to the specified attribute. - * @param string $attribute attribute name - * @param string $error new error message - */ - public function addError($attribute, $error = '') - { - $this->_errors[$attribute][] = $error; - } - - /** - * Removes errors for all attributes or a single attribute. - * @param string $attribute attribute name. Use null to remove errors for all attribute. - */ - public function clearErrors($attribute = null) - { - if ($attribute === null) { - $this->_errors = []; - } else { - unset($this->_errors[$attribute]); - } - } - - /** - * Generates a user friendly attribute label based on the give attribute name. - * This is done by replacing underscores, dashes and dots with blanks and - * changing the first letter of each word to upper case. - * For example, 'department_name' or 'DepartmentName' will generate 'Department Name'. - * @param string $name the column name - * @return string the attribute label - */ - public function generateAttributeLabel($name) - { - return Inflector::camel2words($name, true); - } - - /** - * Returns attribute values. - * @param array $names list of attributes whose value needs to be returned. - * Defaults to null, meaning all attributes listed in [[attributes()]] will be returned. - * If it is an array, only the attributes in the array will be returned. - * @param array $except list of attributes whose value should NOT be returned. - * @return array attribute values (name => value). - */ - public function getAttributes($names = null, $except = []) - { - $values = []; - if ($names === null) { - $names = $this->attributes(); - } - foreach ($names as $name) { - $values[$name] = $this->$name; - } - foreach ($except as $name) { - unset($values[$name]); - } - - return $values; - } - - /** - * Sets the attribute values in a massive way. - * @param array $values attribute values (name => value) to be assigned to the model. - * @param boolean $safeOnly whether the assignments should only be done to the safe attributes. - * A safe attribute is one that is associated with a validation rule in the current [[scenario]]. - * @see safeAttributes() - * @see attributes() - */ - public function setAttributes($values, $safeOnly = true) - { - if (is_array($values)) { - $attributes = array_flip($safeOnly ? $this->safeAttributes() : $this->attributes()); - foreach ($values as $name => $value) { - if (isset($attributes[$name])) { - $this->$name = $value; - } elseif ($safeOnly) { - $this->onUnsafeAttribute($name, $value); - } - } - } - } - - /** - * This method is invoked when an unsafe attribute is being massively assigned. - * The default implementation will log a warning message if YII_DEBUG is on. - * It does nothing otherwise. - * @param string $name the unsafe attribute name - * @param mixed $value the attribute value - */ - public function onUnsafeAttribute($name, $value) - { - if (YII_DEBUG) { - Yii::trace("Failed to set unsafe attribute '$name' in '" . get_class($this) . "'.", __METHOD__); - } - } - - /** - * Returns the scenario that this model is used in. - * - * Scenario affects how validation is performed and which attributes can - * be massively assigned. - * - * @return string the scenario that this model is in. Defaults to [[DEFAULT_SCENARIO]]. - */ - public function getScenario() - { - return $this->_scenario; - } - - /** - * Sets the scenario for the model. - * Note that this method does not check if the scenario exists or not. - * The method [[validate()]] will perform this check. - * @param string $value the scenario that this model is in. - */ - public function setScenario($value) - { - $this->_scenario = $value; - } - - /** - * Returns the attribute names that are safe to be massively assigned in the current scenario. - * @return string[] safe attribute names - */ - public function safeAttributes() - { - $scenario = $this->getScenario(); - $scenarios = $this->scenarios(); - if (!isset($scenarios[$scenario])) { - return []; - } - $attributes = []; - foreach ($scenarios[$scenario] as $attribute) { - if ($attribute[0] !== '!') { - $attributes[] = $attribute; - } - } - return $attributes; - } - - /** - * Returns the attribute names that are subject to validation in the current scenario. - * @return string[] safe attribute names - */ - public function activeAttributes() - { - $scenario = $this->getScenario(); - $scenarios = $this->scenarios(); - if (!isset($scenarios[$scenario])) { - return []; - } - $attributes = $scenarios[$scenario]; - foreach ($attributes as $i => $attribute) { - if ($attribute[0] === '!') { - $attributes[$i] = substr($attribute, 1); - } - } - return $attributes; - } - - /** - * Populates the model with the data from end user. - * The data to be loaded is `$data[formName]`, where `formName` refers to the value of [[formName()]]. - * If [[formName()]] is empty, the whole `$data` array will be used to populate the model. - * The data being populated is subject to the safety check by [[setAttributes()]]. - * @param array $data the data array. This is usually `$_POST` or `$_GET`, but can also be any valid array - * supplied by end user. - * @param string $formName the form name to be used for loading the data into the model. - * If not set, [[formName()]] will be used. - * @return boolean whether the model is successfully populated with some data. - */ - public function load($data, $formName = null) - { - $scope = $formName === null ? $this->formName() : $formName; - if ($scope == '') { - $this->setAttributes($data); - return true; - } elseif (isset($data[$scope])) { - $this->setAttributes($data[$scope]); - return true; - } else { - return false; - } - } - - /** - * Populates a set of models with the data from end user. - * This method is mainly used to collect tabular data input. - * The data to be loaded for each model is `$data[formName][index]`, where `formName` - * refers to the value of [[formName()]], and `index` the index of the model in the `$models` array. - * If [[formName()]] is empty, `$data[index]` will be used to populate each model. - * The data being populated to each model is subject to the safety check by [[setAttributes()]]. - * @param array $models the models to be populated. Note that all models should have the same class. - * @param array $data the data array. This is usually `$_POST` or `$_GET`, but can also be any valid array - * supplied by end user. - * @return boolean whether the model is successfully populated with some data. - */ - public static function loadMultiple($models, $data) - { - /** @var Model $model */ - $model = reset($models); - if ($model === false) { - return false; - } - $success = false; - $scope = $model->formName(); - foreach ($models as $i => $model) { - if ($scope == '') { - if (isset($data[$i])) { - $model->setAttributes($data[$i]); - $success = true; - } - } elseif (isset($data[$scope][$i])) { - $model->setAttributes($data[$scope][$i]); - $success = true; - } - } - return $success; - } - - /** - * Validates multiple models. - * This method will validate every model. The models being validated may - * be of the same or different types. - * @param array $models the models to be validated - * @param array $attributes list of attributes that should be validated. - * If this parameter is empty, it means any attribute listed in the applicable - * validation rules should be validated. - * @return boolean whether all models are valid. False will be returned if one - * or multiple models have validation error. - */ - public static function validateMultiple($models, $attributes = null) - { - $valid = true; - /** @var Model $model */ - foreach ($models as $model) { - $valid = $model->validate($attributes) && $valid; - } - return $valid; - } - - /** - * Converts the object into an array. - * The default implementation will return [[attributes]]. - * @return array the array representation of the object - */ - public function toArray() - { - return $this->getAttributes(); - } - - /** - * Returns an iterator for traversing the attributes in the model. - * This method is required by the interface IteratorAggregate. - * @return ArrayIterator an iterator for traversing the items in the list. - */ - public function getIterator() - { - $attributes = $this->getAttributes(); - return new ArrayIterator($attributes); - } - - /** - * Returns whether there is an element at the specified offset. - * This method is required by the SPL interface `ArrayAccess`. - * It is implicitly called when you use something like `isset($model[$offset])`. - * @param mixed $offset the offset to check on - * @return boolean - */ - public function offsetExists($offset) - { - return $this->$offset !== null; - } - - /** - * Returns the element at the specified offset. - * This method is required by the SPL interface `ArrayAccess`. - * It is implicitly called when you use something like `$value = $model[$offset];`. - * @param mixed $offset the offset to retrieve element. - * @return mixed the element at the offset, null if no element is found at the offset - */ - public function offsetGet($offset) - { - return $this->$offset; - } - - /** - * Sets the element at the specified offset. - * This method is required by the SPL interface `ArrayAccess`. - * It is implicitly called when you use something like `$model[$offset] = $item;`. - * @param integer $offset the offset to set element - * @param mixed $item the element value - */ - public function offsetSet($offset, $item) - { - $this->$offset = $item; - } - - /** - * Sets the element value at the specified offset to null. - * This method is required by the SPL interface `ArrayAccess`. - * It is implicitly called when you use something like `unset($model[$offset])`. - * @param mixed $offset the offset to unset element - */ - public function offsetUnset($offset) - { - $this->$offset = null; - } -} diff --git a/framework/yii/base/ModelEvent.php b/framework/yii/base/ModelEvent.php deleted file mode 100644 index 57e41f9..0000000 --- a/framework/yii/base/ModelEvent.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class ModelEvent extends Event -{ - /** - * @var boolean whether the model is in valid status. Defaults to true. - * A model is in valid status if it passes validations or certain checks. - */ - public $isValid = true; -} diff --git a/framework/yii/base/Module.php b/framework/yii/base/Module.php deleted file mode 100644 index 83dbb4c..0000000 --- a/framework/yii/base/Module.php +++ /dev/null @@ -1,667 +0,0 @@ - - * @since 2.0 - */ -abstract class Module extends Component -{ - /** - * @var array custom module parameters (name => value). - */ - public $params = []; - /** - * @var array the IDs of the components or modules that should be preloaded right after initialization. - */ - public $preload = []; - /** - * @var string an ID that uniquely identifies this module among other modules which have the same [[module|parent]]. - */ - public $id; - /** - * @var Module the parent module of this module. Null if this module does not have a parent. - */ - public $module; - /** - * @var string|boolean the layout that should be applied for views within this module. This refers to a view name - * relative to [[layoutPath]]. If this is not set, it means the layout value of the [[module|parent module]] - * will be taken. If this is false, layout will be disabled within this module. - */ - public $layout; - /** - * @var array mapping from controller ID to controller configurations. - * Each name-value pair specifies the configuration of a single controller. - * A controller configuration can be either a string or an array. - * If the former, the string should be the fully qualified class name of the controller. - * If the latter, the array must contain a 'class' element which specifies - * the controller's fully qualified class name, and the rest of the name-value pairs - * in the array are used to initialize the corresponding controller properties. For example, - * - * ~~~ - * [ - * 'account' => 'app\controllers\UserController', - * 'article' => [ - * 'class' => 'app\controllers\PostController', - * 'pageTitle' => 'something new', - * ], - * ] - * ~~~ - */ - public $controllerMap = []; - /** - * @var string the namespace that controller classes are in. If not set, - * it will use the "controllers" sub-namespace under the namespace of this module. - * For example, if the namespace of this module is "foo\bar", then the default - * controller namespace would be "foo\bar\controllers". - */ - public $controllerNamespace; - /** - * @return string the default route of this module. Defaults to 'default'. - * The route may consist of child module ID, controller ID, and/or action ID. - * For example, `help`, `post/create`, `admin/post/create`. - * If action ID is not given, it will take the default value as specified in - * [[Controller::defaultAction]]. - */ - public $defaultRoute = 'default'; - /** - * @var string the root directory of the module. - */ - private $_basePath; - /** - * @var string the root directory that contains view files for this module - */ - private $_viewPath; - /** - * @var string the root directory that contains layout view files for this module. - */ - private $_layoutPath; - /** - * @var string the directory containing controller classes in the module. - */ - private $_controllerPath; - /** - * @var array child modules of this module - */ - private $_modules = []; - /** - * @var array components registered under this module - */ - private $_components = []; - - /** - * Constructor. - * @param string $id the ID of this module - * @param Module $parent the parent module (if any) - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($id, $parent = null, $config = []) - { - $this->id = $id; - $this->module = $parent; - parent::__construct($config); - } - - /** - * Getter magic method. - * This method is overridden to support accessing components - * like reading module properties. - * @param string $name component or property name - * @return mixed the named property value - */ - public function __get($name) - { - if ($this->hasComponent($name)) { - return $this->getComponent($name); - } else { - return parent::__get($name); - } - } - - /** - * Checks if a property value is null. - * This method overrides the parent implementation by checking - * if the named component is loaded. - * @param string $name the property name or the event name - * @return boolean whether the property value is null - */ - public function __isset($name) - { - if ($this->hasComponent($name)) { - return $this->getComponent($name) !== null; - } else { - return parent::__isset($name); - } - } - - /** - * Initializes the module. - * This method is called after the module is created and initialized with property values - * given in configuration. The default implementation will call [[preloadComponents()]] to - * load components that are declared in [[preload]]. - * - * If you override this method, please make sure you call the parent implementation. - */ - public function init() - { - if ($this->controllerNamespace === null) { - $class = get_class($this); - if (($pos = strrpos($class, '\\')) !== false) { - $this->controllerNamespace = substr($class, 0, $pos) . '\\controllers'; - } - } - $this->preloadComponents(); - } - - /** - * Returns an ID that uniquely identifies this module among all modules within the current application. - * Note that if the module is an application, an empty string will be returned. - * @return string the unique ID of the module. - */ - public function getUniqueId() - { - return $this->module ? ltrim($this->module->getUniqueId() . '/' . $this->id, '/') : $this->id; - } - - /** - * Returns the root directory of the module. - * It defaults to the directory containing the module class file. - * @return string the root directory of the module. - */ - public function getBasePath() - { - if ($this->_basePath === null) { - $class = new \ReflectionClass($this); - $this->_basePath = dirname($class->getFileName()); - } - return $this->_basePath; - } - - /** - * Sets the root directory of the module. - * This method can only be invoked at the beginning of the constructor. - * @param string $path the root directory of the module. This can be either a directory name or a path alias. - * @throws InvalidParamException if the directory does not exist. - */ - public function setBasePath($path) - { - $path = Yii::getAlias($path); - $p = realpath($path); - if ($p !== false && is_dir($p)) { - $this->_basePath = $p; - } else { - throw new InvalidParamException("The directory does not exist: $path"); - } - } - - /** - * Returns the directory that contains the controller classes. - * Defaults to "[[basePath]]/controllers". - * @return string the directory that contains the controller classes. - */ - public function getControllerPath() - { - if ($this->_controllerPath !== null) { - return $this->_controllerPath; - } else { - return $this->_controllerPath = $this->getBasePath() . DIRECTORY_SEPARATOR . 'controllers'; - } - } - - /** - * Sets the directory that contains the controller classes. - * @param string $path the directory that contains the controller classes. - * This can be either a directory name or a path alias. - * @throws InvalidParamException if the directory is invalid - */ - public function setControllerPath($path) - { - $this->_controllerPath = Yii::getAlias($path); - } - - /** - * Returns the directory that contains the view files for this module. - * @return string the root directory of view files. Defaults to "[[basePath]]/view". - */ - public function getViewPath() - { - if ($this->_viewPath !== null) { - return $this->_viewPath; - } else { - return $this->_viewPath = $this->getBasePath() . DIRECTORY_SEPARATOR . 'views'; - } - } - - /** - * Sets the directory that contains the view files. - * @param string $path the root directory of view files. - * @throws InvalidParamException if the directory is invalid - */ - public function setViewPath($path) - { - $this->_viewPath = Yii::getAlias($path); - } - - /** - * Returns the directory that contains layout view files for this module. - * @return string the root directory of layout files. Defaults to "[[viewPath]]/layouts". - */ - public function getLayoutPath() - { - if ($this->_layoutPath !== null) { - return $this->_layoutPath; - } else { - return $this->_layoutPath = $this->getViewPath() . DIRECTORY_SEPARATOR . 'layouts'; - } - } - - /** - * Sets the directory that contains the layout files. - * @param string $path the root directory of layout files. - * @throws InvalidParamException if the directory is invalid - */ - public function setLayoutPath($path) - { - $this->_layoutPath = Yii::getAlias($path); - } - - /** - * Defines path aliases. - * This method calls [[Yii::setAlias()]] to register the path aliases. - * This method is provided so that you can define path aliases when configuring a module. - * @property array list of path aliases to be defined. The array keys are alias names - * (must start with '@') and the array values are the corresponding paths or aliases. - * See [[setAliases()]] for an example. - * @param array $aliases list of path aliases to be defined. The array keys are alias names - * (must start with '@') and the array values are the corresponding paths or aliases. - * For example, - * - * ~~~ - * [ - * '@models' => '@app/models', // an existing alias - * '@backend' => __DIR__ . '/../backend', // a directory - * ] - * ~~~ - */ - public function setAliases($aliases) - { - foreach ($aliases as $name => $alias) { - Yii::setAlias($name, $alias); - } - } - - /** - * Checks whether the child module of the specified ID exists. - * This method supports checking the existence of both child and grand child modules. - * @param string $id module ID. For grand child modules, use ID path relative to this module (e.g. `admin/content`). - * @return boolean whether the named module exists. Both loaded and unloaded modules - * are considered. - */ - public function hasModule($id) - { - if (($pos = strpos($id, '/')) !== false) { - // sub-module - $module = $this->getModule(substr($id, 0, $pos)); - return $module === null ? false : $module->hasModule(substr($id, $pos + 1)); - } else { - return isset($this->_modules[$id]); - } - } - - /** - * Retrieves the child module of the specified ID. - * This method supports retrieving both child modules and grand child modules. - * @param string $id module ID (case-sensitive). To retrieve grand child modules, - * use ID path relative to this module (e.g. `admin/content`). - * @param boolean $load whether to load the module if it is not yet loaded. - * @return Module|null the module instance, null if the module does not exist. - * @see hasModule() - */ - public function getModule($id, $load = true) - { - if (($pos = strpos($id, '/')) !== false) { - // sub-module - $module = $this->getModule(substr($id, 0, $pos)); - return $module === null ? null : $module->getModule(substr($id, $pos + 1), $load); - } - - if (isset($this->_modules[$id])) { - if ($this->_modules[$id] instanceof Module) { - return $this->_modules[$id]; - } elseif ($load) { - Yii::trace("Loading module: $id", __METHOD__); - return $this->_modules[$id] = Yii::createObject($this->_modules[$id], $id, $this); - } - } - return null; - } - - /** - * Adds a sub-module to this module. - * @param string $id module ID - * @param Module|array|null $module the sub-module to be added to this module. This can - * be one of the followings: - * - * - a [[Module]] object - * - a configuration array: when [[getModule()]] is called initially, the array - * will be used to instantiate the sub-module - * - null: the named sub-module will be removed from this module - */ - public function setModule($id, $module) - { - if ($module === null) { - unset($this->_modules[$id]); - } else { - $this->_modules[$id] = $module; - } - } - - /** - * Returns the sub-modules in this module. - * @param boolean $loadedOnly whether to return the loaded sub-modules only. If this is set false, - * then all sub-modules registered in this module will be returned, whether they are loaded or not. - * Loaded modules will be returned as objects, while unloaded modules as configuration arrays. - * @return array the modules (indexed by their IDs) - */ - public function getModules($loadedOnly = false) - { - if ($loadedOnly) { - $modules = []; - foreach ($this->_modules as $module) { - if ($module instanceof Module) { - $modules[] = $module; - } - } - return $modules; - } else { - return $this->_modules; - } - } - - /** - * Registers sub-modules in the current module. - * - * Each sub-module should be specified as a name-value pair, where - * name refers to the ID of the module and value the module or a configuration - * array that can be used to create the module. In the latter case, [[Yii::createObject()]] - * will be used to create the module. - * - * If a new sub-module has the same ID as an existing one, the existing one will be overwritten silently. - * - * The following is an example for registering two sub-modules: - * - * ~~~ - * [ - * 'comment' => [ - * 'class' => 'app\modules\comment\CommentModule', - * 'db' => 'db', - * ], - * 'booking' => ['class' => 'app\modules\booking\BookingModule'], - * ] - * ~~~ - * - * @param array $modules modules (id => module configuration or instances) - */ - public function setModules($modules) - { - foreach ($modules as $id => $module) { - $this->_modules[$id] = $module; - } - } - - /** - * Checks whether the named component exists. - * @param string $id component ID - * @return boolean whether the named component exists. Both loaded and unloaded components - * are considered. - */ - public function hasComponent($id) - { - return isset($this->_components[$id]); - } - - /** - * Retrieves the named component. - * @param string $id component ID (case-sensitive) - * @param boolean $load whether to load the component if it is not yet loaded. - * @return Component|null the component instance, null if the component does not exist. - * @see hasComponent() - */ - public function getComponent($id, $load = true) - { - if (isset($this->_components[$id])) { - if ($this->_components[$id] instanceof Object) { - return $this->_components[$id]; - } elseif ($load) { - return $this->_components[$id] = Yii::createObject($this->_components[$id]); - } - } - return null; - } - - /** - * Registers a component with this module. - * @param string $id component ID - * @param Component|array|null $component the component to be registered with the module. This can - * be one of the followings: - * - * - a [[Component]] object - * - a configuration array: when [[getComponent()]] is called initially for this component, the array - * will be used to instantiate the component via [[Yii::createObject()]]. - * - null: the named component will be removed from the module - */ - public function setComponent($id, $component) - { - if ($component === null) { - unset($this->_components[$id]); - } else { - $this->_components[$id] = $component; - } - } - - /** - * Returns the registered components. - * @param boolean $loadedOnly whether to return the loaded components only. If this is set false, - * then all components specified in the configuration will be returned, whether they are loaded or not. - * Loaded components will be returned as objects, while unloaded components as configuration arrays. - * @return array the components (indexed by their IDs) - */ - public function getComponents($loadedOnly = false) - { - if ($loadedOnly) { - $components = []; - foreach ($this->_components as $component) { - if ($component instanceof Component) { - $components[] = $component; - } - } - return $components; - } else { - return $this->_components; - } - } - - /** - * Registers a set of components in this module. - * - * Each component should be specified as a name-value pair, where - * name refers to the ID of the component and value the component or a configuration - * array that can be used to create the component. In the latter case, [[Yii::createObject()]] - * will be used to create the component. - * - * If a new component has the same ID as an existing one, the existing one will be overwritten silently. - * - * The following is an example for setting two components: - * - * ~~~ - * [ - * 'db' => [ - * 'class' => 'yii\db\Connection', - * 'dsn' => 'sqlite:path/to/file.db', - * ], - * 'cache' => [ - * 'class' => 'yii\caching\DbCache', - * 'db' => 'db', - * ], - * ] - * ~~~ - * - * @param array $components components (id => component configuration or instance) - */ - public function setComponents($components) - { - foreach ($components as $id => $component) { - if (!is_object($component) && isset($this->_components[$id]['class']) && !isset($component['class'])) { - // set default component class - $component['class'] = $this->_components[$id]['class']; - } - $this->_components[$id] = $component; - } - } - - /** - * Loads components that are declared in [[preload]]. - * @throws InvalidConfigException if a component or module to be preloaded is unknown - */ - public function preloadComponents() - { - foreach ($this->preload as $id) { - if ($this->hasComponent($id)) { - $this->getComponent($id); - } elseif ($this->hasModule($id)) { - $this->getModule($id); - } else { - throw new InvalidConfigException("Unknown component or module: $id"); - } - } - } - - /** - * Runs a controller action specified by a route. - * This method parses the specified route and creates the corresponding child module(s), controller and action - * instances. It then calls [[Controller::runAction()]] to run the action with the given parameters. - * If the route is empty, the method will use [[defaultRoute]]. - * @param string $route the route that specifies the action. - * @param array $params the parameters to be passed to the action - * @return mixed the result of the action. - * @throws InvalidRouteException if the requested route cannot be resolved into an action successfully - */ - public function runAction($route, $params = []) - { - $parts = $this->createController($route); - if (is_array($parts)) { - /** @var Controller $controller */ - list($controller, $actionID) = $parts; - $oldController = Yii::$app->controller; - Yii::$app->controller = $controller; - $result = $controller->runAction($actionID, $params); - Yii::$app->controller = $oldController; - return $result; - } else { - $id = $this->getUniqueId(); - throw new InvalidRouteException('Unable to resolve the request "' . ($id === '' ? $route : $id . '/' . $route) . '".'); - } - } - - /** - * Creates a controller instance based on the controller ID. - * - * The controller is created within this module. The method first attempts to - * create the controller based on the [[controllerMap]] of the module. If not available, - * it will look for the controller class under the [[controllerPath]] and create an - * instance of it. - * - * @param string $route the route consisting of module, controller and action IDs. - * @return array|boolean If the controller is created successfully, it will be returned together - * with the requested action ID. Otherwise false will be returned. - * @throws InvalidConfigException if the controller class and its file do not match. - */ - public function createController($route) - { - if ($route === '') { - $route = $this->defaultRoute; - } - if (strpos($route, '/') !== false) { - list ($id, $route) = explode('/', $route, 2); - } else { - $id = $route; - $route = ''; - } - - $module = $this->getModule($id); - if ($module !== null) { - return $module->createController($route); - } - - if (isset($this->controllerMap[$id])) { - $controller = Yii::createObject($this->controllerMap[$id], $id, $this); - } elseif (preg_match('/^[a-z0-9\\-_]+$/', $id) && strpos($id, '--') === false && trim($id, '-') === $id) { - $className = str_replace(' ', '', ucwords(str_replace('-', ' ', $id))) . 'Controller'; - $classFile = $this->controllerPath . DIRECTORY_SEPARATOR . $className . '.php'; - if (!is_file($classFile)) { - return false; - } - $className = ltrim($this->controllerNamespace . '\\' . $className, '\\'); - Yii::$classMap[$className] = $classFile; - if (is_subclass_of($className, 'yii\base\Controller')) { - $controller = new $className($id, $this); - } elseif (YII_DEBUG) { - throw new InvalidConfigException("Controller class must extend from \\yii\\base\\Controller."); - } - } - - return isset($controller) ? [$controller, $route] : false; - } - - /** - * This method is invoked right before an action of this module is to be executed (after all possible filters.) - * You may override this method to do last-minute preparation for the action. - * Make sure you call the parent implementation so that the relevant event is triggered. - * @param Action $action the action to be executed. - * @return boolean whether the action should continue to be executed. - */ - public function beforeAction($action) - { - return true; - } - - /** - * This method is invoked right after an action of this module has been executed. - * You may override this method to do some postprocessing for the action. - * Make sure you call the parent implementation so that the relevant event is triggered. - * @param Action $action the action just executed. - * @param mixed $result the action return result. - */ - public function afterAction($action, &$result) - { - } -} diff --git a/framework/yii/base/NotSupportedException.php b/framework/yii/base/NotSupportedException.php deleted file mode 100644 index 5123f43..0000000 --- a/framework/yii/base/NotSupportedException.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class NotSupportedException extends Exception -{ - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return 'Not Supported'; - } -} diff --git a/framework/yii/base/Object.php b/framework/yii/base/Object.php deleted file mode 100644 index 06fca50..0000000 --- a/framework/yii/base/Object.php +++ /dev/null @@ -1,240 +0,0 @@ - - * @since 2.0 - */ -class Object implements Arrayable -{ - /** - * @return string the fully qualified name of this class. - */ - public static function className() - { - return get_called_class(); - } - - /** - * Constructor. - * The default implementation does two things: - * - * - Initializes the object with the given configuration `$config`. - * - Call [[init()]]. - * - * If this method is overridden in a child class, it is recommended that - * - * - the last parameter of the constructor is a configuration array, like `$config` here. - * - call the parent implementation at the end of the constructor. - * - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($config = []) - { - if (!empty($config)) { - Yii::configure($this, $config); - } - $this->init(); - } - - /** - * Initializes the object. - * This method is invoked at the end of the constructor after the object is initialized with the - * given configuration. - */ - public function init() - { - } - - /** - * Returns the value of an object property. - * - * Do not call this method directly as it is a PHP magic method that - * will be implicitly called when executing `$value = $object->property;`. - * @param string $name the property name - * @return mixed the property value - * @throws UnknownPropertyException if the property is not defined - * @throws InvalidCallException if the property is write-only - * @see __set() - */ - public function __get($name) - { - $getter = 'get' . $name; - if (method_exists($this, $getter)) { - return $this->$getter(); - } elseif (method_exists($this, 'set' . $name)) { - throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name); - } else { - throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name); - } - } - - /** - * Sets value of an object property. - * - * Do not call this method directly as it is a PHP magic method that - * will be implicitly called when executing `$object->property = $value;`. - * @param string $name the property name or the event name - * @param mixed $value the property value - * @throws UnknownPropertyException if the property is not defined - * @throws InvalidCallException if the property is read-only - * @see __get() - */ - public function __set($name, $value) - { - $setter = 'set' . $name; - if (method_exists($this, $setter)) { - $this->$setter($value); - } elseif (method_exists($this, 'get' . $name)) { - throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name); - } else { - throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name); - } - } - - /** - * Checks if the named property is set (not null). - * - * Do not call this method directly as it is a PHP magic method that - * will be implicitly called when executing `isset($object->property)`. - * - * Note that if the property is not defined, false will be returned. - * @param string $name the property name or the event name - * @return boolean whether the named property is set (not null). - */ - public function __isset($name) - { - $getter = 'get' . $name; - if (method_exists($this, $getter)) { - return $this->$getter() !== null; - } else { - return false; - } - } - - /** - * Sets an object property to null. - * - * Do not call this method directly as it is a PHP magic method that - * will be implicitly called when executing `unset($object->property)`. - * - * Note that if the property is not defined, this method will do nothing. - * If the property is read-only, it will throw an exception. - * @param string $name the property name - * @throws InvalidCallException if the property is read only. - */ - public function __unset($name) - { - $setter = 'set' . $name; - if (method_exists($this, $setter)) { - $this->$setter(null); - } elseif (method_exists($this, 'get' . $name)) { - throw new InvalidCallException('Unsetting read-only property: ' . get_class($this) . '::' . $name); - } - } - - /** - * Calls the named method which is not a class method. - * - * Do not call this method directly as it is a PHP magic method that - * will be implicitly called when an unknown method is being invoked. - * @param string $name the method name - * @param array $params method parameters - * @throws UnknownMethodException when calling unknown method - * @return mixed the method return value - */ - public function __call($name, $params) - { - throw new UnknownMethodException('Unknown method: ' . get_class($this) . "::$name()"); - } - - /** - * Returns a value indicating whether a property is defined. - * A property is defined if: - * - * - the class has a getter or setter method associated with the specified name - * (in this case, property name is case-insensitive); - * - the class has a member variable with the specified name (when `$checkVars` is true); - * - * @param string $name the property name - * @param boolean $checkVars whether to treat member variables as properties - * @return boolean whether the property is defined - * @see canGetProperty() - * @see canSetProperty() - */ - public function hasProperty($name, $checkVars = true) - { - return $this->canGetProperty($name, $checkVars) || $this->canSetProperty($name, false); - } - - /** - * Returns a value indicating whether a property can be read. - * A property is readable if: - * - * - the class has a getter method associated with the specified name - * (in this case, property name is case-insensitive); - * - the class has a member variable with the specified name (when `$checkVars` is true); - * - * @param string $name the property name - * @param boolean $checkVars whether to treat member variables as properties - * @return boolean whether the property can be read - * @see canSetProperty() - */ - public function canGetProperty($name, $checkVars = true) - { - return method_exists($this, 'get' . $name) || $checkVars && property_exists($this, $name); - } - - /** - * Returns a value indicating whether a property can be set. - * A property is writable if: - * - * - the class has a setter method associated with the specified name - * (in this case, property name is case-insensitive); - * - the class has a member variable with the specified name (when `$checkVars` is true); - * - * @param string $name the property name - * @param boolean $checkVars whether to treat member variables as properties - * @return boolean whether the property can be written - * @see canGetProperty() - */ - public function canSetProperty($name, $checkVars = true) - { - return method_exists($this, 'set' . $name) || $checkVars && property_exists($this, $name); - } - - /** - * Returns a value indicating whether a method is defined. - * - * The default implementation is a call to php function `method_exists()`. - * You may override this method when you implemented the php magic method `__call()`. - * @param string $name the property name - * @return boolean whether the property is defined - */ - public function hasMethod($name) - { - return method_exists($this, $name); - } - - /** - * Converts the object into an array. - * The default implementation will return all public property values as an array. - * @return array the array representation of the object - */ - public function toArray() - { - return Yii::getObjectVars($this); - } -} diff --git a/framework/yii/base/Request.php b/framework/yii/base/Request.php deleted file mode 100644 index cd3ffdc..0000000 --- a/framework/yii/base/Request.php +++ /dev/null @@ -1,82 +0,0 @@ - - * @since 2.0 - */ -abstract class Request extends Component -{ - private $_scriptFile; - private $_isConsoleRequest; - - /** - * Resolves the current request into a route and the associated parameters. - * @return array the first element is the route, and the second is the associated parameters. - */ - abstract public function resolve(); - - /** - * Returns a value indicating whether the current request is made via command line - * @return boolean the value indicating whether the current request is made via console - */ - public function getIsConsoleRequest() - { - return $this->_isConsoleRequest !== null ? $this->_isConsoleRequest : PHP_SAPI === 'cli'; - } - - /** - * Sets the value indicating whether the current request is made via command line - * @param boolean $value the value indicating whether the current request is made via command line - */ - public function setIsConsoleRequest($value) - { - $this->_isConsoleRequest = $value; - } - - /** - * Returns entry script file path. - * @return string entry script file path (processed w/ realpath()) - * @throws InvalidConfigException if the entry script file path cannot be determined automatically. - */ - public function getScriptFile() - { - if ($this->_scriptFile === null) { - if (isset($_SERVER['SCRIPT_FILENAME'])) { - $this->setScriptFile($_SERVER['SCRIPT_FILENAME']); - } else { - throw new InvalidConfigException('Unable to determine the entry script file path.'); - } - } - return $this->_scriptFile; - } - - /** - * Sets the entry script file path. - * The entry script file path can normally be determined based on the `SCRIPT_FILENAME` SERVER variable. - * However, for some server configurations, this may not be correct or feasible. - * This setter is provided so that the entry script file path can be manually specified. - * @param string $value the entry script file path. This can be either a file path or a path alias. - * @throws InvalidConfigException if the provided entry script file path is invalid. - */ - public function setScriptFile($value) - { - $scriptFile = realpath(\Yii::getAlias($value)); - if ($scriptFile !== false && is_file($scriptFile)) { - $this->_scriptFile = $scriptFile; - } else { - throw new InvalidConfigException('Unable to determine the entry script file path.'); - } - } -} diff --git a/framework/yii/base/Response.php b/framework/yii/base/Response.php deleted file mode 100644 index 1403b69..0000000 --- a/framework/yii/base/Response.php +++ /dev/null @@ -1,30 +0,0 @@ - - * @since 2.0 - */ -class Response extends Component -{ - /** - * @var integer the exit status. Exit statuses should be in the range 0 to 254. - * The status 0 means the program terminates successfully. - */ - public $exitStatus = 0; - - /** - * Sends the response to client. - */ - public function send() - { - } -} diff --git a/framework/yii/base/Theme.php b/framework/yii/base/Theme.php deleted file mode 100644 index 1d8771f..0000000 --- a/framework/yii/base/Theme.php +++ /dev/null @@ -1,152 +0,0 @@ - '/web/themes/basic']`, - * then the themed version for a view file `/web/views/site/index.php` will be - * `/web/themes/basic/site/index.php`. - * - * It is possible to map a single path to multiple paths. For example, - * - * ~~~ - * 'pathMap' => [ - * '/web/views' => [ - * '/web/themes/christmas', - * '/web/themes/basic', - * ], - * ] - * ~~~ - * - * In this case, the themed version could be either `/web/themes/christmas/site/index.php` or - * `/web/themes/basic/site/index.php`. The former has precedence over the latter if both files exist. - * - * To use a theme, you should configure the [[View::theme|theme]] property of the "view" application - * component like the following: - * - * ~~~ - * 'view' => [ - * 'theme' => [ - * 'basePath' => '@webroot/themes/basic', - * 'baseUrl' => '@web/themes/basic', - * ], - * ], - * ~~~ - * - * The above configuration specifies a theme located under the "themes/basic" directory of the Web folder - * that contains the entry script of the application. If your theme is designed to handle modules, - * you may configure the [[pathMap]] property like described above. - * - * @author Qiang Xue - * @since 2.0 - */ -class Theme extends Component -{ - /** - * @var string the root path or path alias of this theme. All resources of this theme are located - * under this directory. This property must be set if [[pathMap]] is not set. - * @see pathMap - */ - public $basePath; - /** - * @var string the base URL (or path alias) for this theme. All resources of this theme are considered - * to be under this base URL. This property must be set. It is mainly used by [[getUrl()]]. - */ - public $baseUrl; - /** - * @var array the mapping between view directories and their corresponding themed versions. - * If not set, it will be initialized as a mapping from [[Application::basePath]] to [[basePath]]. - * This property is used by [[applyTo()]] when a view is trying to apply the theme. - * Path aliases can be used when specifying directories. - */ - public $pathMap; - - - /** - * Initializes the theme. - * @throws InvalidConfigException if [[basePath]] is not set. - */ - public function init() - { - parent::init(); - if (empty($this->pathMap)) { - if ($this->basePath !== null) { - $this->basePath = Yii::getAlias($this->basePath); - $this->pathMap = [Yii::$app->getBasePath() => [$this->basePath]]; - } else { - throw new InvalidConfigException('The "basePath" property must be set.'); - } - } - $paths = []; - foreach ($this->pathMap as $from => $tos) { - $from = FileHelper::normalizePath(Yii::getAlias($from)); - foreach ((array)$tos as $to) { - $to = FileHelper::normalizePath(Yii::getAlias($to)); - $paths[$from . DIRECTORY_SEPARATOR][] = $to . DIRECTORY_SEPARATOR; - } - } - $this->pathMap = $paths; - if ($this->baseUrl === null) { - throw new InvalidConfigException('The "baseUrl" property must be set.'); - } else { - $this->baseUrl = rtrim(Yii::getAlias($this->baseUrl), '/'); - } - } - - /** - * Converts a file to a themed file if possible. - * If there is no corresponding themed file, the original file will be returned. - * @param string $path the file to be themed - * @return string the themed file, or the original file if the themed version is not available. - */ - public function applyTo($path) - { - $path = FileHelper::normalizePath($path); - foreach ($this->pathMap as $from => $tos) { - if (strpos($path, $from) === 0) { - $n = strlen($from); - foreach ($tos as $to) { - $file = $to . substr($path, $n); - if (is_file($file)) { - return $file; - } - } - } - } - return $path; - } - - /** - * Converts a relative URL into an absolute URL using [[baseUrl]]. - * @param string $url the relative URL to be converted. - * @return string the absolute URL - */ - public function getUrl($url) - { - return $this->baseUrl . '/' . ltrim($url, '/'); - } -} diff --git a/framework/yii/base/UnknownClassException.php b/framework/yii/base/UnknownClassException.php deleted file mode 100644 index b64c585..0000000 --- a/framework/yii/base/UnknownClassException.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class UnknownClassException extends Exception -{ - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return 'Unknown Class'; - } -} diff --git a/framework/yii/base/UnknownMethodException.php b/framework/yii/base/UnknownMethodException.php deleted file mode 100644 index 2277aff..0000000 --- a/framework/yii/base/UnknownMethodException.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class UnknownMethodException extends Exception -{ - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return 'Unknown Method'; - } -} diff --git a/framework/yii/base/UnknownPropertyException.php b/framework/yii/base/UnknownPropertyException.php deleted file mode 100644 index 0a12ce1..0000000 --- a/framework/yii/base/UnknownPropertyException.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class UnknownPropertyException extends Exception -{ - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return 'Unknown Property'; - } -} diff --git a/framework/yii/base/UserException.php b/framework/yii/base/UserException.php deleted file mode 100644 index 01ca602..0000000 --- a/framework/yii/base/UserException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @since 2.0 - */ -class UserException extends Exception -{ -} diff --git a/framework/yii/base/View.php b/framework/yii/base/View.php deleted file mode 100644 index 47650f0..0000000 --- a/framework/yii/base/View.php +++ /dev/null @@ -1,461 +0,0 @@ - - * @since 2.0 - */ -class View extends Component -{ - /** - * @event Event an event that is triggered by [[beginPage()]]. - */ - const EVENT_BEGIN_PAGE = 'beginPage'; - /** - * @event Event an event that is triggered by [[endPage()]]. - */ - const EVENT_END_PAGE = 'endPage'; - /** - * @event ViewEvent an event that is triggered by [[renderFile()]] right before it renders a view file. - */ - const EVENT_BEFORE_RENDER = 'beforeRender'; - /** - * @event ViewEvent an event that is triggered by [[renderFile()]] right after it renders a view file. - */ - const EVENT_AFTER_RENDER = 'afterRender'; - - /** - * @var ViewContextInterface the context under which the [[renderFile()]] method is being invoked. - */ - public $context; - /** - * @var mixed custom parameters that are shared among view templates. - */ - public $params = []; - /** - * @var array a list of available renderers indexed by their corresponding supported file extensions. - * Each renderer may be a view renderer object or the configuration for creating the renderer object. - * For example, the following configuration enables both Smarty and Twig view renderers: - * - * ~~~ - * [ - * 'tpl' => ['class' => 'yii\smarty\ViewRenderer'], - * 'twig' => ['class' => 'yii\twig\ViewRenderer'], - * ] - * ~~~ - * - * If no renderer is available for the given view file, the view file will be treated as a normal PHP - * and rendered via [[renderPhpFile()]]. - */ - public $renderers; - /** - * @var string the default view file extension. This will be appended to view file names if they don't have file extensions. - */ - public $defaultExtension = 'php'; - /** - * @var Theme|array the theme object or the configuration array for creating the theme object. - * If not set, it means theming is not enabled. - */ - public $theme; - /** - * @var array a list of named output blocks. The keys are the block names and the values - * are the corresponding block content. You can call [[beginBlock()]] and [[endBlock()]] - * to capture small fragments of a view. They can be later accessed somewhere else - * through this property. - */ - public $blocks; - /** - * @var array a list of currently active fragment cache widgets. This property - * is used internally to implement the content caching feature. Do not modify it directly. - * @internal - */ - public $cacheStack = []; - /** - * @var array a list of placeholders for embedding dynamic contents. This property - * is used internally to implement the content caching feature. Do not modify it directly. - * @internal - */ - public $dynamicPlaceholders = []; - - - /** - * Initializes the view component. - */ - public function init() - { - parent::init(); - if (is_array($this->theme)) { - if (!isset($this->theme['class'])) { - $this->theme['class'] = 'yii\base\Theme'; - } - $this->theme = Yii::createObject($this->theme); - } - } - - /** - * Renders a view. - * - * The view to be rendered can be specified in one of the following formats: - * - * - path alias (e.g. "@app/views/site/index"); - * - absolute path within application (e.g. "//site/index"): the view name starts with double slashes. - * The actual view file will be looked for under the [[Application::viewPath|view path]] of the application. - * - absolute path within current module (e.g. "/site/index"): the view name starts with a single slash. - * The actual view file will be looked for under the [[Module::viewPath|view path]] of [[module]]. - * - resolving any other format will be performed via [[ViewContext::findViewFile()]]. - * - * @param string $view the view name. Please refer to [[Controller::findViewFile()]] - * and [[Widget::findViewFile()]] on how to specify this parameter. - * @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file. - * @param object $context the context that the view should use for rendering the view. If null, - * existing [[context]] will be used. - * @return string the rendering result - * @throws InvalidParamException if the view cannot be resolved or the view file does not exist. - * @see renderFile() - */ - public function render($view, $params = [], $context = null) - { - $viewFile = $this->findViewFile($view, $context); - return $this->renderFile($viewFile, $params, $context); - } - - /** - * Finds the view file based on the given view name. - * @param string $view the view name or the path alias of the view file. Please refer to [[render()]] - * on how to specify this parameter. - * @param object $context the context that the view should be used to search the view file. If null, - * existing [[context]] will be used. - * @return string the view file path. Note that the file may not exist. - * @throws InvalidCallException if [[context]] is required and invalid. - */ - protected function findViewFile($view, $context = null) - { - if (strncmp($view, '@', 1) === 0) { - // e.g. "@app/views/main" - $file = Yii::getAlias($view); - } elseif (strncmp($view, '//', 2) === 0) { - // e.g. "//layouts/main" - $file = Yii::$app->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/'); - } elseif (strncmp($view, '/', 1) === 0) { - // e.g. "/site/index" - if (Yii::$app->controller !== null) { - $file = Yii::$app->controller->module->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/'); - } else { - throw new InvalidCallException("Unable to locate view file for view '$view': no active controller."); - } - } else { - // context required - if ($context === null) { - $context = $this->context; - } - if ($context instanceof ViewContextInterface) { - $file = $context->findViewFile($view); - } else { - throw new InvalidCallException("Unable to locate view file for view '$view': no active view context."); - } - } - - if (pathinfo($file, PATHINFO_EXTENSION) !== '') { - return $file; - } - $path = $file . '.' . $this->defaultExtension; - if ($this->defaultExtension !== 'php' && !is_file($path)) { - $path = $file . '.php'; - } - return $path; - } - - /** - * Renders a view file. - * - * If [[theme]] is enabled (not null), it will try to render the themed version of the view file as long - * as it is available. - * - * The method will call [[FileHelper::localize()]] to localize the view file. - * - * If [[renderer]] is enabled (not null), the method will use it to render the view file. - * Otherwise, it will simply include the view file as a normal PHP file, capture its output and - * return it as a string. - * - * @param string $viewFile the view file. This can be either a file path or a path alias. - * @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file. - * @param object $context the context that the view should use for rendering the view. If null, - * existing [[context]] will be used. - * @return string the rendering result - * @throws InvalidParamException if the view file does not exist - */ - public function renderFile($viewFile, $params = [], $context = null) - { - $viewFile = Yii::getAlias($viewFile); - if ($this->theme !== null) { - $viewFile = $this->theme->applyTo($viewFile); - } - if (is_file($viewFile)) { - $viewFile = FileHelper::localize($viewFile); - } else { - throw new InvalidParamException("The view file does not exist: $viewFile"); - } - - $oldContext = $this->context; - if ($context !== null) { - $this->context = $context; - } - - $output = ''; - if ($this->beforeRender($viewFile)) { - Yii::trace("Rendering view file: $viewFile", __METHOD__); - $ext = pathinfo($viewFile, PATHINFO_EXTENSION); - if (isset($this->renderers[$ext])) { - if (is_array($this->renderers[$ext]) || is_string($this->renderers[$ext])) { - $this->renderers[$ext] = Yii::createObject($this->renderers[$ext]); - } - /** @var ViewRenderer $renderer */ - $renderer = $this->renderers[$ext]; - $output = $renderer->render($this, $viewFile, $params); - } else { - $output = $this->renderPhpFile($viewFile, $params); - } - $this->afterRender($viewFile, $output); - } - - $this->context = $oldContext; - - return $output; - } - - /** - * This method is invoked right before [[renderFile()]] renders a view file. - * The default implementation will trigger the [[EVENT_BEFORE_RENDER]] event. - * If you override this method, make sure you call the parent implementation first. - * @param string $viewFile the view file to be rendered - * @return boolean whether to continue rendering the view file. - */ - public function beforeRender($viewFile) - { - $event = new ViewEvent($viewFile); - $this->trigger(self::EVENT_BEFORE_RENDER, $event); - return $event->isValid; - } - - /** - * This method is invoked right after [[renderFile()]] renders a view file. - * The default implementation will trigger the [[EVENT_AFTER_RENDER]] event. - * If you override this method, make sure you call the parent implementation first. - * @param string $viewFile the view file to be rendered - * @param string $output the rendering result of the view file. Updates to this parameter - * will be passed back and returned by [[renderFile()]]. - */ - public function afterRender($viewFile, &$output) - { - if ($this->hasEventHandlers(self::EVENT_AFTER_RENDER)) { - $event = new ViewEvent($viewFile); - $event->output = $output; - $this->trigger(self::EVENT_AFTER_RENDER, $event); - $output = $event->output; - } - } - - /** - * Renders a view file as a PHP script. - * - * This method treats the view file as a PHP script and includes the file. - * It extracts the given parameters and makes them available in the view file. - * The method captures the output of the included view file and returns it as a string. - * - * This method should mainly be called by view renderer or [[renderFile()]]. - * - * @param string $_file_ the view file. - * @param array $_params_ the parameters (name-value pairs) that will be extracted and made available in the view file. - * @return string the rendering result - */ - public function renderPhpFile($_file_, $_params_ = []) - { - ob_start(); - ob_implicit_flush(false); - extract($_params_, EXTR_OVERWRITE); - require($_file_); - return ob_get_clean(); - } - - /** - * Renders dynamic content returned by the given PHP statements. - * This method is mainly used together with content caching (fragment caching and page caching) - * when some portions of the content (called *dynamic content*) should not be cached. - * The dynamic content must be returned by some PHP statements. - * @param string $statements the PHP statements for generating the dynamic content. - * @return string the placeholder of the dynamic content, or the dynamic content if there is no - * active content cache currently. - */ - public function renderDynamic($statements) - { - if (!empty($this->cacheStack)) { - $n = count($this->dynamicPlaceholders); - $placeholder = ""; - $this->addDynamicPlaceholder($placeholder, $statements); - return $placeholder; - } else { - return $this->evaluateDynamicContent($statements); - } - } - - /** - * Adds a placeholder for dynamic content. - * This method is internally used. - * @param string $placeholder the placeholder name - * @param string $statements the PHP statements for generating the dynamic content - */ - public function addDynamicPlaceholder($placeholder, $statements) - { - foreach ($this->cacheStack as $cache) { - $cache->dynamicPlaceholders[$placeholder] = $statements; - } - $this->dynamicPlaceholders[$placeholder] = $statements; - } - - /** - * Evaluates the given PHP statements. - * This method is mainly used internally to implement dynamic content feature. - * @param string $statements the PHP statements to be evaluated. - * @return mixed the return value of the PHP statements. - */ - public function evaluateDynamicContent($statements) - { - return eval($statements); - } - - /** - * Begins recording a block. - * This method is a shortcut to beginning [[Block]] - * @param string $id the block ID. - * @param boolean $renderInPlace whether to render the block content in place. - * Defaults to false, meaning the captured block will not be displayed. - * @return Block the Block widget instance - */ - public function beginBlock($id, $renderInPlace = false) - { - return Block::begin([ - 'id' => $id, - 'renderInPlace' => $renderInPlace, - 'view' => $this, - ]); - } - - /** - * Ends recording a block. - */ - public function endBlock() - { - Block::end(); - } - - /** - * Begins the rendering of content that is to be decorated by the specified view. - * This method can be used to implement nested layout. For example, a layout can be embedded - * in another layout file specified as '@app/views/layouts/base.php' like the following: - * - * ~~~ - * beginContent('@app/views/layouts/base.php'); ?> - * ...layout content here... - * endContent(); ?> - * ~~~ - * - * @param string $viewFile the view file that will be used to decorate the content enclosed by this widget. - * This can be specified as either the view file path or path alias. - * @param array $params the variables (name => value) to be extracted and made available in the decorative view. - * @return ContentDecorator the ContentDecorator widget instance - * @see ContentDecorator - */ - public function beginContent($viewFile, $params = []) - { - return ContentDecorator::begin([ - 'viewFile' => $viewFile, - 'params' => $params, - 'view' => $this, - ]); - } - - /** - * Ends the rendering of content. - */ - public function endContent() - { - ContentDecorator::end(); - } - - /** - * Begins fragment caching. - * This method will display cached content if it is available. - * If not, it will start caching and would expect an [[endCache()]] - * call to end the cache and save the content into cache. - * A typical usage of fragment caching is as follows, - * - * ~~~ - * if ($this->beginCache($id)) { - * // ...generate content here - * $this->endCache(); - * } - * ~~~ - * - * @param string $id a unique ID identifying the fragment to be cached. - * @param array $properties initial property values for [[FragmentCache]] - * @return boolean whether you should generate the content for caching. - * False if the cached version is available. - */ - public function beginCache($id, $properties = []) - { - $properties['id'] = $id; - $properties['view'] = $this; - /** @var FragmentCache $cache */ - $cache = FragmentCache::begin($properties); - if ($cache->getCachedContent() !== false) { - $this->endCache(); - return false; - } else { - return true; - } - } - - /** - * Ends fragment caching. - */ - public function endCache() - { - FragmentCache::end(); - } - - /** - * Marks the beginning of a page. - */ - public function beginPage() - { - ob_start(); - ob_implicit_flush(false); - - $this->trigger(self::EVENT_BEGIN_PAGE); - } - - /** - * Marks the ending of a page. - */ - public function endPage() - { - $this->trigger(self::EVENT_END_PAGE); - ob_end_flush(); - } -} diff --git a/framework/yii/base/ViewContextInterface.php b/framework/yii/base/ViewContextInterface.php deleted file mode 100644 index 94f6751..0000000 --- a/framework/yii/base/ViewContextInterface.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @since 2.0 - */ -interface ViewContextInterface -{ - /** - * Finds the view file corresponding to the specified relative view name. - * @param string $view a relative view name. The name does NOT start with a slash. - * @return string the view file path. Note that the file may not exist. - */ - public function findViewFile($view); -} diff --git a/framework/yii/base/ViewEvent.php b/framework/yii/base/ViewEvent.php deleted file mode 100644 index d02e180..0000000 --- a/framework/yii/base/ViewEvent.php +++ /dev/null @@ -1,46 +0,0 @@ - - * @since 2.0 - */ -class ViewEvent extends Event -{ - /** - * @var string the rendering result of [[View::renderFile()]]. - * Event handlers may modify this property and the modified output will be - * returned by [[View::renderFile()]]. This property is only used - * by [[View::EVENT_AFTER_RENDER]] event. - */ - public $output; - /** - * @var string the view file path that is being rendered by [[View::renderFile()]]. - */ - public $viewFile; - /** - * @var boolean whether to continue rendering the view file. Event handlers of - * [[View::EVENT_BEFORE_RENDER]] may set this property to decide whether - * to continue rendering the current view file. - */ - public $isValid = true; - - /** - * Constructor. - * @param string $viewFile the view file path that is being rendered by [[View::renderFile()]]. - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($viewFile, $config = []) - { - $this->viewFile = $viewFile; - parent::__construct($config); - } -} diff --git a/framework/yii/base/ViewRenderer.php b/framework/yii/base/ViewRenderer.php deleted file mode 100644 index 576bbe8..0000000 --- a/framework/yii/base/ViewRenderer.php +++ /dev/null @@ -1,30 +0,0 @@ - - * @since 2.0 - */ -abstract class ViewRenderer extends Component -{ - /** - * Renders a view file. - * - * This method is invoked by [[View]] whenever it tries to render a view. - * Child classes must implement this method to render the given view file. - * - * @param View $view the view object used for rendering the file. - * @param string $file the view file. - * @param array $params the parameters to be passed to the view file. - * @return string the rendering result - */ - abstract public function render($view, $file, $params); -} diff --git a/framework/yii/base/Widget.php b/framework/yii/base/Widget.php deleted file mode 100644 index 16c13f7..0000000 --- a/framework/yii/base/Widget.php +++ /dev/null @@ -1,214 +0,0 @@ - - * @since 2.0 - */ -class Widget extends Component implements ViewContextInterface -{ - /** - * @var integer a counter used to generate [[id]] for widgets. - * @internal - */ - public static $counter = 0; - /** - * @var string the prefix to the automatically generated widget IDs. - * @see [[getId()]] - */ - public static $autoIdPrefix = 'w'; - - /** - * @var Widget[] the widgets that are currently being rendered (not ended). This property - * is maintained by [[begin()]] and [[end()]] methods. - * @internal - */ - public static $stack = []; - - - /** - * Begins a widget. - * This method creates an instance of the calling class. It will apply the configuration - * to the created instance. A matching [[end()]] call should be called later. - * @param array $config name-value pairs that will be used to initialize the object properties - * @return static the newly created widget instance - */ - public static function begin($config = []) - { - $config['class'] = get_called_class(); - /** @var Widget $widget */ - $widget = Yii::createObject($config); - self::$stack[] = $widget; - return $widget; - } - - /** - * Ends a widget. - * Note that the rendering result of the widget is directly echoed out. - * @return static the widget instance that is ended. - * @throws InvalidCallException if [[begin()]] and [[end()]] calls are not properly nested - */ - public static function end() - { - if (!empty(self::$stack)) { - $widget = array_pop(self::$stack); - if (get_class($widget) === get_called_class()) { - $widget->run(); - return $widget; - } else { - throw new InvalidCallException("Expecting end() of " . get_class($widget) . ", found " . get_called_class()); - } - } else { - throw new InvalidCallException("Unexpected " . get_called_class() . '::end() call. A matching begin() is not found.'); - } - } - - /** - * Creates a widget instance and runs it. - * The widget rendering result is returned by this method. - * @param array $config name-value pairs that will be used to initialize the object properties - * @return string the rendering result of the widget. - */ - public static function widget($config = []) - { - ob_start(); - ob_implicit_flush(false); - /** @var Widget $widget */ - $config['class'] = get_called_class(); - $widget = Yii::createObject($config); - $widget->run(); - return ob_get_clean(); - } - - private $_id; - - /** - * Returns the ID of the widget. - * @param boolean $autoGenerate whether to generate an ID if it is not set previously - * @return string ID of the widget. - */ - public function getId($autoGenerate = true) - { - if ($autoGenerate && $this->_id === null) { - $this->_id = self::$autoIdPrefix . self::$counter++; - } - return $this->_id; - } - - /** - * Sets the ID of the widget. - * @param string $value id of the widget. - */ - public function setId($value) - { - $this->_id = $value; - } - - private $_view; - - /** - * Returns the view object that can be used to render views or view files. - * The [[render()]] and [[renderFile()]] methods will use - * this view object to implement the actual view rendering. - * If not set, it will default to the "view" application component. - * @return \yii\web\View the view object that can be used to render views or view files. - */ - public function getView() - { - if ($this->_view === null) { - $this->_view = Yii::$app->getView(); - } - return $this->_view; - } - - /** - * Sets the view object to be used by this widget. - * @param View $view the view object that can be used to render views or view files. - */ - public function setView($view) - { - $this->_view = $view; - } - - /** - * Executes the widget. - */ - public function run() - { - } - - /** - * Renders a view. - * The view to be rendered can be specified in one of the following formats: - * - * - path alias (e.g. "@app/views/site/index"); - * - absolute path within application (e.g. "//site/index"): the view name starts with double slashes. - * The actual view file will be looked for under the [[Application::viewPath|view path]] of the application. - * - absolute path within module (e.g. "/site/index"): the view name starts with a single slash. - * The actual view file will be looked for under the [[Module::viewPath|view path]] of the currently - * active module. - * - relative path (e.g. "index"): the actual view file will be looked for under [[viewPath]]. - * - * If the view name does not contain a file extension, it will use the default one `.php`. - - * @param string $view the view name. Please refer to [[findViewFile()]] on how to specify a view name. - * @param array $params the parameters (name-value pairs) that should be made available in the view. - * @return string the rendering result. - * @throws InvalidParamException if the view file does not exist. - */ - public function render($view, $params = []) - { - return $this->getView()->render($view, $params, $this); - } - - /** - * Renders a view file. - * @param string $file the view file to be rendered. This can be either a file path or a path alias. - * @param array $params the parameters (name-value pairs) that should be made available in the view. - * @return string the rendering result. - * @throws InvalidParamException if the view file does not exist. - */ - public function renderFile($file, $params = []) - { - return $this->getView()->renderFile($file, $params, $this); - } - - /** - * Returns the directory containing the view files for this widget. - * The default implementation returns the 'views' subdirectory under the directory containing the widget class file. - * @return string the directory containing the view files for this widget. - */ - public function getViewPath() - { - $class = new ReflectionClass($this); - return dirname($class->getFileName()) . DIRECTORY_SEPARATOR . 'views'; - } - - /** - * Finds the view file based on the given view name. - * File will be searched under [[viewPath]] directory. - * @param string $view the view name. - * @return string the view file path. Note that the file may not exist. - */ - public function findViewFile($view) - { - return $this->getViewPath() . DIRECTORY_SEPARATOR . $view; - } -} diff --git a/framework/yii/behaviors/AutoTimestamp.php b/framework/yii/behaviors/AutoTimestamp.php deleted file mode 100644 index cf8c33e..0000000 --- a/framework/yii/behaviors/AutoTimestamp.php +++ /dev/null @@ -1,116 +0,0 @@ - ['class' => 'yii\behaviors\AutoTimestamp'], - * ]; - * } - * ~~~ - * - * By default, AutoTimestamp will fill the `create_time` attribute with the current timestamp - * when the associated AR object is being inserted; it will fill the `update_time` attribute - * with the timestamp when the AR object is being updated. - * - * @author Qiang Xue - * @since 2.0 - */ -class AutoTimestamp extends Behavior -{ - /** - * @var array list of attributes that are to be automatically filled with timestamps. - * The array keys are the ActiveRecord events upon which the attributes are to be filled with timestamps, - * and the array values are the corresponding attribute(s) to be updated. You can use a string to represent - * a single attribute, or an array to represent a list of attributes. - * The default setting is to update the `create_time` attribute upon AR insertion, - * and update the `update_time` attribute upon AR updating. - */ - public $attributes = [ - ActiveRecord::EVENT_BEFORE_INSERT => 'create_time', - ActiveRecord::EVENT_BEFORE_UPDATE => 'update_time', - ]; - /** - * @var \Closure|Expression The expression that will be used for generating the timestamp. - * This can be either an anonymous function that returns the timestamp value, - * or an [[Expression]] object representing a DB expression (e.g. `new Expression('NOW()')`). - * If not set, it will use the value of `time()` to fill the attributes. - */ - public $timestamp; - - - /** - * Declares event handlers for the [[owner]]'s events. - * @return array events (array keys) and the corresponding event handler methods (array values). - */ - public function events() - { - $events = $this->attributes; - foreach ($events as $i => $event) { - $events[$i] = 'updateTimestamp'; - } - return $events; - } - - /** - * Updates the attributes with the current timestamp. - * @param Event $event - */ - public function updateTimestamp($event) - { - $attributes = isset($this->attributes[$event->name]) ? (array)$this->attributes[$event->name] : []; - if (!empty($attributes)) { - $timestamp = $this->evaluateTimestamp(); - foreach ($attributes as $attribute) { - $this->owner->$attribute = $timestamp; - } - } - } - - /** - * Gets the current timestamp. - * @return mixed the timestamp value - */ - protected function evaluateTimestamp() - { - if ($this->timestamp instanceof Expression) { - return $this->timestamp; - } elseif ($this->timestamp !== null) { - return call_user_func($this->timestamp); - } else { - return time(); - } - } - - /** - * Updates a timestamp attribute to the current timestamp. - * - * ```php - * $model->touch('lastVisit'); - * ``` - * @param string $attribute the name of the attribute to update. - */ - public function touch($attribute) - { - $timestamp = $this->evaluateTimestamp(); - $this->owner->updateAttributes([$attribute => $timestamp]); - } -} diff --git a/framework/yii/caching/ApcCache.php b/framework/yii/caching/ApcCache.php deleted file mode 100644 index 8a0d207..0000000 --- a/framework/yii/caching/ApcCache.php +++ /dev/null @@ -1,133 +0,0 @@ - - * @since 2.0 - */ -class ApcCache extends Cache -{ - /** - * Checks whether a specified key exists in the cache. - * This can be faster than getting the value from the cache if the data is big. - * Note that this method does not check whether the dependency associated - * with the cached data, if there is any, has changed. So a call to [[get]] - * may return false while exists returns true. - * @param mixed $key a key identifying the cached value. This can be a simple string or - * a complex data structure consisting of factors representing the key. - * @return boolean true if a value exists in cache, false if the value is not in the cache or expired. - */ - public function exists($key) - { - $key = $this->buildKey($key); - return apc_exists($key); - } - - /** - * Retrieves a value from cache with a specified key. - * This is the implementation of the method declared in the parent class. - * @param string $key a unique key identifying the cached value - * @return string|boolean the value stored in cache, false if the value is not in the cache or expired. - */ - protected function getValue($key) - { - return apc_fetch($key); - } - - /** - * Retrieves multiple values from cache with the specified keys. - * @param array $keys a list of keys identifying the cached values - * @return array a list of cached values indexed by the keys - */ - protected function getValues($keys) - { - return apc_fetch($keys); - } - - /** - * Stores a value identified by a key in cache. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function setValue($key, $value, $expire) - { - return apc_store($key, $value, $expire); - } - - /** - * Stores multiple key-value pairs in cache. - * @param array $data array where key corresponds to cache key while value - * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. - * @return array array of failed keys - */ - protected function setValues($data, $expire) - { - return array_keys(apc_store($data, null, $expire)); - } - - /** - * Stores a value identified by a key into cache if the cache does not contain this key. - * This is the implementation of the method declared in the parent class. - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function addValue($key, $value, $expire) - { - return apc_add($key, $value, $expire); - } - - /** - * Adds multiple key-value pairs to cache. - * @param array $data array where key corresponds to cache key while value is the value stored - * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. - * @return array array of failed keys - */ - protected function addValues($data, $expire) - { - return array_keys(apc_add($data, null, $expire)); - } - - /** - * Deletes a value with the specified key from cache - * This is the implementation of the method declared in the parent class. - * @param string $key the key of the value to be deleted - * @return boolean if no error happens during deletion - */ - protected function deleteValue($key) - { - return apc_delete($key); - } - - /** - * Deletes all values from cache. - * This is the implementation of the method declared in the parent class. - * @return boolean whether the flush operation was successful. - */ - protected function flushValues() - { - if (extension_loaded('apcu')) { - return apc_clear_cache(); - } else { - return apc_clear_cache('user'); - } - } -} diff --git a/framework/yii/caching/Cache.php b/framework/yii/caching/Cache.php deleted file mode 100644 index 70f2585..0000000 --- a/framework/yii/caching/Cache.php +++ /dev/null @@ -1,474 +0,0 @@ -get($key); - * if ($data === false) { - * // ...generate $data here... - * $cache->set($key, $data, $expire, $dependency); - * } - * ~~~ - * - * Because Cache implements the ArrayAccess interface, it can be used like an array. For example, - * - * ~~~ - * $cache['foo'] = 'some data'; - * echo $cache['foo']; - * ~~~ - * - * Derived classes should implement the following methods: - * - * - [[getValue()]]: retrieve the value with a key (if any) from cache - * - [[setValue()]]: store the value with a key into cache - * - [[addValue()]]: store the value only if the cache does not have this key before - * - [[deleteValue()]]: delete the value with the specified key from cache - * - [[flushValues()]]: delete all values from cache - * - * @author Qiang Xue - * @since 2.0 - */ -abstract class Cache extends Component implements \ArrayAccess -{ - /** - * @var string a string prefixed to every cache key so that it is unique. If not set, - * it will use a prefix generated from [[Application::id]]. You may set this property to be an empty string - * if you don't want to use key prefix. It is recommended that you explicitly set this property to some - * static value if the cached data needs to be shared among multiple applications. - * - * To ensure interoperability, only alphanumeric characters should be used. - */ - public $keyPrefix; - /** - * @var array|boolean the functions used to serialize and unserialize cached data. Defaults to null, meaning - * using the default PHP `serialize()` and `unserialize()` functions. If you want to use some more efficient - * serializer (e.g. [igbinary](http://pecl.php.net/package/igbinary)), you may configure this property with - * a two-element array. The first element specifies the serialization function, and the second the deserialization - * function. If this property is set false, data will be directly sent to and retrieved from the underlying - * cache component without any serialization or deserialization. You should not turn off serialization if - * you are using [[Dependency|cache dependency]], because it relies on data serialization. - */ - public $serializer; - - - /** - * Initializes the application component. - * This method overrides the parent implementation by setting default cache key prefix. - */ - public function init() - { - parent::init(); - if ($this->keyPrefix === null) { - $this->keyPrefix = substr(md5(Yii::$app->id), 0, 5); - } - } - - /** - * Builds a normalized cache key from a given key. - * - * If the given key is a string containing alphanumeric characters only and no more than 32 characters, - * then the key will be returned back prefixed with [[keyPrefix]]. Otherwise, a normalized key - * is generated by serializing the given key, applying MD5 hashing, and prefixing with [[keyPrefix]]. - * - * @param mixed $key the key to be normalized - * @return string the generated cache key - */ - protected function buildKey($key) - { - if (is_string($key)) { - $key = ctype_alnum($key) && StringHelper::byteLength($key) <= 32 ? $key : md5($key); - } else { - $key = md5(json_encode($key)); - } - return $this->keyPrefix . $key; - } - - /** - * Retrieves a value from cache with a specified key. - * @param mixed $key a key identifying the cached value. This can be a simple string or - * a complex data structure consisting of factors representing the key. - * @return mixed the value stored in cache, false if the value is not in the cache, expired, - * or the dependency associated with the cached data has changed. - */ - public function get($key) - { - $key = $this->buildKey($key); - $value = $this->getValue($key); - if ($value === false || $this->serializer === false) { - return $value; - } elseif ($this->serializer === null) { - $value = unserialize($value); - } else { - $value = call_user_func($this->serializer[1], $value); - } - if (is_array($value) && !($value[1] instanceof Dependency && $value[1]->getHasChanged($this))) { - return $value[0]; - } else { - return false; - } - } - - /** - * Checks whether a specified key exists in the cache. - * This can be faster than getting the value from the cache if the data is big. - * In case a cache does not support this feature natively, this method will try to simulate it - * but has no performance improvement over getting it. - * Note that this method does not check whether the dependency associated - * with the cached data, if there is any, has changed. So a call to [[get]] - * may return false while exists returns true. - * @param mixed $key a key identifying the cached value. This can be a simple string or - * a complex data structure consisting of factors representing the key. - * @return boolean true if a value exists in cache, false if the value is not in the cache or expired. - */ - public function exists($key) - { - $key = $this->buildKey($key); - $value = $this->getValue($key); - return $value !== false; - } - - /** - * Retrieves multiple values from cache with the specified keys. - * Some caches (such as memcache, apc) allow retrieving multiple cached values at the same time, - * which may improve the performance. In case a cache does not support this feature natively, - * this method will try to simulate it. - * @param array $keys list of keys identifying the cached values - * @return array list of cached values corresponding to the specified keys. The array - * is returned in terms of (key, value) pairs. - * If a value is not cached or expired, the corresponding array value will be false. - */ - public function mget($keys) - { - $keyMap = []; - foreach ($keys as $key) { - $keyMap[$key] = $this->buildKey($key); - } - $values = $this->getValues(array_values($keyMap)); - $results = []; - foreach ($keyMap as $key => $newKey) { - $results[$key] = false; - if (isset($values[$newKey])) { - if ($this->serializer === false) { - $results[$key] = $values[$newKey]; - } else { - $value = $this->serializer === null ? unserialize($values[$newKey]) - : call_user_func($this->serializer[1], $values[$newKey]); - - if (is_array($value) && !($value[1] instanceof Dependency && $value[1]->getHasChanged($this))) { - $results[$key] = $value[0]; - } - } - } - } - return $results; - } - - /** - * Stores a value identified by a key into cache. - * If the cache already contains such a key, the existing value and - * expiration time will be replaced with the new ones, respectively. - * - * @param mixed $key a key identifying the value to be cached. This can be a simple string or - * a complex data structure consisting of factors representing the key. - * @param mixed $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @param Dependency $dependency dependency of the cached item. If the dependency changes, - * the corresponding value in the cache will be invalidated when it is fetched via [[get()]]. - * This parameter is ignored if [[serializer]] is false. - * @return boolean whether the value is successfully stored into cache - */ - public function set($key, $value, $expire = 0, $dependency = null) - { - if ($dependency !== null && $this->serializer !== false) { - $dependency->evaluateDependency($this); - } - if ($this->serializer === null) { - $value = serialize([$value, $dependency]); - } elseif ($this->serializer !== false) { - $value = call_user_func($this->serializer[0], [$value, $dependency]); - } - $key = $this->buildKey($key); - return $this->setValue($key, $value, $expire); - } - - /** - * Stores multiple items in cache. Each item contains a value identified by a key. - * If the cache already contains such a key, the existing value and - * expiration time will be replaced with the new ones, respectively. - * - * @param array $items the items to be cached, as key-value pairs. - * @param integer $expire default number of seconds in which the cached values will expire. 0 means never expire. - * @param Dependency $dependency dependency of the cached items. If the dependency changes, - * the corresponding values in the cache will be invalidated when it is fetched via [[get()]]. - * This parameter is ignored if [[serializer]] is false. - * @return boolean whether the items are successfully stored into cache - */ - public function mset($items, $expire = 0, $dependency = null) - { - if ($dependency !== null && $this->serializer !== false) { - $dependency->evaluateDependency($this); - } - - $data = []; - foreach ($items as $key => $value) { - $itemKey = $this->buildKey($key); - if ($this->serializer === null) { - $itemValue = serialize([$value, $dependency]); - } elseif ($this->serializer !== false) { - $itemValue = call_user_func($this->serializer[0], [$value, $dependency]); - } - - $data[$itemKey] = $itemValue; - } - return $this->setValues($data, $expire); - } - - /** - * Stores multiple items in cache. Each item contains a value identified by a key. - * If the cache already contains such a key, the existing value and expiration time will be preserved. - * - * @param array $items the items to be cached, as key-value pairs. - * @param integer $expire default number of seconds in which the cached values will expire. 0 means never expire. - * @param Dependency $dependency dependency of the cached items. If the dependency changes, - * the corresponding values in the cache will be invalidated when it is fetched via [[get()]]. - * This parameter is ignored if [[serializer]] is false. - * @return boolean whether the items are successfully stored into cache - */ - public function madd($items, $expire = 0, $dependency = null) - { - if ($dependency !== null && $this->serializer !== false) { - $dependency->evaluateDependency($this); - } - - $data = []; - foreach ($items as $key => $value) { - $itemKey = $this->buildKey($key); - if ($this->serializer === null) { - $itemValue = serialize([$value, $dependency]); - } elseif ($this->serializer !== false) { - $itemValue = call_user_func($this->serializer[0], [$value, $dependency]); - } - - $data[$itemKey] = $itemValue; - } - return $this->addValues($data, $expire); - } - - /** - * Stores a value identified by a key into cache if the cache does not contain this key. - * Nothing will be done if the cache already contains the key. - * @param mixed $key a key identifying the value to be cached. This can be a simple string or - * a complex data structure consisting of factors representing the key. - * @param mixed $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @param Dependency $dependency dependency of the cached item. If the dependency changes, - * the corresponding value in the cache will be invalidated when it is fetched via [[get()]]. - * This parameter is ignored if [[serializer]] is false. - * @return boolean whether the value is successfully stored into cache - */ - public function add($key, $value, $expire = 0, $dependency = null) - { - if ($dependency !== null && $this->serializer !== false) { - $dependency->evaluateDependency($this); - } - if ($this->serializer === null) { - $value = serialize([$value, $dependency]); - } elseif ($this->serializer !== false) { - $value = call_user_func($this->serializer[0], [$value, $dependency]); - } - $key = $this->buildKey($key); - return $this->addValue($key, $value, $expire); - } - - /** - * Deletes a value with the specified key from cache - * @param mixed $key a key identifying the value to be deleted from cache. This can be a simple string or - * a complex data structure consisting of factors representing the key. - * @return boolean if no error happens during deletion - */ - public function delete($key) - { - $key = $this->buildKey($key); - return $this->deleteValue($key); - } - - /** - * Deletes all values from cache. - * Be careful of performing this operation if the cache is shared among multiple applications. - * @return boolean whether the flush operation was successful. - */ - public function flush() - { - return $this->flushValues(); - } - - /** - * Retrieves a value from cache with a specified key. - * This method should be implemented by child classes to retrieve the data - * from specific cache storage. - * @param string $key a unique key identifying the cached value - * @return string|boolean the value stored in cache, false if the value is not in the cache or expired. - */ - abstract protected function getValue($key); - - /** - * Stores a value identified by a key in cache. - * This method should be implemented by child classes to store the data - * in specific cache storage. - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - abstract protected function setValue($key, $value, $expire); - - /** - * Stores a value identified by a key into cache if the cache does not contain this key. - * This method should be implemented by child classes to store the data - * in specific cache storage. - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - abstract protected function addValue($key, $value, $expire); - - /** - * Deletes a value with the specified key from cache - * This method should be implemented by child classes to delete the data from actual cache storage. - * @param string $key the key of the value to be deleted - * @return boolean if no error happens during deletion - */ - abstract protected function deleteValue($key); - - /** - * Deletes all values from cache. - * Child classes may implement this method to realize the flush operation. - * @return boolean whether the flush operation was successful. - */ - abstract protected function flushValues(); - - /** - * Retrieves multiple values from cache with the specified keys. - * The default implementation calls [[getValue()]] multiple times to retrieve - * the cached values one by one. If the underlying cache storage supports multiget, - * this method should be overridden to exploit that feature. - * @param array $keys a list of keys identifying the cached values - * @return array a list of cached values indexed by the keys - */ - protected function getValues($keys) - { - $results = []; - foreach ($keys as $key) { - $results[$key] = $this->getValue($key); - } - return $results; - } - - /** - * Stores multiple key-value pairs in cache. - * The default implementation calls [[setValue()]] multiple times store values one by one. If the underlying cache - * storage supports multiset, this method should be overridden to exploit that feature. - * @param array $data array where key corresponds to cache key while value is the value stored - * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. - * @return array array of failed keys - */ - protected function setValues($data, $expire) - { - $failedKeys = []; - foreach ($data as $key => $value) - { - if ($this->setValue($key, $value, $expire) === false) { - $failedKeys[] = $key; - } - } - return $failedKeys; - } - - /** - * Adds multiple key-value pairs to cache. - * The default implementation calls [[addValue()]] multiple times add values one by one. If the underlying cache - * storage supports multiadd, this method should be overridden to exploit that feature. - * @param array $data array where key corresponds to cache key while value is the value stored - * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. - * @return array array of failed keys - */ - protected function addValues($data, $expire) - { - $failedKeys = []; - foreach ($data as $key => $value) - { - if ($this->addValue($key, $value, $expire) === false) { - $failedKeys[] = $key; - } - } - return $failedKeys; - } - - /** - * Returns whether there is a cache entry with a specified key. - * This method is required by the interface ArrayAccess. - * @param string $key a key identifying the cached value - * @return boolean - */ - public function offsetExists($key) - { - return $this->get($key) !== false; - } - - /** - * Retrieves the value from cache with a specified key. - * This method is required by the interface ArrayAccess. - * @param string $key a key identifying the cached value - * @return mixed the value stored in cache, false if the value is not in the cache or expired. - */ - public function offsetGet($key) - { - return $this->get($key); - } - - /** - * Stores the value identified by a key into cache. - * If the cache already contains such a key, the existing value will be - * replaced with the new ones. To add expiration and dependencies, use the [[set()]] method. - * This method is required by the interface ArrayAccess. - * @param string $key the key identifying the value to be cached - * @param mixed $value the value to be cached - */ - public function offsetSet($key, $value) - { - $this->set($key, $value); - } - - /** - * Deletes the value with the specified key from cache - * This method is required by the interface ArrayAccess. - * @param string $key the key of the value to be deleted - */ - public function offsetUnset($key) - { - $this->delete($key); - } -} diff --git a/framework/yii/caching/ChainedDependency.php b/framework/yii/caching/ChainedDependency.php deleted file mode 100644 index f8bfee3..0000000 --- a/framework/yii/caching/ChainedDependency.php +++ /dev/null @@ -1,75 +0,0 @@ - - * @since 2.0 - */ -class ChainedDependency extends Dependency -{ - /** - * @var Dependency[] list of dependencies that this dependency is composed of. - * Each array element must be a dependency object. - */ - public $dependencies = []; - /** - * @var boolean whether this dependency is depending on every dependency in [[dependencies]]. - * Defaults to true, meaning if any of the dependencies has changed, this dependency is considered changed. - * When it is set false, it means if one of the dependencies has NOT changed, this dependency - * is considered NOT changed. - */ - public $dependOnAll = true; - - /** - * Evaluates the dependency by generating and saving the data related with dependency. - * @param Cache $cache the cache component that is currently evaluating this dependency - */ - public function evaluateDependency($cache) - { - foreach ($this->dependencies as $dependency) { - $dependency->evaluateDependency($cache); - } - } - - /** - * Generates the data needed to determine if dependency has been changed. - * This method does nothing in this class. - * @param Cache $cache the cache component that is currently evaluating this dependency - * @return mixed the data needed to determine if dependency has been changed. - */ - protected function generateDependencyData($cache) - { - return null; - } - - /** - * Performs the actual dependency checking. - * This method returns true if any of the dependency objects - * reports a dependency change. - * @param Cache $cache the cache component that is currently evaluating this dependency - * @return boolean whether the dependency is changed or not. - */ - public function getHasChanged($cache) - { - foreach ($this->dependencies as $dependency) { - if ($this->dependOnAll && $dependency->getHasChanged($cache)) { - return true; - } elseif (!$this->dependOnAll && !$dependency->getHasChanged($cache)) { - return false; - } - } - return !$this->dependOnAll; - } -} diff --git a/framework/yii/caching/DbCache.php b/framework/yii/caching/DbCache.php deleted file mode 100644 index 76e2341..0000000 --- a/framework/yii/caching/DbCache.php +++ /dev/null @@ -1,274 +0,0 @@ - [ - * 'class' => 'yii\caching\DbCache', - * // 'db' => 'mydb', - * // 'cacheTable' => 'my_cache', - * ] - * ~~~ - * - * @author Qiang Xue - * @since 2.0 - */ -class DbCache extends Cache -{ - /** - * @var Connection|string the DB connection object or the application component ID of the DB connection. - * After the DbCache object is created, if you want to change this property, you should only assign it - * with a DB connection object. - */ - public $db = 'db'; - /** - * @var string name of the DB table to store cache content. - * The table should be pre-created as follows: - * - * ~~~ - * CREATE TABLE tbl_cache ( - * id char(128) NOT NULL PRIMARY KEY, - * expire int(11), - * data BLOB - * ); - * ~~~ - * - * where 'BLOB' refers to the BLOB-type of your preferred DBMS. Below are the BLOB type - * that can be used for some popular DBMS: - * - * - MySQL: LONGBLOB - * - PostgreSQL: BYTEA - * - MSSQL: BLOB - * - * When using DbCache in a production server, we recommend you create a DB index for the 'expire' - * column in the cache table to improve the performance. - */ - public $cacheTable = '{{%cache}}'; - /** - * @var integer the probability (parts per million) that garbage collection (GC) should be performed - * when storing a piece of data in the cache. Defaults to 100, meaning 0.01% chance. - * This number should be between 0 and 1000000. A value 0 meaning no GC will be performed at all. - **/ - public $gcProbability = 100; - - - /** - * Initializes the DbCache component. - * This method will initialize the [[db]] property to make sure it refers to a valid DB connection. - * @throws InvalidConfigException if [[db]] is invalid. - */ - public function init() - { - parent::init(); - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - } - if (!$this->db instanceof Connection) { - throw new InvalidConfigException("DbCache::db must be either a DB connection instance or the application component ID of a DB connection."); - } - } - - /** - * Checks whether a specified key exists in the cache. - * This can be faster than getting the value from the cache if the data is big. - * Note that this method does not check whether the dependency associated - * with the cached data, if there is any, has changed. So a call to [[get]] - * may return false while exists returns true. - * @param mixed $key a key identifying the cached value. This can be a simple string or - * a complex data structure consisting of factors representing the key. - * @return boolean true if a value exists in cache, false if the value is not in the cache or expired. - */ - public function exists($key) - { - $key = $this->buildKey($key); - - $query = new Query; - $query->select(['COUNT(*)']) - ->from($this->cacheTable) - ->where('[[id]] = :id AND ([[expire]] = 0 OR [[expire]] >' . time() . ')', [':id' => $key]); - if ($this->db->enableQueryCache) { - // temporarily disable and re-enable query caching - $this->db->enableQueryCache = false; - $result = $query->createCommand($this->db)->queryScalar(); - $this->db->enableQueryCache = true; - } else { - $result = $query->createCommand($this->db)->queryScalar(); - } - return $result > 0; - } - - /** - * Retrieves a value from cache with a specified key. - * This is the implementation of the method declared in the parent class. - * @param string $key a unique key identifying the cached value - * @return string|boolean the value stored in cache, false if the value is not in the cache or expired. - */ - protected function getValue($key) - { - $query = new Query; - $query->select(['data']) - ->from($this->cacheTable) - ->where('[[id]] = :id AND ([[expire]] = 0 OR [[expire]] >' . time() . ')', [':id' => $key]); - if ($this->db->enableQueryCache) { - // temporarily disable and re-enable query caching - $this->db->enableQueryCache = false; - $result = $query->createCommand($this->db)->queryScalar(); - $this->db->enableQueryCache = true; - return $result; - } else { - return $query->createCommand($this->db)->queryScalar(); - } - } - - /** - * Retrieves multiple values from cache with the specified keys. - * @param array $keys a list of keys identifying the cached values - * @return array a list of cached values indexed by the keys - */ - protected function getValues($keys) - { - if (empty($keys)) { - return []; - } - $query = new Query; - $query->select(['id', 'data']) - ->from($this->cacheTable) - ->where(['id' => $keys]) - ->andWhere('([[expire]] = 0 OR [[expire]] > ' . time() . ')'); - - if ($this->db->enableQueryCache) { - $this->db->enableQueryCache = false; - $rows = $query->createCommand($this->db)->queryAll(); - $this->db->enableQueryCache = true; - } else { - $rows = $query->createCommand($this->db)->queryAll(); - } - - $results = []; - foreach ($keys as $key) { - $results[$key] = false; - } - foreach ($rows as $row) { - $results[$row['id']] = $row['data']; - } - return $results; - } - - /** - * Stores a value identified by a key in cache. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function setValue($key, $value, $expire) - { - $command = $this->db->createCommand() - ->update($this->cacheTable, [ - 'expire' => $expire > 0 ? $expire + time() : 0, - 'data' => [$value, \PDO::PARAM_LOB], - ], ['id' => $key]); - - if ($command->execute()) { - $this->gc(); - return true; - } else { - return $this->addValue($key, $value, $expire); - } - } - - /** - * Stores a value identified by a key into cache if the cache does not contain this key. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function addValue($key, $value, $expire) - { - $this->gc(); - - if ($expire > 0) { - $expire += time(); - } else { - $expire = 0; - } - - try { - $this->db->createCommand() - ->insert($this->cacheTable, [ - 'id' => $key, - 'expire' => $expire, - 'data' => [$value, \PDO::PARAM_LOB], - ])->execute(); - return true; - } catch (\Exception $e) { - return false; - } - } - - /** - * Deletes a value with the specified key from cache - * This is the implementation of the method declared in the parent class. - * @param string $key the key of the value to be deleted - * @return boolean if no error happens during deletion - */ - protected function deleteValue($key) - { - $this->db->createCommand() - ->delete($this->cacheTable, ['id' => $key]) - ->execute(); - return true; - } - - /** - * Removes the expired data values. - * @param boolean $force whether to enforce the garbage collection regardless of [[gcProbability]]. - * Defaults to false, meaning the actual deletion happens with the probability as specified by [[gcProbability]]. - */ - public function gc($force = false) - { - if ($force || mt_rand(0, 1000000) < $this->gcProbability) { - $this->db->createCommand() - ->delete($this->cacheTable, '[[expire]] > 0 AND [[expire]] < ' . time()) - ->execute(); - } - } - - /** - * Deletes all values from cache. - * This is the implementation of the method declared in the parent class. - * @return boolean whether the flush operation was successful. - */ - protected function flushValues() - { - $this->db->createCommand() - ->delete($this->cacheTable) - ->execute(); - return true; - } -} diff --git a/framework/yii/caching/DbDependency.php b/framework/yii/caching/DbDependency.php deleted file mode 100644 index ac6f2e7..0000000 --- a/framework/yii/caching/DbDependency.php +++ /dev/null @@ -1,66 +0,0 @@ - - * @since 2.0 - */ -class DbDependency extends Dependency -{ - /** - * @var string the application component ID of the DB connection. - */ - public $db = 'db'; - /** - * @var string the SQL query whose result is used to determine if the dependency has been changed. - * Only the first row of the query result will be used. - */ - public $sql; - /** - * @var array the parameters (name => value) to be bound to the SQL statement specified by [[sql]]. - */ - public $params = []; - - /** - * Generates the data needed to determine if dependency has been changed. - * This method returns the value of the global state. - * @param Cache $cache the cache component that is currently evaluating this dependency - * @return mixed the data needed to determine if dependency has been changed. - * @throws InvalidConfigException if [[db]] is not a valid application component ID - */ - protected function generateDependencyData($cache) - { - $db = Yii::$app->getComponent($this->db); - if (!$db instanceof Connection) { - throw new InvalidConfigException("DbDependency::db must be the application component ID of a DB connection."); - } - if ($this->sql === null) { - throw new InvalidConfigException("DbDependency::sql must be set."); - } - - if ($db->enableQueryCache) { - // temporarily disable and re-enable query caching - $db->enableQueryCache = false; - $result = $db->createCommand($this->sql, $this->params)->queryOne(); - $db->enableQueryCache = true; - } else { - $result = $db->createCommand($this->sql, $this->params)->queryOne(); - } - return $result; - } -} diff --git a/framework/yii/caching/Dependency.php b/framework/yii/caching/Dependency.php deleted file mode 100644 index c84f72d..0000000 --- a/framework/yii/caching/Dependency.php +++ /dev/null @@ -1,99 +0,0 @@ - - * @since 2.0 - */ -abstract class Dependency extends \yii\base\Object -{ - /** - * @var mixed the dependency data that is saved in cache and later is compared with the - * latest dependency data. - */ - public $data; - /** - * @var boolean whether this dependency is reusable or not. True value means that dependent - * data for this cache dependency will be generated only once per request. This allows you - * to use the same cache dependency for multiple separate cache calls while generating the same - * page without an overhead of re-evaluating dependency data each time. Defaults to false. - */ - public $reusable = false; - - /** - * @var array static storage of cached data for reusable dependencies. - */ - private static $_reusableData = []; - /** - * @var string a unique hash value for this cache dependency. - */ - private $_hash; - - - /** - * Evaluates the dependency by generating and saving the data related with dependency. - * This method is invoked by cache before writing data into it. - * @param Cache $cache the cache component that is currently evaluating this dependency - */ - public function evaluateDependency($cache) - { - if (!$this->reusable) { - $this->data = $this->generateDependencyData($cache); - } else { - if ($this->_hash === null) { - $this->_hash = sha1(serialize($this)); - } - if (!array_key_exists($this->_hash, self::$_reusableData)) { - self::$_reusableData[$this->_hash] = $this->generateDependencyData($cache); - } - $this->data = self::$_reusableData[$this->_hash]; - } - } - - /** - * Returns a value indicating whether the dependency has changed. - * @param Cache $cache the cache component that is currently evaluating this dependency - * @return boolean whether the dependency has changed. - */ - public function getHasChanged($cache) - { - if (!$this->reusable) { - return $this->generateDependencyData($cache) !== $this->data; - } else { - if ($this->_hash === null) { - $this->_hash = sha1(serialize($this)); - } - if (!array_key_exists($this->_hash, self::$_reusableData)) { - self::$_reusableData[$this->_hash] = $this->generateDependencyData($cache); - } - return self::$_reusableData[$this->_hash] !== $this->data; - } - } - - /** - * Resets all cached data for reusable dependencies. - */ - public static function resetReusableData() - { - self::$_reusableData = []; - } - - /** - * Generates the data needed to determine if dependency has been changed. - * Derived classes should override this method to generate the actual dependency data. - * @param Cache $cache the cache component that is currently evaluating this dependency - * @return mixed the data needed to determine if dependency has been changed. - */ - abstract protected function generateDependencyData($cache); -} diff --git a/framework/yii/caching/DummyCache.php b/framework/yii/caching/DummyCache.php deleted file mode 100644 index 8d900df..0000000 --- a/framework/yii/caching/DummyCache.php +++ /dev/null @@ -1,81 +0,0 @@ -cache`. - * By replacing DummyCache with some other cache component, one can quickly switch from - * non-caching mode to caching mode. - * - * @author Qiang Xue - * @since 2.0 - */ -class DummyCache extends Cache -{ - /** - * Retrieves a value from cache with a specified key. - * This is the implementation of the method declared in the parent class. - * @param string $key a unique key identifying the cached value - * @return string|boolean the value stored in cache, false if the value is not in the cache or expired. - */ - protected function getValue($key) - { - return false; - } - - /** - * Stores a value identified by a key in cache. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function setValue($key, $value, $expire) - { - return true; - } - - /** - * Stores a value identified by a key into cache if the cache does not contain this key. - * This is the implementation of the method declared in the parent class. - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function addValue($key, $value, $expire) - { - return true; - } - - /** - * Deletes a value with the specified key from cache - * This is the implementation of the method declared in the parent class. - * @param string $key the key of the value to be deleted - * @return boolean if no error happens during deletion - */ - protected function deleteValue($key) - { - return true; - } - - /** - * Deletes all values from cache. - * This is the implementation of the method declared in the parent class. - * @return boolean whether the flush operation was successful. - */ - protected function flushValues() - { - return true; - } -} diff --git a/framework/yii/caching/ExpressionDependency.php b/framework/yii/caching/ExpressionDependency.php deleted file mode 100644 index f6642b4..0000000 --- a/framework/yii/caching/ExpressionDependency.php +++ /dev/null @@ -1,47 +0,0 @@ - - * @since 2.0 - */ -class ExpressionDependency extends Dependency -{ - /** - * @var string the string representation of a PHP expression whose result is used to determine the dependency. - * A PHP expression can be any PHP code that evaluates to a value. To learn more about what an expression is, - * please refer to the [php manual](http://www.php.net/manual/en/language.expressions.php). - */ - public $expression = 'true'; - /** - * @var mixed custom parameters associated with this dependency. You may get the value - * of this property in [[expression]] using `$this->params`. - */ - public $params; - - /** - * Generates the data needed to determine if dependency has been changed. - * This method returns the result of the PHP expression. - * @param Cache $cache the cache component that is currently evaluating this dependency - * @return mixed the data needed to determine if dependency has been changed. - */ - protected function generateDependencyData($cache) - { - return eval("return {$this->expression};"); - } -} diff --git a/framework/yii/caching/FileCache.php b/framework/yii/caching/FileCache.php deleted file mode 100644 index 32cdf58..0000000 --- a/framework/yii/caching/FileCache.php +++ /dev/null @@ -1,240 +0,0 @@ - - * @since 2.0 - */ -class FileCache extends Cache -{ - /** - * @var string the directory to store cache files. You may use path alias here. - * If not set, it will use the "cache" subdirectory under the application runtime path. - */ - public $cachePath = '@runtime/cache'; - /** - * @var string cache file suffix. Defaults to '.bin'. - */ - public $cacheFileSuffix = '.bin'; - /** - * @var integer the level of sub-directories to store cache files. Defaults to 1. - * If the system has huge number of cache files (e.g. one million), you may use a bigger value - * (usually no bigger than 3). Using sub-directories is mainly to ensure the file system - * is not over burdened with a single directory having too many files. - */ - public $directoryLevel = 1; - /** - * @var integer the probability (parts per million) that garbage collection (GC) should be performed - * when storing a piece of data in the cache. Defaults to 10, meaning 0.001% chance. - * This number should be between 0 and 1000000. A value 0 means no GC will be performed at all. - **/ - public $gcProbability = 10; - /** - * @var integer the permission to be set for newly created cache files. - * This value will be used by PHP chmod() function. No umask will be applied. - * If not set, the permission will be determined by the current environment. - */ - public $fileMode; - /** - * @var integer the permission to be set for newly created directories. - * This value will be used by PHP chmod() function. No umask will be applied. - * Defaults to 0775, meaning the directory is read-writable by owner and group, - * but read-only for other users. - */ - public $dirMode = 0775; - - - /** - * Initializes this component by ensuring the existence of the cache path. - */ - public function init() - { - parent::init(); - $this->cachePath = Yii::getAlias($this->cachePath); - if (!is_dir($this->cachePath)) { - FileHelper::createDirectory($this->cachePath, $this->dirMode, true); - } - } - - /** - * Checks whether a specified key exists in the cache. - * This can be faster than getting the value from the cache if the data is big. - * Note that this method does not check whether the dependency associated - * with the cached data, if there is any, has changed. So a call to [[get]] - * may return false while exists returns true. - * @param mixed $key a key identifying the cached value. This can be a simple string or - * a complex data structure consisting of factors representing the key. - * @return boolean true if a value exists in cache, false if the value is not in the cache or expired. - */ - public function exists($key) - { - $cacheFile = $this->getCacheFile($this->buildKey($key)); - return @filemtime($cacheFile) > time(); - } - - /** - * Retrieves a value from cache with a specified key. - * This is the implementation of the method declared in the parent class. - * @param string $key a unique key identifying the cached value - * @return string|boolean the value stored in cache, false if the value is not in the cache or expired. - */ - protected function getValue($key) - { - $cacheFile = $this->getCacheFile($key); - if (@filemtime($cacheFile) > time()) { - return @file_get_contents($cacheFile); - } else { - return false; - } - } - - /** - * Stores a value identified by a key in cache. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function setValue($key, $value, $expire) - { - if ($expire <= 0) { - $expire = 31536000; // 1 year - } - $expire += time(); - - $cacheFile = $this->getCacheFile($key); - if ($this->directoryLevel > 0) { - @FileHelper::createDirectory(dirname($cacheFile), $this->dirMode, true); - } - if (@file_put_contents($cacheFile, $value, LOCK_EX) !== false) { - if ($this->fileMode !== null) { - @chmod($cacheFile, $this->fileMode); - } - return @touch($cacheFile, $expire); - } else { - return false; - } - } - - /** - * Stores a value identified by a key into cache if the cache does not contain this key. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function addValue($key, $value, $expire) - { - $cacheFile = $this->getCacheFile($key); - if (@filemtime($cacheFile) > time()) { - return false; - } - return $this->setValue($key, $value, $expire); - } - - /** - * Deletes a value with the specified key from cache - * This is the implementation of the method declared in the parent class. - * @param string $key the key of the value to be deleted - * @return boolean if no error happens during deletion - */ - protected function deleteValue($key) - { - $cacheFile = $this->getCacheFile($key); - return @unlink($cacheFile); - } - - /** - * Returns the cache file path given the cache key. - * @param string $key cache key - * @return string the cache file path - */ - protected function getCacheFile($key) - { - if ($this->directoryLevel > 0) { - $base = $this->cachePath; - for ($i = 0; $i < $this->directoryLevel; ++$i) { - if (($prefix = substr($key, $i + $i, 2)) !== false) { - $base .= DIRECTORY_SEPARATOR . $prefix; - } - } - return $base . DIRECTORY_SEPARATOR . $key . $this->cacheFileSuffix; - } else { - return $this->cachePath . DIRECTORY_SEPARATOR . $key . $this->cacheFileSuffix; - } - } - - /** - * Deletes all values from cache. - * This is the implementation of the method declared in the parent class. - * @return boolean whether the flush operation was successful. - */ - protected function flushValues() - { - $this->gc(true, false); - return true; - } - - /** - * Removes expired cache files. - * @param boolean $force whether to enforce the garbage collection regardless of [[gcProbability]]. - * Defaults to false, meaning the actual deletion happens with the probability as specified by [[gcProbability]]. - * @param boolean $expiredOnly whether to removed expired cache files only. - * If true, all cache files under [[cachePath]] will be removed. - */ - public function gc($force = false, $expiredOnly = true) - { - if ($force || mt_rand(0, 1000000) < $this->gcProbability) { - $this->gcRecursive($this->cachePath, $expiredOnly); - } - } - - /** - * Recursively removing expired cache files under a directory. - * This method is mainly used by [[gc()]]. - * @param string $path the directory under which expired cache files are removed. - * @param boolean $expiredOnly whether to only remove expired cache files. If false, all files - * under `$path` will be removed. - */ - protected function gcRecursive($path, $expiredOnly) - { - if (($handle = opendir($path)) !== false) { - while (($file = readdir($handle)) !== false) { - if ($file[0] === '.') { - continue; - } - $fullPath = $path . DIRECTORY_SEPARATOR . $file; - if (is_dir($fullPath)) { - $this->gcRecursive($fullPath, $expiredOnly); - if (!$expiredOnly) { - @rmdir($fullPath); - } - } elseif (!$expiredOnly || $expiredOnly && @filemtime($fullPath) < time()) { - @unlink($fullPath); - } - } - closedir($handle); - } - } -} diff --git a/framework/yii/caching/FileDependency.php b/framework/yii/caching/FileDependency.php deleted file mode 100644 index 11afde3..0000000 --- a/framework/yii/caching/FileDependency.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @since 2.0 - */ -class FileDependency extends Dependency -{ - /** - * @var string the name of the file whose last modification time is used to - * check if the dependency has been changed. - */ - public $fileName; - - /** - * Generates the data needed to determine if dependency has been changed. - * This method returns the file's last modification time. - * @param Cache $cache the cache component that is currently evaluating this dependency - * @return mixed the data needed to determine if dependency has been changed. - * @throws InvalidConfigException if [[fileName]] is not set - */ - protected function generateDependencyData($cache) - { - if ($this->fileName === null) { - throw new InvalidConfigException('FileDependency::fileName must be set'); - } - return @filemtime($this->fileName); - } -} diff --git a/framework/yii/caching/GroupDependency.php b/framework/yii/caching/GroupDependency.php deleted file mode 100644 index 1cf7869..0000000 --- a/framework/yii/caching/GroupDependency.php +++ /dev/null @@ -1,73 +0,0 @@ - - * @since 2.0 - */ -class GroupDependency extends Dependency -{ - /** - * @var string the group name. This property must be set. - */ - public $group; - - /** - * Generates the data needed to determine if dependency has been changed. - * This method does nothing in this class. - * @param Cache $cache the cache component that is currently evaluating this dependency - * @return mixed the data needed to determine if dependency has been changed. - * @throws InvalidConfigException if [[group]] is not set. - */ - protected function generateDependencyData($cache) - { - if ($this->group === null) { - throw new InvalidConfigException('GroupDependency::group must be set'); - } - $version = $cache->get([__CLASS__, $this->group]); - if ($version === false) { - $version = $this->invalidate($cache, $this->group); - } - return $version; - } - - /** - * Performs the actual dependency checking. - * @param Cache $cache the cache component that is currently evaluating this dependency - * @return boolean whether the dependency is changed or not. - * @throws InvalidConfigException if [[group]] is not set. - */ - public function getHasChanged($cache) - { - if ($this->group === null) { - throw new InvalidConfigException('GroupDependency::group must be set'); - } - $version = $cache->get([__CLASS__, $this->group]); - return $version === false || $version !== $this->data; - } - - /** - * Invalidates all of the cached data items that have the same [[group]]. - * @param Cache $cache the cache component that caches the data items - * @param string $group the group name - * @return string the current version number - */ - public static function invalidate($cache, $group) - { - $version = microtime(); - $cache->set([__CLASS__, $group], $version); - return $version; - } -} diff --git a/framework/yii/caching/MemCache.php b/framework/yii/caching/MemCache.php deleted file mode 100644 index 3391796..0000000 --- a/framework/yii/caching/MemCache.php +++ /dev/null @@ -1,265 +0,0 @@ - [ - * 'cache' => [ - * 'class' => 'yii\caching\MemCache', - * 'servers' => [ - * [ - * 'host' => 'server1', - * 'port' => 11211, - * 'weight' => 60, - * ], - * [ - * 'host' => 'server2', - * 'port' => 11211, - * 'weight' => 40, - * ], - * ], - * ], - * ], - * ] - * ~~~ - * - * In the above, two memcache servers are used: server1 and server2. You can configure more properties of - * each server, such as `persistent`, `weight`, `timeout`. Please see [[MemCacheServer]] for available options. - * - * @property \Memcache|\Memcached $memcache The memcache (or memcached) object used by this cache component. - * This property is read-only. - * @property MemCacheServer[] $servers List of memcache server configurations. Note that the type of this - * property differs in getter and setter. See [[getServers()]] and [[setServers()]] for details. - * - * @author Qiang Xue - * @since 2.0 - */ -class MemCache extends Cache -{ - /** - * @var boolean whether to use memcached or memcache as the underlying caching extension. - * If true, [memcached](http://pecl.php.net/package/memcached) will be used. - * If false, [memcache](http://pecl.php.net/package/memcache) will be used. - * Defaults to false. - */ - public $useMemcached = false; - /** - * @var \Memcache|\Memcached the Memcache instance - */ - private $_cache = null; - /** - * @var array list of memcache server configurations - */ - private $_servers = []; - - /** - * Initializes this application component. - * It creates the memcache instance and adds memcache servers. - */ - public function init() - { - parent::init(); - $servers = $this->getServers(); - $cache = $this->getMemCache(); - if (empty($servers)) { - $cache->addServer('127.0.0.1', 11211); - } else { - if (!$this->useMemcached) { - // different version of memcache may have different number of parameters for the addServer method. - $class = new \ReflectionClass($cache); - $paramCount = $class->getMethod('addServer')->getNumberOfParameters(); - } - foreach ($servers as $server) { - if ($server->host === null) { - throw new InvalidConfigException("The 'host' property must be specified for every memcache server."); - } - if ($this->useMemcached) { - $cache->addServer($server->host, $server->port, $server->weight); - } else { - // $timeout is used for memcache versions that do not have timeoutms parameter - $timeout = (int) ($server->timeout / 1000) + (($server->timeout % 1000 > 0) ? 1 : 0); - if ($paramCount === 9) { - $cache->addServer( - $server->host, $server->port, $server->persistent, - $server->weight, $timeout, $server->retryInterval, - $server->status, $server->failureCallback, $server->timeout - ); - } else { - $cache->addServer( - $server->host, $server->port, $server->persistent, - $server->weight, $timeout, $server->retryInterval, - $server->status, $server->failureCallback - ); - } - } - } - } - } - - /** - * Returns the underlying memcache (or memcached) object. - * @return \Memcache|\Memcached the memcache (or memcached) object used by this cache component. - * @throws InvalidConfigException if memcache or memcached extension is not loaded - */ - public function getMemcache() - { - if ($this->_cache === null) { - $extension = $this->useMemcached ? 'memcached' : 'memcache'; - if (!extension_loaded($extension)) { - throw new InvalidConfigException("MemCache requires PHP $extension extension to be loaded."); - } - $this->_cache = $this->useMemcached ? new \Memcached : new \Memcache; - } - return $this->_cache; - } - - /** - * Returns the memcache server configurations. - * @return MemCacheServer[] list of memcache server configurations. - */ - public function getServers() - { - return $this->_servers; - } - - /** - * @param array $config list of memcache server configurations. Each element must be an array - * with the following keys: host, port, persistent, weight, timeout, retryInterval, status. - * @see http://www.php.net/manual/en/function.Memcache-addServer.php - */ - public function setServers($config) - { - foreach ($config as $c) { - $this->_servers[] = new MemCacheServer($c); - } - } - - /** - * Retrieves a value from cache with a specified key. - * This is the implementation of the method declared in the parent class. - * @param string $key a unique key identifying the cached value - * @return string|boolean the value stored in cache, false if the value is not in the cache or expired. - */ - protected function getValue($key) - { - return $this->_cache->get($key); - } - - /** - * Retrieves multiple values from cache with the specified keys. - * @param array $keys a list of keys identifying the cached values - * @return array a list of cached values indexed by the keys - */ - protected function getValues($keys) - { - return $this->useMemcached ? $this->_cache->getMulti($keys) : $this->_cache->get($keys); - } - - /** - * Stores a value identified by a key in cache. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function setValue($key, $value, $expire) - { - if ($expire > 0) { - $expire += time(); - } else { - $expire = 0; - } - - return $this->useMemcached ? $this->_cache->set($key, $value, $expire) : $this->_cache->set($key, $value, 0, $expire); - } - - /** - * Stores multiple key-value pairs in cache. - * @param array $data array where key corresponds to cache key while value is the value stored - * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. - * @return array array of failed keys. Always empty in case of using memcached. - */ - protected function setValues($data, $expire) - { - if ($this->useMemcached) { - if ($expire > 0) { - $expire += time(); - } else { - $expire = 0; - } - $this->_cache->setMulti($data, $expire); - return []; - } else { - return parent::setValues($data, $expire); - } - } - - /** - * Stores a value identified by a key into cache if the cache does not contain this key. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function addValue($key, $value, $expire) - { - if ($expire > 0) { - $expire += time(); - } else { - $expire = 0; - } - - return $this->useMemcached ? $this->_cache->add($key, $value, $expire) : $this->_cache->add($key, $value, 0, $expire); - } - - /** - * Deletes a value with the specified key from cache - * This is the implementation of the method declared in the parent class. - * @param string $key the key of the value to be deleted - * @return boolean if no error happens during deletion - */ - protected function deleteValue($key) - { - return $this->_cache->delete($key, 0); - } - - /** - * Deletes all values from cache. - * This is the implementation of the method declared in the parent class. - * @return boolean whether the flush operation was successful. - */ - protected function flushValues() - { - return $this->_cache->flush(); - } -} diff --git a/framework/yii/caching/MemCacheServer.php b/framework/yii/caching/MemCacheServer.php deleted file mode 100644 index b1b7727..0000000 --- a/framework/yii/caching/MemCacheServer.php +++ /dev/null @@ -1,58 +0,0 @@ - - * @since 2.0 - */ -class MemCacheServer extends \yii\base\Object -{ - /** - * @var string memcache server hostname or IP address - */ - public $host; - /** - * @var integer memcache server port - */ - public $port = 11211; - /** - * @var integer probability of using this server among all servers. - */ - public $weight = 1; - /** - * @var boolean whether to use a persistent connection. This is used by memcache only. - */ - public $persistent = true; - /** - * @var integer timeout in milliseconds which will be used for connecting to the server. - * This is used by memcache only. For old versions of memcache that only support specifying - * timeout in seconds this will be rounded up to full seconds. - */ - public $timeout = 1000; - /** - * @var integer how often a failed server will be retried (in seconds). This is used by memcache only. - */ - public $retryInterval = 15; - /** - * @var boolean if the server should be flagged as online upon a failure. This is used by memcache only. - */ - public $status = true; - /** - * @var \Closure this callback function will run upon encountering an error. - * The callback is run before fail over is attempted. The function takes two parameters, - * the [[host]] and the [[port]] of the failed server. - * This is used by memcache only. - */ - public $failureCallback; -} diff --git a/framework/yii/caching/WinCache.php b/framework/yii/caching/WinCache.php deleted file mode 100644 index 6b80f3c..0000000 --- a/framework/yii/caching/WinCache.php +++ /dev/null @@ -1,132 +0,0 @@ - - * @since 2.0 - */ -class WinCache extends Cache -{ - /** - * Checks whether a specified key exists in the cache. - * This can be faster than getting the value from the cache if the data is big. - * Note that this method does not check whether the dependency associated - * with the cached data, if there is any, has changed. So a call to [[get]] - * may return false while exists returns true. - * @param mixed $key a key identifying the cached value. This can be a simple string or - * a complex data structure consisting of factors representing the key. - * @return boolean true if a value exists in cache, false if the value is not in the cache or expired. - */ - public function exists($key) - { - $key = $this->buildKey($key); - return wincache_ucache_exists($key); - } - - /** - * Retrieves a value from cache with a specified key. - * This is the implementation of the method declared in the parent class. - * @param string $key a unique key identifying the cached value - * @return string|boolean the value stored in cache, false if the value is not in the cache or expired. - */ - protected function getValue($key) - { - return wincache_ucache_get($key); - } - - /** - * Retrieves multiple values from cache with the specified keys. - * @param array $keys a list of keys identifying the cached values - * @return array a list of cached values indexed by the keys - */ - protected function getValues($keys) - { - return wincache_ucache_get($keys); - } - - /** - * Stores a value identified by a key in cache. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function setValue($key, $value, $expire) - { - return wincache_ucache_set($key, $value, $expire); - } - - /** - * Stores multiple key-value pairs in cache. - * @param array $data array where key corresponds to cache key while value is the value stored - * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. - * @return array array of failed keys - */ - protected function setValues($data, $expire) - { - return wincache_ucache_set($data, null, $expire); - } - - /** - * Stores a value identified by a key into cache if the cache does not contain this key. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function addValue($key, $value, $expire) - { - return wincache_ucache_add($key, $value, $expire); - } - - /** - * Adds multiple key-value pairs to cache. - * The default implementation calls [[addValue()]] multiple times add values one by one. If the underlying cache - * storage supports multiadd, this method should be overridden to exploit that feature. - * @param array $data array where key corresponds to cache key while value is the value stored - * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. - * @return array array of failed keys - */ - protected function addValues($data, $expire) - { - return wincache_ucache_add($data, null, $expire); - } - - /** - * Deletes a value with the specified key from cache - * This is the implementation of the method declared in the parent class. - * @param string $key the key of the value to be deleted - * @return boolean if no error happens during deletion - */ - protected function deleteValue($key) - { - return wincache_ucache_delete($key); - } - - /** - * Deletes all values from cache. - * This is the implementation of the method declared in the parent class. - * @return boolean whether the flush operation was successful. - */ - protected function flushValues() - { - return wincache_ucache_clear(); - } -} diff --git a/framework/yii/caching/XCache.php b/framework/yii/caching/XCache.php deleted file mode 100644 index 4221a39..0000000 --- a/framework/yii/caching/XCache.php +++ /dev/null @@ -1,104 +0,0 @@ - - * @since 2.0 - */ -class XCache extends Cache -{ - /** - * Checks whether a specified key exists in the cache. - * This can be faster than getting the value from the cache if the data is big. - * Note that this method does not check whether the dependency associated - * with the cached data, if there is any, has changed. So a call to [[get]] - * may return false while exists returns true. - * @param mixed $key a key identifying the cached value. This can be a simple string or - * a complex data structure consisting of factors representing the key. - * @return boolean true if a value exists in cache, false if the value is not in the cache or expired. - */ - public function exists($key) - { - $key = $this->buildKey($key); - return xcache_isset($key); - } - - /** - * Retrieves a value from cache with a specified key. - * This is the implementation of the method declared in the parent class. - * @param string $key a unique key identifying the cached value - * @return string|boolean the value stored in cache, false if the value is not in the cache or expired. - */ - protected function getValue($key) - { - return xcache_isset($key) ? xcache_get($key) : false; - } - - /** - * Stores a value identified by a key in cache. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function setValue($key, $value, $expire) - { - return xcache_set($key, $value, $expire); - } - - /** - * Stores a value identified by a key into cache if the cache does not contain this key. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function addValue($key, $value, $expire) - { - return !xcache_isset($key) ? $this->setValue($key, $value, $expire) : false; - } - - /** - * Deletes a value with the specified key from cache - * This is the implementation of the method declared in the parent class. - * @param string $key the key of the value to be deleted - * @return boolean if no error happens during deletion - */ - protected function deleteValue($key) - { - return xcache_unset($key); - } - - /** - * Deletes all values from cache. - * This is the implementation of the method declared in the parent class. - * @return boolean whether the flush operation was successful. - */ - protected function flushValues() - { - for ($i = 0, $max = xcache_count(XC_TYPE_VAR); $i < $max; $i++) { - if (xcache_clear_cache(XC_TYPE_VAR, $i) === false) { - return false; - } - } - return true; - } -} diff --git a/framework/yii/caching/ZendDataCache.php b/framework/yii/caching/ZendDataCache.php deleted file mode 100644 index 9ff2fd0..0000000 --- a/framework/yii/caching/ZendDataCache.php +++ /dev/null @@ -1,83 +0,0 @@ - - * @since 2.0 - */ -class ZendDataCache extends Cache -{ - /** - * Retrieves a value from cache with a specified key. - * This is the implementation of the method declared in the parent class. - * @param string $key a unique key identifying the cached value - * @return string|boolean the value stored in cache, false if the value is not in the cache or expired. - */ - protected function getValue($key) - { - $result = zend_shm_cache_fetch($key); - return $result === null ? false : $result; - } - - /** - * Stores a value identified by a key in cache. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function setValue($key, $value, $expire) - { - return zend_shm_cache_store($key, $value, $expire); - } - - /** - * Stores a value identified by a key into cache if the cache does not contain this key. - * This is the implementation of the method declared in the parent class. - * - * @param string $key the key identifying the value to be cached - * @param string $value the value to be cached - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. - * @return boolean true if the value is successfully stored into cache, false otherwise - */ - protected function addValue($key, $value, $expire) - { - return zend_shm_cache_fetch($key) === null ? $this->setValue($key, $value, $expire) : false; - } - - /** - * Deletes a value with the specified key from cache - * This is the implementation of the method declared in the parent class. - * @param string $key the key of the value to be deleted - * @return boolean if no error happens during deletion - */ - protected function deleteValue($key) - { - return zend_shm_cache_delete($key); - } - - /** - * Deletes all values from cache. - * This is the implementation of the method declared in the parent class. - * @return boolean whether the flush operation was successful. - */ - protected function flushValues() - { - return zend_shm_cache_clear(); - } -} diff --git a/framework/yii/captcha/Captcha.php b/framework/yii/captcha/Captcha.php deleted file mode 100644 index 9e69b9e..0000000 --- a/framework/yii/captcha/Captcha.php +++ /dev/null @@ -1,138 +0,0 @@ - - * @since 2.0 - */ -class Captcha extends InputWidget -{ - /** - * @var string the route of the action that generates the CAPTCHA images. - * The action represented by this route must be an action of [[CaptchaAction]]. - */ - public $captchaAction = 'site/captcha'; - /** - * @var array HTML attributes to be applied to the CAPTCHA image tag. - */ - public $imageOptions = []; - /** - * @var string the template for arranging the CAPTCHA image tag and the text input tag. - * In this template, the token `{image}` will be replaced with the actual image tag, - * while `{input}` will be replaced with the text input tag. - */ - public $template = '{image} {input}'; - /** - * @var array the HTML attributes for the input tag. - */ - public $options = ['class' => 'form-control']; - - /** - * Initializes the widget. - */ - public function init() - { - parent::init(); - - $this->checkRequirements(); - - if (!isset($this->imageOptions['id'])) { - $this->imageOptions['id'] = $this->options['id'] . '-image'; - } - } - - /** - * Renders the widget. - */ - public function run() - { - $this->registerClientScript(); - if ($this->hasModel()) { - $input = Html::activeTextInput($this->model, $this->attribute, $this->options); - } else { - $input = Html::textInput($this->name, $this->value, $this->options); - } - $url = Yii::$app->getUrlManager()->createUrl($this->captchaAction, ['v' => uniqid()]); - $image = Html::img($url, $this->imageOptions); - echo strtr($this->template, [ - '{input}' => $input, - '{image}' => $image, - ]); - } - - /** - * Registers the needed JavaScript. - */ - public function registerClientScript() - { - $options = $this->getClientOptions(); - $options = empty($options) ? '' : Json::encode($options); - $id = $this->imageOptions['id']; - $view = $this->getView(); - CaptchaAsset::register($view); - $view->registerJs("jQuery('#$id').yiiCaptcha($options);"); - } - - /** - * Returns the options for the captcha JS widget. - * @return array the options - */ - protected function getClientOptions() - { - $options = [ - 'refreshUrl' => Html::url([$this->captchaAction, CaptchaAction::REFRESH_GET_VAR => 1]), - 'hashKey' => "yiiCaptcha/{$this->captchaAction}", - ]; - return $options; - } - - /** - * Checks if there is graphic extension available to generate CAPTCHA images. - * This method will check the existence of ImageMagick and GD extensions. - * @return string the name of the graphic extension, either "imagick" or "gd". - * @throws InvalidConfigException if neither ImageMagick nor GD is installed. - */ - public static function checkRequirements() - { - if (extension_loaded('imagick')) { - $imagick = new \Imagick(); - $imagickFormats = $imagick->queryFormats('PNG'); - if (in_array('PNG', $imagickFormats)) { - return 'imagick'; - } - } - if (extension_loaded('gd')) { - $gdInfo = gd_info(); - if (!empty($gdInfo['FreeType Support'])) { - return 'gd'; - } - } - throw new InvalidConfigException('GD with FreeType or ImageMagick PHP extensions are required.'); - } -} diff --git a/framework/yii/captcha/CaptchaAction.php b/framework/yii/captcha/CaptchaAction.php deleted file mode 100644 index 190ec35..0000000 --- a/framework/yii/captcha/CaptchaAction.php +++ /dev/null @@ -1,341 +0,0 @@ - - * @since 2.0 - */ -class CaptchaAction extends Action -{ - /** - * The name of the GET parameter indicating whether the CAPTCHA image should be regenerated. - */ - const REFRESH_GET_VAR = 'refresh'; - /** - * @var integer how many times should the same CAPTCHA be displayed. Defaults to 3. - * A value less than or equal to 0 means the test is unlimited (available since version 1.1.2). - */ - public $testLimit = 3; - /** - * @var integer the width of the generated CAPTCHA image. Defaults to 120. - */ - public $width = 120; - /** - * @var integer the height of the generated CAPTCHA image. Defaults to 50. - */ - public $height = 50; - /** - * @var integer padding around the text. Defaults to 2. - */ - public $padding = 2; - /** - * @var integer the background color. For example, 0x55FF00. - * Defaults to 0xFFFFFF, meaning white color. - */ - public $backColor = 0xFFFFFF; - /** - * @var integer the font color. For example, 0x55FF00. Defaults to 0x2040A0 (blue color). - */ - public $foreColor = 0x2040A0; - /** - * @var boolean whether to use transparent background. Defaults to false. - */ - public $transparent = false; - /** - * @var integer the minimum length for randomly generated word. Defaults to 6. - */ - public $minLength = 6; - /** - * @var integer the maximum length for randomly generated word. Defaults to 7. - */ - public $maxLength = 7; - /** - * @var integer the offset between characters. Defaults to -2. You can adjust this property - * in order to decrease or increase the readability of the captcha. - **/ - public $offset = -2; - /** - * @var string the TrueType font file. This can be either a file path or path alias. - */ - public $fontFile = '@yii/captcha/SpicyRice.ttf'; - /** - * @var string the fixed verification code. When this property is set, - * [[getVerifyCode()]] will always return the value of this property. - * This is mainly used in automated tests where we want to be able to reproduce - * the same verification code each time we run the tests. - * If not set, it means the verification code will be randomly generated. - */ - public $fixedVerifyCode; - - - /** - * Initializes the action. - * @throws InvalidConfigException if the font file does not exist. - */ - public function init() - { - $this->fontFile = Yii::getAlias($this->fontFile); - if (!is_file($this->fontFile)) { - throw new InvalidConfigException("The font file does not exist: {$this->fontFile}"); - } - } - - /** - * Runs the action. - */ - public function run() - { - if (isset($_GET[self::REFRESH_GET_VAR])) { - // AJAX request for regenerating code - $code = $this->getVerifyCode(true); - /** @var \yii\web\Controller $controller */ - $controller = $this->controller; - return json_encode([ - 'hash1' => $this->generateValidationHash($code), - 'hash2' => $this->generateValidationHash(strtolower($code)), - // we add a random 'v' parameter so that FireFox can refresh the image - // when src attribute of image tag is changed - 'url' => $controller->createUrl($this->id, ['v' => uniqid()]), - ]); - } else { - $this->setHttpHeaders(); - return $this->renderImage($this->getVerifyCode()); - } - } - - /** - * Generates a hash code that can be used for client side validation. - * @param string $code the CAPTCHA code - * @return string a hash code generated from the CAPTCHA code - */ - public function generateValidationHash($code) - { - for ($h = 0, $i = strlen($code) - 1; $i >= 0; --$i) { - $h += ord($code[$i]); - } - return $h; - } - - /** - * Gets the verification code. - * @param boolean $regenerate whether the verification code should be regenerated. - * @return string the verification code. - */ - public function getVerifyCode($regenerate = false) - { - if ($this->fixedVerifyCode !== null) { - return $this->fixedVerifyCode; - } - - $session = Yii::$app->getSession(); - $session->open(); - $name = $this->getSessionKey(); - if ($session[$name] === null || $regenerate) { - $session[$name] = $this->generateVerifyCode(); - $session[$name . 'count'] = 1; - } - return $session[$name]; - } - - /** - * Validates the input to see if it matches the generated code. - * @param string $input user input - * @param boolean $caseSensitive whether the comparison should be case-sensitive - * @return boolean whether the input is valid - */ - public function validate($input, $caseSensitive) - { - $code = $this->getVerifyCode(); - $valid = $caseSensitive ? ($input === $code) : strcasecmp($input, $code) === 0; - $session = Yii::$app->getSession(); - $session->open(); - $name = $this->getSessionKey() . 'count'; - $session[$name] = $session[$name] + 1; - if ($valid || $session[$name] > $this->testLimit && $this->testLimit > 0) { - $this->getVerifyCode(true); - } - return $valid; - } - - /** - * Generates a new verification code. - * @return string the generated verification code - */ - protected function generateVerifyCode() - { - if ($this->minLength > $this->maxLength) { - $this->maxLength = $this->minLength; - } - if ($this->minLength < 3) { - $this->minLength = 3; - } - if ($this->maxLength > 20) { - $this->maxLength = 20; - } - $length = mt_rand($this->minLength, $this->maxLength); - - $letters = 'bcdfghjklmnpqrstvwxyz'; - $vowels = 'aeiou'; - $code = ''; - for ($i = 0; $i < $length; ++$i) { - if ($i % 2 && mt_rand(0, 10) > 2 || !($i % 2) && mt_rand(0, 10) > 9) { - $code .= $vowels[mt_rand(0, 4)]; - } else { - $code .= $letters[mt_rand(0, 20)]; - } - } - - return $code; - } - - /** - * Returns the session variable name used to store verification code. - * @return string the session variable name - */ - protected function getSessionKey() - { - return '__captcha/' . $this->getUniqueId(); - } - - /** - * Renders the CAPTCHA image. - * @param string $code the verification code - * @return string image contents - */ - protected function renderImage($code) - { - if (Captcha::checkRequirements() === 'gd') { - return $this->renderImageByGD($code); - } else { - return $this->renderImageByImagick($code); - } - } - - /** - * Renders the CAPTCHA image based on the code using GD library. - * @param string $code the verification code - * @return string image contents - */ - protected function renderImageByGD($code) - { - $image = imagecreatetruecolor($this->width, $this->height); - - $backColor = imagecolorallocate($image, - (int)($this->backColor % 0x1000000 / 0x10000), - (int)($this->backColor % 0x10000 / 0x100), - $this->backColor % 0x100); - imagefilledrectangle($image, 0, 0, $this->width, $this->height, $backColor); - imagecolordeallocate($image, $backColor); - - if ($this->transparent) { - imagecolortransparent($image, $backColor); - } - - $foreColor = imagecolorallocate($image, - (int)($this->foreColor % 0x1000000 / 0x10000), - (int)($this->foreColor % 0x10000 / 0x100), - $this->foreColor % 0x100); - - $length = strlen($code); - $box = imagettfbbox(30, 0, $this->fontFile, $code); - $w = $box[4] - $box[0] + $this->offset * ($length - 1); - $h = $box[1] - $box[5]; - $scale = min(($this->width - $this->padding * 2) / $w, ($this->height - $this->padding * 2) / $h); - $x = 10; - $y = round($this->height * 27 / 40); - for ($i = 0; $i < $length; ++$i) { - $fontSize = (int)(rand(26, 32) * $scale * 0.8); - $angle = rand(-10, 10); - $letter = $code[$i]; - $box = imagettftext($image, $fontSize, $angle, $x, $y, $foreColor, $this->fontFile, $letter); - $x = $box[2] + $this->offset; - } - - imagecolordeallocate($image, $foreColor); - - ob_start(); - imagepng($image); - imagedestroy($image); - return ob_get_clean(); - } - - /** - * Renders the CAPTCHA image based on the code using ImageMagick library. - * @param string $code the verification code - * @return \Imagick image instance. Can be used as string. In this case it will contain image contents. - */ - protected function renderImageByImagick($code) - { - $backColor = $this->transparent ? new \ImagickPixel('transparent') : new \ImagickPixel('#' . dechex($this->backColor)); - $foreColor = new \ImagickPixel('#' . dechex($this->foreColor)); - - $image = new \Imagick(); - $image->newImage($this->width, $this->height, $backColor); - - $draw = new \ImagickDraw(); - $draw->setFont($this->fontFile); - $draw->setFontSize(30); - $fontMetrics = $image->queryFontMetrics($draw, $code); - - $length = strlen($code); - $w = (int)($fontMetrics['textWidth']) - 8 + $this->offset * ($length - 1); - $h = (int)($fontMetrics['textHeight']) - 8; - $scale = min(($this->width - $this->padding * 2) / $w, ($this->height - $this->padding * 2) / $h); - $x = 10; - $y = round($this->height * 27 / 40); - for ($i = 0; $i < $length; ++$i) { - $draw = new \ImagickDraw(); - $draw->setFont($this->fontFile); - $draw->setFontSize((int)(rand(26, 32) * $scale * 0.8)); - $draw->setFillColor($foreColor); - $image->annotateImage($draw, $x, $y, rand(-10, 10), $code[$i]); - $fontMetrics = $image->queryFontMetrics($draw, $code[$i]); - $x += (int)($fontMetrics['textWidth']) + $this->offset; - } - - $image->setImageFormat('png'); - return $image; - } - - /** - * Sets the HTTP headers needed by image response. - */ - protected function setHttpHeaders() - { - Yii::$app->getResponse()->getHeaders() - ->set('Pragma', 'public') - ->set('Expires', '0') - ->set('Cache-Control', 'must-revalidate, post-check=0, pre-check=0') - ->set('Content-Transfer-Encoding', 'binary') - ->set('Content-type', 'image/png'); - } -} diff --git a/framework/yii/captcha/CaptchaAsset.php b/framework/yii/captcha/CaptchaAsset.php deleted file mode 100644 index 4fc722f..0000000 --- a/framework/yii/captcha/CaptchaAsset.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @since 2.0 - */ -class CaptchaAsset extends AssetBundle -{ - public $sourcePath = '@yii/assets'; - public $js = [ - 'yii.captcha.js', - ]; - public $depends = [ - 'yii\web\YiiAsset', - ]; -} diff --git a/framework/yii/captcha/CaptchaValidator.php b/framework/yii/captcha/CaptchaValidator.php deleted file mode 100644 index 57665ec..0000000 --- a/framework/yii/captcha/CaptchaValidator.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @since 2.0 - */ -class CaptchaValidator extends Validator -{ - /** - * @var boolean whether to skip this validator if the input is empty. - */ - public $skipOnEmpty = false; - /** - * @var boolean whether the comparison is case sensitive. Defaults to false. - */ - public $caseSensitive = false; - /** - * @var string the route of the controller action that renders the CAPTCHA image. - */ - public $captchaAction = 'site/captcha'; - - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->message === null) { - $this->message = Yii::t('yii', 'The verification code is incorrect.'); - } - } - - /** - * @inheritdoc - */ - protected function validateValue($value) - { - $captcha = $this->createCaptchaAction(); - $valid = !is_array($value) && $captcha->validate($value, $this->caseSensitive); - return $valid ? null : [$this->message, []]; - } - - /** - * Creates the CAPTCHA action object from the route specified by [[captchaAction]]. - * @return \yii\captcha\CaptchaAction the action object - * @throws InvalidConfigException - */ - public function createCaptchaAction() - { - $ca = Yii::$app->createController($this->captchaAction); - if ($ca !== false) { - /** @var \yii\base\Controller $controller */ - list($controller, $actionID) = $ca; - $action = $controller->createAction($actionID); - if ($action !== null) { - return $action; - } - } - throw new InvalidConfigException('Invalid CAPTCHA action ID: ' . $this->captchaAction); - } - - /** - * @inheritdoc - */ - public function clientValidateAttribute($object, $attribute, $view) - { - $captcha = $this->createCaptchaAction(); - $code = $captcha->getVerifyCode(false); - $hash = $captcha->generateValidationHash($this->caseSensitive ? $code : strtolower($code)); - $options = [ - 'hash' => $hash, - 'hashKey' => 'yiiCaptcha/' . $this->captchaAction, - 'caseSensitive' => $this->caseSensitive, - 'message' => strtr($this->message, [ - '{attribute}' => $object->getAttributeLabel($attribute), - ]), - ]; - if ($this->skipOnEmpty) { - $options['skipOnEmpty'] = 1; - } - - ValidationAsset::register($view); - return 'yii.validation.captcha(value, messages, ' . json_encode($options) . ');'; - } -} diff --git a/framework/yii/captcha/SpicyRice.md b/framework/yii/captcha/SpicyRice.md deleted file mode 100644 index 7049bd1..0000000 --- a/framework/yii/captcha/SpicyRice.md +++ /dev/null @@ -1,11 +0,0 @@ -## Spicy Rice font - -* **Author:** Brian J. Bonislawsky, Astigmatic (AOETI, Astigmatic One Eye Typographic Institute) -* **License:** SIL Open Font License (OFL), version 1.1, [notes and FAQ](http://scripts.sil.org/OFL) - -## Links - -* [Astigmatic](http://www.astigmatic.com/) -* [Google WebFonts](http://www.google.com/webfonts/specimen/Spicy+Rice) -* [fontsquirrel.com](http://www.fontsquirrel.com/fonts/spicy-rice) -* [fontspace.com](http://www.fontspace.com/astigmatic-one-eye-typographic-institute/spicy-rice) diff --git a/framework/yii/captcha/SpicyRice.ttf b/framework/yii/captcha/SpicyRice.ttf deleted file mode 100644 index 638436c..0000000 Binary files a/framework/yii/captcha/SpicyRice.ttf and /dev/null differ diff --git a/framework/yii/classes.php b/framework/yii/classes.php deleted file mode 100644 index 9606930..0000000 --- a/framework/yii/classes.php +++ /dev/null @@ -1,253 +0,0 @@ - YII_PATH . '/base/Action.php', - 'yii\base\ActionEvent' => YII_PATH . '/base/ActionEvent.php', - 'yii\base\ActionFilter' => YII_PATH . '/base/ActionFilter.php', - 'yii\base\Application' => YII_PATH . '/base/Application.php', - 'yii\base\Arrayable' => YII_PATH . '/base/Arrayable.php', - 'yii\base\Behavior' => YII_PATH . '/base/Behavior.php', - 'yii\base\Component' => YII_PATH . '/base/Component.php', - 'yii\base\Controller' => YII_PATH . '/base/Controller.php', - 'yii\base\ErrorException' => YII_PATH . '/base/ErrorException.php', - 'yii\base\ErrorHandler' => YII_PATH . '/base/ErrorHandler.php', - 'yii\base\Event' => YII_PATH . '/base/Event.php', - 'yii\base\Exception' => YII_PATH . '/base/Exception.php', - 'yii\base\Extension' => YII_PATH . '/base/Extension.php', - 'yii\base\Formatter' => YII_PATH . '/base/Formatter.php', - 'yii\base\InlineAction' => YII_PATH . '/base/InlineAction.php', - 'yii\base\InvalidCallException' => YII_PATH . '/base/InvalidCallException.php', - 'yii\base\InvalidConfigException' => YII_PATH . '/base/InvalidConfigException.php', - 'yii\base\InvalidParamException' => YII_PATH . '/base/InvalidParamException.php', - 'yii\base\InvalidRouteException' => YII_PATH . '/base/InvalidRouteException.php', - 'yii\base\Model' => YII_PATH . '/base/Model.php', - 'yii\base\ModelEvent' => YII_PATH . '/base/ModelEvent.php', - 'yii\base\Module' => YII_PATH . '/base/Module.php', - 'yii\base\NotSupportedException' => YII_PATH . '/base/NotSupportedException.php', - 'yii\base\Object' => YII_PATH . '/base/Object.php', - 'yii\base\Request' => YII_PATH . '/base/Request.php', - 'yii\base\Response' => YII_PATH . '/base/Response.php', - 'yii\base\Theme' => YII_PATH . '/base/Theme.php', - 'yii\base\UnknownClassException' => YII_PATH . '/base/UnknownClassException.php', - 'yii\base\UnknownMethodException' => YII_PATH . '/base/UnknownMethodException.php', - 'yii\base\UnknownPropertyException' => YII_PATH . '/base/UnknownPropertyException.php', - 'yii\base\UserException' => YII_PATH . '/base/UserException.php', - 'yii\base\View' => YII_PATH . '/base/View.php', - 'yii\base\ViewContextInterface' => YII_PATH . '/base/ViewContextInterface.php', - 'yii\base\ViewEvent' => YII_PATH . '/base/ViewEvent.php', - 'yii\base\ViewRenderer' => YII_PATH . '/base/ViewRenderer.php', - 'yii\base\Widget' => YII_PATH . '/base/Widget.php', - 'yii\behaviors\AutoTimestamp' => YII_PATH . '/behaviors/AutoTimestamp.php', - 'yii\caching\ApcCache' => YII_PATH . '/caching/ApcCache.php', - 'yii\caching\Cache' => YII_PATH . '/caching/Cache.php', - 'yii\caching\ChainedDependency' => YII_PATH . '/caching/ChainedDependency.php', - 'yii\caching\DbCache' => YII_PATH . '/caching/DbCache.php', - 'yii\caching\DbDependency' => YII_PATH . '/caching/DbDependency.php', - 'yii\caching\Dependency' => YII_PATH . '/caching/Dependency.php', - 'yii\caching\DummyCache' => YII_PATH . '/caching/DummyCache.php', - 'yii\caching\ExpressionDependency' => YII_PATH . '/caching/ExpressionDependency.php', - 'yii\caching\FileCache' => YII_PATH . '/caching/FileCache.php', - 'yii\caching\FileDependency' => YII_PATH . '/caching/FileDependency.php', - 'yii\caching\GroupDependency' => YII_PATH . '/caching/GroupDependency.php', - 'yii\caching\MemCache' => YII_PATH . '/caching/MemCache.php', - 'yii\caching\MemCacheServer' => YII_PATH . '/caching/MemCacheServer.php', - 'yii\caching\WinCache' => YII_PATH . '/caching/WinCache.php', - 'yii\caching\XCache' => YII_PATH . '/caching/XCache.php', - 'yii\caching\ZendDataCache' => YII_PATH . '/caching/ZendDataCache.php', - 'yii\captcha\Captcha' => YII_PATH . '/captcha/Captcha.php', - 'yii\captcha\CaptchaAction' => YII_PATH . '/captcha/CaptchaAction.php', - 'yii\captcha\CaptchaAsset' => YII_PATH . '/captcha/CaptchaAsset.php', - 'yii\captcha\CaptchaValidator' => YII_PATH . '/captcha/CaptchaValidator.php', - 'yii\data\ActiveDataProvider' => YII_PATH . '/data/ActiveDataProvider.php', - 'yii\data\ArrayDataProvider' => YII_PATH . '/data/ArrayDataProvider.php', - 'yii\data\BaseDataProvider' => YII_PATH . '/data/BaseDataProvider.php', - 'yii\data\DataProviderInterface' => YII_PATH . '/data/DataProviderInterface.php', - 'yii\data\Pagination' => YII_PATH . '/data/Pagination.php', - 'yii\data\Sort' => YII_PATH . '/data/Sort.php', - 'yii\data\SqlDataProvider' => YII_PATH . '/data/SqlDataProvider.php', - 'yii\db\ActiveQuery' => YII_PATH . '/db/ActiveQuery.php', - 'yii\db\ActiveQueryInterface' => YII_PATH . '/db/ActiveQueryInterface.php', - 'yii\db\ActiveQueryTrait' => YII_PATH . '/db/ActiveQueryTrait.php', - 'yii\db\ActiveRecord' => YII_PATH . '/db/ActiveRecord.php', - 'yii\db\ActiveRecordInterface' => YII_PATH . '/db/ActiveRecordInterface.php', - 'yii\db\ActiveRelation' => YII_PATH . '/db/ActiveRelation.php', - 'yii\db\ActiveRelationInterface' => YII_PATH . '/db/ActiveRelationInterface.php', - 'yii\db\ActiveRelationTrait' => YII_PATH . '/db/ActiveRelationTrait.php', - 'yii\db\BaseActiveRecord' => YII_PATH . '/db/BaseActiveRecord.php', - 'yii\db\ColumnSchema' => YII_PATH . '/db/ColumnSchema.php', - 'yii\db\Command' => YII_PATH . '/db/Command.php', - 'yii\db\Connection' => YII_PATH . '/db/Connection.php', - 'yii\db\DataReader' => YII_PATH . '/db/DataReader.php', - 'yii\db\Exception' => YII_PATH . '/db/Exception.php', - 'yii\db\Expression' => YII_PATH . '/db/Expression.php', - 'yii\db\Migration' => YII_PATH . '/db/Migration.php', - 'yii\db\Query' => YII_PATH . '/db/Query.php', - 'yii\db\QueryBuilder' => YII_PATH . '/db/QueryBuilder.php', - 'yii\db\QueryInterface' => YII_PATH . '/db/QueryInterface.php', - 'yii\db\QueryTrait' => YII_PATH . '/db/QueryTrait.php', - 'yii\db\Schema' => YII_PATH . '/db/Schema.php', - 'yii\db\StaleObjectException' => YII_PATH . '/db/StaleObjectException.php', - 'yii\db\TableSchema' => YII_PATH . '/db/TableSchema.php', - 'yii\db\Transaction' => YII_PATH . '/db/Transaction.php', - 'yii\db\cubrid\QueryBuilder' => YII_PATH . '/db/cubrid/QueryBuilder.php', - 'yii\db\cubrid\Schema' => YII_PATH . '/db/cubrid/Schema.php', - 'yii\db\mssql\PDO' => YII_PATH . '/db/mssql/PDO.php', - 'yii\db\mssql\QueryBuilder' => YII_PATH . '/db/mssql/QueryBuilder.php', - 'yii\db\mssql\Schema' => YII_PATH . '/db/mssql/Schema.php', - 'yii\db\mssql\SqlsrvPDO' => YII_PATH . '/db/mssql/SqlsrvPDO.php', - 'yii\db\mssql\TableSchema' => YII_PATH . '/db/mssql/TableSchema.php', - 'yii\db\mysql\QueryBuilder' => YII_PATH . '/db/mysql/QueryBuilder.php', - 'yii\db\mysql\Schema' => YII_PATH . '/db/mysql/Schema.php', - 'yii\db\pgsql\QueryBuilder' => YII_PATH . '/db/pgsql/QueryBuilder.php', - 'yii\db\pgsql\Schema' => YII_PATH . '/db/pgsql/Schema.php', - 'yii\db\sqlite\QueryBuilder' => YII_PATH . '/db/sqlite/QueryBuilder.php', - 'yii\db\sqlite\Schema' => YII_PATH . '/db/sqlite/Schema.php', - 'yii\grid\ActionColumn' => YII_PATH . '/grid/ActionColumn.php', - 'yii\grid\CheckboxColumn' => YII_PATH . '/grid/CheckboxColumn.php', - 'yii\grid\Column' => YII_PATH . '/grid/Column.php', - 'yii\grid\DataColumn' => YII_PATH . '/grid/DataColumn.php', - 'yii\grid\GridView' => YII_PATH . '/grid/GridView.php', - 'yii\grid\GridViewAsset' => YII_PATH . '/grid/GridViewAsset.php', - 'yii\grid\SerialColumn' => YII_PATH . '/grid/SerialColumn.php', - 'yii\helpers\ArrayHelper' => YII_PATH . '/helpers/ArrayHelper.php', - 'yii\helpers\BaseArrayHelper' => YII_PATH . '/helpers/BaseArrayHelper.php', - 'yii\helpers\BaseConsole' => YII_PATH . '/helpers/BaseConsole.php', - 'yii\helpers\BaseFileHelper' => YII_PATH . '/helpers/BaseFileHelper.php', - 'yii\helpers\BaseHtml' => YII_PATH . '/helpers/BaseHtml.php', - 'yii\helpers\BaseHtmlPurifier' => YII_PATH . '/helpers/BaseHtmlPurifier.php', - 'yii\helpers\BaseInflector' => YII_PATH . '/helpers/BaseInflector.php', - 'yii\helpers\BaseJson' => YII_PATH . '/helpers/BaseJson.php', - 'yii\helpers\BaseMarkdown' => YII_PATH . '/helpers/BaseMarkdown.php', - 'yii\helpers\BaseSecurity' => YII_PATH . '/helpers/BaseSecurity.php', - 'yii\helpers\BaseStringHelper' => YII_PATH . '/helpers/BaseStringHelper.php', - 'yii\helpers\BaseVarDumper' => YII_PATH . '/helpers/BaseVarDumper.php', - 'yii\helpers\Console' => YII_PATH . '/helpers/Console.php', - 'yii\helpers\FileHelper' => YII_PATH . '/helpers/FileHelper.php', - 'yii\helpers\Html' => YII_PATH . '/helpers/Html.php', - 'yii\helpers\HtmlPurifier' => YII_PATH . '/helpers/HtmlPurifier.php', - 'yii\helpers\Inflector' => YII_PATH . '/helpers/Inflector.php', - 'yii\helpers\Json' => YII_PATH . '/helpers/Json.php', - 'yii\helpers\Markdown' => YII_PATH . '/helpers/Markdown.php', - 'yii\helpers\Security' => YII_PATH . '/helpers/Security.php', - 'yii\helpers\StringHelper' => YII_PATH . '/helpers/StringHelper.php', - 'yii\helpers\VarDumper' => YII_PATH . '/helpers/VarDumper.php', - 'yii\i18n\DbMessageSource' => YII_PATH . '/i18n/DbMessageSource.php', - 'yii\i18n\Formatter' => YII_PATH . '/i18n/Formatter.php', - 'yii\i18n\GettextFile' => YII_PATH . '/i18n/GettextFile.php', - 'yii\i18n\GettextMessageSource' => YII_PATH . '/i18n/GettextMessageSource.php', - 'yii\i18n\GettextMoFile' => YII_PATH . '/i18n/GettextMoFile.php', - 'yii\i18n\GettextPoFile' => YII_PATH . '/i18n/GettextPoFile.php', - 'yii\i18n\I18N' => YII_PATH . '/i18n/I18N.php', - 'yii\i18n\MessageFormatter' => YII_PATH . '/i18n/MessageFormatter.php', - 'yii\i18n\MessageSource' => YII_PATH . '/i18n/MessageSource.php', - 'yii\i18n\MissingTranslationEvent' => YII_PATH . '/i18n/MissingTranslationEvent.php', - 'yii\i18n\PhpMessageSource' => YII_PATH . '/i18n/PhpMessageSource.php', - 'yii\log\DbTarget' => YII_PATH . '/log/DbTarget.php', - 'yii\log\EmailTarget' => YII_PATH . '/log/EmailTarget.php', - 'yii\log\FileTarget' => YII_PATH . '/log/FileTarget.php', - 'yii\log\Logger' => YII_PATH . '/log/Logger.php', - 'yii\log\Target' => YII_PATH . '/log/Target.php', - 'yii\mail\BaseMailer' => YII_PATH . '/mail/BaseMailer.php', - 'yii\mail\BaseMessage' => YII_PATH . '/mail/BaseMessage.php', - 'yii\mail\MailerInterface' => YII_PATH . '/mail/MailerInterface.php', - 'yii\mail\MessageInterface' => YII_PATH . '/mail/MessageInterface.php', - 'yii\mutex\DbMutex' => YII_PATH . '/mutex/DbMutex.php', - 'yii\mutex\FileMutex' => YII_PATH . '/mutex/FileMutex.php', - 'yii\mutex\Mutex' => YII_PATH . '/mutex/Mutex.php', - 'yii\mutex\MysqlMutex' => YII_PATH . '/mutex/MysqlMutex.php', - 'yii\rbac\Assignment' => YII_PATH . '/rbac/Assignment.php', - 'yii\rbac\DbManager' => YII_PATH . '/rbac/DbManager.php', - 'yii\rbac\Item' => YII_PATH . '/rbac/Item.php', - 'yii\rbac\Manager' => YII_PATH . '/rbac/Manager.php', - 'yii\rbac\PhpManager' => YII_PATH . '/rbac/PhpManager.php', - 'yii\requirements\YiiRequirementChecker' => YII_PATH . '/requirements/YiiRequirementChecker.php', - 'yii\test\DbFixtureManager' => YII_PATH . '/test/DbFixtureManager.php', - 'yii\test\DbTestTrait' => YII_PATH . '/test/DbTestTrait.php', - 'yii\validators\BooleanValidator' => YII_PATH . '/validators/BooleanValidator.php', - 'yii\validators\CompareValidator' => YII_PATH . '/validators/CompareValidator.php', - 'yii\validators\DateValidator' => YII_PATH . '/validators/DateValidator.php', - 'yii\validators\DefaultValueValidator' => YII_PATH . '/validators/DefaultValueValidator.php', - 'yii\validators\EmailValidator' => YII_PATH . '/validators/EmailValidator.php', - 'yii\validators\ExistValidator' => YII_PATH . '/validators/ExistValidator.php', - 'yii\validators\FileValidator' => YII_PATH . '/validators/FileValidator.php', - 'yii\validators\FilterValidator' => YII_PATH . '/validators/FilterValidator.php', - 'yii\validators\ImageValidator' => YII_PATH . '/validators/ImageValidator.php', - 'yii\validators\InlineValidator' => YII_PATH . '/validators/InlineValidator.php', - 'yii\validators\NumberValidator' => YII_PATH . '/validators/NumberValidator.php', - 'yii\validators\PunycodeAsset' => YII_PATH . '/validators/PunycodeAsset.php', - 'yii\validators\RangeValidator' => YII_PATH . '/validators/RangeValidator.php', - 'yii\validators\RegularExpressionValidator' => YII_PATH . '/validators/RegularExpressionValidator.php', - 'yii\validators\RequiredValidator' => YII_PATH . '/validators/RequiredValidator.php', - 'yii\validators\SafeValidator' => YII_PATH . '/validators/SafeValidator.php', - 'yii\validators\StringValidator' => YII_PATH . '/validators/StringValidator.php', - 'yii\validators\UniqueValidator' => YII_PATH . '/validators/UniqueValidator.php', - 'yii\validators\UrlValidator' => YII_PATH . '/validators/UrlValidator.php', - 'yii\validators\ValidationAsset' => YII_PATH . '/validators/ValidationAsset.php', - 'yii\validators\Validator' => YII_PATH . '/validators/Validator.php', - 'yii\web\AccessControl' => YII_PATH . '/web/AccessControl.php', - 'yii\web\AccessDeniedHttpException' => YII_PATH . '/web/AccessDeniedHttpException.php', - 'yii\web\AccessRule' => YII_PATH . '/web/AccessRule.php', - 'yii\web\Application' => YII_PATH . '/web/Application.php', - 'yii\web\AssetBundle' => YII_PATH . '/web/AssetBundle.php', - 'yii\web\AssetConverter' => YII_PATH . '/web/AssetConverter.php', - 'yii\web\AssetConverterInterface' => YII_PATH . '/web/AssetConverterInterface.php', - 'yii\web\AssetManager' => YII_PATH . '/web/AssetManager.php', - 'yii\web\BadRequestHttpException' => YII_PATH . '/web/BadRequestHttpException.php', - 'yii\web\CacheSession' => YII_PATH . '/web/CacheSession.php', - 'yii\web\Controller' => YII_PATH . '/web/Controller.php', - 'yii\web\Cookie' => YII_PATH . '/web/Cookie.php', - 'yii\web\CookieCollection' => YII_PATH . '/web/CookieCollection.php', - 'yii\web\DbSession' => YII_PATH . '/web/DbSession.php', - 'yii\web\ErrorAction' => YII_PATH . '/web/ErrorAction.php', - 'yii\web\HeaderCollection' => YII_PATH . '/web/HeaderCollection.php', - 'yii\web\HttpCache' => YII_PATH . '/web/HttpCache.php', - 'yii\web\HttpException' => YII_PATH . '/web/HttpException.php', - 'yii\web\IdentityInterface' => YII_PATH . '/web/IdentityInterface.php', - 'yii\web\JqueryAsset' => YII_PATH . '/web/JqueryAsset.php', - 'yii\web\JsExpression' => YII_PATH . '/web/JsExpression.php', - 'yii\web\MethodNotAllowedHttpException' => YII_PATH . '/web/MethodNotAllowedHttpException.php', - 'yii\web\NotFoundHttpException' => YII_PATH . '/web/NotFoundHttpException.php', - 'yii\web\PageCache' => YII_PATH . '/web/PageCache.php', - 'yii\web\Request' => YII_PATH . '/web/Request.php', - 'yii\web\Response' => YII_PATH . '/web/Response.php', - 'yii\web\ResponseEvent' => YII_PATH . '/web/ResponseEvent.php', - 'yii\web\ResponseFormatterInterface' => YII_PATH . '/web/ResponseFormatterInterface.php', - 'yii\web\Session' => YII_PATH . '/web/Session.php', - 'yii\web\SessionIterator' => YII_PATH . '/web/SessionIterator.php', - 'yii\web\UploadedFile' => YII_PATH . '/web/UploadedFile.php', - 'yii\web\UrlManager' => YII_PATH . '/web/UrlManager.php', - 'yii\web\UrlRule' => YII_PATH . '/web/UrlRule.php', - 'yii\web\User' => YII_PATH . '/web/User.php', - 'yii\web\UserEvent' => YII_PATH . '/web/UserEvent.php', - 'yii\web\VerbFilter' => YII_PATH . '/web/VerbFilter.php', - 'yii\web\View' => YII_PATH . '/web/View.php', - 'yii\web\XmlResponseFormatter' => YII_PATH . '/web/XmlResponseFormatter.php', - 'yii\web\YiiAsset' => YII_PATH . '/web/YiiAsset.php', - 'yii\widgets\ActiveField' => YII_PATH . '/widgets/ActiveField.php', - 'yii\widgets\ActiveForm' => YII_PATH . '/widgets/ActiveForm.php', - 'yii\widgets\ActiveFormAsset' => YII_PATH . '/widgets/ActiveFormAsset.php', - 'yii\widgets\BaseListView' => YII_PATH . '/widgets/BaseListView.php', - 'yii\widgets\Block' => YII_PATH . '/widgets/Block.php', - 'yii\widgets\Breadcrumbs' => YII_PATH . '/widgets/Breadcrumbs.php', - 'yii\widgets\ContentDecorator' => YII_PATH . '/widgets/ContentDecorator.php', - 'yii\widgets\DetailView' => YII_PATH . '/widgets/DetailView.php', - 'yii\widgets\FragmentCache' => YII_PATH . '/widgets/FragmentCache.php', - 'yii\widgets\InputWidget' => YII_PATH . '/widgets/InputWidget.php', - 'yii\widgets\LinkPager' => YII_PATH . '/widgets/LinkPager.php', - 'yii\widgets\LinkSorter' => YII_PATH . '/widgets/LinkSorter.php', - 'yii\widgets\ListView' => YII_PATH . '/widgets/ListView.php', - 'yii\widgets\MaskedInput' => YII_PATH . '/widgets/MaskedInput.php', - 'yii\widgets\MaskedInputAsset' => YII_PATH . '/widgets/MaskedInputAsset.php', - 'yii\widgets\Menu' => YII_PATH . '/widgets/Menu.php', - 'yii\widgets\Spaceless' => YII_PATH . '/widgets/Spaceless.php', -]; diff --git a/framework/yii/console/Application.php b/framework/yii/console/Application.php deleted file mode 100644 index 6117752..0000000 --- a/framework/yii/console/Application.php +++ /dev/null @@ -1,165 +0,0 @@ - [--param1=value1 --param2 ...] - * ~~~ - * - * where `` refers to a controller route in the form of `ModuleID/ControllerID/ActionID` - * (e.g. `sitemap/create`), and `param1`, `param2` refers to a set of named parameters that - * will be used to initialize the controller action (e.g. `--since=0` specifies a `since` parameter - * whose value is 0 and a corresponding `$since` parameter is passed to the action method). - * - * A `help` command is provided by default, which lists available commands and shows their usage. - * To use this command, simply type: - * - * ~~~ - * yii help - * ~~~ - * - * @property Response $response The response component. This property is read-only. - * - * @author Qiang Xue - * @since 2.0 - */ -class Application extends \yii\base\Application -{ - /** - * @var string the default route of this application. Defaults to 'help', - * meaning the `help` command. - */ - public $defaultRoute = 'help'; - /** - * @var boolean whether to enable the commands provided by the core framework. - * Defaults to true. - */ - public $enableCoreCommands = true; - /** - * @var Controller the currently active controller instance - */ - public $controller; - - /** - * Initialize the application. - */ - public function init() - { - parent::init(); - if ($this->enableCoreCommands) { - foreach ($this->coreCommands() as $id => $command) { - if (!isset($this->controllerMap[$id])) { - $this->controllerMap[$id] = $command; - } - } - } - // ensure we have the 'help' command so that we can list the available commands - if (!isset($this->controllerMap['help'])) { - $this->controllerMap['help'] = 'yii\console\controllers\HelpController'; - } - } - - /** - * Handles the specified request. - * @param Request $request the request to be handled - * @return Response the resulting response - */ - public function handleRequest($request) - { - list ($route, $params) = $request->resolve(); - $this->requestedRoute = $route; - $result = $this->runAction($route, $params); - if ($result instanceof Response) { - return $result; - } else { - $response = $this->getResponse(); - $response->exitStatus = (int)$result; - return $response; - } - } - - /** - * Returns the response component. - * @return Response the response component - */ - public function getResponse() - { - return $this->getComponent('response'); - } - - /** - * Runs a controller action specified by a route. - * This method parses the specified route and creates the corresponding child module(s), controller and action - * instances. It then calls [[Controller::runAction()]] to run the action with the given parameters. - * If the route is empty, the method will use [[defaultRoute]]. - * @param string $route the route that specifies the action. - * @param array $params the parameters to be passed to the action - * @return integer the status code returned by the action execution. 0 means normal, and other values mean abnormal. - * @throws Exception if the route is invalid - */ - public function runAction($route, $params = []) - { - try { - return parent::runAction($route, $params); - } catch (InvalidRouteException $e) { - throw new Exception(Yii::t('yii', 'Unknown command "{command}".', ['command' => $route]), 0, $e); - } - } - - /** - * Returns the configuration of the built-in commands. - * @return array the configuration of the built-in commands. - */ - public function coreCommands() - { - return [ - 'message' => 'yii\console\controllers\MessageController', - 'help' => 'yii\console\controllers\HelpController', - 'migrate' => 'yii\console\controllers\MigrateController', - 'cache' => 'yii\console\controllers\CacheController', - 'asset' => 'yii\console\controllers\AssetController', - 'fixture' => 'yii\console\controllers\FixtureController', - ]; - } - - /** - * Registers the core application components. - * @see setComponents - */ - public function registerCoreComponents() - { - parent::registerCoreComponents(); - $this->setComponents([ - 'request' => ['class' => 'yii\console\Request'], - 'response' => ['class' => 'yii\console\Response'], - ]); - } -} diff --git a/framework/yii/console/Controller.php b/framework/yii/console/Controller.php deleted file mode 100644 index 68db86c..0000000 --- a/framework/yii/console/Controller.php +++ /dev/null @@ -1,276 +0,0 @@ - [--param1=value1 --param2 ...] - * ~~~ - * - * @author Qiang Xue - * @since 2.0 - */ -class Controller extends \yii\base\Controller -{ - /** - * @var boolean whether to run the command interactively. - */ - public $interactive = true; - - /** - * @var boolean whether to enable ANSI color in the output. - * If not set, ANSI color will only be enabled for terminals that support it. - */ - public $color; - - /** - * Returns a value indicating whether ANSI color is enabled. - * - * ANSI color is enabled only if [[color]] is set true or is not set - * and the terminal supports ANSI color. - * - * @param resource $stream the stream to check. - * @return boolean Whether to enable ANSI style in output. - */ - public function isColorEnabled($stream = STDOUT) - { - return $this->color === null ? Console::streamSupportsAnsiColors($stream) : $this->color; - } - - /** - * Runs an action with the specified action ID and parameters. - * If the action ID is empty, the method will use [[defaultAction]]. - * @param string $id the ID of the action to be executed. - * @param array $params the parameters (name-value pairs) to be passed to the action. - * @return integer the status of the action execution. 0 means normal, other values mean abnormal. - * @throws InvalidRouteException if the requested action ID cannot be resolved into an action successfully. - * @see createAction - */ - public function runAction($id, $params = []) - { - if (!empty($params)) { - $options = $this->globalOptions(); - foreach ($params as $name => $value) { - if (in_array($name, $options, true)) { - $this->$name = $value; - unset($params[$name]); - } - } - } - return parent::runAction($id, $params); - } - - /** - * Binds the parameters to the action. - * This method is invoked by [[Action]] when it begins to run with the given parameters. - * This method will first bind the parameters with the [[globalOptions()|global options]] - * available to the action. It then validates the given arguments. - * @param Action $action the action to be bound with parameters - * @param array $params the parameters to be bound to the action - * @return array the valid parameters that the action can run with. - * @throws Exception if there are unknown options or missing arguments - */ - public function bindActionParams($action, $params) - { - $args = []; - if (!empty($params)) { - $options = $this->globalOptions(); - foreach ($params as $name => $value) { - if (in_array($name, $options, true)) { - $this->$name = $value; - } elseif (is_int($name)) { - $args[] = $value; - } else { - throw new Exception(Yii::t('yii', 'Unknown option: --{name}', ['name' => $name])); - } - } - } - - if ($action instanceof InlineAction) { - $method = new \ReflectionMethod($this, $action->actionMethod); - } else { - $method = new \ReflectionMethod($action, 'run'); - } - - $missing = []; - foreach ($method->getParameters() as $i => $param) { - if ($param->isArray() && isset($args[$i])) { - $args[$i] = preg_split('/\s*,\s*/', $args[$i]); - } - if (!isset($args[$i])) { - if ($param->isDefaultValueAvailable()) { - $args[$i] = $param->getDefaultValue(); - } else { - $missing[] = $param->getName(); - } - } - } - - if (!empty($missing)) { - throw new Exception(Yii::t('yii', 'Missing required arguments: {params}', ['params' => implode(', ', $missing)])); - } - - return $args; - } - - /** - * Formats a string with ANSI codes - * - * You may pass additional parameters using the constants defined in [[yii\helpers\Console]]. - * - * Example: - * - * ~~~ - * echo $this->ansiFormat('This will be red and underlined.', Console::FG_RED, Console::UNDERLINE); - * ~~~ - * - * @param string $string the string to be formatted - * @return string - */ - public function ansiFormat($string) - { - if ($this->isColorEnabled()) { - $args = func_get_args(); - array_shift($args); - $string = Console::ansiFormat($string, $args); - } - return $string; - } - - /** - * Prints a string to STDOUT - * - * You may optionally format the string with ANSI codes by - * passing additional parameters using the constants defined in [[yii\helpers\Console]]. - * - * Example: - * - * ~~~ - * $this->stdout('This will be red and underlined.', Console::FG_RED, Console::UNDERLINE); - * ~~~ - * - * @param string $string the string to print - * @return int|boolean Number of bytes printed or false on error - */ - public function stdout($string) - { - if ($this->isColorEnabled()) { - $args = func_get_args(); - array_shift($args); - $string = Console::ansiFormat($string, $args); - } - return Console::stdout($string); - } - - /** - * Prints a string to STDERR - * - * You may optionally format the string with ANSI codes by - * passing additional parameters using the constants defined in [[yii\helpers\Console]]. - * - * Example: - * - * ~~~ - * $this->stderr('This will be red and underlined.', Console::FG_RED, Console::UNDERLINE); - * ~~~ - * - * @param string $string the string to print - * @return int|boolean Number of bytes printed or false on error - */ - public function stderr($string) - { - if ($this->isColorEnabled(STDERR)) { - $args = func_get_args(); - array_shift($args); - $string = Console::ansiFormat($string, $args); - } - return fwrite(STDERR, $string); - } - - /** - * Prompts the user for input and validates it - * - * @param string $text prompt string - * @param array $options the options to validate the input: - * - * - required: whether it is required or not - * - default: default value if no input is inserted by the user - * - pattern: regular expression pattern to validate user input - * - validator: a callable function to validate input. The function must accept two parameters: - * - $input: the user input to validate - * - $error: the error value passed by reference if validation failed. - * @return string the user input - */ - public function prompt($text, $options = []) - { - if ($this->interactive) { - return Console::prompt($text, $options); - } else { - return isset($options['default']) ? $options['default'] : ''; - } - } - - /** - * Asks user to confirm by typing y or n. - * - * @param string $message to echo out before waiting for user input - * @param boolean $default this value is returned if no selection is made. - * @return boolean whether user confirmed. - * Will return true if [[interactive]] is false. - */ - public function confirm($message, $default = false) - { - if ($this->interactive) { - return Console::confirm($message, $default); - } else { - return true; - } - } - - /** - * Gives the user an option to choose from. Giving '?' as an input will show - * a list of options to choose from and their explanations. - * - * @param string $prompt the prompt message - * @param array $options Key-value array of options to choose from - * - * @return string An option character the user chose - */ - public function select($prompt, $options = []) - { - return Console::select($prompt, $options); - } - - /** - * Returns the names of the global options for this command. - * A global option requires the existence of a public member variable whose - * name is the option name. - * Child classes may override this method to specify possible global options. - * - * Note that the values setting via global options are not available - * until [[beforeAction()]] is being called. - * - * @return array the names of the global options for this command. - */ - public function globalOptions() - { - return ['color', 'interactive']; - } -} diff --git a/framework/yii/console/Exception.php b/framework/yii/console/Exception.php deleted file mode 100644 index 5148361..0000000 --- a/framework/yii/console/Exception.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @since 2.0 - */ -class Exception extends UserException -{ - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return 'Error'; - } -} diff --git a/framework/yii/console/Request.php b/framework/yii/console/Request.php deleted file mode 100644 index d4d3af0..0000000 --- a/framework/yii/console/Request.php +++ /dev/null @@ -1,77 +0,0 @@ - - * @since 2.0 - */ -class Request extends \yii\base\Request -{ - private $_params; - - /** - * Returns the command line arguments. - * @return array the command line arguments. It does not include the entry script name. - */ - public function getParams() - { - if (!isset($this->_params)) { - if (isset($_SERVER['argv'])) { - $this->_params = $_SERVER['argv']; - array_shift($this->_params); - } else { - $this->_params = []; - } - } - return $this->_params; - } - - /** - * Sets the command line arguments. - * @param array $params the command line arguments - */ - public function setParams($params) - { - $this->_params = $params; - } - - /** - * Resolves the current request into a route and the associated parameters. - * @return array the first element is the route, and the second is the associated parameters. - */ - public function resolve() - { - $rawParams = $this->getParams(); - if (isset($rawParams[0])) { - $route = $rawParams[0]; - array_shift($rawParams); - } else { - $route = ''; - } - - $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 [$route, $params]; - } -} diff --git a/framework/yii/console/Response.php b/framework/yii/console/Response.php deleted file mode 100644 index eff85c6..0000000 --- a/framework/yii/console/Response.php +++ /dev/null @@ -1,18 +0,0 @@ - - * @since 2.0 - */ -class Response extends \yii\base\Response -{ -} diff --git a/framework/yii/console/controllers/AssetController.php b/framework/yii/console/controllers/AssetController.php deleted file mode 100644 index cea9fed..0000000 --- a/framework/yii/console/controllers/AssetController.php +++ /dev/null @@ -1,611 +0,0 @@ - - * @since 2.0 - */ -class AssetController extends Controller -{ - /** - * @var string controller default action ID. - */ - public $defaultAction = 'compress'; - /** - * @var array list of asset bundles to be compressed. - */ - public $bundles = []; - /** - * @var array list of asset bundles, which represents output compressed files. - * You can specify the name of the output compressed file using 'css' and 'js' keys: - * For example: - * - * ~~~ - * 'app\config\AllAsset' => [ - * 'js' => 'js/all-{ts}.js', - * 'css' => 'css/all-{ts}.css', - * 'depends' => [ ... ], - * ] - * ~~~ - * - * File names can contain placeholder "{ts}", which will be filled by current timestamp, while - * file creation. - */ - public $targets = []; - /** - * @var string|callback JavaScript file compressor. - * If a string, it is treated as shell command template, which should contain - * placeholders {from} - source file name - and {to} - output file name. - * Otherwise, it is treated as PHP callback, which should perform the compression. - * - * Default value relies on usage of "Closure Compiler" - * @see https://developers.google.com/closure/compiler/ - */ - public $jsCompressor = 'java -jar compiler.jar --js {from} --js_output_file {to}'; - /** - * @var string|callback CSS file compressor. - * If a string, it is treated as shell command template, which should contain - * placeholders {from} - source file name - and {to} - output file name. - * Otherwise, it is treated as PHP callback, which should perform the compression. - * - * Default value relies on usage of "YUI Compressor" - * @see https://github.com/yui/yuicompressor/ - */ - public $cssCompressor = 'java -jar yuicompressor.jar {from} -o {to}'; - - /** - * @var array|\yii\web\AssetManager [[yii\web\AssetManager]] instance or its array configuration, which will be used - * for assets processing. - */ - private $_assetManager = []; - - /** - * Returns the asset manager instance. - * @throws \yii\console\Exception on invalid configuration. - * @return \yii\web\AssetManager asset manager instance. - */ - public function getAssetManager() - { - if (!is_object($this->_assetManager)) { - $options = $this->_assetManager; - if (!isset($options['class'])) { - $options['class'] = 'yii\\web\\AssetManager'; - } - if (!isset($options['basePath'])) { - throw new Exception("Please specify 'basePath' for the 'assetManager' option."); - } - if (!isset($options['baseUrl'])) { - throw new Exception("Please specify 'baseUrl' for the 'assetManager' option."); - } - $this->_assetManager = Yii::createObject($options); - } - return $this->_assetManager; - } - - /** - * Sets asset manager instance or configuration. - * @param \yii\web\AssetManager|array $assetManager asset manager instance or its array configuration. - * @throws \yii\console\Exception on invalid argument type. - */ - public function setAssetManager($assetManager) - { - if (is_scalar($assetManager)) { - throw new Exception('"' . get_class($this) . '::assetManager" should be either object or array - "' . gettype($assetManager) . '" given.'); - } - $this->_assetManager = $assetManager; - } - - /** - * Combines and compresses the asset files according to the given configuration. - * During the process new asset bundle configuration file will be created. - * You should replace your original asset bundle configuration with this file in order to use compressed files. - * @param string $configFile configuration file name. - * @param string $bundleFile output asset bundles configuration file name. - */ - public function actionCompress($configFile, $bundleFile) - { - $this->loadConfiguration($configFile); - $bundles = $this->loadBundles($this->bundles); - $targets = $this->loadTargets($this->targets, $bundles); - $timestamp = time(); - foreach ($targets as $name => $target) { - echo "Creating output bundle '{$name}':\n"; - if (!empty($target->js)) { - $this->buildTarget($target, 'js', $bundles, $timestamp); - } - if (!empty($target->css)) { - $this->buildTarget($target, 'css', $bundles, $timestamp); - } - echo "\n"; - } - - $targets = $this->adjustDependency($targets, $bundles); - $this->saveTargets($targets, $bundleFile); - } - - /** - * Applies configuration from the given file to self instance. - * @param string $configFile configuration file name. - * @throws \yii\console\Exception on failure. - */ - protected function loadConfiguration($configFile) - { - echo "Loading configuration from '{$configFile}'...\n"; - foreach (require($configFile) as $name => $value) { - if (property_exists($this, $name) || $this->canSetProperty($name)) { - $this->$name = $value; - } else { - throw new Exception("Unknown configuration option: $name"); - } - } - - $this->getAssetManager(); // check if asset manager configuration is correct - } - - /** - * Creates full list of source asset bundles. - * @param string[] $bundles list of asset bundle names - * @return \yii\web\AssetBundle[] list of source asset bundles. - */ - protected function loadBundles($bundles) - { - echo "Collecting source bundles information...\n"; - - $am = $this->getAssetManager(); - $result = []; - foreach ($bundles as $name) { - $result[$name] = $am->getBundle($name); - } - foreach ($result as $bundle) { - $this->loadDependency($bundle, $result); - } - - return $result; - } - - /** - * Loads asset bundle dependencies recursively. - * @param \yii\web\AssetBundle $bundle bundle instance - * @param array $result already loaded bundles list. - * @throws Exception on failure. - */ - protected function loadDependency($bundle, &$result) - { - $am = $this->getAssetManager(); - foreach ($bundle->depends as $name) { - if (!isset($result[$name])) { - $dependencyBundle = $am->getBundle($name); - $result[$name] = false; - $this->loadDependency($dependencyBundle, $result); - $result[$name] = $dependencyBundle; - } elseif ($result[$name] === false) { - throw new Exception("A circular dependency is detected for bundle '$name'."); - } - } - } - - /** - * Creates full list of output asset bundles. - * @param array $targets output asset bundles configuration. - * @param \yii\web\AssetBundle[] $bundles list of source asset bundles. - * @return \yii\web\AssetBundle[] list of output asset bundles. - * @throws Exception on failure. - */ - protected function loadTargets($targets, $bundles) - { - // build the dependency order of bundles - $registered = []; - foreach ($bundles as $name => $bundle) { - $this->registerBundle($bundles, $name, $registered); - } - $bundleOrders = array_combine(array_keys($registered), range(0, count($bundles) - 1)); - - // fill up the target which has empty 'depends'. - $referenced = []; - foreach ($targets as $name => $target) { - if (empty($target['depends'])) { - if (!isset($all)) { - $all = $name; - } else { - throw new Exception("Only one target can have empty 'depends' option. Found two now: $all, $name"); - } - } else { - foreach ($target['depends'] as $bundle) { - if (!isset($referenced[$bundle])) { - $referenced[$bundle] = $name; - } else { - throw new Exception("Target '{$referenced[$bundle]}' and '$name' cannot contain the bundle '$bundle' at the same time."); - } - } - } - } - if (isset($all)) { - $targets[$all]['depends'] = array_diff(array_keys($registered), array_keys($referenced)); - } - - // adjust the 'depends' order for each target according to the dependency order of bundles - // create an AssetBundle object for each target - foreach ($targets as $name => $target) { - if (!isset($target['basePath'])) { - throw new Exception("Please specify 'basePath' for the '$name' target."); - } - if (!isset($target['baseUrl'])) { - throw new Exception("Please specify 'baseUrl' for the '$name' target."); - } - usort($target['depends'], function ($a, $b) use ($bundleOrders) { - if ($bundleOrders[$a] == $bundleOrders[$b]) { - return 0; - } else { - return $bundleOrders[$a] > $bundleOrders[$b] ? 1 : -1; - } - }); - $target['class'] = $name; - $targets[$name] = Yii::createObject($target); - } - return $targets; - } - - /** - * Builds output asset bundle. - * @param \yii\web\AssetBundle $target output asset bundle - * @param string $type either 'js' or 'css'. - * @param \yii\web\AssetBundle[] $bundles source asset bundles. - * @param integer $timestamp current timestamp. - * @throws Exception on failure. - */ - protected function buildTarget($target, $type, $bundles, $timestamp) - { - $outputFile = strtr($target->$type, [ - '{ts}' => $timestamp, - ]); - $inputFiles = []; - - foreach ($target->depends as $name) { - if (isset($bundles[$name])) { - foreach ($bundles[$name]->$type as $file) { - $inputFiles[] = $bundles[$name]->basePath . '/' . $file; - } - } else { - throw new Exception("Unknown bundle: '{$name}'"); - } - } - if ($type === 'js') { - $this->compressJsFiles($inputFiles, $target->basePath . '/' . $outputFile); - } else { - $this->compressCssFiles($inputFiles, $target->basePath . '/' . $outputFile); - } - $target->$type = [$outputFile]; - } - - /** - * Adjust dependencies between asset bundles in the way source bundles begin to depend on output ones. - * @param \yii\web\AssetBundle[] $targets output asset bundles. - * @param \yii\web\AssetBundle[] $bundles source asset bundles. - * @return \yii\web\AssetBundle[] output asset bundles. - */ - protected function adjustDependency($targets, $bundles) - { - echo "Creating new bundle configuration...\n"; - - $map = []; - foreach ($targets as $name => $target) { - foreach ($target->depends as $bundle) { - $map[$bundle] = $name; - } - } - - foreach ($targets as $name => $target) { - $depends = []; - foreach ($target->depends as $bn) { - foreach ($bundles[$bn]->depends as $bundle) { - $depends[$map[$bundle]] = true; - } - } - unset($depends[$name]); - $target->depends = array_keys($depends); - } - - // detect possible circular dependencies - foreach ($targets as $name => $target) { - $registered = []; - $this->registerBundle($targets, $name, $registered); - } - - foreach ($map as $bundle => $target) { - $targets[$bundle] = Yii::createObject([ - 'class' => 'yii\\web\\AssetBundle', - 'depends' => [$target], - ]); - } - return $targets; - } - - /** - * Registers asset bundles including their dependencies. - * @param \yii\web\AssetBundle[] $bundles asset bundles list. - * @param string $name bundle name. - * @param array $registered stores already registered names. - * @throws Exception if circular dependency is detected. - */ - protected function registerBundle($bundles, $name, &$registered) - { - if (!isset($registered[$name])) { - $registered[$name] = false; - $bundle = $bundles[$name]; - foreach ($bundle->depends as $depend) { - $this->registerBundle($bundles, $depend, $registered); - } - unset($registered[$name]); - $registered[$name] = true; - } elseif ($registered[$name] === false) { - throw new Exception("A circular dependency is detected for target '$name'."); - } - } - - /** - * Saves new asset bundles configuration. - * @param \yii\web\AssetBundle[] $targets list of asset bundles to be saved. - * @param string $bundleFile output file name. - * @throws \yii\console\Exception on failure. - */ - protected function saveTargets($targets, $bundleFile) - { - $array = []; - foreach ($targets as $name => $target) { - foreach (['js', 'css', 'depends', 'basePath', 'baseUrl'] as $prop) { - if (!empty($target->$prop)) { - $array[$name][$prop] = $target->$prop; - } - } - } - $array = var_export($array, true); - $version = date('Y-m-d H:i:s', time()); - $bundleFileContent = <<id}" command. - * DO NOT MODIFY THIS FILE DIRECTLY. - * @version {$version} - */ -return {$array}; -EOD; - if (!file_put_contents($bundleFile, $bundleFileContent)) { - throw new Exception("Unable to write output bundle configuration at '{$bundleFile}'."); - } - echo "Output bundle configuration created at '{$bundleFile}'.\n"; - } - - /** - * Compresses given JavaScript files and combines them into the single one. - * @param array $inputFiles list of source file names. - * @param string $outputFile output file name. - * @throws \yii\console\Exception on failure - */ - protected function compressJsFiles($inputFiles, $outputFile) - { - if (empty($inputFiles)) { - return; - } - echo " Compressing JavaScript files...\n"; - if (is_string($this->jsCompressor)) { - $tmpFile = $outputFile . '.tmp'; - $this->combineJsFiles($inputFiles, $tmpFile); - echo shell_exec(strtr($this->jsCompressor, [ - '{from}' => escapeshellarg($tmpFile), - '{to}' => escapeshellarg($outputFile), - ])); - @unlink($tmpFile); - } else { - call_user_func($this->jsCompressor, $this, $inputFiles, $outputFile); - } - if (!file_exists($outputFile)) { - throw new Exception("Unable to compress JavaScript files into '{$outputFile}'."); - } - echo " JavaScript files compressed into '{$outputFile}'.\n"; - } - - /** - * Compresses given CSS files and combines them into the single one. - * @param array $inputFiles list of source file names. - * @param string $outputFile output file name. - * @throws \yii\console\Exception on failure - */ - protected function compressCssFiles($inputFiles, $outputFile) - { - if (empty($inputFiles)) { - return; - } - echo " Compressing CSS files...\n"; - if (is_string($this->cssCompressor)) { - $tmpFile = $outputFile . '.tmp'; - $this->combineCssFiles($inputFiles, $tmpFile); - echo shell_exec(strtr($this->cssCompressor, [ - '{from}' => escapeshellarg($tmpFile), - '{to}' => escapeshellarg($outputFile), - ])); - @unlink($tmpFile); - } else { - call_user_func($this->cssCompressor, $this, $inputFiles, $outputFile); - } - if (!file_exists($outputFile)) { - throw new Exception("Unable to compress CSS files into '{$outputFile}'."); - } - echo " CSS files compressed into '{$outputFile}'.\n"; - } - - /** - * Combines JavaScript files into a single one. - * @param array $inputFiles source file names. - * @param string $outputFile output file name. - * @throws \yii\console\Exception on failure. - */ - public function combineJsFiles($inputFiles, $outputFile) - { - $content = ''; - foreach ($inputFiles as $file) { - $content .= "/*** BEGIN FILE: $file ***/\n" - . file_get_contents($file) - . "/*** END FILE: $file ***/\n"; - } - if (!file_put_contents($outputFile, $content)) { - throw new Exception("Unable to write output JavaScript file '{$outputFile}'."); - } - } - - /** - * Combines CSS files into a single one. - * @param array $inputFiles source file names. - * @param string $outputFile output file name. - * @throws \yii\console\Exception on failure. - */ - public function combineCssFiles($inputFiles, $outputFile) - { - $content = ''; - foreach ($inputFiles as $file) { - $content .= "/*** BEGIN FILE: $file ***/\n" - . $this->adjustCssUrl(file_get_contents($file), dirname($file), dirname($outputFile)) - . "/*** END FILE: $file ***/\n"; - } - if (!file_put_contents($outputFile, $content)) { - throw new Exception("Unable to write output CSS file '{$outputFile}'."); - } - } - - /** - * Adjusts CSS content allowing URL references pointing to the original resources. - * @param string $cssContent source CSS content. - * @param string $inputFilePath input CSS file name. - * @param string $outputFilePath output CSS file name. - * @return string adjusted CSS content. - */ - protected function adjustCssUrl($cssContent, $inputFilePath, $outputFilePath) - { - $sharedPathParts = []; - $inputFilePathParts = explode('/', $inputFilePath); - $inputFilePathPartsCount = count($inputFilePathParts); - $outputFilePathParts = explode('/', $outputFilePath); - $outputFilePathPartsCount = count($outputFilePathParts); - for ($i =0; $i < $inputFilePathPartsCount && $i < $outputFilePathPartsCount; $i++) { - if ($inputFilePathParts[$i] == $outputFilePathParts[$i]) { - $sharedPathParts[] = $inputFilePathParts[$i]; - } else { - break; - } - } - $sharedPath = implode('/', $sharedPathParts); - - $inputFileRelativePath = trim(str_replace($sharedPath, '', $inputFilePath), '/'); - $outputFileRelativePath = trim(str_replace($sharedPath, '', $outputFilePath), '/'); - $inputFileRelativePathParts = explode('/', $inputFileRelativePath); - $outputFileRelativePathParts = explode('/', $outputFileRelativePath); - - $callback = function ($matches) use ($inputFileRelativePathParts, $outputFileRelativePathParts) { - $fullMatch = $matches[0]; - $inputUrl = $matches[1]; - - if (preg_match('/https?:\/\//is', $inputUrl)) { - return $fullMatch; - } - - $outputUrlParts = array_fill(0, count($outputFileRelativePathParts), '..'); - $outputUrlParts = array_merge($outputUrlParts, $inputFileRelativePathParts); - - if (strpos($inputUrl, '/') !== false) { - $inputUrlParts = explode('/', $inputUrl); - foreach ($inputUrlParts as $key => $inputUrlPart) { - if ($inputUrlPart == '..') { - array_pop($outputUrlParts); - unset($inputUrlParts[$key]); - } - } - $outputUrlParts[] = implode('/', $inputUrlParts); - } else { - $outputUrlParts[] = $inputUrl; - } - $outputUrl = implode('/', $outputUrlParts); - - return str_replace($inputUrl, $outputUrl, $fullMatch); - }; - - $cssContent = preg_replace_callback('/url\(["\']?([^"]*)["\']?\)/is', $callback, $cssContent); - - return $cssContent; - } - - /** - * Creates template of configuration file for [[actionCompress]]. - * @param string $configFile output file name. - * @throws \yii\console\Exception on failure. - */ - public function actionTemplate($configFile) - { - $template = << [ - // 'yii\web\YiiAsset', - // 'yii\web\JqueryAsset', - ], - // Asset bundle for compression output: - 'targets' => [ - 'app\config\AllAsset' => [ - 'basePath' => 'path/to/web', - 'baseUrl' => '', - 'js' => 'js/all-{ts}.js', - 'css' => 'css/all-{ts}.css', - ], - ], - // Asset manager configuration: - 'assetManager' => [ - 'basePath' => __DIR__, - 'baseUrl' => '', - ], -]; -EOD; - if (file_exists($configFile)) { - if (!$this->confirm("File '{$configFile}' already exists. Do you wish to overwrite it?")) { - return; - } - } - if (!file_put_contents($configFile, $template)) { - throw new Exception("Unable to write template file '{$configFile}'."); - } else { - echo "Configuration file template created at '{$configFile}'.\n\n"; - } - } -} diff --git a/framework/yii/console/controllers/CacheController.php b/framework/yii/console/controllers/CacheController.php deleted file mode 100644 index 43932d1..0000000 --- a/framework/yii/console/controllers/CacheController.php +++ /dev/null @@ -1,67 +0,0 @@ - - * @since 2.0 - */ -class CacheController extends Controller -{ - /** - * Lists the caches that can be flushed. - */ - public function actionIndex() - { - $caches = []; - $components = Yii::$app->getComponents(); - foreach ($components as $name => $component) { - if ($component instanceof Cache) { - $caches[$name] = get_class($component); - } elseif (is_array($component) && isset($component['class']) && strpos($component['class'], 'Cache') !== false) { - $caches[$name] = $component['class']; - } - } - if (!empty($caches)) { - echo "The following caches can be flushed:\n\n"; - foreach ($caches as $name => $class) { - echo " * $name: $class\n"; - } - } else { - echo "No cache is used.\n"; - } - } - - /** - * Flushes cache. - * @param string $component Name of the cache application component to use. - * - * @throws \yii\console\Exception - */ - public function actionFlush($component = 'cache') - { - /** @var Cache $cache */ - $cache = Yii::$app->getComponent($component); - if (!$cache || !$cache instanceof Cache) { - throw new Exception('Application component "'.$component.'" is not defined or not a cache.'); - } - - if (!$cache->flush()) { - throw new Exception('Unable to flush cache.'); - } - - echo "\nDone.\n"; - } -} diff --git a/framework/yii/console/controllers/FixtureController.php b/framework/yii/console/controllers/FixtureController.php deleted file mode 100644 index 0b400e8..0000000 --- a/framework/yii/console/controllers/FixtureController.php +++ /dev/null @@ -1,321 +0,0 @@ - [ - * 'class' => 'yii\db\Connection', - * 'dsn' => 'mysql:host=localhost;dbname={your_database}', - * 'username' => '{your_db_user}', - * 'password' => '', - * 'charset' => 'utf8', - * ], - * 'fixture' => [ - * 'class' => 'yii\test\DbFixtureManager', - * ], - * ~~~ - * - * ~~~ - * #load fixtures under $fixturePath to the "users" table - * yii fixture/apply users - * - * #also a short version of this command (generate action is default) - * yii fixture users - * - * #load fixtures under $fixturePath to the "users" table to the different connection - * yii fixture/apply users --db=someOtherDbConneciton - * - * #load fixtures under different $fixturePath to the "users" table. - * yii fixture/apply users --fixturePath=@app/some/other/path/to/fixtures - * ~~~ - * - * @author Mark Jebri - * @since 2.0 - */ -class FixtureController extends Controller -{ - use DbTestTrait; - - /** - * type of fixture apply to database - */ - const APPLY_ALL = 'all'; - - /** - * @var string controller default action ID. - */ - public $defaultAction = 'apply'; - /** - * Alias to the path, where all fixtures are stored. - * @var string - */ - public $fixturePath = '@tests/unit/fixtures'; - /** - * Id of the database connection component of the application. - * @var string - */ - public $db = 'db'; - - - /** - * Returns the names of the global options for this command. - * @return array the names of the global options for this command. - */ - public function globalOptions() - { - return array_merge(parent::globalOptions(), [ - 'db', 'fixturePath' - ]); - } - - /** - * This method is invoked right before an action is to be executed (after all possible filters.) - * It checks that fixtures path and database connection are available. - * @param \yii\base\Action $action - * @return boolean - */ - public function beforeAction($action) - { - if (parent::beforeAction($action)) { - $this->checkRequirements(); - return true; - } else { - return false; - } - } - - /** - * Apply given fixture to the table. You can load several fixtures specifying - * their names separated with commas, like: tbl_user,tbl_profile. Be sure there is no - * whitespace between tables names. - * @param array $fixtures - * @throws \yii\console\Exception - */ - public function actionApply(array $fixtures) - { - if ($this->getFixtureManager() === null) { - throw new Exception('Fixture manager is not configured properly. Please refer to official documentation for this purposes.'); - } - - $foundFixtures = $this->findFixtures($fixtures); - - if (!$this->needToApplyAll($fixtures[0])) { - $notFoundFixtures = array_diff($fixtures, $foundFixtures); - - if ($notFoundFixtures) { - $this->notifyNotFound($notFoundFixtures); - } - } - - if (!$foundFixtures) { - throw new Exception("No files were found by name: \"" . implode(', ', $fixtures) . "\".\n" - . "Check that fixtures with these name exists, under fixtures path: \n\"" . Yii::getAlias($this->fixturePath) . "\"." - ); - } - - if (!$this->confirmApply($foundFixtures)) { - return; - } - - $this->getFixtureManager()->basePath = $this->fixturePath; - $this->getFixtureManager()->db = $this->db; - - $transaction = Yii::$app->db->beginTransaction(); - - try { - $this->loadFixtures($foundFixtures); - $transaction->commit(); - - } catch (\Exception $e) { - $transaction->rollback(); - $this->stdout("Exception occured, transaction rollback. Tables will be in same state.\n", Console::BG_RED); - throw $e; - } - $this->notifySuccess($foundFixtures); - } - - /** - * Truncate given table and clear all fixtures from it. You can clear several tables specifying - * their names separated with commas, like: tbl_user,tbl_profile. Be sure there is no - * whitespace between tables names. - * @param array|string $tables - */ - public function actionClear(array $tables) - { - if ($this->needToApplyAll($tables[0])) { - $tables = $this->getDbConnection()->schema->getTableNames(); - } - - if (!$this->confirmClear($tables)) { - return; - } - - $transaction = Yii::$app->db->beginTransaction(); - - try { - $this->getDbConnection()->createCommand()->checkIntegrity(false)->execute(); - - foreach($tables as $table) { - $this->getDbConnection()->createCommand()->truncateTable($table)->execute(); - $this->getDbConnection()->createCommand()->resetSequence($table)->execute(); - $this->stdout(" Table \"{$table}\" was successfully cleared. \n", Console::FG_GREEN); - } - - $this->getDbConnection()->createCommand()->checkIntegrity(true)->execute(); - $transaction->commit(); - - } catch (\Exception $e) { - $transaction->rollback(); - $this->stdout("Exception occured, transaction rollback. Tables will be in same state.\n", Console::BG_RED); - throw $e; - } - } - - /** - * Checks if the database and fixtures path are available. - * @throws Exception - */ - public function checkRequirements() - { - $path = Yii::getAlias($this->fixturePath, false); - - if (!is_dir($path) || !is_writable($path)) { - throw new Exception("The fixtures path \"{$this->fixturePath}\" not exist or is not writable."); - } - - } - - /** - * Returns database connection component - * @return \yii\db\Connection - * @throws Exception if [[db]] is invalid. - */ - public function getDbConnection() - { - $db = Yii::$app->getComponent($this->db); - - if ($db === null) { - throw new Exception("There is no database connection component with id \"{$this->db}\"."); - } - - return $db; - } - - /** - * Notifies user that fixtures were successfully loaded. - * @param array $fixtures - */ - private function notifySuccess($fixtures) - { - $this->stdout("Fixtures were successfully loaded from path:\n", Console::FG_YELLOW); - $this->stdout(Yii::getAlias($this->fixturePath) . "\n\n", Console::FG_GREEN); - $this->outputList($fixtures); - } - - /** - * Notifies user that fixtures were not found under fixtures path. - * @param array $fixtures - */ - private function notifyNotFound($fixtures) - { - $this->stdout("Some fixtures were not found under path:\n", Console::BG_RED); - $this->stdout(Yii::getAlias($this->fixturePath) . "\n\n", Console::FG_GREEN); - $this->outputList($fixtures); - $this->stdout("\n"); - } - - /** - * Prompts user with confirmation if fixtures should be loaded. - * @param array $fixtures - * @return boolean - */ - private function confirmApply($fixtures) - { - $this->stdout("Fixtures will be loaded from path: \n", Console::FG_YELLOW); - $this->stdout(Yii::getAlias($this->fixturePath) . "\n\n", Console::FG_GREEN); - $this->outputList($fixtures); - return $this->confirm('Load to database above fixtures?'); - } - - /** - * Prompts user with confirmation for tables that should be cleared. - * @param array $tables - * @return boolean - */ - private function confirmClear($tables) - { - $this->stdout("Tables below will be cleared:\n\n", Console::FG_YELLOW); - $this->outputList($tables); - return $this->confirm('Clear tables?'); - } - - /** - * Outputs data to the console as a list. - * @param array $data - */ - private function outputList($data) - { - foreach($data as $index => $item) { - $this->stdout(" " . ($index + 1) . ". {$item}\n", Console::FG_GREEN); - } - } - - /** - * Checks if needed to apply all fixtures. - * @param string $fixture - * @return bool - */ - public function needToApplyAll($fixture) - { - return $fixture == self::APPLY_ALL; - } - - /** - * Returns array of found fixtures. These may differer from input parameter as not all fixtures may exists. - * @param array $fixtures - */ - private function findFixtures(array $fixtures) - { - $fixturesPath = Yii::getAlias($this->fixturePath); - - $files = []; - - if ($this->needToApplyAll($fixtures[0])) { - $files = FileHelper::findFiles($fixturesPath, ['only' => ['.php']]); - } else { - $filesToSearch = []; - foreach ($fixtures as $fileName) { - $filesToSearch[] = $fileName . '.php'; - } - $files = FileHelper::findFiles($fixturesPath, ['only' => $filesToSearch]); - } - - $foundFixtures = []; - - foreach($files as $fixture) { - $foundFixtures[] = basename($fixture , '.php'); - } - - return $foundFixtures; - } - -} diff --git a/framework/yii/console/controllers/HelpController.php b/framework/yii/console/controllers/HelpController.php deleted file mode 100644 index 49ee2c8..0000000 --- a/framework/yii/console/controllers/HelpController.php +++ /dev/null @@ -1,434 +0,0 @@ - - * @since 2.0 - */ -class HelpController extends Controller -{ - /** - * Displays available commands or the detailed information - * about a particular command. For example, - * - * @param string $command The name of the command to show help about. - * If not provided, all available commands will be displayed. - * @return integer the exit status - * @throws Exception if the command for help is unknown - */ - public function actionIndex($command = null) - { - if ($command !== null) { - $result = Yii::$app->createController($command); - if ($result === false) { - throw new Exception(Yii::t('yii', 'No help for unknown command "{command}".', [ - 'command' => $this->ansiFormat($command, Console::FG_YELLOW), - ])); - } - - list($controller, $actionID) = $result; - - $actions = $this->getActions($controller); - if ($actionID !== '' || count($actions) === 1 && $actions[0] === $controller->defaultAction) { - $this->getActionHelp($controller, $actionID); - } else { - $this->getControllerHelp($controller); - } - } else { - $this->getHelp(); - } - } - - /** - * Returns all available command names. - * @return array all available command names - */ - public function getCommands() - { - $commands = $this->getModuleCommands(Yii::$app); - sort($commands); - return array_unique($commands); - } - - /** - * Returns all available actions of the specified controller. - * @param Controller $controller the controller instance - * @return array all available action IDs. - */ - public function getActions($controller) - { - $actions = array_keys($controller->actions()); - $class = new \ReflectionClass($controller); - foreach ($class->getMethods() as $method) { - $name = $method->getName(); - if ($method->isPublic() && !$method->isStatic() && strpos($name, 'action') === 0 && $name !== 'actions') { - $actions[] = Inflector::camel2id(substr($name, 6)); - } - } - sort($actions); - return array_unique($actions); - } - - /** - * Returns available commands of a specified module. - * @param \yii\base\Module $module the module instance - * @return array the available command names - */ - protected function getModuleCommands($module) - { - $prefix = $module instanceof Application ? '' : $module->getUniqueID() . '/'; - - $commands = []; - foreach (array_keys($module->controllerMap) as $id) { - $commands[] = $prefix . $id; - } - - foreach ($module->getModules() as $id => $child) { - if (($child = $module->getModule($id)) === null) { - continue; - } - foreach ($this->getModuleCommands($child) as $command) { - $commands[] = $command; - } - } - - $files = scandir($module->getControllerPath()); - foreach ($files as $file) { - if (strcmp(substr($file, -14), 'Controller.php') === 0) { - $commands[] = $prefix . Inflector::camel2id(substr(basename($file), 0, -14)); - } - } - - return $commands; - } - - /** - * Displays all available commands. - */ - protected function getHelp() - { - $commands = $this->getCommands(); - if (!empty($commands)) { - $this->stdout("\nThe following commands are available:\n\n", Console::BOLD); - foreach ($commands as $command) { - echo "- " . $this->ansiFormat($command, Console::FG_YELLOW) . "\n"; - } - $scriptName = $this->getScriptName(); - $this->stdout("\nTo see the help of each command, enter:\n", Console::BOLD); - echo "\n $scriptName " . $this->ansiFormat('help', Console::FG_YELLOW) . ' ' - . $this->ansiFormat('', Console::FG_CYAN) . "\n\n"; - } else { - $this->stdout("\nNo commands are found.\n\n", Console::BOLD); - } - } - - /** - * Displays the overall information of the command. - * @param Controller $controller the controller instance - */ - protected function getControllerHelp($controller) - { - $class = new \ReflectionClass($controller); - $comment = strtr(trim(preg_replace('/^\s*\**( |\t)?/m', '', trim($class->getDocComment(), '/'))), "\r", ''); - if (preg_match('/^\s*@\w+/m', $comment, $matches, PREG_OFFSET_CAPTURE)) { - $comment = trim(substr($comment, 0, $matches[0][1])); - } - - if ($comment !== '') { - $this->stdout("\nDESCRIPTION\n", Console::BOLD); - echo "\n" . Console::renderColoredString($comment) . "\n\n"; - } - - $actions = $this->getActions($controller); - if (!empty($actions)) { - $this->stdout("\nSUB-COMMANDS\n\n", Console::BOLD); - $prefix = $controller->getUniqueId(); - foreach ($actions as $action) { - echo '- ' . $this->ansiFormat($prefix.'/'.$action, Console::FG_YELLOW); - if ($action === $controller->defaultAction) { - $this->stdout(' (default)', Console::FG_GREEN); - } - $summary = $this->getActionSummary($controller, $action); - if ($summary !== '') { - echo ': ' . $summary; - } - echo "\n"; - } - $scriptName = $this->getScriptName(); - echo "\nTo see the detailed information about individual sub-commands, enter:\n"; - echo "\n $scriptName " . $this->ansiFormat('help', Console::FG_YELLOW) . ' ' - . $this->ansiFormat('', Console::FG_CYAN) . "\n\n"; - } - } - - /** - * Returns the short summary of the action. - * @param Controller $controller the controller instance - * @param string $actionID action ID - * @return string the summary about the action - */ - protected function getActionSummary($controller, $actionID) - { - $action = $controller->createAction($actionID); - if ($action === null) { - return ''; - } - if ($action instanceof InlineAction) { - $reflection = new \ReflectionMethod($controller, $action->actionMethod); - } else { - $reflection = new \ReflectionClass($action); - } - $tags = $this->parseComment($reflection->getDocComment()); - if ($tags['description'] !== '') { - $limit = 73 - strlen($action->getUniqueId()); - if ($actionID === $controller->defaultAction) { - $limit -= 10; - } - if ($limit < 0) { - $limit = 50; - } - $description = $tags['description']; - if (($pos = strpos($tags['description'], "\n")) !== false) { - $description = substr($description, 0, $pos); - } - $text = substr($description, 0, $limit); - return strlen($description) > $limit ? $text . '...' : $text; - } else { - return ''; - } - } - - /** - * Displays the detailed information of a command action. - * @param Controller $controller the controller instance - * @param string $actionID action ID - * @throws Exception if the action does not exist - */ - protected function getActionHelp($controller, $actionID) - { - $action = $controller->createAction($actionID); - if ($action === null) { - throw new Exception(Yii::t('yii', 'No help for unknown sub-command "{command}".', [ - 'command' => rtrim($controller->getUniqueId() . '/' . $actionID, '/'), - ])); - } - if ($action instanceof InlineAction) { - $method = new \ReflectionMethod($controller, $action->actionMethod); - } else { - $method = new \ReflectionMethod($action, 'run'); - } - - $tags = $this->parseComment($method->getDocComment()); - $options = $this->getOptionHelps($controller); - - if ($tags['description'] !== '') { - $this->stdout("\nDESCRIPTION\n", Console::BOLD); - echo "\n" . Console::renderColoredString($tags['description']) . "\n\n"; - } - - $this->stdout("\nUSAGE\n\n", Console::BOLD); - $scriptName = $this->getScriptName(); - if ($action->id === $controller->defaultAction) { - echo $scriptName . ' ' . $this->ansiFormat($controller->getUniqueId(), Console::FG_YELLOW); - } else { - echo $scriptName . ' ' . $this->ansiFormat($action->getUniqueId(), Console::FG_YELLOW); - } - list ($required, $optional) = $this->getArgHelps($method, isset($tags['param']) ? $tags['param'] : []); - foreach ($required as $arg => $description) { - $this->stdout(' <' . $arg . '>', Console::FG_CYAN); - } - foreach ($optional as $arg => $description) { - $this->stdout(' [' . $arg . ']', Console::FG_CYAN); - } - if (!empty($options)) { - $this->stdout(' [...options...]', Console::FG_RED); - } - echo "\n\n"; - - if (!empty($required) || !empty($optional)) { - echo implode("\n\n", array_merge($required, $optional)) . "\n\n"; - } - - $options = $this->getOptionHelps($controller); - if (!empty($options)) { - $this->stdout("\nOPTIONS\n\n", Console::BOLD); - echo implode("\n\n", $options) . "\n\n"; - } - } - - /** - * Returns the help information about arguments. - * @param \ReflectionMethod $method - * @param string $tags the parsed comment block related with arguments - * @return array the required and optional argument help information - */ - protected function getArgHelps($method, $tags) - { - if (is_string($tags)) { - $tags = [$tags]; - } - $params = $method->getParameters(); - $optional = $required = []; - foreach ($params as $i => $param) { - $name = $param->getName(); - $tag = isset($tags[$i]) ? $tags[$i] : ''; - if (preg_match('/^([^\s]+)\s+(\$\w+\s+)?(.*)/s', $tag, $matches)) { - $type = $matches[1]; - $comment = $matches[3]; - } else { - $type = null; - $comment = $tag; - } - if ($param->isDefaultValueAvailable()) { - $optional[$name] = $this->formatOptionHelp('- ' . $this->ansiFormat($name, Console::FG_CYAN), false, $type, $param->getDefaultValue(), $comment); - } else { - $required[$name] = $this->formatOptionHelp('- ' . $this->ansiFormat($name, Console::FG_CYAN), true, $type, null, $comment); - } - } - - return [$required, $optional]; - } - - /** - * Returns the help information about the options available for a console controller. - * @param Controller $controller the console controller - * @return array the help information about the options - */ - protected function getOptionHelps($controller) - { - $optionNames = $controller->globalOptions(); - if (empty($optionNames)) { - return []; - } - - $class = new \ReflectionClass($controller); - $options = []; - foreach ($class->getProperties() as $property) { - $name = $property->getName(); - if (!in_array($name, $optionNames, true)) { - continue; - } - $defaultValue = $property->getValue($controller); - $tags = $this->parseComment($property->getDocComment()); - if (isset($tags['var']) || isset($tags['property'])) { - $doc = isset($tags['var']) ? $tags['var'] : $tags['property']; - if (is_array($doc)) { - $doc = reset($doc); - } - if (preg_match('/^([^\s]+)(.*)/s', $doc, $matches)) { - $type = $matches[1]; - $comment = $matches[2]; - } else { - $type = null; - $comment = $doc; - } - $options[$name] = $this->formatOptionHelp($this->ansiFormat('--' . $name, Console::FG_RED), false, $type, $defaultValue, $comment); - } else { - $options[$name] = $this->formatOptionHelp($this->ansiFormat('--' . $name, Console::FG_RED), false, null, $defaultValue, ''); - } - } - ksort($options); - return $options; - } - - /** - * Parses the comment block into tags. - * @param string $comment the comment block - * @return array the parsed tags - */ - protected function parseComment($comment) - { - $tags = []; - $comment = "@description \n" . strtr(trim(preg_replace('/^\s*\**( |\t)?/m', '', trim($comment, '/'))), "\r", ''); - $parts = preg_split('/^\s*@/m', $comment, -1, PREG_SPLIT_NO_EMPTY); - foreach ($parts as $part) { - if (preg_match('/^(\w+)(.*)/ms', trim($part), $matches)) { - $name = $matches[1]; - if (!isset($tags[$name])) { - $tags[$name] = trim($matches[2]); - } elseif (is_array($tags[$name])) { - $tags[$name][] = trim($matches[2]); - } else { - $tags[$name] = [$tags[$name], trim($matches[2])]; - } - } - } - return $tags; - } - - /** - * Generates a well-formed string for an argument or option. - * @param string $name the name of the argument or option - * @param boolean $required whether the argument is required - * @param string $type the type of the option or argument - * @param mixed $defaultValue the default value of the option or argument - * @param string $comment comment about the option or argument - * @return string the formatted string for the argument or option - */ - protected function formatOptionHelp($name, $required, $type, $defaultValue, $comment) - { - $doc = ''; - $comment = trim($comment); - - if ($defaultValue !== null && !is_array($defaultValue)) { - if ($type === null) { - $type = gettype($defaultValue); - } - if (is_bool($defaultValue)) { - // show as integer to avoid confusion - $defaultValue = (int)$defaultValue; - } - $doc = "$type (defaults to " . var_export($defaultValue, true) . ")"; - } elseif (trim($type) !== '') { - $doc = $type; - } - - if ($doc === '') { - $doc = $comment; - } elseif ($comment !== '') { - $doc .= "\n" . preg_replace("/^/m", " ", $comment); - } - - $name = $required ? "$name (required)" : $name; - return $doc === '' ? $name : "$name: $doc"; - } - - /** - * @return string the name of the cli script currently running. - */ - protected function getScriptName() - { - return basename(Yii::$app->request->scriptFile); - } -} diff --git a/framework/yii/console/controllers/MessageController.php b/framework/yii/console/controllers/MessageController.php deleted file mode 100644 index e34ccd6..0000000 --- a/framework/yii/console/controllers/MessageController.php +++ /dev/null @@ -1,241 +0,0 @@ - - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\console\controllers; - -use Yii; -use yii\console\Controller; -use yii\console\Exception; -use yii\helpers\FileHelper; - -/** - * This command extracts messages to be translated from source files. - * The extracted messages are saved as PHP message source files - * under the specified directory. - * - * Usage: - * 1. Create a configuration file using the 'message/config' command: - * yii message/config /path/to/myapp/messages/config.php - * 2. Edit the created config file, adjusting it for your web application needs. - * 3. Run the 'message/extract' command, using created config: - * yii message /path/to/myapp/messages/config.php - * - * @author Qiang Xue - * @since 2.0 - */ -class MessageController extends Controller -{ - /** - * @var string controller default action ID. - */ - public $defaultAction = 'extract'; - - - /** - * Creates a configuration file for the "extract" command. - * - * The generated configuration file contains detailed instructions on - * how to customize it to fit for your needs. After customization, - * you may use this configuration file with the "extract" command. - * - * @param string $filePath output file name or alias. - * @throws Exception on failure. - */ - public function actionConfig($filePath) - { - $filePath = Yii::getAlias($filePath); - if (file_exists($filePath)) { - if (!$this->confirm("File '{$filePath}' already exists. Do you wish to overwrite it?")) { - return; - } - } - copy(Yii::getAlias('@yii/views/messageConfig.php'), $filePath); - echo "Configuration file template created at '{$filePath}'.\n\n"; - } - - /** - * Extracts messages to be translated from source code. - * - * This command will search through source code files and extract - * messages that need to be translated in different languages. - * - * @param string $configFile the path or alias of the configuration file. - * You may use the "yii message/config" command to generate - * this file and then customize it for your needs. - * @throws Exception on failure. - */ - public function actionExtract($configFile) - { - $configFile = Yii::getAlias($configFile); - if (!is_file($configFile)) { - throw new Exception("The configuration file does not exist: $configFile"); - } - - $config = array_merge([ - 'translator' => 'Yii::t', - 'overwrite' => false, - 'removeUnused' => false, - 'sort' => false, - ], require($configFile)); - - if (!isset($config['sourcePath'], $config['messagePath'], $config['languages'])) { - throw new Exception('The configuration file must specify "sourcePath", "messagePath" and "languages".'); - } - if (!is_dir($config['sourcePath'])) { - throw new Exception("The source path {$config['sourcePath']} is not a valid directory."); - } - if (!is_dir($config['messagePath'])) { - throw new Exception("The message path {$config['messagePath']} is not a valid directory."); - } - if (empty($config['languages'])) { - throw new Exception("Languages cannot be empty."); - } - - $files = FileHelper::findFiles(realpath($config['sourcePath']), $config); - - $messages = []; - foreach ($files as $file) { - $messages = array_merge_recursive($messages, $this->extractMessages($file, $config['translator'])); - } - - foreach ($config['languages'] as $language) { - $dir = $config['messagePath'] . DIRECTORY_SEPARATOR . $language; - if (!is_dir($dir)) { - @mkdir($dir); - } - foreach ($messages as $category => $msgs) { - $file = str_replace("\\", '/', "$dir/$category.php"); - $path = dirname($file); - if (!is_dir($path)) { - mkdir($path, 0755, true); - } - $msgs = array_values(array_unique($msgs)); - $this->generateMessageFile($msgs, $file, $config['overwrite'], $config['removeUnused'], $config['sort']); - } - } - } - - /** - * Extracts messages from a file - * - * @param string $fileName name of the file to extract messages from - * @param string $translator name of the function used to translate messages - * @return array - */ - protected function extractMessages($fileName, $translator) - { - echo "Extracting messages from $fileName...\n"; - $subject = file_get_contents($fileName); - $messages = []; - if (!is_array($translator)) { - $translator = [$translator]; - } - foreach ($translator as $currentTranslator) { - $n = preg_match_all( - '/\b' . $currentTranslator . '\s*\(\s*(\'.*?(? 0) { - $merged[$message] = $translated[$message]; - } else { - $untranslated[] = $message; - } - } - ksort($merged); - sort($untranslated); - $todo = []; - foreach ($untranslated as $message) { - $todo[$message] = ''; - } - ksort($translated); - foreach ($translated as $message => $translation) { - if (!isset($merged[$message]) && !isset($todo[$message]) && !$removeUnused) { - if (substr($translation, 0, 2) === '@@' && substr($translation, -2) === '@@') { - $todo[$message] = $translation; - } else { - $todo[$message] = '@@' . $translation . '@@'; - } - } - } - $merged = array_merge($todo, $merged); - if ($sort) { - ksort($merged); - } - if (false === $overwrite) { - $fileName .= '.merged'; - } - echo "translation merged.\n"; - } else { - $merged = []; - foreach ($messages as $message) { - $merged[$message] = ''; - } - ksort($merged); - echo "saved.\n"; - } - $array = str_replace("\r", '', var_export($merged, true)); - $content = <<id}' command. - * It contains the localizable messages extracted from source code. - * You may modify this file by translating the extracted messages. - * - * Each array element represents the translation (value) of a message (key). - * If the value is empty, the message is considered as not translated. - * Messages that no longer need translation will have their translations - * enclosed between a pair of '@@' marks. - * - * Message string can be used with plural forms format. Check i18n section - * of the guide for details. - * - * NOTE: this file must be saved in UTF-8 encoding. - */ -return $array; - -EOD; - file_put_contents($fileName, $content); - } -} diff --git a/framework/yii/console/controllers/MigrateController.php b/framework/yii/console/controllers/MigrateController.php deleted file mode 100644 index 5730bbd..0000000 --- a/framework/yii/console/controllers/MigrateController.php +++ /dev/null @@ -1,633 +0,0 @@ - - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\console\controllers; - -use Yii; -use yii\console\Exception; -use yii\console\Controller; -use yii\db\Connection; -use yii\db\Query; -use yii\helpers\ArrayHelper; - -/** - * This command manages application migrations. - * - * A migration means a set of persistent changes to the application environment - * that is shared among different developers. For example, in an application - * backed by a database, a migration may refer to a set of changes to - * the database, such as creating a new table, adding a new table column. - * - * This command provides support for tracking the migration history, upgrading - * or downloading with migrations, and creating new migration skeletons. - * - * The migration history is stored in a database table named - * as [[migrationTable]]. The table will be automatically created the first time - * this command is executed, if it does not exist. You may also manually - * create it as follows: - * - * ~~~ - * CREATE TABLE tbl_migration ( - * version varchar(180) PRIMARY KEY, - * apply_time integer - * ) - * ~~~ - * - * Below are some common usages of this command: - * - * ~~~ - * # creates a new migration named 'create_user_table' - * yii migrate/create create_user_table - * - * # applies ALL new migrations - * yii migrate - * - * # reverts the last applied migration - * yii migrate/down - * ~~~ - * - * @author Qiang Xue - * @since 2.0 - */ -class MigrateController extends Controller -{ - /** - * The name of the dummy migration that marks the beginning of the whole migration history. - */ - const BASE_MIGRATION = 'm000000_000000_base'; - - /** - * @var string the default command action. - */ - public $defaultAction = 'up'; - /** - * @var string the directory storing the migration classes. This can be either - * a path alias or a directory. - */ - public $migrationPath = '@app/migrations'; - /** - * @var string the name of the table for keeping applied migration information. - */ - public $migrationTable = '{{%migration}}'; - /** - * @var string the template file for generating new migrations. - * This can be either a path alias (e.g. "@app/migrations/template.php") - * or a file path. - */ - public $templateFile = '@yii/views/migration.php'; - /** - * @var boolean whether to execute the migration in an interactive mode. - */ - public $interactive = true; - /** - * @var Connection|string the DB connection object or the application - * component ID of the DB connection. - */ - public $db = 'db'; - - /** - * Returns the names of the global options for this command. - * @return array the names of the global options for this command. - */ - public function globalOptions() - { - return array_merge(parent::globalOptions(), [ - 'migrationPath', 'migrationTable', 'db', 'templateFile', 'interactive', 'color' - ]); - } - - /** - * This method is invoked right before an action is to be executed (after all possible filters.) - * It checks the existence of the [[migrationPath]]. - * @param \yii\base\Action $action the action to be executed. - * @return boolean whether the action should continue to be executed. - * @throws Exception if the migration directory does not exist. - */ - public function beforeAction($action) - { - if (parent::beforeAction($action)) { - $path = Yii::getAlias($this->migrationPath); - if (!is_dir($path)) { - throw new Exception("The migration directory \"{$this->migrationPath}\" does not exist."); - } - $this->migrationPath = $path; - - if ($action->id !== 'create') { - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - } - if (!$this->db instanceof Connection) { - throw new Exception("The 'db' option must refer to the application component ID of a DB connection."); - } - } - - $version = Yii::getVersion(); - echo "Yii Migration Tool (based on Yii v{$version})\n\n"; - return true; - } else { - return false; - } - } - - /** - * Upgrades the application by applying new migrations. - * For example, - * - * ~~~ - * yii migrate # apply all new migrations - * yii migrate 3 # apply the first 3 new migrations - * ~~~ - * - * @param integer $limit the number of new migrations to be applied. If 0, it means - * applying all available new migrations. - */ - public function actionUp($limit = 0) - { - $migrations = $this->getNewMigrations(); - if (empty($migrations)) { - echo "No new migration found. Your system is up-to-date.\n"; - return; - } - - $total = count($migrations); - $limit = (int)$limit; - if ($limit > 0) { - $migrations = array_slice($migrations, 0, $limit); - } - - $n = count($migrations); - if ($n === $total) { - echo "Total $n new " . ($n === 1 ? 'migration' : 'migrations') . " to be applied:\n"; - } else { - echo "Total $n out of $total new " . ($total === 1 ? 'migration' : 'migrations') . " to be applied:\n"; - } - - foreach ($migrations as $migration) { - echo " $migration\n"; - } - echo "\n"; - - if ($this->confirm('Apply the above ' . ($n === 1 ? 'migration' : 'migrations') . "?")) { - foreach ($migrations as $migration) { - if (!$this->migrateUp($migration)) { - echo "\nMigration failed. The rest of the migrations are canceled.\n"; - return; - } - } - echo "\nMigrated up successfully.\n"; - } - } - - /** - * Downgrades the application by reverting old migrations. - * For example, - * - * ~~~ - * yii migrate/down # revert the last migration - * yii migrate/down 3 # revert the last 3 migrations - * ~~~ - * - * @param integer $limit the number of migrations to be reverted. Defaults to 1, - * meaning the last applied migration will be reverted. - * @throws Exception if the number of the steps specified is less than 1. - */ - public function actionDown($limit = 1) - { - $limit = (int)$limit; - if ($limit < 1) { - throw new Exception("The step argument must be greater than 0."); - } - - $migrations = $this->getMigrationHistory($limit); - if (empty($migrations)) { - echo "No migration has been done before.\n"; - return; - } - $migrations = array_keys($migrations); - - $n = count($migrations); - echo "Total $n " . ($n === 1 ? 'migration' : 'migrations') . " to be reverted:\n"; - foreach ($migrations as $migration) { - echo " $migration\n"; - } - echo "\n"; - - if ($this->confirm('Revert the above ' . ($n === 1 ? 'migration' : 'migrations') . "?")) { - foreach ($migrations as $migration) { - if (!$this->migrateDown($migration)) { - echo "\nMigration failed. The rest of the migrations are canceled.\n"; - return; - } - } - echo "\nMigrated down successfully.\n"; - } - } - - /** - * Redoes the last few migrations. - * - * This command will first revert the specified migrations, and then apply - * them again. For example, - * - * ~~~ - * yii migrate/redo # redo the last applied migration - * yii migrate/redo 3 # redo the last 3 applied migrations - * ~~~ - * - * @param integer $limit the number of migrations to be redone. Defaults to 1, - * meaning the last applied migration will be redone. - * @throws Exception if the number of the steps specified is less than 1. - */ - public function actionRedo($limit = 1) - { - $limit = (int)$limit; - if ($limit < 1) { - throw new Exception("The step argument must be greater than 0."); - } - - $migrations = $this->getMigrationHistory($limit); - if (empty($migrations)) { - echo "No migration has been done before.\n"; - return; - } - $migrations = array_keys($migrations); - - $n = count($migrations); - echo "Total $n " . ($n === 1 ? 'migration' : 'migrations') . " to be redone:\n"; - foreach ($migrations as $migration) { - echo " $migration\n"; - } - echo "\n"; - - if ($this->confirm('Redo the above ' . ($n === 1 ? 'migration' : 'migrations') . "?")) { - foreach ($migrations as $migration) { - if (!$this->migrateDown($migration)) { - echo "\nMigration failed. The rest of the migrations are canceled.\n"; - return; - } - } - foreach (array_reverse($migrations) as $migration) { - if (!$this->migrateUp($migration)) { - echo "\nMigration failed. The rest of the migrations migrations are canceled.\n"; - return; - } - } - echo "\nMigration redone successfully.\n"; - } - } - - /** - * Upgrades or downgrades till the specified version. - * - * This command will first revert the specified migrations, and then apply - * them again. For example, - * - * ~~~ - * yii migrate/to 101129_185401 # using timestamp - * yii migrate/to m101129_185401_create_user_table # using full name - * ~~~ - * - * @param string $version the version name that the application should be migrated to. - * This can be either the timestamp or the full name of the migration. - * @throws Exception if the version argument is invalid - */ - public function actionTo($version) - { - $originalVersion = $version; - if (preg_match('/^m?(\d{6}_\d{6})(_.*?)?$/', $version, $matches)) { - $version = 'm' . $matches[1]; - } else { - throw new Exception("The version argument must be either a timestamp (e.g. 101129_185401)\nor the full name of a migration (e.g. m101129_185401_create_user_table)."); - } - - // try migrate up - $migrations = $this->getNewMigrations(); - foreach ($migrations as $i => $migration) { - if (strpos($migration, $version . '_') === 0) { - $this->actionUp($i + 1); - return; - } - } - - // try migrate down - $migrations = array_keys($this->getMigrationHistory(-1)); - foreach ($migrations as $i => $migration) { - if (strpos($migration, $version . '_') === 0) { - if ($i === 0) { - echo "Already at '$originalVersion'. Nothing needs to be done.\n"; - } else { - $this->actionDown($i); - } - return; - } - } - - throw new Exception("Unable to find the version '$originalVersion'."); - } - - /** - * Modifies the migration history to the specified version. - * - * No actual migration will be performed. - * - * ~~~ - * yii migrate/mark 101129_185401 # using timestamp - * yii migrate/mark m101129_185401_create_user_table # using full name - * ~~~ - * - * @param string $version the version at which the migration history should be marked. - * This can be either the timestamp or the full name of the migration. - * @throws Exception if the version argument is invalid or the version cannot be found. - */ - public function actionMark($version) - { - $originalVersion = $version; - if (preg_match('/^m?(\d{6}_\d{6})(_.*?)?$/', $version, $matches)) { - $version = 'm' . $matches[1]; - } else { - throw new Exception("The version argument must be either a timestamp (e.g. 101129_185401)\nor the full name of a migration (e.g. m101129_185401_create_user_table)."); - } - - // try mark up - $migrations = $this->getNewMigrations(); - foreach ($migrations as $i => $migration) { - if (strpos($migration, $version . '_') === 0) { - if ($this->confirm("Set migration history at $originalVersion?")) { - $command = $this->db->createCommand(); - for ($j = 0; $j <= $i; ++$j) { - $command->insert($this->migrationTable, [ - 'version' => $migrations[$j], - 'apply_time' => time(), - ])->execute(); - } - echo "The migration history is set at $originalVersion.\nNo actual migration was performed.\n"; - } - return; - } - } - - // try mark down - $migrations = array_keys($this->getMigrationHistory(-1)); - foreach ($migrations as $i => $migration) { - if (strpos($migration, $version . '_') === 0) { - if ($i === 0) { - echo "Already at '$originalVersion'. Nothing needs to be done.\n"; - } else { - if ($this->confirm("Set migration history at $originalVersion?")) { - $command = $this->db->createCommand(); - for ($j = 0; $j < $i; ++$j) { - $command->delete($this->migrationTable, [ - 'version' => $migrations[$j], - ])->execute(); - } - echo "The migration history is set at $originalVersion.\nNo actual migration was performed.\n"; - } - } - return; - } - } - - throw new Exception("Unable to find the version '$originalVersion'."); - } - - /** - * Displays the migration history. - * - * This command will show the list of migrations that have been applied - * so far. For example, - * - * ~~~ - * yii migrate/history # showing the last 10 migrations - * yii migrate/history 5 # showing the last 5 migrations - * yii migrate/history 0 # showing the whole history - * ~~~ - * - * @param integer $limit the maximum number of migrations to be displayed. - * If it is 0, the whole migration history will be displayed. - */ - public function actionHistory($limit = 10) - { - $limit = (int)$limit; - $migrations = $this->getMigrationHistory($limit); - if (empty($migrations)) { - echo "No migration has been done before.\n"; - } else { - $n = count($migrations); - if ($limit > 0) { - echo "Showing the last $n applied " . ($n === 1 ? 'migration' : 'migrations') . ":\n"; - } else { - echo "Total $n " . ($n === 1 ? 'migration has' : 'migrations have') . " been applied before:\n"; - } - foreach ($migrations as $version => $time) { - echo " (" . date('Y-m-d H:i:s', $time) . ') ' . $version . "\n"; - } - } - } - - /** - * Displays the un-applied new migrations. - * - * This command will show the new migrations that have not been applied. - * For example, - * - * ~~~ - * yii migrate/new # showing the first 10 new migrations - * yii migrate/new 5 # showing the first 5 new migrations - * yii migrate/new 0 # showing all new migrations - * ~~~ - * - * @param integer $limit the maximum number of new migrations to be displayed. - * If it is 0, all available new migrations will be displayed. - */ - public function actionNew($limit = 10) - { - $limit = (int)$limit; - $migrations = $this->getNewMigrations(); - if (empty($migrations)) { - echo "No new migrations found. Your system is up-to-date.\n"; - } else { - $n = count($migrations); - if ($limit > 0 && $n > $limit) { - $migrations = array_slice($migrations, 0, $limit); - echo "Showing $limit out of $n new " . ($n === 1 ? 'migration' : 'migrations') . ":\n"; - } else { - echo "Found $n new " . ($n === 1 ? 'migration' : 'migrations') . ":\n"; - } - - foreach ($migrations as $migration) { - echo " " . $migration . "\n"; - } - } - } - - /** - * Creates a new migration. - * - * This command creates a new migration using the available migration template. - * After using this command, developers should modify the created migration - * skeleton by filling up the actual migration logic. - * - * ~~~ - * yii migrate/create create_user_table - * ~~~ - * - * @param string $name the name of the new migration. This should only contain - * letters, digits and/or underscores. - * @throws Exception if the name argument is invalid. - */ - public function actionCreate($name) - { - if (!preg_match('/^\w+$/', $name)) { - throw new Exception("The migration name should contain letters, digits and/or underscore characters only."); - } - - $name = 'm' . gmdate('ymd_His') . '_' . $name; - $file = $this->migrationPath . DIRECTORY_SEPARATOR . $name . '.php'; - - if ($this->confirm("Create new migration '$file'?")) { - $content = $this->renderFile(Yii::getAlias($this->templateFile), ['className' => $name]); - file_put_contents($file, $content); - echo "New migration created successfully.\n"; - } - } - - /** - * Upgrades with the specified migration class. - * @param string $class the migration class name - * @return boolean whether the migration is successful - */ - protected function migrateUp($class) - { - if ($class === self::BASE_MIGRATION) { - return true; - } - - echo "*** applying $class\n"; - $start = microtime(true); - $migration = $this->createMigration($class); - if ($migration->up() !== false) { - $this->db->createCommand()->insert($this->migrationTable, [ - 'version' => $class, - 'apply_time' => time(), - ])->execute(); - $time = microtime(true) - $start; - echo "*** applied $class (time: " . sprintf("%.3f", $time) . "s)\n\n"; - return true; - } else { - $time = microtime(true) - $start; - echo "*** failed to apply $class (time: " . sprintf("%.3f", $time) . "s)\n\n"; - return false; - } - } - - /** - * Downgrades with the specified migration class. - * @param string $class the migration class name - * @return boolean whether the migration is successful - */ - protected function migrateDown($class) - { - if ($class === self::BASE_MIGRATION) { - return true; - } - - echo "*** reverting $class\n"; - $start = microtime(true); - $migration = $this->createMigration($class); - if ($migration->down() !== false) { - $this->db->createCommand()->delete($this->migrationTable, [ - 'version' => $class, - ])->execute(); - $time = microtime(true) - $start; - echo "*** reverted $class (time: " . sprintf("%.3f", $time) . "s)\n\n"; - return true; - } else { - $time = microtime(true) - $start; - echo "*** failed to revert $class (time: " . sprintf("%.3f", $time) . "s)\n\n"; - return false; - } - } - - /** - * Creates a new migration instance. - * @param string $class the migration class name - * @return \yii\db\Migration the migration instance - */ - protected function createMigration($class) - { - $file = $this->migrationPath . DIRECTORY_SEPARATOR . $class . '.php'; - require_once($file); - return new $class(['db' => $this->db]); - } - - /** - * Returns the migration history. - * @param integer $limit the maximum number of records in the history to be returned - * @return array the migration history - */ - protected function getMigrationHistory($limit) - { - if ($this->db->schema->getTableSchema($this->migrationTable, true) === null) { - $this->createMigrationHistoryTable(); - } - $query = new Query; - $rows = $query->select(['version', 'apply_time']) - ->from($this->migrationTable) - ->orderBy('version DESC') - ->limit($limit) - ->createCommand($this->db) - ->queryAll(); - $history = ArrayHelper::map($rows, 'version', 'apply_time'); - unset($history[self::BASE_MIGRATION]); - return $history; - } - - /** - * Creates the migration history table. - */ - protected function createMigrationHistoryTable() - { - echo 'Creating migration history table "' . $this->migrationTable . '"...'; - $this->db->createCommand()->createTable($this->migrationTable, [ - 'version' => 'varchar(180) NOT NULL PRIMARY KEY', - 'apply_time' => 'integer', - ])->execute(); - $this->db->createCommand()->insert($this->migrationTable, [ - 'version' => self::BASE_MIGRATION, - 'apply_time' => time(), - ])->execute(); - echo "done.\n"; - } - - /** - * Returns the migrations that are not applied. - * @return array list of new migrations - */ - protected function getNewMigrations() - { - $applied = []; - foreach ($this->getMigrationHistory(-1) as $version => $time) { - $applied[substr($version, 1, 13)] = true; - } - - $migrations = []; - $handle = opendir($this->migrationPath); - while (($file = readdir($handle)) !== false) { - if ($file === '.' || $file === '..') { - continue; - } - $path = $this->migrationPath . DIRECTORY_SEPARATOR . $file; - if (preg_match('/^(m(\d{6}_\d{6})_.*?)\.php$/', $file, $matches) && is_file($path) && !isset($applied[$matches[2]])) { - $migrations[] = $matches[1]; - } - } - closedir($handle); - sort($migrations); - return $migrations; - } -} diff --git a/framework/yii/console/runtime/.gitignore b/framework/yii/console/runtime/.gitignore deleted file mode 100644 index f59ec20..0000000 --- a/framework/yii/console/runtime/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* \ No newline at end of file diff --git a/framework/yii/data/ActiveDataProvider.php b/framework/yii/data/ActiveDataProvider.php deleted file mode 100644 index d3e3b56..0000000 --- a/framework/yii/data/ActiveDataProvider.php +++ /dev/null @@ -1,182 +0,0 @@ - Post::find(), - * 'pagination' => [ - * 'pageSize' => 20, - * ], - * ]); - * - * // get the posts in the current page - * $posts = $provider->getModels(); - * ~~~ - * - * And the following example shows how to use ActiveDataProvider without ActiveRecord: - * - * ~~~ - * $query = new Query; - * $provider = new ActiveDataProvider([ - * 'query' => $query->from('tbl_post'), - * 'pagination' => [ - * 'pageSize' => 20, - * ], - * ]); - * - * // get the posts in the current page - * $posts = $provider->getModels(); - * ~~~ - * - * @author Qiang Xue - * @since 2.0 - */ -class ActiveDataProvider extends BaseDataProvider -{ - /** - * @var QueryInterface the query that is used to fetch data models and [[totalCount]] - * if it is not explicitly set. - */ - public $query; - /** - * @var string|callable the column that is used as the key of the data models. - * This can be either a column name, or a callable that returns the key value of a given data model. - * - * If this is not set, the following rules will be used to determine the keys of the data models: - * - * - If [[query]] is an [[ActiveQuery]] instance, the primary keys of [[ActiveQuery::modelClass]] will be used. - * - Otherwise, the keys of the [[models]] array will be used. - * - * @see getKeys() - */ - public $key; - /** - * @var Connection|string the DB connection object or the application component ID of the DB connection. - * If not set, the default DB connection will be used. - */ - public $db; - - /** - * Initializes the DB connection component. - * This method will initialize the [[db]] property to make sure it refers to a valid DB connection. - * @throws InvalidConfigException if [[db]] is invalid. - */ - public function init() - { - parent::init(); - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - if ($this->db === null) { - throw new InvalidConfigException('The "db" property must be a valid DB Connection application component.'); - } - } - } - - /** - * @inheritdoc - */ - protected function prepareModels() - { - if (!$this->query instanceof QueryInterface) { - throw new InvalidConfigException('The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.'); - } - if (($pagination = $this->getPagination()) !== false) { - $pagination->totalCount = $this->getTotalCount(); - $this->query->limit($pagination->getLimit())->offset($pagination->getOffset()); - } - if (($sort = $this->getSort()) !== false) { - $this->query->addOrderBy($sort->getOrders()); - } - return $this->query->all($this->db); - } - - /** - * @inheritdoc - */ - protected function prepareKeys($models) - { - $keys = []; - if ($this->key !== null) { - foreach ($models as $model) { - if (is_string($this->key)) { - $keys[] = $model[$this->key]; - } else { - $keys[] = call_user_func($this->key, $model); - } - } - return $keys; - } elseif ($this->query instanceof ActiveQueryInterface) { - /** @var \yii\db\ActiveRecord $class */ - $class = $this->query->modelClass; - $pks = $class::primaryKey(); - if (count($pks) === 1) { - $pk = $pks[0]; - foreach ($models as $model) { - $keys[] = $model[$pk]; - } - } else { - foreach ($models as $model) { - $kk = []; - foreach ($pks as $pk) { - $kk[$pk] = $model[$pk]; - } - $keys[] = $kk; - } - } - return $keys; - } else { - return array_keys($models); - } - } - - /** - * @inheritdoc - */ - protected function prepareTotalCount() - { - if (!$this->query instanceof QueryInterface) { - throw new InvalidConfigException('The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.'); - } - $query = clone $this->query; - return (int) $query->limit(-1)->offset(-1)->orderBy([])->count('*', $this->db); - } - - /** - * @inheritdoc - */ - public function setSort($value) - { - parent::setSort($value); - if (($sort = $this->getSort()) !== false && empty($sort->attributes) && $this->query instanceof ActiveQueryInterface) { - /** @var Model $model */ - $model = new $this->query->modelClass; - foreach ($model->attributes() as $attribute) { - $sort->attributes[$attribute] = [ - 'asc' => [$attribute => SORT_ASC], - 'desc' => [$attribute => SORT_DESC], - 'label' => $model->getAttributeLabel($attribute), - ]; - } - } - } -} diff --git a/framework/yii/data/ArrayDataProvider.php b/framework/yii/data/ArrayDataProvider.php deleted file mode 100644 index 2b694c7..0000000 --- a/framework/yii/data/ArrayDataProvider.php +++ /dev/null @@ -1,131 +0,0 @@ - $query->from('tbl_post')->all(), - * 'sort' => [ - * 'attributes' => ['id', 'username', 'email'], - * ], - * 'pagination' => [ - * 'pageSize' => 10, - * ], - * ]); - * // get the posts in the current page - * $posts = $provider->getModels(); - * ~~~ - * - * Note: if you want to use the sorting feature, you must configure the [[sort]] property - * so that the provider knows which columns can be sorted. - * - * @author Qiang Xue - * @since 2.0 - */ -class ArrayDataProvider extends BaseDataProvider -{ - /** - * @var string|callable the column that is used as the key of the data models. - * This can be either a column name, or a callable that returns the key value of a given data model. - * If this is not set, the index of the [[models]] array will be used. - * @see getKeys() - */ - public $key; - /** - * @var array the data that is not paginated or sorted. When pagination is enabled, - * this property usually contains more elements than [[models]]. - * The array elements must use zero-based integer keys. - */ - public $allModels; - - - /** - * @inheritdoc - */ - protected function prepareModels() - { - if (($models = $this->allModels) === null) { - return []; - } - - if (($sort = $this->getSort()) !== false) { - $models = $this->sortModels($models, $sort); - } - - if (($pagination = $this->getPagination()) !== false) { - $pagination->totalCount = $this->getTotalCount(); - $models = array_slice($models, $pagination->getOffset(), $pagination->getLimit()); - } - - return $models; - } - - /** - * @inheritdoc - */ - protected function prepareKeys($models) - { - if ($this->key !== null) { - $keys = []; - foreach ($models as $model) { - if (is_string($this->key)) { - $keys[] = $model[$this->key]; - } else { - $keys[] = call_user_func($this->key, $model); - } - } - return $keys; - } else { - return array_keys($models); - } - } - - /** - * @inheritdoc - */ - protected function prepareTotalCount() - { - return count($this->allModels); - } - - /** - * Sorts the data models according to the given sort definition - * @param array $models the models to be sorted - * @param Sort $sort the sort definition - * @return array the sorted data models - */ - protected function sortModels($models, $sort) - { - $orders = $sort->getOrders(); - if (!empty($orders)) { - ArrayHelper::multisort($models, array_keys($orders), array_values($orders)); - } - return $models; - } -} diff --git a/framework/yii/data/BaseDataProvider.php b/framework/yii/data/BaseDataProvider.php deleted file mode 100644 index cf094c7..0000000 --- a/framework/yii/data/BaseDataProvider.php +++ /dev/null @@ -1,249 +0,0 @@ - - * @since 2.0 - */ -abstract class BaseDataProvider extends Component implements DataProviderInterface -{ - /** - * @var string an ID that uniquely identifies the data provider among all data providers. - * You should set this property if the same page contains two or more different data providers. - * Otherwise, the [[pagination]] and [[sort]] mainly not work properly. - */ - public $id; - - private $_sort; - private $_pagination; - private $_keys; - private $_models; - private $_totalCount; - - - /** - * Prepares the data models that will be made available in the current page. - * @return array the available data models - */ - abstract protected function prepareModels(); - - /** - * Prepares the keys associated with the currently available data models. - * @param array $models the available data models - * @return array the keys - */ - abstract protected function prepareKeys($models); - - /** - * Returns a value indicating the total number of data models in this data provider. - * @return integer total number of data models in this data provider. - */ - abstract protected function prepareTotalCount(); - - /** - * Prepares the data models and keys. - * - * This method will prepare the data models and keys that can be retrieved via - * [[getModels()]] and [[getKeys()]]. - * - * This method will be implicitly called by [[getModels()]] and [[getKeys()]] if it has not been called before. - * - * @param boolean $forcePrepare whether to force data preparation even if it has been done before. - */ - public function prepare($forcePrepare = false) - { - if ($forcePrepare || $this->_models === null) { - $this->_models = $this->prepareModels(); - } - if ($forcePrepare || $this->_keys === null) { - $this->_keys = $this->prepareKeys($this->_models); - } - } - - /** - * Returns the data models in the current page. - * @return array the list of data models in the current page. - */ - public function getModels() - { - $this->prepare(); - return $this->_models; - } - - /** - * Sets the data models in the current page. - * @param array $models the models in the current page - */ - public function setModels($models) - { - $this->_models = $models; - } - - /** - * Returns the key values associated with the data models. - * @return array the list of key values corresponding to [[models]]. Each data model in [[models]] - * is uniquely identified by the corresponding key value in this array. - */ - public function getKeys() - { - $this->prepare(); - return $this->_keys; - } - - /** - * Sets the key values associated with the data models. - * @param array $keys the list of key values corresponding to [[models]]. - */ - public function setKeys($keys) - { - $this->_keys = $keys; - } - - /** - * Returns the number of data models in the current page. - * @return integer the number of data models in the current page. - */ - public function getCount() - { - return count($this->getModels()); - } - - /** - * Returns the total number of data models. - * When [[pagination]] is false, this returns the same value as [[count]]. - * Otherwise, it will call [[prepareTotalCount()]] to get the count. - * @return integer total number of possible data models. - */ - public function getTotalCount() - { - if ($this->getPagination() === false) { - return $this->getCount(); - } elseif ($this->_totalCount === null) { - $this->_totalCount = $this->prepareTotalCount(); - } - return $this->_totalCount; - } - - /** - * Sets the total number of data models. - * @param integer $value the total number of data models. - */ - public function setTotalCount($value) - { - $this->_totalCount = $value; - } - - /** - * Returns the pagination object used by this data provider. - * Note that you should call [[prepare()]] or [[getModels()]] first to get correct values - * of [[Pagination::totalCount]] and [[Pagination::pageCount]]. - * @return Pagination|boolean the pagination object. If this is false, it means the pagination is disabled. - */ - public function getPagination() - { - if ($this->_pagination === null) { - $this->setPagination([]); - } - return $this->_pagination; - } - - /** - * Sets the pagination for this data provider. - * @param array|Pagination|boolean $value the pagination to be used by this data provider. - * This can be one of the following: - * - * - a configuration array for creating the pagination object. The "class" element defaults - * to 'yii\data\Pagination' - * - an instance of [[Pagination]] or its subclass - * - false, if pagination needs to be disabled. - * - * @throws InvalidParamException - */ - public function setPagination($value) - { - if (is_array($value)) { - $config = ['class' => Pagination::className()]; - if ($this->id !== null) { - $config['pageVar'] = $this->id . '-page'; - } - $this->_pagination = Yii::createObject(array_merge($config, $value)); - } elseif ($value instanceof Pagination || $value === false) { - $this->_pagination = $value; - } else { - throw new InvalidParamException('Only Pagination instance, configuration array or false is allowed.'); - } - } - - /** - * @return Sort|boolean the sorting object. If this is false, it means the sorting is disabled. - */ - public function getSort() - { - if ($this->_sort === null) { - $this->setSort([]); - } - return $this->_sort; - } - - /** - * Sets the sort definition for this data provider. - * @param array|Sort|boolean $value the sort definition to be used by this data provider. - * This can be one of the following: - * - * - a configuration array for creating the sort definition object. The "class" element defaults - * to 'yii\data\Sort' - * - an instance of [[Sort]] or its subclass - * - false, if sorting needs to be disabled. - * - * @throws InvalidParamException - */ - public function setSort($value) - { - if (is_array($value)) { - $config = ['class' => Sort::className()]; - if ($this->id !== null) { - $config['sortVar'] = $this->id . '-sort'; - } - $this->_sort = Yii::createObject(array_merge($config, $value)); - } elseif ($value instanceof Sort || $value === false) { - $this->_sort = $value; - } else { - throw new InvalidParamException('Only Sort instance, configuration array or false is allowed.'); - } - } - - /** - * Refreshes the data provider. - * After calling this method, if [[getModels()]], [[getKeys()]] or [[getTotalCount()]] is called again, - * they will re-execute the query and return the latest data available. - */ - public function refresh() - { - $this->_totalCount = null; - $this->_models = null; - $this->_keys = null; - } -} diff --git a/framework/yii/data/DataProviderInterface.php b/framework/yii/data/DataProviderInterface.php deleted file mode 100644 index 1dea1e6..0000000 --- a/framework/yii/data/DataProviderInterface.php +++ /dev/null @@ -1,70 +0,0 @@ - - * @since 2.0 - */ -interface DataProviderInterface -{ - /** - * Prepares the data models and keys. - * - * This method will prepare the data models and keys that can be retrieved via - * [[getModels()]] and [[getKeys()]]. - * - * This method will be implicitly called by [[getModels()]] and [[getKeys()]] if it has not been called before. - * - * @param boolean $forcePrepare whether to force data preparation even if it has been done before. - */ - public function prepare($forcePrepare = false); - - /** - * Returns the number of data models in the current page. - * This is equivalent to `count($provider->getModels())`. - * When [[pagination]] is false, this is the same as [[totalCount]]. - * @return integer the number of data models in the current page. - */ - public function getCount(); - - /** - * Returns the total number of data models. - * When [[pagination]] is false, this is the same as [[count]]. - * @return integer total number of possible data models. - */ - public function getTotalCount(); - - /** - * Returns the data models in the current page. - * @return array the list of data models in the current page. - */ - public function getModels(); - - /** - * Returns the key values associated with the data models. - * @return array the list of key values corresponding to [[models]]. Each data model in [[models]] - * is uniquely identified by the corresponding key value in this array. - */ - public function getKeys(); - - /** - * @return Sort the sorting object. If this is false, it means the sorting is disabled. - */ - public function getSort(); - - /** - * @return Pagination the pagination object. If this is false, it means the pagination is disabled. - */ - public function getPagination(); -} diff --git a/framework/yii/data/Pagination.php b/framework/yii/data/Pagination.php deleted file mode 100644 index 8fa8b87..0000000 --- a/framework/yii/data/Pagination.php +++ /dev/null @@ -1,218 +0,0 @@ -where(['status' => 1]); - * $countQuery = clone $query; - * $pages = new Pagination(['totalCount' => $countQuery->count()]); - * $models = $query->offset($pages->offset) - * ->limit($pages->limit) - * ->all(); - * - * return $this->render('index', [ - * 'models' => $models, - * 'pages' => $pages, - * ]); - * } - * ~~~ - * - * View: - * - * ~~~ - * foreach ($models as $model) { - * // display $model here - * } - * - * // display pagination - * echo LinkPager::widget([ - * 'pagination' => $pages, - * ]); - * ~~~ - * - * @property integer $limit The limit of the data. This may be used to set the LIMIT value for a SQL statement - * for fetching the current page of data. Note that if the page size is infinite, a value -1 will be returned. - * This property is read-only. - * @property integer $offset The offset of the data. This may be used to set the OFFSET value for a SQL - * statement for fetching the current page of data. This property is read-only. - * @property integer $page The zero-based current page number. - * @property integer $pageCount Number of pages. This property is read-only. - * - * @author Qiang Xue - * @since 2.0 - */ -class Pagination extends Object -{ - /** - * @var string name of the parameter storing the current page index. Defaults to 'page'. - * @see params - */ - public $pageVar = 'page'; - /** - * @var boolean whether to always have the page parameter in the URL created by [[createUrl()]]. - * If false and [[page]] is 0, the page parameter will not be put in the URL. - */ - public $forcePageVar = true; - /** - * @var string the route of the controller action for displaying the paged contents. - * If not set, it means using the currently requested route. - */ - public $route; - /** - * @var array parameters (name => value) that should be used to obtain the current page number - * and to create new pagination URLs. If not set, all parameters from $_GET will be used instead. - * - * The array element indexed by [[pageVar]] is considered to be the current page number. - * If the element does not exist, the current page number is considered 0. - */ - public $params; - /** - * @var \yii\web\UrlManager the URL manager used for creating pagination URLs. If not set, - * the "urlManager" application component will be used. - */ - public $urlManager; - /** - * @var boolean whether to check if [[page]] is within valid range. - * When this property is true, the value of [[page]] will always be between 0 and ([[pageCount]]-1). - * Because [[pageCount]] relies on the correct value of [[totalCount]] which may not be available - * in some cases (e.g. MongoDB), you may want to set this property to be false to disable the page - * number validation. By doing so, [[page]] will return the value indexed by [[pageVar]] in [[params]]. - */ - public $validatePage = true; - /** - * @var integer number of items on each page. Defaults to 20. - * If it is less than 1, it means the page size is infinite, and thus a single page contains all items. - */ - public $pageSize = 20; - /** - * @var integer total number of items. - */ - public $totalCount = 0; - - - /** - * @return integer number of pages - */ - public function getPageCount() - { - if ($this->pageSize < 1) { - return $this->totalCount > 0 ? 1 : 0; - } else { - $totalCount = $this->totalCount < 0 ? 0 : (int)$this->totalCount; - return (int)(($totalCount + $this->pageSize - 1) / $this->pageSize); - } - } - - private $_page; - - /** - * Returns the zero-based current page number. - * @param boolean $recalculate whether to recalculate the current page based on the page size and item count. - * @return integer the zero-based current page number. - */ - public function getPage($recalculate = false) - { - if ($this->_page === null || $recalculate) { - if (($params = $this->params) === null) { - $request = Yii::$app->getRequest(); - $params = $request instanceof Request ? $request->get() : []; - } - if (isset($params[$this->pageVar]) && is_scalar($params[$this->pageVar])) { - $this->_page = (int)$params[$this->pageVar] - 1; - if ($this->validatePage) { - $pageCount = $this->getPageCount(); - if ($this->_page >= $pageCount) { - $this->_page = $pageCount - 1; - } - } - if ($this->_page < 0) { - $this->_page = 0; - } - } else { - $this->_page = 0; - } - } - return $this->_page; - } - - /** - * Sets the current page number. - * @param integer $value the zero-based index of the current page. - */ - public function setPage($value) - { - $this->_page = $value; - } - - /** - * Creates the URL suitable for pagination with the specified page number. - * This method is mainly called by pagers when creating URLs used to perform pagination. - * @param integer $page the zero-based page number that the URL should point to. - * @param boolean $absolute whether to create an absolute URL. Defaults to `false`. - * @return string the created URL - * @see params - * @see forcePageVar - */ - public function createUrl($page, $absolute = false) - { - if (($params = $this->params) === null) { - $request = Yii::$app->getRequest(); - $params = $request instanceof Request ? $request->get() : []; - } - if ($page > 0 || $page >= 0 && $this->forcePageVar) { - $params[$this->pageVar] = $page + 1; - } else { - unset($params[$this->pageVar]); - } - $route = $this->route === null ? Yii::$app->controller->getRoute() : $this->route; - $urlManager = $this->urlManager === null ? Yii::$app->getUrlManager() : $this->urlManager; - if ($absolute) { - return $urlManager->createAbsoluteUrl($route, $params); - } else { - return $urlManager->createUrl($route, $params); - } - } - - /** - * @return integer the offset of the data. This may be used to set the - * OFFSET value for a SQL statement for fetching the current page of data. - */ - public function getOffset() - { - return $this->pageSize < 1 ? 0 : $this->getPage() * $this->pageSize; - } - - /** - * @return integer the limit of the data. This may be used to set the - * LIMIT value for a SQL statement for fetching the current page of data. - * Note that if the page size is infinite, a value -1 will be returned. - */ - public function getLimit() - { - return $this->pageSize < 1 ? -1 : $this->pageSize; - } -} diff --git a/framework/yii/data/Sort.php b/framework/yii/data/Sort.php deleted file mode 100644 index 0432006..0000000 --- a/framework/yii/data/Sort.php +++ /dev/null @@ -1,398 +0,0 @@ - [ - * 'age', - * 'name' => [ - * 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - * 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - * 'default' => SORT_DESC, - * 'label' => 'Name', - * ], - * ], - * ]); - * - * $models = Article::find() - * ->where(['status' => 1]) - * ->orderBy($sort->orders) - * ->all(); - * - * return $this->render('index', [ - * 'models' => $models, - * 'sort' => $sort, - * ]); - * } - * ~~~ - * - * View: - * - * ~~~ - * // display links leading to sort actions - * echo $sort->link('name') . ' | ' . $sort->link('age'); - * - * foreach ($models as $model) { - * // display $model here - * } - * ~~~ - * - * In the above, we declare two [[attributes]] that support sorting: name and age. - * We pass the sort information to the Article query so that the query results are - * sorted by the orders specified by the Sort object. In the view, we show two hyperlinks - * that can lead to pages with the data sorted by the corresponding attributes. - * - * @property array $attributeOrders Sort directions indexed by attribute names. Sort direction can be either - * `SORT_ASC` for ascending order or `SORT_DESC` for descending order. This property is read-only. - * @property array $orders The columns (keys) and their corresponding sort directions (values). This can be - * passed to [[\yii\db\Query::orderBy()]] to construct a DB query. This property is read-only. - * - * @author Qiang Xue - * @since 2.0 - */ -class Sort extends Object -{ - /** - * @var boolean whether the sorting can be applied to multiple attributes simultaneously. - * Defaults to false, which means each time the data can only be sorted by one attribute. - */ - public $enableMultiSort = false; - - /** - * @var array list of attributes that are allowed to be sorted. Its syntax can be - * described using the following example: - * - * ~~~ - * [ - * 'age', - * 'name' => [ - * 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - * 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - * 'default' => SORT_DESC, - * 'label' => 'Name', - * ], - * ] - * ~~~ - * - * In the above, two attributes are declared: "age" and "user". The "age" attribute is - * a simple attribute which is equivalent to the following: - * - * ~~~ - * 'age' => [ - * 'asc' => ['age' => SORT_ASC], - * 'desc' => ['age' => SORT_DESC], - * 'default' => SORT_ASC, - * 'label' => Inflector::camel2words('age'), - * ] - * ~~~ - * - * The "user" attribute is a composite attribute: - * - * - The "user" key represents the attribute name which will appear in the URLs leading - * to sort actions. Attribute names cannot contain characters listed in [[separators]]. - * - The "asc" and "desc" elements specify how to sort by the attribute in ascending - * and descending orders, respectively. Their values represent the actual columns and - * the directions by which the data should be sorted by. - * - The "default" element specifies by which direction the attribute should be sorted - * if it is not currently sorted (the default value is ascending order). - * - The "label" element specifies what label should be used when calling [[link()]] to create - * a sort link. If not set, [[Inflector::camel2words()]] will be called to get a label. - * Note that it will not be HTML-encoded. - * - * Note that if the Sort object is already created, you can only use the full format - * to configure every attribute. Each attribute must include these elements: asc and desc. - */ - public $attributes = []; - /** - * @var string the name of the parameter that specifies which attributes to be sorted - * in which direction. Defaults to 'sort'. - * @see params - */ - public $sortVar = 'sort'; - /** - * @var string the tag appeared in the [[sortVar]] parameter that indicates the attribute should be sorted - * in descending order. Defaults to 'desc'. - */ - public $descTag = 'desc'; - /** - * @var array the order that should be used when the current request does not specify any order. - * The array keys are attribute names and the array values are the corresponding sort directions. For example, - * - * ~~~ - * [ - * 'name' => SORT_ASC, - * 'create_time' => SORT_DESC, - * ] - * ~~~ - * - * @see attributeOrders - */ - public $defaultOrder; - /** - * @var string the route of the controller action for displaying the sorted contents. - * If not set, it means using the currently requested route. - */ - public $route; - /** - * @var array separators used in the generated URL. This must be an array consisting of - * two elements. The first element specifies the character separating different - * attributes, while the second element specifies the character separating attribute name - * and the corresponding sort direction. Defaults to `['.', '-']`. - */ - public $separators = ['.', '-']; - /** - * @var array parameters (name => value) that should be used to obtain the current sort directions - * and to create new sort URLs. If not set, $_GET will be used instead. - * - * The array element indexed by [[sortVar]] is considered to be the current sort directions. - * If the element does not exist, the [[defaults|default order]] will be used. - * - * @see sortVar - * @see defaultOrder - */ - public $params; - /** - * @var \yii\web\UrlManager the URL manager used for creating sort URLs. If not set, - * the "urlManager" application component will be used. - */ - public $urlManager; - - /** - * Normalizes the [[attributes]] property. - */ - public function init() - { - $attributes = []; - foreach ($this->attributes as $name => $attribute) { - if (!is_array($attribute)) { - $attributes[$attribute] = [ - 'asc' => [$attribute => SORT_ASC], - 'desc' => [$attribute => SORT_DESC], - ]; - } elseif (!isset($attribute['asc'], $attribute['desc'])) { - $attributes[$name] = array_merge([ - 'asc' => [$name => SORT_ASC], - 'desc' => [$name => SORT_DESC], - ], $attribute); - } else { - $attributes[$name] = $attribute; - } - } - $this->attributes = $attributes; - } - - /** - * Returns the columns and their corresponding sort directions. - * @param boolean $recalculate whether to recalculate the sort directions - * @return array the columns (keys) and their corresponding sort directions (values). - * This can be passed to [[\yii\db\Query::orderBy()]] to construct a DB query. - */ - public function getOrders($recalculate = false) - { - $attributeOrders = $this->getAttributeOrders($recalculate); - $orders = []; - foreach ($attributeOrders as $attribute => $direction) { - $definition = $this->attributes[$attribute]; - $columns = $definition[$direction === SORT_ASC ? 'asc' : 'desc']; - foreach ($columns as $name => $dir) { - $orders[$name] = $dir; - } - } - return $orders; - } - - /** - * @var array the currently requested sort order as computed by [[getAttributeOrders]]. - */ - private $_attributeOrders; - - /** - * Returns the currently requested sort information. - * @param boolean $recalculate whether to recalculate the sort directions - * @return array sort directions indexed by attribute names. - * Sort direction can be either `SORT_ASC` for ascending order or - * `SORT_DESC` for descending order. - */ - public function getAttributeOrders($recalculate = false) - { - if ($this->_attributeOrders === null || $recalculate) { - $this->_attributeOrders = []; - if (($params = $this->params) === null) { - $request = Yii::$app->getRequest(); - $params = $request instanceof Request ? $request->get() : []; - } - if (isset($params[$this->sortVar]) && is_scalar($params[$this->sortVar])) { - $attributes = explode($this->separators[0], $params[$this->sortVar]); - foreach ($attributes as $attribute) { - $descending = false; - if (($pos = strrpos($attribute, $this->separators[1])) !== false) { - if ($descending = (substr($attribute, $pos + 1) === $this->descTag)) { - $attribute = substr($attribute, 0, $pos); - } - } - - if (isset($this->attributes[$attribute])) { - $this->_attributeOrders[$attribute] = $descending ? SORT_DESC : SORT_ASC; - if (!$this->enableMultiSort) { - return $this->_attributeOrders; - } - } - } - } - if (empty($this->_attributeOrders) && is_array($this->defaultOrder)) { - $this->_attributeOrders = $this->defaultOrder; - } - } - return $this->_attributeOrders; - } - - /** - * Returns the sort direction of the specified attribute in the current request. - * @param string $attribute the attribute name - * @return boolean|null Sort direction of the attribute. Can be either `SORT_ASC` - * for ascending order or `SORT_DESC` for descending order. Null is returned - * if the attribute is invalid or does not need to be sorted. - */ - public function getAttributeOrder($attribute) - { - $orders = $this->getAttributeOrders(); - return isset($orders[$attribute]) ? $orders[$attribute] : null; - } - - /** - * Generates a hyperlink that links to the sort action to sort by the specified attribute. - * Based on the sort direction, the CSS class of the generated hyperlink will be appended - * with "asc" or "desc". - * @param string $attribute the attribute name by which the data should be sorted by. - * @param array $options additional HTML attributes for the hyperlink tag. - * There is one special attribute `label` which will be used as the label of the hyperlink. - * If this is not set, the label defined in [[attributes]] will be used. - * If no label is defined, [[yii\helpers\Inflector::camel2words()]] will be called to get a label. - * Note that it will not be HTML-encoded. - * @return string the generated hyperlink - * @throws InvalidConfigException if the attribute is unknown - */ - public function link($attribute, $options = []) - { - if (($direction = $this->getAttributeOrder($attribute)) !== null) { - $class = $direction === SORT_DESC ? 'desc' : 'asc'; - if (isset($options['class'])) { - $options['class'] .= ' ' . $class; - } else { - $options['class'] = $class; - } - } - - $url = $this->createUrl($attribute); - $options['data-sort'] = $this->createSortVar($attribute); - - if (isset($options['label'])) { - $label = $options['label']; - unset($options['label']); - } else { - if (isset($this->attributes[$attribute]['label'])) { - $label = $this->attributes[$attribute]['label']; - } else { - $label = Inflector::camel2words($attribute); - } - } - return Html::a($label, $url, $options); - } - - /** - * Creates a URL for sorting the data by the specified attribute. - * This method will consider the current sorting status given by [[attributeOrders]]. - * For example, if the current page already sorts the data by the specified attribute in ascending order, - * then the URL created will lead to a page that sorts the data by the specified attribute in descending order. - * @param string $attribute the attribute name - * @param boolean $absolute whether to create an absolute URL. Defaults to `false`. - * @return string the URL for sorting. False if the attribute is invalid. - * @throws InvalidConfigException if the attribute is unknown - * @see attributeOrders - * @see params - */ - public function createUrl($attribute, $absolute = false) - { - if (($params = $this->params) === null) { - $request = Yii::$app->getRequest(); - $params = $request instanceof Request ? $request->get() : []; - } - $params[$this->sortVar] = $this->createSortVar($attribute); - $route = $this->route === null ? Yii::$app->controller->getRoute() : $this->route; - $urlManager = $this->urlManager === null ? Yii::$app->getUrlManager() : $this->urlManager; - if ($absolute) { - return $urlManager->createAbsoluteUrl($route, $params); - } else { - return $urlManager->createUrl($route, $params); - } - } - - /** - * Creates the sort variable for the specified attribute. - * The newly created sort variable can be used to create a URL that will lead to - * sorting by the specified attribute. - * @param string $attribute the attribute name - * @return string the value of the sort variable - * @throws InvalidConfigException if the specified attribute is not defined in [[attributes]] - */ - public function createSortVar($attribute) - { - if (!isset($this->attributes[$attribute])) { - throw new InvalidConfigException("Unknown attribute: $attribute"); - } - $definition = $this->attributes[$attribute]; - $directions = $this->getAttributeOrders(); - if (isset($directions[$attribute])) { - $direction = $directions[$attribute] === SORT_DESC ? SORT_ASC : SORT_DESC; - unset($directions[$attribute]); - } else { - $direction = isset($definition['default']) ? $definition['default'] : SORT_ASC; - } - - if ($this->enableMultiSort) { - $directions = array_merge([$attribute => $direction], $directions); - } else { - $directions = [$attribute => $direction]; - } - - $sorts = []; - foreach ($directions as $attribute => $direction) { - $sorts[] = $direction === SORT_DESC ? $attribute . $this->separators[1] . $this->descTag : $attribute; - } - return implode($this->separators[0], $sorts); - } - - /** - * Returns a value indicating whether the sort definition supports sorting by the named attribute. - * @param string $name the attribute name - * @return boolean whether the sort definition supports sorting by the named attribute. - */ - public function hasAttribute($name) - { - return isset($this->attributes[$name]); - } -} diff --git a/framework/yii/data/SqlDataProvider.php b/framework/yii/data/SqlDataProvider.php deleted file mode 100644 index 5517aa1..0000000 --- a/framework/yii/data/SqlDataProvider.php +++ /dev/null @@ -1,159 +0,0 @@ -db->createCommand(' - * SELECT COUNT(*) FROM tbl_user WHERE status=:status - * ', [':status' => 1])->queryScalar(); - * - * $dataProvider = new SqlDataProvider([ - * 'sql' => 'SELECT * FROM tbl_user WHERE status=:status', - * 'params' => [':status' => 1], - * 'totalCount' => $count, - * 'sort' => [ - * 'attributes' => [ - * 'age', - * 'name' => [ - * 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - * 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - * 'default' => SORT_DESC, - * 'label' => 'Name', - * ], - * ], - * ], - * 'pagination' => [ - * 'pageSize' => 20, - * ], - * ]); - * - * // get the user records in the current page - * $models = $dataProvider->getModels(); - * ~~~ - * - * Note: if you want to use the pagination feature, you must configure the [[totalCount]] property - * to be the total number of rows (without pagination). And if you want to use the sorting feature, - * you must configure the [[sort]] property so that the provider knows which columns can be sorted. - * - * @author Qiang Xue - * @since 2.0 - */ -class SqlDataProvider extends BaseDataProvider -{ - /** - * @var Connection|string the DB connection object or the application component ID of the DB connection. - */ - public $db = 'db'; - /** - * @var string the SQL statement to be used for fetching data rows. - */ - public $sql; - /** - * @var array parameters (name=>value) to be bound to the SQL statement. - */ - public $params = []; - /** - * @var string|callable the column that is used as the key of the data models. - * This can be either a column name, or a callable that returns the key value of a given data model. - * - * If this is not set, the keys of the [[models]] array will be used. - */ - public $key; - - - /** - * Initializes the DB connection component. - * This method will initialize the [[db]] property to make sure it refers to a valid DB connection. - * @throws InvalidConfigException if [[db]] is invalid. - */ - public function init() - { - parent::init(); - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - } - if (!$this->db instanceof Connection) { - throw new InvalidConfigException('The "db" property must be a valid DB Connection application component.'); - } - if ($this->sql === null) { - throw new InvalidConfigException('The "sql" property must be set.'); - } - } - - /** - * @inheritdoc - */ - protected function prepareModels() - { - $sql = $this->sql; - $qb = $this->db->getQueryBuilder(); - if (($sort = $this->getSort()) !== false) { - $orderBy = $qb->buildOrderBy($sort->getOrders()); - if (!empty($orderBy)) { - $orderBy = substr($orderBy, 9); - if (preg_match('/\s+order\s+by\s+[\w\s,\.]+$/i', $sql)) { - $sql .= ', ' . $orderBy; - } else { - $sql .= ' ORDER BY ' . $orderBy; - } - } - } - - if (($pagination = $this->getPagination()) !== false) { - $pagination->totalCount = $this->getTotalCount(); - $sql .= ' ' . $qb->buildLimit($pagination->getLimit(), $pagination->getOffset()); - } - - return $this->db->createCommand($sql, $this->params)->queryAll(); - } - - /** - * @inheritdoc - */ - protected function prepareKeys($models) - { - $keys = []; - if ($this->key !== null) { - foreach ($models as $model) { - if (is_string($this->key)) { - $keys[] = $model[$this->key]; - } else { - $keys[] = call_user_func($this->key, $model); - } - } - return $keys; - } else { - return array_keys($models); - } - } - - /** - * @inheritdoc - */ - protected function prepareTotalCount() - { - return 0; - } -} diff --git a/framework/yii/db/ActiveQuery.php b/framework/yii/db/ActiveQuery.php deleted file mode 100644 index e7e76cb..0000000 --- a/framework/yii/db/ActiveQuery.php +++ /dev/null @@ -1,427 +0,0 @@ - - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\db; - -/** - * ActiveQuery represents a DB query associated with an Active Record class. - * - * ActiveQuery instances are usually created by [[ActiveRecord::find()]] and [[ActiveRecord::findBySql()]]. - * - * ActiveQuery mainly provides the following methods to retrieve the query results: - * - * - [[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. - * - [[sum()]]: returns the sum over the specified column. - * - [[average()]]: returns the average over the specified column. - * - [[min()]]: returns the min over the specified column. - * - [[max()]]: returns the max over the specified column. - * - [[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. - * - * Because ActiveQuery extends from [[Query]], one can use query methods, such as [[where()]], - * [[orderBy()]] to customize the query options. - * - * ActiveQuery also provides the following additional query options: - * - * - [[with()]]: list of relations that this query should be performed with. - * - [[indexBy()]]: the name of the column by which the query result should be indexed. - * - [[asArray()]]: whether to return each record as an array. - * - * These options can be configured using methods of the same name. For example: - * - * ~~~ - * $customers = Customer::find()->with('orders')->asArray()->all(); - * ~~~ - * - * @author Qiang Xue - * @author Carsten Brandt - * @since 2.0 - */ -class ActiveQuery extends Query implements ActiveQueryInterface -{ - use ActiveQueryTrait; - - /** - * @var string the SQL statement to be executed for retrieving AR records. - * This is set by [[ActiveRecord::findBySql()]]. - */ - public $sql; - - - /** - * 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) - { - $command = $this->createCommand($db); - $rows = $command->queryAll(); - if (!empty($rows)) { - $models = $this->createModels($rows); - if (!empty($this->join) && $this->indexBy === null) { - $models = $this->removeDuplicatedModels($models); - } - if (!empty($this->with)) { - $this->findWith($this->with, $models); - } - return $models; - } else { - return []; - } - } - - /** - * Removes duplicated models by checking their primary key values. - * This method is mainly called when a join query is performed, which may cause duplicated rows being returned. - * @param array $models the models to be checked - * @return array the distinctive models - */ - private function removeDuplicatedModels($models) - { - $hash = []; - /** @var ActiveRecord $class */ - $class = $this->modelClass; - $pks = $class::primaryKey(); - - if (count($pks) > 1) { - foreach ($models as $i => $model) { - $key = []; - foreach ($pks as $pk) { - $key[] = $model[$pk]; - } - $key = serialize($key); - if (isset($hash[$key])) { - unset($models[$i]); - } else { - $hash[$key] = true; - } - } - } else { - $pk = reset($pks); - foreach ($models as $i => $model) { - $key = $model[$pk]; - if (isset($hash[$key])) { - unset($models[$i]); - } else { - $hash[$key] = true; - } - } - } - - return array_values($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) - { - $command = $this->createCommand($db); - $row = $command->queryOne(); - if ($row !== false) { - if ($this->asArray) { - $model = $row; - } else { - /** @var ActiveRecord $class */ - $class = $this->modelClass; - $model = $class::create($row); - } - if (!empty($this->with)) { - $models = [$model]; - $this->findWith($this->with, $models); - $model = $models[0]; - } - return $model; - } else { - return null; - } - } - - /** - * 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->sql === null) { - $select = $this->select; - $from = $this->from; - - if ($this->from === null) { - $tableName = $modelClass::tableName(); - if ($this->select === null && !empty($this->join)) { - $this->select = ["$tableName.*"]; - } - $this->from = [$tableName]; - } - list ($sql, $params) = $db->getQueryBuilder()->build($this); - - $this->select = $select; - $this->from = $from; - } else { - $sql = $this->sql; - $params = $this->params; - } - return $db->createCommand($sql, $params); - } - - /** - * Joins with the specified relations. - * - * This method allows you to reuse existing relation definitions to perform JOIN queries. - * Based on the definition of the specified relation(s), the method will append one or multiple - * JOIN statements to the current query. - * - * If the `$eagerLoading` parameter is true, the method will also eager loading the specified relations, - * which is equivalent to calling [[with()]] using the specified relations. - * - * Note that because a JOIN query will be performed, you are responsible to disambiguate column names. - * - * This method differs from [[with()]] in that it will build up and execute a JOIN SQL statement - * for the primary table. And when `$eagerLoading` is true, it will call [[with()]] in addition with the specified relations. - * - * @param array $with the relations to be joined. Each array element represents a single relation. - * The array keys are relation names, and the array values are the corresponding anonymous functions that - * can be used to modify the relation queries on-the-fly. If a relation query does not need modification, - * you may use the relation name as the array value. Sub-relations can also be specified (see [[with()]]). - * For example, - * - * ```php - * // find all orders that contain books, and eager loading "books" - * Order::find()->joinWith('books', true, 'INNER JOIN')->all(); - * // find all orders, eager loading "books", and sort the orders and books by the book names. - * Order::find()->joinWith([ - * 'books' => function ($query) { - * $query->orderBy('tbl_item.name'); - * } - * ])->all(); - * ``` - * - * @param boolean|array $eagerLoading whether to eager load the relations specified in `$with`. - * When this is a boolean, it applies to all relations specified in `$with`. Use an array - * to explicitly list which relations in `$with` need to be eagerly loaded. - * @param string|array $joinType the join type of the relations specified in `$with`. - * When this is a string, it applies to all relations specified in `$with`. Use an array - * in the format of `relationName => joinType` to specify different join types for different relations. - * @return static the query object itself - */ - public function joinWith($with, $eagerLoading = true, $joinType = 'LEFT JOIN') - { - $with = (array)$with; - $this->joinWithRelations(new $this->modelClass, $with, $joinType); - - if (is_array($eagerLoading)) { - foreach ($with as $name => $callback) { - if (is_integer($name)) { - if (!in_array($callback, $eagerLoading, true)) { - unset($with[$name]); - } - } elseif (!in_array($name, $eagerLoading, true)) { - unset($with[$name]); - } - } - } elseif (!$eagerLoading) { - $with = []; - } - - return $this->with($with); - } - - /** - * Inner joins with the specified relations. - * This is a shortcut method to [[joinWith()]] with the join type set as "INNER JOIN". - * Please refer to [[joinWith()]] for detailed usage of this method. - * @param array $with the relations to be joined with - * @param boolean|array $eagerLoading whether to eager loading the relations - * @return static the query object itself - * @see joinWith() - */ - public function innerJoinWith($with, $eagerLoading = true) - { - return $this->joinWith($with, $eagerLoading, 'INNER JOIN'); - } - - /** - * Modifies the current query by adding join fragments based on the given relations. - * @param ActiveRecord $model the primary model - * @param array $with the relations to be joined - * @param string|array $joinType the join type - */ - private function joinWithRelations($model, $with, $joinType) - { - $relations = []; - - foreach ($with as $name => $callback) { - if (is_integer($name)) { - $name = $callback; - $callback = null; - } - - $primaryModel = $model; - $parent = $this; - $prefix = ''; - while (($pos = strpos($name, '.')) !== false) { - $childName = substr($name, $pos + 1); - $name = substr($name, 0, $pos); - $fullName = $prefix === '' ? $name : "$prefix.$name"; - if (!isset($relations[$fullName])) { - $relations[$fullName] = $relation = $primaryModel->getRelation($name); - $this->joinWithRelation($parent, $relation, $this->getJoinType($joinType, $fullName)); - } else { - $relation = $relations[$fullName]; - } - $primaryModel = new $relation->modelClass; - $parent = $relation; - $prefix = $fullName; - $name = $childName; - } - - $fullName = $prefix === '' ? $name : "$prefix.$name"; - if (!isset($relations[$fullName])) { - $relations[$fullName] = $relation = $primaryModel->getRelation($name); - if ($callback !== null) { - call_user_func($callback, $relation); - } - $this->joinWithRelation($parent, $relation, $this->getJoinType($joinType, $fullName)); - } - } - } - - /** - * Returns the join type based on the given join type parameter and the relation name. - * @param string|array $joinType the given join type(s) - * @param string $name relation name - * @return string the real join type - */ - private function getJoinType($joinType, $name) - { - if (is_array($joinType) && isset($joinType[$name])) { - return $joinType[$name]; - } else { - return is_string($joinType) ? $joinType : 'INNER JOIN'; - } - } - - /** - * Returns the table name and the table alias for [[modelClass]]. - * @param ActiveQuery $query - * @return array the table name and the table alias. - */ - private function getQueryTableName($query) - { - if (empty($query->from)) { - /** @var ActiveRecord $modelClass */ - $modelClass = $query->modelClass; - $tableName = $modelClass::tableName(); - } else { - $tableName = reset($query->from); - } - - if (preg_match('/^(.*?)\s+({{\w+}}|\w+)$/', $tableName, $matches)) { - $alias = $matches[2]; - } else { - $alias = $tableName; - } - - return [$tableName, $alias]; - } - - /** - * Joins a parent query with a child query. - * The current query object will be modified accordingly. - * @param ActiveQuery $parent - * @param ActiveRelation $child - * @param string $joinType - */ - private function joinWithRelation($parent, $child, $joinType) - { - $via = $child->via; - $child->via = null; - if ($via instanceof ActiveRelation) { - // via table - $this->joinWithRelation($parent, $via, $joinType); - $this->joinWithRelation($via, $child, $joinType); - return; - } elseif (is_array($via)) { - // via relation - $this->joinWithRelation($parent, $via[1], $joinType); - $this->joinWithRelation($via[1], $child, $joinType); - return; - } - - list ($parentTable, $parentAlias) = $this->getQueryTableName($parent); - list ($childTable, $childAlias) = $this->getQueryTableName($child); - - if (!empty($child->link)) { - - if (strpos($parentAlias, '{{') === false) { - $parentAlias = '{{' . $parentAlias . '}}'; - } - if (strpos($childAlias, '{{') === false) { - $childAlias = '{{' . $childAlias . '}}'; - } - - $on = []; - foreach ($child->link as $childColumn => $parentColumn) { - $on[] = "$parentAlias.[[$parentColumn]] = $childAlias.[[$childColumn]]"; - } - $on = implode(' AND ', $on); - if (!empty($child->on)) { - $on = ['and', $on, $child->on]; - } - } else { - $on = $child->on; - } - $this->join($joinType, $childTable, $on); - - - if (!empty($child->where)) { - $this->andWhere($child->where); - } - if (!empty($child->having)) { - $this->andHaving($child->having); - } - if (!empty($child->orderBy)) { - $this->addOrderBy($child->orderBy); - } - if (!empty($child->groupBy)) { - $this->addGroupBy($child->groupBy); - } - if (!empty($child->params)) { - $this->addParams($child->params); - } - if (!empty($child->join)) { - foreach ($child->join as $join) { - $this->join[] = $join; - } - } - if (!empty($child->union)) { - foreach ($child->union as $union) { - $this->union[] = $union; - } - } - } -} diff --git a/framework/yii/db/ActiveQueryInterface.php b/framework/yii/db/ActiveQueryInterface.php deleted file mode 100644 index a2e132f..0000000 --- a/framework/yii/db/ActiveQueryInterface.php +++ /dev/null @@ -1,77 +0,0 @@ - - * @author Carsten Brandt - * @since 2.0 - */ -interface ActiveQueryInterface extends QueryInterface -{ - /** - * Sets the [[asArray]] property. - * @param boolean $value whether to return the query results in terms of arrays instead of Active Records. - * @return static the query object itself - */ - public function asArray($value = true); - - /** - * Sets the [[indexBy]] property. - * @param string|callable $column the name of the column by which the query results should be indexed by. - * This can also be a callable (e.g. anonymous function) that returns the index value based on the given - * row or model data. The signature of the callable should be: - * - * ~~~ - * // $model is an AR instance when `asArray` is false, - * // or an array of column values when `asArray` is true. - * function ($model) - * { - * // return the index value corresponding to $model - * } - * ~~~ - * - * @return static the query object itself - */ - public function indexBy($column); - - /** - * Specifies the relations with which this query should be performed. - * - * The parameters to this method can be either one or multiple strings, or a single array - * of relation names and the optional callbacks to customize the relations. - * - * A relation name can refer to a relation defined in [[modelClass]] - * or a sub-relation that stands for a relation of a related record. - * For example, `orders.address` means the `address` relation defined - * in the model class corresponding to the `orders` relation. - * - * The followings are some usage examples: - * - * ~~~ - * // find customers together with their orders and country - * Customer::find()->with('orders', 'country')->all(); - * // find customers together with their orders and the orders' shipping address - * Customer::find()->with('orders.address')->all(); - * // find customers together with their country and orders of status 1 - * Customer::find()->with([ - * 'orders' => function($query) { - * $query->andWhere('status = 1'); - * }, - * 'country', - * ])->all(); - * ~~~ - * - * @return static the query object itself - */ - public function with(); -} diff --git a/framework/yii/db/ActiveQueryTrait.php b/framework/yii/db/ActiveQueryTrait.php deleted file mode 100644 index 465c1f3..0000000 --- a/framework/yii/db/ActiveQueryTrait.php +++ /dev/null @@ -1,228 +0,0 @@ - - * @author Carsten Brandt - * @since 2.0 - */ -trait ActiveQueryTrait -{ - /** - * @var string the name of the ActiveRecord class. - */ - public $modelClass; - /** - * @var array a list of relations that this query should be performed with - */ - public $with; - /** - * @var boolean whether to return each record as an array. If false (default), an object - * of [[modelClass]] will be created to represent each record. - */ - public $asArray; - - - /** - * PHP magic method. - * This method allows calling static method defined in [[modelClass]] via this query object. - * It is mainly implemented for supporting the feature of scope. - * @param string $name the method name to be called - * @param array $params the parameters passed to the method - * @return mixed the method return result - */ - public function __call($name, $params) - { - if (method_exists($this->modelClass, $name)) { - $method = new \ReflectionMethod($this->modelClass, $name); - if (!$method->isStatic() || !$method->isPublic()) { - throw new InvalidCallException("The scope method \"{$this->modelClass}::$name()\" must be public and static."); - } - array_unshift($params, $this); - call_user_func_array([$this->modelClass, $name], $params); - return $this; - } else { - return parent::__call($name, $params); - } - } - - /** - * Sets the [[asArray]] property. - * @param boolean $value whether to return the query results in terms of arrays instead of Active Records. - * @return static the query object itself - */ - public function asArray($value = true) - { - $this->asArray = $value; - return $this; - } - - /** - * Specifies the relations with which this query should be performed. - * - * The parameters to this method can be either one or multiple strings, or a single array - * of relation names and the optional callbacks to customize the relations. - * - * A relation name can refer to a relation defined in [[modelClass]] - * or a sub-relation that stands for a relation of a related record. - * For example, `orders.address` means the `address` relation defined - * in the model class corresponding to the `orders` relation. - * - * The followings are some usage examples: - * - * ~~~ - * // find customers together with their orders and country - * Customer::find()->with('orders', 'country')->all(); - * // find customers together with their orders and the orders' shipping address - * Customer::find()->with('orders.address')->all(); - * // find customers together with their country and orders of status 1 - * Customer::find()->with([ - * 'orders' => function($query) { - * $query->andWhere('status = 1'); - * }, - * 'country', - * ])->all(); - * ~~~ - * - * You can call `with()` multiple times. Each call will add relations to the existing ones. - * For example, the following two statements are equivalent: - * - * ~~~ - * Customer::find()->with('orders', 'country')->all(); - * Customer::find()->with('orders')->with('country')->all(); - * ~~~ - * - * @return static the query object itself - */ - public function with() - { - $with = func_get_args(); - if (isset($with[0]) && is_array($with[0])) { - // the parameter is given as an array - $with = $with[0]; - } - - if (empty($this->with)) { - $this->with = $with; - } elseif (!empty($with)) { - foreach ($with as $name => $value) { - if (is_integer($name)) { - // repeating relation is fine as normalizeRelations() handle it well - $this->with[] = $value; - } else { - $this->with[$name] = $value; - } - } - } - - return $this; - } - - /** - * Converts found rows into model instances - * @param array $rows - * @return array|ActiveRecord[] - */ - private function createModels($rows) - { - $models = []; - if ($this->asArray) { - if ($this->indexBy === null) { - return $rows; - } - foreach ($rows as $row) { - if (is_string($this->indexBy)) { - $key = $row[$this->indexBy]; - } else { - $key = call_user_func($this->indexBy, $row); - } - $models[$key] = $row; - } - } else { - /** @var ActiveRecord $class */ - $class = $this->modelClass; - if ($this->indexBy === null) { - foreach ($rows as $row) { - $models[] = $class::create($row); - } - } else { - foreach ($rows as $row) { - $model = $class::create($row); - if (is_string($this->indexBy)) { - $key = $model->{$this->indexBy}; - } else { - $key = call_user_func($this->indexBy, $model); - } - $models[$key] = $model; - } - } - } - return $models; - } - - /** - * Finds records corresponding to one or multiple relations and populates them into the primary models. - * @param array $with a list of relations that this query should be performed with. Please - * refer to [[with()]] for details about specifying this parameter. - * @param array $models the primary models (can be either AR instances or arrays) - */ - public function findWith($with, &$models) - { - $primaryModel = new $this->modelClass; - $relations = $this->normalizeRelations($primaryModel, $with); - foreach ($relations as $name => $relation) { - if ($relation->asArray === null) { - // inherit asArray from primary query - $relation->asArray = $this->asArray; - } - $relation->populateRelation($name, $models); - } - } - - /** - * @param ActiveRecord $model - * @param array $with - * @return ActiveRelationInterface[] - */ - private function normalizeRelations($model, $with) - { - $relations = []; - foreach ($with as $name => $callback) { - if (is_integer($name)) { - $name = $callback; - $callback = null; - } - if (($pos = strpos($name, '.')) !== false) { - // with sub-relations - $childName = substr($name, $pos + 1); - $name = substr($name, 0, $pos); - } else { - $childName = null; - } - - if (!isset($relations[$name])) { - $relation = $model->getRelation($name); - $relation->primaryModel = null; - $relations[$name] = $relation; - } else { - $relation = $relations[$name]; - } - - if (isset($childName)) { - $relation->with[$childName] = $callback; - } elseif ($callback !== null) { - call_user_func($callback, $relation); - } - } - return $relations; - } -} diff --git a/framework/yii/db/ActiveRecord.php b/framework/yii/db/ActiveRecord.php deleted file mode 100644 index 28454b6..0000000 --- a/framework/yii/db/ActiveRecord.php +++ /dev/null @@ -1,534 +0,0 @@ - - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\db; - -use yii\base\InvalidConfigException; -use yii\helpers\Inflector; -use yii\helpers\StringHelper; - -/** - * ActiveRecord is the base class for classes representing relational data in terms of objects. - * - * @include @yii/db/ActiveRecord.md - * - * @author Qiang Xue - * @author Carsten Brandt - * @since 2.0 - */ -class ActiveRecord extends BaseActiveRecord -{ - /** - * The insert operation. This is mainly used when overriding [[transactions()]] to specify which operations are transactional. - */ - const OP_INSERT = 0x01; - /** - * The update operation. This is mainly used when overriding [[transactions()]] to specify which operations are transactional. - */ - const OP_UPDATE = 0x02; - /** - * The delete operation. This is mainly used when overriding [[transactions()]] to specify which operations are transactional. - */ - const OP_DELETE = 0x04; - /** - * All three operations: insert, update, delete. - * This is a shortcut of the expression: OP_INSERT | OP_UPDATE | OP_DELETE. - */ - const OP_ALL = 0x07; - - /** - * Returns the database connection used by this AR class. - * By default, the "db" 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->getDb(); - } - - /** - * Creates an [[ActiveQuery]] instance with a given SQL statement. - * - * Note that because the SQL statement is already specified, calling additional - * query modification methods (such as `where()`, `order()`) on the created [[ActiveQuery]] - * instance will have no effect. However, calling `with()`, `asArray()` or `indexBy()` is - * still fine. - * - * Below is an example: - * - * ~~~ - * $customers = Customer::findBySql('SELECT * FROM tbl_customer')->all(); - * ~~~ - * - * @param string $sql the SQL statement to be executed - * @param array $params parameters to be bound to the SQL statement during execution. - * @return ActiveQuery the newly created [[ActiveQuery]] instance - */ - public static function findBySql($sql, $params = []) - { - $query = static::createQuery(); - $query->sql = $sql; - return $query->params($params); - } - - /** - * Updates the whole table using the provided attribute values and conditions. - * For example, to change the status to be 1 for all customers whose status is 2: - * - * ~~~ - * Customer::updateAll(['status' => 1], 'status = 2'); - * ~~~ - * - * @param array $attributes attribute values (name-value pairs) to be saved into the table - * @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. - * @param array $params the parameters (name => value) to be bound to the query. - * @return integer the number of rows updated - */ - public static function updateAll($attributes, $condition = '', $params = []) - { - $command = static::getDb()->createCommand(); - $command->update(static::tableName(), $attributes, $condition, $params); - return $command->execute(); - } - - /** - * Updates the whole table 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. - * @param array $params the parameters (name => value) to be bound to the query. - * Do not name the parameters as `:bp0`, `:bp1`, etc., because they are used internally by this method. - * @return integer the number of rows updated - */ - public static function updateAllCounters($counters, $condition = '', $params = []) - { - $n = 0; - foreach ($counters as $name => $value) { - $counters[$name] = new Expression("[[$name]]+:bp{$n}", [":bp{$n}" => $value]); - $n++; - } - $command = static::getDb()->createCommand(); - $command->update(static::tableName(), $counters, $condition, $params); - return $command->execute(); - } - - /** - * 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 string|array $condition the conditions that will be put in the WHERE part of the DELETE SQL. - * Please refer to [[Query::where()]] on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query. - * @return integer the number of rows deleted - */ - public static function deleteAll($condition = '', $params = []) - { - $command = static::getDb()->createCommand(); - $command->delete(static::tableName(), $condition, $params); - return $command->execute(); - } - - /** - * Creates an [[ActiveQuery]] instance. - * - * This method is called by [[find()]], [[findBySql()]] to start a SELECT query. - * You may override this method to return a customized query (e.g. `CustomerQuery` specified - * written for querying `Customer` purpose.) - * - * You may also define default conditions that should apply to all queries unless overridden: - * - * ```php - * public static function createQuery() - * { - * return parent::createQuery()->where(['deleted' => false]); - * } - * ``` - * - * Note that all queries should use [[Query::andWhere()]] and [[Query::orWhere()]] to keep the - * default condition. Using [[Query::where()]] will override the default condition. - * - * @return ActiveQuery the newly created [[ActiveQuery]] instance. - */ - public static function createQuery() - { - return new ActiveQuery(['modelClass' => get_called_class()]); - } - - /** - * Declares the name of the database table associated with this AR class. - * By default this method returns the class name as the table name by calling [[Inflector::camel2id()]] - * with prefix [[DbConnection::tablePrefix]]. For example if [[DbConnection::tablePrefix]] is 'tbl_', - * 'Customer' becomes 'tbl_customer', and 'OrderItem' becomes 'tbl_order_item'. You may override this method - * if the table is not named after this convention. - * @return string the table name - */ - public static function tableName() - { - return '{{%' . Inflector::camel2id(StringHelper::basename(get_called_class()), '_') . '}}'; - } - - /** - * Returns the schema information of the DB table associated with this AR class. - * @return TableSchema the schema information of the DB table associated with this AR class. - * @throws InvalidConfigException if the table for the AR class does not exist. - */ - public static function getTableSchema() - { - $schema = static::getDb()->getTableSchema(static::tableName()); - if ($schema !== null) { - return $schema; - } else { - throw new InvalidConfigException("The table does not exist: " . static::tableName()); - } - } - - /** - * Returns the primary key name(s) for this AR class. - * The default implementation will return the primary key(s) as declared - * in the DB table that is associated with this AR class. - * - * If the DB table does not declare any primary key, you should override - * this method to return the attributes that you want to use as primary keys - * for this AR class. - * - * Note that an array should be returned even for a table with single primary key. - * - * @return string[] the primary keys of the associated database table. - */ - public static function primaryKey() - { - return static::getTableSchema()->primaryKey; - } - - /** - * Returns the list of all attribute names of the model. - * The default implementation will return all column names of the table associated with this AR class. - * @return array list of attribute names. - */ - public function attributes() - { - return array_keys(static::getTableSchema()->columns); - } - - /** - * Declares which DB operations should be performed within a transaction in different scenarios. - * The supported DB operations are: [[OP_INSERT]], [[OP_UPDATE]] and [[OP_DELETE]], - * which correspond to the [[insert()]], [[update()]] and [[delete()]] methods, respectively. - * By default, these methods are NOT enclosed in a DB transaction. - * - * In some scenarios, to ensure data consistency, you may want to enclose some or all of them - * in transactions. You can do so by overriding this method and returning the operations - * that need to be transactional. For example, - * - * ~~~ - * return [ - * 'admin' => self::OP_INSERT, - * 'api' => self::OP_INSERT | self::OP_UPDATE | self::OP_DELETE, - * // the above is equivalent to the following: - * // 'api' => self::OP_ALL, - * - * ]; - * ~~~ - * - * The above declaration specifies that in the "admin" scenario, the insert operation ([[insert()]]) - * should be done in a transaction; and in the "api" scenario, all the operations should be done - * in a transaction. - * - * @return array the declarations of transactional operations. The array keys are scenarios names, - * and the array values are the corresponding transaction operations. - */ - public function transactions() - { - return []; - } - - /** - * Creates an [[ActiveRelation]] instance. - * This method is called by [[hasOne()]] and [[hasMany()]] to create a relation instance. - * You may override this method to return a customized relation. - * @param array $config the configuration passed to the ActiveRelation class. - * @return ActiveRelation the newly created [[ActiveRelation]] instance. - */ - public static function createActiveRelation($config = []) - { - return new ActiveRelation($config); - } - - /** - * Inserts a row into the associated database table 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 table's primary key is auto-incremental and is null during insertion, - * it will be populated with the actual value 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 that are loaded from DB will be saved. - * @return boolean whether the attributes are valid and the record is inserted successfully. - * @throws \Exception in case insert failed. - */ - public function insert($runValidation = true, $attributes = null) - { - if ($runValidation && !$this->validate($attributes)) { - return false; - } - $db = static::getDb(); - if ($this->isTransactional(self::OP_INSERT) && $db->getTransaction() === null) { - $transaction = $db->beginTransaction(); - try { - $result = $this->insertInternal($attributes); - if ($result === false) { - $transaction->rollback(); - } else { - $transaction->commit(); - } - } catch (\Exception $e) { - $transaction->rollback(); - throw $e; - } - } else { - $result = $this->insertInternal($attributes); - } - return $result; - } - - /** - * @see ActiveRecord::insert() - */ - private function insertInternal($attributes = null) - { - if (!$this->beforeSave(true)) { - return false; - } - $values = $this->getDirtyAttributes($attributes); - if (empty($values)) { - foreach ($this->getPrimaryKey(true) as $key => $value) { - $values[$key] = $value; - } - } - $db = static::getDb(); - $command = $db->createCommand()->insert($this->tableName(), $values); - if (!$command->execute()) { - return false; - } - $table = $this->getTableSchema(); - if ($table->sequenceName !== null) { - foreach ($table->primaryKey as $name) { - if ($this->getAttribute($name) === null) { - $id = $db->getLastInsertID($table->sequenceName); - $this->setAttribute($name, $id); - $this->setOldAttribute($name, $id); - break; - } - } - } - foreach ($values as $name => $value) { - $this->setOldAttribute($name, $value); - } - $this->afterSave(true); - return true; - } - - /** - * Saves the changes to this active record into the associated database table. - * - * 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. save 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_UPDATE]], [[EVENT_AFTER_UPDATE]] and [[EVENT_AFTER_VALIDATE]] - * will be raised by the corresponding methods. - * - * Only the [[changedAttributes|changed attribute values]] will be saved into database. - * - * For example, to update a customer record: - * - * ~~~ - * $customer = Customer::find($id); - * $customer->name = $name; - * $customer->email = $email; - * $customer->update(); - * ~~~ - * - * Note that it is possible the update does not affect any row in the table. - * In this case, this method will return 0. For this reason, you should use the following - * code to check if update() is successful or not: - * - * ~~~ - * if ($this->update() !== false) { - * // update successful - * } else { - * // update failed - * } - * ~~~ - * - * @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 that are loaded from DB will be saved. - * @return integer|boolean the number of rows affected, or false if validation fails - * or [[beforeSave()]] stops the updating process. - * @throws StaleObjectException if [[optimisticLock|optimistic locking]] is enabled and the data - * being updated is outdated. - * @throws \Exception in case update failed. - */ - public function update($runValidation = true, $attributes = null) - { - if ($runValidation && !$this->validate($attributes)) { - return false; - } - $db = static::getDb(); - if ($this->isTransactional(self::OP_UPDATE) && $db->getTransaction() === null) { - $transaction = $db->beginTransaction(); - try { - $result = $this->updateInternal($attributes); - if ($result === false) { - $transaction->rollback(); - } else { - $transaction->commit(); - } - } catch (\Exception $e) { - $transaction->rollback(); - throw $e; - } - } else { - $result = $this->updateInternal($attributes); - } - return $result; - } - - /** - * Deletes the table row corresponding to this active record. - * - * This method performs the following steps in order: - * - * 1. call [[beforeDelete()]]. If the method returns false, it will skip the - * rest of the steps; - * 2. delete the record from the database; - * 3. call [[afterDelete()]]. - * - * In the above step 1 and 3, events named [[EVENT_BEFORE_DELETE]] and [[EVENT_AFTER_DELETE]] - * will be raised by the corresponding methods. - * - * @return integer|boolean the number of rows deleted, or false if the deletion is unsuccessful for some reason. - * Note that it is possible the number of rows deleted is 0, even though the deletion execution is successful. - * @throws StaleObjectException if [[optimisticLock|optimistic locking]] is enabled and the data - * being deleted is outdated. - * @throws \Exception in case delete failed. - */ - public function delete() - { - $db = static::getDb(); - $transaction = $this->isTransactional(self::OP_DELETE) && $db->getTransaction() === null ? $db->beginTransaction() : null; - try { - $result = false; - if ($this->beforeDelete()) { - // we do not check the return value of deleteAll() because it's possible - // the record is already deleted in the database and thus the method will return 0 - $condition = $this->getOldPrimaryKey(true); - $lock = $this->optimisticLock(); - if ($lock !== null) { - $condition[$lock] = $this->$lock; - } - $result = $this->deleteAll($condition); - if ($lock !== null && !$result) { - throw new StaleObjectException('The object being deleted is outdated.'); - } - $this->setOldAttributes(null); - $this->afterDelete(); - } - if ($transaction !== null) { - if ($result === false) { - $transaction->rollback(); - } else { - $transaction->commit(); - } - } - } catch (\Exception $e) { - if ($transaction !== null) { - $transaction->rollback(); - } - throw $e; - } - return $result; - } - - /** - * Returns a value indicating whether the given active record is the same as the current one. - * The comparison is made by comparing the table names and the primary key values of the two active records. - * If one of the records [[isNewRecord|is new]] they are also considered not equal. - * @param ActiveRecord $record record to compare to - * @return boolean whether the two active records refer to the same row in the same database table. - */ - public function equals($record) - { - if ($this->isNewRecord || $record->isNewRecord) { - return false; - } - return $this->tableName() === $record->tableName() && $this->getPrimaryKey() === $record->getPrimaryKey(); - } - - /** - * Returns a value indicating whether the specified operation is transactional in the current [[scenario]]. - * @param integer $operation the operation to check. Possible values are [[OP_INSERT]], [[OP_UPDATE]] and [[OP_DELETE]]. - * @return boolean whether the specified operation is transactional in the current [[scenario]]. - */ - public function isTransactional($operation) - { - $scenario = $this->getScenario(); - $transactions = $this->transactions(); - return isset($transactions[$scenario]) && ($transactions[$scenario] & $operation); - } -} diff --git a/framework/yii/db/ActiveRecordInterface.php b/framework/yii/db/ActiveRecordInterface.php deleted file mode 100644 index 73db852..0000000 --- a/framework/yii/db/ActiveRecordInterface.php +++ /dev/null @@ -1,310 +0,0 @@ - - */ - -namespace yii\db; - -/** - * ActiveRecordInterface - * - * @author Qiang Xue - * @author Carsten Brandt - * @since 2.0 - */ -interface ActiveRecordInterface -{ - /** - * Returns the primary key **name(s)** for this AR class. - * - * Note that an array should be returned even when the record only has a single primary key. - * - * For the primary key **value** see [[getPrimaryKey()]] instead. - * - * @return string[] the primary key name(s) for this AR class. - */ - public static function primaryKey(); - - /** - * Returns the list of all attribute names of the record. - * @return array list of attribute names. - */ - public function attributes(); - - /** - * Returns the named attribute value. - * If this record is the result of a query and the attribute is not loaded, - * null will be returned. - * @param string $name the attribute name - * @return mixed the attribute value. Null if the attribute is not set or does not exist. - * @see hasAttribute() - */ - public function getAttribute($name); - - /** - * Sets the named attribute value. - * @param string $name the attribute name. - * @param mixed $value the attribute value. - * @see hasAttribute() - */ - public function setAttribute($name, $value); - - /** - * Returns a value indicating whether the record has an attribute with the specified name. - * @param string $name the name of the attribute - * @return boolean whether the record has an attribute with the specified name. - */ - public function hasAttribute($name); - - /** - * Returns the primary key value(s). - * @param boolean $asArray whether to return the primary key value as an array. If true, - * the return value will be an array with attribute names as keys and attribute values as values. - * Note that for composite primary keys, an array will always be returned regardless of this parameter value. - * @return mixed the primary key value. An array (attribute name => attribute value) is returned if the primary key - * is composite or `$asArray` is true. A string is returned otherwise (null will be returned if - * the key value is null). - */ - public function getPrimaryKey($asArray = false); - - /** - * Returns the old primary key value(s). - * This refers to the primary key value that is populated into the record - * after executing a find method (e.g. find(), findAll()). - * The value remains unchanged even if the primary key attribute is manually assigned with a different value. - * @param boolean $asArray whether to return the primary key value as an array. If true, - * the return value will be an array with column name as key and column value as value. - * If this is false (default), a scalar value will be returned for non-composite primary key. - * @property mixed The old primary key value. An array (column name => column value) is - * returned if the primary key is composite. A string is returned otherwise (null will be - * returned if the key value is null). - * @return mixed the old primary key value. An array (column name => column value) is returned if the primary key - * is composite or `$asArray` is true. A string is returned otherwise (null will be returned if - * the key value is null). - */ - public function getOldPrimaryKey($asArray = false); - - /** - * Creates an [[ActiveQueryInterface|ActiveQuery]] instance for query purpose. - * - * This method is usually ment to be used like this: - * - * ```php - * Customer::find(1); // find one customer by primary key - * Customer::find()->all(); // find all customers - * ``` - * - * @param mixed $q the query parameter. This can be one of the followings: - * - * - a scalar value (integer or string): query by a single primary key value and return the - * corresponding record. - * - an array of name-value pairs: query by a set of attribute values and return a single record matching all of them. - * - null (not specified): return a new [[ActiveQuery]] object for further query purpose. - * - * @return ActiveQueryInterface|static|null When `$q` is null, a new [[ActiveQuery]] instance - * is returned; when `$q` is a scalar or an array, an ActiveRecord object matching it will be - * returned (null will be returned if there is no matching). - */ - public static function find($q = null); - - /** - * Creates an [[ActiveQueryInterface|ActiveQuery]] instance. - * - * This method is called by [[find()]] to start a SELECT query. - * You may override this method to return a customized query (e.g. `CustomerQuery` specified - * written for querying `Customer` purpose.) - * - * You may also define default conditions that should apply to all queries unless overridden: - * - * ```php - * public static function createQuery() - * { - * return parent::createQuery()->where(['deleted' => false]); - * } - * ``` - * - * Note that all queries should use [[Query::andWhere()]] and [[Query::orWhere()]] to keep the - * default condition. Using [[Query::where()]] will override the default condition. - * - * @return ActiveQueryInterface the newly created [[ActiveQueryInterface|ActiveQuery]] instance. - */ - public static function createQuery(); - - /** - * Updates records using the provided attribute values and conditions. - * For example, to change the status to be 1 for all customers whose status is 2: - * - * ~~~ - * Customer::updateAll(['status' => 1], ['status' => '2']); - * ~~~ - * - * @param array $attributes attribute values (name-value pairs) to be saved for the record. - * Unlike [[update()]] these are not going to be validated. - * @param array $condition the condition that matches the records that should get updated. - * Please refer to [[QueryInterface::where()]] on how to specify this parameter. - * An empty condition will match all records. - * @return integer the number of rows updated - */ - public static function updateAll($attributes, $condition = null); - - /** - * Deletes records 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 condition that matches the records that should get deleted. - * Please refer to [[QueryInterface::where()]] on how to specify this parameter. - * An empty condition will match all records. - * @return integer the number of rows deleted - */ - public static function deleteAll($condition = null); - - /** - * Saves the current record. - * - * This method will call [[insert()]] when [[isNewRecord]] is true, or [[update()]] - * when [[isNewRecord]] is false. - * - * For example, to save a customer record: - * - * ~~~ - * $customer = new Customer; // or $customer = Customer::find($id); - * $customer->name = $name; - * $customer->email = $email; - * $customer->save(); - * ~~~ - * - * @param boolean $runValidation whether to perform validation before saving the record. - * If the validation fails, the record will not be saved to database. `false` will be returned - * in this case. - * @param array $attributes list of attributes that need to be saved. Defaults to null, - * meaning all attributes that are loaded from DB will be saved. - * @return boolean whether the saving succeeds - */ - public function save($runValidation = true, $attributes = null); - - /** - * Inserts the record into the database using the attribute values of this record. - * - * Usage example: - * - * ```php - * $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 that are loaded from DB will be saved. - * @return boolean whether the attributes are valid and the record is inserted successfully. - */ - public function insert($runValidation = true, $attributes = null); - - /** - * Saves the changes to this active record into the database. - * - * Usage example: - * - * ```php - * $customer = Customer::find($id); - * $customer->name = $name; - * $customer->email = $email; - * $customer->update(); - * ``` - * - * @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 that are loaded from DB will be saved. - * @return integer|boolean the number of rows affected, or false if validation fails - * or updating process is stopped for other reasons. - * Note that it is possible that the number of rows affected is 0, even though the - * update execution is successful. - */ - public function update($runValidation = true, $attributes = null); - - /** - * Deletes the record from the database. - * - * @return integer|boolean the number of rows deleted, or false if the deletion is unsuccessful for some reason. - * Note that it is possible that the number of rows deleted is 0, even though the deletion execution is successful. - */ - public function delete(); - - /** - * Returns a value indicating whether the current record is new (not saved in the database). - * @return boolean whether the record is new and should be inserted when calling [[save()]]. - */ - public function getIsNewRecord(); - - /** - * Returns a value indicating whether the given active record is the same as the current one. - * Two [[isNewRecord|new]] records are considered to be not equal. - * @param static $record record to compare to - * @return boolean whether the two active records refer to the same row in the same database table. - */ - public function equals($record); - - /** - * Creates an [[ActiveRelationInterface|ActiveRelation]] instance. - * This method is called by [[BaseActiveRecord::hasOne()]] and [[BaseActiveRecord::hasMany()]] to - * create a relation instance. - * You may override this method to return a customized relation. - * @param array $config the configuration passed to the ActiveRelation class. - * @return ActiveRelation the newly created [[ActiveRelation]] instance. - */ - public static function createActiveRelation($config = []); - - /** - * Returns the relation object with the specified name. - * A relation is defined by a getter method which returns an [[ActiveRelationInterface|ActiveRelation]] object. - * It can be declared in either the ActiveRecord class itself or one of its behaviors. - * @param string $name the relation name - * @return ActiveRelation the relation object - */ - public function getRelation($name); - - /** - * Establishes the relationship between two records. - * - * The relationship is established by setting the foreign key value(s) in one record - * to be the corresponding primary key value(s) in the other record. - * The record with the foreign key will be saved into database without performing validation. - * - * If the relationship involves a pivot table, a new row will be inserted into the - * pivot table which contains the primary key values from both records. - * - * This method requires that the primary key value is not null. - * - * @param string $name the case sensitive name of the relationship. - * @param static $model the record to be linked with the current one. - * @param array $extraColumns additional column values to be saved into the pivot table. - * This parameter is only meaningful for a relationship involving a pivot table - * (i.e., a relation set with `[[ActiveRelationInterface::via()]]`.) - */ - public function link($name, $model, $extraColumns = []); - - /** - * Destroys the relationship between two records. - * - * The record with the foreign key of the relationship will be deleted if `$delete` is true. - * Otherwise, the foreign key will be set null and the record will be saved without validation. - * - * @param string $name the case sensitive name of the relationship. - * @param static $model the model to be unlinked from the current one. - * @param boolean $delete whether to delete the model that contains the foreign key. - * If false, the model's foreign key will be set null and saved. - * If true, the model containing the foreign key will be deleted. - */ - public function unlink($name, $model, $delete = false); -} diff --git a/framework/yii/db/ActiveRelation.php b/framework/yii/db/ActiveRelation.php deleted file mode 100644 index 559bc28..0000000 --- a/framework/yii/db/ActiveRelation.php +++ /dev/null @@ -1,135 +0,0 @@ - - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\db; - -/** - * ActiveRelation represents a relation between two Active Record classes. - * - * ActiveRelation instances are usually created by calling [[ActiveRecord::hasOne()]] and - * [[ActiveRecord::hasMany()]]. An Active Record class declares a relation by defining - * a getter method which calls one of the above methods and returns the created ActiveRelation object. - * - * A relation is specified by [[link]] which represents the association between columns - * of different tables; and the multiplicity of the relation is indicated by [[multiple]]. - * - * If a relation involves a pivot table, it may be specified by [[via()]] or [[viaTable()]] method. - * - * @author Qiang Xue - * @author Carsten Brandt - * @since 2.0 - */ -class ActiveRelation extends ActiveQuery implements ActiveRelationInterface -{ - use ActiveRelationTrait; - - /** - * @var string|array the join condition. Please refer to [[Query::where()]] on how to specify this parameter. - * The condition will be used in the ON part when [[ActiveQuery::joinRelation()]] is called. - * Otherwise, the condition will be used in the WHERE part of a query. - */ - public $on; - - /** - * Sets the ON condition for the query. - * The condition will be used in the ON part when [[ActiveQuery::joinRelation()]] is called. - * Otherwise, the condition will be used in the WHERE part of a query. - * @param string|array $condition the ON condition. Please refer to [[Query::where()]] on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query. - * @return static the query object itself - */ - public function onCondition($condition, $params = []) - { - $this->on = $condition; - $this->addParams($params); - return $this; - } - - /** - * Specifies the pivot table. - * @param string $tableName the name of the pivot table. - * @param array $link the link between the pivot table and the table associated with [[primaryModel]]. - * The keys of the array represent the columns in the pivot table, and the values represent the columns - * in the [[primaryModel]] table. - * @param callable $callable a PHP callback for customizing the relation associated with the pivot table. - * Its signature should be `function($query)`, where `$query` is the query to be customized. - * @return static - */ - public function viaTable($tableName, $link, $callable = null) - { - $relation = new ActiveRelation([ - 'modelClass' => get_class($this->primaryModel), - 'from' => [$tableName], - 'link' => $link, - 'multiple' => true, - 'asArray' => true, - ]); - $this->via = $relation; - if ($callable !== null) { - call_user_func($callable, $relation); - } - return $this; - } - - /** - * 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) { - // eager loading - if (!empty($this->on)) { - $where = $this->where; - $this->andWhere($this->on); - $command = parent::createCommand($db); - $this->where = $where; - return $command; - } else { - return parent::createCommand($db); - } - } - - // lazy loading - - $where = $this->where; - - if ($this->via instanceof self) { - // via pivot table - $viaModels = $this->via->findPivotRows([$this->primaryModel]); - $this->filterByModels($viaModels); - } elseif (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]); - } - - if (!empty($this->on)) { - $this->andWhere($this->on); - } - - $command = parent::createCommand($db); - - $this->where = $where; - - return $command; - } -} diff --git a/framework/yii/db/ActiveRelationInterface.php b/framework/yii/db/ActiveRelationInterface.php deleted file mode 100644 index 84e0648..0000000 --- a/framework/yii/db/ActiveRelationInterface.php +++ /dev/null @@ -1,29 +0,0 @@ - - * @author Carsten Brandt - * @since 2.0 - */ -interface ActiveRelationInterface extends ActiveQueryInterface -{ - /** - * Specifies the relation associated with the pivot table. - * @param string $relationName the relation name. This refers to a relation declared in [[primaryModel]]. - * @param callable $callable a PHP callback for customizing the relation associated with the pivot table. - * Its signature should be `function($query)`, where `$query` is the query to be customized. - * @return static the relation object itself. - */ - public function via($relationName, $callable = null); -} diff --git a/framework/yii/db/ActiveRelationTrait.php b/framework/yii/db/ActiveRelationTrait.php deleted file mode 100644 index dac3028..0000000 --- a/framework/yii/db/ActiveRelationTrait.php +++ /dev/null @@ -1,257 +0,0 @@ - - * @author Carsten Brandt - * @since 2.0 - */ -trait ActiveRelationTrait -{ - /** - * @var boolean whether this relation should populate all query results into AR instances. - * If false, only the first row of the results will be retrieved. - */ - public $multiple; - /** - * @var ActiveRecord the primary model that this relation is associated with. - * This is used only in lazy loading with dynamic query options. - */ - public $primaryModel; - /** - * @var array the columns of the primary and foreign tables that establish the relation. - * The array keys must be columns of the table for this relation, and the array values - * must be the corresponding columns from the primary table. - * Do not prefix or quote the column names as this will be done automatically by Yii. - */ - public $link; - /** - * @var array the query associated with the pivot table. Please call [[via()]] - * to set this property instead of directly setting it. - */ - public $via; - - /** - * Clones internal objects. - */ - public function __clone() - { - // make a clone of "via" object so that the same query object can be reused multiple times - if (is_object($this->via)) { - $this->via = clone $this->via; - } elseif (is_array($this->via)) { - $this->via = [$this->via[0], clone $this->via[1]]; - } - } - - /** - * Specifies the relation associated with the pivot table. - * @param string $relationName the relation name. This refers to a relation declared in [[primaryModel]]. - * @param callable $callable a PHP callback for customizing the relation associated with the pivot table. - * Its signature should be `function($query)`, where `$query` is the query to be customized. - * @return static the relation object itself. - */ - public function via($relationName, $callable = null) - { - $relation = $this->primaryModel->getRelation($relationName); - $this->via = [$relationName, $relation]; - if ($callable !== null) { - call_user_func($callable, $relation); - } - return $this; - } - - /** - * Finds the related records and populates them into the primary models. - * @param string $name the relation name - * @param array $primaryModels primary models - * @return array the related models - * @throws InvalidConfigException if [[link]] is invalid - */ - public function populateRelation($name, &$primaryModels) - { - if (!is_array($this->link)) { - throw new InvalidConfigException('Invalid link: it must be an array of key-value pairs.'); - } - - if ($this->via instanceof self) { - // via pivot table - /** @var ActiveRelationTrait $viaQuery */ - $viaQuery = $this->via; - $viaModels = $viaQuery->findPivotRows($primaryModels); - $this->filterByModels($viaModels); - } elseif (is_array($this->via)) { - // via relation - /** @var ActiveRelationTrait $viaQuery */ - list($viaName, $viaQuery) = $this->via; - $viaQuery->primaryModel = null; - $viaModels = $viaQuery->populateRelation($viaName, $primaryModels); - $this->filterByModels($viaModels); - } else { - $this->filterByModels($primaryModels); - } - - if (count($primaryModels) === 1 && !$this->multiple) { - $model = $this->one(); - foreach ($primaryModels as $i => $primaryModel) { - if ($primaryModel instanceof ActiveRecordInterface) { - $primaryModel->populateRelation($name, $model); - } else { - $primaryModels[$i][$name] = $model; - } - } - return [$model]; - } else { - $models = $this->all(); - if (isset($viaModels, $viaQuery)) { - $buckets = $this->buildBuckets($models, $this->link, $viaModels, $viaQuery->link); - } else { - $buckets = $this->buildBuckets($models, $this->link); - } - - $link = array_values(isset($viaQuery) ? $viaQuery->link : $this->link); - foreach ($primaryModels as $i => $primaryModel) { - $key = $this->getModelKey($primaryModel, $link); - $value = isset($buckets[$key]) ? $buckets[$key] : ($this->multiple ? [] : null); - if ($primaryModel instanceof ActiveRecordInterface) { - $primaryModel->populateRelation($name, $value); - } else { - $primaryModels[$i][$name] = $value; - } - } - return $models; - } - } - - /** - * @param array $models - * @param array $link - * @param array $viaModels - * @param array $viaLink - * @return array - */ - private function buildBuckets($models, $link, $viaModels = null, $viaLink = null) - { - if ($viaModels !== null) { - $map = []; - $viaLinkKeys = array_keys($viaLink); - $linkValues = array_values($link); - foreach ($viaModels as $viaModel) { - $key1 = $this->getModelKey($viaModel, $viaLinkKeys); - $key2 = $this->getModelKey($viaModel, $linkValues); - $map[$key2][$key1] = true; - } - } - - $buckets = []; - $linkKeys = array_keys($link); - - if (isset($map)) { - foreach ($models as $i => $model) { - $key = $this->getModelKey($model, $linkKeys); - if (isset($map[$key])) { - foreach (array_keys($map[$key]) as $key2) { - if ($this->indexBy !== null) { - $buckets[$key2][$i] = $model; - } else { - $buckets[$key2][] = $model; - } - } - } - } - } else { - foreach ($models as $i => $model) { - $key = $this->getModelKey($model, $linkKeys); - if ($this->indexBy !== null) { - $buckets[$key][$i] = $model; - } else { - $buckets[$key][] = $model; - } - } - } - - if (!$this->multiple) { - foreach ($buckets as $i => $bucket) { - $buckets[$i] = reset($bucket); - } - } - return $buckets; - } - - /** - * @param array $models - */ - private function filterByModels($models) - { - $attributes = array_keys($this->link); - $values = []; - if (count($attributes) === 1) { - // single key - $attribute = reset($this->link); - foreach ($models as $model) { - if (($value = $model[$attribute]) !== null) { - $values[] = $value; - } - } - } else { - // composite keys - foreach ($models as $model) { - $v = []; - foreach ($this->link as $attribute => $link) { - $v[$attribute] = $model[$link]; - } - $values[] = $v; - } - } - $this->andWhere(['in', $attributes, array_unique($values, SORT_REGULAR)]); - } - - /** - * @param ActiveRecord|array $model - * @param array $attributes - * @return string - */ - private function getModelKey($model, $attributes) - { - if (count($attributes) > 1) { - $key = []; - foreach ($attributes as $attribute) { - $key[] = $model[$attribute]; - } - return serialize($key); - } else { - $attribute = reset($attributes); - $key = $model[$attribute]; - return is_scalar($key) ? $key : serialize($key); - } - } - - /** - * @param array $primaryModels either array of AR instances or arrays - * @return array - */ - private function findPivotRows($primaryModels) - { - if (empty($primaryModels)) { - return []; - } - $this->filterByModels($primaryModels); - /** @var ActiveRecord $primaryModel */ - $primaryModel = reset($primaryModels); - if (!$primaryModel instanceof ActiveRecordInterface) { - // when primaryModels are array of arrays (asArray case) - $primaryModel = new $this->modelClass; - } - return $this->asArray()->all($primaryModel->getDb()); - } -} diff --git a/framework/yii/db/BaseActiveRecord.php b/framework/yii/db/BaseActiveRecord.php deleted file mode 100644 index 6646b4a..0000000 --- a/framework/yii/db/BaseActiveRecord.php +++ /dev/null @@ -1,1282 +0,0 @@ - - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\db; - -use yii\base\InvalidConfigException; -use yii\base\Model; -use yii\base\InvalidParamException; -use yii\base\ModelEvent; -use yii\base\NotSupportedException; -use yii\base\UnknownMethodException; -use yii\base\InvalidCallException; -use yii\helpers\StringHelper; -use yii\helpers\Inflector; - -/** - * ActiveRecord is the base class for classes representing relational data in terms of objects. - * - * @include @yii/db/ActiveRecord.md - * - * @property array $dirtyAttributes The changed attribute values (name-value pairs). This property is - * read-only. - * @property boolean $isNewRecord Whether the record is new and should be inserted when calling [[save()]]. - * @property array $oldAttributes The old attribute values (name-value pairs). - * @property mixed $oldPrimaryKey The old primary key value. An array (column name => column value) is - * returned if the primary key is composite. A string is returned otherwise (null will be returned if the key - * value is null). This property is read-only. - * @property mixed $primaryKey The primary key value. An array (column name => column value) is returned if - * the primary key is composite. A string is returned otherwise (null will be returned if the key value is null). - * This property is read-only. - * @property array $relatedRecords An array of related records indexed by relation names. This property is - * read-only. - * - * @author Qiang Xue - * @author Carsten Brandt - * @since 2.0 - */ -abstract class BaseActiveRecord extends Model implements ActiveRecordInterface -{ - /** - * @event Event an event that is triggered when the record is initialized via [[init()]]. - */ - const EVENT_INIT = 'init'; - /** - * @event Event an event that is triggered after the record is created and populated with query result. - */ - const EVENT_AFTER_FIND = 'afterFind'; - /** - * @event ModelEvent an event that is triggered before inserting a record. - * You may set [[ModelEvent::isValid]] to be false to stop the insertion. - */ - const EVENT_BEFORE_INSERT = 'beforeInsert'; - /** - * @event Event an event that is triggered after a record is inserted. - */ - const EVENT_AFTER_INSERT = 'afterInsert'; - /** - * @event ModelEvent an event that is triggered before updating a record. - * You may set [[ModelEvent::isValid]] to be false to stop the update. - */ - const EVENT_BEFORE_UPDATE = 'beforeUpdate'; - /** - * @event Event an event that is triggered after a record is updated. - */ - const EVENT_AFTER_UPDATE = 'afterUpdate'; - /** - * @event ModelEvent an event that is triggered before deleting a record. - * You may set [[ModelEvent::isValid]] to be false to stop the deletion. - */ - const EVENT_BEFORE_DELETE = 'beforeDelete'; - /** - * @event Event an event that is triggered after a record is deleted. - */ - const EVENT_AFTER_DELETE = 'afterDelete'; - - /** - * @var array attribute values indexed by attribute names - */ - private $_attributes = []; - /** - * @var array old attribute values indexed by attribute names. - */ - private $_oldAttributes; - /** - * @var array related models indexed by the relation names - */ - private $_related = []; - - - /** - * Creates an [[ActiveQuery]] instance for query purpose. - * - * @include @yii/db/ActiveRecord-find.md - * - * @param mixed $q the query parameter. This can be one of the followings: - * - * - a scalar value (integer or string): query by a single primary key value and return the - * corresponding record. - * - an array of name-value pairs: query by a set of column values and return a single record matching all of them. - * - null: return a new [[ActiveQuery]] object for further query purpose. - * - * @return ActiveQuery|ActiveRecord|null When `$q` is null, a new [[ActiveQuery]] instance - * is returned; when `$q` is a scalar or an array, an ActiveRecord object matching it will be - * returned (null will be returned if there is no matching). - * @throws InvalidConfigException if the AR class does not have a primary key - * @see createQuery() - */ - public static function find($q = null) - { - $query = static::createQuery(); - if (is_array($q)) { - return $query->andWhere($q)->one(); - } elseif ($q !== null) { - // query by primary key - $primaryKey = static::primaryKey(); - if (isset($primaryKey[0])) { - return $query->andWhere([$primaryKey[0] => $q])->one(); - } else { - throw new InvalidConfigException(get_called_class() . ' must have a primary key.'); - } - } - return $query; - } - - /** - * Updates the whole table using the provided attribute values and conditions. - * For example, to change the status to be 1 for all customers whose status is 2: - * - * ~~~ - * Customer::updateAll(['status' => 1], 'status = 2'); - * ~~~ - * - * @param array $attributes attribute values (name-value pairs) to be saved into the table - * @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 updateAll($attributes, $condition = '') - { - throw new NotSupportedException(__METHOD__ . ' is not supported.'); - } - - /** - * Updates the whole table 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 = '') - { - throw new NotSupportedException(__METHOD__ . ' is not supported.'); - } - - /** - * 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 string|array $condition the conditions that will be put in the WHERE part of the DELETE SQL. - * Please refer to [[Query::where()]] on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query. - * @return integer the number of rows deleted - */ - public static function deleteAll($condition = '', $params = []) - { - throw new NotSupportedException(__METHOD__ . ' is not supported.'); - } - - /** - * Returns the name of the column that stores the lock version for implementing optimistic locking. - * - * Optimistic locking allows multiple users to access the same record for edits and avoids - * potential conflicts. In case when a user attempts to save the record upon some staled data - * (because another user has modified the data), a [[StaleObjectException]] exception will be thrown, - * and the update or deletion is skipped. - * - * Optimistic locking is only supported by [[update()]] and [[delete()]]. - * - * To use Optimistic locking: - * - * 1. Create a column to store the version number of each row. The column type should be `BIGINT DEFAULT 0`. - * Override this method to return the name of this column. - * 2. In the Web form that collects the user input, add a hidden field that stores - * the lock version of the recording being updated. - * 3. In the controller action that does the data updating, try to catch the [[StaleObjectException]] - * and implement necessary business logic (e.g. merging the changes, prompting stated data) - * to resolve the conflict. - * - * @return string the column name that stores the lock version of a table row. - * If null is returned (default implemented), optimistic locking will not be supported. - */ - public function optimisticLock() - { - return null; - } - - /** - * PHP getter magic method. - * This method is overridden so that attributes and related objects can be accessed like properties. - * @param string $name property name - * @return mixed property value - * @see getAttribute() - */ - public function __get($name) - { - if (isset($this->_attributes[$name]) || array_key_exists($name, $this->_attributes)) { - return $this->_attributes[$name]; - } elseif ($this->hasAttribute($name)) { - return null; - } else { - if (isset($this->_related[$name]) || array_key_exists($name, $this->_related)) { - return $this->_related[$name]; - } - $value = parent::__get($name); - if ($value instanceof ActiveRelationInterface) { - if (method_exists($this, 'get' . $name)) { - $method = new \ReflectionMethod($this, 'get' . $name); - $realName = lcfirst(substr($method->getName(), 3)); - if ($realName !== $name) { - throw new InvalidParamException('Relation names are case sensitive. ' . get_class($this) . " has a relation named \"$realName\" instead of \"$name\"."); - } - } - return $this->_related[$name] = $value->multiple ? $value->all() : $value->one(); - } else { - return $value; - } - } - } - - /** - * PHP setter magic method. - * This method is overridden so that AR attributes can be accessed like properties. - * @param string $name property name - * @param mixed $value property value - */ - public function __set($name, $value) - { - if ($this->hasAttribute($name)) { - $this->_attributes[$name] = $value; - } else { - parent::__set($name, $value); - } - } - - /** - * Checks if a property value is null. - * This method overrides the parent implementation by checking if the named attribute is null or not. - * @param string $name the property name or the event name - * @return boolean whether the property value is null - */ - public function __isset($name) - { - try { - return $this->__get($name) !== null; - } catch (\Exception $e) { - return false; - } - } - - /** - * Sets a component property to be null. - * This method overrides the parent implementation by clearing - * the specified attribute value. - * @param string $name the property name or the event name - */ - public function __unset($name) - { - if ($this->hasAttribute($name)) { - unset($this->_attributes[$name]); - } else { - if (isset($this->_related[$name])) { - unset($this->_related[$name]); - } else { - parent::__unset($name); - } - } - } - - /** - * Declares a `has-one` relation. - * The declaration is returned in terms of an [[ActiveRelation]] instance - * through which the related record can be queried and retrieved back. - * - * A `has-one` relation means that there is at most one related record matching - * the criteria set by this relation, e.g., a customer has one country. - * - * For example, to declare the `country` relation for `Customer` class, we can write - * the following code in the `Customer` class: - * - * ~~~ - * public function getCountry() - * { - * return $this->hasOne(Country::className(), ['id' => 'country_id']); - * } - * ~~~ - * - * Note that in the above, the 'id' key in the `$link` parameter refers to an attribute name - * in the related class `Country`, while the 'country_id' value refers to an attribute name - * in the current AR class. - * - * Call methods declared in [[ActiveRelation]] to further customize the relation. - * - * @param string $class the class name of the related record - * @param array $link the primary-foreign key constraint. The keys of the array refer to - * the attributes of the record associated with the `$class` model, while the values of the - * array refer to the corresponding attributes in **this** AR class. - * @return ActiveRelationInterface the relation object. - */ - public function hasOne($class, $link) - { - /** @var ActiveRecord $class */ - return $class::createActiveRelation([ - 'modelClass' => $class, - 'primaryModel' => $this, - 'link' => $link, - 'multiple' => false, - ]); - } - - /** - * Declares a `has-many` relation. - * The declaration is returned in terms of an [[ActiveRelation]] instance - * through which the related record can be queried and retrieved back. - * - * A `has-many` relation means that there are multiple related records matching - * the criteria set by this relation, e.g., a customer has many orders. - * - * For example, to declare the `orders` relation for `Customer` class, we can write - * the following code in the `Customer` class: - * - * ~~~ - * public function getOrders() - * { - * return $this->hasMany(Order::className(), ['customer_id' => 'id']); - * } - * ~~~ - * - * Note that in the above, the 'customer_id' key in the `$link` parameter refers to - * an attribute name in the related class `Order`, while the 'id' value refers to - * an attribute name in the current AR class. - * - * @param string $class the class name of the related record - * @param array $link the primary-foreign key constraint. The keys of the array refer to - * the attributes of the record associated with the `$class` model, while the values of the - * array refer to the corresponding attributes in **this** AR class. - * @return ActiveRelationInterface the relation object. - */ - public function hasMany($class, $link) - { - /** @var ActiveRecord $class */ - return $class::createActiveRelation([ - 'modelClass' => $class, - 'primaryModel' => $this, - 'link' => $link, - 'multiple' => true, - ]); - } - - /** - * Populates the named relation with the related records. - * Note that this method does not check if the relation exists or not. - * @param string $name the relation name (case-sensitive) - * @param ActiveRecord|array|null $records the related records to be populated into the relation. - */ - public function populateRelation($name, $records) - { - $this->_related[$name] = $records; - } - - /** - * Check whether the named relation has been populated with records. - * @param string $name the relation name (case-sensitive) - * @return bool whether relation has been populated with records. - */ - public function isRelationPopulated($name) - { - return array_key_exists($name, $this->_related); - } - - /** - * Returns all populated related records. - * @return array an array of related records indexed by relation names. - */ - public function getRelatedRecords() - { - return $this->_related; - } - - /** - * Returns a value indicating whether the model has an attribute with the specified name. - * @param string $name the name of the attribute - * @return boolean whether the model has an attribute with the specified name. - */ - public function hasAttribute($name) - { - return isset($this->_attributes[$name]) || in_array($name, $this->attributes()); - } - - /** - * Returns the named attribute value. - * If this record is the result of a query and the attribute is not loaded, - * null will be returned. - * @param string $name the attribute name - * @return mixed the attribute value. Null if the attribute is not set or does not exist. - * @see hasAttribute() - */ - public function getAttribute($name) - { - return isset($this->_attributes[$name]) ? $this->_attributes[$name] : null; - } - - /** - * Sets the named attribute value. - * @param string $name the attribute name - * @param mixed $value the attribute value. - * @throws InvalidParamException if the named attribute does not exist. - * @see hasAttribute() - */ - public function setAttribute($name, $value) - { - if ($this->hasAttribute($name)) { - $this->_attributes[$name] = $value; - } else { - throw new InvalidParamException(get_class($this) . ' has no attribute named "' . $name . '".'); - } - } - - /** - * Returns the old attribute values. - * @return array the old attribute values (name-value pairs) - */ - public function getOldAttributes() - { - return $this->_oldAttributes === null ? [] : $this->_oldAttributes; - } - - /** - * Sets the old attribute values. - * All existing old attribute values will be discarded. - * @param array $values old attribute values to be set. - */ - public function setOldAttributes($values) - { - $this->_oldAttributes = $values; - } - - /** - * Returns the old value of the named attribute. - * If this record is the result of a query and the attribute is not loaded, - * null will be returned. - * @param string $name the attribute name - * @return mixed the old attribute value. Null if the attribute is not loaded before - * or does not exist. - * @see hasAttribute() - */ - public function getOldAttribute($name) - { - return isset($this->_oldAttributes[$name]) ? $this->_oldAttributes[$name] : null; - } - - /** - * Sets the old value of the named attribute. - * @param string $name the attribute name - * @param mixed $value the old attribute value. - * @throws InvalidParamException if the named attribute does not exist. - * @see hasAttribute() - */ - public function setOldAttribute($name, $value) - { - if (isset($this->_oldAttributes[$name]) || $this->hasAttribute($name)) { - $this->_oldAttributes[$name] = $value; - } else { - throw new InvalidParamException(get_class($this) . ' has no attribute named "' . $name . '".'); - } - } - - /** - * Marks an attribute dirty. - * This method may be called to force updating a record when calling [[update()]], - * even if there is no change being made to the record. - * @param string $name the attribute name - */ - public function markAttributeDirty($name) - { - unset($this->_oldAttributes[$name]); - } - - /** - * Returns a value indicating whether the named attribute has been changed. - * @param string $name the name of the attribute - * @return boolean whether the attribute has been changed - */ - public function isAttributeChanged($name) - { - if (isset($this->_attributes[$name], $this->_oldAttributes[$name])) { - return $this->_attributes[$name] !== $this->_oldAttributes[$name]; - } else { - return isset($this->_attributes[$name]) || isset($this->_oldAttributes[$name]); - } - } - - /** - * Returns the attribute values that have been modified since they are loaded or saved most recently. - * @param string[]|null $names the names of the attributes whose values may be returned if they are - * changed recently. If null, [[attributes()]] will be used. - * @return array the changed attribute values (name-value pairs) - */ - public function getDirtyAttributes($names = null) - { - if ($names === null) { - $names = $this->attributes(); - } - $names = array_flip($names); - $attributes = []; - if ($this->_oldAttributes === null) { - foreach ($this->_attributes as $name => $value) { - if (isset($names[$name])) { - $attributes[$name] = $value; - } - } - } else { - foreach ($this->_attributes as $name => $value) { - if (isset($names[$name]) && (!array_key_exists($name, $this->_oldAttributes) || $value !== $this->_oldAttributes[$name])) { - $attributes[$name] = $value; - } - } - } - return $attributes; - } - - /** - * Saves the current record. - * - * This method will call [[insert()]] when [[isNewRecord]] is true, or [[update()]] - * when [[isNewRecord]] is false. - * - * For example, to save a customer record: - * - * ~~~ - * $customer = new Customer; // or $customer = Customer::find($id); - * $customer->name = $name; - * $customer->email = $email; - * $customer->save(); - * ~~~ - * - * - * @param boolean $runValidation whether to perform validation before saving the record. - * If the validation fails, the record will not be saved to database. - * @param array $attributes list of attributes that need to be saved. Defaults to null, - * meaning all attributes that are loaded from DB will be saved. - * @return boolean whether the saving succeeds - */ - public function save($runValidation = true, $attributes = null) - { - if ($this->getIsNewRecord()) { - return $this->insert($runValidation, $attributes); - } else { - return $this->update($runValidation, $attributes) !== false; - } - } - - /** - * Saves the changes to this active record into the associated database table. - * - * 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. save 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_UPDATE]], [[EVENT_AFTER_UPDATE]] and [[EVENT_AFTER_VALIDATE]] - * will be raised by the corresponding methods. - * - * Only the [[changedAttributes|changed attribute values]] will be saved into database. - * - * For example, to update a customer record: - * - * ~~~ - * $customer = Customer::find($id); - * $customer->name = $name; - * $customer->email = $email; - * $customer->update(); - * ~~~ - * - * Note that it is possible the update does not affect any row in the table. - * In this case, this method will return 0. For this reason, you should use the following - * code to check if update() is successful or not: - * - * ~~~ - * if ($this->update() !== false) { - * // update successful - * } else { - * // update failed - * } - * ~~~ - * - * @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 that are loaded from DB will be saved. - * @return integer|boolean the number of rows affected, or false if validation fails - * or [[beforeSave()]] stops the updating process. - * @throws StaleObjectException if [[optimisticLock|optimistic locking]] is enabled and the data - * being updated is outdated. - * @throws \Exception in case update failed. - */ - public function update($runValidation = true, $attributes = null) - { - if ($runValidation && !$this->validate($attributes)) { - return false; - } - return $this->updateInternal($attributes); - } - - /** - * Updates the specified attributes. - * - * This method is a shortcut to [[update()]] when data validation is not needed - * and only a list of attributes need to be updated. - * - * You may specify the attributes to be updated as name list or name-value pairs. - * If the latter, the corresponding attribute values will be modified accordingly. - * The method will then save the specified attributes into database. - * - * Note that this method will NOT perform data validation. - * - * @param array $attributes the attributes (names or name-value pairs) to be updated - * @return integer|boolean the number of rows affected, or false if [[beforeSave()]] stops the updating process. - */ - public function updateAttributes($attributes) - { - $attrs = []; - foreach ($attributes as $name => $value) { - if (is_integer($name)) { - $attrs[] = $value; - } else { - $this->$name = $value; - $attrs[] = $name; - } - } - return $this->update(false, $attrs); - } - - /** - * @see update() - * @throws StaleObjectException - */ - protected function updateInternal($attributes = null) - { - if (!$this->beforeSave(false)) { - return false; - } - $values = $this->getDirtyAttributes($attributes); - if (empty($values)) { - $this->afterSave(false); - return 0; - } - $condition = $this->getOldPrimaryKey(true); - $lock = $this->optimisticLock(); - if ($lock !== null) { - if (!isset($values[$lock])) { - $values[$lock] = $this->$lock + 1; - } - $condition[$lock] = $this->$lock; - } - // We do not check the return value of updateAll() because it's possible - // that the UPDATE statement doesn't change anything and thus returns 0. - $rows = $this->updateAll($values, $condition); - - if ($lock !== null && !$rows) { - throw new StaleObjectException('The object being updated is outdated.'); - } - - foreach ($values as $name => $value) { - $this->_oldAttributes[$name] = $this->_attributes[$name]; - } - $this->afterSave(false); - return $rows; - } - - /** - * Updates one or several counter columns for the current AR object. - * Note that this method differs from [[updateAllCounters()]] in that it only - * saves counters for the current AR object. - * - * An example usage is as follows: - * - * ~~~ - * $post = Post::find($id); - * $post->updateCounters(['view_count' => 1]); - * ~~~ - * - * @param array $counters the counters to be updated (attribute name => increment value) - * Use negative values if you want to decrement the counters. - * @return boolean whether the saving is successful - * @see updateAllCounters() - */ - public function updateCounters($counters) - { - if ($this->updateAllCounters($counters, $this->getOldPrimaryKey(true)) > 0) { - foreach ($counters as $name => $value) { - $this->_attributes[$name] += $value; - $this->_oldAttributes[$name] = $this->_attributes[$name]; - } - return true; - } else { - return false; - } - } - - /** - * Deletes the table row corresponding to this active record. - * - * This method performs the following steps in order: - * - * 1. call [[beforeDelete()]]. If the method returns false, it will skip the - * rest of the steps; - * 2. delete the record from the database; - * 3. call [[afterDelete()]]. - * - * In the above step 1 and 3, events named [[EVENT_BEFORE_DELETE]] and [[EVENT_AFTER_DELETE]] - * will be raised by the corresponding methods. - * - * @return integer|boolean the number of rows deleted, or false if the deletion is unsuccessful for some reason. - * Note that it is possible the number of rows deleted is 0, even though the deletion execution is successful. - * @throws StaleObjectException if [[optimisticLock|optimistic locking]] is enabled and the data - * being deleted is outdated. - * @throws \Exception in case delete failed. - */ - public function delete() - { - $result = false; - if ($this->beforeDelete()) { - // we do not check the return value of deleteAll() because it's possible - // the record is already deleted in the database and thus the method will return 0 - $condition = $this->getOldPrimaryKey(true); - $lock = $this->optimisticLock(); - if ($lock !== null) { - $condition[$lock] = $this->$lock; - } - $result = $this->deleteAll($condition); - if ($lock !== null && !$result) { - throw new StaleObjectException('The object being deleted is outdated.'); - } - $this->_oldAttributes = null; - $this->afterDelete(); - } - return $result; - } - - /** - * Returns a value indicating whether the current record is new. - * @return boolean whether the record is new and should be inserted when calling [[save()]]. - */ - public function getIsNewRecord() - { - return $this->_oldAttributes === null; - } - - /** - * Sets the value indicating whether the record is new. - * @param boolean $value whether the record is new and should be inserted when calling [[save()]]. - * @see getIsNewRecord() - */ - public function setIsNewRecord($value) - { - $this->_oldAttributes = $value ? null : $this->_attributes; - } - - /** - * Initializes the object. - * This method is called at the end of the constructor. - * The default implementation will trigger an [[EVENT_INIT]] event. - * If you override this method, make sure you call the parent implementation at the end - * to ensure triggering of the event. - */ - public function init() - { - parent::init(); - $this->trigger(self::EVENT_INIT); - } - - /** - * This method is called when the AR object is created and populated with the query result. - * The default implementation will trigger an [[EVENT_AFTER_FIND]] event. - * When overriding this method, make sure you call the parent implementation to ensure the - * event is triggered. - */ - public function afterFind() - { - $this->trigger(self::EVENT_AFTER_FIND); - } - - /** - * This method is called at the beginning of inserting or updating a record. - * The default implementation will trigger an [[EVENT_BEFORE_INSERT]] event when `$insert` is true, - * or an [[EVENT_BEFORE_UPDATE]] event if `$insert` is false. - * When overriding this method, make sure you call the parent implementation like the following: - * - * ~~~ - * public function beforeSave($insert) - * { - * if (parent::beforeSave($insert)) { - * // ...custom code here... - * return true; - * } else { - * return false; - * } - * } - * ~~~ - * - * @param boolean $insert whether this method called while inserting a record. - * If false, it means the method is called while updating a record. - * @return boolean whether the insertion or updating should continue. - * If false, the insertion or updating will be cancelled. - */ - public function beforeSave($insert) - { - $event = new ModelEvent; - $this->trigger($insert ? self::EVENT_BEFORE_INSERT : self::EVENT_BEFORE_UPDATE, $event); - return $event->isValid; - } - - /** - * This method is called at the end of inserting or updating a record. - * The default implementation will trigger an [[EVENT_AFTER_INSERT]] event when `$insert` is true, - * or an [[EVENT_AFTER_UPDATE]] event if `$insert` is false. - * When overriding this method, make sure you call the parent implementation so that - * the event is triggered. - * @param boolean $insert whether this method called while inserting a record. - * If false, it means the method is called while updating a record. - */ - public function afterSave($insert) - { - $this->trigger($insert ? self::EVENT_AFTER_INSERT : self::EVENT_AFTER_UPDATE); - } - - /** - * This method is invoked before deleting a record. - * The default implementation raises the [[EVENT_BEFORE_DELETE]] event. - * When overriding this method, make sure you call the parent implementation like the following: - * - * ~~~ - * public function beforeDelete() - * { - * if (parent::beforeDelete()) { - * // ...custom code here... - * return true; - * } else { - * return false; - * } - * } - * ~~~ - * - * @return boolean whether the record should be deleted. Defaults to true. - */ - public function beforeDelete() - { - $event = new ModelEvent; - $this->trigger(self::EVENT_BEFORE_DELETE, $event); - return $event->isValid; - } - - /** - * This method is invoked after deleting a record. - * The default implementation raises the [[EVENT_AFTER_DELETE]] event. - * You may override this method to do postprocessing after the record is deleted. - * Make sure you call the parent implementation so that the event is raised properly. - */ - public function afterDelete() - { - $this->trigger(self::EVENT_AFTER_DELETE); - } - - /** - * Repopulates this active record with the latest data. - * @return boolean whether the row still exists in the database. If true, the latest data - * will be populated to this active record. Otherwise, this record will remain unchanged. - */ - public function refresh() - { - $record = $this->find($this->getPrimaryKey(true)); - if ($record === null) { - return false; - } - foreach ($this->attributes() as $name) { - $this->_attributes[$name] = isset($record->_attributes[$name]) ? $record->_attributes[$name] : null; - } - $this->_oldAttributes = $this->_attributes; - $this->_related = []; - return true; - } - - /** - * Returns a value indicating whether the given active record is the same as the current one. - * The comparison is made by comparing the table names and the primary key values of the two active records. - * If one of the records [[isNewRecord|is new]] they are also considered not equal. - * @param ActiveRecord $record record to compare to - * @return boolean whether the two active records refer to the same row in the same database table. - */ - public function equals($record) - { - if ($this->getIsNewRecord() || $record->getIsNewRecord()) { - return false; - } - return get_class($this) === get_class($record) && $this->getPrimaryKey() === $record->getPrimaryKey(); - } - - /** - * Returns the primary key value(s). - * @param boolean $asArray whether to return the primary key value as an array. If true, - * the return value will be an array with column names as keys and column values as values. - * Note that for composite primary keys, an array will always be returned regardless of this parameter value. - * @property mixed The primary key value. An array (column name => column value) is returned if - * the primary key is composite. A string is returned otherwise (null will be returned if - * the key value is null). - * @return mixed the primary key value. An array (column name => column value) is returned if the primary key - * is composite or `$asArray` is true. A string is returned otherwise (null will be returned if - * the key value is null). - */ - public function getPrimaryKey($asArray = false) - { - $keys = $this->primaryKey(); - if (count($keys) === 1 && !$asArray) { - return isset($this->_attributes[$keys[0]]) ? $this->_attributes[$keys[0]] : null; - } else { - $values = []; - foreach ($keys as $name) { - $values[$name] = isset($this->_attributes[$name]) ? $this->_attributes[$name] : null; - } - return $values; - } - } - - /** - * Returns the old primary key value(s). - * This refers to the primary key value that is populated into the record - * after executing a find method (e.g. find(), findAll()). - * The value remains unchanged even if the primary key attribute is manually assigned with a different value. - * @param boolean $asArray whether to return the primary key value as an array. If true, - * the return value will be an array with column name as key and column value as value. - * If this is false (default), a scalar value will be returned for non-composite primary key. - * @property mixed The old primary key value. An array (column name => column value) is - * returned if the primary key is composite. A string is returned otherwise (null will be - * returned if the key value is null). - * @return mixed the old primary key value. An array (column name => column value) is returned if the primary key - * is composite or `$asArray` is true. A string is returned otherwise (null will be returned if - * the key value is null). - */ - public function getOldPrimaryKey($asArray = false) - { - $keys = $this->primaryKey(); - if (count($keys) === 1 && !$asArray) { - return isset($this->_oldAttributes[$keys[0]]) ? $this->_oldAttributes[$keys[0]] : null; - } else { - $values = []; - foreach ($keys as $name) { - $values[$name] = isset($this->_oldAttributes[$name]) ? $this->_oldAttributes[$name] : null; - } - return $values; - } - } - - /** - * 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 = static::instantiate($row); - $columns = array_flip($record->attributes()); - foreach ($row as $name => $value) { - if (isset($columns[$name])) { - $record->_attributes[$name] = $value; - } else { - $record->$name = $value; - } - } - $record->_oldAttributes = $record->_attributes; - $record->afterFind(); - return $record; - } - - /** - * Creates an active record instance. - * This method is called by [[create()]]. - * You may override this method if the instance being created - * depends on the row data to be populated into the record. - * For example, by creating a record based on the value of a column, - * you may implement the so-called single-table inheritance mapping. - * @param array $row row data to be populated into the record. - * @return ActiveRecord the newly created active record - */ - public static function instantiate($row) - { - return new static; - } - - /** - * Returns whether there is an element at the specified offset. - * This method is required by the interface ArrayAccess. - * @param mixed $offset the offset to check on - * @return boolean whether there is an element at the specified offset. - */ - public function offsetExists($offset) - { - return $this->__isset($offset); - } - - /** - * Returns the relation object with the specified name. - * A relation is defined by a getter method which returns an [[ActiveRelation]] object. - * It can be declared in either the Active Record class itself or one of its behaviors. - * @param string $name the relation name - * @return ActiveRelation the relation object - * @throws InvalidParamException if the named relation does not exist. - */ - public function getRelation($name) - { - $getter = 'get' . $name; - try { - // the relation could be defined in a behavior - $relation = $this->$getter(); - } catch (UnknownMethodException $e) { - throw new InvalidParamException(get_class($this) . ' has no relation named "' . $name . '".', 0, $e); - } - if (!$relation instanceof ActiveRelationInterface) { - throw new InvalidParamException(get_class($this) . ' has no relation named "' . $name . '".'); - } - - if (method_exists($this, $getter)) { - // relation name is case sensitive, trying to validate it when the relation is defined within this class - $method = new \ReflectionMethod($this, $getter); - $realName = lcfirst(substr($method->getName(), 3)); - if ($realName !== $name) { - throw new InvalidParamException('Relation names are case sensitive. ' . get_class($this) . " has a relation named \"$realName\" instead of \"$name\"."); - } - } - - return $relation; - } - - /** - * Establishes the relationship between two models. - * - * The relationship is established by setting the foreign key value(s) in one model - * to be the corresponding primary key value(s) in the other model. - * The model with the foreign key will be saved into database without performing validation. - * - * If the relationship involves a pivot table, a new row will be inserted into the - * pivot table which contains the primary key values from both models. - * - * Note that this method requires that the primary key value is not null. - * - * @param string $name the case sensitive name of the relationship - * @param ActiveRecord $model the model to be linked with the current one. - * @param array $extraColumns additional column values to be saved into the pivot table. - * This parameter is only meaningful for a relationship involving a pivot table - * (i.e., a relation set with `[[ActiveRelation::via()]]` or `[[ActiveRelation::viaTable()]]`.) - * @throws InvalidCallException if the method is unable to link two models. - */ - public function link($name, $model, $extraColumns = []) - { - $relation = $this->getRelation($name); - - if ($relation->via !== null) { - if ($this->getIsNewRecord() || $model->getIsNewRecord()) { - throw new InvalidCallException('Unable to link models: both models must NOT be newly created.'); - } - if (is_array($relation->via)) { - /** @var ActiveRelation $viaRelation */ - list($viaName, $viaRelation) = $relation->via; - $viaClass = $viaRelation->modelClass; - // unset $viaName so that it can be reloaded to reflect the change - unset($this->_related[$viaName]); - } else { - $viaRelation = $relation->via; - $viaTable = reset($relation->via->from); - } - $columns = []; - foreach ($viaRelation->link as $a => $b) { - $columns[$a] = $this->$b; - } - foreach ($relation->link as $a => $b) { - $columns[$b] = $model->$a; - } - foreach ($extraColumns as $k => $v) { - $columns[$k] = $v; - } - if (is_array($relation->via)) { - /** @var $viaClass ActiveRecord */ - /** @var $record ActiveRecord */ - $record = new $viaClass(); - foreach($columns as $column => $value) { - $record->$column = $value; - } - $record->insert(false); - } else { - /** @var $viaTable string */ - static::getDb()->createCommand() - ->insert($viaTable, $columns)->execute(); - } - } else { - $p1 = $model->isPrimaryKey(array_keys($relation->link)); - $p2 = $this->isPrimaryKey(array_values($relation->link)); - if ($p1 && $p2) { - if ($this->getIsNewRecord() && $model->getIsNewRecord()) { - throw new InvalidCallException('Unable to link models: both models are newly created.'); - } elseif ($this->getIsNewRecord()) { - $this->bindModels(array_flip($relation->link), $this, $model); - } else { - $this->bindModels($relation->link, $model, $this); - } - } elseif ($p1) { - $this->bindModels(array_flip($relation->link), $this, $model); - } elseif ($p2) { - $this->bindModels($relation->link, $model, $this); - } else { - throw new InvalidCallException('Unable to link models: the link does not involve any primary key.'); - } - } - - // update lazily loaded related objects - if (!$relation->multiple) { - $this->_related[$name] = $model; - } elseif (isset($this->_related[$name])) { - if ($relation->indexBy !== null) { - $indexBy = $relation->indexBy; - $this->_related[$name][$model->$indexBy] = $model; - } else { - $this->_related[$name][] = $model; - } - } - } - - /** - * Destroys the relationship between two models. - * - * The model with the foreign key of the relationship will be deleted if `$delete` is true. - * Otherwise, the foreign key will be set null and the model will be saved without validation. - * - * @param string $name the case sensitive name of the relationship. - * @param ActiveRecord $model the model to be unlinked from the current one. - * @param boolean $delete whether to delete the model that contains the foreign key. - * If false, the model's foreign key will be set null and saved. - * If true, the model containing the foreign key will be deleted. - * @throws InvalidCallException if the models cannot be unlinked - */ - public function unlink($name, $model, $delete = false) - { - $relation = $this->getRelation($name); - - if ($relation->via !== null) { - if (is_array($relation->via)) { - /** @var ActiveRelation $viaRelation */ - list($viaName, $viaRelation) = $relation->via; - $viaClass = $viaRelation->modelClass; - unset($this->_related[$viaName]); - } else { - $viaRelation = $relation->via; - $viaTable = reset($relation->via->from); - } - $columns = []; - foreach ($viaRelation->link as $a => $b) { - $columns[$a] = $this->$b; - } - foreach ($relation->link as $a => $b) { - $columns[$b] = $model->$a; - } - if (is_array($relation->via)) { - /** @var $viaClass ActiveRecord */ - if ($delete) { - $viaClass::deleteAll($columns); - } else { - $nulls = []; - foreach (array_keys($columns) as $a) { - $nulls[$a] = null; - } - $viaClass::updateAll($nulls, $columns); - } - } else { - /** @var $viaTable string */ - $command = static::getDb()->createCommand(); - if ($delete) { - $command->delete($viaTable, $columns)->execute(); - } else { - $nulls = []; - foreach (array_keys($columns) as $a) { - $nulls[$a] = null; - } - $command->update($viaTable, $nulls, $columns)->execute(); - } - } - } else { - $p1 = $model->isPrimaryKey(array_keys($relation->link)); - $p2 = $this->isPrimaryKey(array_values($relation->link)); - if ($p1 && $p2 || $p2) { - foreach ($relation->link as $a => $b) { - $model->$a = null; - } - $delete ? $model->delete() : $model->save(false); - } elseif ($p1) { - foreach ($relation->link as $b) { - $this->$b = null; - } - $delete ? $this->delete() : $this->save(false); - } else { - throw new InvalidCallException('Unable to unlink models: the link does not involve any primary key.'); - } - } - - if (!$relation->multiple) { - unset($this->_related[$name]); - } elseif (isset($this->_related[$name])) { - /** @var ActiveRecord $b */ - foreach ($this->_related[$name] as $a => $b) { - if ($model->getPrimaryKey() == $b->getPrimaryKey()) { - unset($this->_related[$name][$a]); - } - } - } - } - - /** - * @param array $link - * @param ActiveRecord $foreignModel - * @param ActiveRecord $primaryModel - * @throws InvalidCallException - */ - private function bindModels($link, $foreignModel, $primaryModel) - { - foreach ($link as $fk => $pk) { - $value = $primaryModel->$pk; - if ($value === null) { - throw new InvalidCallException('Unable to link models: the primary key of ' . get_class($primaryModel) . ' is null.'); - } - $foreignModel->$fk = $value; - } - $foreignModel->save(false); - } - - /** - * Returns a value indicating whether the given set of attributes represents the primary key for this model - * @param array $keys the set of attributes to check - * @return boolean whether the given set of attributes represents the primary key for this model - */ - public static function isPrimaryKey($keys) - { - $pks = static::primaryKey(); - if (count($keys) === count($pks)) { - return count(array_intersect($keys, $pks)) === count($pks); - } else { - return false; - } - } -} diff --git a/framework/yii/db/ColumnSchema.php b/framework/yii/db/ColumnSchema.php deleted file mode 100644 index 3e7f6cf..0000000 --- a/framework/yii/db/ColumnSchema.php +++ /dev/null @@ -1,106 +0,0 @@ - - * @since 2.0 - */ -class ColumnSchema extends Object -{ - /** - * @var string name of this column (without quotes). - */ - public $name; - /** - * @var boolean whether this column can be null. - */ - public $allowNull; - /** - * @var string abstract type of this column. Possible abstract types include: - * string, text, boolean, smallint, integer, bigint, float, decimal, datetime, - * timestamp, time, date, binary, and money. - */ - public $type; - /** - * @var string the PHP type of this column. Possible PHP types include: - * string, boolean, integer, double. - */ - public $phpType; - /** - * @var string the DB type of this column. Possible DB types vary according to the type of DBMS. - */ - public $dbType; - /** - * @var mixed default value of this column - */ - public $defaultValue; - /** - * @var array enumerable values. This is set only if the column is declared to be an enumerable type. - */ - public $enumValues; - /** - * @var integer display size of the column. - */ - public $size; - /** - * @var integer precision of the column data, if it is numeric. - */ - public $precision; - /** - * @var integer scale of the column data, if it is numeric. - */ - public $scale; - /** - * @var boolean whether this column is a primary key - */ - public $isPrimaryKey; - /** - * @var boolean whether this column is auto-incremental - */ - public $autoIncrement = false; - /** - * @var boolean whether this column is unsigned. This is only meaningful - * when [[type]] is `smallint`, `integer` or `bigint`. - */ - public $unsigned; - /** - * @var string comment of this column. Not all DBMS support this. - */ - public $comment; - - - /** - * Converts the input value according to [[phpType]]. - * If the value is null or an [[Expression]], it will not be converted. - * @param mixed $value input value - * @return mixed converted value - */ - public function typecast($value) - { - if ($value === '' && $this->type !== Schema::TYPE_TEXT && $this->type !== Schema::TYPE_STRING && $this->type !== Schema::TYPE_BINARY) { - return null; - } - if ($value === null || gettype($value) === $this->phpType || $value instanceof Expression) { - return $value; - } - switch ($this->phpType) { - case 'string': - return (string)$value; - case 'integer': - return (integer)$value; - case 'boolean': - return (boolean)$value; - } - return $value; - } -} diff --git a/framework/yii/db/Command.php b/framework/yii/db/Command.php deleted file mode 100644 index f7eb227..0000000 --- a/framework/yii/db/Command.php +++ /dev/null @@ -1,756 +0,0 @@ -createCommand('SELECT * FROM tbl_user')->queryAll(); - * ~~~ - * - * Command supports SQL statement preparation and parameter binding. - * Call [[bindValue()]] to bind a value to a SQL parameter; - * Call [[bindParam()]] to bind a PHP variable to a SQL parameter. - * When binding a parameter, the SQL statement is automatically prepared. - * You may also call [[prepare()]] explicitly to prepare a SQL statement. - * - * Command also supports building SQL statements by providing methods such as [[insert()]], - * [[update()]], etc. For example, - * - * ~~~ - * $connection->createCommand()->insert('tbl_user', [ - * 'name' => 'Sam', - * 'age' => 30, - * ])->execute(); - * ~~~ - * - * To build SELECT SQL statements, please use [[QueryBuilder]] instead. - * - * @property string $rawSql The raw SQL with parameter values inserted into the corresponding placeholders in - * [[sql]]. This property is read-only. - * @property string $sql The SQL statement to be executed. - * - * @author Qiang Xue - * @since 2.0 - */ -class Command extends \yii\base\Component -{ - /** - * @var Connection the DB connection that this command is associated with - */ - public $db; - /** - * @var \PDOStatement the PDOStatement object that this command is associated with - */ - public $pdoStatement; - /** - * @var integer the default fetch mode for this command. - * @see http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php - */ - public $fetchMode = \PDO::FETCH_ASSOC; - /** - * @var array the parameters (name => value) that are bound to the current PDO statement. - * This property is maintained by methods such as [[bindValue()]]. - * Do not modify it directly. - */ - public $params = []; - /** - * @var string the SQL statement that this command represents - */ - private $_sql; - - /** - * Returns the SQL statement for this command. - * @return string the SQL statement to be executed - */ - public function getSql() - { - return $this->_sql; - } - - /** - * Specifies the SQL statement to be executed. - * The previous SQL execution (if any) will be cancelled, and [[params]] will be cleared as well. - * @param string $sql the SQL statement to be set. - * @return static this command instance - */ - public function setSql($sql) - { - if ($sql !== $this->_sql) { - $this->cancel(); - $this->_sql = $this->db->quoteSql($sql); - $this->params = []; - } - return $this; - } - - /** - * Returns the raw SQL by inserting parameter values into the corresponding placeholders in [[sql]]. - * Note that the return value of this method should mainly be used for logging purpose. - * It is likely that this method returns an invalid SQL due to improper replacement of parameter placeholders. - * @return string the raw SQL with parameter values inserted into the corresponding placeholders in [[sql]]. - */ - public function getRawSql() - { - if (empty($this->params)) { - return $this->_sql; - } else { - $params = []; - foreach ($this->params as $name => $value) { - if (is_string($value)) { - $params[$name] = $this->db->quoteValue($value); - } elseif ($value === null) { - $params[$name] = 'NULL'; - } else { - $params[$name] = $value; - } - } - if (isset($params[1])) { - $sql = ''; - foreach (explode('?', $this->_sql) as $i => $part) { - $sql .= (isset($params[$i]) ? $params[$i] : '') . $part; - } - return $sql; - } else { - return strtr($this->_sql, $params); - } - } - } - - /** - * Prepares the SQL statement to be executed. - * For complex SQL statement that is to be executed multiple times, - * this may improve performance. - * For SQL statement with binding parameters, this method is invoked - * automatically. - * @throws Exception if there is any DB error - */ - public function prepare() - { - if ($this->pdoStatement == null) { - $sql = $this->getSql(); - try { - $this->pdoStatement = $this->db->pdo->prepare($sql); - } catch (\Exception $e) { - $message = $e->getMessage() . "\nFailed to prepare SQL: $sql"; - $errorInfo = $e instanceof \PDOException ? $e->errorInfo : null; - throw new Exception($message, $errorInfo, (int)$e->getCode(), $e); - } - } - } - - /** - * Cancels the execution of the SQL statement. - * This method mainly sets [[pdoStatement]] to be null. - */ - public function cancel() - { - $this->pdoStatement = null; - } - - /** - * Binds a parameter to the SQL statement to be executed. - * @param string|integer $name parameter identifier. For a prepared statement - * using named placeholders, this will be a parameter name of - * the form `:name`. For a prepared statement using question mark - * placeholders, this will be the 1-indexed position of the parameter. - * @param mixed $value Name of the PHP variable to bind to the SQL statement parameter - * @param integer $dataType SQL data type of the parameter. If null, the type is determined by the PHP type of the value. - * @param integer $length length of the data type - * @param mixed $driverOptions the driver-specific options - * @return static the current command being executed - * @see http://www.php.net/manual/en/function.PDOStatement-bindParam.php - */ - public function bindParam($name, &$value, $dataType = null, $length = null, $driverOptions = null) - { - $this->prepare(); - if ($dataType === null) { - $dataType = $this->db->getSchema()->getPdoType($value); - } - if ($length === null) { - $this->pdoStatement->bindParam($name, $value, $dataType); - } elseif ($driverOptions === null) { - $this->pdoStatement->bindParam($name, $value, $dataType, $length); - } else { - $this->pdoStatement->bindParam($name, $value, $dataType, $length, $driverOptions); - } - $this->params[$name] =& $value; - return $this; - } - - /** - * Binds a value to a parameter. - * @param string|integer $name Parameter identifier. For a prepared statement - * using named placeholders, this will be a parameter name of - * the form `:name`. For a prepared statement using question mark - * placeholders, this will be the 1-indexed position of the parameter. - * @param mixed $value The value to bind to the parameter - * @param integer $dataType SQL data type of the parameter. If null, the type is determined by the PHP type of the value. - * @return static the current command being executed - * @see http://www.php.net/manual/en/function.PDOStatement-bindValue.php - */ - public function bindValue($name, $value, $dataType = null) - { - $this->prepare(); - if ($dataType === null) { - $dataType = $this->db->getSchema()->getPdoType($value); - } - $this->pdoStatement->bindValue($name, $value, $dataType); - $this->params[$name] = $value; - return $this; - } - - /** - * Binds a list of values to the corresponding parameters. - * This is similar to [[bindValue()]] except that it binds multiple values at a time. - * Note that the SQL data type of each value is determined by its PHP type. - * @param array $values the values to be bound. This must be given in terms of an associative - * array with array keys being the parameter names, and array values the corresponding parameter values, - * e.g. `[':name' => 'John', ':age' => 25]`. By default, the PDO type of each value is determined - * by its PHP type. You may explicitly specify the PDO type by using an array: `[value, type]`, - * e.g. `[':name' => 'John', ':profile' => [$profile, \PDO::PARAM_LOB]]`. - * @return static the current command being executed - */ - public function bindValues($values) - { - if (!empty($values)) { - $this->prepare(); - foreach ($values as $name => $value) { - if (is_array($value)) { - $type = $value[1]; - $value = $value[0]; - } else { - $type = $this->db->getSchema()->getPdoType($value); - } - $this->pdoStatement->bindValue($name, $value, $type); - $this->params[$name] = $value; - } - } - return $this; - } - - /** - * Executes the SQL statement. - * This method should only be used for executing non-query SQL statement, such as `INSERT`, `DELETE`, `UPDATE` SQLs. - * No result set will be returned. - * @return integer number of rows affected by the execution. - * @throws Exception execution failed - */ - public function execute() - { - $sql = $this->getSql(); - - $rawSql = $this->getRawSql(); - - Yii::info($rawSql, __METHOD__); - - if ($sql == '') { - return 0; - } - - $token = $rawSql; - try { - Yii::beginProfile($token, __METHOD__); - - $this->prepare(); - $this->pdoStatement->execute(); - $n = $this->pdoStatement->rowCount(); - - Yii::endProfile($token, __METHOD__); - return $n; - } catch (\Exception $e) { - Yii::endProfile($token, __METHOD__); - if ($e instanceof Exception) { - throw $e; - } else { - $message = $e->getMessage() . "\nThe SQL being executed was: $rawSql"; - $errorInfo = $e instanceof \PDOException ? $e->errorInfo : null; - throw new Exception($message, $errorInfo, (int)$e->getCode(), $e); - } - } - } - - /** - * Executes the SQL statement and returns query result. - * This method is for executing a SQL query that returns result set, such as `SELECT`. - * @return DataReader the reader object for fetching the query result - * @throws Exception execution failed - */ - public function query() - { - return $this->queryInternal(''); - } - - /** - * Executes the SQL statement and returns ALL rows at once. - * @param integer $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php) - * for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used. - * @return array all rows of the query result. Each array element is an array representing a row of data. - * An empty array is returned if the query results in nothing. - * @throws Exception execution failed - */ - public function queryAll($fetchMode = null) - { - return $this->queryInternal('fetchAll', $fetchMode); - } - - /** - * Executes the SQL statement and returns the first row of the result. - * This method is best used when only the first row of result is needed for a query. - * @param integer $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php) - * for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] 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. - * @throws Exception execution failed - */ - public function queryOne($fetchMode = null) - { - return $this->queryInternal('fetch', $fetchMode); - } - - /** - * Executes the SQL statement and returns the value of the first column in the first row of data. - * This method is best used when only a single value is needed for a query. - * @return string|boolean the value of the first column in the first row of the query result. - * False is returned if there is no value. - * @throws Exception execution failed - */ - public function queryScalar() - { - $result = $this->queryInternal('fetchColumn', 0); - if (is_resource($result) && get_resource_type($result) === 'stream') { - return stream_get_contents($result); - } else { - return $result; - } - } - - /** - * Executes the SQL statement and returns the first column of the result. - * This method is best used when only the first column of result (i.e. the first element in each row) - * is needed for a query. - * @return array the first column of the query result. Empty array is returned if the query results in nothing. - * @throws Exception execution failed - */ - public function queryColumn() - { - return $this->queryInternal('fetchAll', \PDO::FETCH_COLUMN); - } - - /** - * Performs the actual DB query of a SQL statement. - * @param string $method method of PDOStatement to be called - * @param integer $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php) - * for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used. - * @return mixed the method execution result - * @throws Exception if the query causes any problem - */ - private function queryInternal($method, $fetchMode = null) - { - $db = $this->db; - $rawSql = $this->getRawSql(); - - Yii::info($rawSql, 'yii\db\Command::query'); - - /** @var \yii\caching\Cache $cache */ - if ($db->enableQueryCache && $method !== '') { - $cache = is_string($db->queryCache) ? Yii::$app->getComponent($db->queryCache) : $db->queryCache; - } - - if (isset($cache) && $cache instanceof Cache) { - $cacheKey = [ - __CLASS__, - $method, - $db->dsn, - $db->username, - $rawSql, - ]; - if (($result = $cache->get($cacheKey)) !== false) { - Yii::trace('Query result served from cache', 'yii\db\Command::query'); - return $result; - } - } - - $token = $rawSql; - try { - Yii::beginProfile($token, 'yii\db\Command::query'); - - $this->prepare(); - $this->pdoStatement->execute(); - - if ($method === '') { - $result = new DataReader($this); - } else { - if ($fetchMode === null) { - $fetchMode = $this->fetchMode; - } - $result = call_user_func_array([$this->pdoStatement, $method], (array)$fetchMode); - $this->pdoStatement->closeCursor(); - } - - Yii::endProfile($token, 'yii\db\Command::query'); - - if (isset($cache, $cacheKey) && $cache instanceof Cache) { - $cache->set($cacheKey, $result, $db->queryCacheDuration, $db->queryCacheDependency); - Yii::trace('Saved query result in cache', 'yii\db\Command::query'); - } - - return $result; - } catch (\Exception $e) { - Yii::endProfile($token, 'yii\db\Command::query'); - if ($e instanceof Exception) { - throw $e; - } else { - $message = $e->getMessage() . "\nThe SQL being executed was: $rawSql"; - $errorInfo = $e instanceof \PDOException ? $e->errorInfo : null; - throw new Exception($message, $errorInfo, (int)$e->getCode(), $e); - } - } - } - - /** - * Creates an INSERT command. - * For example, - * - * ~~~ - * $connection->createCommand()->insert('tbl_user', [ - * 'name' => 'Sam', - * 'age' => 30, - * ])->execute(); - * ~~~ - * - * The method will properly escape the column names, and bind the values to be inserted. - * - * Note that the created command is not executed until [[execute()]] is called. - * - * @param string $table the table that new rows will be inserted into. - * @param array $columns the column data (name => value) to be inserted into the table. - * @return Command the command object itself - */ - public function insert($table, $columns) - { - $params = []; - $sql = $this->db->getQueryBuilder()->insert($table, $columns, $params); - return $this->setSql($sql)->bindValues($params); - } - - /** - * Creates a batch INSERT command. - * For example, - * - * ~~~ - * $connection->createCommand()->batchInsert('tbl_user', ['name', 'age'], [ - * ['Tom', 30], - * ['Jane', 20], - * ['Linda', 25], - * ])->execute(); - * ~~~ - * - * Note that the values in each row must match the corresponding column names. - * - * @param string $table the table that new rows will be inserted into. - * @param array $columns the column names - * @param array $rows the rows to be batch inserted into the table - * @return Command the command object itself - */ - public function batchInsert($table, $columns, $rows) - { - $sql = $this->db->getQueryBuilder()->batchInsert($table, $columns, $rows); - return $this->setSql($sql); - } - - /** - * Creates an UPDATE command. - * For example, - * - * ~~~ - * $connection->createCommand()->update('tbl_user', ['status' => 1], 'age > 30')->execute(); - * ~~~ - * - * The method will properly escape the column names and bind the values to be updated. - * - * Note that the created command is not executed until [[execute()]] is called. - * - * @param string $table the table to be updated. - * @param array $columns the column data (name => value) to be updated. - * @param string|array $condition the condition that will be put in the WHERE part. Please - * refer to [[Query::where()]] on how to specify condition. - * @param array $params the parameters to be bound to the command - * @return Command the command object itself - */ - public function update($table, $columns, $condition = '', $params = []) - { - $sql = $this->db->getQueryBuilder()->update($table, $columns, $condition, $params); - return $this->setSql($sql)->bindValues($params); - } - - /** - * Creates a DELETE command. - * For example, - * - * ~~~ - * $connection->createCommand()->delete('tbl_user', 'status = 0')->execute(); - * ~~~ - * - * The method will properly escape the table and column names. - * - * Note that the created command is not executed until [[execute()]] is called. - * - * @param string $table the table where the data will be deleted from. - * @param string|array $condition the condition that will be put in the WHERE part. Please - * refer to [[Query::where()]] on how to specify condition. - * @param array $params the parameters to be bound to the command - * @return Command the command object itself - */ - public function delete($table, $condition = '', $params = []) - { - $sql = $this->db->getQueryBuilder()->delete($table, $condition, $params); - return $this->setSql($sql)->bindValues($params); - } - - - /** - * Creates a SQL command for creating a new DB table. - * - * The columns in the new table should be specified as name-definition pairs (e.g. 'name' => 'string'), - * where name stands for a column name which will be properly quoted by the method, and definition - * stands for the column type which can contain an abstract DB type. - * The method [[QueryBuilder::getColumnType()]] will be called - * to convert the abstract column types to physical ones. For example, `string` will be converted - * as `varchar(255)`, and `string not null` becomes `varchar(255) not null`. - * - * If a column is specified with definition only (e.g. 'PRIMARY KEY (name, type)'), it will be directly - * inserted into the generated SQL. - * - * @param string $table the name of the table to be created. The name will be properly quoted by the method. - * @param array $columns the columns (name => definition) in the new table. - * @param string $options additional SQL fragment that will be appended to the generated SQL. - * @return Command the command object itself - */ - public function createTable($table, $columns, $options = null) - { - $sql = $this->db->getQueryBuilder()->createTable($table, $columns, $options); - return $this->setSql($sql); - } - - /** - * Creates a SQL command for renaming a DB table. - * @param string $table the table to be renamed. The name will be properly quoted by the method. - * @param string $newName the new table name. The name will be properly quoted by the method. - * @return Command the command object itself - */ - public function renameTable($table, $newName) - { - $sql = $this->db->getQueryBuilder()->renameTable($table, $newName); - return $this->setSql($sql); - } - - /** - * Creates a SQL command for dropping a DB table. - * @param string $table the table to be dropped. The name will be properly quoted by the method. - * @return Command the command object itself - */ - public function dropTable($table) - { - $sql = $this->db->getQueryBuilder()->dropTable($table); - return $this->setSql($sql); - } - - /** - * Creates a SQL command for truncating a DB table. - * @param string $table the table to be truncated. The name will be properly quoted by the method. - * @return Command the command object itself - */ - public function truncateTable($table) - { - $sql = $this->db->getQueryBuilder()->truncateTable($table); - return $this->setSql($sql); - } - - /** - * Creates a SQL command for adding a new DB column. - * @param string $table the table that the new column will be added to. The table name will be properly quoted by the method. - * @param string $column the name of the new column. The name will be properly quoted by the method. - * @param string $type the column type. [[\yii\db\QueryBuilder::getColumnType()]] will be called - * to convert the give column type to the physical one. For example, `string` will be converted - * as `varchar(255)`, and `string not null` becomes `varchar(255) not null`. - * @return Command the command object itself - */ - public function addColumn($table, $column, $type) - { - $sql = $this->db->getQueryBuilder()->addColumn($table, $column, $type); - return $this->setSql($sql); - } - - /** - * Creates a SQL command for dropping a DB column. - * @param string $table the table whose column is to be dropped. The name will be properly quoted by the method. - * @param string $column the name of the column to be dropped. The name will be properly quoted by the method. - * @return Command the command object itself - */ - public function dropColumn($table, $column) - { - $sql = $this->db->getQueryBuilder()->dropColumn($table, $column); - return $this->setSql($sql); - } - - /** - * Creates a SQL command for renaming a column. - * @param string $table the table whose column is to be renamed. The name will be properly quoted by the method. - * @param string $oldName the old name of the column. The name will be properly quoted by the method. - * @param string $newName the new name of the column. The name will be properly quoted by the method. - * @return Command the command object itself - */ - public function renameColumn($table, $oldName, $newName) - { - $sql = $this->db->getQueryBuilder()->renameColumn($table, $oldName, $newName); - return $this->setSql($sql); - } - - /** - * Creates a SQL command for changing the definition of a column. - * @param string $table the table whose column is to be changed. The table name will be properly quoted by the method. - * @param string $column the name of the column to be changed. The name will be properly quoted by the method. - * @param string $type the column type. [[\yii\db\QueryBuilder::getColumnType()]] will be called - * to convert the give column type to the physical one. For example, `string` will be converted - * as `varchar(255)`, and `string not null` becomes `varchar(255) not null`. - * @return Command the command object itself - */ - public function alterColumn($table, $column, $type) - { - $sql = $this->db->getQueryBuilder()->alterColumn($table, $column, $type); - return $this->setSql($sql); - } - - /** - * Creates a SQL command for adding a primary key constraint to an existing table. - * The method will properly quote the table and column names. - * @param string $name the name of the primary key constraint. - * @param string $table the table that the primary key constraint will be added to. - * @param string|array $columns comma separated string or array of columns that the primary key will consist of. - * @return Command the command object itself. - */ - public function addPrimaryKey($name, $table, $columns) - { - $sql = $this->db->getQueryBuilder()->addPrimaryKey($name, $table, $columns); - return $this->setSql($sql); - } - - /** - * Creates a SQL command for removing a primary key constraint to an existing table. - * @param string $name the name of the primary key constraint to be removed. - * @param string $table the table that the primary key constraint will be removed from. - * @return Command the command object itself - */ - public function dropPrimaryKey($name, $table) - { - $sql = $this->db->getQueryBuilder()->dropPrimaryKey($name, $table); - return $this->setSql($sql); - } - - /** - * Creates a SQL command for adding a foreign key constraint to an existing table. - * The method will properly quote the table and column names. - * @param string $name the name of the foreign key constraint. - * @param string $table the table that the foreign key constraint will be added to. - * @param string $columns the name of the column to that the constraint will be added on. If there are multiple columns, separate them with commas. - * @param string $refTable the table that the foreign key references to. - * @param string $refColumns the name of the column that the foreign key references to. If there are multiple columns, separate them with commas. - * @param string $delete the ON DELETE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL - * @param string $update the ON UPDATE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL - * @return Command the command object itself - */ - public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete = null, $update = null) - { - $sql = $this->db->getQueryBuilder()->addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete, $update); - return $this->setSql($sql); - } - - /** - * Creates a SQL command for dropping a foreign key constraint. - * @param string $name the name of the foreign key constraint to be dropped. The name will be properly quoted by the method. - * @param string $table the table whose foreign is to be dropped. The name will be properly quoted by the method. - * @return Command the command object itself - */ - public function dropForeignKey($name, $table) - { - $sql = $this->db->getQueryBuilder()->dropForeignKey($name, $table); - return $this->setSql($sql); - } - - /** - * Creates a SQL command for creating a new index. - * @param string $name the name of the index. The name will be properly quoted by the method. - * @param string $table the table that the new index will be created for. The table name will be properly quoted by the method. - * @param string $columns the column(s) that should be included in the index. If there are multiple columns, please separate them - * by commas. The column names will be properly quoted by the method. - * @param boolean $unique whether to add UNIQUE constraint on the created index. - * @return Command the command object itself - */ - public function createIndex($name, $table, $columns, $unique = false) - { - $sql = $this->db->getQueryBuilder()->createIndex($name, $table, $columns, $unique); - return $this->setSql($sql); - } - - /** - * Creates a SQL command for dropping an index. - * @param string $name the name of the index to be dropped. The name will be properly quoted by the method. - * @param string $table the table whose index is to be dropped. The name will be properly quoted by the method. - * @return Command the command object itself - */ - public function dropIndex($name, $table) - { - $sql = $this->db->getQueryBuilder()->dropIndex($name, $table); - return $this->setSql($sql); - } - - /** - * Creates a SQL command for resetting the sequence value of a table's primary key. - * The sequence will be reset such that the primary key of the next new row inserted - * will have the specified value or 1. - * @param string $table the name of the table whose primary key sequence will be reset - * @param mixed $value the value for the primary key of the next new row inserted. If this is not set, - * the next new row's primary key will have a value 1. - * @return Command the command object itself - * @throws NotSupportedException if this is not supported by the underlying DBMS - */ - public function resetSequence($table, $value = null) - { - $sql = $this->db->getQueryBuilder()->resetSequence($table, $value); - return $this->setSql($sql); - } - - /** - * Builds a SQL command for enabling or disabling integrity check. - * @param boolean $check whether to turn on or off the integrity check. - * @param string $schema the schema name of the tables. Defaults to empty string, meaning the current - * or default schema. - * @param string $table the table name. - * @return Command the command object itself - * @throws NotSupportedException if this is not supported by the underlying DBMS - */ - public function checkIntegrity($check = true, $schema = '', $table = '') - { - $sql = $this->db->getQueryBuilder()->checkIntegrity($check, $schema, $table); - return $this->setSql($sql); - } -} diff --git a/framework/yii/db/Connection.php b/framework/yii/db/Connection.php deleted file mode 100644 index 9637087..0000000 --- a/framework/yii/db/Connection.php +++ /dev/null @@ -1,538 +0,0 @@ - $dsn, - * 'username' => $username, - * 'password' => $password, - * ]); - * $connection->open(); - * ~~~ - * - * After the DB connection is established, one can execute SQL statements like the following: - * - * ~~~ - * $command = $connection->createCommand('SELECT * FROM tbl_post'); - * $posts = $command->queryAll(); - * $command = $connection->createCommand('UPDATE tbl_post SET status=1'); - * $command->execute(); - * ~~~ - * - * One can also do prepared SQL execution and bind parameters to the prepared SQL. - * When the parameters are coming from user input, you should use this approach - * to prevent SQL injection attacks. The following is an example: - * - * ~~~ - * $command = $connection->createCommand('SELECT * FROM tbl_post WHERE id=:id'); - * $command->bindValue(':id', $_GET['id']); - * $post = $command->query(); - * ~~~ - * - * For more information about how to perform various DB queries, please refer to [[Command]]. - * - * If the underlying DBMS supports transactions, you can perform transactional SQL queries - * like the following: - * - * ~~~ - * $transaction = $connection->beginTransaction(); - * try { - * $connection->createCommand($sql1)->execute(); - * $connection->createCommand($sql2)->execute(); - * // ... executing other SQL statements ... - * $transaction->commit(); - * } catch(Exception $e) { - * $transaction->rollback(); - * } - * ~~~ - * - * Connection is often used as an application component and configured in the application - * configuration like the following: - * - * ~~~ - * [ - * 'components' => [ - * 'db' => [ - * 'class' => '\yii\db\Connection', - * 'dsn' => 'mysql:host=127.0.0.1;dbname=demo', - * 'username' => 'root', - * 'password' => '', - * 'charset' => 'utf8', - * ], - * ], - * ] - * ~~~ - * - * @property string $driverName Name of the DB driver. This property is read-only. - * @property boolean $isActive Whether the DB connection is established. This property is read-only. - * @property string $lastInsertID The row ID of the last row inserted, or the last value retrieved from the - * sequence object. This property is read-only. - * @property QueryBuilder $queryBuilder The query builder for the current DB connection. This property is - * read-only. - * @property Schema $schema The schema information for the database opened by this connection. This property - * is read-only. - * @property Transaction $transaction The currently active transaction. Null if no active transaction. This - * property is read-only. - * - * @author Qiang Xue - * @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 string the Data Source Name, or DSN, contains the information required to connect to the database. - * Please refer to the [PHP manual](http://www.php.net/manual/en/function.PDO-construct.php) on - * the format of the DSN string. - * @see charset - */ - public $dsn; - /** - * @var string the username for establishing DB connection. Defaults to `null` meaning no username to use. - */ - public $username; - /** - * @var string the password for establishing DB connection. Defaults to `null` meaning no password to use. - */ - public $password; - /** - * @var array PDO attributes (name => value) that should be set when calling [[open()]] - * to establish a DB connection. Please refer to the - * [PHP manual](http://www.php.net/manual/en/function.PDO-setAttribute.php) for - * details about available attributes. - */ - public $attributes; - /** - * @var PDO the PHP PDO instance associated with this DB connection. - * This property is mainly managed by [[open()]] and [[close()]] methods. - * When a DB connection is active, this property will represent a PDO instance; - * otherwise, it will be null. - */ - public $pdo; - /** - * @var boolean whether to enable schema caching. - * Note that in order to enable truly schema caching, a valid cache component as specified - * by [[schemaCache]] must be enabled and [[enableSchemaCache]] must be set true. - * @see schemaCacheDuration - * @see schemaCacheExclude - * @see schemaCache - */ - public $enableSchemaCache = false; - /** - * @var integer number of seconds that table metadata can remain valid in cache. - * Use 0 to indicate that the cached data will never expire. - * @see enableSchemaCache - */ - public $schemaCacheDuration = 3600; - /** - * @var array list of tables whose metadata should NOT be cached. Defaults to empty array. - * The table names may contain schema prefix, if any. Do not quote the table names. - * @see enableSchemaCache - */ - public $schemaCacheExclude = []; - /** - * @var Cache|string the cache object or the ID of the cache application component that - * is used to cache the table metadata. - * @see enableSchemaCache - */ - public $schemaCache = 'cache'; - /** - * @var boolean whether to enable query caching. - * Note that in order to enable query caching, a valid cache component as specified - * by [[queryCache]] must be enabled and [[enableQueryCache]] must be set true. - * - * Methods [[beginCache()]] and [[endCache()]] can be used as shortcuts to turn on - * and off query caching on the fly. - * @see queryCacheDuration - * @see queryCache - * @see queryCacheDependency - * @see beginCache() - * @see endCache() - */ - public $enableQueryCache = false; - /** - * @var integer number of seconds that query results can remain valid in cache. - * Defaults to 3600, meaning 3600 seconds, or one hour. - * Use 0 to indicate that the cached data will never expire. - * @see enableQueryCache - */ - public $queryCacheDuration = 3600; - /** - * @var \yii\caching\Dependency the dependency that will be used when saving query results into cache. - * Defaults to null, meaning no dependency. - * @see enableQueryCache - */ - public $queryCacheDependency; - /** - * @var Cache|string the cache object or the ID of the cache application component - * that is used for query caching. - * @see enableQueryCache - */ - public $queryCache = 'cache'; - /** - * @var string the charset used for database connection. The property is only used - * for MySQL, PostgreSQL and CUBRID databases. Defaults to null, meaning using default charset - * as specified by the database. - * - * Note that if you're using GBK or BIG5 then it's highly recommended to - * specify charset via DSN like 'mysql:dbname=mydatabase;host=127.0.0.1;charset=GBK;'. - */ - public $charset; - /** - * @var boolean whether to turn on prepare emulation. Defaults to false, meaning PDO - * will use the native prepare support if available. For some databases (such as MySQL), - * this may need to be set true so that PDO can emulate the prepare support to bypass - * the buggy native prepare support. - * The default value is null, which means the PDO ATTR_EMULATE_PREPARES value will not be changed. - */ - public $emulatePrepare; - /** - * @var string the common prefix or suffix for table names. If a table name is given - * as `{{%TableName}}`, then the percentage character `%` will be replaced with this - * property value. For example, `{{%post}}` becomes `{{tbl_post}}`. - */ - public $tablePrefix = 'tbl_'; - /** - * @var array mapping between PDO driver names and [[Schema]] classes. - * The keys of the array are PDO driver names while the values the corresponding - * schema class name or configuration. Please refer to [[Yii::createObject()]] for - * details on how to specify a configuration. - * - * This property is mainly used by [[getSchema()]] when fetching the database schema information. - * You normally do not need to set this property unless you want to use your own - * [[Schema]] class to support DBMS that is not supported by Yii. - */ - public $schemaMap = [ - 'pgsql' => 'yii\db\pgsql\Schema', // PostgreSQL - 'mysqli' => 'yii\db\mysql\Schema', // MySQL - 'mysql' => 'yii\db\mysql\Schema', // MySQL - 'sqlite' => 'yii\db\sqlite\Schema', // sqlite 3 - 'sqlite2' => 'yii\db\sqlite\Schema', // sqlite 2 - 'sqlsrv' => 'yii\db\mssql\Schema', // newer MSSQL driver on MS Windows hosts - 'oci' => 'yii\db\oci\Schema', // Oracle driver - 'mssql' => 'yii\db\mssql\Schema', // older MSSQL driver on MS Windows hosts - 'dblib' => 'yii\db\mssql\Schema', // dblib drivers on GNU/Linux (and maybe other OSes) hosts - 'cubrid' => 'yii\db\cubrid\Schema', // CUBRID - ]; - /** - * @var string Custom PDO wrapper class. If not set, it will use "PDO" or "yii\db\mssql\PDO" when MSSQL is used. - */ - public $pdoClass; - /** - * @var Transaction the currently active transaction - */ - private $_transaction; - /** - * @var Schema the database schema - */ - private $_schema; - - - /** - * Returns a value indicating whether the DB connection is established. - * @return boolean whether the DB connection is established - */ - public function getIsActive() - { - return $this->pdo !== null; - } - - /** - * Turns on query caching. - * This method is provided as a shortcut to setting two properties that are related - * with query caching: [[queryCacheDuration]] and [[queryCacheDependency]]. - * @param integer $duration the number of seconds that query results may remain valid in cache. - * If not set, it will use the value of [[queryCacheDuration]]. See [[queryCacheDuration]] for more details. - * @param \yii\caching\Dependency $dependency the dependency for the cached query result. - * See [[queryCacheDependency]] for more details. - */ - public function beginCache($duration = null, $dependency = null) - { - $this->enableQueryCache = true; - if ($duration !== null) { - $this->queryCacheDuration = $duration; - } - $this->queryCacheDependency = $dependency; - } - - /** - * Turns off query caching. - */ - public function endCache() - { - $this->enableQueryCache = false; - } - - /** - * 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->pdo === null) { - if (empty($this->dsn)) { - throw new InvalidConfigException('Connection::dsn cannot be empty.'); - } - $token = 'Opening DB connection: ' . $this->dsn; - try { - Yii::trace($token, __METHOD__); - Yii::beginProfile($token, __METHOD__); - $this->pdo = $this->createPdoInstance(); - $this->initConnection(); - Yii::endProfile($token, __METHOD__); - } catch (\PDOException $e) { - Yii::endProfile($token, __METHOD__); - throw new Exception($e->getMessage(), $e->errorInfo, (int)$e->getCode(), $e); - } - } - } - - /** - * Closes the currently active DB connection. - * It does nothing if the connection is already closed. - */ - public function close() - { - if ($this->pdo !== null) { - Yii::trace('Closing DB connection: ' . $this->dsn, __METHOD__); - $this->pdo = null; - $this->_schema = null; - $this->_transaction = null; - } - } - - /** - * Creates the PDO instance. - * This method is called by [[open]] to establish a DB connection. - * The default implementation will create a PHP PDO instance. - * You may override this method if the default PDO needs to be adapted for certain DBMS. - * @return PDO the pdo instance - */ - protected function createPdoInstance() - { - $pdoClass = $this->pdoClass; - if ($pdoClass === null) { - $pdoClass = 'PDO'; - if (($pos = strpos($this->dsn, ':')) !== false) { - $driver = strtolower(substr($this->dsn, 0, $pos)); - if ($driver === 'mssql' || $driver === 'dblib' || $driver === 'sqlsrv') { - $pdoClass = 'yii\db\mssql\PDO'; - } - } - } - - return new $pdoClass($this->dsn, $this->username, $this->password, $this->attributes); - } - - /** - * Initializes the DB connection. - * This method is invoked right after the DB connection is established. - * The default implementation turns on `PDO::ATTR_EMULATE_PREPARES` - * if [[emulatePrepare]] is true, and sets the database [[charset]] if it is not empty. - * It then triggers an [[EVENT_AFTER_OPEN]] event. - */ - protected function initConnection() - { - $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - if ($this->emulatePrepare !== null && constant('PDO::ATTR_EMULATE_PREPARES')) { - $this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->emulatePrepare); - } - if ($this->charset !== null && in_array($this->getDriverName(), ['pgsql', 'mysql', 'mysqli', 'cubrid'])) { - $this->pdo->exec('SET NAMES ' . $this->pdo->quote($this->charset)); - } - $this->trigger(self::EVENT_AFTER_OPEN); - } - - /** - * Creates a command for execution. - * @param string $sql the SQL statement to be executed - * @param array $params the parameters to be bound to the SQL statement - * @return Command the DB command - */ - public function createCommand($sql = null, $params = []) - { - $this->open(); - $command = new Command([ - 'db' => $this, - 'sql' => $sql, - ]); - return $command->bindValues($params); - } - - /** - * Returns the currently active transaction. - * @return Transaction the currently active transaction. Null if no active transaction. - */ - public function getTransaction() - { - return $this->_transaction && $this->_transaction->isActive ? $this->_transaction : null; - } - - /** - * Starts a transaction. - * @return Transaction the transaction initiated - */ - public function beginTransaction() - { - $this->open(); - $this->_transaction = new Transaction(['db' => $this]); - $this->_transaction->begin(); - return $this->_transaction; - } - - /** - * Returns the schema information for the database opened by this connection. - * @return Schema the schema information for the database opened by this connection. - * @throws NotSupportedException if there is no support for the current driver type - */ - public function getSchema() - { - if ($this->_schema !== null) { - return $this->_schema; - } else { - $driver = $this->getDriverName(); - if (isset($this->schemaMap[$driver])) { - $this->_schema = Yii::createObject($this->schemaMap[$driver]); - $this->_schema->db = $this; - return $this->_schema; - } else { - throw new NotSupportedException("Connection does not support reading schema information for '$driver' DBMS."); - } - } - } - - /** - * Returns the query builder for the current DB connection. - * @return QueryBuilder the query builder for the current DB connection. - */ - public function getQueryBuilder() - { - return $this->getSchema()->getQueryBuilder(); - } - - /** - * Obtains the schema information for the named table. - * @param string $name table name. - * @param boolean $refresh whether to reload the table schema even if it is found in the cache. - * @return TableSchema table schema information. Null if the named table does not exist. - */ - public function getTableSchema($name, $refresh = false) - { - return $this->getSchema()->getTableSchema($name, $refresh); - } - - /** - * Returns the ID of the last inserted row or sequence value. - * @param string $sequenceName name of the sequence object (required by some DBMS) - * @return string the row ID of the last row inserted, or the last value retrieved from the sequence object - * @see http://www.php.net/manual/en/function.PDO-lastInsertId.php - */ - public function getLastInsertID($sequenceName = '') - { - return $this->getSchema()->getLastInsertID($sequenceName); - } - - /** - * Quotes a string value for use in a query. - * Note that if the parameter is not a string, it will be returned without change. - * @param string $str string to be quoted - * @return string the properly quoted string - * @see http://www.php.net/manual/en/function.PDO-quote.php - */ - public function quoteValue($str) - { - return $this->getSchema()->quoteValue($str); - } - - /** - * Quotes a table name for use in a query. - * If the table name contains schema prefix, the prefix will also be properly quoted. - * If the table name is already quoted or contains special characters including '(', '[[' and '{{', - * then this method will do nothing. - * @param string $name table name - * @return string the properly quoted table name - */ - public function quoteTableName($name) - { - return $this->getSchema()->quoteTableName($name); - } - - /** - * Quotes a column name for use in a query. - * If the column name contains prefix, the prefix will also be properly quoted. - * If the column name is already quoted or contains special characters including '(', '[[' and '{{', - * then this method will do nothing. - * @param string $name column name - * @return string the properly quoted column name - */ - public function quoteColumnName($name) - { - return $this->getSchema()->quoteColumnName($name); - } - - /** - * Processes a SQL statement by quoting table and column names that are enclosed within double brackets. - * Tokens enclosed within double curly brackets are treated as table names, while - * tokens enclosed within double square brackets are column names. They will be quoted accordingly. - * Also, the percentage character "%" at the beginning or ending of a table name will be replaced - * with [[tablePrefix]]. - * @param string $sql the SQL to be quoted - * @return string the quoted SQL - */ - public function quoteSql($sql) - { - return preg_replace_callback('/(\\{\\{(%?[\w\-\. ]+%?)\\}\\}|\\[\\[([\w\-\. ]+)\\]\\])/', - function ($matches) { - if (isset($matches[3])) { - return $this->quoteColumnName($matches[3]); - } else { - return str_replace('%', $this->tablePrefix, $this->quoteTableName($matches[2])); - } - }, $sql); - } - - /** - * Returns the name of the DB driver for the current [[dsn]]. - * @return string name of the DB driver - */ - public function getDriverName() - { - if (($pos = strpos($this->dsn, ':')) !== false) { - return strtolower(substr($this->dsn, 0, $pos)); - } else { - $this->open(); - return strtolower($this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME)); - } - } -} diff --git a/framework/yii/db/DataReader.php b/framework/yii/db/DataReader.php deleted file mode 100644 index 213db52..0000000 --- a/framework/yii/db/DataReader.php +++ /dev/null @@ -1,264 +0,0 @@ -query('SELECT * FROM tbl_post'); - * - * while ($row = $reader->read()) { - * $rows[] = $row; - * } - * - * // equivalent to: - * foreach ($reader as $row) { - * $rows[] = $row; - * } - * - * // equivalent to: - * $rows = $reader->readAll(); - * ~~~ - * - * Note that since DataReader is a forward-only stream, you can only traverse it once. - * Doing it the second time will throw an exception. - * - * It is possible to use a specific mode of data fetching by setting - * [[fetchMode]]. See the [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php) - * for more details about possible fetch mode. - * - * @property integer $columnCount The number of columns in the result set. This property is read-only. - * @property integer $fetchMode Fetch mode. This property is write-only. - * @property boolean $isClosed Whether the reader is closed or not. This property is read-only. - * @property integer $rowCount Number of rows contained in the result. This property is read-only. - * - * @author Qiang Xue - * @since 2.0 - */ -class DataReader extends \yii\base\Object implements \Iterator, \Countable -{ - /** - * @var \PDOStatement the PDOStatement associated with the command - */ - private $_statement; - private $_closed = false; - private $_row; - private $_index = -1; - - /** - * Constructor. - * @param Command $command the command generating the query result - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct(Command $command, $config = []) - { - $this->_statement = $command->pdoStatement; - $this->_statement->setFetchMode(\PDO::FETCH_ASSOC); - parent::__construct($config); - } - - /** - * Binds a column to a PHP variable. - * When rows of data are being fetched, the corresponding column value - * will be set in the variable. Note, the fetch mode must include PDO::FETCH_BOUND. - * @param integer|string $column Number of the column (1-indexed) or name of the column - * in the result set. If using the column name, be aware that the name - * should match the case of the column, as returned by the driver. - * @param mixed $value Name of the PHP variable to which the column will be bound. - * @param integer $dataType Data type of the parameter - * @see http://www.php.net/manual/en/function.PDOStatement-bindColumn.php - */ - public function bindColumn($column, &$value, $dataType = null) - { - if ($dataType === null) { - $this->_statement->bindColumn($column, $value); - } else { - $this->_statement->bindColumn($column, $value, $dataType); - } - } - - /** - * Set the default fetch mode for this statement - * @param integer $mode fetch mode - * @see http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php - */ - public function setFetchMode($mode) - { - $params = func_get_args(); - call_user_func_array([$this->_statement, 'setFetchMode'], $params); - } - - /** - * Advances the reader to the next row in a result set. - * @return array the current row, false if no more row available - */ - public function read() - { - return $this->_statement->fetch(); - } - - /** - * Returns a single column from the next row of a result set. - * @param integer $columnIndex zero-based column index - * @return mixed the column of the current row, false if no more rows available - */ - public function readColumn($columnIndex) - { - return $this->_statement->fetchColumn($columnIndex); - } - - /** - * Returns an object populated with the next row of data. - * @param string $className class name of the object to be created and populated - * @param array $fields Elements of this array are passed to the constructor - * @return mixed the populated object, false if no more row of data available - */ - public function readObject($className, $fields) - { - return $this->_statement->fetchObject($className, $fields); - } - - /** - * Reads the whole result set into an array. - * @return array the result set (each array element represents a row of data). - * An empty array will be returned if the result contains no row. - */ - public function readAll() - { - return $this->_statement->fetchAll(); - } - - /** - * Advances the reader to the next result when reading the results of a batch of statements. - * This method is only useful when there are multiple result sets - * returned by the query. Not all DBMS support this feature. - * @return boolean Returns true on success or false on failure. - */ - public function nextResult() - { - if (($result = $this->_statement->nextRowset()) !== false) { - $this->_index = -1; - } - return $result; - } - - /** - * Closes the reader. - * This frees up the resources allocated for executing this SQL statement. - * Read attempts after this method call are unpredictable. - */ - public function close() - { - $this->_statement->closeCursor(); - $this->_closed = true; - } - - /** - * whether the reader is closed or not. - * @return boolean whether the reader is closed or not. - */ - public function getIsClosed() - { - return $this->_closed; - } - - /** - * Returns the number of rows in the result set. - * Note, most DBMS may not give a meaningful count. - * In this case, use "SELECT COUNT(*) FROM tableName" to obtain the number of rows. - * @return integer number of rows contained in the result. - */ - public function getRowCount() - { - return $this->_statement->rowCount(); - } - - /** - * Returns the number of rows in the result set. - * This method is required by the Countable interface. - * Note, most DBMS may not give a meaningful count. - * In this case, use "SELECT COUNT(*) FROM tableName" to obtain the number of rows. - * @return integer number of rows contained in the result. - */ - public function count() - { - return $this->getRowCount(); - } - - /** - * Returns the number of columns in the result set. - * Note, even there's no row in the reader, this still gives correct column number. - * @return integer the number of columns in the result set. - */ - public function getColumnCount() - { - return $this->_statement->columnCount(); - } - - /** - * Resets the iterator to the initial state. - * This method is required by the interface Iterator. - * @throws InvalidCallException if this method is invoked twice - */ - public function rewind() - { - if ($this->_index < 0) { - $this->_row = $this->_statement->fetch(); - $this->_index = 0; - } else { - throw new InvalidCallException('DataReader cannot rewind. It is a forward-only reader.'); - } - } - - /** - * Returns the index of the current row. - * This method is required by the interface Iterator. - * @return integer the index of the current row. - */ - public function key() - { - return $this->_index; - } - - /** - * Returns the current row. - * This method is required by the interface Iterator. - * @return mixed the current row. - */ - public function current() - { - return $this->_row; - } - - /** - * Moves the internal pointer to the next row. - * This method is required by the interface Iterator. - */ - public function next() - { - $this->_row = $this->_statement->fetch(); - $this->_index++; - } - - /** - * Returns whether there is a row of data at current position. - * This method is required by the interface Iterator. - * @return boolean whether there is a row of data at current position. - */ - public function valid() - { - return $this->_row !== false; - } -} diff --git a/framework/yii/db/Exception.php b/framework/yii/db/Exception.php deleted file mode 100644 index 210dee7..0000000 --- a/framework/yii/db/Exception.php +++ /dev/null @@ -1,44 +0,0 @@ - - * @since 2.0 - */ -class Exception extends \yii\base\Exception -{ - /** - * @var array the error info provided by a PDO exception. This is the same as returned - * by [PDO::errorInfo](http://www.php.net/manual/en/pdo.errorinfo.php). - */ - public $errorInfo = []; - - /** - * Constructor. - * @param string $message PDO error message - * @param array $errorInfo PDO error info - * @param integer $code PDO error code - * @param \Exception $previous The previous exception used for the exception chaining. - */ - public function __construct($message, $errorInfo = [], $code = 0, \Exception $previous = null) - { - $this->errorInfo = $errorInfo; - parent::__construct($message, $code, $previous); - } - - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return 'Database Exception'; - } -} diff --git a/framework/yii/db/Expression.php b/framework/yii/db/Expression.php deleted file mode 100644 index 7fa9124..0000000 --- a/framework/yii/db/Expression.php +++ /dev/null @@ -1,60 +0,0 @@ - - * @since 2.0 - */ -class Expression extends \yii\base\Object -{ - /** - * @var string the DB expression - */ - public $expression; - /** - * @var array list of parameters that should be bound for this expression. - * The keys are placeholders appearing in [[expression]] and the values - * are the corresponding parameter values. - */ - public $params = []; - - /** - * Constructor. - * @param string $expression the DB expression - * @param array $params parameters - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($expression, $params = [], $config = []) - { - $this->expression = $expression; - $this->params = $params; - parent::__construct($config); - } - - /** - * String magic method - * @return string the DB expression - */ - public function __toString() - { - return $this->expression; - } -} diff --git a/framework/yii/db/Migration.php b/framework/yii/db/Migration.php deleted file mode 100644 index 79a5abc..0000000 --- a/framework/yii/db/Migration.php +++ /dev/null @@ -1,416 +0,0 @@ - - * @since 2.0 - */ -class Migration extends \yii\base\Component -{ - /** - * @var Connection the database connection that this migration should work with. - * If not set, it will be initialized as the 'db' application component. - */ - public $db; - - /** - * Initializes the migration. - * This method will set [[db]] to be the 'db' application component, if it is null. - */ - public function init() - { - parent::init(); - if ($this->db === null) { - $this->db = \Yii::$app->getComponent('db'); - } - } - - /** - * This method contains the logic to be executed when applying this migration. - * Child classes may overwrite this method to provide actual migration logic. - * @return boolean return a false value to indicate the migration fails - * and should not proceed further. All other return values mean the migration succeeds. - */ - public function up() - { - $transaction = $this->db->beginTransaction(); - try { - if ($this->safeUp() === false) { - $transaction->rollback(); - return false; - } - $transaction->commit(); - } catch (\Exception $e) { - echo "Exception: " . $e->getMessage() . ' (' . $e->getFile() . ':' . $e->getLine() . ")\n"; - echo $e->getTraceAsString() . "\n"; - $transaction->rollback(); - return false; - } - return null; - } - - /** - * This method contains the logic to be executed when removing this migration. - * The default implementation throws an exception indicating the migration cannot be removed. - * Child classes may override this method if the corresponding migrations can be removed. - * @return boolean return a false value to indicate the migration fails - * and should not proceed further. All other return values mean the migration succeeds. - */ - public function down() - { - $transaction = $this->db->beginTransaction(); - try { - if ($this->safeDown() === false) { - $transaction->rollback(); - return false; - } - $transaction->commit(); - } catch (\Exception $e) { - echo "Exception: " . $e->getMessage() . ' (' . $e->getFile() . ':' . $e->getLine() . ")\n"; - echo $e->getTraceAsString() . "\n"; - $transaction->rollback(); - return false; - } - return null; - } - - /** - * This method contains the logic to be executed when applying this migration. - * This method differs from [[up()]] in that the DB logic implemented here will - * be enclosed within a DB transaction. - * Child classes may implement this method instead of [[up()]] if the DB logic - * needs to be within a transaction. - * @return boolean return a false value to indicate the migration fails - * and should not proceed further. All other return values mean the migration succeeds. - */ - public function safeUp() - { - } - - /** - * This method contains the logic to be executed when removing this migration. - * This method differs from [[down()]] in that the DB logic implemented here will - * be enclosed within a DB transaction. - * Child classes may implement this method instead of [[up()]] if the DB logic - * needs to be within a transaction. - * @return boolean return a false value to indicate the migration fails - * and should not proceed further. All other return values mean the migration succeeds. - */ - public function safeDown() - { - } - - /** - * Executes a SQL statement. - * This method executes the specified SQL statement using [[db]]. - * @param string $sql the SQL statement to be executed - * @param array $params input parameters (name => value) for the SQL execution. - * See [[Command::execute()]] for more details. - */ - public function execute($sql, $params = []) - { - echo " > execute SQL: $sql ..."; - $time = microtime(true); - $this->db->createCommand($sql)->execute($params); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Creates and executes an INSERT SQL statement. - * The method will properly escape the column names, and bind the values to be inserted. - * @param string $table the table that new rows will be inserted into. - * @param array $columns the column data (name => value) to be inserted into the table. - */ - public function insert($table, $columns) - { - echo " > insert into $table ..."; - $time = microtime(true); - $this->db->createCommand()->insert($table, $columns)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Creates and executes an batch INSERT SQL statement. - * The method will properly escape the column names, and bind the values to be inserted. - * @param string $table the table that new rows will be inserted into. - * @param array $columns the column names. - * @param array $rows the rows to be batch inserted into the table - */ - public function batchInsert($table, $columns, $rows) - { - echo " > insert into $table ..."; - $time = microtime(true); - $this->db->createCommand()->batchInsert($table, $columns, $rows)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Creates and executes an UPDATE SQL statement. - * The method will properly escape the column names and bind the values to be updated. - * @param string $table the table to be updated. - * @param array $columns the column data (name => value) to be updated. - * @param array|string $condition the conditions that will be put in the WHERE part. Please - * refer to [[Query::where()]] on how to specify conditions. - * @param array $params the parameters to be bound to the query. - */ - public function update($table, $columns, $condition = '', $params = []) - { - echo " > update $table ..."; - $time = microtime(true); - $this->db->createCommand()->update($table, $columns, $condition, $params)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Creates and executes a DELETE SQL statement. - * @param string $table the table where the data will be deleted from. - * @param array|string $condition the conditions that will be put in the WHERE part. Please - * refer to [[Query::where()]] on how to specify conditions. - * @param array $params the parameters to be bound to the query. - */ - public function delete($table, $condition = '', $params = []) - { - echo " > delete from $table ..."; - $time = microtime(true); - $this->db->createCommand()->delete($table, $condition, $params)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Builds and executes a SQL statement for creating a new DB table. - * - * The columns in the new table should be specified as name-definition pairs (e.g. 'name' => 'string'), - * where name stands for a column name which will be properly quoted by the method, and definition - * stands for the column type which can contain an abstract DB type. - * - * The [[QueryBuilder::getColumnType()]] method will be invoked to convert any abstract type into a physical one. - * - * If a column is specified with definition only (e.g. 'PRIMARY KEY (name, type)'), it will be directly - * put into the generated SQL. - * - * @param string $table the name of the table to be created. The name will be properly quoted by the method. - * @param array $columns the columns (name => definition) in the new table. - * @param string $options additional SQL fragment that will be appended to the generated SQL. - */ - public function createTable($table, $columns, $options = null) - { - echo " > create table $table ..."; - $time = microtime(true); - $this->db->createCommand()->createTable($table, $columns, $options)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Builds and executes a SQL statement for renaming a DB table. - * @param string $table the table to be renamed. The name will be properly quoted by the method. - * @param string $newName the new table name. The name will be properly quoted by the method. - */ - public function renameTable($table, $newName) - { - echo " > rename table $table to $newName ..."; - $time = microtime(true); - $this->db->createCommand()->renameTable($table, $newName)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Builds and executes a SQL statement for dropping a DB table. - * @param string $table the table to be dropped. The name will be properly quoted by the method. - */ - public function dropTable($table) - { - echo " > drop table $table ..."; - $time = microtime(true); - $this->db->createCommand()->dropTable($table)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Builds and executes a SQL statement for truncating a DB table. - * @param string $table the table to be truncated. The name will be properly quoted by the method. - */ - public function truncateTable($table) - { - echo " > truncate table $table ..."; - $time = microtime(true); - $this->db->createCommand()->truncateTable($table)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Builds and executes a SQL statement for adding a new DB column. - * @param string $table the table that the new column will be added to. The table name will be properly quoted by the method. - * @param string $column the name of the new column. The name will be properly quoted by the method. - * @param string $type the column type. The [[QueryBuilder::getColumnType()]] method will be invoked to convert abstract column type (if any) - * into the physical one. Anything that is not recognized as abstract type will be kept in the generated SQL. - * For example, 'string' will be turned into 'varchar(255)', while 'string not null' will become 'varchar(255) not null'. - */ - public function addColumn($table, $column, $type) - { - echo " > add column $column $type to table $table ..."; - $time = microtime(true); - $this->db->createCommand()->addColumn($table, $column, $type)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Builds and executes a SQL statement for dropping a DB column. - * @param string $table the table whose column is to be dropped. The name will be properly quoted by the method. - * @param string $column the name of the column to be dropped. The name will be properly quoted by the method. - */ - public function dropColumn($table, $column) - { - echo " > drop column $column from table $table ..."; - $time = microtime(true); - $this->db->createCommand()->dropColumn($table, $column)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Builds and executes a SQL statement for renaming a column. - * @param string $table the table whose column is to be renamed. The name will be properly quoted by the method. - * @param string $name the old name of the column. The name will be properly quoted by the method. - * @param string $newName the new name of the column. The name will be properly quoted by the method. - */ - public function renameColumn($table, $name, $newName) - { - echo " > rename column $name in table $table to $newName ..."; - $time = microtime(true); - $this->db->createCommand()->renameColumn($table, $name, $newName)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Builds and executes a SQL statement for changing the definition of a column. - * @param string $table the table whose column is to be changed. The table name will be properly quoted by the method. - * @param string $column the name of the column to be changed. The name will be properly quoted by the method. - * @param string $type the new column type. The [[getColumnType()]] method will be invoked to convert abstract column type (if any) - * into the physical one. Anything that is not recognized as abstract type will be kept in the generated SQL. - * For example, 'string' will be turned into 'varchar(255)', while 'string not null' will become 'varchar(255) not null'. - */ - public function alterColumn($table, $column, $type) - { - echo " > alter column $column in table $table to $type ..."; - $time = microtime(true); - $this->db->createCommand()->alterColumn($table, $column, $type)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Builds and executes a SQL statement for creating a primary key. - * The method will properly quote the table and column names. - * @param string $name the name of the primary key constraint. - * @param string $table the table that the primary key constraint will be added to. - * @param string|array $columns comma separated string or array of columns that the primary key will consist of. - */ - public function addPrimaryKey($name, $table, $columns) - { - echo " > add primary key $name on $table (".(is_array($columns) ? implode(',', $columns) : $columns).") ..."; - $time = microtime(true); - $this->db->createCommand()->addPrimaryKey($name, $table, $columns)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Builds and executes a SQL statement for dropping a primary key. - * @param string $name the name of the primary key constraint to be removed. - * @param string $table the table that the primary key constraint will be removed from. - * @return Command the command object itself - */ - public function dropPrimaryKey($name, $table) - { - echo " > drop primary key $name ..."; - $time = microtime(true); - $this->db->createCommand()->dropPrimaryKey($name, $table)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Builds a SQL statement for adding a foreign key constraint to an existing table. - * The method will properly quote the table and column names. - * @param string $name the name of the foreign key constraint. - * @param string $table the table that the foreign key constraint will be added to. - * @param string $columns the name of the column to that the constraint will be added on. If there are multiple columns, separate them with commas. - * @param string $refTable the table that the foreign key references to. - * @param string $refColumns the name of the column that the foreign key references to. If there are multiple columns, separate them with commas. - * @param string $delete the ON DELETE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL - * @param string $update the ON UPDATE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL - */ - public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete = null, $update = null) - { - echo " > add foreign key $name: $table ($columns) references $refTable ($refColumns) ..."; - $time = microtime(true); - $this->db->createCommand()->addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete, $update)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Builds a SQL statement for dropping a foreign key constraint. - * @param string $name the name of the foreign key constraint to be dropped. The name will be properly quoted by the method. - * @param string $table the table whose foreign is to be dropped. The name will be properly quoted by the method. - */ - public function dropForeignKey($name, $table) - { - echo " > drop foreign key $name from table $table ..."; - $time = microtime(true); - $this->db->createCommand()->dropForeignKey($name, $table)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Builds and executes a SQL statement for creating a new index. - * @param string $name the name of the index. The name will be properly quoted by the method. - * @param string $table the table that the new index will be created for. The table name will be properly quoted by the method. - * @param string $column the column(s) that should be included in the index. If there are multiple columns, please separate them - * by commas. The column names will be properly quoted by the method. - * @param boolean $unique whether to add UNIQUE constraint on the created index. - */ - public function createIndex($name, $table, $column, $unique = false) - { - echo " > create" . ($unique ? ' unique' : '') . " index $name on $table ($column) ..."; - $time = microtime(true); - $this->db->createCommand()->createIndex($name, $table, $column, $unique)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } - - /** - * Builds and executes a SQL statement for dropping an index. - * @param string $name the name of the index to be dropped. The name will be properly quoted by the method. - * @param string $table the table whose index is to be dropped. The name will be properly quoted by the method. - */ - public function dropIndex($name, $table) - { - echo " > drop index $name ..."; - $time = microtime(true); - $this->db->createCommand()->dropIndex($name, $table)->execute(); - echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; - } -} diff --git a/framework/yii/db/Query.php b/framework/yii/db/Query.php deleted file mode 100644 index 9da4f14..0000000 --- a/framework/yii/db/Query.php +++ /dev/null @@ -1,678 +0,0 @@ -select('id, name') - * ->from('tbl_user') - * ->limit(10); - * // build and execute the query - * $rows = $query->all(); - * // alternatively, you can create DB command and execute it - * $command = $query->createCommand(); - * // $command->sql returns the actual SQL - * $rows = $command->queryAll(); - * ~~~ - * - * @author Qiang Xue - * @author Carsten Brandt - * @since 2.0 - */ -class Query extends Component implements QueryInterface -{ - use QueryTrait; - - /** - * @var array the columns being selected. For example, `['id', 'name']`. - * This is used to construct the SELECT clause in a SQL statement. If not set, it means selecting all columns. - * @see select() - */ - public $select; - /** - * @var string additional option that should be appended to the 'SELECT' keyword. For example, - * in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used. - */ - public $selectOption; - /** - * @var boolean whether to select distinct rows of data only. If this is set true, - * the SELECT clause would be changed to SELECT DISTINCT. - */ - public $distinct; - /** - * @var array the table(s) to be selected from. For example, `['tbl_user', 'tbl_post']`. - * This is used to construct the FROM clause in a SQL statement. - * @see from() - */ - public $from; - /** - * @var array how to group the query results. For example, `['company', 'department']`. - * This is used to construct the GROUP BY clause in a SQL statement. - */ - public $groupBy; - /** - * @var array how to join with other tables. Each array element represents the specification - * of one join which has the following structure: - * - * ~~~ - * [$joinType, $tableName, $joinCondition] - * ~~~ - * - * For example, - * - * ~~~ - * [ - * ['INNER JOIN', 'tbl_user', 'tbl_user.id = author_id'], - * ['LEFT JOIN', 'tbl_team', 'tbl_team.id = team_id'], - * ] - * ~~~ - */ - public $join; - /** - * @var string|array the condition to be applied in the GROUP BY clause. - * It can be either a string or an array. Please refer to [[where()]] on how to specify the condition. - */ - public $having; - /** - * @var array this is used to construct the UNION clause(s) in a SQL statement. - * Each array element can be either a string or a [[Query]] object representing a sub-query. - */ - public $union; - /** - * @var array list of query parameter values indexed by parameter placeholders. - * For example, `[':name' => 'Dan', ':age' => 31]`. - */ - public $params; - - - /** - * Creates a DB command that can be used to execute this query. - * @param Connection $db the database connection used to generate the SQL statement. - * If this parameter is not given, the `db` application component will be used. - * @return Command the created DB command instance. - */ - public function createCommand($db = null) - { - if ($db === null) { - $db = Yii::$app->getDb(); - } - list ($sql, $params) = $db->getQueryBuilder()->build($this); - return $db->createCommand($sql, $params); - } - - /** - * Executes the query and returns all results as an array. - * @param Connection $db the database connection used to generate the SQL statement. - * If this parameter is not given, the `db` 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) - { - $rows = $this->createCommand($db)->queryAll(); - if ($this->indexBy === null) { - return $rows; - } - $result = []; - foreach ($rows as $row) { - if (is_string($this->indexBy)) { - $key = $row[$this->indexBy]; - } else { - $key = call_user_func($this->indexBy, $row); - } - $result[$key] = $row; - } - return $result; - } - - /** - * Executes the query and returns a single row of result. - * @param Connection $db the database connection used to generate the SQL statement. - * If this parameter is not given, the `db` 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) - { - return $this->createCommand($db)->queryOne(); - } - - /** - * Returns the query result as a scalar value. - * The value returned will be the first column in the first row of the query results. - * @param Connection $db the database connection used to generate the SQL statement. - * If this parameter is not given, the `db` application component will be used. - * @return string|boolean the value of the first column in the first row of the query result. - * False is returned if the query result is empty. - */ - public function scalar($db = null) - { - return $this->createCommand($db)->queryScalar(); - } - - /** - * Executes the query and returns the first column of the result. - * @param Connection $db the database connection used to generate the SQL statement. - * If this parameter is not given, the `db` 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($db = null) - { - return $this->createCommand($db)->queryColumn(); - } - - /** - * Returns the number of records. - * @param string $q the COUNT expression. Defaults to '*'. - * Make sure you properly quote column names in the expression. - * @param Connection $db the database connection used to generate the SQL statement. - * If this parameter is not given (or null), the `db` application component will be used. - * @return integer number of records - */ - public function count($q = '*', $db = null) - { - return $this->queryScalar("COUNT($q)", $db); - } - - /** - * Returns the sum of the specified column values. - * @param string $q the column name or expression. - * Make sure you properly quote column names in the expression. - * @param Connection $db the database connection used to generate the SQL statement. - * If this parameter is not given, the `db` application component will be used. - * @return integer the sum of the specified column values - */ - public function sum($q, $db = null) - { - return $this->queryScalar("SUM($q)", $db); - } - - /** - * Returns the average of the specified column values. - * @param string $q the column name or expression. - * Make sure you properly quote column names in the expression. - * @param Connection $db the database connection used to generate the SQL statement. - * If this parameter is not given, the `db` application component will be used. - * @return integer the average of the specified column values. - */ - public function average($q, $db = null) - { - return $this->queryScalar("AVG($q)", $db); - } - - /** - * Returns the minimum of the specified column values. - * @param string $q the column name or expression. - * Make sure you properly quote column names in the expression. - * @param Connection $db the database connection used to generate the SQL statement. - * If this parameter is not given, the `db` application component will be used. - * @return integer the minimum of the specified column values. - */ - public function min($q, $db = null) - { - return $this->queryScalar("MIN($q)", $db); - } - - /** - * Returns the maximum of the specified column values. - * @param string $q the column name or expression. - * Make sure you properly quote column names in the expression. - * @param Connection $db the database connection used to generate the SQL statement. - * If this parameter is not given, the `db` application component will be used. - * @return integer the maximum of the specified column values. - */ - public function max($q, $db = null) - { - return $this->queryScalar("MAX($q)", $db); - } - - /** - * Returns a value indicating whether the query result contains any row of data. - * @param Connection $db the database connection used to generate the SQL statement. - * If this parameter is not given, the `db` application component will be used. - * @return boolean whether the query result contains any row of data. - */ - public function exists($db = null) - { - $select = $this->select; - $this->select = [new Expression('1')]; - $command = $this->createCommand($db); - $this->select = $select; - return $command->queryScalar() !== false; - } - - /** - * Queries a scalar value by setting [[select]] first. - * Restores the value of select to make this query reusable. - * @param string|Expression $selectExpression - * @param Connection $db - * @return bool|string - */ - private function queryScalar($selectExpression, $db) - { - $select = $this->select; - $limit = $this->limit; - $offset = $this->offset; - - $this->select = [$selectExpression]; - $this->limit = null; - $this->offset = null; - $command = $this->createCommand($db); - - $this->select = $select; - $this->limit = $limit; - $this->offset = $offset; - - return $command->queryScalar(); - } - - /** - * Sets the SELECT part of the query. - * @param string|array $columns the columns to be selected. - * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. ['id', 'name']). - * Columns can contain table prefixes (e.g. "tbl_user.id") and/or column aliases (e.g. "tbl_user.id AS user_id"). - * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a DB expression). - * - * Note that if you are selecting an expression like `CONCAT(first_name, ' ', last_name)`, you should - * use an array to specify the columns. Otherwise, the expression may be incorrectly split into several parts. - * - * @param string $option additional option that should be appended to the 'SELECT' keyword. For example, - * in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used. - * @return static the query object itself - */ - public function select($columns, $option = null) - { - if (!is_array($columns)) { - $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); - } - $this->select = $columns; - $this->selectOption = $option; - return $this; - } - - /** - * Sets the value indicating whether to SELECT DISTINCT or not. - * @param bool $value whether to SELECT DISTINCT or not. - * @return static the query object itself - */ - public function distinct($value = true) - { - $this->distinct = $value; - return $this; - } - - /** - * Sets the FROM part of the query. - * @param string|array $tables the table(s) to be selected from. This can be either a string (e.g. `'tbl_user'`) - * or an array (e.g. `['tbl_user', 'tbl_profile']`) specifying one or several table names. - * Table names can contain schema prefixes (e.g. `'public.tbl_user'`) and/or table aliases (e.g. `'tbl_user u'`). - * The method will automatically quote the table names unless it contains some parenthesis - * (which means the table is given as a sub-query or DB expression). - * @return static the query object itself - */ - public function from($tables) - { - if (!is_array($tables)) { - $tables = preg_split('/\s*,\s*/', trim($tables), -1, PREG_SPLIT_NO_EMPTY); - } - $this->from = $tables; - return $this; - } - - /** - * Sets the WHERE part of the query. - * - * The method requires a $condition parameter, and optionally a $params parameter - * specifying the values to be bound to the query. - * - * The $condition parameter should be either a string (e.g. 'id=1') or an array. - * If the latter, it must be in one of the following two formats: - * - * - hash format: `['column1' => value1, 'column2' => value2, ...]` - * - operator format: `[operator, operand1, operand2, ...]` - * - * A condition in hash format represents the following SQL expression in general: - * `column1=value1 AND column2=value2 AND ...`. In case when a value is an array, - * an `IN` expression will be generated. And if a value is null, `IS NULL` will be used - * in the generated expression. Below are some examples: - * - * - `['type' => 1, 'status' => 2]` generates `(type = 1) AND (status = 2)`. - * - `['id' => [1, 2, 3], 'status' => 2]` generates `(id IN (1, 2, 3)) AND (status = 2)`. - * - `['status' => null] generates `status IS NULL`. - * - * A condition in operator format generates the SQL expression according to the specified operator, which - * can be one of the followings: - * - * - `and`: the operands should be concatenated together using `AND`. For example, - * `['and', 'id=1', 'id=2']` will generate `id=1 AND id=2`. If an operand is an array, - * it will be converted into a string using the rules described here. For example, - * `['and', 'type=1', ['or', 'id=1', 'id=2']]` will generate `type=1 AND (id=1 OR id=2)`. - * The method will NOT do any quoting or escaping. - * - * - `or`: similar to the `and` operator except that the operands are concatenated using `OR`. - * - * - `between`: operand 1 should be the column name, and operand 2 and 3 should be the - * starting and ending values of the range that the column is in. - * For example, `['between', 'id', 1, 10]` will generate `id BETWEEN 1 AND 10`. - * - * - `not between`: similar to `between` except the `BETWEEN` is replaced with `NOT BETWEEN` - * in the generated condition. - * - * - `in`: operand 1 should be a column or DB expression, and operand 2 be an array representing - * the range of the values that the column or DB expression should be in. For example, - * `['in', 'id', [1, 2, 3]]` will generate `id IN (1, 2, 3)`. - * The method will properly quote the column name and escape values in the range. - * - * - `not in`: similar to the `in` operator except that `IN` is replaced with `NOT IN` in the generated condition. - * - * - `like`: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing - * the values that the column or DB expression should be like. - * For example, `['like', 'name', 'tester']` will generate `name LIKE '%tester%'`. - * When the value range is given as an array, multiple `LIKE` predicates will be generated and concatenated - * using `AND`. For example, `['like', 'name', ['test', 'sample']]` will generate - * `name LIKE '%test%' AND name LIKE '%sample%'`. - * The method will properly quote the column name and escape special characters in the values. - * Sometimes, you may want to add the percentage characters to the matching value by yourself, you may supply - * a third operand `false` to do so. For example, `['like', 'name', '%tester', false]` will generate `name LIKE '%tester'`. - * - * - `or like`: similar to the `like` operator except that `OR` is used to concatenate the `LIKE` - * predicates when operand 2 is an array. - * - * - `not like`: similar to the `like` operator except that `LIKE` is replaced with `NOT LIKE` - * in the generated condition. - * - * - `or not like`: similar to the `not like` operator except that `OR` is used to concatenate - * the `NOT LIKE` predicates. - * - * @param string|array $condition the conditions that should be put in the WHERE part. - * @param array $params the parameters (name => value) to be bound to the query. - * @return static the query object itself - * @see andWhere() - * @see orWhere() - */ - public function where($condition, $params = []) - { - $this->where = $condition; - $this->addParams($params); - return $this; - } - - /** - * Adds an additional WHERE condition to the existing one. - * The new condition and the existing one will be joined using the 'AND' operator. - * @param string|array $condition the new WHERE condition. Please refer to [[where()]] - * on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query. - * @return static the query object itself - * @see where() - * @see orWhere() - */ - public function andWhere($condition, $params = []) - { - if ($this->where === null) { - $this->where = $condition; - } else { - $this->where = ['and', $this->where, $condition]; - } - $this->addParams($params); - return $this; - } - - /** - * Adds an additional WHERE condition to the existing one. - * The new condition and the existing one will be joined using the 'OR' operator. - * @param string|array $condition the new WHERE condition. Please refer to [[where()]] - * on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query. - * @return static the query object itself - * @see where() - * @see andWhere() - */ - public function orWhere($condition, $params = []) - { - if ($this->where === null) { - $this->where = $condition; - } else { - $this->where = ['or', $this->where, $condition]; - } - $this->addParams($params); - return $this; - } - - /** - * Appends a JOIN part to the query. - * The first parameter specifies what type of join it is. - * @param string $type the type of join, such as INNER JOIN, LEFT JOIN. - * @param string $table the table to be joined. - * Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u'). - * The method will automatically quote the table name unless it contains some parenthesis - * (which means the table is given as a sub-query or DB expression). - * @param string|array $on the join condition that should appear in the ON part. - * Please refer to [[where()]] on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query. - * @return Query the query object itself - */ - public function join($type, $table, $on = '', $params = []) - { - $this->join[] = [$type, $table, $on]; - return $this->addParams($params); - } - - /** - * Appends an INNER JOIN part to the query. - * @param string $table the table to be joined. - * Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u'). - * The method will automatically quote the table name unless it contains some parenthesis - * (which means the table is given as a sub-query or DB expression). - * @param string|array $on the join condition that should appear in the ON part. - * Please refer to [[where()]] on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query. - * @return Query the query object itself - */ - public function innerJoin($table, $on = '', $params = []) - { - $this->join[] = ['INNER JOIN', $table, $on]; - return $this->addParams($params); - } - - /** - * Appends a LEFT OUTER JOIN part to the query. - * @param string $table the table to be joined. - * Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u'). - * The method will automatically quote the table name unless it contains some parenthesis - * (which means the table is given as a sub-query or DB expression). - * @param string|array $on the join condition that should appear in the ON part. - * Please refer to [[where()]] on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query - * @return Query the query object itself - */ - public function leftJoin($table, $on = '', $params = []) - { - $this->join[] = ['LEFT JOIN', $table, $on]; - return $this->addParams($params); - } - - /** - * Appends a RIGHT OUTER JOIN part to the query. - * @param string $table the table to be joined. - * Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u'). - * The method will automatically quote the table name unless it contains some parenthesis - * (which means the table is given as a sub-query or DB expression). - * @param string|array $on the join condition that should appear in the ON part. - * Please refer to [[where()]] on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query - * @return Query the query object itself - */ - public function rightJoin($table, $on = '', $params = []) - { - $this->join[] = ['RIGHT JOIN', $table, $on]; - return $this->addParams($params); - } - - /** - * Sets the GROUP BY part of the query. - * @param string|array $columns the columns to be grouped by. - * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. ['id', 'name']). - * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a DB expression). - * @return static the query object itself - * @see addGroupBy() - */ - public function groupBy($columns) - { - if (!is_array($columns)) { - $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); - } - $this->groupBy = $columns; - return $this; - } - - /** - * Adds additional group-by columns to the existing ones. - * @param string|array $columns additional columns to be grouped by. - * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. ['id', 'name']). - * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a DB expression). - * @return static the query object itself - * @see groupBy() - */ - public function addGroupBy($columns) - { - if (!is_array($columns)) { - $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); - } - if ($this->groupBy === null) { - $this->groupBy = $columns; - } else { - $this->groupBy = array_merge($this->groupBy, $columns); - } - return $this; - } - - /** - * Sets the HAVING part of the query. - * @param string|array $condition the conditions to be put after HAVING. - * Please refer to [[where()]] on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query. - * @return static the query object itself - * @see andHaving() - * @see orHaving() - */ - public function having($condition, $params = []) - { - $this->having = $condition; - $this->addParams($params); - return $this; - } - - /** - * Adds an additional HAVING condition to the existing one. - * The new condition and the existing one will be joined using the 'AND' operator. - * @param string|array $condition the new HAVING condition. Please refer to [[where()]] - * on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query. - * @return static the query object itself - * @see having() - * @see orHaving() - */ - public function andHaving($condition, $params = []) - { - if ($this->having === null) { - $this->having = $condition; - } else { - $this->having = ['and', $this->having, $condition]; - } - $this->addParams($params); - return $this; - } - - /** - * Adds an additional HAVING condition to the existing one. - * The new condition and the existing one will be joined using the 'OR' operator. - * @param string|array $condition the new HAVING condition. Please refer to [[where()]] - * on how to specify this parameter. - * @param array $params the parameters (name => value) to be bound to the query. - * @return static the query object itself - * @see having() - * @see andHaving() - */ - public function orHaving($condition, $params = []) - { - if ($this->having === null) { - $this->having = $condition; - } else { - $this->having = ['or', $this->having, $condition]; - } - $this->addParams($params); - return $this; - } - - /** - * Appends a SQL statement using UNION operator. - * @param string|Query $sql the SQL statement to be appended using UNION - * @return static the query object itself - */ - public function union($sql) - { - $this->union[] = $sql; - return $this; - } - - /** - * Sets the parameters to be bound to the query. - * @param array $params list of query parameter values indexed by parameter placeholders. - * For example, `[':name' => 'Dan', ':age' => 31]`. - * @return static the query object itself - * @see addParams() - */ - public function params($params) - { - $this->params = $params; - return $this; - } - - /** - * Adds additional parameters to be bound to the query. - * @param array $params list of query parameter values indexed by parameter placeholders. - * For example, `[':name' => 'Dan', ':age' => 31]`. - * @return static the query object itself - * @see params() - */ - public function addParams($params) - { - if (!empty($params)) { - if ($this->params === null) { - $this->params = $params; - } else { - foreach ($params as $name => $value) { - if (is_integer($name)) { - $this->params[] = $value; - } else { - $this->params[$name] = $value; - } - } - } - } - return $this; - } -} diff --git a/framework/yii/db/QueryBuilder.php b/framework/yii/db/QueryBuilder.php deleted file mode 100644 index f819362..0000000 --- a/framework/yii/db/QueryBuilder.php +++ /dev/null @@ -1,1074 +0,0 @@ - - * @since 2.0 - */ -class QueryBuilder extends \yii\base\Object -{ - /** - * The prefix for automatically generated query binding parameters. - */ - const PARAM_PREFIX = ':qp'; - - /** - * @var Connection the database connection. - */ - public $db; - /** - * @var string the separator between different fragments of a SQL statement. - * Defaults to an empty space. This is mainly used by [[build()]] when generating a SQL statement. - */ - public $separator = " "; - /** - * @var array the abstract column types mapped to physical column types. - * This is mainly used to support creating/modifying tables using DB-independent data type specifications. - * Child classes should override this property to declare supported type mappings. - */ - public $typeMap = []; - - /** - * 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 a SELECT SQL statement from a [[Query]] object. - * @param Query $query the [[Query]] object from which the SQL statement 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) - { - $params = $query->params; - $clauses = [ - $this->buildSelect($query->select, $query->distinct, $query->selectOption), - $this->buildFrom($query->from), - $this->buildJoin($query->join, $params), - $this->buildWhere($query->where, $params), - $this->buildGroupBy($query->groupBy), - $this->buildHaving($query->having, $params), - $this->buildUnion($query->union, $params), - $this->buildOrderBy($query->orderBy), - $this->buildLimit($query->limit, $query->offset), - ]; - return [implode($this->separator, array_filter($clauses)), $params]; - } - - /** - * Creates an INSERT SQL statement. - * For example, - * - * ~~~ - * $sql = $queryBuilder->insert('tbl_user', [ - * 'name' => 'Sam', - * 'age' => 30, - * ], $params); - * ~~~ - * - * The method will properly escape the table and column names. - * - * @param string $table the table that new rows will be inserted into. - * @param array $columns the column data (name => value) to be inserted into the table. - * @param array $params the binding parameters that will be generated by this method. - * They should be bound to the DB command later. - * @return string the INSERT SQL - */ - public function insert($table, $columns, &$params) - { - if (($tableSchema = $this->db->getTableSchema($table)) !== null) { - $columnSchemas = $tableSchema->columns; - } else { - $columnSchemas = []; - } - $names = []; - $placeholders = []; - foreach ($columns as $name => $value) { - $names[] = $this->db->quoteColumnName($name); - if ($value instanceof Expression) { - $placeholders[] = $value->expression; - foreach ($value->params as $n => $v) { - $params[$n] = $v; - } - } else { - $phName = self::PARAM_PREFIX . count($params); - $placeholders[] = $phName; - $params[$phName] = !is_array($value) && isset($columnSchemas[$name]) ? $columnSchemas[$name]->typecast($value) : $value; - } - } - - return 'INSERT INTO ' . $this->db->quoteTableName($table) - . ' (' . implode(', ', $names) . ') VALUES (' - . implode(', ', $placeholders) . ')'; - } - - /** - * Generates a batch INSERT SQL statement. - * For example, - * - * ~~~ - * $connection->createCommand()->batchInsert('tbl_user', ['name', 'age'], [ - * ['Tom', 30], - * ['Jane', 20], - * ['Linda', 25], - * ])->execute(); - * ~~~ - * - * Note that the values in each row must match the corresponding column names. - * - * @param string $table the table that new rows will be inserted into. - * @param array $columns the column names - * @param array $rows the rows to be batch inserted into the table - * @return string the batch INSERT SQL statement - */ - public function batchInsert($table, $columns, $rows) - { - if (($tableSchema = $this->db->getTableSchema($table)) !== null) { - $columnSchemas = $tableSchema->columns; - } else { - $columnSchemas = []; - } - - foreach ($columns as $i => $name) { - $columns[$i] = $this->db->quoteColumnName($name); - } - - $values = []; - foreach ($rows as $row) { - $vs = []; - foreach ($row as $i => $value) { - if (!is_array($value) && isset($columnSchemas[$columns[$i]])) { - $value = $columnSchemas[$columns[$i]]->typecast($value); - } - $vs[] = is_string($value) ? $this->db->quoteValue($value) : $value; - } - $values[] = '(' . implode(', ', $vs) . ')'; - } - - return 'INSERT INTO ' . $this->db->quoteTableName($table) - . ' (' . implode(', ', $columns) . ') VALUES ' . implode(', ', $values); - } - - /** - * Creates an UPDATE SQL statement. - * For example, - * - * ~~~ - * $params = []; - * $sql = $queryBuilder->update('tbl_user', ['status' => 1], 'age > 30', $params); - * ~~~ - * - * The method will properly escape the table and column names. - * - * @param string $table the table to be updated. - * @param array $columns the column data (name => value) to be updated. - * @param array|string $condition the condition that will be put in the WHERE part. Please - * refer to [[Query::where()]] on how to specify condition. - * @param array $params the binding parameters that will be modified by this method - * so that they can be bound to the DB command later. - * @return string the UPDATE SQL - */ - public function update($table, $columns, $condition, &$params) - { - if (($tableSchema = $this->db->getTableSchema($table)) !== null) { - $columnSchemas = $tableSchema->columns; - } else { - $columnSchemas = []; - } - - $lines = []; - foreach ($columns as $name => $value) { - if ($value instanceof Expression) { - $lines[] = $this->db->quoteColumnName($name) . '=' . $value->expression; - foreach ($value->params as $n => $v) { - $params[$n] = $v; - } - } else { - $phName = self::PARAM_PREFIX . count($params); - $lines[] = $this->db->quoteColumnName($name) . '=' . $phName; - $params[$phName] = !is_array($value) && isset($columnSchemas[$name]) ? $columnSchemas[$name]->typecast($value) : $value; - } - } - - $sql = 'UPDATE ' . $this->db->quoteTableName($table) . ' SET ' . implode(', ', $lines); - $where = $this->buildWhere($condition, $params); - return $where === '' ? $sql : $sql . ' ' . $where; - } - - /** - * Creates a DELETE SQL statement. - * For example, - * - * ~~~ - * $sql = $queryBuilder->delete('tbl_user', 'status = 0'); - * ~~~ - * - * The method will properly escape the table and column names. - * - * @param string $table the table where the data will be deleted from. - * @param array|string $condition the condition that will be put in the WHERE part. Please - * refer to [[Query::where()]] on how to specify condition. - * @param array $params the binding parameters that will be modified by this method - * so that they can be bound to the DB command later. - * @return string the DELETE SQL - */ - public function delete($table, $condition, &$params) - { - $sql = 'DELETE FROM ' . $this->db->quoteTableName($table); - $where = $this->buildWhere($condition, $params); - return $where === '' ? $sql : $sql . ' ' . $where; - } - - /** - * Builds a SQL statement for creating a new DB table. - * - * The columns in the new table should be specified as name-definition pairs (e.g. 'name' => 'string'), - * where name stands for a column name which will be properly quoted by the method, and definition - * stands for the column type which can contain an abstract DB type. - * The [[getColumnType()]] method will be invoked to convert any abstract type into a physical one. - * - * If a column is specified with definition only (e.g. 'PRIMARY KEY (name, type)'), it will be directly - * inserted into the generated SQL. - * - * For example, - * - * ~~~ - * $sql = $queryBuilder->createTable('tbl_user', [ - * 'id' => 'pk', - * 'name' => 'string', - * 'age' => 'integer', - * ]); - * ~~~ - * - * @param string $table the name of the table to be created. The name will be properly quoted by the method. - * @param array $columns the columns (name => definition) in the new table. - * @param string $options additional SQL fragment that will be appended to the generated SQL. - * @return string the SQL statement for creating a new DB table. - */ - public function createTable($table, $columns, $options = null) - { - $cols = []; - foreach ($columns as $name => $type) { - if (is_string($name)) { - $cols[] = "\t" . $this->db->quoteColumnName($name) . ' ' . $this->getColumnType($type); - } else { - $cols[] = "\t" . $type; - } - } - $sql = "CREATE TABLE " . $this->db->quoteTableName($table) . " (\n" . implode(",\n", $cols) . "\n)"; - return $options === null ? $sql : $sql . ' ' . $options; - } - - /** - * Builds a SQL statement for renaming a DB table. - * @param string $oldName the table to be renamed. The name will be properly quoted by the method. - * @param string $newName the new table name. The name will be properly quoted by the method. - * @return string the SQL statement for renaming a DB table. - */ - public function renameTable($oldName, $newName) - { - return 'RENAME TABLE ' . $this->db->quoteTableName($oldName) . ' TO ' . $this->db->quoteTableName($newName); - } - - /** - * Builds a SQL statement for dropping a DB table. - * @param string $table the table to be dropped. The name will be properly quoted by the method. - * @return string the SQL statement for dropping a DB table. - */ - public function dropTable($table) - { - return "DROP TABLE " . $this->db->quoteTableName($table); - } - - /** - * Builds a SQL statement for adding a primary key constraint to an existing table. - * @param string $name the name of the primary key constraint. - * @param string $table the table that the primary key constraint will be added to. - * @param string|array $columns comma separated string or array of columns that the primary key will consist of. - * @return string the SQL statement for adding a primary key constraint to an existing table. - */ - public function addPrimaryKey($name, $table, $columns) - { - if (is_string($columns)) { - $columns = preg_split('/\s*,\s*/', $columns, -1, PREG_SPLIT_NO_EMPTY); - } - - foreach ($columns as $i => $col) { - $columns[$i] = $this->db->quoteColumnName($col); - } - - return 'ALTER TABLE ' . $this->db->quoteTableName($table) . ' ADD CONSTRAINT ' - . $this->db->quoteColumnName($name) . ' PRIMARY KEY (' - . implode(', ', $columns). ' )'; - } - - /** - * Builds a SQL statement for removing a primary key constraint to an existing table. - * @param string $name the name of the primary key constraint to be removed. - * @param string $table the table that the primary key constraint will be removed from. - * @return string the SQL statement for removing a primary key constraint from an existing table. * - */ - public function dropPrimaryKey($name, $table) - { - return 'ALTER TABLE ' . $this->db->quoteTableName($table) - . ' DROP CONSTRAINT ' . $this->db->quoteColumnName($name); - } - - /** - * Builds a SQL statement for truncating a DB table. - * @param string $table the table to be truncated. The name will be properly quoted by the method. - * @return string the SQL statement for truncating a DB table. - */ - public function truncateTable($table) - { - return "TRUNCATE TABLE " . $this->db->quoteTableName($table); - } - - /** - * Builds a SQL statement for adding a new DB column. - * @param string $table the table that the new column will be added to. The table name will be properly quoted by the method. - * @param string $column the name of the new column. The name will be properly quoted by the method. - * @param string $type the column type. The [[getColumnType()]] method will be invoked to convert abstract column type (if any) - * into the physical one. Anything that is not recognized as abstract type will be kept in the generated SQL. - * For example, 'string' will be turned into 'varchar(255)', while 'string not null' will become 'varchar(255) not null'. - * @return string the SQL statement for adding a new column. - */ - public function addColumn($table, $column, $type) - { - return 'ALTER TABLE ' . $this->db->quoteTableName($table) - . ' ADD ' . $this->db->quoteColumnName($column) . ' ' - . $this->getColumnType($type); - } - - /** - * Builds a SQL statement for dropping a DB column. - * @param string $table the table whose column is to be dropped. The name will be properly quoted by the method. - * @param string $column the name of the column to be dropped. The name will be properly quoted by the method. - * @return string the SQL statement for dropping a DB column. - */ - public function dropColumn($table, $column) - { - return "ALTER TABLE " . $this->db->quoteTableName($table) - . " DROP COLUMN " . $this->db->quoteColumnName($column); - } - - /** - * Builds a SQL statement for renaming a column. - * @param string $table the table whose column is to be renamed. The name will be properly quoted by the method. - * @param string $oldName the old name of the column. The name will be properly quoted by the method. - * @param string $newName the new name of the column. The name will be properly quoted by the method. - * @return string the SQL statement for renaming a DB column. - */ - public function renameColumn($table, $oldName, $newName) - { - return "ALTER TABLE " . $this->db->quoteTableName($table) - . " RENAME COLUMN " . $this->db->quoteColumnName($oldName) - . " TO " . $this->db->quoteColumnName($newName); - } - - /** - * Builds a SQL statement for changing the definition of a column. - * @param string $table the table whose column is to be changed. The table name will be properly quoted by the method. - * @param string $column the name of the column to be changed. The name will be properly quoted by the method. - * @param string $type the new column type. The [[getColumnType()]] method will be invoked to convert abstract - * column type (if any) into the physical one. Anything that is not recognized as abstract type will be kept - * in the generated SQL. For example, 'string' will be turned into 'varchar(255)', while 'string not null' - * will become 'varchar(255) not null'. - * @return string the SQL statement for changing the definition of a column. - */ - public function alterColumn($table, $column, $type) - { - return 'ALTER TABLE ' . $this->db->quoteTableName($table) . ' CHANGE ' - . $this->db->quoteColumnName($column) . ' ' - . $this->db->quoteColumnName($column) . ' ' - . $this->getColumnType($type); - } - - /** - * Builds a SQL statement for adding a foreign key constraint to an existing table. - * The method will properly quote the table and column names. - * @param string $name the name of the foreign key constraint. - * @param string $table the table that the foreign key constraint will be added to. - * @param string|array $columns the name of the column to that the constraint will be added on. - * If there are multiple columns, separate them with commas or use an array to represent them. - * @param string $refTable the table that the foreign key references to. - * @param string|array $refColumns the name of the column that the foreign key references to. - * If there are multiple columns, separate them with commas or use an array to represent them. - * @param string $delete the ON DELETE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL - * @param string $update the ON UPDATE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL - * @return string the SQL statement for adding a foreign key constraint to an existing table. - */ - public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete = null, $update = null) - { - $sql = 'ALTER TABLE ' . $this->db->quoteTableName($table) - . ' ADD CONSTRAINT ' . $this->db->quoteColumnName($name) - . ' FOREIGN KEY (' . $this->buildColumns($columns) . ')' - . ' REFERENCES ' . $this->db->quoteTableName($refTable) - . ' (' . $this->buildColumns($refColumns) . ')'; - if ($delete !== null) { - $sql .= ' ON DELETE ' . $delete; - } - if ($update !== null) { - $sql .= ' ON UPDATE ' . $update; - } - return $sql; - } - - /** - * Builds a SQL statement for dropping a foreign key constraint. - * @param string $name the name of the foreign key constraint to be dropped. The name will be properly quoted by the method. - * @param string $table the table whose foreign is to be dropped. The name will be properly quoted by the method. - * @return string the SQL statement for dropping a foreign key constraint. - */ - public function dropForeignKey($name, $table) - { - return 'ALTER TABLE ' . $this->db->quoteTableName($table) - . ' DROP CONSTRAINT ' . $this->db->quoteColumnName($name); - } - - /** - * Builds a SQL statement for creating a new index. - * @param string $name the name of the index. The name will be properly quoted by the method. - * @param string $table the table that the new index will be created for. The table name will be properly quoted by the method. - * @param string|array $columns the column(s) that should be included in the index. If there are multiple columns, - * separate them with commas or use an array to represent them. Each column name will be properly quoted - * by the method, unless a parenthesis is found in the name. - * @param boolean $unique whether to add UNIQUE constraint on the created index. - * @return string the SQL statement for creating a new index. - */ - public function createIndex($name, $table, $columns, $unique = false) - { - return ($unique ? 'CREATE UNIQUE INDEX ' : 'CREATE INDEX ') - . $this->db->quoteTableName($name) . ' ON ' - . $this->db->quoteTableName($table) - . ' (' . $this->buildColumns($columns) . ')'; - } - - /** - * Builds a SQL statement for dropping an index. - * @param string $name the name of the index to be dropped. The name will be properly quoted by the method. - * @param string $table the table whose index is to be dropped. The name will be properly quoted by the method. - * @return string the SQL statement for dropping an index. - */ - public function dropIndex($name, $table) - { - return 'DROP INDEX ' . $this->db->quoteTableName($name) . ' ON ' . $this->db->quoteTableName($table); - } - - /** - * Creates a SQL statement for resetting the sequence value of a table's primary key. - * The sequence will be reset such that the primary key of the next new row inserted - * will have the specified value or 1. - * @param string $table the name of the table whose primary key sequence will be reset - * @param array|string $value the value for the primary key of the next new row inserted. If this is not set, - * the next new row's primary key will have a value 1. - * @return string the SQL statement for resetting sequence - * @throws NotSupportedException if this is not supported by the underlying DBMS - */ - public function resetSequence($table, $value = null) - { - throw new NotSupportedException($this->db->getDriverName() . ' does not support resetting sequence.'); - } - - /** - * Builds a SQL statement for enabling or disabling integrity check. - * @param boolean $check whether to turn on or off the integrity check. - * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. - * @param string $table the table name. Defaults to empty string, meaning that no table will be changed. - * @return string the SQL statement for checking integrity - * @throws NotSupportedException if this is not supported by the underlying DBMS - */ - public function checkIntegrity($check = true, $schema = '', $table = '') - { - throw new NotSupportedException($this->db->getDriverName() . ' does not support enabling/disabling integrity check.'); - } - - /** - * Converts an abstract column type into a physical column type. - * The conversion is done using the type map specified in [[typeMap]]. - * The following abstract column types are supported (using MySQL as an example to explain the corresponding - * physical types): - * - * - `pk`: an auto-incremental primary key type, will be converted into "int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY" - * - `bigpk`: an auto-incremental primary key type, will be converted into "bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY" - * - `string`: string type, will be converted into "varchar(255)" - * - `text`: a long string type, will be converted into "text" - * - `smallint`: a small integer type, will be converted into "smallint(6)" - * - `integer`: integer type, will be converted into "int(11)" - * - `bigint`: a big integer type, will be converted into "bigint(20)" - * - `boolean`: boolean type, will be converted into "tinyint(1)" - * - `float``: float number type, will be converted into "float" - * - `decimal`: decimal number type, will be converted into "decimal" - * - `datetime`: datetime type, will be converted into "datetime" - * - `timestamp`: timestamp type, will be converted into "timestamp" - * - `time`: time type, will be converted into "time" - * - `date`: date type, will be converted into "date" - * - `money`: money type, will be converted into "decimal(19,4)" - * - `binary`: binary data type, will be converted into "blob" - * - * If the abstract type contains two or more parts separated by spaces (e.g. "string NOT NULL"), then only - * the first part will be converted, and the rest of the parts will be appended to the converted result. - * For example, 'string NOT NULL' is converted to 'varchar(255) NOT NULL'. - * - * For some of the abstract types you can also specify a length or precision constraint - * by prepending it in round brackets directly to the type. - * For example `string(32)` will be converted into "varchar(32)" on a MySQL database. - * If the underlying DBMS does not support these kind of constraints for a type it will - * be ignored. - * - * If a type cannot be found in [[typeMap]], it will be returned without any change. - * @param string $type abstract column type - * @return string physical column type. - */ - public function getColumnType($type) - { - if (isset($this->typeMap[$type])) { - return $this->typeMap[$type]; - } elseif (preg_match('/^(\w+)\((.+?)\)(.*)$/', $type, $matches)) { - if (isset($this->typeMap[$matches[1]])) { - return preg_replace('/\(.+\)/', '(' . $matches[2] . ')', $this->typeMap[$matches[1]]) . $matches[3]; - } - } elseif (preg_match('/^(\w+)\s+/', $type, $matches)) { - if (isset($this->typeMap[$matches[1]])) { - return preg_replace('/^\w+/', $this->typeMap[$matches[1]], $type); - } - } - return $type; - } - - /** - * @param array $columns - * @param boolean $distinct - * @param string $selectOption - * @return string the SELECT clause built from [[query]]. - */ - public function buildSelect($columns, $distinct = false, $selectOption = null) - { - $select = $distinct ? 'SELECT DISTINCT' : 'SELECT'; - if ($selectOption !== null) { - $select .= ' ' . $selectOption; - } - - if (empty($columns)) { - return $select . ' *'; - } - - foreach ($columns as $i => $column) { - if (is_object($column)) { - $columns[$i] = (string)$column; - } elseif (strpos($column, '(') === false) { - if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)([\w\-_\.]+)$/', $column, $matches)) { - $columns[$i] = $this->db->quoteColumnName($matches[1]) . ' AS ' . $this->db->quoteColumnName($matches[2]); - } else { - $columns[$i] = $this->db->quoteColumnName($column); - } - } - } - - if (is_array($columns)) { - $columns = implode(', ', $columns); - } - - return $select . ' ' . $columns; - } - - /** - * @param array $tables - * @return string the FROM clause built from [[query]]. - */ - public function buildFrom($tables) - { - if (empty($tables)) { - return ''; - } - - foreach ($tables as $i => $table) { - if (strpos($table, '(') === false) { - if (preg_match('/^(.*?)(?i:\s+as|)\s+([^ ]+)$/', $table, $matches)) { // with alias - $tables[$i] = $this->db->quoteTableName($matches[1]) . ' ' . $this->db->quoteTableName($matches[2]); - } else { - $tables[$i] = $this->db->quoteTableName($table); - } - } - } - - if (is_array($tables)) { - $tables = implode(', ', $tables); - } - - return 'FROM ' . $tables; - } - - /** - * @param string|array $joins - * @param array $params the binding parameters to be populated - * @return string the JOIN clause built from [[query]]. - * @throws Exception if the $joins parameter is not in proper format - */ - public function buildJoin($joins, &$params) - { - if (empty($joins)) { - return ''; - } - - foreach ($joins as $i => $join) { - if (is_object($join)) { - $joins[$i] = (string)$join; - } elseif (is_array($join) && isset($join[0], $join[1])) { - // 0:join type, 1:table name, 2:on-condition - $table = $join[1]; - if (strpos($table, '(') === false) { - if (preg_match('/^(.*?)(?i:\s+as|)\s+([^ ]+)$/', $table, $matches)) { // with alias - $table = $this->db->quoteTableName($matches[1]) . ' ' . $this->db->quoteTableName($matches[2]); - } else { - $table = $this->db->quoteTableName($table); - } - } - $joins[$i] = $join[0] . ' ' . $table; - if (isset($join[2])) { - $condition = $this->buildCondition($join[2], $params); - if ($condition !== '') { - $joins[$i] .= ' ON ' . $condition; - } - } - } else { - throw new Exception('A join clause must be specified as an array of join type, join table, and optionally join condition.'); - } - } - - return implode($this->separator, $joins); - } - - /** - * @param string|array $condition - * @param array $params the binding parameters to be populated - * @return string the WHERE clause built from [[query]]. - */ - public function buildWhere($condition, &$params) - { - $where = $this->buildCondition($condition, $params); - return $where === '' ? '' : 'WHERE ' . $where; - } - - /** - * @param array $columns - * @return string the GROUP BY clause - */ - public function buildGroupBy($columns) - { - return empty($columns) ? '' : 'GROUP BY ' . $this->buildColumns($columns); - } - - /** - * @param string|array $condition - * @param array $params the binding parameters to be populated - * @return string the HAVING clause built from [[query]]. - */ - public function buildHaving($condition, &$params) - { - $having = $this->buildCondition($condition, $params); - return $having === '' ? '' : 'HAVING ' . $having; - } - - /** - * @param array $columns - * @return string the ORDER BY clause built from [[query]]. - */ - public function buildOrderBy($columns) - { - if (empty($columns)) { - return ''; - } - $orders = []; - foreach ($columns as $name => $direction) { - if (is_object($direction)) { - $orders[] = (string)$direction; - } else { - $orders[] = $this->db->quoteColumnName($name) . ($direction === SORT_DESC ? ' DESC' : ''); - } - } - - return 'ORDER BY ' . implode(', ', $orders); - } - - /** - * @param integer $limit - * @param integer $offset - * @return string the LIMIT and OFFSET clauses built from [[query]]. - */ - public function buildLimit($limit, $offset) - { - $sql = ''; - if ($limit !== null && $limit >= 0) { - $sql = 'LIMIT ' . (int)$limit; - } - if ($offset > 0) { - $sql .= ' OFFSET ' . (int)$offset; - } - return ltrim($sql); - } - - /** - * @param array $unions - * @param array $params the binding parameters to be populated - * @return string the UNION clause built from [[query]]. - */ - public function buildUnion($unions, &$params) - { - if (empty($unions)) { - return ''; - } - foreach ($unions as $i => $union) { - if ($union instanceof Query) { - // save the original parameters so that we can restore them later to prevent from modifying the query object - $originalParams = $union->params; - $union->addParams($params); - list ($unions[$i], $params) = $this->build($union); - $union->params = $originalParams; - } - } - return "UNION (\n" . implode("\n) UNION (\n", $unions) . "\n)"; - } - - /** - * Processes columns and properly quote them if necessary. - * It will join all columns into a string with comma as separators. - * @param string|array $columns the columns to be processed - * @return string the processing result - */ - public function buildColumns($columns) - { - if (!is_array($columns)) { - if (strpos($columns, '(') !== false) { - return $columns; - } else { - $columns = preg_split('/\s*,\s*/', $columns, -1, PREG_SPLIT_NO_EMPTY); - } - } - foreach ($columns as $i => $column) { - if (is_object($column)) { - $columns[$i] = (string)$column; - } elseif (strpos($column, '(') === false) { - $columns[$i] = $this->db->quoteColumnName($column); - } - } - return is_array($columns) ? implode(', ', $columns) : $columns; - } - - - /** - * 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 InvalidParamException if the condition is in bad format - */ - public function buildCondition($condition, &$params) - { - static $builders = [ - '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 (!is_array($condition)) { - return (string)$condition; - } elseif (empty($condition)) { - return ''; - } - if (isset($condition[0])) { // operator format: operator, operand 1, operand 2, ... - $operator = strtoupper($condition[0]); - if (isset($builders[$operator])) { - $method = $builders[$operator]; - array_shift($condition); - return $this->$method($operator, $condition, $params); - } else { - throw new InvalidParamException('Found unknown operator in query: ' . $operator); - } - } else { // hash format: 'column1' => 'value1', 'column2' => 'value2', ... - return $this->buildHashCondition($condition, $params); - } - } - - /** - * Creates a condition based on column-value pairs. - * @param array $condition the condition specification. - * @param array $params the binding parameters to be populated - * @return string the generated SQL expression - */ - public function buildHashCondition($condition, &$params) - { - $parts = []; - foreach ($condition as $column => $value) { - if (is_array($value)) { // IN condition - $parts[] = $this->buildInCondition('IN', [$column, $value], $params); - } else { - if (strpos($column, '(') === false) { - $column = $this->db->quoteColumnName($column); - } - if ($value === null) { - $parts[] = "$column IS NULL"; - } elseif ($value instanceof Expression) { - $parts[] = "$column=" . $value->expression; - foreach ($value->params as $n => $v) { - $params[$n] = $v; - } - } else { - $phName = self::PARAM_PREFIX . count($params); - $parts[] = "$column=$phName"; - $params[$phName] = $value; - } - } - } - return count($parts) === 1 ? $parts[0] : '(' . implode(') AND (', $parts) . ')'; - } - - /** - * Connects two or more SQL expressions with the `AND` or `OR` operator. - * @param string $operator the operator to use for connecting the given operands - * @param array $operands the SQL expressions to connect. - * @param array $params the binding parameters to be populated - * @return string the generated SQL expression - */ - public function buildAndCondition($operator, $operands, &$params) - { - $parts = []; - foreach ($operands as $operand) { - if (is_array($operand)) { - $operand = $this->buildCondition($operand, $params); - } - if ($operand !== '') { - $parts[] = $operand; - } - } - if (!empty($parts)) { - return '(' . implode(") $operator (", $parts) . ')'; - } else { - return ''; - } - } - - /** - * Inverts an SQL expressions with `NOT` operator. - * @param string $operator the operator to use for connecting the given operands - * @param array $operands the SQL expressions to connect. - * @param array $params the binding parameters to be populated - * @return string the generated SQL expression - * @throws InvalidParamException if wrong number of operands have been given. - */ - public 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); - } - if ($operand === '') { - return ''; - } - return "$operator ($operand)"; - } - - /** - * Creates an SQL expressions with the `BETWEEN` operator. - * @param string $operator the operator to use (e.g. `BETWEEN` or `NOT BETWEEN`) - * @param array $operands the first operand is the column name. The second and third operands - * describe the interval that column value should be in. - * @param array $params the binding parameters to be populated - * @return string the generated SQL expression - * @throws InvalidParamException if wrong number of operands have been given. - */ - public function buildBetweenCondition($operator, $operands, &$params) - { - if (!isset($operands[0], $operands[1], $operands[2])) { - throw new InvalidParamException("Operator '$operator' requires three operands."); - } - - list($column, $value1, $value2) = $operands; - - if (strpos($column, '(') === false) { - $column = $this->db->quoteColumnName($column); - } - $phName1 = self::PARAM_PREFIX . count($params); - $params[$phName1] = $value1; - $phName2 = self::PARAM_PREFIX . count($params); - $params[$phName2] = $value2; - - return "$column $operator $phName1 AND $phName2"; - } - - /** - * Creates an SQL expressions with the `IN` operator. - * @param string $operator the operator to use (e.g. `IN` or `NOT IN`) - * @param array $operands the first operand is the column name. If it is an array - * a composite IN condition will be generated. - * The second operand is an array of values that column value should be among. - * If it is an empty array the generated expression will be a `false` value if - * operator is `IN` and empty if operator is `NOT IN`. - * @param array $params the binding parameters to be populated - * @return string the generated SQL expression - * @throws Exception if wrong number of operands have been given. - */ - public function buildInCondition($operator, $operands, &$params) - { - if (!isset($operands[0], $operands[1])) { - throw new Exception("Operator '$operator' requires two operands."); - } - - list($column, $values) = $operands; - - $values = (array)$values; - - if (empty($values) || $column === []) { - return $operator === 'IN' ? '0=1' : ''; - } - - if (count($column) > 1) { - return $this->buildCompositeInCondition($operator, $column, $values, $params); - } elseif (is_array($column)) { - $column = reset($column); - } - foreach ($values as $i => $value) { - if (is_array($value)) { - $value = isset($value[$column]) ? $value[$column] : null; - } - if ($value === null) { - $values[$i] = 'NULL'; - } elseif ($value instanceof Expression) { - $values[$i] = $value->expression; - foreach ($value->params as $n => $v) { - $params[$n] = $v; - } - } else { - $phName = self::PARAM_PREFIX . count($params); - $params[$phName] = $value; - $values[$i] = $phName; - } - } - if (strpos($column, '(') === false) { - $column = $this->db->quoteColumnName($column); - } - - if (count($values) > 1) { - return "$column $operator (" . implode(', ', $values) . ')'; - } else { - $operator = $operator === 'IN' ? '=' : '<>'; - return "$column$operator{$values[0]}"; - } - } - - protected function buildCompositeInCondition($operator, $columns, $values, &$params) - { - $vss = []; - foreach ($values as $value) { - $vs = []; - foreach ($columns as $column) { - if (isset($value[$column])) { - $phName = self::PARAM_PREFIX . count($params); - $params[$phName] = $value[$column]; - $vs[] = $phName; - } else { - $vs[] = 'NULL'; - } - } - $vss[] = '(' . implode(', ', $vs) . ')'; - } - foreach ($columns as $i => $column) { - if (strpos($column, '(') === false) { - $columns[$i] = $this->db->quoteColumnName($column); - } - } - return '(' . implode(', ', $columns) . ") $operator (" . implode(', ', $vss) . ')'; - } - - /** - * Creates an SQL expressions with the `LIKE` operator. - * @param string $operator the operator to use (e.g. `LIKE`, `NOT LIKE`, `OR LIKE` or `OR NOT LIKE`) - * @param array $operands an array of two or three operands - * - * - The first operand is the column name. - * - The second operand is a single value or an array of values that column value - * should be compared with. If it is an empty array the generated expression will - * be a `false` value if operator is `LIKE` or `OR LIKE`, and empty if operator - * is `NOT LIKE` or `OR NOT LIKE`. - * - An optional third operand can also be provided to specify how to escape special characters - * in the value(s). The operand should be an array of mappings from the special characters to their - * escaped counterparts. If this operand is not provided, a default escape mapping will be used. - * You may use `false` or an empty array to indicate the values are already escaped and no escape - * should be applied. Note that when using an escape mapping (or the third operand is not provided), - * the values will be automatically enclosed within a pair of percentage characters. - * @param array $params the binding parameters to be populated - * @return string the generated SQL expression - * @throws InvalidParamException if wrong number of operands have been given. - */ - public function buildLikeCondition($operator, $operands, &$params) - { - if (!isset($operands[0], $operands[1])) { - throw new InvalidParamException("Operator '$operator' requires two operands."); - } - - $escape = isset($operands[2]) ? $operands[2] : ['%'=>'\%', '_'=>'\_', '\\'=>'\\\\']; - unset($operands[2]); - - list($column, $values) = $operands; - - $values = (array)$values; - - if (empty($values)) { - return $operator === 'LIKE' || $operator === 'OR LIKE' ? '0=1' : ''; - } - - if ($operator === 'LIKE' || $operator === 'NOT LIKE') { - $andor = ' AND '; - } else { - $andor = ' OR '; - $operator = $operator === 'OR LIKE' ? 'LIKE' : 'NOT LIKE'; - } - - if (strpos($column, '(') === false) { - $column = $this->db->quoteColumnName($column); - } - - $parts = []; - foreach ($values as $value) { - $phName = self::PARAM_PREFIX . count($params); - $params[$phName] = empty($escape) ? $value : ('%' . strtr($value, $escape) . '%'); - $parts[] = "$column $operator $phName"; - } - - return implode($andor, $parts); - } -} diff --git a/framework/yii/db/QueryInterface.php b/framework/yii/db/QueryInterface.php deleted file mode 100644 index 4cf802d..0000000 --- a/framework/yii/db/QueryInterface.php +++ /dev/null @@ -1,208 +0,0 @@ - - * @author Carsten Brandt - * @since 2.0 - */ -interface QueryInterface -{ - /** - * 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 `db` 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); - - /** - * 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 `db` 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); - - /** - * Returns the number of records. - * @param string $q the COUNT expression. Defaults to '*'. - * @param Connection $db the database connection used to execute the query. - * If this parameter is not given, the `db` application component will be used. - * @return integer number of records - */ - public function count($q = '*', $db = null); - - /** - * 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 `db` application component will be used. - * @return boolean whether the query result contains any row of data. - */ - public function exists($db = null); - - /** - * Sets the [[indexBy]] property. - * @param string|callable $column the name of the column by which the query results should be indexed by. - * This can also be a callable (e.g. anonymous function) that returns the index value based on the given - * row data. The signature of the callable should be: - * - * ~~~ - * function ($row) - * { - * // return the index value corresponding to $row - * } - * ~~~ - * - * @return static the query object itself - */ - public function indexBy($column); - - /** - * Sets the WHERE part of the query. - * - * The method requires a $condition parameter. - * - * The $condition parameter should be an array in one of the following two formats: - * - * - hash format: `['column1' => value1, 'column2' => value2, ...]` - * - operator format: `[operator, operand1, operand2, ...]` - * - * A condition in hash format represents the following SQL expression in general: - * `column1=value1 AND column2=value2 AND ...`. In case when a value is an array, - * an `IN` expression will be generated. And if a value is null, `IS NULL` will be used - * in the generated expression. Below are some examples: - * - * - `['type' => 1, 'status' => 2]` generates `(type = 1) AND (status = 2)`. - * - `['id' => [1, 2, 3], 'status' => 2]` generates `(id IN (1, 2, 3)) AND (status = 2)`. - * - `['status' => null] generates `status IS NULL`. - * - * A condition in operator format generates the SQL expression according to the specified operator, which - * can be one of the followings: - * - * - `and`: the operands should be concatenated together using `AND`. For example, - * `['and', 'id=1', 'id=2']` will generate `id=1 AND id=2`. If an operand is an array, - * it will be converted into a string using the rules described here. For example, - * `['and', 'type=1', ['or', 'id=1', 'id=2']]` will generate `type=1 AND (id=1 OR id=2)`. - * The method will NOT do any quoting or escaping. - * - * - `or`: similar to the `and` operator except that the operands are concatenated using `OR`. - * - * - `between`: operand 1 should be the column name, and operand 2 and 3 should be the - * starting and ending values of the range that the column is in. - * For example, `['between', 'id', 1, 10]` will generate `id BETWEEN 1 AND 10`. - * - * - `not between`: similar to `between` except the `BETWEEN` is replaced with `NOT BETWEEN` - * in the generated condition. - * - * - `in`: operand 1 should be a column or DB expression, and operand 2 be an array representing - * the range of the values that the column or DB expression should be in. For example, - * `['in', 'id', [1, 2, 3]]` will generate `id IN (1, 2, 3)`. - * The method will properly quote the column name and escape values in the range. - * - * - `not in`: similar to the `in` operator except that `IN` is replaced with `NOT IN` in the generated condition. - * - * - `like`: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing - * the values that the column or DB expression should be like. - * For example, `['like', 'name', 'tester']` will generate `name LIKE '%tester%'`. - * When the value range is given as an array, multiple `LIKE` predicates will be generated and concatenated - * using `AND`. For example, `['like', 'name', ['test', 'sample']]` will generate - * `name LIKE '%test%' AND name LIKE '%sample%'`. - * The method will properly quote the column name and escape special characters in the values. - * Sometimes, you may want to add the percentage characters to the matching value by yourself, you may supply - * a third operand `false` to do so. For example, `['like', 'name', '%tester', false]` will generate `name LIKE '%tester'`. - * - * - `or like`: similar to the `like` operator except that `OR` is used to concatenate the `LIKE` - * predicates when operand 2 is an array. - * - * - `not like`: similar to the `like` operator except that `LIKE` is replaced with `NOT LIKE` - * in the generated condition. - * - * - `or not like`: similar to the `not like` operator except that `OR` is used to concatenate - * the `NOT LIKE` predicates. - * - * @param array $condition the conditions that should be put in the WHERE part. - * @return static the query object itself - * @see andWhere() - * @see orWhere() - */ - public function where($condition); - - /** - * Adds an additional WHERE condition to the existing one. - * The new condition and the existing one will be joined using the 'AND' operator. - * @param string|array $condition the new WHERE condition. Please refer to [[where()]] - * on how to specify this parameter. - * @return static the query object itself - * @see where() - * @see orWhere() - */ - public function andWhere($condition); - - /** - * Adds an additional WHERE condition to the existing one. - * The new condition and the existing one will be joined using the 'OR' operator. - * @param string|array $condition the new WHERE condition. Please refer to [[where()]] - * on how to specify this parameter. - * @return static the query object itself - * @see where() - * @see andWhere() - */ - public function orWhere($condition); - - /** - * Sets the ORDER BY part of the query. - * @param string|array $columns the columns (and the directions) to be ordered by. - * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array - * (e.g. `['id' => SORT_ASC, 'name' => SORT_DESC]`). - * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a DB expression). - * @return static the query object itself - * @see addOrderBy() - */ - public function orderBy($columns); - - /** - * Adds additional ORDER BY columns to the query. - * @param string|array $columns the columns (and the directions) to be ordered by. - * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array - * (e.g. `['id' => SORT_ASC, 'name' => SORT_DESC]`). - * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a DB expression). - * @return static the query object itself - * @see orderBy() - */ - public function addOrderBy($columns); - - /** - * Sets the LIMIT part of the query. - * @param integer $limit the limit. Use null or negative value to disable limit. - * @return static the query object itself - */ - public function limit($limit); - - /** - * Sets the OFFSET part of the query. - * @param integer $offset the offset. Use null or negative value to disable offset. - * @return static the query object itself - */ - public function offset($offset); -} diff --git a/framework/yii/db/QueryTrait.php b/framework/yii/db/QueryTrait.php deleted file mode 100644 index 029b675..0000000 --- a/framework/yii/db/QueryTrait.php +++ /dev/null @@ -1,211 +0,0 @@ - - * @author Carsten Brandt - * @since 2.0 - */ -trait QueryTrait -{ - /** - * @var string|array query condition. This refers to the WHERE clause in a SQL statement. - * For example, `age > 31 AND team = 1`. - * @see where() - */ - public $where; - /** - * @var integer maximum number of records to be returned. If not set or less than 0, it means no limit. - */ - public $limit; - /** - * @var integer zero-based offset from where the records are to be returned. If not set or - * less than 0, it means starting from the beginning. - */ - public $offset; - /** - * @var array how to sort the query results. This is used to construct the ORDER BY clause in a SQL statement. - * The array keys are the columns to be sorted by, and the array values are the corresponding sort directions which - * can be either [SORT_ASC](http://php.net/manual/en/array.constants.php#constant.sort-asc) - * or [SORT_DESC](http://php.net/manual/en/array.constants.php#constant.sort-desc). - * The array may also contain [[Expression]] objects. If that is the case, the expressions - * will be converted into strings without any change. - */ - public $orderBy; - /** - * @var string|callable $column the name of the column by which the query results should be indexed by. - * This can also be a callable (e.g. anonymous function) that returns the index value based on the given - * row data. For more details, see [[indexBy()]]. This property is only used by [[all()]]. - */ - public $indexBy; - - /** - * Sets the [[indexBy]] property. - * @param string|callable $column the name of the column by which the query results should be indexed by. - * This can also be a callable (e.g. anonymous function) that returns the index value based on the given - * row data. The signature of the callable should be: - * - * ~~~ - * function ($row) - * { - * // return the index value corresponding to $row - * } - * ~~~ - * - * @return static the query object itself - */ - public function indexBy($column) - { - $this->indexBy = $column; - return $this; - } - - /** - * Sets the WHERE part of the query. - * - * See [[QueryInterface::where()]] for detailed documentation. - * - * @param array $condition the conditions that should be put in the WHERE part. - * @return static the query object itself - * @see andWhere() - * @see orWhere() - */ - public function where($condition) - { - $this->where = $condition; - return $this; - } - - /** - * Adds an additional WHERE condition to the existing one. - * The new condition and the existing one will be joined using the 'AND' operator. - * @param string|array $condition the new WHERE condition. Please refer to [[where()]] - * on how to specify this parameter. - * @return static the query object itself - * @see where() - * @see orWhere() - */ - public function andWhere($condition) - { - if ($this->where === null) { - $this->where = $condition; - } else { - $this->where = ['and', $this->where, $condition]; - } - return $this; - } - - /** - * Adds an additional WHERE condition to the existing one. - * The new condition and the existing one will be joined using the 'OR' operator. - * @param string|array $condition the new WHERE condition. Please refer to [[where()]] - * on how to specify this parameter. - * @return static the query object itself - * @see where() - * @see andWhere() - */ - public function orWhere($condition) - { - if ($this->where === null) { - $this->where = $condition; - } else { - $this->where = ['or', $this->where, $condition]; - } - return $this; - } - - /** - * Sets the ORDER BY part of the query. - * @param string|array $columns the columns (and the directions) to be ordered by. - * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array - * (e.g. `['id' => SORT_ASC, 'name' => SORT_DESC]`). - * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a DB expression). - * Note that if your order-by is an expression containing commas, you should always use an array - * to represent the order-by information. Otherwise, the method will not be able to correctly determine - * the order-by columns. - * @return static the query object itself - * @see addOrderBy() - */ - public function orderBy($columns) - { - $this->orderBy = $this->normalizeOrderBy($columns); - return $this; - } - - /** - * Adds additional ORDER BY columns to the query. - * @param string|array $columns the columns (and the directions) to be ordered by. - * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array - * (e.g. `['id' => SORT_ASC, 'name' => SORT_DESC]`). - * The method will automatically quote the column names unless a column contains some parenthesis - * (which means the column contains a DB expression). - * @return static the query object itself - * @see orderBy() - */ - public function addOrderBy($columns) - { - $columns = $this->normalizeOrderBy($columns); - if ($this->orderBy === null) { - $this->orderBy = $columns; - } else { - $this->orderBy = array_merge($this->orderBy, $columns); - } - return $this; - } - - protected function normalizeOrderBy($columns) - { - if (is_array($columns)) { - return $columns; - } else { - $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); - $result = []; - foreach ($columns as $column) { - if (preg_match('/^(.*?)\s+(asc|desc)$/i', $column, $matches)) { - $result[$matches[1]] = strcasecmp($matches[2], 'desc') ? SORT_ASC : SORT_DESC; - } else { - $result[$column] = SORT_ASC; - } - } - return $result; - } - } - - /** - * Sets the LIMIT part of the query. - * @param integer $limit the limit. Use null or negative value to disable limit. - * @return static the query object itself - */ - public function limit($limit) - { - $this->limit = $limit; - return $this; - } - - /** - * Sets the OFFSET part of the query. - * @param integer $offset the offset. Use null or negative value to disable offset. - * @return static the query object itself - */ - public function offset($offset) - { - $this->offset = $offset; - return $this; - } -} diff --git a/framework/yii/db/Schema.php b/framework/yii/db/Schema.php deleted file mode 100644 index 9698179..0000000 --- a/framework/yii/db/Schema.php +++ /dev/null @@ -1,424 +0,0 @@ - - * @since 2.0 - */ -abstract class Schema extends Object -{ - /** - * The followings are the supported abstract column data types. - */ - const TYPE_PK = 'pk'; - const TYPE_BIGPK = 'bigpk'; - const TYPE_STRING = 'string'; - const TYPE_TEXT = 'text'; - const TYPE_SMALLINT = 'smallint'; - const TYPE_INTEGER = 'integer'; - const TYPE_BIGINT = 'bigint'; - const TYPE_FLOAT = 'float'; - const TYPE_DECIMAL = 'decimal'; - const TYPE_DATETIME = 'datetime'; - const TYPE_TIMESTAMP = 'timestamp'; - const TYPE_TIME = 'time'; - const TYPE_DATE = 'date'; - const TYPE_BINARY = 'binary'; - const TYPE_BOOLEAN = 'boolean'; - const TYPE_MONEY = 'money'; - - /** - * @var Connection the database connection - */ - public $db; - /** - * @var array list of ALL table names in the database - */ - private $_tableNames = []; - /** - * @var array list of loaded table metadata (table name => TableSchema) - */ - private $_tables = []; - /** - * @var QueryBuilder the query builder for this database - */ - private $_builder; - - /** - * Loads the metadata for the specified table. - * @param string $name table name - * @return TableSchema DBMS-dependent table metadata, null if the table does not exist. - */ - abstract protected function loadTableSchema($name); - - - /** - * Obtains the metadata for the named table. - * @param string $name table name. The table name may contain schema name if any. Do not quote the table name. - * @param boolean $refresh whether to reload the table schema even if it is found in the cache. - * @return TableSchema table metadata. Null if the named table does not exist. - */ - public function getTableSchema($name, $refresh = false) - { - if (isset($this->_tables[$name]) && !$refresh) { - return $this->_tables[$name]; - } - - $db = $this->db; - $realName = $this->getRawTableName($name); - - if ($db->enableSchemaCache && !in_array($name, $db->schemaCacheExclude, true)) { - /** @var Cache $cache */ - $cache = is_string($db->schemaCache) ? Yii::$app->getComponent($db->schemaCache) : $db->schemaCache; - if ($cache instanceof Cache) { - $key = $this->getCacheKey($name); - if ($refresh || ($table = $cache->get($key)) === false) { - $table = $this->loadTableSchema($realName); - if ($table !== null) { - $cache->set($key, $table, $db->schemaCacheDuration, new GroupDependency([ - 'group' => $this->getCacheGroup(), - ])); - } - } - return $this->_tables[$name] = $table; - } - } - return $this->_tables[$name] = $table = $this->loadTableSchema($realName); - } - - /** - * Returns the cache key for the specified table name. - * @param string $name the table name - * @return mixed the cache key - */ - protected function getCacheKey($name) - { - return [ - __CLASS__, - $this->db->dsn, - $this->db->username, - $name, - ]; - } - - /** - * Returns the cache group name. - * This allows [[refresh()]] to invalidate all cached table schemas. - * @return string the cache group name - */ - protected function getCacheGroup() - { - return md5(serialize([ - __CLASS__, - $this->db->dsn, - $this->db->username, - ])); - } - - /** - * Returns the metadata for all tables in the database. - * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name. - * @param boolean $refresh whether to fetch the latest available table schemas. If this is false, - * cached data may be returned if available. - * @return TableSchema[] the metadata for all tables in the database. - * Each array element is an instance of [[TableSchema]] or its child class. - */ - public function getTableSchemas($schema = '', $refresh = false) - { - $tables = []; - foreach ($this->getTableNames($schema, $refresh) as $name) { - if ($schema !== '') { - $name = $schema . '.' . $name; - } - if (($table = $this->getTableSchema($name, $refresh)) !== null) { - $tables[] = $table; - } - } - return $tables; - } - - /** - * Returns all table names in the database. - * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name. - * If not empty, the returned table names will be prefixed with the schema name. - * @param boolean $refresh whether to fetch the latest available table names. If this is false, - * table names fetched previously (if available) will be returned. - * @return string[] all table names in the database. - */ - public function getTableNames($schema = '', $refresh = false) - { - if (!isset($this->_tableNames[$schema]) || $refresh) { - $this->_tableNames[$schema] = $this->findTableNames($schema); - } - return $this->_tableNames[$schema]; - } - - /** - * @return QueryBuilder the query builder for this connection. - */ - public function getQueryBuilder() - { - if ($this->_builder === null) { - $this->_builder = $this->createQueryBuilder(); - } - return $this->_builder; - } - - /** - * Determines the PDO type for the given PHP data value. - * @param mixed $data the data whose PDO type is to be determined - * @return integer the PDO type - * @see http://www.php.net/manual/en/pdo.constants.php - */ - public function getPdoType($data) - { - static $typeMap = [ - // php type => PDO type - 'boolean' => \PDO::PARAM_BOOL, - 'integer' => \PDO::PARAM_INT, - 'string' => \PDO::PARAM_STR, - 'resource' => \PDO::PARAM_LOB, - 'NULL' => \PDO::PARAM_NULL, - ]; - $type = gettype($data); - return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR; - } - - /** - * Refreshes the schema. - * This method cleans up all cached table schemas so that they can be re-created later - * to reflect the database schema change. - */ - public function refresh() - { - /** @var Cache $cache */ - $cache = is_string($this->db->schemaCache) ? Yii::$app->getComponent($this->db->schemaCache) : $this->db->schemaCache; - if ($this->db->enableSchemaCache && $cache instanceof Cache) { - GroupDependency::invalidate($cache, $this->getCacheGroup()); - } - $this->_tableNames = []; - $this->_tables = []; - } - - /** - * Creates a query builder for the database. - * This method may be overridden by child classes to create a DBMS-specific query builder. - * @return QueryBuilder query builder instance - */ - public function createQueryBuilder() - { - return new QueryBuilder($this->db); - } - - /** - * Returns all table names in the database. - * This method should be overridden by child classes in order to support this feature - * because the default implementation simply throws an exception. - * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. - * @return array all table names in the database. The names have NO schema name prefix. - * @throws NotSupportedException if this method is called - */ - protected function findTableNames($schema = '') - { - throw new NotSupportedException(get_class($this) . ' does not support fetching all table names.'); - } - - /** - * Returns all unique indexes for the given table. - * Each array element is of the following structure: - * - * ~~~ - * [ - * 'IndexName1' => ['col1' [, ...]], - * 'IndexName2' => ['col2' [, ...]], - * ] - * ~~~ - * - * This method should be overridden by child classes in order to support this feature - * because the default implementation simply throws an exception - * @param TableSchema $table the table metadata - * @return array all unique indexes for the given table. - * @throws NotSupportedException if this method is called - */ - public function findUniqueIndexes($table) - { - throw new NotSupportedException(get_class($this) . ' does not support getting unique indexes information.'); - } - - /** - * Returns the ID of the last inserted row or sequence value. - * @param string $sequenceName name of the sequence object (required by some DBMS) - * @return string the row ID of the last row inserted, or the last value retrieved from the sequence object - * @throws InvalidCallException if the DB connection is not active - * @see http://www.php.net/manual/en/function.PDO-lastInsertId.php - */ - public function getLastInsertID($sequenceName = '') - { - if ($this->db->isActive) { - return $this->db->pdo->lastInsertId($sequenceName); - } else { - throw new InvalidCallException('DB Connection is not active.'); - } - } - - /** - * Quotes a string value for use in a query. - * Note that if the parameter is not a string, it will be returned without change. - * @param string $str string to be quoted - * @return string the properly quoted string - * @see http://www.php.net/manual/en/function.PDO-quote.php - */ - public function quoteValue($str) - { - if (!is_string($str)) { - return $str; - } - - $this->db->open(); - if (($value = $this->db->pdo->quote($str)) !== false) { - return $value; - } else { // the driver doesn't support quote (e.g. oci) - return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") . "'"; - } - } - - /** - * Quotes a table name for use in a query. - * If the table name contains schema prefix, the prefix will also be properly quoted. - * If the table name is already quoted or contains '(' or '{{', - * then this method will do nothing. - * @param string $name table name - * @return string the properly quoted table name - * @see quoteSimpleTableName() - */ - public function quoteTableName($name) - { - if (strpos($name, '(') !== false || strpos($name, '{{') !== false) { - return $name; - } - if (strpos($name, '.') === false) { - return $this->quoteSimpleTableName($name); - } - $parts = explode('.', $name); - foreach ($parts as $i => $part) { - $parts[$i] = $this->quoteSimpleTableName($part); - } - return implode('.', $parts); - - } - - /** - * Quotes a column name for use in a query. - * If the column name contains prefix, the prefix will also be properly quoted. - * If the column name is already quoted or contains '(', '[[' or '{{', - * then this method will do nothing. - * @param string $name column name - * @return string the properly quoted column name - * @see quoteSimpleColumnName() - */ - public function quoteColumnName($name) - { - if (strpos($name, '(') !== false || strpos($name, '[[') !== false || strpos($name, '{{') !== false) { - return $name; - } - if (($pos = strrpos($name, '.')) !== false) { - $prefix = $this->quoteTableName(substr($name, 0, $pos)) . '.'; - $name = substr($name, $pos + 1); - } else { - $prefix = ''; - } - return $prefix . $this->quoteSimpleColumnName($name); - } - - /** - * Quotes a simple table name for use in a query. - * A simple table name should contain the table name only without any schema prefix. - * If the table name is already quoted, this method will do nothing. - * @param string $name table name - * @return string the properly quoted table name - */ - public function quoteSimpleTableName($name) - { - return strpos($name, "'") !== false ? $name : "'" . $name . "'"; - } - - /** - * Quotes a simple column name for use in a query. - * A simple column name should contain the column name only without any prefix. - * If the column name is already quoted or is the asterisk character '*', this method will do nothing. - * @param string $name column name - * @return string the properly quoted column name - */ - public function quoteSimpleColumnName($name) - { - return strpos($name, '"') !== false || $name === '*' ? $name : '"' . $name . '"'; - } - - /** - * Returns the actual name of a given table name. - * This method will strip off curly brackets from the given table name - * and replace the percentage character '%' with [[Connection::tablePrefix]]. - * @param string $name the table name to be converted - * @return string the real name of the given table name - */ - public function getRawTableName($name) - { - if (strpos($name, '{{') !== false) { - $name = preg_replace('/\\{\\{(.*?)\\}\\}/', '\1', $name); - return str_replace('%', $this->db->tablePrefix, $name); - } else { - return $name; - } - } - - /** - * Extracts the PHP type from abstract DB type. - * @param ColumnSchema $column the column schema information - * @return string PHP type name - */ - protected function getColumnPhpType($column) - { - static $typeMap = [ // abstract type => php type - 'smallint' => 'integer', - 'integer' => 'integer', - 'bigint' => 'integer', - 'boolean' => 'boolean', - 'float' => 'double', - ]; - if (isset($typeMap[$column->type])) { - if ($column->type === 'bigint') { - return PHP_INT_SIZE == 8 && !$column->unsigned ? 'integer' : 'string'; - } elseif ($column->type === 'integer') { - return PHP_INT_SIZE == 4 && $column->unsigned ? 'string' : 'integer'; - } else { - return $typeMap[$column->type]; - } - } else { - return 'string'; - } - } -} diff --git a/framework/yii/db/StaleObjectException.php b/framework/yii/db/StaleObjectException.php deleted file mode 100644 index efa8ee9..0000000 --- a/framework/yii/db/StaleObjectException.php +++ /dev/null @@ -1,23 +0,0 @@ - - * @since 2.0 - */ -class StaleObjectException extends Exception -{ - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return 'Stale Object Exception'; - } -} diff --git a/framework/yii/db/TableSchema.php b/framework/yii/db/TableSchema.php deleted file mode 100644 index 91ce78d..0000000 --- a/framework/yii/db/TableSchema.php +++ /dev/null @@ -1,98 +0,0 @@ - - * @since 2.0 - */ -class TableSchema extends Object -{ - /** - * @var string name of the schema that this table belongs to. - */ - public $schemaName; - /** - * @var string name of this table. - */ - public $name; - /** - * @var string[] primary keys of this table. - */ - public $primaryKey = []; - /** - * @var string sequence name for the primary key. Null if no sequence. - */ - public $sequenceName; - /** - * @var array foreign keys of this table. Each array element is of the following structure: - * - * ~~~ - * [ - * 'ForeignTableName', - * 'fk1' => 'pk1', // pk1 is in foreign table - * 'fk2' => 'pk2', // if composite foreign key - * ] - * ~~~ - */ - public $foreignKeys = []; - /** - * @var ColumnSchema[] column metadata of this table. Each array element is a [[ColumnSchema]] object, indexed by column names. - */ - public $columns = []; - - /** - * Gets the named column metadata. - * This is a convenient method for retrieving a named column even if it does not exist. - * @param string $name column name - * @return ColumnSchema metadata of the named column. Null if the named column does not exist. - */ - public function getColumn($name) - { - return isset($this->columns[$name]) ? $this->columns[$name] : null; - } - - /** - * Returns the names of all columns in this table. - * @return array list of column names - */ - public function getColumnNames() - { - return array_keys($this->columns); - } - - /** - * Manually specifies the primary key for this table. - * @param string|array $keys the primary key (can be composite) - * @throws InvalidParamException if the specified key cannot be found in the table. - */ - public function fixPrimaryKey($keys) - { - if (!is_array($keys)) { - $keys = [$keys]; - } - $this->primaryKey = $keys; - foreach ($this->columns as $column) { - $column->isPrimaryKey = false; - } - foreach ($keys as $key) { - if (isset($this->columns[$key])) { - $this->columns[$key]->isPrimaryKey = true; - } else { - throw new InvalidParamException("Primary key '$key' cannot be found in table '{$this->name}'."); - } - } - } -} diff --git a/framework/yii/db/Transaction.php b/framework/yii/db/Transaction.php deleted file mode 100644 index e0b90d9..0000000 --- a/framework/yii/db/Transaction.php +++ /dev/null @@ -1,106 +0,0 @@ -beginTransaction(); - * try { - * $connection->createCommand($sql1)->execute(); - * $connection->createCommand($sql2)->execute(); - * //.... other SQL executions - * $transaction->commit(); - * } catch(Exception $e) { - * $transaction->rollback(); - * } - * ~~~ - * - * @property boolean $isActive Whether this transaction is active. Only an active transaction can [[commit()]] - * or [[rollback()]]. This property is read-only. - * - * @author Qiang Xue - * @since 2.0 - */ -class Transaction extends \yii\base\Object -{ - /** - * @var Connection the database connection that this transaction is associated with. - */ - public $db; - /** - * @var boolean whether this transaction is active. Only an active transaction - * can [[commit()]] or [[rollback()]]. This property is set true when the transaction is started. - */ - private $_active = false; - - /** - * Returns a value indicating whether this transaction is active. - * @return boolean whether this transaction is active. Only an active transaction - * can [[commit()]] or [[rollback()]]. - */ - public function getIsActive() - { - return $this->_active; - } - - /** - * Begins a transaction. - * @throws InvalidConfigException if [[connection]] is null - */ - public function begin() - { - if (!$this->_active) { - if ($this->db === null) { - throw new InvalidConfigException('Transaction::db must be set.'); - } - \Yii::trace('Starting transaction', __METHOD__); - $this->db->open(); - $this->db->pdo->beginTransaction(); - $this->_active = true; - } - } - - /** - * Commits a transaction. - * @throws Exception if the transaction or the DB connection is not active. - */ - public function commit() - { - if ($this->_active && $this->db && $this->db->isActive) { - \Yii::trace('Committing transaction', __METHOD__); - $this->db->pdo->commit(); - $this->_active = false; - } else { - throw new Exception('Failed to commit transaction: transaction was inactive.'); - } - } - - /** - * Rolls back a transaction. - * @throws Exception if the transaction or the DB connection is not active. - */ - public function rollback() - { - if ($this->_active && $this->db && $this->db->isActive) { - \Yii::trace('Rolling back transaction', __METHOD__); - $this->db->pdo->rollBack(); - $this->_active = false; - } else { - throw new Exception('Failed to roll back transaction: transaction was inactive.'); - } - } -} diff --git a/framework/yii/db/cubrid/QueryBuilder.php b/framework/yii/db/cubrid/QueryBuilder.php deleted file mode 100644 index 9acf91f..0000000 --- a/framework/yii/db/cubrid/QueryBuilder.php +++ /dev/null @@ -1,90 +0,0 @@ - - * @since 2.0 - */ -class QueryBuilder extends \yii\db\QueryBuilder -{ - /** - * @var array mapping from abstract column types (keys) to physical column types (values). - */ - public $typeMap = [ - Schema::TYPE_PK => 'int NOT NULL AUTO_INCREMENT PRIMARY KEY', - Schema::TYPE_BIGPK => 'bigint NOT NULL AUTO_INCREMENT PRIMARY KEY', - Schema::TYPE_STRING => 'varchar(255)', - Schema::TYPE_TEXT => 'varchar', - Schema::TYPE_SMALLINT => 'smallint', - Schema::TYPE_INTEGER => 'int', - Schema::TYPE_BIGINT => 'bigint', - Schema::TYPE_FLOAT => 'float(7)', - Schema::TYPE_DECIMAL => 'decimal(10,0)', - Schema::TYPE_DATETIME => 'datetime', - Schema::TYPE_TIMESTAMP => 'timestamp', - Schema::TYPE_TIME => 'time', - Schema::TYPE_DATE => 'date', - Schema::TYPE_BINARY => 'blob', - Schema::TYPE_BOOLEAN => 'smallint', - Schema::TYPE_MONEY => 'decimal(19,4)', - ]; - - /** - * Creates a SQL statement for resetting the sequence value of a table's primary key. - * The sequence will be reset such that the primary key of the next new row inserted - * will have the specified value or 1. - * @param string $tableName the name of the table whose primary key sequence will be reset - * @param mixed $value the value for the primary key of the next new row inserted. If this is not set, - * the next new row's primary key will have a value 1. - * @return string the SQL statement for resetting sequence - * @throws InvalidParamException if the table does not exist or there is no sequence associated with the table. - */ - public function resetSequence($tableName, $value = null) - { - $table = $this->db->getTableSchema($tableName); - if ($table !== null && $table->sequenceName !== null) { - $tableName = $this->db->quoteTableName($tableName); - if ($value === null) { - $key = reset($table->primaryKey); - $value = (int)$this->db->createCommand("SELECT MAX(`$key`) FROM " . $this->db->schema->quoteTableName($tableName))->queryScalar() + 1; - } else { - $value = (int)$value; - } - return "ALTER TABLE " . $this->db->schema->quoteTableName($tableName) . " AUTO_INCREMENT=$value;"; - } elseif ($table === null) { - throw new InvalidParamException("Table not found: $tableName"); - } else { - throw new InvalidParamException("There is not sequence associated with table '$tableName'."); - } - } - - /** - * @inheritdoc - */ - public function buildLimit($limit, $offset) - { - $sql = ''; - // limit is not optional in CUBRID - // http://www.cubrid.org/manual/90/en/LIMIT%20Clause - // "You can specify a very big integer for row_count to display to the last row, starting from a specific row." - if ($limit !== null && $limit >= 0) { - $sql = 'LIMIT ' . (int)$limit; - if ($offset > 0) { - $sql .= ' OFFSET ' . (int)$offset; - } - } elseif ($offset > 0) { - $sql = 'LIMIT 9223372036854775807 OFFSET ' . (int)$offset; // 2^63-1 - } - return $sql; - } -} diff --git a/framework/yii/db/cubrid/Schema.php b/framework/yii/db/cubrid/Schema.php deleted file mode 100644 index 458f2e3..0000000 --- a/framework/yii/db/cubrid/Schema.php +++ /dev/null @@ -1,265 +0,0 @@ - - * @since 2.0 - */ -class Schema extends \yii\db\Schema -{ - /** - * @var array mapping from physical column types (keys) to abstract column types (values) - * Please refer to [CUBRID manual](http://www.cubrid.org/manual/91/en/sql/datatype.html) for - * details on data types. - */ - public $typeMap = [ - // Numeric data types - 'short' => self::TYPE_SMALLINT, - 'smallint' => self::TYPE_SMALLINT, - 'int' => self::TYPE_INTEGER, - 'integer' => self::TYPE_INTEGER, - 'bigint' => self::TYPE_BIGINT, - 'numeric' => self::TYPE_DECIMAL, - 'decimal' => self::TYPE_DECIMAL, - 'float' => self::TYPE_FLOAT, - 'real' => self::TYPE_FLOAT, - 'double' => self::TYPE_FLOAT, - 'double precision' => self::TYPE_FLOAT, - 'monetary' => self::TYPE_MONEY, - // Date/Time data types - 'date' => self::TYPE_DATE, - 'time' => self::TYPE_TIME, - 'timestamp' => self::TYPE_TIMESTAMP, - 'datetime' => self::TYPE_DATETIME, - // String data types - 'char' => self::TYPE_STRING, - 'varchar' => self::TYPE_STRING, - 'char varying' => self::TYPE_STRING, - 'nchar' => self::TYPE_STRING, - 'nchar varying' => self::TYPE_STRING, - 'string' => self::TYPE_STRING, - // BLOB/CLOB data types - 'blob' => self::TYPE_BINARY, - 'clob' => self::TYPE_BINARY, - // Bit string data types - 'bit' => self::TYPE_STRING, - 'bit varying' => self::TYPE_STRING, - // Collection data types (considered strings for now) - 'set' => self::TYPE_STRING, - 'multiset' => self::TYPE_STRING, - 'list' => self::TYPE_STRING, - 'sequence' => self::TYPE_STRING, - 'enum' => self::TYPE_STRING, - ]; - - /** - * Quotes a table name for use in a query. - * A simple table name has no schema prefix. - * @param string $name table name - * @return string the properly quoted table name - */ - public function quoteSimpleTableName($name) - { - return strpos($name, '"') !== false ? $name : '"' . $name . '"'; - } - - /** - * Quotes a column name for use in a query. - * A simple column name has no prefix. - * @param string $name column name - * @return string the properly quoted column name - */ - public function quoteSimpleColumnName($name) - { - return strpos($name, '"') !== false || $name === '*' ? $name : '"' . $name . '"'; - } - - /** - * Quotes a string value for use in a query. - * Note that if the parameter is not a string, it will be returned without change. - * @param string $str string to be quoted - * @return string the properly quoted string - * @see http://www.php.net/manual/en/function.PDO-quote.php - */ - public function quoteValue($str) - { - if (!is_string($str)) { - return $str; - } - - $this->db->open(); - // workaround for broken PDO::quote() implementation in CUBRID 9.1.0 http://jira.cubrid.org/browse/APIS-658 - $version = $this->db->pdo->getAttribute(\PDO::ATTR_CLIENT_VERSION); - if (version_compare($version, '8.4.4.0002', '<') || $version[0] == '9' && version_compare($version, '9.2.0.0002', '<=')) { - return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") . "'"; - } else { - return $this->db->pdo->quote($str); - } - } - - /** - * Creates a query builder for the CUBRID database. - * @return QueryBuilder query builder instance - */ - public function createQueryBuilder() - { - return new QueryBuilder($this->db); - } - - /** - * Loads the metadata for the specified table. - * @param string $name table name - * @return TableSchema driver dependent table metadata. Null if the table does not exist. - */ - protected function loadTableSchema($name) - { - $this->db->open(); - $tableInfo = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_TABLE, $name); - - if (isset($tableInfo[0]['NAME'])) { - $table = new TableSchema(); - $table->name = $tableInfo[0]['NAME']; - - $sql = 'SHOW FULL COLUMNS FROM ' . $this->quoteSimpleTableName($table->name); - $columns = $this->db->createCommand($sql)->queryAll(); - - foreach ($columns as $info) { - $column = $this->loadColumnSchema($info); - $table->columns[$column->name] = $column; - } - - $primaryKeys = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_PRIMARY_KEY, $table->name); - foreach ($primaryKeys as $key) { - $column = $table->columns[$key['ATTR_NAME']]; - $column->isPrimaryKey = true; - $table->primaryKey[] = $column->name; - if ($column->autoIncrement) { - $table->sequenceName = ''; - } - } - - $foreignKeys = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_IMPORTED_KEYS, $table->name); - foreach ($foreignKeys as $key) { - if (isset($table->foreignKeys[$key['FK_NAME']])) { - $table->foreignKeys[$key['FK_NAME']][$key['FKCOLUMN_NAME']] = $key['PKCOLUMN_NAME']; - } else { - $table->foreignKeys[$key['FK_NAME']] = [ - $key['PKTABLE_NAME'], - $key['FKCOLUMN_NAME'] => $key['PKCOLUMN_NAME'] - ]; - } - } - $table->foreignKeys = array_values($table->foreignKeys); - - return $table; - } else { - return null; - } - } - - /** - * Loads the column information into a [[ColumnSchema]] object. - * @param array $info column information - * @return ColumnSchema the column schema object - */ - protected function loadColumnSchema($info) - { - $column = new ColumnSchema(); - - $column->name = $info['Field']; - $column->allowNull = $info['Null'] === 'YES'; - $column->isPrimaryKey = false; // primary key will be set by loadTableSchema() later - $column->autoIncrement = stripos($info['Extra'], 'auto_increment') !== false; - - $column->dbType = strtolower($info['Type']); - $column->unsigned = strpos($column->dbType, 'unsigned') !== false; - - $column->type = self::TYPE_STRING; - if (preg_match('/^([\w ]+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) { - $type = $matches[1]; - if (isset($this->typeMap[$type])) { - $column->type = $this->typeMap[$type]; - } - if (!empty($matches[2])) { - if ($type === 'enum') { - $values = explode(',', $matches[2]); - foreach ($values as $i => $value) { - $values[$i] = trim($value, "'"); - } - $column->enumValues = $values; - } else { - $values = explode(',', $matches[2]); - $column->size = $column->precision = (int)$values[0]; - if (isset($values[1])) { - $column->scale = (int)$values[1]; - } - } - } - } - - $column->phpType = $this->getColumnPhpType($column); - - if ($column->type === 'timestamp' && $info['Default'] === 'CURRENT_TIMESTAMP' || - $column->type === 'datetime' && $info['Default'] === 'SYS_DATETIME' || - $column->type === 'date' && $info['Default'] === 'SYS_DATE' || - $column->type === 'time' && $info['Default'] === 'SYS_TIME' - ) { - $column->defaultValue = new Expression($info['Default']); - } else { - $column->defaultValue = $column->typecast($info['Default']); - } - - return $column; - } - - /** - * Returns all table names in the database. - * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. - * @return array all table names in the database. The names have NO schema name prefix. - */ - protected function findTableNames($schema = '') - { - $this->db->open(); - $tables = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_TABLE); - $tableNames = []; - foreach ($tables as $table) { - // do not list system tables - if ($table['TYPE'] != 0) { - $tableNames[] = $table['NAME']; - } - } - return $tableNames; - } - - /** - * Determines the PDO type for the given PHP data value. - * @param mixed $data the data whose PDO type is to be determined - * @return integer the PDO type - * @see http://www.php.net/manual/en/pdo.constants.php - */ - public function getPdoType($data) - { - static $typeMap = [ - // php type => PDO type - 'boolean' => \PDO::PARAM_INT, // PARAM_BOOL is not supported by CUBRID PDO - 'integer' => \PDO::PARAM_INT, - 'string' => \PDO::PARAM_STR, - 'resource' => \PDO::PARAM_LOB, - 'NULL' => \PDO::PARAM_NULL, - ]; - $type = gettype($data); - return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR; - } -} diff --git a/framework/yii/db/mssql/PDO.php b/framework/yii/db/mssql/PDO.php deleted file mode 100644 index c29cd4c..0000000 --- a/framework/yii/db/mssql/PDO.php +++ /dev/null @@ -1,61 +0,0 @@ - - * @since 2.0 - */ -class PDO extends \PDO -{ - /** - * Returns value of the last inserted ID. - * @param string|null $sequence the sequence name. Defaults to null. - * @return integer last inserted ID value. - */ - public function lastInsertId($sequence = null) - { - return $this->query('SELECT CAST(COALESCE(SCOPE_IDENTITY(), @@IDENTITY) AS bigint)')->fetchColumn(); - } - - /** - * Starts a transaction. It is necessary to override PDO's method as MSSQL PDO driver does not - * natively support transactions. - * @return boolean the result of a transaction start. - */ - public function beginTransaction() - { - $this->exec('BEGIN TRANSACTION'); - return true; - } - - /** - * Commits a transaction. It is necessary to override PDO's method as MSSQL PDO driver does not - * natively support transactions. - * @return boolean the result of a transaction commit. - */ - public function commit() - { - $this->exec('COMMIT TRANSACTION'); - return true; - } - - /** - * Rollbacks a transaction. It is necessary to override PDO's method as MSSQL PDO driver does not - * natively support transactions. - * @return boolean the result of a transaction rollback. - */ - public function rollBack() - { - $this->exec('ROLLBACK TRANSACTION'); - return true; - } -} diff --git a/framework/yii/db/mssql/QueryBuilder.php b/framework/yii/db/mssql/QueryBuilder.php deleted file mode 100644 index 77b9532..0000000 --- a/framework/yii/db/mssql/QueryBuilder.php +++ /dev/null @@ -1,123 +0,0 @@ - - * @since 2.0 - */ -class QueryBuilder extends \yii\db\QueryBuilder -{ - /** - * @var array mapping from abstract column types (keys) to physical column types (values). - */ - public $typeMap = [ - Schema::TYPE_PK => 'int IDENTITY PRIMARY KEY', - Schema::TYPE_BIGPK => 'bigint IDENTITY PRIMARY KEY', - Schema::TYPE_STRING => 'varchar(255)', - Schema::TYPE_TEXT => 'text', - Schema::TYPE_SMALLINT => 'smallint', - Schema::TYPE_INTEGER => 'int', - Schema::TYPE_BIGINT => 'bigint', - Schema::TYPE_FLOAT => 'float', - Schema::TYPE_DECIMAL => 'decimal', - Schema::TYPE_DATETIME => 'datetime', - Schema::TYPE_TIMESTAMP => 'timestamp', - Schema::TYPE_TIME => 'time', - Schema::TYPE_DATE => 'date', - Schema::TYPE_BINARY => 'binary', - Schema::TYPE_BOOLEAN => 'bit', - Schema::TYPE_MONEY => 'decimal(19,4)', - ]; - -// public function update($table, $columns, $condition, &$params) -// { -// return ''; -// } - -// public function delete($table, $condition, &$params) -// { -// return ''; -// } - -// public function buildLimit($limit, $offset) -// { -// return ''; -// } - -// public function resetSequence($table, $value = null) -// { -// return ''; -// } - - /** - * Builds a SQL statement for renaming a DB table. - * @param string $table the table to be renamed. The name will be properly quoted by the method. - * @param string $newName the new table name. The name will be properly quoted by the method. - * @return string the SQL statement for renaming a DB table. - */ - public function renameTable($table, $newName) - { - return "sp_rename '$table', '$newName'"; - } - - /** - * Builds a SQL statement for renaming a column. - * @param string $table the table whose column is to be renamed. The name will be properly quoted by the method. - * @param string $name the old name of the column. The name will be properly quoted by the method. - * @param string $newName the new name of the column. The name will be properly quoted by the method. - * @return string the SQL statement for renaming a DB column. - */ - public function renameColumn($table, $name, $newName) - { - return "sp_rename '$table.$name', '$newName', 'COLUMN'"; - } - - /** - * Builds a SQL statement for changing the definition of a column. - * @param string $table the table whose column is to be changed. The table name will be properly quoted by the method. - * @param string $column the name of the column to be changed. The name will be properly quoted by the method. - * @param string $type the new column type. The {@link getColumnType} method will be invoked to convert abstract column type (if any) - * into the physical one. Anything that is not recognized as abstract type will be kept in the generated SQL. - * For example, 'string' will be turned into 'varchar(255)', while 'string not null' will become 'varchar(255) not null'. - * @return string the SQL statement for changing the definition of a column. - */ - public function alterColumn($table, $column, $type) - { - $type=$this->getColumnType($type); - $sql='ALTER TABLE ' . $this->db->quoteTableName($table) . ' ALTER COLUMN ' - . $this->db->quoteColumnName($column) . ' ' - . $this->getColumnType($type); - return $sql; - } - - /** - * Builds a SQL statement for enabling or disabling integrity check. - * @param boolean $check whether to turn on or off the integrity check. - * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. - * @param string $table the table name. Defaults to empty string, meaning that no table will be changed. - * @return string the SQL statement for checking integrity - * @throws InvalidParamException if the table does not exist or there is no sequence associated with the table. - */ - public function checkIntegrity($check = true, $schema = '', $table = '') - { - if ($schema !== '') { - $table = "{$schema}.{$table}"; - } - $table = $this->db->quoteTableName($table); - if ($this->db->getTableSchema($table) === null) { - throw new InvalidParamException("Table not found: $table"); - } - $enable = $check ? 'CHECK' : 'NOCHECK'; - return "ALTER TABLE {$table} {$enable} CONSTRAINT ALL"; - } -} diff --git a/framework/yii/db/mssql/Schema.php b/framework/yii/db/mssql/Schema.php deleted file mode 100644 index a6c4ffa..0000000 --- a/framework/yii/db/mssql/Schema.php +++ /dev/null @@ -1,353 +0,0 @@ - - * @since 2.0 - */ -class Schema extends \yii\db\Schema -{ - /** - * Default schema name to be used. - */ - const DEFAULT_SCHEMA = 'dbo'; - - /** - * @var array mapping from physical column types (keys) to abstract column types (values) - */ - public $typeMap = [ - // exact numerics - 'bigint' => self::TYPE_BIGINT, - 'numeric' => self::TYPE_DECIMAL, - 'bit' => self::TYPE_SMALLINT, - 'smallint' => self::TYPE_SMALLINT, - 'decimal' => self::TYPE_DECIMAL, - 'smallmoney' => self::TYPE_MONEY, - 'int' => self::TYPE_INTEGER, - 'tinyint' => self::TYPE_SMALLINT, - 'money' => self::TYPE_MONEY, - - // approximate numerics - 'float' => self::TYPE_FLOAT, - 'real' => self::TYPE_FLOAT, - - // date and time - 'date' => self::TYPE_DATE, - 'datetimeoffset' => self::TYPE_DATETIME, - 'datetime2' => self::TYPE_DATETIME, - 'smalldatetime' => self::TYPE_DATETIME, - 'datetime' => self::TYPE_DATETIME, - 'time' => self::TYPE_TIME, - - // character strings - 'char' => self::TYPE_STRING, - 'varchar' => self::TYPE_STRING, - 'text' => self::TYPE_TEXT, - - // unicode character strings - 'nchar' => self::TYPE_STRING, - 'nvarchar' => self::TYPE_STRING, - 'ntext' => self::TYPE_TEXT, - - // binary strings - 'binary' => self::TYPE_BINARY, - 'varbinary' => self::TYPE_BINARY, - 'image' => self::TYPE_BINARY, - - // other data types - // 'cursor' type cannot be used with tables - 'timestamp' => self::TYPE_TIMESTAMP, - 'hierarchyid' => self::TYPE_STRING, - 'uniqueidentifier' => self::TYPE_STRING, - 'sql_variant' => self::TYPE_STRING, - 'xml' => self::TYPE_STRING, - 'table' => self::TYPE_STRING, - ]; - - /** - * Quotes a table name for use in a query. - * A simple table name has no schema prefix. - * @param string $name table name. - * @return string the properly quoted table name. - */ - public function quoteSimpleTableName($name) - { - return strpos($name, '[') === false ? "[{$name}]" : $name; - } - - /** - * Quotes a column name for use in a query. - * A simple column name has no prefix. - * @param string $name column name. - * @return string the properly quoted column name. - */ - public function quoteSimpleColumnName($name) - { - return strpos($name, '[') === false && $name !== '*' ? "[{$name}]" : $name; - } - - /** - * Creates a query builder for the MSSQL database. - * @return QueryBuilder query builder interface. - */ - public function createQueryBuilder() - { - return new QueryBuilder($this->db); - } - - /** - * Loads the metadata for the specified table. - * @param string $name table name - * @return TableSchema|null driver dependent table metadata. Null if the table does not exist. - */ - public function loadTableSchema($name) - { - $table = new TableSchema(); - $this->resolveTableNames($table, $name); - $this->findPrimaryKeys($table); - if ($this->findColumns($table)) { - $this->findForeignKeys($table); - return $table; - } else { - return null; - } - } - - /** - * Resolves the table name and schema name (if any). - * @param TableSchema $table the table metadata object - * @param string $name the table name - */ - protected function resolveTableNames($table, $name) - { - $parts = explode('.', str_replace(['[', ']'], '', $name)); - $partCount = count($parts); - if ($partCount == 3) { - // catalog name, schema name and table name passed - $table->catalogName = $parts[0]; - $table->schemaName = $parts[1]; - $table->name = $parts[2]; - } elseif ($partCount == 2) { - // only schema name and table name passed - $table->schemaName = $parts[0]; - $table->name = $parts[1]; - } else { - // only schema name passed - $table->schemaName = static::DEFAULT_SCHEMA; - $table->name = $parts[0]; - } - } - - /** - * Loads the column information into a [[ColumnSchema]] object. - * @param array $info column information - * @return ColumnSchema the column schema object - */ - protected function loadColumnSchema($info) - { - $column = new ColumnSchema(); - - $column->name = $info['column_name']; - $column->allowNull = $info['is_nullable'] == 'YES'; - $column->dbType = $info['data_type']; - $column->enumValues = []; // mssql has only vague equivalents to enum - $column->isPrimaryKey = null; // primary key will be determined in findColumns() method - $column->autoIncrement = $info['is_identity'] == 1; - $column->unsigned = stripos($column->dbType, 'unsigned') !== false; - $column->comment = $info['comment'] === null ? '' : $info['comment']; - - $column->type = self::TYPE_STRING; - if (preg_match('/^(\w+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) { - $type = $matches[1]; - if (isset($this->typeMap[$type])) { - $column->type = $this->typeMap[$type]; - } - if (!empty($matches[2])) { - $values = explode(',', $matches[2]); - $column->size = $column->precision = (int)$values[0]; - if (isset($values[1])) { - $column->scale = (int)$values[1]; - } - if ($column->size === 1 && ($type === 'tinyint' || $type === 'bit')) { - $column->type = 'boolean'; - } elseif ($type === 'bit') { - if ($column->size > 32) { - $column->type = 'bigint'; - } elseif ($column->size === 32) { - $column->type = 'integer'; - } - } - } - } - - $column->phpType = $this->getColumnPhpType($column); - - if ($info['column_default'] == '(NULL)') { - $info['column_default'] = null; - } - if ($column->type !== 'timestamp' || $info['column_default'] !== 'CURRENT_TIMESTAMP') { - $column->defaultValue = $column->typecast($info['column_default']); - } - - return $column; - } - - /** - * Collects the metadata of table columns. - * @param TableSchema $table the table metadata - * @return boolean whether the table exists in the database - */ - protected function findColumns($table) - { - $columnsTableName = 'information_schema.columns'; - $whereSql = "[t1].[table_name] = '{$table->name}'"; - if ($table->catalogName !== null) { - $columnsTableName = "{$table->catalogName}.{$columnsTableName}"; - $whereSql .= " AND [t1].[table_catalog] = '{$table->catalogName}'"; - } - if ($table->schemaName !== null) { - $whereSql .= " AND [t1].[table_schema] = '{$table->schemaName}'"; - } - $columnsTableName = $this->quoteTableName($columnsTableName); - - $sql = <<db->createCommand($sql)->queryAll(); - } catch (\Exception $e) { - return false; - } - foreach ($columns as $column) { - $column = $this->loadColumnSchema($column); - foreach ($table->primaryKey as $primaryKey) { - if (strcasecmp($column->name, $primaryKey) === 0) { - $column->isPrimaryKey = true; - break; - } - } - if ($column->isPrimaryKey && $column->autoIncrement) { - $table->sequenceName = ''; - } - $table->columns[$column->name] = $column; - } - return true; - } - - /** - * Collects the primary key column details for the given table. - * @param TableSchema $table the table metadata - */ - protected function findPrimaryKeys($table) - { - $keyColumnUsageTableName = 'information_schema.key_column_usage'; - $tableConstraintsTableName = 'information_schema.table_constraints'; - if ($table->catalogName !== null) { - $keyColumnUsageTableName = $table->catalogName . '.' . $keyColumnUsageTableName; - $tableConstraintsTableName = $table->catalogName . '.' . $tableConstraintsTableName; - } - $keyColumnUsageTableName = $this->quoteTableName($keyColumnUsageTableName); - $tableConstraintsTableName = $this->quoteTableName($tableConstraintsTableName); - - $sql = <<primaryKey = $this->db - ->createCommand($sql, [':tableName' => $table->name, ':schemaName' => $table->schemaName]) - ->queryColumn(); - } - - /** - * Collects the foreign key column details for the given table. - * @param TableSchema $table the table metadata - */ - protected function findForeignKeys($table) - { - $referentialConstraintsTableName = 'information_schema.referential_constraints'; - $keyColumnUsageTableName = 'information_schema.key_column_usage'; - if ($table->catalogName !== null) { - $referentialConstraintsTableName = $table->catalogName . '.' . $referentialConstraintsTableName; - $keyColumnUsageTableName = $table->catalogName . '.' . $keyColumnUsageTableName; - } - $referentialConstraintsTableName = $this->quoteTableName($referentialConstraintsTableName); - $keyColumnUsageTableName = $this->quoteTableName($keyColumnUsageTableName); - - // please refer to the following page for more details: - // http://msdn2.microsoft.com/en-us/library/aa175805(SQL.80).aspx - $sql = <<db->createCommand($sql, [':tableName' => $table->name])->queryAll(); - $table->foreignKeys = []; - foreach ($rows as $row) { - $table->foreignKeys[] = [$row['uq_table_name'], $row['fk_column_name'] => $row['uq_column_name']]; - } - } - - /** - * Returns all table names in the database. - * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. - * @return array all table names in the database. The names have NO schema name prefix. - */ - protected function findTableNames($schema = '') - { - if ($schema === '') { - $schema = static::DEFAULT_SCHEMA; - } - - $sql = <<db->createCommand($sql, [':schema' => $schema])->queryColumn(); - } -} diff --git a/framework/yii/db/mssql/SqlsrvPDO.php b/framework/yii/db/mssql/SqlsrvPDO.php deleted file mode 100644 index 29444c5..0000000 --- a/framework/yii/db/mssql/SqlsrvPDO.php +++ /dev/null @@ -1,33 +0,0 @@ - - * @since 2.0 - */ -class SqlsrvPDO extends \PDO -{ - /** - * Returns value of the last inserted ID. - * - * SQLSRV driver implements [[PDO::lastInsertId()]] method but with a single peculiarity: - * when `$sequence` value is a null or an empty string it returns an empty string. - * But when parameter is not specified it works as expected and returns actual - * last inserted ID (like the other PDO drivers). - * @param string|null $sequence the sequence name. Defaults to null. - * @return integer last inserted ID value. - */ - public function lastInsertId($sequence = null) - { - return !$sequence ? parent::lastInsertId() : parent::lastInsertId($sequence); - } -} diff --git a/framework/yii/db/mssql/TableSchema.php b/framework/yii/db/mssql/TableSchema.php deleted file mode 100644 index 67ad85c..0000000 --- a/framework/yii/db/mssql/TableSchema.php +++ /dev/null @@ -1,23 +0,0 @@ - - * @since 2.0 - */ -class TableSchema extends \yii\db\TableSchema -{ - /** - * @var string name of the catalog (database) that this table belongs to. - * Defaults to null, meaning no catalog (or the current database). - */ - public $catalogName; -} diff --git a/framework/yii/db/mysql/QueryBuilder.php b/framework/yii/db/mysql/QueryBuilder.php deleted file mode 100644 index e9481a4..0000000 --- a/framework/yii/db/mysql/QueryBuilder.php +++ /dev/null @@ -1,163 +0,0 @@ - - * @since 2.0 - */ -class QueryBuilder extends \yii\db\QueryBuilder -{ - /** - * @var array mapping from abstract column types (keys) to physical column types (values). - */ - public $typeMap = [ - Schema::TYPE_PK => 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY', - Schema::TYPE_BIGPK => 'bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY', - Schema::TYPE_STRING => 'varchar(255)', - Schema::TYPE_TEXT => 'text', - Schema::TYPE_SMALLINT => 'smallint(6)', - Schema::TYPE_INTEGER => 'int(11)', - Schema::TYPE_BIGINT => 'bigint(20)', - Schema::TYPE_FLOAT => 'float', - Schema::TYPE_DECIMAL => 'decimal(10,0)', - Schema::TYPE_DATETIME => 'datetime', - Schema::TYPE_TIMESTAMP => 'timestamp', - Schema::TYPE_TIME => 'time', - Schema::TYPE_DATE => 'date', - Schema::TYPE_BINARY => 'blob', - Schema::TYPE_BOOLEAN => 'tinyint(1)', - Schema::TYPE_MONEY => 'decimal(19,4)', - ]; - - /** - * Builds a SQL statement for renaming a column. - * @param string $table the table whose column is to be renamed. The name will be properly quoted by the method. - * @param string $oldName the old name of the column. The name will be properly quoted by the method. - * @param string $newName the new name of the column. The name will be properly quoted by the method. - * @return string the SQL statement for renaming a DB column. - * @throws Exception - */ - public function renameColumn($table, $oldName, $newName) - { - $quotedTable = $this->db->quoteTableName($table); - $row = $this->db->createCommand('SHOW CREATE TABLE ' . $quotedTable)->queryOne(); - if ($row === false) { - throw new Exception("Unable to find column '$oldName' in table '$table'."); - } - if (isset($row['Create Table'])) { - $sql = $row['Create Table']; - } else { - $row = array_values($row); - $sql = $row[1]; - } - if (preg_match_all('/^\s*`(.*?)`\s+(.*?),?$/m', $sql, $matches)) { - foreach ($matches[1] as $i => $c) { - if ($c === $oldName) { - return "ALTER TABLE $quotedTable CHANGE " - . $this->db->quoteColumnName($oldName) . ' ' - . $this->db->quoteColumnName($newName) . ' ' - . $matches[2][$i]; - } - } - } - // try to give back a SQL anyway - return "ALTER TABLE $quotedTable CHANGE " - . $this->db->quoteColumnName($oldName) . ' ' - . $this->db->quoteColumnName($newName); - } - - /** - * Builds a SQL statement for dropping a foreign key constraint. - * @param string $name the name of the foreign key constraint to be dropped. The name will be properly quoted by the method. - * @param string $table the table whose foreign is to be dropped. The name will be properly quoted by the method. - * @return string the SQL statement for dropping a foreign key constraint. - */ - public function dropForeignKey($name, $table) - { - return 'ALTER TABLE ' . $this->db->quoteTableName($table) - . ' DROP FOREIGN KEY ' . $this->db->quoteColumnName($name); - } - - /** - * Builds a SQL statement for removing a primary key constraint to an existing table. - * @param string $name the name of the primary key constraint to be removed. - * @param string $table the table that the primary key constraint will be removed from. - * @return string the SQL statement for removing a primary key constraint from an existing table. - */ - public function dropPrimaryKey($name, $table) - { - return 'ALTER TABLE ' . $this->db->quoteTableName($table) . ' DROP PRIMARY KEY'; - } - - /** - * Creates a SQL statement for resetting the sequence value of a table's primary key. - * The sequence will be reset such that the primary key of the next new row inserted - * will have the specified value or 1. - * @param string $tableName the name of the table whose primary key sequence will be reset - * @param mixed $value the value for the primary key of the next new row inserted. If this is not set, - * the next new row's primary key will have a value 1. - * @return string the SQL statement for resetting sequence - * @throws InvalidParamException if the table does not exist or there is no sequence associated with the table. - */ - public function resetSequence($tableName, $value = null) - { - $table = $this->db->getTableSchema($tableName); - if ($table !== null && $table->sequenceName !== null) { - $tableName = $this->db->quoteTableName($tableName); - if ($value === null) { - $key = reset($table->primaryKey); - $value = $this->db->createCommand("SELECT MAX(`$key`) FROM $tableName")->queryScalar() + 1; - } else { - $value = (int)$value; - } - return "ALTER TABLE $tableName AUTO_INCREMENT=$value"; - } elseif ($table === null) { - throw new InvalidParamException("Table not found: $tableName"); - } else { - throw new InvalidParamException("There is not sequence associated with table '$tableName'."); - } - } - - /** - * Builds a SQL statement for enabling or disabling integrity check. - * @param boolean $check whether to turn on or off the integrity check. - * @param string $table the table name. Meaningless for MySQL. - * @param string $schema the schema of the tables. Meaningless for MySQL. - * @return string the SQL statement for checking integrity - */ - public function checkIntegrity($check = true, $schema = '', $table = '') - { - return 'SET FOREIGN_KEY_CHECKS = ' . ($check ? 1 : 0); - } - - /** - * @inheritdoc - */ - public function buildLimit($limit, $offset) - { - $sql = ''; - // limit is not optional in MySQL - // http://stackoverflow.com/a/271650/1106908 - // http://dev.mysql.com/doc/refman/5.0/en/select.html#idm47619502796240 - if ($limit !== null && $limit >= 0) { - $sql = 'LIMIT ' . (int)$limit; - if ($offset > 0) { - $sql .= ' OFFSET ' . (int)$offset; - } - } elseif ($offset > 0) { - $sql = 'LIMIT ' . (int)$offset . ', 18446744073709551615'; // 2^64-1 - } - return $sql; - } -} diff --git a/framework/yii/db/mysql/Schema.php b/framework/yii/db/mysql/Schema.php deleted file mode 100644 index a649d8a..0000000 --- a/framework/yii/db/mysql/Schema.php +++ /dev/null @@ -1,291 +0,0 @@ - - * @since 2.0 - */ -class Schema extends \yii\db\Schema -{ - /** - * @var array mapping from physical column types (keys) to abstract column types (values) - */ - public $typeMap = [ - 'tinyint' => self::TYPE_SMALLINT, - 'bit' => self::TYPE_SMALLINT, - 'smallint' => self::TYPE_SMALLINT, - 'mediumint' => self::TYPE_INTEGER, - 'int' => self::TYPE_INTEGER, - 'integer' => self::TYPE_INTEGER, - 'bigint' => self::TYPE_BIGINT, - 'float' => self::TYPE_FLOAT, - 'double' => self::TYPE_FLOAT, - 'real' => self::TYPE_FLOAT, - 'decimal' => self::TYPE_DECIMAL, - 'numeric' => self::TYPE_DECIMAL, - 'tinytext' => self::TYPE_TEXT, - 'mediumtext' => self::TYPE_TEXT, - 'longtext' => self::TYPE_TEXT, - 'text' => self::TYPE_TEXT, - 'varchar' => self::TYPE_STRING, - 'string' => self::TYPE_STRING, - 'char' => self::TYPE_STRING, - 'datetime' => self::TYPE_DATETIME, - 'year' => self::TYPE_DATE, - 'date' => self::TYPE_DATE, - 'time' => self::TYPE_TIME, - 'timestamp' => self::TYPE_TIMESTAMP, - 'enum' => self::TYPE_STRING, - ]; - - /** - * Quotes a table name for use in a query. - * A simple table name has no schema prefix. - * @param string $name table name - * @return string the properly quoted table name - */ - public function quoteSimpleTableName($name) - { - return strpos($name, "`") !== false ? $name : "`" . $name . "`"; - } - - /** - * Quotes a column name for use in a query. - * A simple column name has no prefix. - * @param string $name column name - * @return string the properly quoted column name - */ - public function quoteSimpleColumnName($name) - { - return strpos($name, '`') !== false || $name === '*' ? $name : '`' . $name . '`'; - } - - /** - * Creates a query builder for the MySQL database. - * @return QueryBuilder query builder instance - */ - public function createQueryBuilder() - { - return new QueryBuilder($this->db); - } - - /** - * Loads the metadata for the specified table. - * @param string $name table name - * @return TableSchema driver dependent table metadata. Null if the table does not exist. - */ - protected function loadTableSchema($name) - { - $table = new TableSchema; - $this->resolveTableNames($table, $name); - - if ($this->findColumns($table)) { - $this->findConstraints($table); - return $table; - } else { - return null; - } - } - - /** - * Resolves the table name and schema name (if any). - * @param TableSchema $table the table metadata object - * @param string $name the table name - */ - protected function resolveTableNames($table, $name) - { - $parts = explode('.', str_replace('`', '', $name)); - if (isset($parts[1])) { - $table->schemaName = $parts[0]; - $table->name = $parts[1]; - } else { - $table->name = $parts[0]; - } - } - - /** - * Loads the column information into a [[ColumnSchema]] object. - * @param array $info column information - * @return ColumnSchema the column schema object - */ - protected function loadColumnSchema($info) - { - $column = new ColumnSchema; - - $column->name = $info['Field']; - $column->allowNull = $info['Null'] === 'YES'; - $column->isPrimaryKey = strpos($info['Key'], 'PRI') !== false; - $column->autoIncrement = stripos($info['Extra'], 'auto_increment') !== false; - $column->comment = $info['Comment']; - - - $column->dbType = $info['Type']; - $column->unsigned = strpos($column->dbType, 'unsigned') !== false; - - $column->type = self::TYPE_STRING; - if (preg_match('/^(\w+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) { - $type = $matches[1]; - if (isset($this->typeMap[$type])) { - $column->type = $this->typeMap[$type]; - } - if (!empty($matches[2])) { - if ($type === 'enum') { - $values = explode(',', $matches[2]); - foreach ($values as $i => $value) { - $values[$i] = trim($value, "'"); - } - $column->enumValues = $values; - } else { - $values = explode(',', $matches[2]); - $column->size = $column->precision = (int)$values[0]; - if (isset($values[1])) { - $column->scale = (int)$values[1]; - } - if ($column->size === 1 && ($type === 'tinyint' || $type === 'bit')) { - $column->type = 'boolean'; - } elseif ($type === 'bit') { - if ($column->size > 32) { - $column->type = 'bigint'; - } elseif ($column->size === 32) { - $column->type = 'integer'; - } - } - } - } - } - - $column->phpType = $this->getColumnPhpType($column); - - if ($column->type !== 'timestamp' || $info['Default'] !== 'CURRENT_TIMESTAMP') { - $column->defaultValue = $column->typecast($info['Default']); - } - - return $column; - } - - /** - * Collects the metadata of table columns. - * @param TableSchema $table the table metadata - * @return boolean whether the table exists in the database - * @throws \Exception if DB query fails - */ - protected function findColumns($table) - { - $sql = 'SHOW FULL COLUMNS FROM ' . $this->quoteSimpleTableName($table->name); - try { - $columns = $this->db->createCommand($sql)->queryAll(); - } catch (\Exception $e) { - $previous = $e->getPrevious(); - if ($previous instanceof \PDOException && $previous->getCode() == '42S02') { - // table does not exist - return false; - } - throw $e; - } - foreach ($columns as $info) { - $column = $this->loadColumnSchema($info); - $table->columns[$column->name] = $column; - if ($column->isPrimaryKey) { - $table->primaryKey[] = $column->name; - if ($column->autoIncrement) { - $table->sequenceName = ''; - } - } - } - return true; - } - - /** - * Gets the CREATE TABLE sql string. - * @param TableSchema $table the table metadata - * @return string $sql the result of 'SHOW CREATE TABLE' - */ - protected function getCreateTableSql($table) - { - $row = $this->db->createCommand('SHOW CREATE TABLE ' . $this->quoteSimpleTableName($table->name))->queryOne(); - if (isset($row['Create Table'])) { - $sql = $row['Create Table']; - } else { - $row = array_values($row); - $sql = $row[1]; - } - return $sql; - } - - /** - * Collects the foreign key column details for the given table. - * @param TableSchema $table the table metadata - */ - protected function findConstraints($table) - { - $sql = $this->getCreateTableSql($table); - - $regexp = '/FOREIGN KEY\s+\(([^\)]+)\)\s+REFERENCES\s+([^\(^\s]+)\s*\(([^\)]+)\)/mi'; - if (preg_match_all($regexp, $sql, $matches, PREG_SET_ORDER)) { - foreach ($matches as $match) { - $fks = array_map('trim', explode(',', str_replace('`', '', $match[1]))); - $pks = array_map('trim', explode(',', str_replace('`', '', $match[3]))); - $constraint = [str_replace('`', '', $match[2])]; - foreach ($fks as $k => $name) { - $constraint[$name] = $pks[$k]; - } - $table->foreignKeys[] = $constraint; - } - } - } - - /** - * Returns all unique indexes for the given table. - * Each array element is of the following structure: - * - * ~~~ - * [ - * 'IndexName1' => ['col1' [, ...]], - * 'IndexName2' => ['col2' [, ...]], - * ] - * ~~~ - * - * @param TableSchema $table the table metadata - * @return array all unique indexes for the given table. - */ - public function findUniqueIndexes($table) - { - $sql = $this->getCreateTableSql($table); - $uniqueIndexes = []; - - $regexp = '/UNIQUE KEY\s+([^\(^\s]+)\s*\(([^\)]+)\)/mi'; - if (preg_match_all($regexp, $sql, $matches, PREG_SET_ORDER)) { - foreach ($matches as $match) { - $indexName = str_replace('`', '', $match[1]); - $indexColumns = array_map('trim', explode(',', str_replace('`', '', $match[2]))); - $uniqueIndexes[$indexName] = $indexColumns; - } - } - return $uniqueIndexes; - } - - /** - * Returns all table names in the database. - * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. - * @return array all table names in the database. The names have NO schema name prefix. - */ - protected function findTableNames($schema = '') - { - $sql = 'SHOW TABLES'; - if ($schema !== '') { - $sql .= ' FROM ' . $this->quoteSimpleTableName($schema); - } - return $this->db->createCommand($sql)->queryColumn(); - } -} diff --git a/framework/yii/db/oci/QueryBuilder.php b/framework/yii/db/oci/QueryBuilder.php deleted file mode 100644 index cf8234f..0000000 --- a/framework/yii/db/oci/QueryBuilder.php +++ /dev/null @@ -1,137 +0,0 @@ -params; - $clauses = [ - $this->buildSelect($query->select, $query->distinct, $query->selectOption), - $this->buildFrom($query->from), - $this->buildJoin($query->join, $params), - $this->buildWhere($query->where, $params), - $this->buildGroupBy($query->groupBy), - $this->buildHaving($query->having, $params), - $this->buildUnion($query->union, $params), - $this->buildOrderBy($query->orderBy), - ]; - $this->sql = implode($this->separator, array_filter($clauses)); - - if ($query->limit !== null || $query->offset !== null) { - $this->sql = $this->buildLimit($query->limit, $query->offset); - } - return [$this->sql, $params]; - } - - public function buildLimit($limit, $offset) - { - if (($limit < 0) && ($offset < 0)) { - return $this->sql; - } - $filters = []; - if ($offset > 0) { - $filters[] = 'rowNumId > ' . (int)$offset; - } - - if ($limit >= 0) { - $filters[] = 'rownum <= ' . (int)$limit; - } - - if (count($filters) > 0) { - $filter = implode(' and ', $filters); - $filter = " WHERE " . $filter; - } else { - $filter = ''; - } - - $sql = <<sql}), - PAGINATION AS (SELECT USER_SQL.*, rownum as rowNumId FROM USER_SQL) -SELECT * -FROM PAGINATION -{$filter} -EOD; - return $sql; - } - - - /** - * Builds a SQL statement for renaming a DB table. - * - * @param string $table the table to be renamed. The name will be properly quoted by the method. - * @param string $newName the new table name. The name will be properly quoted by the method. - * @return string the SQL statement for renaming a DB table. - */ - public function renameTable($table, $newName) - { - return 'ALTER TABLE ' . $this->db->quoteTableName($table) . ' RENAME TO ' . $this->db->quoteTableName($newName); - } - - /** - * Builds a SQL statement for changing the definition of a column. - * - * @param string $table the table whose column is to be changed. The table name will be properly quoted by the method. - * @param string $column the name of the column to be changed. The name will be properly quoted by the method. - * @param string $type the new column type. The {@link getColumnType} method will be invoked to convert abstract column type (if any) - * into the physical one. Anything that is not recognized as abstract type will be kept in the generated SQL. - * For example, 'string' will be turned into 'varchar(255)', while 'string not null' will become 'varchar(255) not null'. - * @return string the SQL statement for changing the definition of a column. - */ - public function alterColumn($table, $column, $type) - { - $type = $this->getColumnType($type); - return 'ALTER TABLE ' . $this->db->quoteTableName($table) . ' MODIFY ' . $this->db->quoteColumnName($column) . ' ' . $this->getColumnType($type); - } - - /** - * Builds a SQL statement for dropping an index. - * - * @param string $name the name of the index to be dropped. The name will be properly quoted by the method. - * @param string $table the table whose index is to be dropped. The name will be properly quoted by the method. - * @return string the SQL statement for dropping an index. - */ - public function dropIndex($name, $table) - { - return 'DROP INDEX ' . $this->db->quoteTableName($name); - } - - /** - * @inheritdoc - */ - public function resetSequence($table, $value = null) - { - $tableSchema = $this->db->getTableSchema($table); - if ($tableSchema === null) { - throw new InvalidParamException("Unknown table: $table"); - } - if ($tableSchema->sequenceName === null) { - return ''; - } - - if ($value !== null) { - $value = (int)$value; - } else { - $value = (int)$this->db->createCommand("SELECT MAX(\"{$tableSchema->primaryKey}\") FROM \"{$tableSchema->name}\"")->queryScalar(); - $value++; - } - return "DROP SEQUENCE \"{$tableSchema->name}_SEQ\";" - . "CREATE SEQUENCE \"{$tableSchema->name}_SEQ\" START WITH {$value} INCREMENT BY 1 NOMAXVALUE NOCACHE"; - } -} diff --git a/framework/yii/db/oci/Schema.php b/framework/yii/db/oci/Schema.php deleted file mode 100644 index 9ee9854..0000000 --- a/framework/yii/db/oci/Schema.php +++ /dev/null @@ -1,275 +0,0 @@ - - * @since 2.0 - */ -class Schema extends \yii\db\Schema -{ - private $_defaultSchema; - - /** - * @inheritdoc - */ - public function quoteSimpleTableName($name) - { - return '"' . $name . '"'; - } - - /** - * @inheritdoc - */ - public function quoteSimpleColumnName($name) - { - return '"' . $name . '"'; - } - - /** - * @inheritdoc - */ - public function createQueryBuilder() - { - return new QueryBuilder($this->db); - } - - /** - * @inheritdoc - */ - public function loadTableSchema($name) - { - $table = new TableSchema(); - $this->resolveTableNames($table, $name); - - if ($this->findColumns($table)) { - $this->findConstraints($table); - return $table; - } else { - return null; - } - } - - /** - * Resolves the table name and schema name (if any). - * - * @param TableSchema $table the table metadata object - * @param string $name the table name - */ - protected function resolveTableNames($table, $name) - { - $parts = explode('.', str_replace('"', '', $name)); - if (isset($parts[1])) { - $table->schemaName = $parts[0]; - $table->name = $parts[1]; - } else { - $table->schemaName = $this->getDefaultSchema(); - $table->name = $parts[0]; - } - } - - /** - * @return string default schema. - */ - public function getDefaultSchema() - { - if ($this->_defaultSchema === null) { - $this->setDefaultSchema(strtoupper($this->db->username)); - } - return $this->_defaultSchema; - } - - /** - * @param string $schema default schema. - */ - public function setDefaultSchema($schema) - { - $this->_defaultSchema = $schema; - } - - /** - * Collects the table column metadata. - * @param TableSchema $table the table schema - * @return boolean whether the table exists - */ - protected function findColumns($table) - { - $schemaName = $table->schemaName; - $tableName = $table->name; - - $sql = << 0 then ',' || a.data_scale else '' end - || ')' - when data_type = 'DATE' then '' - when data_type = 'NUMBER' then '' - else '(' || to_char(a.data_length) || ')' - end as data_type, - a.nullable, a.data_default, - ( SELECT D.constraint_type - FROM ALL_CONS_COLUMNS C - inner join ALL_constraints D on D.OWNER = C.OWNER and D.constraint_name = C.constraint_name - WHERE C.OWNER = B.OWNER - and C.table_name = B.object_name - and C.column_name = A.column_name - and D.constraint_type = 'P') as Key, - com.comments as column_comment -FROM ALL_TAB_COLUMNS A -inner join ALL_OBJECTS B ON b.owner = a.owner and ltrim(B.OBJECT_NAME) = ltrim(A.TABLE_NAME) -LEFT JOIN user_col_comments com ON (A.table_name = com.table_name AND A.column_name = com.column_name) -WHERE - a.owner = '{$schemaName}' - and (b.object_type = 'TABLE' or b.object_type = 'VIEW') - and b.object_name = '{$tableName}' -ORDER by a.column_id -EOD; - - try { - $columns = $this->db->createCommand($sql)->queryAll(); - } catch (\Exception $e) { - return false; - } - - foreach ($columns as $column) { - $c = $this->createColumn($column); - $table->columns[$c->name] = $c; - if ($c->isPrimaryKey) { - $table->primaryKey[] = $c->name; - $table->sequenceName = ''; - $c->autoIncrement = true; - } - } - return true; - } - - protected function createColumn($column) - { - $c = new ColumnSchema(); - $c->name = $column['COLUMN_NAME']; - $c->allowNull = $column['NULLABLE'] === 'Y'; - $c->isPrimaryKey = strpos($column['KEY'], 'P') !== false; - $c->comment = $column['COLUMN_COMMENT'] === null ? '' : $column['COLUMN_COMMENT']; - - $this->extractColumnType($c, $column['DATA_TYPE']); - $this->extractColumnSize($c, $column['DATA_TYPE']); - - if (stripos($column['DATA_DEFAULT'], 'timestamp') !== false) { - $c->defaultValue = null; - } else { - $c->defaultValue = $c->typecast($column['DATA_DEFAULT']); - } - - return $c; - } - - protected function findConstraints($table) - { - $sql = << 'P' - order by d.constraint_name, c.position -EOD; - $command = $this->db->createCommand($sql); - foreach ($command->queryAll() as $row) { - if ($row['CONSTRAINT_TYPE'] === 'R') { - $name = $row["COLUMN_NAME"]; - $table->foreignKeys[$name] = [$row["TABLE_REF"], $row["COLUMN_REF"]]; - } - } - } - - /** - * @inheritdoc - */ - protected function findTableNames($schema = '') - { - if ($schema === '') { - $sql = <<db->createCommand($sql); - } else { - $sql = <<db->createCommand($sql); - $command->bindParam(':schema', $schema); - } - - $rows = $command->queryAll(); - $names = []; - foreach ($rows as $row) { - $names[] = $row['TABLE_NAME']; - } - return $names; - } - - /** - * Extracts the data types for the given column - * @param ColumnSchema $column - * @param string $dbType DB type - */ - protected function extractColumnType($column, $dbType) - { - $column->dbType = $dbType; - - if (strpos($dbType, 'FLOAT') !== false) { - $column->type = 'double'; - } elseif (strpos($dbType, 'NUMBER') !== false || strpos($dbType, 'INTEGER') !== false) { - if (strpos($dbType, '(') && preg_match('/\((.*)\)/', $dbType, $matches)) { - $values = explode(',', $matches[1]); - if (isset($values[1]) and (((int)$values[1]) > 0)) { - $column->type = 'double'; - } else { - $column->type = 'integer'; - } - } else { - $column->type = 'double'; - } - } else { - $column->type = 'string'; - } - } - - /** - * Extracts size, precision and scale information from column's DB type. - * @param ColumnSchema $column - * @param string $dbType the column's DB type - */ - protected function extractColumnSize($column, $dbType) - { - if (strpos($dbType, '(') && preg_match('/\((.*)\)/', $dbType, $matches)) { - $values = explode(',', $matches[1]); - $column->size = $column->precision = (int)$values[0]; - if (isset($values[1])) { - $column->scale = (int)$values[1]; - } - } - } -} diff --git a/framework/yii/db/pgsql/QueryBuilder.php b/framework/yii/db/pgsql/QueryBuilder.php deleted file mode 100644 index 998e746..0000000 --- a/framework/yii/db/pgsql/QueryBuilder.php +++ /dev/null @@ -1,141 +0,0 @@ - - * @since 2.0 - */ -class QueryBuilder extends \yii\db\QueryBuilder -{ - - /** - * @var array mapping from abstract column types (keys) to physical column types (values). - */ - public $typeMap = [ - Schema::TYPE_PK => 'serial NOT NULL PRIMARY KEY', - Schema::TYPE_BIGPK => 'bigserial NOT NULL PRIMARY KEY', - Schema::TYPE_STRING => 'varchar(255)', - Schema::TYPE_TEXT => 'text', - Schema::TYPE_SMALLINT => 'smallint', - Schema::TYPE_INTEGER => 'integer', - Schema::TYPE_BIGINT => 'bigint', - Schema::TYPE_FLOAT => 'double precision', - Schema::TYPE_DECIMAL => 'numeric(10,0)', - Schema::TYPE_DATETIME => 'timestamp', - Schema::TYPE_TIMESTAMP => 'timestamp', - Schema::TYPE_TIME => 'time', - Schema::TYPE_DATE => 'date', - Schema::TYPE_BINARY => 'bytea', - Schema::TYPE_BOOLEAN => 'boolean', - Schema::TYPE_MONEY => 'numeric(19,4)', - ]; - - /** - * Builds a SQL statement for dropping an index. - * @param string $name the name of the index to be dropped. The name will be properly quoted by the method. - * @param string $table the table whose index is to be dropped. The name will be properly quoted by the method. - * @return string the SQL statement for dropping an index. - */ - public function dropIndex($name, $table) - { - return 'DROP INDEX ' . $this->db->quoteTableName($name); - } - - /** - * Builds a SQL statement for renaming a DB table. - * @param string $oldName the table to be renamed. The name will be properly quoted by the method. - * @param string $newName the new table name. The name will be properly quoted by the method. - * @return string the SQL statement for renaming a DB table. - */ - public function renameTable($oldName, $newName) - { - return 'ALTER TABLE ' . $this->db->quoteTableName($oldName) . ' RENAME TO ' . $this->db->quoteTableName($newName); - } - - /** - * Creates a SQL statement for resetting the sequence value of a table's primary key. - * The sequence will be reset such that the primary key of the next new row inserted - * will have the specified value or 1. - * @param string $tableName the name of the table whose primary key sequence will be reset - * @param mixed $value the value for the primary key of the next new row inserted. If this is not set, - * the next new row's primary key will have a value 1. - * @return string the SQL statement for resetting sequence - * @throws InvalidParamException if the table does not exist or there is no sequence associated with the table. - */ - public function resetSequence($tableName, $value = null) - { - $table = $this->db->getTableSchema($tableName); - if ($table !== null && $table->sequenceName !== null) { - $sequence = '"' . $table->sequenceName . '"'; - - if (strpos($sequence, '.') !== false) { - $sequence = str_replace('.', '"."', $sequence); - } - - $tableName = $this->db->quoteTableName($tableName); - if ($value === null) { - $key = reset($table->primaryKey); - $value = "(SELECT COALESCE(MAX(\"{$key}\"),0) FROM {$tableName})+1"; - } else { - $value = (int)$value; - } - return "SELECT SETVAL('$sequence',$value,false)"; - } elseif ($table === null) { - throw new InvalidParamException("Table not found: $tableName"); - } else { - throw new InvalidParamException("There is not sequence associated with table '$tableName'."); - } - } - - /** - * Builds a SQL statement for enabling or disabling integrity check. - * @param boolean $check whether to turn on or off the integrity check. - * @param string $schema the schema of the tables. - * @param string $table the table name. - * @return string the SQL statement for checking integrity - */ - public function checkIntegrity($check = true, $schema = '', $table = '') - { - $enable = $check ? 'ENABLE' : 'DISABLE'; - $schema = $schema ? $schema : $this->db->schema->defaultSchema; - $tableNames = $table ? [$table] : $this->db->schema->getTableNames($schema); - $command = ''; - - foreach ($tableNames as $tableName) { - $tableName = '"' . $schema . '"."' . $tableName . '"'; - $command .= "ALTER TABLE $tableName $enable TRIGGER ALL; "; - } - - #enable to have ability to alter several tables - $this->db->pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true); - return $command; - } - - /** - * Builds a SQL statement for changing the definition of a column. - * @param string $table the table whose column is to be changed. The table name will be properly quoted by the method. - * @param string $column the name of the column to be changed. The name will be properly quoted by the method. - * @param string $type the new column type. The [[getColumnType()]] method will be invoked to convert abstract - * column type (if any) into the physical one. Anything that is not recognized as abstract type will be kept - * in the generated SQL. For example, 'string' will be turned into 'varchar(255)', while 'string not null' - * will become 'varchar(255) not null'. - * @return string the SQL statement for changing the definition of a column. - */ - public function alterColumn($table, $column, $type) - { - return 'ALTER TABLE ' . $this->db->quoteTableName($table) . ' ALTER COLUMN ' - . $this->db->quoteColumnName($column) . ' TYPE ' - . $this->getColumnType($type); - } -} diff --git a/framework/yii/db/pgsql/Schema.php b/framework/yii/db/pgsql/Schema.php deleted file mode 100644 index 96889ab..0000000 --- a/framework/yii/db/pgsql/Schema.php +++ /dev/null @@ -1,407 +0,0 @@ - - * @since 2.0 - */ -class Schema extends \yii\db\Schema -{ - - /** - * The default schema used for the current session. - * @var string - */ - public $defaultSchema = 'public'; - - /** - * @var array mapping from physical column types (keys) to abstract - * column types (values) - */ - public $typeMap = [ - 'abstime' => self::TYPE_TIMESTAMP, - 'bit' => self::TYPE_STRING, - 'bool' => self::TYPE_BOOLEAN, - 'boolean' => self::TYPE_BOOLEAN, - 'box' => self::TYPE_STRING, - 'character' => self::TYPE_STRING, - 'bytea' => self::TYPE_BINARY, - 'char' => self::TYPE_STRING, - 'cidr' => self::TYPE_STRING, - 'circle' => self::TYPE_STRING, - 'date' => self::TYPE_DATE, - 'real' => self::TYPE_FLOAT, - 'decimal' => self::TYPE_DECIMAL, - 'double precision' => self::TYPE_DECIMAL, - 'inet' => self::TYPE_STRING, - 'smallint' => self::TYPE_SMALLINT, - 'int4' => self::TYPE_INTEGER, - 'int8' => self::TYPE_BIGINT, - 'integer' => self::TYPE_INTEGER, - 'bigint' => self::TYPE_BIGINT, - 'interval' => self::TYPE_STRING, - 'json' => self::TYPE_STRING, - 'line' => self::TYPE_STRING, - 'macaddr' => self::TYPE_STRING, - 'money' => self::TYPE_MONEY, - 'name' => self::TYPE_STRING, - 'numeric' => self::TYPE_STRING, - 'oid' => self::TYPE_BIGINT, // should not be used. it's pg internal! - 'path' => self::TYPE_STRING, - 'point' => self::TYPE_STRING, - 'polygon' => self::TYPE_STRING, - 'text' => self::TYPE_TEXT, - 'time without time zone' => self::TYPE_TIME, - 'timestamp without time zone' => self::TYPE_TIMESTAMP, - 'timestamp with time zone' => self::TYPE_TIMESTAMP, - 'time with time zone' => self::TYPE_TIMESTAMP, - 'unknown' => self::TYPE_STRING, - 'uuid' => self::TYPE_STRING, - 'bit varying' => self::TYPE_STRING, - 'character varying' => self::TYPE_STRING, - 'xml' => self::TYPE_STRING - ]; - - /** - * Creates a query builder for the PostgreSQL database. - * @return QueryBuilder query builder instance - */ - public function createQueryBuilder() - { - return new QueryBuilder($this->db); - } - - /** - * Resolves the table name and schema name (if any). - * @param TableSchema $table the table metadata object - * @param string $name the table name - */ - protected function resolveTableNames($table, $name) - { - $parts = explode('.', str_replace('"', '', $name)); - if (isset($parts[1])) { - $table->schemaName = $parts[0]; - $table->name = $parts[1]; - } else { - $table->name = $parts[0]; - } - if ($table->schemaName === null) { - $table->schemaName = $this->defaultSchema; - } - } - - /** - * Quotes a table name for use in a query. - * A simple table name has no schema prefix. - * @param string $name table name - * @return string the properly quoted table name - */ - public function quoteSimpleTableName($name) - { - return strpos($name, '"') !== false ? $name : '"' . $name . '"'; - } - - /** - * Loads the metadata for the specified table. - * @param string $name table name - * @return TableSchema|null driver dependent table metadata. Null if the table does not exist. - */ - public function loadTableSchema($name) - { - $table = new TableSchema(); - $this->resolveTableNames($table, $name); - if ($this->findColumns($table)) { - $this->findConstraints($table); - return $table; - } else { - return null; - } - } - - /** - * Determines the PDO type for the given PHP data value. - * @param mixed $data the data whose PDO type is to be determined - * @return integer the PDO type - * @see http://www.php.net/manual/en/pdo.constants.php - */ - public function getPdoType($data) - { - // php type => PDO type - static $typeMap = [ - // https://github.com/yiisoft/yii2/issues/1115 - // Cast boolean to integer values to work around problems with PDO casting false to string '' https://bugs.php.net/bug.php?id=33876 - 'boolean' => \PDO::PARAM_INT, - 'integer' => \PDO::PARAM_INT, - 'string' => \PDO::PARAM_STR, - 'resource' => \PDO::PARAM_LOB, - 'NULL' => \PDO::PARAM_NULL, - ]; - $type = gettype($data); - return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR; - } - - /** - * Returns all table names in the database. - * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. - * @return array all table names in the database. The names have NO schema name prefix. - */ - protected function findTableNames($schema = '') - { - if ($schema === '') { - $schema = $this->defaultSchema; - } - $sql = <<db->createCommand($sql); - $command->bindParam(':schema', $schema); - $rows = $command->queryAll(); - $names = []; - foreach ($rows as $row) { - $names[] = $row['table_name']; - } - return $names; - } - - /** - * Collects the foreign key column details for the given table. - * @param TableSchema $table the table metadata - */ - protected function findConstraints($table) - { - - $tableName = $this->quoteValue($table->name); - $tableSchema = $this->quoteValue($table->schemaName); - - //We need to extract the constraints de hard way since: - //http://www.postgresql.org/message-id/26677.1086673982@sss.pgh.pa.us - - $sql = <<db->createCommand($sql)->queryAll(); - foreach ($constraints as $constraint) { - $columns = explode(',', $constraint['columns']); - $fcolumns = explode(',', $constraint['foreign_columns']); - if ($constraint['foreign_table_schema'] !== $this->defaultSchema) { - $foreignTable = $constraint['foreign_table_schema'] . '.' . $constraint['foreign_table_name']; - } else { - $foreignTable = $constraint['foreign_table_name']; - } - $citem = [$foreignTable]; - foreach ($columns as $idx => $column) { - $citem[$column] = $fcolumns[$idx]; - } - $table->foreignKeys[] = $citem; - } - } - - /** - * Gets information about given table unique indexes. - * @param TableSchema $table the table metadata - * @return array with index names, columns and if it is an expression tree - */ - protected function getUniqueIndexInformation($table) - { - $tableName = $this->quoteValue($table->name); - $tableSchema = $this->quoteValue($table->schemaName); - - $sql = <<db->createCommand($sql)->queryAll(); - } - - /** - * Returns all unique indexes for the given table. - * Each array element is of the following structure: - * - * ~~~ - * [ - * 'IndexName1' => ['col1' [, ...]], - * 'IndexName2' => ['col2' [, ...]], - * ] - * ~~~ - * - * @param TableSchema $table the table metadata - * @return array all unique indexes for the given table. - */ - public function findUniqueIndexes($table) - { - $indexes = $this->getUniqueIndexInformation($table); - $uniqueIndexes = []; - - foreach ($indexes as $index) { - $indexName = $index['indexname']; - - if ($index['indexprs']) { - // Index is an expression like "lower(colname::text)" - $indexColumns = preg_replace("/.*\(([^\:]+).*/mi", "$1", $index['indexcolumns']); - } else { - $indexColumns = array_map('trim', explode(',', str_replace(['{', '}'], '', $index['indexcolumns']))); - } - - $uniqueIndexes[$indexName] = $indexColumns; - - } - return $uniqueIndexes; - } - - /** - * Collects the metadata of table columns. - * @param TableSchema $table the table metadata - * @return boolean whether the table exists in the database - */ - protected function findColumns($table) - { - $tableName = $this->db->quoteValue($table->name); - $schemaName = $this->db->quoteValue($table->schemaName); - $sql = <<> 16) & 65535 - END - WHEN 700 /*float4*/ THEN 24 /*FLT_MANT_DIG*/ - WHEN 701 /*float8*/ THEN 53 /*DBL_MANT_DIG*/ - ELSE null - END AS numeric_precision, - CASE - WHEN atttypid IN (21, 23, 20) THEN 0 - WHEN atttypid IN (1700) THEN - CASE - WHEN atttypmod = -1 THEN null - ELSE (atttypmod - 4) & 65535 - END - ELSE null - END AS numeric_scale, - CAST( - information_schema._pg_char_max_length(information_schema._pg_truetypid(a, t), information_schema._pg_truetypmod(a, t)) - AS numeric - ) AS size, - a.attnum = any (ct.conkey) as is_pkey -FROM - pg_class c - LEFT JOIN pg_attribute a ON a.attrelid = c.oid - LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum - LEFT JOIN pg_type t ON a.atttypid = t.oid - LEFT JOIN pg_namespace d ON d.oid = c.relnamespace - LEFT join pg_constraint ct on ct.conrelid=c.oid and ct.contype='p' -WHERE - a.attnum > 0 and t.typname != '' - and c.relname = {$tableName} - and d.nspname = {$schemaName} -ORDER BY - a.attnum; -SQL; - - $columns = $this->db->createCommand($sql)->queryAll(); - if (empty($columns)) { - return false; - } - foreach ($columns as $column) { - $column = $this->loadColumnSchema($column); - $table->columns[$column->name] = $column; - if ($column->isPrimaryKey === true) { - $table->primaryKey[] = $column->name; - if ($table->sequenceName === null && preg_match("/nextval\\('\"?\\w+\"?\.?\"?\\w+\"?'(::regclass)?\\)/", $column->defaultValue) === 1) { - $table->sequenceName = preg_replace(['/nextval/', '/::/', '/regclass/', '/\'\)/', '/\(\'/'], '', $column->defaultValue); - } - } - } - return true; - } - - /** - * Loads the column information into a [[ColumnSchema]] object. - * @param array $info column information - * @return ColumnSchema the column schema object - */ - protected function loadColumnSchema($info) - { - $column = new ColumnSchema(); - $column->allowNull = $info['is_nullable']; - $column->autoIncrement = $info['is_autoinc']; - $column->comment = $info['column_comment']; - $column->dbType = $info['data_type']; - $column->defaultValue = $info['column_default']; - $column->enumValues = explode(',', str_replace(["''"], ["'"], $info['enum_values'])); - $column->unsigned = false; // has no meaning in PG - $column->isPrimaryKey = $info['is_pkey']; - $column->name = $info['column_name']; - $column->precision = $info['numeric_precision']; - $column->scale = $info['numeric_scale']; - $column->size = $info['size']; - - if (isset($this->typeMap[$column->dbType])) { - $column->type = $this->typeMap[$column->dbType]; - } else { - $column->type = self::TYPE_STRING; - } - $column->phpType = $this->getColumnPhpType($column); - return $column; - } -} diff --git a/framework/yii/db/sqlite/QueryBuilder.php b/framework/yii/db/sqlite/QueryBuilder.php deleted file mode 100644 index bddc436..0000000 --- a/framework/yii/db/sqlite/QueryBuilder.php +++ /dev/null @@ -1,275 +0,0 @@ - - * @since 2.0 - */ -class QueryBuilder extends \yii\db\QueryBuilder -{ - /** - * @var array mapping from abstract column types (keys) to physical column types (values). - */ - public $typeMap = [ - Schema::TYPE_PK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL', - Schema::TYPE_BIGPK => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL', - Schema::TYPE_STRING => 'varchar(255)', - Schema::TYPE_TEXT => 'text', - Schema::TYPE_SMALLINT => 'smallint', - Schema::TYPE_INTEGER => 'integer', - Schema::TYPE_BIGINT => 'bigint', - Schema::TYPE_FLOAT => 'float', - Schema::TYPE_DECIMAL => 'decimal(10,0)', - Schema::TYPE_DATETIME => 'datetime', - Schema::TYPE_TIMESTAMP => 'timestamp', - Schema::TYPE_TIME => 'time', - Schema::TYPE_DATE => 'date', - Schema::TYPE_BINARY => 'blob', - Schema::TYPE_BOOLEAN => 'boolean', - Schema::TYPE_MONEY => 'decimal(19,4)', - ]; - - /** - * Generates a batch INSERT SQL statement. - * For example, - * - * ~~~ - * $connection->createCommand()->batchInsert('tbl_user', ['name', 'age'], [ - * ['Tom', 30], - * ['Jane', 20], - * ['Linda', 25], - * ])->execute(); - * ~~~ - * - * Note that the values in each row must match the corresponding column names. - * - * @param string $table the table that new rows will be inserted into. - * @param array $columns the column names - * @param array $rows the rows to be batch inserted into the table - * @return string the batch INSERT SQL statement - */ - public function batchInsert($table, $columns, $rows) - { - if (($tableSchema = $this->db->getTableSchema($table)) !== null) { - $columnSchemas = $tableSchema->columns; - } else { - $columnSchemas = []; - } - - foreach ($columns as $i => $name) { - $columns[$i] = $this->db->quoteColumnName($name); - } - - $values = []; - foreach ($rows as $row) { - $vs = []; - foreach ($row as $i => $value) { - if (!is_array($value) && isset($columnSchemas[$columns[$i]])) { - $value = $columnSchemas[$columns[$i]]->typecast($value); - } - $vs[] = is_string($value) ? $this->db->quoteValue($value) : $value; - } - $values[] = implode(', ', $vs); - } - - return 'INSERT INTO ' . $this->db->quoteTableName($table) - . ' (' . implode(', ', $columns) . ') SELECT ' . implode(' UNION ALL ', $values); - } - - /** - * Creates a SQL statement for resetting the sequence value of a table's primary key. - * The sequence will be reset such that the primary key of the next new row inserted - * will have the specified value or 1. - * @param string $tableName the name of the table whose primary key sequence will be reset - * @param mixed $value the value for the primary key of the next new row inserted. If this is not set, - * the next new row's primary key will have a value 1. - * @return string the SQL statement for resetting sequence - * @throws InvalidParamException if the table does not exist or there is no sequence associated with the table. - */ - public function resetSequence($tableName, $value = null) - { - $db = $this->db; - $table = $db->getTableSchema($tableName); - if ($table !== null && $table->sequenceName !== null) { - if ($value === null) { - $key = reset($table->primaryKey); - $tableName = $db->quoteTableName($tableName); - $value = $db->createCommand("SELECT MAX('$key') FROM $tableName")->queryScalar(); - } else { - $value = (int)$value - 1; - } - try { - // it's possible sqlite_sequence does not exist - $db->createCommand("UPDATE sqlite_sequence SET seq='$value' WHERE name='{$table->name}'")->execute(); - } catch (Exception $e) { - } - } elseif ($table === null) { - throw new InvalidParamException("Table not found: $tableName"); - } else { - throw new InvalidParamException("There is not sequence associated with table '$tableName'.'"); - } - } - - /** - * Enables or disables integrity check. - * @param boolean $check whether to turn on or off the integrity check. - * @param string $schema the schema of the tables. Meaningless for SQLite. - * @param string $table the table name. Meaningless for SQLite. - * @return string the SQL statement for checking integrity - * @throws NotSupportedException this is not supported by SQLite - */ - public function checkIntegrity($check = true, $schema = '', $table = '') - { - throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.'); - } - - /** - * Builds a SQL statement for truncating a DB table. - * @param string $table the table to be truncated. The name will be properly quoted by the method. - * @return string the SQL statement for truncating a DB table. - */ - public function truncateTable($table) - { - return "DELETE FROM " . $this->db->quoteTableName($table); - } - - /** - * Builds a SQL statement for dropping an index. - * @param string $name the name of the index to be dropped. The name will be properly quoted by the method. - * @param string $table the table whose index is to be dropped. The name will be properly quoted by the method. - * @return string the SQL statement for dropping an index. - */ - public function dropIndex($name, $table) - { - return 'DROP INDEX ' . $this->db->quoteTableName($name); - } - - /** - * Builds a SQL statement for dropping a DB column. - * @param string $table the table whose column is to be dropped. The name will be properly quoted by the method. - * @param string $column the name of the column to be dropped. The name will be properly quoted by the method. - * @return string the SQL statement for dropping a DB column. - * @throws NotSupportedException this is not supported by SQLite - */ - public function dropColumn($table, $column) - { - throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.'); - } - - /** - * Builds a SQL statement for renaming a column. - * @param string $table the table whose column is to be renamed. The name will be properly quoted by the method. - * @param string $oldName the old name of the column. The name will be properly quoted by the method. - * @param string $newName the new name of the column. The name will be properly quoted by the method. - * @return string the SQL statement for renaming a DB column. - * @throws NotSupportedException this is not supported by SQLite - */ - public function renameColumn($table, $oldName, $newName) - { - throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.'); - } - - /** - * Builds a SQL statement for adding a foreign key constraint to an existing table. - * The method will properly quote the table and column names. - * @param string $name the name of the foreign key constraint. - * @param string $table the table that the foreign key constraint will be added to. - * @param string|array $columns the name of the column to that the constraint will be added on. - * If there are multiple columns, separate them with commas or use an array to represent them. - * @param string $refTable the table that the foreign key references to. - * @param string|array $refColumns the name of the column that the foreign key references to. - * If there are multiple columns, separate them with commas or use an array to represent them. - * @param string $delete the ON DELETE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL - * @param string $update the ON UPDATE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL - * @return string the SQL statement for adding a foreign key constraint to an existing table. - * @throws NotSupportedException this is not supported by SQLite - */ - public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete = null, $update = null) - { - throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.'); - } - - /** - * Builds a SQL statement for dropping a foreign key constraint. - * @param string $name the name of the foreign key constraint to be dropped. The name will be properly quoted by the method. - * @param string $table the table whose foreign is to be dropped. The name will be properly quoted by the method. - * @return string the SQL statement for dropping a foreign key constraint. - * @throws NotSupportedException this is not supported by SQLite - */ - public function dropForeignKey($name, $table) - { - throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.'); - } - - /** - * Builds a SQL statement for changing the definition of a column. - * @param string $table the table whose column is to be changed. The table name will be properly quoted by the method. - * @param string $column the name of the column to be changed. The name will be properly quoted by the method. - * @param string $type the new column type. The [[getColumnType()]] method will be invoked to convert abstract - * column type (if any) into the physical one. Anything that is not recognized as abstract type will be kept - * in the generated SQL. For example, 'string' will be turned into 'varchar(255)', while 'string not null' - * will become 'varchar(255) not null'. - * @return string the SQL statement for changing the definition of a column. - * @throws NotSupportedException this is not supported by SQLite - */ - public function alterColumn($table, $column, $type) - { - throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.'); - } - - /** - * Builds a SQL statement for adding a primary key constraint to an existing table. - * @param string $name the name of the primary key constraint. - * @param string $table the table that the primary key constraint will be added to. - * @param string|array $columns comma separated string or array of columns that the primary key will consist of. - * @return string the SQL statement for adding a primary key constraint to an existing table. - * @throws NotSupportedException this is not supported by SQLite - */ - public function addPrimaryKey($name, $table, $columns) - { - throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.'); - } - - /** - * Builds a SQL statement for removing a primary key constraint to an existing table. - * @param string $name the name of the primary key constraint to be removed. - * @param string $table the table that the primary key constraint will be removed from. - * @return string the SQL statement for removing a primary key constraint from an existing table. - * @throws NotSupportedException this is not supported by SQLite * - */ - public function dropPrimaryKey($name, $table) - { - throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.'); - } - - /** - * @inheritdoc - */ - public function buildLimit($limit, $offset) - { - $sql = ''; - // limit is not optional in SQLite - // http://www.sqlite.org/syntaxdiagrams.html#select-stmt - if ($limit !== null && $limit >= 0) { - $sql = 'LIMIT ' . (int)$limit; - if ($offset > 0) { - $sql .= ' OFFSET ' . (int)$offset; - } - } elseif ($offset > 0) { - $sql = 'LIMIT 9223372036854775807 OFFSET ' . (int)$offset; // 2^63-1 - } - return $sql; - } -} diff --git a/framework/yii/db/sqlite/Schema.php b/framework/yii/db/sqlite/Schema.php deleted file mode 100644 index 9f410b4..0000000 --- a/framework/yii/db/sqlite/Schema.php +++ /dev/null @@ -1,245 +0,0 @@ - - * @since 2.0 - */ -class Schema extends \yii\db\Schema -{ - /** - * @var array mapping from physical column types (keys) to abstract column types (values) - */ - public $typeMap = [ - 'tinyint' => self::TYPE_SMALLINT, - 'bit' => self::TYPE_SMALLINT, - 'smallint' => self::TYPE_SMALLINT, - 'mediumint' => self::TYPE_INTEGER, - 'int' => self::TYPE_INTEGER, - 'integer' => self::TYPE_INTEGER, - 'bigint' => self::TYPE_BIGINT, - 'float' => self::TYPE_FLOAT, - 'double' => self::TYPE_FLOAT, - 'real' => self::TYPE_FLOAT, - 'decimal' => self::TYPE_DECIMAL, - 'numeric' => self::TYPE_DECIMAL, - 'tinytext' => self::TYPE_TEXT, - 'mediumtext' => self::TYPE_TEXT, - 'longtext' => self::TYPE_TEXT, - 'text' => self::TYPE_TEXT, - 'varchar' => self::TYPE_STRING, - 'string' => self::TYPE_STRING, - 'char' => self::TYPE_STRING, - 'datetime' => self::TYPE_DATETIME, - 'year' => self::TYPE_DATE, - 'date' => self::TYPE_DATE, - 'time' => self::TYPE_TIME, - 'timestamp' => self::TYPE_TIMESTAMP, - 'enum' => self::TYPE_STRING, - ]; - - /** - * Quotes a table name for use in a query. - * A simple table name has no schema prefix. - * @param string $name table name - * @return string the properly quoted table name - */ - public function quoteSimpleTableName($name) - { - return strpos($name, "`") !== false ? $name : "`" . $name . "`"; - } - - /** - * Quotes a column name for use in a query. - * A simple column name has no prefix. - * @param string $name column name - * @return string the properly quoted column name - */ - public function quoteSimpleColumnName($name) - { - return strpos($name, '`') !== false || $name === '*' ? $name : '`' . $name . '`'; - } - - /** - * Creates a query builder for the MySQL database. - * This method may be overridden by child classes to create a DBMS-specific query builder. - * @return QueryBuilder query builder instance - */ - public function createQueryBuilder() - { - return new QueryBuilder($this->db); - } - - /** - * Returns all table names in the database. - * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema. - * If not empty, the returned table names will be prefixed with the schema name. - * @return array all table names in the database. - */ - protected function findTableNames($schema = '') - { - $sql = "SELECT DISTINCT tbl_name FROM sqlite_master WHERE tbl_name<>'sqlite_sequence'"; - return $this->db->createCommand($sql)->queryColumn(); - } - - /** - * Loads the metadata for the specified table. - * @param string $name table name - * @return TableSchema driver dependent table metadata. Null if the table does not exist. - */ - protected function loadTableSchema($name) - { - $table = new TableSchema; - $table->name = $name; - - if ($this->findColumns($table)) { - $this->findConstraints($table); - return $table; - } else { - return null; - } - } - - /** - * Collects the table column metadata. - * @param TableSchema $table the table metadata - * @return boolean whether the table exists in the database - */ - protected function findColumns($table) - { - $sql = "PRAGMA table_info(" . $this->quoteSimpleTableName($table->name) . ')'; - $columns = $this->db->createCommand($sql)->queryAll(); - if (empty($columns)) { - return false; - } - - foreach ($columns as $info) { - $column = $this->loadColumnSchema($info); - $table->columns[$column->name] = $column; - if ($column->isPrimaryKey) { - $table->primaryKey[] = $column->name; - } - } - if (count($table->primaryKey) === 1 && !strncasecmp($table->columns[$table->primaryKey[0]]->dbType, 'int', 3)) { - $table->sequenceName = ''; - $table->columns[$table->primaryKey[0]]->autoIncrement = true; - } - - return true; - } - - /** - * Collects the foreign key column details for the given table. - * @param TableSchema $table the table metadata - */ - protected function findConstraints($table) - { - $sql = "PRAGMA foreign_key_list(" . $this->quoteSimpleTableName($table->name) . ')'; - $keys = $this->db->createCommand($sql)->queryAll(); - foreach ($keys as $key) { - $id = (int)$key['id']; - if (!isset($table->foreignKeys[$id])) { - $table->foreignKeys[$id] = [$key['table'], $key['from'] => $key['to']]; - } else { - // composite FK - $table->foreignKeys[$id][$key['from']] = $key['to']; - } - } - } - - /** - * Returns all unique indexes for the given table. - * Each array element is of the following structure: - * - * ~~~ - * [ - * 'IndexName1' => ['col1' [, ...]], - * 'IndexName2' => ['col2' [, ...]], - * ] - * ~~~ - * - * @param TableSchema $table the table metadata - * @return array all unique indexes for the given table. - */ - public function findUniqueIndexes($table) - { - $sql = "PRAGMA index_list(" . $this->quoteSimpleTableName($table->name) . ')'; - $indexes = $this->db->createCommand($sql)->queryAll(); - $uniqueIndexes = []; - - foreach ($indexes as $index) { - $indexName = $index['name']; - $indexInfo = $this->db->createCommand("PRAGMA index_info(" . $this->quoteValue($index['name']) . ")")->queryAll(); - - if ($index['unique']) { - $uniqueIndexes[$indexName] = []; - foreach ($indexInfo as $row) { - $uniqueIndexes[$indexName][] = $row['name']; - } - } - } - return $uniqueIndexes; - } - - /** - * Loads the column information into a [[ColumnSchema]] object. - * @param array $info column information - * @return ColumnSchema the column schema object - */ - protected function loadColumnSchema($info) - { - $column = new ColumnSchema; - $column->name = $info['name']; - $column->allowNull = !$info['notnull']; - $column->isPrimaryKey = $info['pk'] != 0; - - $column->dbType = $info['type']; - $column->unsigned = strpos($column->dbType, 'unsigned') !== false; - - $column->type = self::TYPE_STRING; - if (preg_match('/^(\w+)(?:\(([^\)]+)\))?/', $column->dbType, $matches)) { - $type = strtolower($matches[1]); - if (isset($this->typeMap[$type])) { - $column->type = $this->typeMap[$type]; - } - - if (!empty($matches[2])) { - $values = explode(',', $matches[2]); - $column->size = $column->precision = (int)$values[0]; - if (isset($values[1])) { - $column->scale = (int)$values[1]; - } - if ($column->size === 1 && ($type === 'tinyint' || $type === 'bit')) { - $column->type = 'boolean'; - } elseif ($type === 'bit') { - if ($column->size > 32) { - $column->type = 'bigint'; - } elseif ($column->size === 32) { - $column->type = 'integer'; - } - } - } - } - $column->phpType = $this->getColumnPhpType($column); - - $value = $info['dflt_value']; - if ($column->type === 'string') { - $column->defaultValue = trim($value, "'\""); - } else { - $column->defaultValue = $column->typecast(strcasecmp($value, 'null') ? $value : null); - } - - return $column; - } -} diff --git a/framework/yii/grid/ActionColumn.php b/framework/yii/grid/ActionColumn.php deleted file mode 100644 index 26ed1c3..0000000 --- a/framework/yii/grid/ActionColumn.php +++ /dev/null @@ -1,135 +0,0 @@ - - * @since 2.0 - */ -class ActionColumn extends Column -{ - /** - * @var string the ID of the controller that should handle the actions specified here. - * If not set, it will use the currently active controller. This property is mainly used by - * [[urlCreator]] to create URLs for different actions. The value of this property will be prefixed - * to each action name to form the route of the action. - */ - public $controller; - /** - * @var string the template used for composing each cell in the action column. - * Tokens enclosed within curly brackets are treated as controller action IDs (also called *button names* - * in the context of action column). They will be replaced by the corresponding button rendering callbacks - * specified in [[buttons]]. For example, the token `{view}` will be replaced by the result of - * the callback `buttons['view']`. If a callback cannot be found, the token will be replaced with an empty string. - * @see buttons - */ - public $template = '{view} {update} {delete}'; - /** - * @var array button rendering callbacks. The array keys are the button names (without curly brackets), - * and the values are the corresponding button rendering callbacks. The callbacks should use the following - * signature: - * - * ```php - * function ($url, $model) { - * // return the button HTML code - * } - * ``` - * - * where `$url` is the URL that the column creates for the button, and `$model` is the model object - * being rendered for the current row. - */ - public $buttons = []; - /** - * @var callback a callback that creates a button URL using the specified model information. - * The signature of the callback should be the same as that of [[createUrl()]]. - * If this property is not set, button URLs will be created using [[createUrl()]]. - */ - public $urlCreator; - - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - $this->initDefaultButtons(); - } - - /** - * Initializes the default button rendering callbacks - */ - protected function initDefaultButtons() - { - if (!isset($this->buttons['view'])) { - $this->buttons['view'] = function ($url, $model) { - return Html::a('', $url, [ - 'title' => Yii::t('yii', 'View'), - ]); - }; - } - if (!isset($this->buttons['update'])) { - $this->buttons['update'] = function ($url, $model) { - return Html::a('', $url, [ - 'title' => Yii::t('yii', 'Update'), - ]); - }; - } - if (!isset($this->buttons['delete'])) { - $this->buttons['delete'] = function ($url, $model) { - return Html::a('', $url, [ - 'title' => Yii::t('yii', 'Delete'), - 'data-confirm' => Yii::t('yii', 'Are you sure to delete this item?'), - 'data-method' => 'post', - ]); - }; - } - } - - /** - * Creates a URL for the given action and model. - * This method is called for each button and each row. - * @param string $action the button name (or action ID) - * @param \yii\db\ActiveRecord $model the data model - * @param mixed $key the key associated with the data model - * @param integer $index the current row index - * @return string the created URL - */ - public function createUrl($action, $model, $key, $index) - { - if ($this->urlCreator instanceof Closure) { - return call_user_func($this->urlCreator, $action, $model, $key, $index); - } else { - $params = is_array($key) ? $key : ['id' => $key]; - $route = $this->controller ? $this->controller . '/' . $action : $action; - return Yii::$app->controller->createUrl($route, $params); - } - } - - /** - * @inheritdoc - */ - protected function renderDataCellContent($model, $key, $index) - { - return preg_replace_callback('/\\{([\w\-]+)\\}/', function ($matches) use ($model, $key, $index) { - $name = $matches[1]; - if (isset($this->buttons[$name])) { - $url = $this->createUrl($name, $model, $key, $index); - return call_user_func($this->buttons[$name], $url, $model); - } else { - return ''; - } - }, $this->template); - } -} diff --git a/framework/yii/grid/CheckboxColumn.php b/framework/yii/grid/CheckboxColumn.php deleted file mode 100644 index bf6bcef..0000000 --- a/framework/yii/grid/CheckboxColumn.php +++ /dev/null @@ -1,84 +0,0 @@ - - * @since 2.0 - */ -class CheckboxColumn extends Column -{ - public $name = 'selection'; - public $checkboxOptions = []; - public $multiple = true; - - - public function init() - { - parent::init(); - if (empty($this->name)) { - throw new InvalidConfigException('The "name" property must be set.'); - } - if (substr($this->name, -2) !== '[]') { - $this->name .= '[]'; - } - } - - /** - * Renders the header cell content. - * The default implementation simply renders [[header]]. - * This method may be overridden to customize the rendering of the header cell. - * @return string the rendering result - */ - protected function renderHeaderCellContent() - { - $name = rtrim($this->name, '[]') . '_all'; - $id = $this->grid->options['id']; - $options = json_encode([ - 'name' => $this->name, - 'multiple' => $this->multiple, - 'checkAll' => $name, - ]); - $this->grid->getView()->registerJs("jQuery('#$id').yiiGridView('setSelectionColumn', $options);"); - - if ($this->header !== null || !$this->multiple) { - return parent::renderHeaderCellContent(); - } else { - return Html::checkBox($name, false, ['class' => 'select-on-check-all']); - } - } - - /** - * @inheritdoc - */ - protected function renderDataCellContent($model, $key, $index) - { - if ($this->checkboxOptions instanceof Closure) { - $options = call_user_func($this->checkboxOptions, $model, $key, $index, $this); - } else { - $options = $this->checkboxOptions; - if (!isset($options['value'])) { - $options['value'] = is_array($key) ? json_encode($key) : $key; - } - } - return Html::checkbox($this->name, !empty($options['checked']), $options); - } -} diff --git a/framework/yii/grid/Column.php b/framework/yii/grid/Column.php deleted file mode 100644 index 5cc4c42..0000000 --- a/framework/yii/grid/Column.php +++ /dev/null @@ -1,144 +0,0 @@ - - * @since 2.0 - */ -class Column extends Object -{ - /** - * @var GridView the grid view object that owns this column. - */ - public $grid; - /** - * @var string the header cell content. Note that it will not be HTML-encoded. - */ - public $header; - /** - * @var string the footer cell content. Note that it will not be HTML-encoded. - */ - public $footer; - /** - * @var callable - */ - public $content; - /** - * @var boolean whether this column is visible. Defaults to true. - */ - public $visible = true; - public $options = []; - public $headerOptions = []; - /** - * @var array|\Closure - */ - public $contentOptions = []; - public $footerOptions = []; - /** - * @var array the HTML attributes for the filter cell tag. - */ - public $filterOptions=[]; - - - /** - * Renders the header cell. - */ - public function renderHeaderCell() - { - return Html::tag('th', $this->renderHeaderCellContent(), $this->headerOptions); - } - - /** - * Renders the footer cell. - */ - public function renderFooterCell() - { - return Html::tag('td', $this->renderFooterCellContent(), $this->footerOptions); - } - - /** - * Renders a data cell. - * @param mixed $model the data model being rendered - * @param mixed $key the key associated with the data model - * @param integer $index the zero-based index of the data item among the item array returned by [[dataProvider]]. - * @return string the rendering result - */ - public function renderDataCell($model, $key, $index) - { - if ($this->contentOptions instanceof Closure) { - $options = call_user_func($this->contentOptions, $model, $key, $index, $this); - } else { - $options = $this->contentOptions; - } - return Html::tag('td', $this->renderDataCellContent($model, $key, $index), $options); - } - - /** - * Renders the filter cell. - */ - public function renderFilterCell() - { - return Html::tag('td', $this->renderFilterCellContent(), $this->filterOptions); - } - - /** - * Renders the header cell content. - * The default implementation simply renders [[header]]. - * This method may be overridden to customize the rendering of the header cell. - * @return string the rendering result - */ - protected function renderHeaderCellContent() - { - return trim($this->header) !== '' ? $this->header : $this->grid->emptyCell; - } - - /** - * Renders the footer cell content. - * The default implementation simply renders [[footer]]. - * This method may be overridden to customize the rendering of the footer cell. - * @return string the rendering result - */ - protected function renderFooterCellContent() - { - return trim($this->footer) !== '' ? $this->footer : $this->grid->emptyCell; - } - - /** - * Renders the data cell content. - * @param mixed $model the data model - * @param mixed $key the key associated with the data model - * @param integer $index the zero-based index of the data model among the models array returned by [[dataProvider]]. - * @return string the rendering result - */ - protected function renderDataCellContent($model, $key, $index) - { - if ($this->content !== null) { - return call_user_func($this->content, $model, $key, $index, $this); - } else { - return $this->grid->emptyCell; - } - } - - /** - * Renders the filter cell content. - * The default implementation simply renders a space. - * This method may be overridden to customize the rendering of the filter cell (if any). - * @return string the rendering result - */ - protected function renderFilterCellContent() - { - return $this->grid->emptyCell; - } -} diff --git a/framework/yii/grid/DataColumn.php b/framework/yii/grid/DataColumn.php deleted file mode 100644 index 032c21c..0000000 --- a/framework/yii/grid/DataColumn.php +++ /dev/null @@ -1,151 +0,0 @@ - - * @since 2.0 - */ -class DataColumn extends Column -{ - /** - * @var string the attribute name associated with this column. When neither [[content]] nor [[value]] - * is specified, the value of the specified attribute will be retrieved from each data model and displayed. - * - * Also, if [[header]] is not specified, the label associated with the attribute will be displayed. - */ - public $attribute; - /** - * @var string label to be displayed in the [[header|header cell]] and also to be used as the sorting - * link label when sorting is enabled for this column. - * If it is not set and the models provided by the GridViews data provider are instances - * of [[yii\db\ActiveRecord]], the label will be determined using [[yii\db\ActiveRecord::getAttributeLabel()]]. - * Otherwise [[yii\helpers\Inflector::camel2words()]] will be used to get a label. - */ - public $label; - /** - * @var \Closure an anonymous function that returns the value to be displayed for every data model. - * The signature of this function is `function ($model, $index, $widget)`. - * If this is not set, `$model[$attribute]` will be used to obtain the value. - */ - public $value; - /** - * @var string|array in which format should the value of each data model be displayed as (e.g. "text", "html", - * ['date', 'Y-m-d']). Supported formats are determined by the [[GridView::formatter|formatter]] used by - * the [[GridView]]. Default format is "text" which will format the value as an HTML-encoded plain text when - * [[\yii\base\Formatter::format()]] or [[\yii\i18n\Formatter::format()]] is used. - */ - public $format = 'text'; - /** - * @var boolean whether to allow sorting by this column. If true and [[attribute]] is found in - * the sort definition of [[GridView::dataProvider]], then the header cell of this column - * will contain a link that may trigger the sorting when being clicked. - */ - public $enableSorting = true; - /** - * @var array the HTML attributes for the link tag in the header cell - * generated by [[Sort::link]] when sorting is enabled for this column. - */ - public $sortLinkOptions = []; - /** - * @var string|array|boolean the HTML code representing a filter input (e.g. a text field, a dropdown list) - * that is used for this data column. This property is effective only when [[GridView::filterModel]] is set. - * - * - If this property is not set, a text field will be generated as the filter input; - * - If this property is an array, a dropdown list will be generated that uses this property value as - * the list options. - * - If you don't want a filter for this data column, set this value to be false. - */ - public $filter; - /** - * @var array the HTML attributes for the filter input fields. This property is used in combination with - * the [[filter]] property. When [[filter]] is not set or is an array, this property will be used to - * render the HTML attributes for the generated filter input fields. - */ - public $filterInputOptions = ['class' => 'form-control', 'id' => null]; - - - protected function renderHeaderCellContent() - { - if ($this->header !== null || $this->label === null && $this->attribute === null) { - return parent::renderHeaderCellContent(); - } - - $provider = $this->grid->dataProvider; - - if ($this->label === null) { - if ($provider instanceof ActiveDataProvider && $provider->query instanceof ActiveQuery) { - /** @var Model $model */ - $model = new $provider->query->modelClass; - $label = $model->getAttributeLabel($this->attribute); - } else { - $models = $provider->getModels(); - if (($model = reset($models)) instanceof Model) { - /** @var Model $model */ - $label = $model->getAttributeLabel($this->attribute); - } else { - $label = Inflector::camel2words($this->attribute); - } - } - } else { - $label = $this->label; - } - - if ($this->attribute !== null && $this->enableSorting && - ($sort = $provider->getSort()) !== false && $sort->hasAttribute($this->attribute)) { - - return $sort->link($this->attribute, array_merge($this->sortLinkOptions, ['label' => Html::encode($label)])); - } else { - return Html::encode($label); - } - } - - protected function renderFilterCellContent() - { - if (is_string($this->filter)) { - return $this->filter; - } elseif ($this->filter !== false && $this->grid->filterModel instanceof Model && - $this->attribute !== null && $this->grid->filterModel->isAttributeActive($this->attribute)) - { - if (is_array($this->filter)) { - $options = array_merge(['prompt' => ''], $this->filterInputOptions); - return Html::activeDropDownList($this->grid->filterModel, $this->attribute, $this->filter, $options); - } else { - return Html::activeTextInput($this->grid->filterModel, $this->attribute, $this->filterInputOptions); - } - } else { - return parent::renderFilterCellContent(); - } - } - - /** - * @inheritdoc - */ - protected function renderDataCellContent($model, $key, $index) - { - if ($this->value !== null) { - $value = call_user_func($this->value, $model, $index, $this); - } elseif ($this->content === null && $this->attribute !== null) { - $value = ArrayHelper::getValue($model, $this->attribute); - } else { - return parent::renderDataCellContent($model, $key, $index); - } - return $this->grid->formatter->format($value, $this->format); - } -} diff --git a/framework/yii/grid/GridView.php b/framework/yii/grid/GridView.php deleted file mode 100644 index e270974..0000000 --- a/framework/yii/grid/GridView.php +++ /dev/null @@ -1,442 +0,0 @@ - - * @since 2.0 - */ -class GridView extends BaseListView -{ - const FILTER_POS_HEADER = 'header'; - const FILTER_POS_FOOTER = 'footer'; - const FILTER_POS_BODY = 'body'; - - /** - * @var string the default data column class if the class name is not explicitly specified when configuring a data column. - * Defaults to 'yii\grid\DataColumn'. - */ - public $dataColumnClass; - /** - * @var string the caption of the grid table - * @see captionOptions - */ - public $caption; - /** - * @var array the HTML attributes for the caption element - * @see caption - */ - public $captionOptions = []; - /** - * @var array the HTML attributes for the grid table element - */ - public $tableOptions = ['class' => 'table table-striped table-bordered']; - /** - * @var array the HTML attributes for the container tag of the grid view. - * The "tag" element specifies the tag name of the container element and defaults to "div". - */ - public $options = ['class' => 'grid-view']; - /** - * @var array the HTML attributes for the table header row - */ - public $headerRowOptions = []; - /** - * @var array the HTML attributes for the table footer row - */ - public $footerRowOptions = []; - /** - * @var array|Closure the HTML attributes for the table body rows. This can be either an array - * specifying the common HTML attributes for all body rows, or an anonymous function that - * returns an array of the HTML attributes. The anonymous function will be called once for every - * data model returned by [[dataProvider]]. It should have the following signature: - * - * ~~~php - * function ($model, $key, $index, $grid) - * ~~~ - * - * - `$model`: the current data model being rendered - * - `$key`: the key value associated with the current data model - * - `$index`: the zero-based index of the data model in the model array returned by [[dataProvider]] - * - `$grid`: the GridView object - */ - public $rowOptions = []; - /** - * @var Closure an anonymous function that is called once BEFORE rendering each data model. - * It should have the similar signature as [[rowOptions]]. The return result of the function - * will be rendered directly. - */ - public $beforeRow; - /** - * @var Closure an anonymous function that is called once AFTER rendering each data model. - * It should have the similar signature as [[rowOptions]]. The return result of the function - * will be rendered directly. - */ - public $afterRow; - /** - * @var boolean whether to show the header section of the grid table. - */ - public $showHeader = true; - /** - * @var boolean whether to show the footer section of the grid table. - */ - public $showFooter = false; - /** - * @var boolean whether to show the grid view if [[dataProvider]] returns no data. - */ - public $showOnEmpty = true; - /** - * @var array|Formatter the formatter used to format model attribute values into displayable texts. - * This can be either an instance of [[Formatter]] or an configuration array for creating the [[Formatter]] - * instance. If this property is not set, the "formatter" application component will be used. - */ - public $formatter; - /** - * @var array grid column configuration. Each array element represents the configuration - * for one particular grid column. For example, - * - * ~~~php - * [ - * ['class' => SerialColumn::className()], - * [ - * 'class' => DataColumn::className(), - * 'attribute' => 'name', - * 'format' => 'text', - * 'label' => 'Name', - * ], - * ['class' => CheckboxColumn::className()], - * ] - * ~~~ - * - * If a column is of class [[DataColumn]], the "class" element can be omitted. - * - * As a shortcut format, a string may be used to specify the configuration of a data column - * which only contains "attribute", "format", and/or "label" options: `"attribute:format:label"`. - * For example, the above "name" column can also be specified as: `"name:text:Name"`. - * Both "format" and "label" are optional. They will take default values if absent. - */ - public $columns = []; - public $emptyCell = ' '; - /** - * @var \yii\base\Model the model that keeps the user-entered filter data. When this property is set, - * the grid view will enable column-based filtering. Each data column by default will display a text field - * at the top that users can fill in to filter the data. - * - * Note that in order to show an input field for filtering, a column must have its [[DataColumn::attribute]] - * property set or have [[DataColumn::filter]] set as the HTML code for the input field. - * - * When this property is not set (null) the filtering feature is disabled. - */ - public $filterModel; - /** - * @var string|array the URL for returning the filtering result. [[Html::url()]] will be called to - * normalize the URL. If not set, the current controller action will be used. - * When the user makes change to any filter input, the current filtering inputs will be appended - * as GET parameters to this URL. - */ - public $filterUrl; - public $filterSelector; - /** - * @var string whether the filters should be displayed in the grid view. Valid values include: - * - * - [[FILTER_POS_HEADER]]: the filters will be displayed on top of each column's header cell. - * - [[FILTER_POS_BODY]]: the filters will be displayed right below each column's header cell. - * - [[FILTER_POS_FOOTER]]: the filters will be displayed below each column's footer cell. - */ - public $filterPosition = self::FILTER_POS_BODY; - /** - * @var array the HTML attributes for the filter row element - */ - public $filterRowOptions = ['class' => 'filters']; - - /** - * Initializes the grid view. - * This method will initialize required property values and instantiate [[columns]] objects. - */ - public function init() - { - parent::init(); - if ($this->formatter == null) { - $this->formatter = Yii::$app->getFormatter(); - } elseif (is_array($this->formatter)) { - $this->formatter = Yii::createObject($this->formatter); - } - if (!$this->formatter instanceof Formatter) { - throw new InvalidConfigException('The "formatter" property must be either a Format object or a configuration array.'); - } - if (!isset($this->options['id'])) { - $this->options['id'] = $this->getId(); - } - if (!isset($this->filterRowOptions['id'])) { - $this->filterRowOptions['id'] = $this->options['id'] . '-filters'; - } - - $this->initColumns(); - } - - /** - * Runs the widget. - */ - public function run() - { - $id = $this->options['id']; - $options = Json::encode($this->getClientOptions()); - $view = $this->getView(); - GridViewAsset::register($view); - $view->registerJs("jQuery('#$id').yiiGridView($options);"); - parent::run(); - } - - - /** - * Returns the options for the grid view JS widget. - * @return array the options - */ - protected function getClientOptions() - { - $filterUrl = isset($this->filterUrl) ? $this->filterUrl : [Yii::$app->controller->action->id]; - $id = $this->filterRowOptions['id']; - $filterSelector = "#$id input, #$id select"; - if (isset($this->filterSelector)) { - $filterSelector .= ', ' . $this->filterSelector; - } - - return [ - 'filterUrl' => Html::url($filterUrl), - 'filterSelector' => $filterSelector, - ]; - } - - /** - * Renders the data models for the grid view. - */ - public function renderItems() - { - $content = array_filter([ - $this->renderCaption(), - $this->renderColumnGroup(), - $this->showHeader ? $this->renderTableHeader() : false, - $this->showFooter ? $this->renderTableFooter() : false, - $this->renderTableBody(), - ]); - return Html::tag('table', implode("\n", $content), $this->tableOptions); - } - - public function renderCaption() - { - if (!empty($this->caption)) { - return Html::tag('caption', $this->caption, $this->captionOptions); - } else { - return false; - } - } - - public function renderColumnGroup() - { - $requireColumnGroup = false; - foreach ($this->columns as $column) { - /** @var Column $column */ - if (!empty($column->options)) { - $requireColumnGroup = true; - break; - } - } - if ($requireColumnGroup) { - $cols = []; - foreach ($this->columns as $column) { - $cols[] = Html::tag('col', '', $column->options); - } - return Html::tag('colgroup', implode("\n", $cols)); - } else { - return false; - } - } - - /** - * Renders the table header. - * @return string the rendering result - */ - public function renderTableHeader() - { - $cells = []; - foreach ($this->columns as $column) { - /** @var Column $column */ - $cells[] = $column->renderHeaderCell(); - } - $content = implode('', $cells); - if ($this->filterPosition == self::FILTER_POS_HEADER) { - $content = $this->renderFilters() . $content; - } elseif ($this->filterPosition == self::FILTER_POS_BODY) { - $content .= $this->renderFilters(); - } - return "\n" . Html::tag('tr', $content, $this->headerRowOptions) . "\n"; - } - - /** - * Renders the table footer. - * @return string the rendering result - */ - public function renderTableFooter() - { - $cells = []; - foreach ($this->columns as $column) { - /** @var Column $column */ - $cells[] = $column->renderFooterCell(); - } - $content = implode('', $cells); - if ($this->filterPosition == self::FILTER_POS_FOOTER) { - $content .= $this->renderFilters(); - } - return "\n" . Html::tag('tr', $content, $this->footerRowOptions) . "\n"; - } - - /** - * Renders the filter. - */ - public function renderFilters() - { - if ($this->filterModel !== null) { - $cells = []; - foreach ($this->columns as $column) { - /** @var Column $column */ - $cells[] = $column->renderFilterCell(); - } - return Html::tag('tr', implode('', $cells), $this->filterRowOptions); - } else { - return ''; - } - } - - /** - * Renders the table body. - * @return string the rendering result - */ - public function renderTableBody() - { - $models = array_values($this->dataProvider->getModels()); - $keys = $this->dataProvider->getKeys(); - $rows = []; - foreach ($models as $index => $model) { - $key = $keys[$index]; - if ($this->beforeRow !== null) { - $row = call_user_func($this->beforeRow, $model, $key, $index, $this); - if (!empty($row)) { - $rows[] = $row; - } - } - - $rows[] = $this->renderTableRow($model, $key, $index); - - if ($this->afterRow !== null) { - $row = call_user_func($this->afterRow, $model, $key, $index, $this); - if (!empty($row)) { - $rows[] = $row; - } - } - } - - if (empty($rows)) { - $colspan = count($this->columns); - return "\n" . $this->renderEmpty() . "\n"; - } else { - return "\n" . implode("\n", $rows) . "\n"; - } - } - - /** - * Renders a table row with the given data model and key. - * @param mixed $model the data model to be rendered - * @param mixed $key the key associated with the data model - * @param integer $index the zero-based index of the data model among the model array returned by [[dataProvider]]. - * @return string the rendering result - */ - public function renderTableRow($model, $key, $index) - { - $cells = []; - /** @var Column $column */ - foreach ($this->columns as $column) { - $cells[] = $column->renderDataCell($model, $key, $index); - } - if ($this->rowOptions instanceof Closure) { - $options = call_user_func($this->rowOptions, $model, $key, $index, $this); - } else { - $options = $this->rowOptions; - } - $options['data-key'] = is_array($key) ? json_encode($key) : $key; - return Html::tag('tr', implode('', $cells), $options); - } - - /** - * Creates column objects and initializes them. - */ - protected function initColumns() - { - if (empty($this->columns)) { - $this->guessColumns(); - } - foreach ($this->columns as $i => $column) { - if (is_string($column)) { - $column = $this->createDataColumn($column); - } else { - $column = Yii::createObject(array_merge([ - 'class' => $this->dataColumnClass ?: DataColumn::className(), - 'grid' => $this, - ], $column)); - } - if (!$column->visible) { - unset($this->columns[$i]); - continue; - } - $this->columns[$i] = $column; - } - } - - /** - * Creates a [[DataColumn]] object based on a string in the format of "attribute:format:label". - * @param string $text the column specification string - * @return DataColumn the column instance - * @throws InvalidConfigException if the column specification is invalid - */ - protected function createDataColumn($text) - { - if (!preg_match('/^([\w\.]+)(:(\w*))?(:(.*))?$/', $text, $matches)) { - throw new InvalidConfigException('The column must be specified in the format of "attribute", "attribute:format" or "attribute:format:label'); - } - return Yii::createObject([ - 'class' => $this->dataColumnClass ?: DataColumn::className(), - 'grid' => $this, - 'attribute' => $matches[1], - 'format' => isset($matches[3]) ? $matches[3] : 'text', - 'label' => isset($matches[5]) ? $matches[5] : null, - ]); - } - - protected function guessColumns() - { - $models = $this->dataProvider->getModels(); - $model = reset($models); - if (is_array($model) || is_object($model)) { - foreach ($model as $name => $value) { - $this->columns[] = $name; - } - } else { - throw new InvalidConfigException('Unable to generate columns from data.'); - } - } -} diff --git a/framework/yii/grid/GridViewAsset.php b/framework/yii/grid/GridViewAsset.php deleted file mode 100644 index a67999d..0000000 --- a/framework/yii/grid/GridViewAsset.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @since 2.0 - */ -class GridViewAsset extends AssetBundle -{ - public $sourcePath = '@yii/assets'; - public $js = [ - 'yii.gridView.js', - ]; - public $depends = [ - 'yii\web\YiiAsset', - ]; -} diff --git a/framework/yii/grid/SerialColumn.php b/framework/yii/grid/SerialColumn.php deleted file mode 100644 index 8179ead..0000000 --- a/framework/yii/grid/SerialColumn.php +++ /dev/null @@ -1,32 +0,0 @@ - - * @since 2.0 - */ -class SerialColumn extends Column -{ - public $header = '#'; - - /** - * @inheritdoc - */ - protected function renderDataCellContent($model, $key, $index) - { - $pagination = $this->grid->dataProvider->getPagination(); - if ($pagination !== false) { - return $pagination->getOffset() + $index + 1; - } else { - return $index + 1; - } - } -} diff --git a/framework/yii/helpers/ArrayHelper.php b/framework/yii/helpers/ArrayHelper.php deleted file mode 100644 index 9d428f5..0000000 --- a/framework/yii/helpers/ArrayHelper.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @since 2.0 - */ -class ArrayHelper extends BaseArrayHelper -{ -} diff --git a/framework/yii/helpers/BaseArrayHelper.php b/framework/yii/helpers/BaseArrayHelper.php deleted file mode 100644 index d3ae705..0000000 --- a/framework/yii/helpers/BaseArrayHelper.php +++ /dev/null @@ -1,475 +0,0 @@ - - * @since 2.0 - */ -class BaseArrayHelper -{ - /** - * Converts an object or an array of objects into an array. - * @param object|array $object the object to be converted into an array - * @param array $properties a mapping from object class names to the properties that need to put into the resulting arrays. - * The properties specified for each class is an array of the following format: - * - * ~~~ - * [ - * 'app\models\Post' => [ - * 'id', - * 'title', - * // the key name in array result => property name - * 'createTime' => 'create_time', - * // the key name in array result => anonymous function - * 'length' => function ($post) { - * return strlen($post->content); - * }, - * ], - * ] - * ~~~ - * - * The result of `ArrayHelper::toArray($post, $properties)` could be like the following: - * - * ~~~ - * [ - * 'id' => 123, - * 'title' => 'test', - * 'createTime' => '2013-01-01 12:00AM', - * 'length' => 301, - * ] - * ~~~ - * - * @param boolean $recursive whether to recursively converts properties which are objects into arrays. - * @return array the array representation of the object - */ - public static function toArray($object, $properties = [], $recursive = true) - { - if (!empty($properties) && is_object($object)) { - $className = get_class($object); - if (!empty($properties[$className])) { - $result = []; - foreach ($properties[$className] as $key => $name) { - if (is_int($key)) { - $result[$name] = $object->$name; - } else { - $result[$key] = static::getValue($object, $name); - } - } - return $result; - } - } - if ($object instanceof Arrayable) { - $object = $object->toArray(); - if (!$recursive) { - return $object; - } - } - $result = []; - foreach ($object as $key => $value) { - if ($recursive && (is_array($value) || is_object($value))) { - $result[$key] = static::toArray($value, true); - } else { - $result[$key] = $value; - } - } - return $result; - } - - /** - * Merges two or more arrays into one recursively. - * If each array has an element with the same string key value, the latter - * will overwrite the former (different from array_merge_recursive). - * Recursive merging will be conducted if both arrays have an element of array - * type and are having the same key. - * For integer-keyed elements, the elements from the latter array will - * be appended to the former array. - * @param array $a array to be merged to - * @param array $b array to be merged from. You can specify additional - * arrays via third argument, fourth argument etc. - * @return array the merged array (the original arrays are not changed.) - */ - public static function merge($a, $b) - { - $args = func_get_args(); - $res = array_shift($args); - while (!empty($args)) { - $next = array_shift($args); - foreach ($next as $k => $v) { - if (is_integer($k)) { - isset($res[$k]) ? $res[] = $v : $res[$k] = $v; - } elseif (is_array($v) && isset($res[$k]) && is_array($res[$k])) { - $res[$k] = self::merge($res[$k], $v); - } else { - $res[$k] = $v; - } - } - } - return $res; - } - - /** - * Retrieves the value of an array element or object property with the given key or property name. - * If the key does not exist in the array or object, the default value will be returned instead. - * - * The key may be specified in a dot format to retrieve the value of a sub-array or the property - * of an embedded object. In particular, if the key is `x.y.z`, then the returned value would - * be `$array['x']['y']['z']` or `$array->x->y->z` (if `$array` is an object). If `$array['x']` - * or `$array->x` is neither an array nor an object, the default value will be returned. - * Note that if the array already has an element `x.y.z`, then its value will be returned - * instead of going through the sub-arrays. - * - * Below are some usage examples, - * - * ~~~ - * // working with array - * $username = \yii\helpers\ArrayHelper::getValue($_POST, 'username'); - * // working with object - * $username = \yii\helpers\ArrayHelper::getValue($user, 'username'); - * // working with anonymous function - * $fullName = \yii\helpers\ArrayHelper::getValue($user, function($user, $defaultValue) { - * return $user->firstName . ' ' . $user->lastName; - * }); - * // using dot format to retrieve the property of embedded object - * $street = \yii\helpers\ArrayHelper::getValue($users, 'address.street'); - * ~~~ - * - * @param array|object $array array or object to extract value from - * @param string|\Closure $key key name of the array element, or property name of the object, - * or an anonymous function returning the value. The anonymous function signature should be: - * `function($array, $defaultValue)`. - * @param mixed $default the default value to be returned if the specified key does not exist - * @return mixed the value of the element if found, default value otherwise - * @throws InvalidParamException if $array is neither an array nor an object. - */ - public static function getValue($array, $key, $default = null) - { - if ($key instanceof \Closure) { - return $key($array, $default); - } - - if (is_array($array) && array_key_exists($key, $array)) { - return $array[$key]; - } - - if (($pos = strrpos($key, '.')) !== false) { - $array = static::getValue($array, substr($key, 0, $pos), $default); - $key = substr($key, $pos + 1); - } - - if (is_object($array)) { - return $array->$key; - } elseif (is_array($array)) { - return array_key_exists($key, $array) ? $array[$key] : $default; - } else { - return $default; - } - } - - /** - * Removes an item from an array and returns the value. If the key does not exist in the array, the default value - * will be returned instead. - * - * Usage examples, - * - * ~~~ - * // $array = ['type' => 'A', 'options' => [1, 2]]; - * // working with array - * $type = \yii\helpers\ArrayHelper::remove($array, 'type'); - * // $array content - * // $array = ['options' => [1, 2]]; - * ~~~ - * - * @param array $array the array to extract value from - * @param string $key key name of the array element - * @param mixed $default the default value to be returned if the specified key does not exist - * @return mixed|null the value of the element if found, default value otherwise - */ - public static function remove(&$array, $key, $default = null) - { - if (is_array($array) && (isset($array[$key]) || array_key_exists($key, $array))) { - $value = $array[$key]; - unset($array[$key]); - return $value; - } - return $default; - } - - /** - * Indexes an array according to a specified key. - * The input array should be multidimensional or an array of objects. - * - * The key can be a key name of the sub-array, a property name of object, or an anonymous - * function which returns the key value given an array element. - * - * If a key value is null, the corresponding array element will be discarded and not put in the result. - * - * For example, - * - * ~~~ - * $array = [ - * ['id' => '123', 'data' => 'abc'], - * ['id' => '345', 'data' => 'def'], - * ]; - * $result = ArrayHelper::index($array, 'id'); - * // the result is: - * // [ - * // '123' => ['id' => '123', 'data' => 'abc'], - * // '345' => ['id' => '345', 'data' => 'def'], - * // ] - * - * // using anonymous function - * $result = ArrayHelper::index($array, function ($element) { - * return $element['id']; - * }); - * ~~~ - * - * @param array $array the array that needs to be indexed - * @param string|\Closure $key the column name or anonymous function whose result will be used to index the array - * @return array the indexed array - */ - public static function index($array, $key) - { - $result = []; - foreach ($array as $element) { - $value = static::getValue($element, $key); - $result[$value] = $element; - } - return $result; - } - - /** - * Returns the values of a specified column in an array. - * The input array should be multidimensional or an array of objects. - * - * For example, - * - * ~~~ - * $array = [ - * ['id' => '123', 'data' => 'abc'], - * ['id' => '345', 'data' => 'def'], - * ]; - * $result = ArrayHelper::getColumn($array, 'id'); - * // the result is: ['123', '345'] - * - * // using anonymous function - * $result = ArrayHelper::getColumn($array, function ($element) { - * return $element['id']; - * }); - * ~~~ - * - * @param array $array - * @param string|\Closure $name - * @param boolean $keepKeys whether to maintain the array keys. If false, the resulting array - * will be re-indexed with integers. - * @return array the list of column values - */ - public static function getColumn($array, $name, $keepKeys = true) - { - $result = []; - if ($keepKeys) { - foreach ($array as $k => $element) { - $result[$k] = static::getValue($element, $name); - } - } else { - foreach ($array as $element) { - $result[] = static::getValue($element, $name); - } - } - - return $result; - } - - /** - * Builds a map (key-value pairs) from a multidimensional array or an array of objects. - * The `$from` and `$to` parameters specify the key names or property names to set up the map. - * Optionally, one can further group the map according to a grouping field `$group`. - * - * For example, - * - * ~~~ - * $array = [ - * ['id' => '123', 'name' => 'aaa', 'class' => 'x'], - * ['id' => '124', 'name' => 'bbb', 'class' => 'x'], - * ['id' => '345', 'name' => 'ccc', 'class' => 'y'], - * ); - * - * $result = ArrayHelper::map($array, 'id', 'name'); - * // the result is: - * // [ - * // '123' => 'aaa', - * // '124' => 'bbb', - * // '345' => 'ccc', - * // ] - * - * $result = ArrayHelper::map($array, 'id', 'name', 'class'); - * // the result is: - * // [ - * // 'x' => [ - * // '123' => 'aaa', - * // '124' => 'bbb', - * // ], - * // 'y' => [ - * // '345' => 'ccc', - * // ], - * // ] - * ~~~ - * - * @param array $array - * @param string|\Closure $from - * @param string|\Closure $to - * @param string|\Closure $group - * @return array - */ - public static function map($array, $from, $to, $group = null) - { - $result = []; - foreach ($array as $element) { - $key = static::getValue($element, $from); - $value = static::getValue($element, $to); - if ($group !== null) { - $result[static::getValue($element, $group)][$key] = $value; - } else { - $result[$key] = $value; - } - } - return $result; - } - - /** - * Checks if the given array contains the specified key. - * This method enhances the `array_key_exists()` function by supporting case-insensitive - * key comparison. - * @param string $key the key to check - * @param array $array the array with keys to check - * @param boolean $caseSensitive whether the key comparison should be case-sensitive - * @return boolean whether the array contains the specified key - */ - public static function keyExists($key, $array, $caseSensitive = true) - { - if ($caseSensitive) { - return array_key_exists($key, $array); - } else { - foreach (array_keys($array) as $k) { - if (strcasecmp($key, $k) === 0) { - return true; - } - } - return false; - } - } - - /** - * Sorts an array of objects or arrays (with the same structure) by one or several keys. - * @param array $array the array to be sorted. The array will be modified after calling this method. - * @param string|\Closure|array $key the key(s) to be sorted by. This refers to a key name of the sub-array - * elements, a property name of the objects, or an anonymous function returning the values for comparison - * purpose. The anonymous function signature should be: `function($item)`. - * To sort by multiple keys, provide an array of keys here. - * @param integer|array $direction the sorting direction. It can be either `SORT_ASC` or `SORT_DESC`. - * When sorting by multiple keys with different sorting directions, use an array of sorting directions. - * @param integer|array $sortFlag the PHP sort flag. Valid values include - * `SORT_REGULAR`, `SORT_NUMERIC`, `SORT_STRING`, `SORT_LOCALE_STRING`, `SORT_NATURAL` and `SORT_FLAG_CASE`. - * Please refer to [PHP manual](http://php.net/manual/en/function.sort.php) - * for more details. When sorting by multiple keys with different sort flags, use an array of sort flags. - * @throws InvalidParamException if the $descending or $sortFlag parameters do not have - * correct number of elements as that of $key. - */ - public static function multisort(&$array, $key, $direction = SORT_ASC, $sortFlag = SORT_REGULAR) - { - $keys = is_array($key) ? $key : [$key]; - if (empty($keys) || empty($array)) { - return; - } - $n = count($keys); - if (is_scalar($direction)) { - $direction = array_fill(0, $n, $direction); - } elseif (count($direction) !== $n) { - throw new InvalidParamException('The length of $descending parameter must be the same as that of $keys.'); - } - if (is_scalar($sortFlag)) { - $sortFlag = array_fill(0, $n, $sortFlag); - } elseif (count($sortFlag) !== $n) { - throw new InvalidParamException('The length of $sortFlag parameter must be the same as that of $keys.'); - } - $args = []; - foreach ($keys as $i => $key) { - $flag = $sortFlag[$i]; - $args[] = static::getColumn($array, $key); - $args[] = $direction[$i]; - $args[] = $flag; - } - $args[] = &$array; - call_user_func_array('array_multisort', $args); - } - - /** - * Encodes special characters in an array of strings into HTML entities. - * Both the array keys and values will be encoded. - * If a value is an array, this method will also encode it recursively. - * @param array $data data to be encoded - * @param boolean $valuesOnly whether to encode array values only. If false, - * both the array keys and array values will be encoded. - * @param string $charset the charset that the data is using. If not set, - * [[\yii\base\Application::charset]] will be used. - * @return array the encoded data - * @see http://www.php.net/manual/en/function.htmlspecialchars.php - */ - public static function htmlEncode($data, $valuesOnly = true, $charset = null) - { - if ($charset === null) { - $charset = Yii::$app->charset; - } - $d = []; - foreach ($data as $key => $value) { - if (!$valuesOnly && is_string($key)) { - $key = htmlspecialchars($key, ENT_QUOTES, $charset); - } - if (is_string($value)) { - $d[$key] = htmlspecialchars($value, ENT_QUOTES, $charset); - } elseif (is_array($value)) { - $d[$key] = static::htmlEncode($value, $charset); - } - } - return $d; - } - - /** - * Decodes HTML entities into the corresponding characters in an array of strings. - * Both the array keys and values will be decoded. - * If a value is an array, this method will also decode it recursively. - * @param array $data data to be decoded - * @param boolean $valuesOnly whether to decode array values only. If false, - * both the array keys and array values will be decoded. - * @return array the decoded data - * @see http://www.php.net/manual/en/function.htmlspecialchars-decode.php - */ - public static function htmlDecode($data, $valuesOnly = true) - { - $d = []; - foreach ($data as $key => $value) { - if (!$valuesOnly && is_string($key)) { - $key = htmlspecialchars_decode($key, ENT_QUOTES); - } - if (is_string($value)) { - $d[$key] = htmlspecialchars_decode($value, ENT_QUOTES); - } elseif (is_array($value)) { - $d[$key] = static::htmlDecode($value); - } - } - return $d; - } -} diff --git a/framework/yii/helpers/BaseConsole.php b/framework/yii/helpers/BaseConsole.php deleted file mode 100644 index 307fb00..0000000 --- a/framework/yii/helpers/BaseConsole.php +++ /dev/null @@ -1,922 +0,0 @@ - - * @since 2.0 - */ -class BaseConsole -{ - const FG_BLACK = 30; - const FG_RED = 31; - const FG_GREEN = 32; - const FG_YELLOW = 33; - const FG_BLUE = 34; - const FG_PURPLE = 35; - const FG_CYAN = 36; - const FG_GREY = 37; - - const BG_BLACK = 40; - const BG_RED = 41; - const BG_GREEN = 42; - const BG_YELLOW = 43; - const BG_BLUE = 44; - const BG_PURPLE = 45; - const BG_CYAN = 46; - const BG_GREY = 47; - - const RESET = 0; - const NORMAL = 0; - const BOLD = 1; - const ITALIC = 3; - const UNDERLINE = 4; - const BLINK = 5; - const NEGATIVE = 7; - const CONCEALED = 8; - const CROSSED_OUT = 9; - const FRAMED = 51; - const ENCIRCLED = 52; - const OVERLINED = 53; - - /** - * Moves the terminal cursor up by sending ANSI control code CUU to the terminal. - * If the cursor is already at the edge of the screen, this has no effect. - * @param integer $rows number of rows the cursor should be moved up - */ - public static function moveCursorUp($rows = 1) - { - echo "\033[" . (int)$rows . 'A'; - } - - /** - * Moves the terminal cursor down by sending ANSI control code CUD to the terminal. - * If the cursor is already at the edge of the screen, this has no effect. - * @param integer $rows number of rows the cursor should be moved down - */ - public static function moveCursorDown($rows = 1) - { - echo "\033[" . (int)$rows . 'B'; - } - - /** - * Moves the terminal cursor forward by sending ANSI control code CUF to the terminal. - * If the cursor is already at the edge of the screen, this has no effect. - * @param integer $steps number of steps the cursor should be moved forward - */ - public static function moveCursorForward($steps = 1) - { - echo "\033[" . (int)$steps . 'C'; - } - - /** - * Moves the terminal cursor backward by sending ANSI control code CUB to the terminal. - * If the cursor is already at the edge of the screen, this has no effect. - * @param integer $steps number of steps the cursor should be moved backward - */ - public static function moveCursorBackward($steps = 1) - { - echo "\033[" . (int)$steps . 'D'; - } - - /** - * Moves the terminal cursor to the beginning of the next line by sending ANSI control code CNL to the terminal. - * @param integer $lines number of lines the cursor should be moved down - */ - public static function moveCursorNextLine($lines = 1) - { - echo "\033[" . (int)$lines . 'E'; - } - - /** - * Moves the terminal cursor to the beginning of the previous line by sending ANSI control code CPL to the terminal. - * @param integer $lines number of lines the cursor should be moved up - */ - public static function moveCursorPrevLine($lines = 1) - { - echo "\033[" . (int)$lines . 'F'; - } - - /** - * Moves the cursor to an absolute position given as column and row by sending ANSI control code CUP or CHA to the terminal. - * @param integer $column 1-based column number, 1 is the left edge of the screen. - * @param integer|null $row 1-based row number, 1 is the top edge of the screen. if not set, will move cursor only in current line. - */ - public static function moveCursorTo($column, $row = null) - { - if ($row === null) { - echo "\033[" . (int)$column . 'G'; - } else { - echo "\033[" . (int)$row . ';' . (int)$column . 'H'; - } - } - - /** - * Scrolls whole page up by sending ANSI control code SU to the terminal. - * New lines are added at the bottom. This is not supported by ANSI.SYS used in windows. - * @param int $lines number of lines to scroll up - */ - public static function scrollUp($lines = 1) - { - echo "\033[" . (int)$lines . "S"; - } - - /** - * Scrolls whole page down by sending ANSI control code SD to the terminal. - * New lines are added at the top. This is not supported by ANSI.SYS used in windows. - * @param int $lines number of lines to scroll down - */ - public static function scrollDown($lines = 1) - { - echo "\033[" . (int)$lines . "T"; - } - - /** - * Saves the current cursor position by sending ANSI control code SCP to the terminal. - * Position can then be restored with [[restoreCursorPosition()]]. - */ - public static function saveCursorPosition() - { - echo "\033[s"; - } - - /** - * Restores the cursor position saved with [[saveCursorPosition()]] by sending ANSI control code RCP to the terminal. - */ - public static function restoreCursorPosition() - { - echo "\033[u"; - } - - /** - * Hides the cursor by sending ANSI DECTCEM code ?25l to the terminal. - * Use [[showCursor()]] to bring it back. - * Do not forget to show cursor when your application exits. Cursor might stay hidden in terminal after exit. - */ - public static function hideCursor() - { - echo "\033[?25l"; - } - - /** - * Will show a cursor again when it has been hidden by [[hideCursor()]] by sending ANSI DECTCEM code ?25h to the terminal. - */ - public static function showCursor() - { - echo "\033[?25h"; - } - - /** - * Clears entire screen content by sending ANSI control code ED with argument 2 to the terminal. - * Cursor position will not be changed. - * **Note:** ANSI.SYS implementation used in windows will reset cursor position to upper left corner of the screen. - */ - public static function clearScreen() - { - echo "\033[2J"; - } - - /** - * Clears text from cursor to the beginning of the screen by sending ANSI control code ED with argument 1 to the terminal. - * Cursor position will not be changed. - */ - public static function clearScreenBeforeCursor() - { - echo "\033[1J"; - } - - /** - * Clears text from cursor to the end of the screen by sending ANSI control code ED with argument 0 to the terminal. - * Cursor position will not be changed. - */ - public static function clearScreenAfterCursor() - { - echo "\033[0J"; - } - - /** - * Clears the line, the cursor is currently on by sending ANSI control code EL with argument 2 to the terminal. - * Cursor position will not be changed. - */ - public static function clearLine() - { - echo "\033[2K"; - } - - /** - * Clears text from cursor position to the beginning of the line by sending ANSI control code EL with argument 1 to the terminal. - * Cursor position will not be changed. - */ - public static function clearLineBeforeCursor() - { - echo "\033[1K"; - } - - /** - * Clears text from cursor position to the end of the line by sending ANSI control code EL with argument 0 to the terminal. - * Cursor position will not be changed. - */ - public static function clearLineAfterCursor() - { - echo "\033[0K"; - } - - /** - * Returns the ANSI format code. - * - * @param array $format An array containing formatting values. - * You can pass any of the FG_*, BG_* and TEXT_* constants - * and also [[xtermFgColor]] and [[xtermBgColor]] to specify a format. - * @return string The ANSI format code according to the given formatting constants. - */ - public static function ansiFormatCode($format) - { - return "\033[" . implode(';', $format) . 'm'; - } - - /** - * Echoes an ANSI format code that affects the formatting of any text that is printed afterwards. - * - * @param array $format An array containing formatting values. - * You can pass any of the FG_*, BG_* and TEXT_* constants - * and also [[xtermFgColor]] and [[xtermBgColor]] to specify a format. - * @see ansiFormatCode() - * @see ansiFormatEnd() - */ - public static function beginAnsiFormat($format) - { - echo "\033[" . implode(';', $format) . 'm'; - } - - /** - * Resets any ANSI format set by previous method [[ansiFormatBegin()]] - * Any output after this will have default text format. - * This is equal to calling - * - * ```php - * echo Console::ansiFormatCode([Console::RESET]) - * ``` - */ - public static function endAnsiFormat() - { - echo "\033[0m"; - } - - /** - * Will return a string formatted with the given ANSI style - * - * @param string $string the string to be formatted - * @param array $format An array containing formatting values. - * You can pass any of the FG_*, BG_* and TEXT_* constants - * and also [[xtermFgColor]] and [[xtermBgColor]] to specify a format. - * @return string - */ - public static function ansiFormat($string, $format = []) - { - $code = implode(';', $format); - return "\033[0m" . ($code !== '' ? "\033[" . $code . "m" : '') . $string . "\033[0m"; - } - - /** - * Returns the ansi format code for xterm foreground color. - * You can pass the return value of this to one of the formatting methods: - * [[ansiFormat]], [[ansiFormatCode]], [[beginAnsiFormat]] - * - * @param integer $colorCode xterm color code - * @return string - * @see http://en.wikipedia.org/wiki/Talk:ANSI_escape_code#xterm-256colors - */ - public static function xtermFgColor($colorCode) - { - return '38;5;' . $colorCode; - } - - /** - * Returns the ansi format code for xterm background color. - * You can pass the return value of this to one of the formatting methods: - * [[ansiFormat]], [[ansiFormatCode]], [[beginAnsiFormat]] - * - * @param integer $colorCode xterm color code - * @return string - * @see http://en.wikipedia.org/wiki/Talk:ANSI_escape_code#xterm-256colors - */ - public static function xtermBgColor($colorCode) - { - return '48;5;' . $colorCode; - } - - /** - * Strips ANSI control codes from a string - * - * @param string $string String to strip - * @return string - */ - public static function stripAnsiFormat($string) - { - return preg_replace('/\033\[[\d;?]*\w/', '', $string); - } - - /** - * Converts an ANSI formatted string to HTML - * @param $string - * @return mixed - */ - // TODO rework/refactor according to https://github.com/yiisoft/yii2/issues/746 - public static function ansiToHtml($string) - { - $tags = 0; - return preg_replace_callback( - '/\033\[[\d;]+m/', - function ($ansi) use (&$tags) { - $styleA = []; - foreach (explode(';', $ansi) as $controlCode) { - switch ($controlCode) { - case self::FG_BLACK: - $style = ['color' => '#000000']; - break; - case self::FG_BLUE: - $style = ['color' => '#000078']; - break; - case self::FG_CYAN: - $style = ['color' => '#007878']; - break; - case self::FG_GREEN: - $style = ['color' => '#007800']; - break; - case self::FG_GREY: - $style = ['color' => '#787878']; - break; - case self::FG_PURPLE: - $style = ['color' => '#780078']; - break; - case self::FG_RED: - $style = ['color' => '#780000']; - break; - case self::FG_YELLOW: - $style = ['color' => '#787800']; - break; - case self::BG_BLACK: - $style = ['background-color' => '#000000']; - break; - case self::BG_BLUE: - $style = ['background-color' => '#000078']; - break; - case self::BG_CYAN: - $style = ['background-color' => '#007878']; - break; - case self::BG_GREEN: - $style = ['background-color' => '#007800']; - break; - case self::BG_GREY: - $style = ['background-color' => '#787878']; - break; - case self::BG_PURPLE: - $style = ['background-color' => '#780078']; - break; - case self::BG_RED: - $style = ['background-color' => '#780000']; - break; - case self::BG_YELLOW: - $style = ['background-color' => '#787800']; - break; - case self::BOLD: - $style = ['font-weight' => 'bold']; - break; - case self::ITALIC: - $style = ['font-style' => 'italic']; - break; - case self::UNDERLINE: - $style = ['text-decoration' => ['underline']]; - break; - case self::OVERLINED: - $style = ['text-decoration' => ['overline']]; - break; - case self::CROSSED_OUT: - $style = ['text-decoration' => ['line-through']]; - break; - case self::BLINK: - $style = ['text-decoration' => ['blink']]; - break; - case self::NEGATIVE: // ??? - case self::CONCEALED: - case self::ENCIRCLED: - case self::FRAMED: - // TODO allow resetting codes - break; - case 0: // ansi reset - $return = ''; - for ($n = $tags; $tags > 0; $tags--) { - $return .= ''; - } - return $return; - } - - $styleA = ArrayHelper::merge($styleA, $style); - } - $styleString[] = []; - foreach ($styleA as $name => $content) { - if ($name === 'text-decoration') { - $content = implode(' ', $content); - } - $styleString[] = $name . ':' . $content; - } - $tags++; - return ' $value) { - static::output(" $key - $value"); - } - static::output(" ? - Show help"); - goto top; - } elseif (!in_array($input, array_keys($options))) { - goto top; - } - return $input; - } - - private static $_progressStart; - private static $_progressWidth; - private static $_progressPrefix; - - /** - * Starts display of a progress bar on screen. - * - * This bar will be updated by [[updateProgress()]] and my be ended by [[endProgress()]]. - * - * The following example shows a simple usage of a progress bar: - * - * ```php - * Console::startProgress(0, 1000); - * for ($n = 1; $n <= 1000; $n++) { - * usleep(1000); - * Console::updateProgress($n, 1000); - * } - * Console::endProgress(); - * ``` - * - * Git clone like progress (showing only status information): - * ```php - * Console::startProgress(0, 1000, 'Counting objects: ', false); - * for ($n = 1; $n <= 1000; $n++) { - * usleep(1000); - * Console::updateProgress($n, 1000); - * } - * Console::endProgress("done." . PHP_EOL); - * ``` - * - * @param integer $done the number of items that are completed. - * @param integer $total the total value of items that are to be done. - * @param string $prefix an optional string to display before the progress bar. - * Default to empty string which results in no prefix to be displayed. - * @param integer|boolean $width optional width of the progressbar. This can be an integer representing - * the number of characters to display for the progress bar or a float between 0 and 1 representing the - * percentage of screen with the progress bar may take. It can also be set to false to disable the - * bar and only show progress information like percent, number of items and ETA. - * If not set, the bar will be as wide as the screen. Screen size will be detected using [[getScreenSize()]]. - * @see startProgress - * @see updateProgress - * @see endProgress - */ - public static function startProgress($done, $total, $prefix = '', $width = null) - { - self::$_progressStart = time(); - self::$_progressWidth = $width; - self::$_progressPrefix = $prefix; - - static::updateProgress($done, $total); - } - - /** - * Updates a progress bar that has been started by [[startProgress()]]. - * - * @param integer $done the number of items that are completed. - * @param integer $total the total value of items that are to be done. - * @param string $prefix an optional string to display before the progress bar. - * Defaults to null meaning the prefix specified by [[startProgress()]] will be used. - * If prefix is specified it will update the prefix that will be used by later calls. - * @see startProgress - * @see endProgress - */ - public static function updateProgress($done, $total, $prefix = null) - { - $width = self::$_progressWidth; - if ($width === false) { - $width = 0; - } else { - $screenSize = static::getScreenSize(true); - if ($screenSize === false && $width < 1) { - $width = 0; - } elseif ($width === null) { - $width = $screenSize[0]; - } elseif ($width > 0 && $width < 1) { - $width = floor($screenSize[0] * $width); - } - } - if ($prefix === null) { - $prefix = self::$_progressPrefix; - } else { - self::$_progressPrefix = $prefix; - } - $width -= mb_strlen($prefix); - - $percent = ($total == 0) ? 1 : $done / $total; - $info = sprintf("%d%% (%d/%d)", $percent * 100, $done, $total); - - if ($done > $total || $done == 0) { - $info .= ' ETA: n/a'; - } elseif ($done < $total) { - $rate = (time() - self::$_progressStart) / $done; - $info .= sprintf(' ETA: %d sec.', $rate * ($total - $done)); - } - - $width -= 3 + mb_strlen($info); - // skipping progress bar on very small display or if forced to skip - if ($width < 5) { - static::stdout("\r$prefix$info "); - } else { - if ($percent < 0) { - $percent = 0; - } elseif ($percent > 1) { - $percent = 1; - } - $bar = floor($percent * $width); - $status = str_repeat("=", $bar); - if ($bar < $width) { - $status .= ">"; - $status .= str_repeat(" ", $width - $bar - 1); - } - static::stdout("\r$prefix" . "[$status] $info"); - } - flush(); - } - - /** - * Ends a progress bar that has been started by [[startProgress()]]. - * - * @param string|boolean $remove This can be `false` to leave the progress bar on screen and just print a newline. - * If set to `true`, the line of the progress bar will be cleared. This may also be a string to be displayed instead - * of the progress bar. - * @param bool $keepPrefix whether to keep the prefix that has been specified for the progressbar when progressbar - * gets removed. Defaults to true. - * @see startProgress - * @see updateProgress - */ - public static function endProgress($remove = false, $keepPrefix = true) - { - if ($remove === false) { - static::stdout(PHP_EOL); - } else { - if (static::streamSupportsAnsiColors(STDOUT)) { - static::clearLine(); - } - static::stdout("\r" . ($keepPrefix ? self::$_progressPrefix : '') . (is_string($remove) ? $remove : '')); - } - flush(); - - self::$_progressStart = null; - self::$_progressWidth = null; - self::$_progressPrefix = ''; - } -} diff --git a/framework/yii/helpers/BaseFileHelper.php b/framework/yii/helpers/BaseFileHelper.php deleted file mode 100644 index 36591ae..0000000 --- a/framework/yii/helpers/BaseFileHelper.php +++ /dev/null @@ -1,341 +0,0 @@ - - * @author Alex Makarov - * @since 2.0 - */ -class BaseFileHelper -{ - /** - * Normalizes a file/directory path. - * After normalization, the directory separators in the path will be `DIRECTORY_SEPARATOR`, - * and any trailing directory separators will be removed. For example, '/home\demo/' on Linux - * will be normalized as '/home/demo'. - * @param string $path the file/directory path to be normalized - * @param string $ds the directory separator to be used in the normalized result. Defaults to `DIRECTORY_SEPARATOR`. - * @return string the normalized file/directory path - */ - public static function normalizePath($path, $ds = DIRECTORY_SEPARATOR) - { - return rtrim(strtr($path, ['/' => $ds, '\\' => $ds]), $ds); - } - - /** - * Returns the localized version of a specified file. - * - * The searching is based on the specified language code. In particular, - * a file with the same name will be looked for under the subdirectory - * whose name is the same as the language code. For example, given the file "path/to/view.php" - * and language code "zh_CN", the localized file will be looked for as - * "path/to/zh_CN/view.php". If the file is not found, the original file - * will be returned. - * - * If the target and the source language codes are the same, - * the original file will be returned. - * - * @param string $file the original file - * @param string $language the target language that the file should be localized to. - * If not set, the value of [[\yii\base\Application::language]] will be used. - * @param string $sourceLanguage the language that the original file is in. - * If not set, the value of [[\yii\base\Application::sourceLanguage]] will be used. - * @return string the matching localized file, or the original file if the localized version is not found. - * If the target and the source language codes are the same, the original file will be returned. - */ - public static function localize($file, $language = null, $sourceLanguage = null) - { - if ($language === null) { - $language = Yii::$app->language; - } - if ($sourceLanguage === null) { - $sourceLanguage = Yii::$app->sourceLanguage; - } - if ($language === $sourceLanguage) { - return $file; - } - $desiredFile = dirname($file) . DIRECTORY_SEPARATOR . $language . DIRECTORY_SEPARATOR . basename($file); - return is_file($desiredFile) ? $desiredFile : $file; - } - - /** - * Determines the MIME type of the specified file. - * This method will first try to determine the MIME type based on - * [finfo_open](http://php.net/manual/en/function.finfo-open.php). If this doesn't work, it will - * fall back to [[getMimeTypeByExtension()]]. - * @param string $file the file name. - * @param string $magicFile name of the optional magic database file, usually something like `/path/to/magic.mime`. - * This will be passed as the second parameter to [finfo_open](http://php.net/manual/en/function.finfo-open.php). - * @param boolean $checkExtension whether to use the file extension to determine the MIME type in case - * `finfo_open()` cannot determine it. - * @return string the MIME type (e.g. `text/plain`). Null is returned if the MIME type cannot be determined. - */ - public static function getMimeType($file, $magicFile = null, $checkExtension = true) - { - if (function_exists('finfo_open')) { - $info = finfo_open(FILEINFO_MIME_TYPE, $magicFile); - if ($info) { - $result = finfo_file($info, $file); - finfo_close($info); - if ($result !== false) { - return $result; - } - } - } - - return $checkExtension ? static::getMimeTypeByExtension($file) : null; - } - - /** - * Determines the MIME type based on the extension name of the specified file. - * This method will use a local map between extension names and MIME types. - * @param string $file the file name. - * @param string $magicFile the path of the file that contains all available MIME type information. - * If this is not set, the default file aliased by `@yii/util/mimeTypes.php` will be used. - * @return string the MIME type. Null is returned if the MIME type cannot be determined. - */ - public static function getMimeTypeByExtension($file, $magicFile = null) - { - static $mimeTypes = []; - if ($magicFile === null) { - $magicFile = __DIR__ . '/mimeTypes.php'; - } - if (!isset($mimeTypes[$magicFile])) { - $mimeTypes[$magicFile] = require($magicFile); - } - if (($ext = pathinfo($file, PATHINFO_EXTENSION)) !== '') { - $ext = strtolower($ext); - if (isset($mimeTypes[$magicFile][$ext])) { - return $mimeTypes[$magicFile][$ext]; - } - } - return null; - } - - /** - * Copies a whole directory as another one. - * The files and sub-directories will also be copied over. - * @param string $src the source directory - * @param string $dst the destination directory - * @param array $options options for directory copy. Valid options are: - * - * - dirMode: integer, the permission to be set for newly copied directories. Defaults to 0775. - * - fileMode: integer, the permission to be set for newly copied files. Defaults to the current environment setting. - * - filter: callback, a PHP callback that is called for each directory or file. - * The signature of the callback should be: `function ($path)`, where `$path` refers the full path to be filtered. - * The callback can return one of the following values: - * - * * true: the directory or file will be copied (the "only" and "except" options will be ignored) - * * false: the directory or file will NOT be copied (the "only" and "except" options will be ignored) - * * null: the "only" and "except" options will determine whether the directory or file should be copied - * - * - only: array, list of patterns that the file paths should match if they want to be copied. - * A path matches a pattern if it contains the pattern string at its end. - * For example, '.php' matches all file paths ending with '.php'. - * Note, the '/' characters in a pattern matches both '/' and '\' in the paths. - * If a file path matches a pattern in both "only" and "except", it will NOT be copied. - * - except: array, list of patterns that the files or directories should match if they want to be excluded from being copied. - * A path matches a pattern if it contains the pattern string at its end. - * Patterns ending with '/' apply to directory paths only, and patterns not ending with '/' - * apply to file paths only. For example, '/a/b' matches all file paths ending with '/a/b'; - * and '.svn/' matches directory paths ending with '.svn'. Note, the '/' characters in a pattern matches - * both '/' and '\' in the paths. - * - recursive: boolean, whether the files under the subdirectories should also be copied. Defaults to true. - * - beforeCopy: callback, a PHP callback that is called before copying each sub-directory or file. - * If the callback returns false, the copy operation for the sub-directory or file will be cancelled. - * The signature of the callback should be: `function ($from, $to)`, where `$from` is the sub-directory or - * file to be copied from, while `$to` is the copy target. - * - afterCopy: callback, a PHP callback that is called after each sub-directory or file is successfully copied. - * The signature of the callback should be: `function ($from, $to)`, where `$from` is the sub-directory or - * file copied from, while `$to` is the copy target. - */ - public static function copyDirectory($src, $dst, $options = []) - { - if (!is_dir($dst)) { - static::createDirectory($dst, isset($options['dirMode']) ? $options['dirMode'] : 0775, true); - } - - $handle = opendir($src); - while (($file = readdir($handle)) !== false) { - if ($file === '.' || $file === '..') { - continue; - } - $from = $src . DIRECTORY_SEPARATOR . $file; - $to = $dst . DIRECTORY_SEPARATOR . $file; - if (static::filterPath($from, $options)) { - if (isset($options['beforeCopy']) && !call_user_func($options['beforeCopy'], $from, $to)) { - continue; - } - if (is_file($from)) { - copy($from, $to); - if (isset($options['fileMode'])) { - @chmod($to, $options['fileMode']); - } - } else { - static::copyDirectory($from, $to, $options); - } - if (isset($options['afterCopy'])) { - call_user_func($options['afterCopy'], $from, $to); - } - } - } - closedir($handle); - } - - /** - * Removes a directory (and all its content) recursively. - * @param string $dir the directory to be deleted recursively. - */ - public static function removeDirectory($dir) - { - if (!is_dir($dir) || !($handle = opendir($dir))) { - return; - } - while (($file = readdir($handle)) !== false) { - if ($file === '.' || $file === '..') { - continue; - } - $path = $dir . DIRECTORY_SEPARATOR . $file; - if (is_file($path)) { - unlink($path); - } else { - static::removeDirectory($path); - } - } - closedir($handle); - rmdir($dir); - } - - /** - * Returns the files found under the specified directory and subdirectories. - * @param string $dir the directory under which the files will be looked for. - * @param array $options options for file searching. Valid options are: - * - * - filter: callback, a PHP callback that is called for each directory or file. - * The signature of the callback should be: `function ($path)`, where `$path` refers the full path to be filtered. - * The callback can return one of the following values: - * - * * true: the directory or file will be returned (the "only" and "except" options will be ignored) - * * false: the directory or file will NOT be returned (the "only" and "except" options will be ignored) - * * null: the "only" and "except" options will determine whether the directory or file should be returned - * - * - only: array, list of patterns that the file paths should match if they want to be returned. - * A path matches a pattern if it contains the pattern string at its end. - * For example, '.php' matches all file paths ending with '.php'. - * Note, the '/' characters in a pattern matches both '/' and '\' in the paths. - * If a file path matches a pattern in both "only" and "except", it will NOT be returned. - * - except: array, list of patterns that the file paths or directory paths should match if they want to be excluded from the result. - * A path matches a pattern if it contains the pattern string at its end. - * Patterns ending with '/' apply to directory paths only, and patterns not ending with '/' - * apply to file paths only. For example, '/a/b' matches all file paths ending with '/a/b'; - * and '.svn/' matches directory paths ending with '.svn'. Note, the '/' characters in a pattern matches - * both '/' and '\' in the paths. - * - recursive: boolean, whether the files under the subdirectories should also be looked for. Defaults to true. - * @return array files found under the directory. The file list is sorted. - */ - public static function findFiles($dir, $options = []) - { - $list = []; - $handle = opendir($dir); - while (($file = readdir($handle)) !== false) { - if ($file === '.' || $file === '..') { - continue; - } - $path = $dir . DIRECTORY_SEPARATOR . $file; - if (static::filterPath($path, $options)) { - if (is_file($path)) { - $list[] = $path; - } elseif (!isset($options['recursive']) || $options['recursive']) { - $list = array_merge($list, static::findFiles($path, $options)); - } - } - } - closedir($handle); - return $list; - } - - /** - * Checks if the given file path satisfies the filtering options. - * @param string $path the path of the file or directory to be checked - * @param array $options the filtering options. See [[findFiles()]] for explanations of - * the supported options. - * @return boolean whether the file or directory satisfies the filtering options. - */ - public static function filterPath($path, $options) - { - if (isset($options['filter'])) { - $result = call_user_func($options['filter'], $path); - if (is_bool($result)) { - return $result; - } - } - - if (empty($options['except']) && empty($options['only'])) { - return true; - } - - $path = str_replace('\\', '/', $path); - if ($isDir = is_dir($path)) { - $path .= '/'; - } - $n = StringHelper::byteLength($path); - - if (!empty($options['except'])) { - foreach ($options['except'] as $name) { - if (StringHelper::byteSubstr($path, -StringHelper::byteLength($name), $n) === $name) { - return false; - } - } - } - - if (!$isDir && !empty($options['only'])) { - foreach ($options['only'] as $name) { - if (StringHelper::byteSubstr($path, -StringHelper::byteLength($name), $n) === $name) { - return true; - } - } - return false; - } - return true; - } - - /** - * Creates a new directory. - * - * This method is similar to the PHP `mkdir()` function except that - * it uses `chmod()` to set the permission of the created directory - * in order to avoid the impact of the `umask` setting. - * - * @param string $path path of the directory to be created. - * @param integer $mode the permission to be set for the created directory. - * @param boolean $recursive whether to create parent directories if they do not exist. - * @return boolean whether the directory is created successfully - */ - public static function createDirectory($path, $mode = 0775, $recursive = true) - { - if (is_dir($path)) { - return true; - } - $parentDir = dirname($path); - if ($recursive && !is_dir($parentDir)) { - static::createDirectory($parentDir, $mode, true); - } - $result = mkdir($path, $mode); - chmod($path, $mode); - return $result; - } -} diff --git a/framework/yii/helpers/BaseHtml.php b/framework/yii/helpers/BaseHtml.php deleted file mode 100644 index a3d7d71..0000000 --- a/framework/yii/helpers/BaseHtml.php +++ /dev/null @@ -1,1640 +0,0 @@ - - * @since 2.0 - */ -class BaseHtml -{ - /** - * @var array list of void elements (element name => 1) - * @see http://www.w3.org/TR/html-markup/syntax.html#void-element - */ - public static $voidElements = [ - 'area' => 1, - 'base' => 1, - 'br' => 1, - 'col' => 1, - 'command' => 1, - 'embed' => 1, - 'hr' => 1, - 'img' => 1, - 'input' => 1, - 'keygen' => 1, - 'link' => 1, - 'meta' => 1, - 'param' => 1, - 'source' => 1, - 'track' => 1, - 'wbr' => 1, - ]; - /** - * @var array the preferred order of attributes in a tag. This mainly affects the order of the attributes - * that are rendered by [[renderTagAttributes()]]. - */ - public static $attributeOrder = [ - 'type', - 'id', - 'class', - 'name', - 'value', - - 'href', - 'src', - 'action', - 'method', - - 'selected', - 'checked', - 'readonly', - 'disabled', - 'multiple', - - 'size', - 'maxlength', - 'width', - 'height', - 'rows', - 'cols', - - 'alt', - 'title', - 'rel', - 'media', - ]; - - /** - * Encodes special characters into HTML entities. - * The [[yii\base\Application::charset|application charset]] will be used for encoding. - * @param string $content the content to be encoded - * @param boolean $doubleEncode whether to encode HTML entities in `$content`. If false, - * HTML entities in `$content` will not be further encoded. - * @return string the encoded content - * @see decode() - * @see http://www.php.net/manual/en/function.htmlspecialchars.php - */ - public static function encode($content, $doubleEncode = true) - { - return htmlspecialchars($content, ENT_QUOTES, Yii::$app->charset, $doubleEncode); - } - - /** - * Decodes special HTML entities back to the corresponding characters. - * This is the opposite of [[encode()]]. - * @param string $content the content to be decoded - * @return string the decoded content - * @see encode() - * @see http://www.php.net/manual/en/function.htmlspecialchars-decode.php - */ - public static function decode($content) - { - return htmlspecialchars_decode($content, ENT_QUOTES); - } - - /** - * Generates a complete HTML tag. - * @param string $name the tag name - * @param string $content the content to be enclosed between the start and end tags. It will not be HTML-encoded. - * If this is coming from end users, you should consider [[encode()]] it to prevent XSS attacks. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated HTML tag - * @see beginTag() - * @see endTag() - */ - public static function tag($name, $content = '', $options = []) - { - $html = "<$name" . static::renderTagAttributes($options) . '>'; - return isset(static::$voidElements[strtolower($name)]) ? $html : "$html$content"; - } - - /** - * Generates a start tag. - * @param string $name the tag name - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated start tag - * @see endTag() - * @see tag() - */ - public static function beginTag($name, $options = []) - { - return "<$name" . static::renderTagAttributes($options) . '>'; - } - - /** - * Generates an end tag. - * @param string $name the tag name - * @return string the generated end tag - * @see beginTag() - * @see tag() - */ - public static function endTag($name) - { - return ""; - } - - /** - * Generates a style tag. - * @param string $content the style content - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * If the options does not contain "type", a "type" attribute with value "text/css" will be used. - * @return string the generated style tag - */ - public static function style($content, $options = []) - { - return static::tag('style', $content, $options); - } - - /** - * Generates a script tag. - * @param string $content the script content - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * If the options does not contain "type", a "type" attribute with value "text/javascript" will be rendered. - * @return string the generated script tag - */ - public static function script($content, $options = []) - { - return static::tag('script', $content, $options); - } - - /** - * Generates a link tag that refers to an external CSS file. - * @param array|string $url the URL of the external CSS file. This parameter will be processed by [[url()]]. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated link tag - * @see url() - */ - public static function cssFile($url, $options = []) - { - if (!isset($options['rel'])) { - $options['rel'] = 'stylesheet'; - } - $options['href'] = static::url($url); - return static::tag('link', '', $options); - } - - /** - * Generates a script tag that refers to an external JavaScript file. - * @param string $url the URL of the external JavaScript file. This parameter will be processed by [[url()]]. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated script tag - * @see url() - */ - public static function jsFile($url, $options = []) - { - $options['src'] = static::url($url); - return static::tag('script', '', $options); - } - - /** - * Generates a form start tag. - * @param array|string $action the form action URL. This parameter will be processed by [[url()]]. - * @param string $method the form submission method, such as "post", "get", "put", "delete" (case-insensitive). - * Since most browsers only support "post" and "get", if other methods are given, they will - * be simulated using "post", and a hidden input will be added which contains the actual method type. - * See [[\yii\web\Request::restVar]] for more details. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated form start tag. - * @see endForm() - */ - public static function beginForm($action = '', $method = 'post', $options = []) - { - $action = static::url($action); - - $hiddenInputs = []; - - $request = Yii::$app->getRequest(); - if ($request instanceof Request) { - if (strcasecmp($method, 'get') && strcasecmp($method, 'post')) { - // simulate PUT, DELETE, etc. via POST - $hiddenInputs[] = static::hiddenInput($request->restVar, $method); - $method = 'post'; - } - if ($request->enableCsrfValidation && !strcasecmp($method, 'post')) { - $hiddenInputs[] = static::hiddenInput($request->csrfVar, $request->getMaskedCsrfToken()); - } - } - - if (!strcasecmp($method, 'get') && ($pos = strpos($action, '?')) !== false) { - // query parameters in the action are ignored for GET method - // we use hidden fields to add them back - foreach (explode('&', substr($action, $pos + 1)) as $pair) { - if (($pos1 = strpos($pair, '=')) !== false) { - $hiddenInputs[] = static::hiddenInput( - urldecode(substr($pair, 0, $pos1)), - urldecode(substr($pair, $pos1 + 1)) - ); - } else { - $hiddenInputs[] = static::hiddenInput(urldecode($pair), ''); - } - } - $action = substr($action, 0, $pos); - } - - $options['action'] = $action; - $options['method'] = $method; - $form = static::beginTag('form', $options); - if (!empty($hiddenInputs)) { - $form .= "\n" . implode("\n", $hiddenInputs); - } - - return $form; - } - - /** - * Generates a form end tag. - * @return string the generated tag - * @see beginForm() - */ - public static function endForm() - { - return ''; - } - - /** - * Generates a hyperlink tag. - * @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code - * such as an image tag. If this is coming from end users, you should consider [[encode()]] - * it to prevent XSS attacks. - * @param array|string|null $url the URL for the hyperlink tag. This parameter will be processed by [[url()]] - * and will be used for the "href" attribute of the tag. If this parameter is null, the "href" attribute - * will not be generated. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated hyperlink - * @see url() - */ - public static function a($text, $url = null, $options = []) - { - if ($url !== null) { - $options['href'] = static::url($url); - } - return static::tag('a', $text, $options); - } - - /** - * Generates a mailto hyperlink. - * @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code - * such as an image tag. If this is coming from end users, you should consider [[encode()]] - * it to prevent XSS attacks. - * @param string $email email address. If this is null, the first parameter (link body) will be treated - * as the email address and used. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated mailto link - */ - public static function mailto($text, $email = null, $options = []) - { - $options['href'] = 'mailto:' . ($email === null ? $text : $email); - return static::tag('a', $text, $options); - } - - /** - * Generates an image tag. - * @param string $src the image URL. This parameter will be processed by [[url()]]. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated image tag - */ - public static function img($src, $options = []) - { - $options['src'] = static::url($src); - if (!isset($options['alt'])) { - $options['alt'] = ''; - } - return static::tag('img', '', $options); - } - - /** - * Generates a label tag. - * @param string $content label text. It will NOT be HTML-encoded. Therefore you can pass in HTML code - * such as an image tag. If this is is coming from end users, you should [[encode()]] - * it to prevent XSS attacks. - * @param string $for the ID of the HTML element that this label is associated with. - * If this is null, the "for" attribute will not be generated. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated label tag - */ - public static function label($content, $for = null, $options = []) - { - $options['for'] = $for; - return static::tag('label', $content, $options); - } - - /** - * Generates a button tag. - * @param string $content the content enclosed within the button tag. It will NOT be HTML-encoded. - * Therefore you can pass in HTML code such as an image tag. If this is is coming from end users, - * you should consider [[encode()]] it to prevent XSS attacks. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated button tag - */ - public static function button($content = 'Button', $options = []) - { - return static::tag('button', $content, $options); - } - - /** - * Generates a submit button tag. - * @param string $content the content enclosed within the button tag. It will NOT be HTML-encoded. - * Therefore you can pass in HTML code such as an image tag. If this is is coming from end users, - * you should consider [[encode()]] it to prevent XSS attacks. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated submit button tag - */ - public static function submitButton($content = 'Submit', $options = []) - { - $options['type'] = 'submit'; - return static::button($content, $options); - } - - /** - * Generates a reset button tag. - * @param string $content the content enclosed within the button tag. It will NOT be HTML-encoded. - * Therefore you can pass in HTML code such as an image tag. If this is is coming from end users, - * you should consider [[encode()]] it to prevent XSS attacks. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated reset button tag - */ - public static function resetButton($content = 'Reset', $options = []) - { - $options['type'] = 'reset'; - return static::button($content, $options); - } - - /** - * Generates an input type of the given type. - * @param string $type the type attribute. - * @param string $name the name attribute. If it is null, the name attribute will not be generated. - * @param string $value the value attribute. If it is null, the value attribute will not be generated. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated input tag - */ - public static function input($type, $name = null, $value = null, $options = []) - { - $options['type'] = $type; - $options['name'] = $name; - $options['value'] = $value === null ? null : (string)$value; - return static::tag('input', '', $options); - } - - /** - * Generates an input button. - * @param string $label the value attribute. If it is null, the value attribute will not be generated. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated button tag - */ - public static function buttonInput($label = 'Button', $options = []) - { - $options['type'] = 'button'; - $options['value'] = $label; - return static::tag('input', '', $options); - } - - /** - * Generates a submit input button. - * @param string $label the value attribute. If it is null, the value attribute will not be generated. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated button tag - */ - public static function submitInput($label = 'Submit', $options = []) - { - $options['type'] = 'submit'; - $options['value'] = $label; - return static::tag('input', '', $options); - } - - /** - * Generates a reset input button. - * @param string $label the value attribute. If it is null, the value attribute will not be generated. - * @param array $options the attributes of the button tag. The values will be HTML-encoded using [[encode()]]. - * Attributes whose value is null will be ignored and not put in the tag returned. - * @return string the generated button tag - */ - public static function resetInput($label = 'Reset', $options = []) - { - $options['type'] = 'reset'; - $options['value'] = $label; - return static::tag('input', '', $options); - } - - /** - * Generates a text input field. - * @param string $name the name attribute. - * @param string $value the value attribute. If it is null, the value attribute will not be generated. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated button tag - */ - public static function textInput($name, $value = null, $options = []) - { - return static::input('text', $name, $value, $options); - } - - /** - * Generates a hidden input field. - * @param string $name the name attribute. - * @param string $value the value attribute. If it is null, the value attribute will not be generated. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated button tag - */ - public static function hiddenInput($name, $value = null, $options = []) - { - return static::input('hidden', $name, $value, $options); - } - - /** - * Generates a password input field. - * @param string $name the name attribute. - * @param string $value the value attribute. If it is null, the value attribute will not be generated. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated button tag - */ - public static function passwordInput($name, $value = null, $options = []) - { - return static::input('password', $name, $value, $options); - } - - /** - * Generates a file input field. - * To use a file input field, you should set the enclosing form's "enctype" attribute to - * be "multipart/form-data". After the form is submitted, the uploaded file information - * can be obtained via $_FILES[$name] (see PHP documentation). - * @param string $name the name attribute. - * @param string $value the value attribute. If it is null, the value attribute will not be generated. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated button tag - */ - public static function fileInput($name, $value = null, $options = []) - { - return static::input('file', $name, $value, $options); - } - - /** - * Generates a text area input. - * @param string $name the input name - * @param string $value the input value. Note that it will be encoded using [[encode()]]. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * @return string the generated text area tag - */ - public static function textarea($name, $value = '', $options = []) - { - $options['name'] = $name; - return static::tag('textarea', static::encode($value), $options); - } - - /** - * Generates a radio button input. - * @param string $name the name attribute. - * @param boolean $checked whether the radio button should be checked. - * @param array $options the tag options in terms of name-value pairs. The following options are specially handled: - * - * - uncheck: string, the value associated with the uncheck state of the radio button. When this attribute - * is present, a hidden input will be generated so that if the radio button is not checked and is submitted, - * the value of this attribute will still be submitted to the server via the hidden input. - * - label: string, a label displayed next to the radio button. It will NOT be HTML-encoded. Therefore you can pass - * in HTML code such as an image tag. If this is is coming from end users, you should [[encode()]] it to prevent XSS attacks. - * When this option is specified, the radio button will be enclosed by a label tag. - * - labelOptions: array, the HTML attributes for the label tag. This is only used when the "label" option is specified. - * - container: array|boolean, the HTML attributes for the container tag. This is only used when the "label" option is specified. - * If it is false, no container will be rendered. If it is an array or not, a "div" container will be rendered - * around the the radio button. - * - * The rest of the options will be rendered as the attributes of the resulting radio button tag. The values will - * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. - * - * @return string the generated radio button tag - */ - public static function radio($name, $checked = false, $options = []) - { - $options['checked'] = (boolean)$checked; - $value = array_key_exists('value', $options) ? $options['value'] : '1'; - if (isset($options['uncheck'])) { - // add a hidden field so that if the radio button is not selected, it still submits a value - $hidden = static::hiddenInput($name, $options['uncheck']); - unset($options['uncheck']); - } else { - $hidden = ''; - } - if (isset($options['label'])) { - $label = $options['label']; - $labelOptions = isset($options['labelOptions']) ? $options['labelOptions'] : []; - $container = isset($options['container']) ? $options['container'] : ['class' => 'radio']; - unset($options['label'], $options['labelOptions'], $options['container']); - $content = static::label(static::input('radio', $name, $value, $options) . ' ' . $label, null, $labelOptions); - if (is_array($container)) { - return $hidden . static::tag('div', $content, $container); - } else { - return $hidden . $content; - } - } else { - return $hidden . static::input('radio', $name, $value, $options); - } - } - - /** - * Generates a checkbox input. - * @param string $name the name attribute. - * @param boolean $checked whether the checkbox should be checked. - * @param array $options the tag options in terms of name-value pairs. The following options are specially handled: - * - * - uncheck: string, the value associated with the uncheck state of the checkbox. When this attribute - * is present, a hidden input will be generated so that if the checkbox is not checked and is submitted, - * the value of this attribute will still be submitted to the server via the hidden input. - * - label: string, a label displayed next to the checkbox. It will NOT be HTML-encoded. Therefore you can pass - * in HTML code such as an image tag. If this is is coming from end users, you should [[encode()]] it to prevent XSS attacks. - * When this option is specified, the checkbox will be enclosed by a label tag. - * - labelOptions: array, the HTML attributes for the label tag. This is only used when the "label" option is specified. - * - container: array|boolean, the HTML attributes for the container tag. This is only used when the "label" option is specified. - * If it is false, no container will be rendered. If it is an array or not, a "div" container will be rendered - * around the the radio button. - * - * The rest of the options will be rendered as the attributes of the resulting checkbox tag. The values will - * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. - * - * @return string the generated checkbox tag - */ - public static function checkbox($name, $checked = false, $options = []) - { - $options['checked'] = (boolean)$checked; - $value = array_key_exists('value', $options) ? $options['value'] : '1'; - if (isset($options['uncheck'])) { - // add a hidden field so that if the checkbox is not selected, it still submits a value - $hidden = static::hiddenInput($name, $options['uncheck']); - unset($options['uncheck']); - } else { - $hidden = ''; - } - if (isset($options['label'])) { - $label = $options['label']; - $labelOptions = isset($options['labelOptions']) ? $options['labelOptions'] : []; - $container = isset($options['container']) ? $options['container'] : ['class' => 'checkbox']; - unset($options['label'], $options['labelOptions'], $options['container']); - $content = static::label(static::input('checkbox', $name, $value, $options) . ' ' . $label, null, $labelOptions); - if (is_array($container)) { - return $hidden . static::tag('div', $content, $container); - } else { - return $hidden . $content; - } - } else { - return $hidden . static::input('checkbox', $name, $value, $options); - } - } - - /** - * Generates a drop-down list. - * @param string $name the input name - * @param string $selection the selected value - * @param array $items the option data items. The array keys are option values, and the array values - * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too). - * For each sub-array, an option group will be generated whose label is the key associated with the sub-array. - * If you have a list of data models, you may convert them into the format described above using - * [[\yii\helpers\ArrayHelper::map()]]. - * - * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in - * the labels will also be HTML-encoded. - * @param array $options the tag options in terms of name-value pairs. The following options are specially handled: - * - * - prompt: string, a prompt text to be displayed as the first option; - * - options: array, the attributes for the select option tags. The array keys must be valid option values, - * and the array values are the extra attributes for the corresponding option tags. For example, - * - * ~~~ - * [ - * 'value1' => ['disabled' => true], - * 'value2' => ['label' => 'value 2'], - * ]; - * ~~~ - * - * - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options', - * except that the array keys represent the optgroup labels specified in $items. - * - * The rest of the options will be rendered as the attributes of the resulting tag. The values will - * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. - * - * @return string the generated drop-down list tag - */ - public static function dropDownList($name, $selection = null, $items = [], $options = []) - { - if (!empty($options['multiple'])) { - return static::listBox($name, $selection, $items, $options); - } - $options['name'] = $name; - $selectOptions = static::renderSelectOptions($selection, $items, $options); - return static::tag('select', "\n" . $selectOptions . "\n", $options); - } - - /** - * Generates a list box. - * @param string $name the input name - * @param string|array $selection the selected value(s) - * @param array $items the option data items. The array keys are option values, and the array values - * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too). - * For each sub-array, an option group will be generated whose label is the key associated with the sub-array. - * If you have a list of data models, you may convert them into the format described above using - * [[\yii\helpers\ArrayHelper::map()]]. - * - * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in - * the labels will also be HTML-encoded. - * @param array $options the tag options in terms of name-value pairs. The following options are specially handled: - * - * - prompt: string, a prompt text to be displayed as the first option; - * - options: array, the attributes for the select option tags. The array keys must be valid option values, - * and the array values are the extra attributes for the corresponding option tags. For example, - * - * ~~~ - * [ - * 'value1' => ['disabled' => true], - * 'value2' => ['label' => 'value 2'], - * ]; - * ~~~ - * - * - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options', - * except that the array keys represent the optgroup labels specified in $items. - * - unselect: string, the value that will be submitted when no option is selected. - * When this attribute is set, a hidden field will be generated so that if no option is selected in multiple - * mode, we can still obtain the posted unselect value. - * - * The rest of the options will be rendered as the attributes of the resulting tag. The values will - * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. - * - * @return string the generated list box tag - */ - public static function listBox($name, $selection = null, $items = [], $options = []) - { - if (!isset($options['size'])) { - $options['size'] = 4; - } - if (!empty($options['multiple']) && substr($name, -2) !== '[]') { - $name .= '[]'; - } - $options['name'] = $name; - if (isset($options['unselect'])) { - // add a hidden field so that if the list box has no option being selected, it still submits a value - if (substr($name, -2) === '[]') { - $name = substr($name, 0, -2); - } - $hidden = static::hiddenInput($name, $options['unselect']); - unset($options['unselect']); - } else { - $hidden = ''; - } - $selectOptions = static::renderSelectOptions($selection, $items, $options); - return $hidden . static::tag('select', "\n" . $selectOptions . "\n", $options); - } - - /** - * Generates a list of checkboxes. - * A checkbox list allows multiple selection, like [[listBox()]]. - * As a result, the corresponding submitted value is an array. - * @param string $name the name attribute of each checkbox. - * @param string|array $selection the selected value(s). - * @param array $items the data item used to generate the checkboxes. - * The array values are the labels, while the array keys are the corresponding checkbox values. - * @param array $options options (name => config) for the checkbox list container tag. - * The following options are specially handled: - * - * - tag: string, the tag name of the container element. - * - unselect: string, the value that should be submitted when none of the checkboxes is selected. - * By setting this option, a hidden input will be generated. - * - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true. - * This option is ignored if `item` option is set. - * - separator: string, the HTML code that separates items. - * - itemOptions: array, the options for generating the radio button tag using [[checkbox()]]. - * - item: callable, a callback that can be used to customize the generation of the HTML code - * corresponding to a single item in $items. The signature of this callback must be: - * - * ~~~ - * function ($index, $label, $name, $checked, $value) - * ~~~ - * - * where $index is the zero-based index of the checkbox in the whole list; $label - * is the label for the checkbox; and $name, $value and $checked represent the name, - * value and the checked status of the checkbox input, respectively. - * @return string the generated checkbox list - */ - public static function checkboxList($name, $selection = null, $items = [], $options = []) - { - if (substr($name, -2) !== '[]') { - $name .= '[]'; - } - - $formatter = isset($options['item']) ? $options['item'] : null; - $itemOptions = isset($options['itemOptions']) ? $options['itemOptions'] : []; - $encode = !isset($options['encode']) || $options['encode']; - $lines = []; - $index = 0; - foreach ($items as $value => $label) { - $checked = $selection !== null && - (!is_array($selection) && !strcmp($value, $selection) - || is_array($selection) && in_array($value, $selection)); - if ($formatter !== null) { - $lines[] = call_user_func($formatter, $index, $label, $name, $checked, $value); - } else { - $lines[] = static::checkbox($name, $checked, array_merge($itemOptions, [ - 'value' => $value, - 'label' => $encode ? static::encode($label) : $label, - ])); - } - $index++; - } - - if (isset($options['unselect'])) { - // add a hidden field so that if the list box has no option being selected, it still submits a value - $name2 = substr($name, -2) === '[]' ? substr($name, 0, -2) : $name; - $hidden = static::hiddenInput($name2, $options['unselect']); - } else { - $hidden = ''; - } - $separator = isset($options['separator']) ? $options['separator'] : "\n"; - - $tag = isset($options['tag']) ? $options['tag'] : 'div'; - unset($options['tag'], $options['unselect'], $options['encode'], $options['separator'], $options['item'], $options['itemOptions']); - - return $hidden . static::tag($tag, implode($separator, $lines), $options); - } - - /** - * Generates a list of radio buttons. - * A radio button list is like a checkbox list, except that it only allows single selection. - * @param string $name the name attribute of each radio button. - * @param string|array $selection the selected value(s). - * @param array $items the data item used to generate the radio buttons. - * The array values are the labels, while the array keys are the corresponding radio button values. - * @param array $options options (name => config) for the radio button list. The following options are supported: - * - * - unselect: string, the value that should be submitted when none of the radio buttons is selected. - * By setting this option, a hidden input will be generated. - * - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true. - * This option is ignored if `item` option is set. - * - separator: string, the HTML code that separates items. - * - itemOptions: array, the options for generating the radio button tag using [[radio()]]. - * - item: callable, a callback that can be used to customize the generation of the HTML code - * corresponding to a single item in $items. The signature of this callback must be: - * - * ~~~ - * function ($index, $label, $name, $checked, $value) - * ~~~ - * - * where $index is the zero-based index of the radio button in the whole list; $label - * is the label for the radio button; and $name, $value and $checked represent the name, - * value and the checked status of the radio button input, respectively. - * @return string the generated radio button list - */ - public static function radioList($name, $selection = null, $items = [], $options = []) - { - $encode = !isset($options['encode']) || $options['encode']; - $formatter = isset($options['item']) ? $options['item'] : null; - $itemOptions = isset($options['itemOptions']) ? $options['itemOptions'] : []; - $lines = []; - $index = 0; - foreach ($items as $value => $label) { - $checked = $selection !== null && - (!is_array($selection) && !strcmp($value, $selection) - || is_array($selection) && in_array($value, $selection)); - if ($formatter !== null) { - $lines[] = call_user_func($formatter, $index, $label, $name, $checked, $value); - } else { - $lines[] = static::radio($name, $checked, array_merge($itemOptions, [ - 'value' => $value, - 'label' => $encode ? static::encode($label) : $label, - ])); - } - $index++; - } - - $separator = isset($options['separator']) ? $options['separator'] : "\n"; - if (isset($options['unselect'])) { - // add a hidden field so that if the list box has no option being selected, it still submits a value - $hidden = static::hiddenInput($name, $options['unselect']); - } else { - $hidden = ''; - } - - $tag = isset($options['tag']) ? $options['tag'] : 'div'; - unset($options['tag'], $options['unselect'], $options['encode'], $options['separator'], $options['item'], $options['itemOptions']); - - return $hidden . static::tag($tag, implode($separator, $lines), $options); - } - - /** - * Generates an unordered list. - * @param array|\Traversable $items the items for generating the list. Each item generates a single list item. - * Note that items will be automatically HTML encoded if `$options['encode']` is not set or true. - * @param array $options options (name => config) for the radio button list. The following options are supported: - * - * - encode: boolean, whether to HTML-encode the items. Defaults to true. - * This option is ignored if the `item` option is specified. - * - itemOptions: array, the HTML attributes for the `li` tags. This option is ignored if the `item` option is specified. - * - item: callable, a callback that is used to generate each individual list item. - * The signature of this callback must be: - * - * ~~~ - * function ($item, $index) - * ~~~ - * - * where $index is the array key corresponding to `$item` in `$items`. The callback should return - * the whole list item tag. - * - * @return string the generated unordered list. An empty string is returned if `$items` is empty. - */ - public static function ul($items, $options = []) - { - if (empty($items)) { - return ''; - } - $tag = isset($options['tag']) ? $options['tag'] : 'ul'; - $encode = !isset($options['encode']) || $options['encode']; - $formatter = isset($options['item']) ? $options['item'] : null; - $itemOptions = isset($options['itemOptions']) ? $options['itemOptions'] : []; - unset($options['tag'], $options['encode'], $options['item'], $options['itemOptions']); - $results = []; - foreach ($items as $index => $item) { - if ($formatter !== null) { - $results[] = call_user_func($formatter, $item, $index); - } else { - $results[] = static::tag('li', $encode ? static::encode($item) : $item, $itemOptions); - } - } - return static::tag($tag, "\n" . implode("\n", $results) . "\n", $options); - } - - /** - * Generates an ordered list. - * @param array|\Traversable $items the items for generating the list. Each item generates a single list item. - * Note that items will be automatically HTML encoded if `$options['encode']` is not set or true. - * @param array $options options (name => config) for the radio button list. The following options are supported: - * - * - encode: boolean, whether to HTML-encode the items. Defaults to true. - * This option is ignored if the `item` option is specified. - * - itemOptions: array, the HTML attributes for the `li` tags. This option is ignored if the `item` option is specified. - * - item: callable, a callback that is used to generate each individual list item. - * The signature of this callback must be: - * - * ~~~ - * function ($item, $index) - * ~~~ - * - * where $index is the array key corresponding to `$item` in `$items`. The callback should return - * the whole list item tag. - * - * @return string the generated ordered list. An empty string is returned if `$items` is empty. - */ - public static function ol($items, $options = []) - { - $options['tag'] = 'ol'; - return static::ul($items, $options); - } - - /** - * Generates a label tag for the given model attribute. - * The label text is the label associated with the attribute, obtained via [[Model::getAttributeLabel()]]. - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format - * about attribute expression. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * The following options are specially handled: - * - * - label: this specifies the label to be displayed. Note that this will NOT be [[encoded()]]. - * If this is not set, [[Model::getAttributeLabel()]] will be called to get the label for display - * (after encoding). - * - * @return string the generated label tag - */ - public static function activeLabel($model, $attribute, $options = []) - { - $for = array_key_exists('for', $options) ? $options['for'] : static::getInputId($model, $attribute); - $attribute = static::getAttributeName($attribute); - $label = isset($options['label']) ? $options['label'] : static::encode($model->getAttributeLabel($attribute)); - unset($options['label'], $options['for']); - return static::label($label, $for, $options); - } - - /** - * Generates a tag that contains the first validation error of the specified model attribute. - * Note that even if there is no validation error, this method will still return an empty error tag. - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format - * about attribute expression. - * @param array $options the tag options in terms of name-value pairs. The values will be HTML-encoded - * using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. - * - * The following options are specially handled: - * - * - tag: this specifies the tag name. If not set, "div" will be used. - * - * @return string the generated label tag - */ - public static function error($model, $attribute, $options = []) - { - $attribute = static::getAttributeName($attribute); - $error = $model->getFirstError($attribute); - $tag = isset($options['tag']) ? $options['tag'] : 'div'; - unset($options['tag']); - return Html::tag($tag, Html::encode($error), $options); - } - - /** - * Generates an input tag for the given model attribute. - * This method will generate the "name" and "value" tag attributes automatically for the model attribute - * unless they are explicitly specified in `$options`. - * @param string $type the input type (e.g. 'text', 'password') - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format - * about attribute expression. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * @return string the generated input tag - */ - public static function activeInput($type, $model, $attribute, $options = []) - { - $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute); - $value = isset($options['value']) ? $options['value'] : static::getAttributeValue($model, $attribute); - if (!array_key_exists('id', $options)) { - $options['id'] = static::getInputId($model, $attribute); - } - return static::input($type, $name, $value, $options); - } - - /** - * Generates a text input tag for the given model attribute. - * This method will generate the "name" and "value" tag attributes automatically for the model attribute - * unless they are explicitly specified in `$options`. - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format - * about attribute expression. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * @return string the generated input tag - */ - public static function activeTextInput($model, $attribute, $options = []) - { - return static::activeInput('text', $model, $attribute, $options); - } - - /** - * Generates a hidden input tag for the given model attribute. - * This method will generate the "name" and "value" tag attributes automatically for the model attribute - * unless they are explicitly specified in `$options`. - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format - * about attribute expression. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * @return string the generated input tag - */ - public static function activeHiddenInput($model, $attribute, $options = []) - { - return static::activeInput('hidden', $model, $attribute, $options); - } - - /** - * Generates a password input tag for the given model attribute. - * This method will generate the "name" and "value" tag attributes automatically for the model attribute - * unless they are explicitly specified in `$options`. - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format - * about attribute expression. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * @return string the generated input tag - */ - public static function activePasswordInput($model, $attribute, $options = []) - { - return static::activeInput('password', $model, $attribute, $options); - } - - /** - * Generates a file input tag for the given model attribute. - * This method will generate the "name" and "value" tag attributes automatically for the model attribute - * unless they are explicitly specified in `$options`. - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format - * about attribute expression. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * @return string the generated input tag - */ - public static function activeFileInput($model, $attribute, $options = []) - { - // add a hidden field so that if a model only has a file field, we can - // still use isset($_POST[$modelClass]) to detect if the input is submitted - return static::activeHiddenInput($model, $attribute, ['id' => null, 'value' => '']) - . static::activeInput('file', $model, $attribute, $options); - } - - /** - * Generates a textarea tag for the given model attribute. - * The model attribute value will be used as the content in the textarea. - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format - * about attribute expression. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]]. - * @return string the generated textarea tag - */ - public static function activeTextarea($model, $attribute, $options = []) - { - $name = static::getInputName($model, $attribute); - $value = static::getAttributeValue($model, $attribute); - if (!array_key_exists('id', $options)) { - $options['id'] = static::getInputId($model, $attribute); - } - return static::textarea($name, $value, $options); - } - - /** - * Generates a radio button tag for the given model attribute. - * This method will generate the "checked" tag attribute according to the model attribute value. - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format - * about attribute expression. - * @param array $options the tag options in terms of name-value pairs. The following options are specially handled: - * - * - uncheck: string, the value associated with the uncheck state of the radio button. If not set, - * it will take the default value '0'. This method will render a hidden input so that if the radio button - * is not checked and is submitted, the value of this attribute will still be submitted to the server - * via the hidden input. - * - label: string, a label displayed next to the radio button. It will NOT be HTML-encoded. Therefore you can pass - * in HTML code such as an image tag. If this is is coming from end users, you should [[encode()]] it to prevent XSS attacks. - * When this option is specified, the radio button will be enclosed by a label tag. - * - labelOptions: array, the HTML attributes for the label tag. This is only used when the "label" option is specified. - * - * The rest of the options will be rendered as the attributes of the resulting tag. The values will - * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. - * - * @return string the generated radio button tag - */ - public static function activeRadio($model, $attribute, $options = []) - { - $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute); - $checked = static::getAttributeValue($model, $attribute); - if (!array_key_exists('uncheck', $options)) { - $options['uncheck'] = '0'; - } - if (!array_key_exists('id', $options)) { - $options['id'] = static::getInputId($model, $attribute); - } - return static::radio($name, $checked, $options); - } - - /** - * Generates a checkbox tag for the given model attribute. - * This method will generate the "checked" tag attribute according to the model attribute value. - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format - * about attribute expression. - * @param array $options the tag options in terms of name-value pairs. The following options are specially handled: - * - * - uncheck: string, the value associated with the uncheck state of the radio button. If not set, - * it will take the default value '0'. This method will render a hidden input so that if the radio button - * is not checked and is submitted, the value of this attribute will still be submitted to the server - * via the hidden input. - * - label: string, a label displayed next to the checkbox. It will NOT be HTML-encoded. Therefore you can pass - * in HTML code such as an image tag. If this is is coming from end users, you should [[encode()]] it to prevent XSS attacks. - * When this option is specified, the checkbox will be enclosed by a label tag. - * - labelOptions: array, the HTML attributes for the label tag. This is only used when the "label" option is specified. - * - * The rest of the options will be rendered as the attributes of the resulting tag. The values will - * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. - * - * @return string the generated checkbox tag - */ - public static function activeCheckbox($model, $attribute, $options = []) - { - $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute); - $checked = static::getAttributeValue($model, $attribute); - if (!array_key_exists('uncheck', $options)) { - $options['uncheck'] = '0'; - } - if (!array_key_exists('id', $options)) { - $options['id'] = static::getInputId($model, $attribute); - } - return static::checkbox($name, $checked, $options); - } - - /** - * Generates a drop-down list for the given model attribute. - * The selection of the drop-down list is taken from the value of the model attribute. - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format - * about attribute expression. - * @param array $items the option data items. The array keys are option values, and the array values - * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too). - * For each sub-array, an option group will be generated whose label is the key associated with the sub-array. - * If you have a list of data models, you may convert them into the format described above using - * [[\yii\helpers\ArrayHelper::map()]]. - * - * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in - * the labels will also be HTML-encoded. - * @param array $options the tag options in terms of name-value pairs. The following options are specially handled: - * - * - prompt: string, a prompt text to be displayed as the first option; - * - options: array, the attributes for the select option tags. The array keys must be valid option values, - * and the array values are the extra attributes for the corresponding option tags. For example, - * - * ~~~ - * [ - * 'value1' => ['disabled' => true], - * 'value2' => ['label' => 'value 2'], - * ]; - * ~~~ - * - * - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options', - * except that the array keys represent the optgroup labels specified in $items. - * - * The rest of the options will be rendered as the attributes of the resulting tag. The values will - * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. - * - * @return string the generated drop-down list tag - */ - public static function activeDropDownList($model, $attribute, $items, $options = []) - { - $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute); - $selection = static::getAttributeValue($model, $attribute); - if (!array_key_exists('id', $options)) { - $options['id'] = static::getInputId($model, $attribute); - } - return static::dropDownList($name, $selection, $items, $options); - } - - /** - * Generates a list box. - * The selection of the list box is taken from the value of the model attribute. - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format - * about attribute expression. - * @param array $items the option data items. The array keys are option values, and the array values - * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too). - * For each sub-array, an option group will be generated whose label is the key associated with the sub-array. - * If you have a list of data models, you may convert them into the format described above using - * [[\yii\helpers\ArrayHelper::map()]]. - * - * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in - * the labels will also be HTML-encoded. - * @param array $options the tag options in terms of name-value pairs. The following options are specially handled: - * - * - prompt: string, a prompt text to be displayed as the first option; - * - options: array, the attributes for the select option tags. The array keys must be valid option values, - * and the array values are the extra attributes for the corresponding option tags. For example, - * - * ~~~ - * [ - * 'value1' => ['disabled' => true], - * 'value2' => ['label' => 'value 2'], - * ]; - * ~~~ - * - * - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options', - * except that the array keys represent the optgroup labels specified in $items. - * - unselect: string, the value that will be submitted when no option is selected. - * When this attribute is set, a hidden field will be generated so that if no option is selected in multiple - * mode, we can still obtain the posted unselect value. - * - * The rest of the options will be rendered as the attributes of the resulting tag. The values will - * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. - * - * @return string the generated list box tag - */ - public static function activeListBox($model, $attribute, $items, $options = []) - { - $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute); - $selection = static::getAttributeValue($model, $attribute); - if (!array_key_exists('unselect', $options)) { - $options['unselect'] = '0'; - } - if (!array_key_exists('id', $options)) { - $options['id'] = static::getInputId($model, $attribute); - } - return static::listBox($name, $selection, $items, $options); - } - - /** - * Generates a list of checkboxes. - * A checkbox list allows multiple selection, like [[listBox()]]. - * As a result, the corresponding submitted value is an array. - * The selection of the checkbox list is taken from the value of the model attribute. - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format - * about attribute expression. - * @param array $items the data item used to generate the checkboxes. - * The array values are the labels, while the array keys are the corresponding checkbox values. - * Note that the labels will NOT be HTML-encoded, while the values will. - * @param array $options options (name => config) for the checkbox list. The following options are specially handled: - * - * - unselect: string, the value that should be submitted when none of the checkboxes is selected. - * You may set this option to be null to prevent default value submission. - * If this option is not set, an empty string will be submitted. - * - separator: string, the HTML code that separates items. - * - item: callable, a callback that can be used to customize the generation of the HTML code - * corresponding to a single item in $items. The signature of this callback must be: - * - * ~~~ - * function ($index, $label, $name, $checked, $value) - * ~~~ - * - * where $index is the zero-based index of the checkbox in the whole list; $label - * is the label for the checkbox; and $name, $value and $checked represent the name, - * value and the checked status of the checkbox input. - * @return string the generated checkbox list - */ - public static function activeCheckboxList($model, $attribute, $items, $options = []) - { - $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute); - $selection = static::getAttributeValue($model, $attribute); - if (!array_key_exists('unselect', $options)) { - $options['unselect'] = ''; - } - if (!array_key_exists('id', $options)) { - $options['id'] = static::getInputId($model, $attribute); - } - return static::checkboxList($name, $selection, $items, $options); - } - - /** - * Generates a list of radio buttons. - * A radio button list is like a checkbox list, except that it only allows single selection. - * The selection of the radio buttons is taken from the value of the model attribute. - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format - * about attribute expression. - * @param array $items the data item used to generate the radio buttons. - * The array keys are the labels, while the array values are the corresponding radio button values. - * Note that the labels will NOT be HTML-encoded, while the values will. - * @param array $options options (name => config) for the radio button list. The following options are specially handled: - * - * - unselect: string, the value that should be submitted when none of the radio buttons is selected. - * You may set this option to be null to prevent default value submission. - * If this option is not set, an empty string will be submitted. - * - separator: string, the HTML code that separates items. - * - item: callable, a callback that can be used to customize the generation of the HTML code - * corresponding to a single item in $items. The signature of this callback must be: - * - * ~~~ - * function ($index, $label, $name, $checked, $value) - * ~~~ - * - * where $index is the zero-based index of the radio button in the whole list; $label - * is the label for the radio button; and $name, $value and $checked represent the name, - * value and the checked status of the radio button input. - * @return string the generated radio button list - */ - public static function activeRadioList($model, $attribute, $items, $options = []) - { - $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute); - $selection = static::getAttributeValue($model, $attribute); - if (!array_key_exists('unselect', $options)) { - $options['unselect'] = ''; - } - if (!array_key_exists('id', $options)) { - $options['id'] = static::getInputId($model, $attribute); - } - return static::radioList($name, $selection, $items, $options); - } - - /** - * Renders the option tags that can be used by [[dropDownList()]] and [[listBox()]]. - * @param string|array $selection the selected value(s). This can be either a string for single selection - * or an array for multiple selections. - * @param array $items the option data items. The array keys are option values, and the array values - * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too). - * For each sub-array, an option group will be generated whose label is the key associated with the sub-array. - * If you have a list of data models, you may convert them into the format described above using - * [[\yii\helpers\ArrayHelper::map()]]. - * - * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in - * the labels will also be HTML-encoded. - * @param array $tagOptions the $options parameter that is passed to the [[dropDownList()]] or [[listBox()]] call. - * This method will take out these elements, if any: "prompt", "options" and "groups". See more details - * in [[dropDownList()]] for the explanation of these elements. - * - * @return string the generated list options - */ - public static function renderSelectOptions($selection, $items, &$tagOptions = []) - { - $lines = []; - if (isset($tagOptions['prompt'])) { - $prompt = str_replace(' ', ' ', static::encode($tagOptions['prompt'])); - $lines[] = static::tag('option', $prompt, ['value' => '']); - } - - $options = isset($tagOptions['options']) ? $tagOptions['options'] : []; - $groups = isset($tagOptions['groups']) ? $tagOptions['groups'] : []; - unset($tagOptions['prompt'], $tagOptions['options'], $tagOptions['groups']); - - foreach ($items as $key => $value) { - if (is_array($value)) { - $groupAttrs = isset($groups[$key]) ? $groups[$key] : []; - $groupAttrs['label'] = $key; - $attrs = ['options' => $options, 'groups' => $groups]; - $content = static::renderSelectOptions($selection, $value, $attrs); - $lines[] = static::tag('optgroup', "\n" . $content . "\n", $groupAttrs); - } else { - $attrs = isset($options[$key]) ? $options[$key] : []; - $attrs['value'] = (string)$key; - $attrs['selected'] = $selection !== null && - (!is_array($selection) && !strcmp($key, $selection) - || is_array($selection) && in_array($key, $selection)); - $lines[] = static::tag('option', str_replace(' ', ' ', static::encode($value)), $attrs); - } - } - - return implode("\n", $lines); - } - - /** - * Renders the HTML tag attributes. - * Attributes whose values are of boolean type will be treated as - * [boolean attributes](http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes). - * And attributes whose values are null will not be rendered. - * @param array $attributes attributes to be rendered. The attribute values will be HTML-encoded using [[encode()]]. - * @return string the rendering result. If the attributes are not empty, they will be rendered - * into a string with a leading white space (so that it can be directly appended to the tag name - * in a tag. If there is no attribute, an empty string will be returned. - */ - public static function renderTagAttributes($attributes) - { - if (count($attributes) > 1) { - $sorted = []; - foreach (static::$attributeOrder as $name) { - if (isset($attributes[$name])) { - $sorted[$name] = $attributes[$name]; - } - } - $attributes = array_merge($sorted, $attributes); - } - - $html = ''; - foreach ($attributes as $name => $value) { - if (is_bool($value)) { - if ($value) { - $html .= " $name"; - } - } elseif ($value !== null) { - $html .= " $name=\"" . static::encode($value) . '"'; - } - } - return $html; - } - - /** - * Normalizes the input parameter to be a valid URL. - * - * If the input parameter - * - * - is an empty string: the currently requested URL will be returned; - * - is a non-empty string: it will first be processed by [[Yii::getAlias()]]. If the result - * is an absolute URL, it will be returned without any change further; Otherwise, the result - * will be prefixed with [[\yii\web\Request::baseUrl]] and returned. - * - is an array: the first array element is considered a route, while the rest of the name-value - * pairs are treated as the parameters to be used for URL creation using [[\yii\web\Controller::createUrl()]]. - * For example: `['post/index', 'page' => 2]`, `['index']`. - * In case there is no controller, [[\yii\web\UrlManager::createUrl()]] will be used. - * - * @param array|string $url the parameter to be used to generate a valid URL - * @return string the normalized URL - * @throws InvalidParamException if the parameter is invalid. - */ - public static function url($url) - { - if (is_array($url)) { - if (isset($url[0])) { - $route = $url[0]; - $params = array_splice($url, 1); - if (Yii::$app->controller instanceof \yii\web\Controller) { - return Yii::$app->controller->createUrl($route, $params); - } else { - return Yii::$app->getUrlManager()->createUrl($route, $params); - } - } else { - throw new InvalidParamException('The array specifying a URL must contain at least one element.'); - } - } elseif ($url === '') { - return Yii::$app->getRequest()->getUrl(); - } else { - $url = Yii::getAlias($url); - if ($url !== '' && ($url[0] === '/' || $url[0] === '#' || strpos($url, '://') || !strncmp($url, './', 2))) { - return $url; - } else { - return Yii::$app->getRequest()->getBaseUrl() . '/' . $url; - } - } - } - - /** - * Adds a CSS class to the specified options. - * If the CSS class is already in the options, it will not be added again. - * @param array $options the options to be modified. - * @param string $class the CSS class to be added - */ - public static function addCssClass(&$options, $class) - { - if (isset($options['class'])) { - $classes = ' ' . $options['class'] . ' '; - if (($pos = strpos($classes, ' ' . $class . ' ')) === false) { - $options['class'] .= ' ' . $class; - } - } else { - $options['class'] = $class; - } - } - - /** - * Removes a CSS class from the specified options. - * @param array $options the options to be modified. - * @param string $class the CSS class to be removed - */ - public static function removeCssClass(&$options, $class) - { - if (isset($options['class'])) { - $classes = array_unique(preg_split('/\s+/', $options['class'] . ' ' . $class, -1, PREG_SPLIT_NO_EMPTY)); - if (($index = array_search($class, $classes)) !== false) { - unset($classes[$index]); - } - if (empty($classes)) { - unset($options['class']); - } else { - $options['class'] = implode(' ', $classes); - } - } - } - - /** - * Returns the real attribute name from the given attribute expression. - * - * An attribute expression is an attribute name prefixed and/or suffixed with array indexes. - * It is mainly used in tabular data input and/or input of array type. Below are some examples: - * - * - `[0]content` is used in tabular data input to represent the "content" attribute - * for the first model in tabular input; - * - `dates[0]` represents the first array element of the "dates" attribute; - * - `[0]dates[0]` represents the first array element of the "dates" attribute - * for the first model in tabular input. - * - * If `$attribute` has neither prefix nor suffix, it will be returned back without change. - * @param string $attribute the attribute name or expression - * @return string the attribute name without prefix and suffix. - * @throws InvalidParamException if the attribute name contains non-word characters. - */ - public static function getAttributeName($attribute) - { - if (preg_match('/(^|.*\])(\w+)(\[.*|$)/', $attribute, $matches)) { - return $matches[2]; - } else { - throw new InvalidParamException('Attribute name must contain word characters only.'); - } - } - - /** - * Returns the value of the specified attribute name or expression. - * - * For an attribute expression like `[0]dates[0]`, this method will return the value of `$model->dates[0]`. - * See [[getAttributeName()]] for more details about attribute expression. - * - * If an attribute value is an instance of [[ActiveRecordInterface]] or an array of such instances, - * the primary value(s) of the AR instance(s) will be returned instead. - * - * @param Model $model the model object - * @param string $attribute the attribute name or expression - * @return string|array the corresponding attribute value - * @throws InvalidParamException if the attribute name contains non-word characters. - */ - public static function getAttributeValue($model, $attribute) - { - if (!preg_match('/(^|.*\])(\w+)(\[.*|$)/', $attribute, $matches)) { - throw new InvalidParamException('Attribute name must contain word characters only.'); - } - $attribute = $matches[2]; - $value = $model->$attribute; - if ($matches[3] !== '') { - foreach (explode('][', trim($matches[3], '[]')) as $id) { - if ((is_array($value) || $value instanceof \ArrayAccess) && isset($value[$id])) { - $value = $value[$id]; - } else { - return null; - } - } - } - - // https://github.com/yiisoft/yii2/issues/1457 - if (is_array($value)) { - foreach ($value as $i => $v) { - if ($v instanceof ActiveRecordInterface) { - $v = $v->getPrimaryKey(false); - $value[$i] = is_array($v) ? json_encode($v) : $v; - } - } - } elseif ($value instanceof ActiveRecordInterface) { - $value = $value->getPrimaryKey(false); - return is_array($value) ? json_encode($value) : $value; - } - return $value; - } - - /** - * Generates an appropriate input name for the specified attribute name or expression. - * - * This method generates a name that can be used as the input name to collect user input - * for the specified attribute. The name is generated according to the [[Model::formName|form name]] - * of the model and the given attribute name. For example, if the form name of the `Post` model - * is `Post`, then the input name generated for the `content` attribute would be `Post[content]`. - * - * See [[getAttributeName()]] for explanation of attribute expression. - * - * @param Model $model the model object - * @param string $attribute the attribute name or expression - * @return string the generated input name - * @throws InvalidParamException if the attribute name contains non-word characters. - */ - public static function getInputName($model, $attribute) - { - $formName = $model->formName(); - if (!preg_match('/(^|.*\])(\w+)(\[.*|$)/', $attribute, $matches)) { - throw new InvalidParamException('Attribute name must contain word characters only.'); - } - $prefix = $matches[1]; - $attribute = $matches[2]; - $suffix = $matches[3]; - if ($formName === '' && $prefix === '') { - return $attribute . $suffix; - } elseif ($formName !== '') { - return $formName . $prefix . "[$attribute]" . $suffix; - } else { - throw new InvalidParamException(get_class($model) . '::formName() cannot be empty for tabular inputs.'); - } - } - - /** - * Generates an appropriate input ID for the specified attribute name or expression. - * - * This method converts the result [[getInputName()]] into a valid input ID. - * For example, if [[getInputName()]] returns `Post[content]`, this method will return `post-content`. - * @param Model $model the model object - * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for explanation of attribute expression. - * @return string the generated input ID - * @throws InvalidParamException if the attribute name contains non-word characters. - */ - public static function getInputId($model, $attribute) - { - $name = strtolower(static::getInputName($model, $attribute)); - return str_replace(['[]', '][', '[', ']', ' '], ['', '-', '-', '', '-'], $name); - } -} diff --git a/framework/yii/helpers/BaseHtmlPurifier.php b/framework/yii/helpers/BaseHtmlPurifier.php deleted file mode 100644 index 17d2122..0000000 --- a/framework/yii/helpers/BaseHtmlPurifier.php +++ /dev/null @@ -1,34 +0,0 @@ - - * @since 2.0 - */ -class BaseHtmlPurifier -{ - /** - * Passes markup through HTMLPurifier making it safe to output to end user - * - * @param string $content - * @param array|null $config - * @return string - */ - public static function process($content, $config = null) - { - $configInstance = \HTMLPurifier_Config::create($config); - $configInstance->autoFinalize = false; - $purifier=\HTMLPurifier::instance($configInstance); - $purifier->config->set('Cache.SerializerPath', \Yii::$app->getRuntimePath()); - return $purifier->purify($content); - } -} diff --git a/framework/yii/helpers/BaseInflector.php b/framework/yii/helpers/BaseInflector.php deleted file mode 100644 index f9f19a8..0000000 --- a/framework/yii/helpers/BaseInflector.php +++ /dev/null @@ -1,491 +0,0 @@ - - * @since 2.0 - */ -class BaseInflector -{ - /** - * @var array the rules for converting a word into its plural form. - * The keys are the regular expressions and the values are the corresponding replacements. - */ - public static $plurals = [ - '/([nrlm]ese|deer|fish|sheep|measles|ois|pox|media)$/i' => '\1', - '/^(sea[- ]bass)$/i' => '\1', - '/(m)ove$/i' => '\1oves', - '/(f)oot$/i' => '\1eet', - '/(h)uman$/i' => '\1umans', - '/(s)tatus$/i' => '\1tatuses', - '/(s)taff$/i' => '\1taff', - '/(t)ooth$/i' => '\1eeth', - '/(quiz)$/i' => '\1zes', - '/^(ox)$/i' => '\1\2en', - '/([m|l])ouse$/i' => '\1ice', - '/(matr|vert|ind)(ix|ex)$/i' => '\1ices', - '/(x|ch|ss|sh)$/i' => '\1es', - '/([^aeiouy]|qu)y$/i' => '\1ies', - '/(hive)$/i' => '\1s', - '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves', - '/sis$/i' => 'ses', - '/([ti])um$/i' => '\1a', - '/(p)erson$/i' => '\1eople', - '/(m)an$/i' => '\1en', - '/(c)hild$/i' => '\1hildren', - '/(buffal|tomat|potat|ech|her|vet)o$/i' => '\1oes', - '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i', - '/us$/i' => 'uses', - '/(alias)$/i' => '\1es', - '/(ax|cris|test)is$/i' => '\1es', - '/s$/' => 's', - '/^$/' => '', - '/$/' => 's', - ]; - /** - * @var array the rules for converting a word into its singular form. - * The keys are the regular expressions and the values are the corresponding replacements. - */ - public static $singulars = [ - '/([nrlm]ese|deer|fish|sheep|measles|ois|pox|media|ss)$/i' => '\1', - '/^(sea[- ]bass)$/i' => '\1', - '/(s)tatuses$/i' => '\1tatus', - '/(f)eet$/i' => '\1oot', - '/(t)eeth$/i' => '\1ooth', - '/^(.*)(menu)s$/i' => '\1\2', - '/(quiz)zes$/i' => '\\1', - '/(matr)ices$/i' => '\1ix', - '/(vert|ind)ices$/i' => '\1ex', - '/^(ox)en/i' => '\1', - '/(alias)(es)*$/i' => '\1', - '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us', - '/([ftw]ax)es/i' => '\1', - '/(cris|ax|test)es$/i' => '\1is', - '/(shoe|slave)s$/i' => '\1', - '/(o)es$/i' => '\1', - '/ouses$/' => 'ouse', - '/([^a])uses$/' => '\1us', - '/([m|l])ice$/i' => '\1ouse', - '/(x|ch|ss|sh)es$/i' => '\1', - '/(m)ovies$/i' => '\1\2ovie', - '/(s)eries$/i' => '\1\2eries', - '/([^aeiouy]|qu)ies$/i' => '\1y', - '/([lr])ves$/i' => '\1f', - '/(tive)s$/i' => '\1', - '/(hive)s$/i' => '\1', - '/(drive)s$/i' => '\1', - '/([^fo])ves$/i' => '\1fe', - '/(^analy)ses$/i' => '\1sis', - '/(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis', - '/([ti])a$/i' => '\1um', - '/(p)eople$/i' => '\1\2erson', - '/(m)en$/i' => '\1an', - '/(c)hildren$/i' => '\1\2hild', - '/(n)ews$/i' => '\1\2ews', - '/eaus$/' => 'eau', - '/^(.*us)$/' => '\\1', - '/s$/i' => '', - ]; - /** - * @var array the special rules for converting a word between its plural form and singular form. - * The keys are the special words in singular form, and the values are the corresponding plural form. - */ - public static $specials = [ - 'atlas' => 'atlases', - 'beef' => 'beefs', - 'brother' => 'brothers', - 'cafe' => 'cafes', - 'child' => 'children', - 'cookie' => 'cookies', - 'corpus' => 'corpuses', - 'cow' => 'cows', - 'curve' => 'curves', - 'foe' => 'foes', - 'ganglion' => 'ganglions', - 'genie' => 'genies', - 'genus' => 'genera', - 'graffito' => 'graffiti', - 'hoof' => 'hoofs', - 'loaf' => 'loaves', - 'man' => 'men', - 'money' => 'monies', - 'mongoose' => 'mongooses', - 'move' => 'moves', - 'mythos' => 'mythoi', - 'niche' => 'niches', - 'numen' => 'numina', - 'occiput' => 'occiputs', - 'octopus' => 'octopuses', - 'opus' => 'opuses', - 'ox' => 'oxen', - 'penis' => 'penises', - 'sex' => 'sexes', - 'soliloquy' => 'soliloquies', - 'testis' => 'testes', - 'trilby' => 'trilbys', - 'turf' => 'turfs', - 'wave' => 'waves', - 'Amoyese' => 'Amoyese', - 'bison' => 'bison', - 'Borghese' => 'Borghese', - 'bream' => 'bream', - 'breeches' => 'breeches', - 'britches' => 'britches', - 'buffalo' => 'buffalo', - 'cantus' => 'cantus', - 'carp' => 'carp', - 'chassis' => 'chassis', - 'clippers' => 'clippers', - 'cod' => 'cod', - 'coitus' => 'coitus', - 'Congoese' => 'Congoese', - 'contretemps' => 'contretemps', - 'corps' => 'corps', - 'debris' => 'debris', - 'diabetes' => 'diabetes', - 'djinn' => 'djinn', - 'eland' => 'eland', - 'elk' => 'elk', - 'equipment' => 'equipment', - 'Faroese' => 'Faroese', - 'flounder' => 'flounder', - 'Foochowese' => 'Foochowese', - 'gallows' => 'gallows', - 'Genevese' => 'Genevese', - 'Genoese' => 'Genoese', - 'Gilbertese' => 'Gilbertese', - 'graffiti' => 'graffiti', - 'headquarters' => 'headquarters', - 'herpes' => 'herpes', - 'hijinks' => 'hijinks', - 'Hottentotese' => 'Hottentotese', - 'information' => 'information', - 'innings' => 'innings', - 'jackanapes' => 'jackanapes', - 'Kiplingese' => 'Kiplingese', - 'Kongoese' => 'Kongoese', - 'Lucchese' => 'Lucchese', - 'mackerel' => 'mackerel', - 'Maltese' => 'Maltese', - 'mews' => 'mews', - 'moose' => 'moose', - 'mumps' => 'mumps', - 'Nankingese' => 'Nankingese', - 'news' => 'news', - 'nexus' => 'nexus', - 'Niasese' => 'Niasese', - 'Pekingese' => 'Pekingese', - 'Piedmontese' => 'Piedmontese', - 'pincers' => 'pincers', - 'Pistoiese' => 'Pistoiese', - 'pliers' => 'pliers', - 'Portuguese' => 'Portuguese', - 'proceedings' => 'proceedings', - 'rabies' => 'rabies', - 'rice' => 'rice', - 'rhinoceros' => 'rhinoceros', - 'salmon' => 'salmon', - 'Sarawakese' => 'Sarawakese', - 'scissors' => 'scissors', - 'series' => 'series', - 'Shavese' => 'Shavese', - 'shears' => 'shears', - 'siemens' => 'siemens', - 'species' => 'species', - 'swine' => 'swine', - 'testes' => 'testes', - 'trousers' => 'trousers', - 'trout' => 'trout', - 'tuna' => 'tuna', - 'Vermontese' => 'Vermontese', - 'Wenchowese' => 'Wenchowese', - 'whiting' => 'whiting', - 'wildebeest' => 'wildebeest', - 'Yengeese' => 'Yengeese', - ]; - - /** - * @var array map of special chars and its translation. This is used by [[slug()]]. - */ - public static $transliteration = [ - // Latin - 'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A', 'Å' => 'A', 'Æ' => 'AE', 'Ç' => 'C', - 'È' => 'E', 'É' => 'E', 'Ê' => 'E', 'Ë' => 'E', 'Ì' => 'I', 'Í' => 'I', 'Î' => 'I', 'Ï' => 'I', - 'Ð' => 'D', 'Ñ' => 'N', 'Ò' => 'O', 'Ó' => 'O', 'Ô' => 'O', 'Õ' => 'O', 'Ö' => 'O', 'Ő' => 'O', - 'Ø' => 'O', 'Ù' => 'U', 'Ú' => 'U', 'Û' => 'U', 'Ü' => 'U', 'Ű' => 'U', 'Ý' => 'Y', 'Þ' => 'TH', - 'ß' => 'ss', - 'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a', 'ä' => 'a', 'å' => 'a', 'æ' => 'ae', 'ç' => 'c', - 'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e', 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', - 'ð' => 'd', 'ñ' => 'n', 'ò' => 'o', 'ó' => 'o', 'ô' => 'o', 'õ' => 'o', 'ö' => 'o', 'ő' => 'o', - 'ø' => 'o', 'ù' => 'u', 'ú' => 'u', 'û' => 'u', 'ü' => 'u', 'ű' => 'u', 'ý' => 'y', 'þ' => 'th', - 'ÿ' => 'y', - // Latin symbols - '©' => '(c)', - // Greek - 'Α' => 'A', 'Β' => 'B', 'Γ' => 'G', 'Δ' => 'D', 'Ε' => 'E', 'Ζ' => 'Z', 'Η' => 'H', 'Θ' => '8', - 'Ι' => 'I', 'Κ' => 'K', 'Λ' => 'L', 'Μ' => 'M', 'Ν' => 'N', 'Ξ' => '3', 'Ο' => 'O', 'Π' => 'P', - 'Ρ' => 'R', 'Σ' => 'S', 'Τ' => 'T', 'Υ' => 'Y', 'Φ' => 'F', 'Χ' => 'X', 'Ψ' => 'PS', 'Ω' => 'W', - 'Ά' => 'A', 'Έ' => 'E', 'Ί' => 'I', 'Ό' => 'O', 'Ύ' => 'Y', 'Ή' => 'H', 'Ώ' => 'W', 'Ϊ' => 'I', - 'Ϋ' => 'Y', - 'α' => 'a', 'β' => 'b', 'γ' => 'g', 'δ' => 'd', 'ε' => 'e', 'ζ' => 'z', 'η' => 'h', 'θ' => '8', - 'ι' => 'i', 'κ' => 'k', 'λ' => 'l', 'μ' => 'm', 'ν' => 'n', 'ξ' => '3', 'ο' => 'o', 'π' => 'p', - 'ρ' => 'r', 'σ' => 's', 'τ' => 't', 'υ' => 'y', 'φ' => 'f', 'χ' => 'x', 'ψ' => 'ps', 'ω' => 'w', - 'ά' => 'a', 'έ' => 'e', 'ί' => 'i', 'ό' => 'o', 'ύ' => 'y', 'ή' => 'h', 'ώ' => 'w', 'ς' => 's', - 'ϊ' => 'i', 'ΰ' => 'y', 'ϋ' => 'y', 'ΐ' => 'i', - // Turkish - 'Ş' => 'S', 'İ' => 'I', 'Ç' => 'C', 'Ü' => 'U', 'Ö' => 'O', 'Ğ' => 'G', - 'ş' => 's', 'ı' => 'i', 'ç' => 'c', 'ü' => 'u', 'ö' => 'o', 'ğ' => 'g', - // Russian - 'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D', 'Е' => 'E', 'Ё' => 'Yo', 'Ж' => 'Zh', - 'З' => 'Z', 'И' => 'I', 'Й' => 'J', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N', 'О' => 'O', - 'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T', 'У' => 'U', 'Ф' => 'F', 'Х' => 'H', 'Ц' => 'C', - 'Ч' => 'Ch', 'Ш' => 'Sh', 'Щ' => 'Sh', 'Ъ' => '', 'Ы' => 'Y', 'Ь' => '', 'Э' => 'E', 'Ю' => 'Yu', - 'Я' => 'Ya', - 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 'ё' => 'yo', 'ж' => 'zh', - 'з' => 'z', 'и' => 'i', 'й' => 'j', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n', 'о' => 'o', - 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'c', - 'ч' => 'ch', 'ш' => 'sh', 'щ' => 'sh', 'ъ' => '', 'ы' => 'y', 'ь' => '', 'э' => 'e', 'ю' => 'yu', - 'я' => 'ya', - // Ukrainian - 'Є' => 'Ye', 'І' => 'I', 'Ї' => 'Yi', 'Ґ' => 'G', - 'є' => 'ye', 'і' => 'i', 'ї' => 'yi', 'ґ' => 'g', - // Czech - 'Č' => 'C', 'Ď' => 'D', 'Ě' => 'E', 'Ň' => 'N', 'Ř' => 'R', 'Š' => 'S', 'Ť' => 'T', 'Ů' => 'U', - 'Ž' => 'Z', - 'č' => 'c', 'ď' => 'd', 'ě' => 'e', 'ň' => 'n', 'ř' => 'r', 'š' => 's', 'ť' => 't', 'ů' => 'u', - 'ž' => 'z', - // Polish - 'Ą' => 'A', 'Ć' => 'C', 'Ę' => 'e', 'Ł' => 'L', 'Ń' => 'N', 'Ó' => 'o', 'Ś' => 'S', 'Ź' => 'Z', - 'Ż' => 'Z', - 'ą' => 'a', 'ć' => 'c', 'ę' => 'e', 'ł' => 'l', 'ń' => 'n', 'ó' => 'o', 'ś' => 's', 'ź' => 'z', - 'ż' => 'z', - // Latvian - 'Ā' => 'A', 'Č' => 'C', 'Ē' => 'E', 'Ģ' => 'G', 'Ī' => 'i', 'Ķ' => 'k', 'Ļ' => 'L', 'Ņ' => 'N', - 'Š' => 'S', 'Ū' => 'u', 'Ž' => 'Z', - 'ā' => 'a', 'č' => 'c', 'ē' => 'e', 'ģ' => 'g', 'ī' => 'i', 'ķ' => 'k', 'ļ' => 'l', 'ņ' => 'n', - 'š' => 's', 'ū' => 'u', 'ž' => 'z' - ]; - - /** - * Converts a word to its plural form. - * Note that this is for English only! - * For example, 'apple' will become 'apples', and 'child' will become 'children'. - * @param string $word the word to be pluralized - * @return string the pluralized word - */ - public static function pluralize($word) - { - if (isset(static::$specials[$word])) { - return static::$specials[$word]; - } - foreach (static::$plurals as $rule => $replacement) { - if (preg_match($rule, $word)) { - return preg_replace($rule, $replacement, $word); - } - } - return $word; - } - - /** - * Returns the singular of the $word - * @param string $word the english word to singularize - * @return string Singular noun. - */ - public static function singularize($word) - { - $result = array_search($word, static::$specials, true); - if ($result !== false) { - return $result; - } - foreach (static::$singulars as $rule => $replacement) { - if (preg_match($rule, $word)) { - return preg_replace($rule, $replacement, $word); - } - } - return $word; - } - - /** - * Converts an underscored or CamelCase word into a English - * sentence. - * @param string $words - * @param bool $ucAll whether to set all words to uppercase - * @return string - */ - public static function titleize($words, $ucAll = false) - { - $words = static::humanize(static::underscore($words), $ucAll); - return $ucAll ? ucwords($words) : ucfirst($words); - } - - /** - * Returns given word as CamelCased - * Converts a word like "send_email" to "SendEmail". It - * will remove non alphanumeric character from the word, so - * "who's online" will be converted to "WhoSOnline" - * @see variablize() - * @param string $word the word to CamelCase - * @return string - */ - public static function camelize($word) - { - return str_replace(' ', '', ucwords(preg_replace('/[^A-Za-z0-9]+/', ' ', $word))); - } - - /** - * Converts a CamelCase name into space-separated words. - * For example, 'PostTag' will be converted to 'Post Tag'. - * @param string $name the string to be converted - * @param boolean $ucwords whether to capitalize the first letter in each word - * @return string the resulting words - */ - public static function camel2words($name, $ucwords = true) - { - $label = trim(strtolower(str_replace([ - '-', - '_', - '.' - ], ' ', preg_replace('/(? - * @since 2.0 - */ -class BaseJson -{ - /** - * Encodes the given value into a JSON string. - * The method enhances `json_encode()` by supporting JavaScript expressions. - * In particular, the method will not encode a JavaScript expression that is - * represented in terms of a [[JsExpression]] object. - * @param mixed $value the data to be encoded - * @param integer $options the encoding options. For more details please refer to - * - * @return string the encoding result - */ - public static function encode($value, $options = 0) - { - $expressions = []; - $value = static::processData($value, $expressions, uniqid()); - $json = json_encode($value, $options); - return empty($expressions) ? $json : strtr($json, $expressions); - } - - /** - * Decodes the given JSON string into a PHP data structure. - * @param string $json the JSON string to be decoded - * @param boolean $asArray whether to return objects in terms of associative arrays. - * @return mixed the PHP data - * @throws InvalidParamException if there is any decoding error - */ - public static function decode($json, $asArray = true) - { - if (is_array($json)) { - throw new InvalidParamException('Invalid JSON data.'); - } - $decode = json_decode((string)$json, $asArray); - switch (json_last_error()) { - case JSON_ERROR_NONE: - break; - case JSON_ERROR_DEPTH: - throw new InvalidParamException('The maximum stack depth has been exceeded.'); - case JSON_ERROR_CTRL_CHAR: - throw new InvalidParamException('Control character error, possibly incorrectly encoded.'); - case JSON_ERROR_SYNTAX: - throw new InvalidParamException('Syntax error.'); - case JSON_ERROR_STATE_MISMATCH: - throw new InvalidParamException('Invalid or malformed JSON.'); - case JSON_ERROR_UTF8: - throw new InvalidParamException('Malformed UTF-8 characters, possibly incorrectly encoded.'); - default: - throw new InvalidParamException('Unknown JSON decoding error.'); - } - - return $decode; - } - - /** - * Pre-processes the data before sending it to `json_encode()`. - * @param mixed $data the data to be processed - * @param array $expressions collection of JavaScript expressions - * @param string $expPrefix a prefix internally used to handle JS expressions - * @return mixed the processed data - */ - protected static function processData($data, &$expressions, $expPrefix) - { - if ($data instanceof \JsonSerializable) { - return $data; - } - - if (is_object($data)) { - if ($data instanceof JsExpression) { - $token = "!{[$expPrefix=" . count($expressions) . ']}!'; - $expressions['"' . $token . '"'] = $data->expression; - return $token; - } - $data = $data instanceof Arrayable ? $data->toArray() : get_object_vars($data); - if ($data === [] && !$data instanceof Arrayable) { - return new \stdClass(); - } - } - - if (is_array($data)) { - foreach ($data as $key => $value) { - if (is_array($value) || is_object($value)) { - $data[$key] = static::processData($value, $expressions, $expPrefix); - } - } - } - - return $data; - } -} diff --git a/framework/yii/helpers/BaseMarkdown.php b/framework/yii/helpers/BaseMarkdown.php deleted file mode 100644 index 5258534..0000000 --- a/framework/yii/helpers/BaseMarkdown.php +++ /dev/null @@ -1,44 +0,0 @@ - - * @since 2.0 - */ -class BaseMarkdown -{ - /** - * @var MarkdownExtra - */ - protected static $markdown; - - /** - * Converts markdown into HTML - * - * @param string $content - * @param array $config - * @return string - */ - public static function process($content, $config = []) - { - if (static::$markdown === null) { - static::$markdown = new MarkdownExtra(); - } - foreach ($config as $name => $value) { - static::$markdown->{$name} = $value; - } - return static::$markdown->transform($content); - } -} diff --git a/framework/yii/helpers/BaseSecurity.php b/framework/yii/helpers/BaseSecurity.php deleted file mode 100644 index ba7567f..0000000 --- a/framework/yii/helpers/BaseSecurity.php +++ /dev/null @@ -1,354 +0,0 @@ - - * @author Tom Worster - * @since 2.0 - */ -class BaseSecurity -{ - /** - * Uses AES, block size is 128-bit (16 bytes). - */ - const CRYPT_BLOCK_SIZE = 16; - - /** - * Uses AES-192, key size is 192-bit (24 bytes). - */ - const CRYPT_KEY_SIZE = 24; - - /** - * Uses SHA-256. - */ - const DERIVATION_HASH = 'sha256'; - - /** - * Uses 1000 iterations. - */ - const DERIVATION_ITERATIONS = 1000; - - /** - * Encrypts data. - * @param string $data data to be encrypted. - * @param string $password the encryption password - * @return string the encrypted data - * @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized - * @see decrypt() - */ - public static function encrypt($data, $password) - { - $module = static::openCryptModule(); - $data = static::addPadding($data); - srand(); - $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND); - $key = static::deriveKey($password, $iv); - mcrypt_generic_init($module, $key, $iv); - $encrypted = $iv . mcrypt_generic($module, $data); - mcrypt_generic_deinit($module); - mcrypt_module_close($module); - return $encrypted; - } - - /** - * Decrypts data - * @param string $data data to be decrypted. - * @param string $password the decryption password - * @return string the decrypted data - * @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized - * @see encrypt() - */ - public static function decrypt($data, $password) - { - if ($data === null) { - return null; - } - $module = static::openCryptModule(); - $ivSize = mcrypt_enc_get_iv_size($module); - $iv = StringHelper::byteSubstr($data, 0, $ivSize); - $key = static::deriveKey($password, $iv); - mcrypt_generic_init($module, $key, $iv); - $decrypted = mdecrypt_generic($module, StringHelper::byteSubstr($data, $ivSize, StringHelper::byteLength($data))); - mcrypt_generic_deinit($module); - mcrypt_module_close($module); - return static::stripPadding($decrypted); - } - - /** - * Adds a padding to the given data (PKCS #7). - * @param string $data the data to pad - * @return string the padded data - */ - protected static function addPadding($data) - { - $pad = self::CRYPT_BLOCK_SIZE - (StringHelper::byteLength($data) % self::CRYPT_BLOCK_SIZE); - return $data . str_repeat(chr($pad), $pad); - } - - /** - * Strips the padding from the given data. - * @param string $data the data to trim - * @return string the trimmed data - */ - protected static function stripPadding($data) - { - $end = StringHelper::byteSubstr($data, -1, NULL); - $last = ord($end); - $n = StringHelper::byteLength($data) - $last; - if (StringHelper::byteSubstr($data, $n, NULL) == str_repeat($end, $last)) { - return StringHelper::byteSubstr($data, 0, $n); - } - return false; - } - - /** - * Derives a key from the given password (PBKDF2). - * @param string $password the source password - * @param string $salt the random salt - * @return string the derived key - */ - protected static function deriveKey($password, $salt) - { - if (function_exists('hash_pbkdf2')) { - return hash_pbkdf2(self::DERIVATION_HASH, $password, $salt, self::DERIVATION_ITERATIONS, self::CRYPT_KEY_SIZE, true); - } - $hmac = hash_hmac(self::DERIVATION_HASH, $salt . pack('N', 1), $password, true); - $xorsum = $hmac; - for ($i = 1; $i < self::DERIVATION_ITERATIONS; $i++) { - $hmac = hash_hmac(self::DERIVATION_HASH, $hmac, $password, true); - $xorsum ^= $hmac; - } - return substr($xorsum, 0, self::CRYPT_KEY_SIZE); - } - - /** - * Prefixes data with a keyed hash value so that it can later be detected if it is tampered. - * @param string $data the data to be protected - * @param string $key the secret key to be used for generating hash - * @param string $algorithm the hashing algorithm (e.g. "md5", "sha1", "sha256", etc.). Call PHP "hash_algos()" - * function to see the supported hashing algorithms on your system. - * @return string the data prefixed with the keyed hash - * @see validateData() - * @see getSecretKey() - */ - public static function hashData($data, $key, $algorithm = 'sha256') - { - return hash_hmac($algorithm, $data, $key) . $data; - } - - /** - * Validates if the given data is tampered. - * @param string $data the data to be validated. The data must be previously - * generated by [[hashData()]]. - * @param string $key the secret key that was previously used to generate the hash for the data in [[hashData()]]. - * @param string $algorithm the hashing algorithm (e.g. "md5", "sha1", "sha256", etc.). Call PHP "hash_algos()" - * function to see the supported hashing algorithms on your system. This must be the same - * as the value passed to [[hashData()]] when generating the hash for the data. - * @return string the real data with the hash stripped off. False if the data is tampered. - * @see hashData() - */ - public static function validateData($data, $key, $algorithm = 'sha256') - { - $hashSize = StringHelper::byteLength(hash_hmac($algorithm, 'test', $key)); - $n = StringHelper::byteLength($data); - if ($n >= $hashSize) { - $hash = StringHelper::byteSubstr($data, 0, $hashSize); - $data2 = StringHelper::byteSubstr($data, $hashSize, $n - $hashSize); - return $hash === hash_hmac($algorithm, $data2, $key) ? $data2 : false; - } else { - return false; - } - } - - /** - * Returns a secret key associated with the specified name. - * If the secret key does not exist, a random key will be generated - * and saved in the file "keys.json" under the application's runtime directory - * so that the same secret key can be returned in future requests. - * @param string $name the name that is associated with the secret key - * @param integer $length the length of the key that should be generated if not exists - * @return string the secret key associated with the specified name - */ - public static function getSecretKey($name, $length = 32) - { - static $keys; - $keyFile = Yii::$app->getRuntimePath() . '/keys.json'; - if ($keys === null) { - $keys = []; - if (is_file($keyFile)) { - $keys = json_decode(file_get_contents($keyFile), true); - } - } - if (!isset($keys[$name])) { - $keys[$name] = static::generateRandomKey($length); - file_put_contents($keyFile, json_encode($keys)); - } - return $keys[$name]; - } - - /** - * Generates a random key. The key may contain uppercase and lowercase latin letters, digits, underscore, dash and dot. - * @param integer $length the length of the key that should be generated - * @return string the generated random key - */ - public static function generateRandomKey($length = 32) - { - if (function_exists('openssl_random_pseudo_bytes')) { - $key = strtr(base64_encode(openssl_random_pseudo_bytes($length, $strong)), '+/=', '_-.'); - if ($strong) { - return substr($key, 0, $length); - } - } - $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.'; - return substr(str_shuffle(str_repeat($chars, 5)), 0, $length); - } - - /** - * Opens the mcrypt module. - * @return resource the mcrypt module handle. - * @throws InvalidConfigException if mcrypt extension is not installed - * @throws Exception if mcrypt initialization fails - */ - protected static function openCryptModule() - { - if (!extension_loaded('mcrypt')) { - throw new InvalidConfigException('The mcrypt PHP extension is not installed.'); - } - // AES uses a 128-bit block size - $module = @mcrypt_module_open('rijndael-128', '', 'cbc', ''); - if ($module === false) { - throw new Exception('Failed to initialize the mcrypt module.'); - } - return $module; - } - - /** - * Generates a secure hash from a password and a random salt. - * - * The generated hash can be stored in database (e.g. `CHAR(64) CHARACTER SET latin1` on MySQL). - * Later when a password needs to be validated, the hash can be fetched and passed - * to [[validatePassword()]]. For example, - * - * ~~~ - * // generates the hash (usually done during user registration or when the password is changed) - * $hash = Security::generatePasswordHash($password); - * // ...save $hash in database... - * - * // during login, validate if the password entered is correct using $hash fetched from database - * if (Security::validatePassword($password, $hash) { - * // password is good - * } else { - * // password is bad - * } - * ~~~ - * - * @param string $password The password to be hashed. - * @param integer $cost Cost parameter used by the Blowfish hash algorithm. - * The higher the value of cost, - * the longer it takes to generate the hash and to verify a password against it. Higher cost - * therefore slows down a brute-force attack. For best protection against brute for attacks, - * set it to the highest value that is tolerable on production servers. The time taken to - * compute the hash doubles for every increment by one of $cost. So, for example, if the - * hash takes 1 second to compute when $cost is 14 then then the compute time varies as - * 2^($cost - 14) seconds. - * @throws Exception on bad password parameter or cost parameter - * @return string The password hash string, ASCII and not longer than 64 characters. - * @see validatePassword() - */ - public static function generatePasswordHash($password, $cost = 13) - { - $salt = static::generateSalt($cost); - $hash = crypt($password, $salt); - - if (!is_string($hash) || strlen($hash) < 32) { - throw new Exception('Unknown error occurred while generating hash.'); - } - - return $hash; - } - - /** - * Verifies a password against a hash. - * @param string $password The password to verify. - * @param string $hash The hash to verify the password against. - * @return boolean whether the password is correct. - * @throws InvalidParamException on bad password or hash parameters or if crypt() with Blowfish hash is not available. - * @see generatePasswordHash() - */ - public static function validatePassword($password, $hash) - { - if (!is_string($password) || $password === '') { - throw new InvalidParamException('Password must be a string and cannot be empty.'); - } - - if (!preg_match('/^\$2[axy]\$(\d\d)\$[\.\/0-9A-Za-z]{22}/', $hash, $matches) || $matches[1] < 4 || $matches[1] > 30) { - throw new InvalidParamException('Hash is invalid.'); - } - - $test = crypt($password, $hash); - $n = strlen($test); - if ($n < 32 || $n !== strlen($hash)) { - return false; - } - - // Use a for-loop to compare two strings to prevent timing attacks. See: - // http://codereview.stackexchange.com/questions/13512 - $check = 0; - for ($i = 0; $i < $n; ++$i) { - $check |= (ord($test[$i]) ^ ord($hash[$i])); - } - - return $check === 0; - } - - /** - * Generates a salt that can be used to generate a password hash. - * - * The PHP [crypt()](http://php.net/manual/en/function.crypt.php) built-in function - * requires, for the Blowfish hash algorithm, a salt string in a specific format: - * "$2a$", "$2x$" or "$2y$", a two digit cost parameter, "$", and 22 characters - * from the alphabet "./0-9A-Za-z". - * - * @param integer $cost the cost parameter - * @return string the random salt value. - * @throws InvalidParamException if the cost parameter is not between 4 and 31 - */ - protected static function generateSalt($cost = 13) - { - $cost = (int)$cost; - if ($cost < 4 || $cost > 31) { - throw new InvalidParamException('Cost must be between 4 and 31.'); - } - - // Get 20 * 8bits of pseudo-random entropy from mt_rand(). - $rand = ''; - for ($i = 0; $i < 20; ++$i) { - $rand .= chr(mt_rand(0, 255)); - } - - // Add the microtime for a little more entropy. - $rand .= microtime(); - // Mix the bits cryptographically into a 20-byte binary string. - $rand = sha1($rand, true); - // Form the prefix that specifies Blowfish algorithm and cost parameter. - $salt = sprintf("$2y$%02d$", $cost); - // Append the random salt data in the required base64 format. - $salt .= str_replace('+', '.', substr(base64_encode($rand), 0, 22)); - return $salt; - } -} diff --git a/framework/yii/helpers/BaseStringHelper.php b/framework/yii/helpers/BaseStringHelper.php deleted file mode 100644 index e282913..0000000 --- a/framework/yii/helpers/BaseStringHelper.php +++ /dev/null @@ -1,140 +0,0 @@ - - * @author Alex Makarov - * @since 2.0 - */ -class BaseStringHelper -{ - /** - * Returns the number of bytes in the given string. - * This method ensures the string is treated as a byte array by using `mb_strlen()`. - * @param string $string the string being measured for length - * @return integer the number of bytes in the given string. - */ - public static function byteLength($string) - { - return mb_strlen($string, '8bit'); - } - - /** - * Returns the portion of string specified by the start and length parameters. - * This method ensures the string is treated as a byte array by using `mb_substr()`. - * @param string $string the input string. Must be one character or longer. - * @param integer $start the starting position - * @param integer $length the desired portion length - * @return string the extracted part of string, or FALSE on failure or an empty string. - * @see http://www.php.net/manual/en/function.substr.php - */ - public static function byteSubstr($string, $start, $length) - { - return mb_substr($string, $start, $length, '8bit'); - } - - /** - * Returns the trailing name component of a path. - * This method is similar to the php function `basename()` except that it will - * treat both \ and / as directory separators, independent of the operating system. - * This method was mainly created to work on php namespaces. When working with real - * file paths, php's `basename()` should work fine for you. - * Note: this method is not aware of the actual filesystem, or path components such as "..". - * - * @param string $path A path string. - * @param string $suffix If the name component ends in suffix this will also be cut off. - * @return string the trailing name component of the given path. - * @see http://www.php.net/manual/en/function.basename.php - */ - public static function basename($path, $suffix = '') - { - if (($len = mb_strlen($suffix)) > 0 && mb_substr($path, -$len) == $suffix) { - $path = mb_substr($path, 0, -$len); - } - $path = rtrim(str_replace('\\', '/', $path), '/\\'); - if (($pos = mb_strrpos($path, '/')) !== false) { - return mb_substr($path, $pos + 1); - } - return $path; - } - - /** - * Returns parent directory's path. - * This method is similar to `dirname()` except that it will treat - * both \ and / as directory separators, independent of the operating system. - * - * @param string $path A path string. - * @return string the parent directory's path. - * @see http://www.php.net/manual/en/function.basename.php - */ - public static function dirname($path) - { - $pos = mb_strrpos(str_replace('\\', '/', $path), '/'); - if ($pos !== false) { - return mb_substr($path, 0, $pos); - } else { - return $path; - } - } - - /** - * Compares two strings or string arrays, and return their differences. - * This is a wrapper of the [phpspec/php-diff](https://packagist.org/packages/phpspec/php-diff) package. - * @param string|array $lines1 the first string or string array to be compared. If it is a string, - * it will be converted into a string array by breaking at newlines. - * @param string|array $lines2 the second string or string array to be compared. If it is a string, - * it will be converted into a string array by breaking at newlines. - * @param string $format the output format. It must be 'inline', 'unified', 'context', 'side-by-side', or 'array'. - * @return string|array the comparison result. An array is returned if `$format` is 'array'. For all other - * formats, a string is returned. - * @throws InvalidParamException if the format is invalid. - */ - public static function diff($lines1, $lines2, $format = 'inline') - { - if (!is_array($lines1)) { - $lines1 = explode("\n", $lines1); - } - if (!is_array($lines2)) { - $lines2 = explode("\n", $lines2); - } - foreach ($lines1 as $i => $line) { - $lines1[$i] = rtrim($line, "\r\n"); - } - foreach ($lines2 as $i => $line) { - $lines2[$i] = rtrim($line, "\r\n"); - } - switch ($format) { - case 'inline': - $renderer = new \Diff_Renderer_Html_Inline(); - break; - case 'array': - $renderer = new \Diff_Renderer_Html_Array(); - break; - case 'side-by-side': - $renderer = new \Diff_Renderer_Html_SideBySide(); - break; - case 'context': - $renderer = new \Diff_Renderer_Text_Context(); - break; - case 'unified': - $renderer = new \Diff_Renderer_Text_Unified(); - break; - default: - throw new InvalidParamException("Output format must be 'inline', 'side-by-side', 'array', 'context' or 'unified'."); - } - $diff = new \Diff($lines1, $lines2); - return $diff->render($renderer); - } -} diff --git a/framework/yii/helpers/BaseVarDumper.php b/framework/yii/helpers/BaseVarDumper.php deleted file mode 100644 index 36b739c..0000000 --- a/framework/yii/helpers/BaseVarDumper.php +++ /dev/null @@ -1,126 +0,0 @@ - - * @link http://www.yiiframework.com/ - * @copyright Copyright © 2008-2011 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\helpers; - -/** - * BaseVarDumper provides concrete implementation for [[VarDumper]]. - * - * Do not use BaseVarDumper. Use [[VarDumper]] instead. - * - * @author Qiang Xue - * @since 2.0 - */ -class BaseVarDumper -{ - private static $_objects; - private static $_output; - private static $_depth; - - /** - * Displays a variable. - * This method achieves the similar functionality as var_dump and print_r - * but is more robust when handling complex objects such as Yii controllers. - * @param mixed $var variable to be dumped - * @param integer $depth maximum depth that the dumper should go into the variable. Defaults to 10. - * @param boolean $highlight whether the result should be syntax-highlighted - */ - public static function dump($var, $depth = 10, $highlight = false) - { - echo static::dumpAsString($var, $depth, $highlight); - } - - /** - * Dumps a variable in terms of a string. - * This method achieves the similar functionality as var_dump and print_r - * but is more robust when handling complex objects such as Yii controllers. - * @param mixed $var variable to be dumped - * @param integer $depth maximum depth that the dumper should go into the variable. Defaults to 10. - * @param boolean $highlight whether the result should be syntax-highlighted - * @return string the string representation of the variable - */ - public static function dumpAsString($var, $depth = 10, $highlight = false) - { - self::$_output = ''; - self::$_objects = []; - self::$_depth = $depth; - self::dumpInternal($var, 0); - if ($highlight) { - $result = highlight_string("/', '', $result, 1); - } - return self::$_output; - } - - /** - * @param mixed $var variable to be dumped - * @param integer $level depth level - */ - private static function dumpInternal($var, $level) - { - switch (gettype($var)) { - case 'boolean': - self::$_output .= $var ? 'true' : 'false'; - break; - case 'integer': - self::$_output .= "$var"; - break; - case 'double': - self::$_output .= "$var"; - break; - case 'string': - self::$_output .= "'" . addslashes($var) . "'"; - break; - case 'resource': - self::$_output .= '{resource}'; - break; - case 'NULL': - self::$_output .= "null"; - break; - case 'unknown type': - self::$_output .= '{unknown}'; - break; - case 'array': - if (self::$_depth <= $level) { - self::$_output .= '[...]'; - } elseif (empty($var)) { - self::$_output .= '[]'; - } else { - $keys = array_keys($var); - $spaces = str_repeat(' ', $level * 4); - self::$_output .= '['; - foreach ($keys as $key) { - self::$_output .= "\n" . $spaces . ' '; - self::dumpInternal($key, 0); - self::$_output .= ' => '; - self::dumpInternal($var[$key], $level + 1); - } - self::$_output .= "\n" . $spaces . ']'; - } - break; - case 'object': - if (($id = array_search($var, self::$_objects, true)) !== false) { - self::$_output .= get_class($var) . '#' . ($id + 1) . '(...)'; - } elseif (self::$_depth <= $level) { - self::$_output .= get_class($var) . '(...)'; - } else { - $id = array_push(self::$_objects, $var); - $className = get_class($var); - $spaces = str_repeat(' ', $level * 4); - self::$_output .= "$className#$id\n" . $spaces . '('; - foreach ((array)$var as $key => $value) { - $keyDisplay = strtr(trim($key), ["\0" => ':']); - self::$_output .= "\n" . $spaces . " [$keyDisplay] => "; - self::dumpInternal($value, $level + 1); - } - self::$_output .= "\n" . $spaces . ')'; - } - break; - } - } -} diff --git a/framework/yii/helpers/Console.php b/framework/yii/helpers/Console.php deleted file mode 100644 index a34dc96..0000000 --- a/framework/yii/helpers/Console.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @since 2.0 - */ -class Console extends BaseConsole -{ -} diff --git a/framework/yii/helpers/FileHelper.php b/framework/yii/helpers/FileHelper.php deleted file mode 100644 index 63954a4..0000000 --- a/framework/yii/helpers/FileHelper.php +++ /dev/null @@ -1,21 +0,0 @@ - - * @author Alex Makarov - * @since 2.0 - */ -class FileHelper extends BaseFileHelper -{ -} diff --git a/framework/yii/helpers/Html.php b/framework/yii/helpers/Html.php deleted file mode 100644 index f4fbbba..0000000 --- a/framework/yii/helpers/Html.php +++ /dev/null @@ -1,18 +0,0 @@ - - * @since 2.0 - */ -class Html extends BaseHtml -{ -} diff --git a/framework/yii/helpers/HtmlPurifier.php b/framework/yii/helpers/HtmlPurifier.php deleted file mode 100644 index f2852ad..0000000 --- a/framework/yii/helpers/HtmlPurifier.php +++ /dev/null @@ -1,37 +0,0 @@ - true, - * ]); - * ``` - * - * For more details please refer to HTMLPurifier documentation](http://htmlpurifier.org/). - * - * Note that you should add `ezyang/htmlpurifier` to your composer.json `require` section and run `composer install` - * before using it. - * - * @author Alexander Makarov - * @since 2.0 - */ -class HtmlPurifier extends BaseHtmlPurifier -{ -} diff --git a/framework/yii/helpers/Inflector.php b/framework/yii/helpers/Inflector.php deleted file mode 100644 index ab4713e..0000000 --- a/framework/yii/helpers/Inflector.php +++ /dev/null @@ -1,18 +0,0 @@ - - * @since 2.0 - */ -class Inflector extends BaseInflector -{ -} diff --git a/framework/yii/helpers/Json.php b/framework/yii/helpers/Json.php deleted file mode 100644 index 8ca436a..0000000 --- a/framework/yii/helpers/Json.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @since 2.0 - */ -class Json extends BaseJson -{ -} diff --git a/framework/yii/helpers/Markdown.php b/framework/yii/helpers/Markdown.php deleted file mode 100644 index 326cd34..0000000 --- a/framework/yii/helpers/Markdown.php +++ /dev/null @@ -1,35 +0,0 @@ - 'footnote_', - * ]); - * ``` - * - * Note that in order to use this helper you need to install "michelf/php-markdown" Composer package. - * - * For more details please refer to [PHP Markdown library documentation](http://michelf.ca/projects/php-markdown/). - * @author Alexander Makarov - * @since 2.0 - */ -class Markdown extends BaseMarkdown -{ -} diff --git a/framework/yii/helpers/Security.php b/framework/yii/helpers/Security.php deleted file mode 100644 index 0e3ee38..0000000 --- a/framework/yii/helpers/Security.php +++ /dev/null @@ -1,29 +0,0 @@ - - * @author Tom Worster - * @since 2.0 - */ -class Security extends BaseSecurity -{ -} diff --git a/framework/yii/helpers/StringHelper.php b/framework/yii/helpers/StringHelper.php deleted file mode 100644 index 5ecd390..0000000 --- a/framework/yii/helpers/StringHelper.php +++ /dev/null @@ -1,19 +0,0 @@ - - * @author Alex Makarov - * @since 2.0 - */ -class StringHelper extends BaseStringHelper -{ -} diff --git a/framework/yii/helpers/VarDumper.php b/framework/yii/helpers/VarDumper.php deleted file mode 100644 index 1ac5aa7..0000000 --- a/framework/yii/helpers/VarDumper.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @link http://www.yiiframework.com/ - * @copyright Copyright © 2008-2011 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\helpers; - -/** - * VarDumper is intended to replace the buggy PHP function var_dump and print_r. - * It can correctly identify the recursively referenced objects in a complex - * object structure. It also has a recursive depth control to avoid indefinite - * recursive display of some peculiar variables. - * - * VarDumper can be used as follows, - * - * ~~~ - * VarDumper::dump($var); - * ~~~ - * - * @author Qiang Xue - * @since 2.0 - */ -class VarDumper extends BaseVarDumper -{ -} diff --git a/framework/yii/helpers/mimeTypes.php b/framework/yii/helpers/mimeTypes.php deleted file mode 100644 index 4e9f61a..0000000 --- a/framework/yii/helpers/mimeTypes.php +++ /dev/null @@ -1,187 +0,0 @@ - 'application/postscript', - 'aif' => 'audio/x-aiff', - 'aifc' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'anx' => 'application/annodex', - 'asc' => 'text/plain', - 'au' => 'audio/basic', - 'avi' => 'video/x-msvideo', - 'axa' => 'audio/annodex', - 'axv' => 'video/annodex', - 'bcpio' => 'application/x-bcpio', - 'bin' => 'application/octet-stream', - 'bmp' => 'image/bmp', - 'c' => 'text/plain', - 'cc' => 'text/plain', - 'ccad' => 'application/clariscad', - 'cdf' => 'application/x-netcdf', - 'class' => 'application/octet-stream', - 'cpio' => 'application/x-cpio', - 'cpt' => 'application/mac-compactpro', - 'csh' => 'application/x-csh', - 'css' => 'text/css', - 'dcr' => 'application/x-director', - 'dir' => 'application/x-director', - 'dms' => 'application/octet-stream', - 'doc' => 'application/msword', - 'drw' => 'application/drafting', - 'dvi' => 'application/x-dvi', - 'dwg' => 'application/acad', - 'dxf' => 'application/dxf', - 'dxr' => 'application/x-director', - 'eps' => 'application/postscript', - 'etx' => 'text/x-setext', - 'exe' => 'application/octet-stream', - 'ez' => 'application/andrew-inset', - 'f' => 'text/plain', - 'f90' => 'text/plain', - 'flac' => 'audio/flac', - 'fli' => 'video/x-fli', - 'flv' => 'video/x-flv', - 'gif' => 'image/gif', - 'gtar' => 'application/x-gtar', - 'gz' => 'application/x-gzip', - 'h' => 'text/plain', - 'hdf' => 'application/x-hdf', - 'hh' => 'text/plain', - 'hqx' => 'application/mac-binhex40', - 'htm' => 'text/html', - 'html' => 'text/html', - 'ice' => 'x-conference/x-cooltalk', - 'ief' => 'image/ief', - 'iges' => 'model/iges', - 'igs' => 'model/iges', - 'ips' => 'application/x-ipscript', - 'ipx' => 'application/x-ipix', - 'jpe' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'js' => 'application/x-javascript', - 'kar' => 'audio/midi', - 'latex' => 'application/x-latex', - 'lha' => 'application/octet-stream', - 'lsp' => 'application/x-lisp', - 'lzh' => 'application/octet-stream', - 'm' => 'text/plain', - 'man' => 'application/x-troff-man', - 'me' => 'application/x-troff-me', - 'mesh' => 'model/mesh', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'mif' => 'application/vnd.mif', - 'mime' => 'www/mime', - 'mov' => 'video/quicktime', - 'movie' => 'video/x-sgi-movie', - 'mp2' => 'audio/mpeg', - 'mp3' => 'audio/mpeg', - 'mpe' => 'video/mpeg', - 'mpeg' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'mpga' => 'audio/mpeg', - 'ms' => 'application/x-troff-ms', - 'msh' => 'model/mesh', - 'nc' => 'application/x-netcdf', - 'oga' => 'audio/ogg', - 'ogg' => 'audio/ogg', - 'ogv' => 'video/ogg', - 'ogx' => 'application/ogg', - 'oda' => 'application/oda', - 'pbm' => 'image/x-portable-bitmap', - 'pdb' => 'chemical/x-pdb', - 'pdf' => 'application/pdf', - 'pgm' => 'image/x-portable-graymap', - 'pgn' => 'application/x-chess-pgn', - 'png' => 'image/png', - 'pnm' => 'image/x-portable-anymap', - 'pot' => 'application/mspowerpoint', - 'ppm' => 'image/x-portable-pixmap', - 'pps' => 'application/mspowerpoint', - 'ppt' => 'application/mspowerpoint', - 'ppz' => 'application/mspowerpoint', - 'pre' => 'application/x-freelance', - 'prt' => 'application/pro_eng', - 'ps' => 'application/postscript', - 'qt' => 'video/quicktime', - 'ra' => 'audio/x-realaudio', - 'ram' => 'audio/x-pn-realaudio', - 'ras' => 'image/cmu-raster', - 'rgb' => 'image/x-rgb', - 'rm' => 'audio/x-pn-realaudio', - 'roff' => 'application/x-troff', - 'rpm' => 'audio/x-pn-realaudio-plugin', - 'rtf' => 'text/rtf', - 'rtx' => 'text/richtext', - 'scm' => 'application/x-lotusscreencam', - 'set' => 'application/set', - 'sgm' => 'text/sgml', - 'sgml' => 'text/sgml', - 'sh' => 'application/x-sh', - 'shar' => 'application/x-shar', - 'silo' => 'model/mesh', - 'sit' => 'application/x-stuffit', - 'skd' => 'application/x-koan', - 'skm' => 'application/x-koan', - 'skp' => 'application/x-koan', - 'skt' => 'application/x-koan', - 'smi' => 'application/smil', - 'smil' => 'application/smil', - 'snd' => 'audio/basic', - 'sol' => 'application/solids', - 'spl' => 'application/x-futuresplash', - 'spx' => 'audio/ogg', - 'src' => 'application/x-wais-source', - 'step' => 'application/STEP', - 'stl' => 'application/SLA', - 'stp' => 'application/STEP', - 'sv4cpio' => 'application/x-sv4cpio', - 'sv4crc' => 'application/x-sv4crc', - 'swf' => 'application/x-shockwave-flash', - 't' => 'application/x-troff', - 'tar' => 'application/x-tar', - 'tcl' => 'application/x-tcl', - 'tex' => 'application/x-tex', - 'texi' => 'application/x-texinfo', - 'texinfo' => 'application/x-texinfo', - 'tif' => 'image/tiff', - 'tiff' => 'image/tiff', - 'tr' => 'application/x-troff', - 'tsi' => 'audio/TSP-audio', - 'tsp' => 'application/dsptype', - 'tsv' => 'text/tab-separated-values', - 'txt' => 'text/plain', - 'unv' => 'application/i-deas', - 'ustar' => 'application/x-ustar', - 'vcd' => 'application/x-cdlink', - 'vda' => 'application/vda', - 'viv' => 'video/vnd.vivo', - 'vivo' => 'video/vnd.vivo', - 'vrml' => 'model/vrml', - 'wav' => 'audio/x-wav', - 'wrl' => 'model/vrml', - 'xbm' => 'image/x-xbitmap', - 'xlc' => 'application/vnd.ms-excel', - 'xll' => 'application/vnd.ms-excel', - 'xlm' => 'application/vnd.ms-excel', - 'xls' => 'application/vnd.ms-excel', - 'xlw' => 'application/vnd.ms-excel', - 'xml' => 'application/xml', - 'xpm' => 'image/x-xpixmap', - 'xspf' => 'application/xspf+xml', - 'xwd' => 'image/x-xwindowdump', - 'xyz' => 'chemical/x-pdb', - 'zip' => 'application/zip', -]; diff --git a/framework/yii/i18n/DbMessageSource.php b/framework/yii/i18n/DbMessageSource.php deleted file mode 100644 index 9d43727..0000000 --- a/framework/yii/i18n/DbMessageSource.php +++ /dev/null @@ -1,158 +0,0 @@ - - * @since 2.0 - */ -class DbMessageSource extends MessageSource -{ - /** - * Prefix which would be used when generating cache key. - */ - const CACHE_KEY_PREFIX = 'DbMessageSource'; - - /** - * @var Connection|string the DB connection object or the application component ID of the DB connection. - * After the DbMessageSource object is created, if you want to change this property, you should only assign - * it with a DB connection object. - */ - public $db = 'db'; - /** - * @var Cache|string the cache object or the application component ID of the cache object. - * The messages data will be cached using this cache object. Note, this property has meaning only - * in case [[cachingDuration]] set to non-zero value. - * After the DbMessageSource object is created, if you want to change this property, you should only assign - * it with a cache object. - */ - public $cache = 'cache'; - /** - * @var string the name of the source message table. - */ - public $sourceMessageTable = '{{%source_message}}'; - /** - * @var string the name of the translated message table. - */ - public $messageTable = '{{%message}}'; - /** - * @var integer the time in seconds that the messages can remain valid in cache. - * Use 0 to indicate that the cached data will never expire. - * @see enableCaching - */ - public $cachingDuration = 0; - /** - * @var boolean whether to enable caching translated messages - */ - public $enableCaching = false; - - /** - * Initializes the DbMessageSource component. - * This method will initialize the [[db]] property to make sure it refers to a valid DB connection. - * Configured [[cache]] component would also be initialized. - * @throws InvalidConfigException if [[db]] is invalid or [[cache]] is invalid. - */ - public function init() - { - parent::init(); - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - } - if (!$this->db instanceof Connection) { - throw new InvalidConfigException("DbMessageSource::db must be either a DB connection instance or the application component ID of a DB connection."); - } - if ($this->enableCaching) { - if (is_string($this->cache)) { - $this->cache = Yii::$app->getComponent($this->cache); - } - if (!$this->cache instanceof Cache) { - throw new InvalidConfigException("DbMessageSource::cache must be either a cache object or the application component ID of the cache object."); - } - } - } - - /** - * Loads the message translation for the specified language and category. - * Child classes should override this method to return the message translations of - * the specified language and category. - * @param string $category the message category - * @param string $language the target language - * @return array the loaded messages. The keys are original messages, and the values - * are translated messages. - */ - protected function loadMessages($category, $language) - { - if ($this->enableCaching) { - $key = [ - __CLASS__, - $category, - $language, - ]; - $messages = $this->cache->get($key); - if ($messages === false) { - $messages = $this->loadMessagesFromDb($category, $language); - $this->cache->set($key, $messages, $this->cachingDuration); - } - return $messages; - } else { - return $this->loadMessagesFromDb($category, $language); - } - } - - /** - * Loads the messages from database. - * You may override this method to customize the message storage in the database. - * @param string $category the message category. - * @param string $language the target language. - * @return array the messages loaded from database. - */ - protected function loadMessagesFromDb($category, $language) - { - $query = new Query(); - $messages = $query->select(['t1.message message', 't2.translation translation']) - ->from([$this->sourceMessageTable . ' t1', $this->messageTable . ' t2']) - ->where('t1.id = t2.id AND t1.category = :category AND t2.language = :language') - ->params([':category' => $category, ':language' => $language]) - ->createCommand($this->db) - ->queryAll(); - return ArrayHelper::map($messages, 'message', 'translation'); - } -} diff --git a/framework/yii/i18n/Formatter.php b/framework/yii/i18n/Formatter.php deleted file mode 100644 index 0c83290..0000000 --- a/framework/yii/i18n/Formatter.php +++ /dev/null @@ -1,330 +0,0 @@ - [ - * 'class' => 'yii\i18n\Formatter', - * ] - * ``` - * - * @author Qiang Xue - * @since 2.0 - */ -class Formatter extends \yii\base\Formatter -{ - /** - * @var string the locale ID that is used to localize the date and number formatting. - * If not set, [[\yii\base\Application::language]] will be used. - */ - public $locale; - /** - * @var string|\IntlTimeZone|\DateTimeZone the timezone to use for formatting time and date values. - * This can be any value that may be passed to [date_default_timezone_set()](http://www.php.net/manual/en/function.date-default-timezone-set.php) - * e.g. `UTC`, `Europe/Berlin` or `America/Chicago`. - * Refer to the [php manual](http://www.php.net/manual/en/timezones.php) for available timezones. - * This can also be an IntlTimeZone or a DateTimeZone object. - * If not set, [[\yii\base\Application::timezone]] will be used. - */ - public $timeZone; - /** - * @var string the default format string to be used to format a date. - * This can be "short", "medium", "long", or "full", which represents a preset format of different lengths. - * It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime). - */ - public $dateFormat = 'short'; - /** - * @var string the default format string to be used to format a time. - * This can be "short", "medium", "long", or "full", which represents a preset format of different lengths. - * It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime). - */ - public $timeFormat = 'short'; - /** - * @var string the default format string to be used to format a date and time. - * This can be "short", "medium", "long", or "full", which represents a preset format of different lengths. - * It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime). - */ - public $datetimeFormat = 'short'; - /** - * @var array the options to be set for the NumberFormatter objects. Please refer to - * [PHP manual](http://php.net/manual/en/class.numberformatter.php#intl.numberformatter-constants.unumberformatattribute) - * for the possible options. This property is used by [[createNumberFormatter]] when - * creating a new number formatter to format decimals, currencies, etc. - */ - public $numberFormatOptions = []; - /** - * @var string the character displayed as the decimal point when formatting a number. - * If not set, the decimal separator corresponding to [[locale]] will be used. - */ - public $decimalSeparator; - /** - * @var string the character displayed as the thousands separator character when formatting a number. - * If not set, the thousand separator corresponding to [[locale]] will be used. - */ - public $thousandSeparator; - - - /** - * Initializes the component. - * This method will check if the "intl" PHP extension is installed and set the - * default value of [[locale]]. - * @throws InvalidConfigException if the "intl" PHP extension is not installed. - */ - public function init() - { - if (!extension_loaded('intl')) { - throw new InvalidConfigException('The "intl" PHP extension is not installed. It is required to format data values in localized formats.'); - } - if ($this->locale === null) { - $this->locale = Yii::$app->language; - } - if ($this->timeZone === null) { - $this->timeZone = Yii::$app->timeZone; - } - if ($this->decimalSeparator === null || $this->thousandSeparator === null) { - $formatter = new NumberFormatter($this->locale, NumberFormatter::DECIMAL); - if ($this->decimalSeparator === null) { - $this->decimalSeparator = $formatter->getSymbol(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL); - } - if ($this->thousandSeparator === null) { - $this->thousandSeparator = $formatter->getSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL); - } - } - - parent::init(); - } - - private $_dateFormats = [ - 'short' => IntlDateFormatter::SHORT, - 'medium' => IntlDateFormatter::MEDIUM, - 'long' => IntlDateFormatter::LONG, - 'full' => IntlDateFormatter::FULL, - ]; - - /** - * Formats the value as a date. - * @param integer|string|DateTime $value the value to be formatted. The following - * types of value are supported: - * - * - an integer representing a UNIX timestamp - * - a string that can be parsed into a UNIX timestamp via `strtotime()` - * - a PHP DateTime object - * - * @param string $format the format used to convert the value into a date string. - * If null, [[dateFormat]] will be used. - * - * This can be "short", "medium", "long", or "full", which represents a preset format of different lengths. - * It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime). - * - * @return string the formatted result - * @throws InvalidConfigException when formatting fails due to invalid parameters. - * @see dateFormat - */ - public function asDate($value, $format = null) - { - if ($value === null) { - return $this->nullDisplay; - } - $value = $this->normalizeDatetimeValue($value); - if ($format === null) { - $format = $this->dateFormat; - } - if (isset($this->_dateFormats[$format])) { - $formatter = new IntlDateFormatter($this->locale, $this->_dateFormats[$format], IntlDateFormatter::NONE, $this->timeZone); - } else { - $formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE, $this->timeZone); - if ($formatter !== null) { - $formatter->setPattern($format); - } - } - if ($formatter === null) { - throw new InvalidConfigException(intl_get_error_message()); - } - return $formatter->format($value); - } - - /** - * Formats the value as a time. - * @param integer|string|DateTime $value the value to be formatted. The following - * types of value are supported: - * - * - an integer representing a UNIX timestamp - * - a string that can be parsed into a UNIX timestamp via `strtotime()` - * - a PHP DateTime object - * - * @param string $format the format used to convert the value into a date string. - * If null, [[dateFormat]] will be used. - * - * This can be "short", "medium", "long", or "full", which represents a preset format of different lengths. - * It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime). - * - * @return string the formatted result - * @throws InvalidConfigException when formatting fails due to invalid parameters. - * @see timeFormat - */ - public function asTime($value, $format = null) - { - if ($value === null) { - return $this->nullDisplay; - } - $value = $this->normalizeDatetimeValue($value); - if ($format === null) { - $format = $this->timeFormat; - } - if (isset($this->_dateFormats[$format])) { - $formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, $this->_dateFormats[$format], $this->timeZone); - } else { - $formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE, $this->timeZone); - if ($formatter !== null) { - $formatter->setPattern($format); - } - } - if ($formatter === null) { - throw new InvalidConfigException(intl_get_error_message()); - } - return $formatter->format($value); - } - - /** - * Formats the value as a datetime. - * @param integer|string|DateTime $value the value to be formatted. The following - * types of value are supported: - * - * - an integer representing a UNIX timestamp - * - a string that can be parsed into a UNIX timestamp via `strtotime()` - * - a PHP DateTime object - * - * @param string $format the format used to convert the value into a date string. - * If null, [[dateFormat]] will be used. - * - * This can be "short", "medium", "long", or "full", which represents a preset format of different lengths. - * It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime). - * - * @return string the formatted result - * @throws InvalidConfigException when formatting fails due to invalid parameters. - * @see datetimeFormat - */ - public function asDatetime($value, $format = null) - { - if ($value === null) { - return $this->nullDisplay; - } - $value = $this->normalizeDatetimeValue($value); - if ($format === null) { - $format = $this->datetimeFormat; - } - if (isset($this->_dateFormats[$format])) { - $formatter = new IntlDateFormatter($this->locale, $this->_dateFormats[$format], $this->_dateFormats[$format], $this->timeZone); - } else { - $formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE, $this->timeZone); - if ($formatter !== null) { - $formatter->setPattern($format); - } - } - if ($formatter === null) { - throw new InvalidConfigException(intl_get_error_message()); - } - return $formatter->format($value); - } - - /** - * Formats the value as a decimal number. - * @param mixed $value the value to be formatted - * @param string $format the format to be used. Please refer to [ICU manual](http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details) - * for details on how to specify a format. - * @return string the formatted result. - */ - public function asDecimal($value, $format = null) - { - if ($value === null) { - return $this->nullDisplay; - } - return $this->createNumberFormatter(NumberFormatter::DECIMAL, $format)->format($value); - } - - /** - * Formats the value as a currency number. - * @param mixed $value the value to be formatted - * @param string $currency the 3-letter ISO 4217 currency code indicating the currency to use. - * @param string $format the format to be used. Please refer to [ICU manual](http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details) - * for details on how to specify a format. - * @return string the formatted result. - */ - public function asCurrency($value, $currency = 'USD', $format = null) - { - if ($value === null) { - return $this->nullDisplay; - } - return $this->createNumberFormatter(NumberFormatter::CURRENCY, $format)->formatCurrency($value, $currency); - } - - /** - * Formats the value as a percent number. - * @param mixed $value the value to be formatted - * @param string $format the format to be used. Please refer to [ICU manual](http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details) - * for details on how to specify a format. - * @return string the formatted result. - */ - public function asPercent($value, $format = null) - { - if ($value === null) { - return $this->nullDisplay; - } - return $this->createNumberFormatter(NumberFormatter::PERCENT, $format)->format($value); - } - - /** - * Formats the value as a scientific number. - * @param mixed $value the value to be formatted - * @param string $format the format to be used. Please refer to [ICU manual](http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details) - * for details on how to specify a format. - * @return string the formatted result. - */ - public function asScientific($value, $format = null) - { - if ($value === null) { - return $this->nullDisplay; - } - return $this->createNumberFormatter(NumberFormatter::SCIENTIFIC, $format)->format($value); - } - - /** - * Creates a number formatter based on the given type and format. - * @param integer $type the type of the number formatter - * @param string $format the format to be used. Please refer to [ICU manual](http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details) - * @return NumberFormatter the created formatter instance - */ - protected function createNumberFormatter($type, $format) - { - $formatter = new NumberFormatter($this->locale, $type); - if ($format !== null) { - $formatter->setPattern($format); - } - if (!empty($this->numberFormatOptions)) { - foreach ($this->numberFormatOptions as $name => $attribute) { - $formatter->setAttribute($name, $attribute); - } - } - return $formatter; - } -} diff --git a/framework/yii/i18n/GettextFile.php b/framework/yii/i18n/GettextFile.php deleted file mode 100644 index 03eecca..0000000 --- a/framework/yii/i18n/GettextFile.php +++ /dev/null @@ -1,37 +0,0 @@ - - * @since 2.0 - */ -abstract class GettextFile extends Component -{ - /** - * Loads messages from a file. - * @param string $filePath file path - * @param string $context message context - * @return array message translations. Array keys are source messages and array values are translated messages: - * source message => translated message. - */ - abstract public function load($filePath, $context); - - /** - * Saves messages to a file. - * @param string $filePath file path - * @param array $messages message translations. Array keys are source messages and array values are - * translated messages: source message => translated message. Note if the message has a context, - * the message ID must be prefixed with the context with chr(4) as the separator. - */ - abstract public function save($filePath, $messages); -} diff --git a/framework/yii/i18n/GettextMessageSource.php b/framework/yii/i18n/GettextMessageSource.php deleted file mode 100644 index 66704c4..0000000 --- a/framework/yii/i18n/GettextMessageSource.php +++ /dev/null @@ -1,85 +0,0 @@ - - * @since 2.0 - */ -class GettextMessageSource extends MessageSource -{ - const MO_FILE_EXT = '.mo'; - const PO_FILE_EXT = '.po'; - - /** - * @var string - */ - public $basePath = '@app/messages'; - /** - * @var string - */ - public $catalog = 'messages'; - /** - * @var boolean - */ - public $useMoFile = true; - /** - * @var boolean - */ - public $useBigEndian = false; - - /** - * Loads the message translation for the specified language and category. - * Child classes should override this method to return the message translations of - * the specified language and category. - * @param string $category the message category - * @param string $language the target language - * @return array the loaded messages. The keys are original messages, and the values - * are translated messages. - */ - protected function loadMessages($category, $language) - { - $messageFile = Yii::getAlias($this->basePath) . '/' . $language . '/' . $this->catalog; - if ($this->useMoFile) { - $messageFile .= static::MO_FILE_EXT; - } else { - $messageFile .= static::PO_FILE_EXT; - } - - if (is_file($messageFile)) { - if ($this->useMoFile) { - $gettextFile = new GettextMoFile(['useBigEndian' => $this->useBigEndian]); - } else { - $gettextFile = new GettextPoFile(); - } - $messages = $gettextFile->load($messageFile, $category); - if (!is_array($messages)) { - $messages = []; - } - return $messages; - } else { - Yii::error("The message file for category '$category' does not exist: $messageFile", __METHOD__); - return []; - } - } -} diff --git a/framework/yii/i18n/GettextMoFile.php b/framework/yii/i18n/GettextMoFile.php deleted file mode 100644 index b4a016d..0000000 --- a/framework/yii/i18n/GettextMoFile.php +++ /dev/null @@ -1,271 +0,0 @@ -. - * 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. - * - * 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. - * - * @author Qiang Xue - * @since 2.0 - */ -class GettextMoFile extends GettextFile -{ - /** - * @var boolean whether to use big-endian when reading and writing an integer. - */ - public $useBigEndian = false; - - /** - * Loads messages from an MO file. - * @param string $filePath file path - * @param string $context message context - * @return array message translations. Array keys are source messages and array values are translated messages: - * source message => translated message. - * @throws Exception if unable to read the MO file - */ - public function load($filePath, $context) - { - if (false === ($fileHandle = @fopen($filePath, 'rb'))) { - throw new Exception('Unable to read file "' . $filePath . '".'); - } - if (false === @flock($fileHandle, LOCK_SH)) { - throw new Exception('Unable to lock file "' . $filePath . '" for reading.'); - } - - // magic - $array = unpack('c', $this->readBytes($fileHandle, 4)); - $magic = current($array); - if ($magic == -34) { - $this->useBigEndian = false; - } elseif ($magic == -107) { - $this->useBigEndian = true; - } else { - throw new Exception('Invalid MO file: ' . $filePath . ' (magic: ' . $magic . ').'); - } - - // revision - $revision = $this->readInteger($fileHandle); - if ($revision != 0) { - throw new Exception('Invalid MO file revision: ' . $revision . '.'); - } - - $count = $this->readInteger($fileHandle); - $sourceOffset = $this->readInteger($fileHandle); - $targetOffset = $this->readInteger($fileHandle); - - $sourceLengths = []; - $sourceOffsets = []; - fseek($fileHandle, $sourceOffset); - for ($i = 0; $i < $count; ++$i) { - $sourceLengths[] = $this->readInteger($fileHandle); - $sourceOffsets[] = $this->readInteger($fileHandle); - } - - $targetLengths = []; - $targetOffsets = []; - fseek($fileHandle, $targetOffset); - for ($i = 0; $i < $count; ++$i) { - $targetLengths[] = $this->readInteger($fileHandle); - $targetOffsets[] = $this->readInteger($fileHandle); - } - - $messages = []; - for ($i = 0; $i < $count; ++$i) { - $id = $this->readString($fileHandle, $sourceLengths[$i], $sourceOffsets[$i]); - $separatorPosition = strpos($id, chr(4)); - - if (($context && $separatorPosition !== false && substr($id, 0, $separatorPosition) === $context) || - (!$context && $separatorPosition === false)) { - if ($separatorPosition !== false) { - $id = substr($id, $separatorPosition+1); - } - - $message = $this->readString($fileHandle, $targetLengths[$i], $targetOffsets[$i]); - $messages[$id] = $message; - } - } - - @flock($fileHandle, LOCK_UN); - @fclose($fileHandle); - return $messages; - } - - /** - * Saves messages to an MO file. - * @param string $filePath file path - * @param array $messages message translations. Array keys are source messages and array values are - * translated messages: source message => translated message. Note if the message has a context, - * the message ID must be prefixed with the context with chr(4) as the separator. - * @throws Exception if unable to save the MO file - */ - public function save($filePath, $messages) - { - if (false === ($fileHandle = @fopen($filePath, 'wb'))) { - throw new Exception('Unable to write file "' . $filePath . '".'); - } - if (false === @flock($fileHandle, LOCK_EX)) { - throw new Exception('Unable to lock file "' . $filePath . '" for reading.'); - } - - // magic - if ($this->useBigEndian) { - $this->writeBytes($fileHandle, pack('c*', 0x95, 0x04, 0x12, 0xde)); // -107 - } else { - $this->writeBytes($fileHandle, pack('c*', 0xde, 0x12, 0x04, 0x95)); // -34 - } - - // revision - $this->writeInteger($fileHandle, 0); - - // message count - $messageCount = count($messages); - $this->writeInteger($fileHandle, $messageCount); - - // offset of source message table - $offset = 28; - $this->writeInteger($fileHandle, $offset); - $offset += $messageCount * 8; - $this->writeInteger($fileHandle, $offset); - - // hashtable size, omitted - $this->writeInteger($fileHandle, 0); - $offset += $messageCount * 8; - $this->writeInteger($fileHandle, $offset); - - // length and offsets for source messages - foreach (array_keys($messages) as $id) { - $length = strlen($id); - $this->writeInteger($fileHandle, $length); - $this->writeInteger($fileHandle, $offset); - $offset += $length + 1; - } - - // length and offsets for target messages - foreach ($messages as $message) { - $length = strlen($message); - $this->writeInteger($fileHandle, $length); - $this->writeInteger($fileHandle, $offset); - $offset += $length + 1; - } - - // source messages - foreach (array_keys($messages) as $id) { - $this->writeString($fileHandle, $id); - } - - // target messages - foreach ($messages as $message) { - $this->writeString($fileHandle, $message); - } - - @flock($fileHandle, LOCK_UN); - @fclose($fileHandle); - } - - /** - * Reads one or several bytes. - * @param resource $fileHandle to read from - * @param integer $byteCount to be read - * @return string bytes - */ - protected function readBytes($fileHandle, $byteCount = 1) - { - if ($byteCount > 0) { - return fread($fileHandle, $byteCount); - } else { - return null; - } - } - - /** - * Write bytes. - * @param resource $fileHandle to write to - * @param string $bytes to be written - * @return integer how many bytes are written - */ - protected function writeBytes($fileHandle, $bytes) - { - return fwrite($fileHandle, $bytes); - } - - /** - * Reads a 4-byte integer. - * @param resource $fileHandle to read from - * @return integer the result - */ - protected function readInteger($fileHandle) - { - $array = unpack($this->useBigEndian ? 'N' : 'V', $this->readBytes($fileHandle, 4)); - return current($array); - } - - /** - * Writes a 4-byte integer. - * @param resource $fileHandle to write to - * @param integer $integer to be written - * @return integer how many bytes are written - */ - protected function writeInteger($fileHandle, $integer) - { - return $this->writeBytes($fileHandle, pack($this->useBigEndian ? 'N' : 'V', (int)$integer)); - } - - /** - * Reads a string. - * @param resource $fileHandle file handle - * @param integer $length of the string - * @param integer $offset of the string in the file. If null, it reads from the current position. - * @return string the result - */ - protected function readString($fileHandle, $length, $offset = null) - { - if ($offset !== null) { - fseek($fileHandle, $offset); - } - return $this->readBytes($fileHandle, $length); - } - - /** - * Writes a string. - * @param resource $fileHandle to write to - * @param string $string to be written - * @return integer how many bytes are written - */ - protected function writeString($fileHandle, $string) - { - return $this->writeBytes($fileHandle, $string. "\0"); - } -} diff --git a/framework/yii/i18n/GettextPoFile.php b/framework/yii/i18n/GettextPoFile.php deleted file mode 100644 index 8fb618c..0000000 --- a/framework/yii/i18n/GettextPoFile.php +++ /dev/null @@ -1,97 +0,0 @@ - - * @since 2.0 - */ -class GettextPoFile extends GettextFile -{ - /** - * Loads messages from a PO file. - * @param string $filePath file path - * @param string $context message context - * @return array message translations. Array keys are source messages and array values are translated messages: - * source message => translated message. - */ - public function load($filePath, $context) - { - $pattern = '/(msgctxt\s+"(.*?(?decode($matches[3][$i]); - $message = $this->decode($matches[4][$i]); - $messages[$id] = $message; - } - } - return $messages; - } - - /** - * Saves messages to a PO file. - * @param string $filePath file path - * @param array $messages message translations. Array keys are source messages and array values are - * translated messages: source message => translated message. Note if the message has a context, - * the message ID must be prefixed with the context with chr(4) as the separator. - */ - public function save($filePath, $messages) - { - $content = ''; - foreach ($messages as $id => $message) { - $separatorPosition = strpos($id, chr(4)); - if ($separatorPosition !== false) { - $content .= 'msgctxt "' . substr($id, 0, $separatorPosition) . "\"\n"; - $id = substr($id, $separatorPosition + 1); - } - $content .= 'msgid "' . $this->encode($id) . "\"\n"; - $content .= 'msgstr "' . $this->encode($message) . "\"\n\n"; - } - file_put_contents($filePath, $content); - } - - /** - * Encodes special characters in a message. - * @param string $string message to be encoded - * @return string the encoded message - */ - protected function encode($string) - { - return str_replace( - ['"', "\n", "\t", "\r"], - ['\\"', '\\n', '\\t', '\\r'], - $string - ); - } - - /** - * Decodes special characters in a message. - * @param string $string message to be decoded - * @return string the decoded message - */ - protected function decode($string) - { - $string = preg_replace( - ['/"\s+"/', '/\\\\n/', '/\\\\r/', '/\\\\t/', '/\\\\"/'], - ['', "\n", "\r", "\t", '"'], - $string - ); - return substr(rtrim($string), 1, -1); - } -} diff --git a/framework/yii/i18n/I18N.php b/framework/yii/i18n/I18N.php deleted file mode 100644 index 7123342..0000000 --- a/framework/yii/i18n/I18N.php +++ /dev/null @@ -1,185 +0,0 @@ -i18n`. - * - * @property MessageFormatter $messageFormatter The message formatter to be used to format message via ICU - * message format. Note that the type of this property differs in getter and setter. See - * [[getMessageFormatter()]] and [[setMessageFormatter()]] for details. - * - * @author Qiang Xue - * @since 2.0 - */ -class I18N extends Component -{ - /** - * @var array list of [[MessageSource]] configurations or objects. The array keys are message - * categories, and the array values are the corresponding [[MessageSource]] objects or the configurations - * for creating the [[MessageSource]] objects. The message categories can contain the wildcard '*' at the end - * to match multiple categories with the same prefix. For example, 'app\*' matches both 'app\cat1' and 'app\cat2'. - * - * This property may be modified on the fly by extensions who want to have their own message sources - * registered under their own namespaces. - * - * The category "yii" and "app" are always defined. The former refers to the messages used in the Yii core - * framework code, while the latter refers to the default message category for custom application code. - * By default, both of these categories use [[PhpMessageSource]] and the corresponding message files are - * stored under "@yii/messages" and "@app/messages", respectively. - * - * You may override the configuration of both categories. - */ - public $translations; - - /** - * Initializes the component by configuring the default message categories. - */ - public function init() - { - parent::init(); - if (!isset($this->translations['yii'])) { - $this->translations['yii'] = [ - 'class' => 'yii\i18n\PhpMessageSource', - 'sourceLanguage' => 'en-US', - 'basePath' => '@yii/messages', - ]; - } - if (!isset($this->translations['app'])) { - $this->translations['app'] = [ - 'class' => 'yii\i18n\PhpMessageSource', - 'sourceLanguage' => 'en-US', - 'basePath' => '@app/messages', - ]; - } - } - - /** - * Translates a message to the specified language. - * - * After translation the message will be formatted using [[MessageFormatter]] if it contains - * ICU message format and `$params` are not empty. - * - * @param string $category the message category. - * @param string $message the message to be translated. - * @param array $params the parameters that will be used to replace the corresponding placeholders in the message. - * @param string $language the language code (e.g. `en-US`, `en`). - * @return string the translated and formatted message. - */ - public function translate($category, $message, $params, $language) - { - $message = $this->getMessageSource($category)->translate($category, $message, $language); - return $this->format($message, $params, $language); - } - - /** - * Formats a message using [[MessageFormatter]]. - * - * @param string $message the message to be formatted. - * @param array $params the parameters that will be used to replace the corresponding placeholders in the message. - * @param string $language the language code (e.g. `en-US`, `en`). - * @return string the formatted message. - */ - public function format($message, $params, $language) - { - if ($params instanceof Arrayable) { - $params = $params->toArray(); - } else { - $params = (array)$params; - } - if ($params === []) { - return $message; - } - - if (preg_match('~{\s*[\d\w]+\s*,~u', $message)) { - $formatter = $this->getMessageFormatter(); - $result = $formatter->format($message, $params, $language); - if ($result === false) { - $errorMessage = $formatter->getErrorMessage(); - Yii::warning("Formatting message for language '$language' failed with error: $errorMessage. The message being formatted was: $message."); - return $message; - } else { - return $result; - } - } - - $p = []; - foreach($params as $name => $value) { - $p['{' . $name . '}'] = $value; - } - return strtr($message, $p); - } - - /** - * @var string|array|MessageFormatter - */ - private $_messageFormatter; - - /** - * Returns the message formatter instance. - * @return MessageFormatter the message formatter to be used to format message via ICU message format. - */ - public function getMessageFormatter() - { - if ($this->_messageFormatter === null) { - $this->_messageFormatter = new MessageFormatter(); - } elseif (is_array($this->_messageFormatter) || is_string($this->_messageFormatter)) { - $this->_messageFormatter = Yii::createObject($this->_messageFormatter); - } - return $this->_messageFormatter; - } - - /** - * @param string|array|MessageFormatter $value the message formatter to be used to format message via ICU message format. - * Can be given as array or string configuration that will be given to [[Yii::createObject]] to create an instance - * or a [[MessageFormatter]] instance. - */ - public function setMessageFormatter($value) - { - $this->_messageFormatter = $value; - } - - /** - * Returns the message source for the given category. - * @param string $category the category name. - * @return MessageSource the message source for the given category. - * @throws InvalidConfigException if there is no message source available for the specified category. - */ - public function getMessageSource($category) - { - if (isset($this->translations[$category])) { - $source = $this->translations[$category]; - if ($source instanceof MessageSource) { - return $source; - } else { - return $this->translations[$category] = Yii::createObject($source); - } - } else { - // try wildcard matching - foreach ($this->translations as $pattern => $config) { - if ($pattern === '*' || substr($pattern, -1) === '*' && strpos($category, rtrim($pattern, '*')) === 0) { - if ($config instanceof MessageSource) { - return $config; - } else { - return $this->translations[$category] = $this->translations[$pattern] = Yii::createObject($config); - } - } - } - } - - throw new InvalidConfigException("Unable to locate message source for category '$category'."); - } -} diff --git a/framework/yii/i18n/MessageFormatter.php b/framework/yii/i18n/MessageFormatter.php deleted file mode 100644 index 43aebdd..0000000 --- a/framework/yii/i18n/MessageFormatter.php +++ /dev/null @@ -1,396 +0,0 @@ - - * @author Carsten Brandt - * @since 2.0 - */ -class MessageFormatter extends Component -{ - private $_errorCode = 0; - private $_errorMessage = ''; - - /** - * Get the error code from the last operation - * @link http://php.net/manual/en/messageformatter.geterrorcode.php - * @return string Code of the last error. - */ - public function getErrorCode() - { - return $this->_errorCode; - } - - /** - * Get the error text from the last operation - * @link http://php.net/manual/en/messageformatter.geterrormessage.php - * @return string Description of the last error. - */ - public function getErrorMessage() - { - return $this->_errorMessage; - } - - /** - * Formats a message via [ICU message format](http://userguide.icu-project.org/formatparse/messages) - * - * It uses the PHP intl extension's [MessageFormatter](http://www.php.net/manual/en/class.messageformatter.php) - * and works around some issues. - * If PHP intl is not installed a fallback will be used that supports a subset of the ICU message format. - * - * @param string $pattern The pattern string to insert parameters into. - * @param array $params The array of name value pairs to insert into the format string. - * @param string $language The locale to use for formatting locale-dependent parts - * @return string|boolean The formatted pattern string or `FALSE` if an error occurred - */ - public function format($pattern, $params, $language) - { - $this->_errorCode = 0; - $this->_errorMessage = ''; - - if ($params === []) { - return $pattern; - } - - if (!class_exists('MessageFormatter', false)) { - return $this->fallbackFormat($pattern, $params, $language); - } - - if (version_compare(PHP_VERSION, '5.5.0', '<') || version_compare(INTL_ICU_VERSION, '4.8', '<')) { - // replace named arguments - $pattern = $this->replaceNamedArguments($pattern, $params, $newParams); - $params = $newParams; - } - - $formatter = new \MessageFormatter($language, $pattern); - if ($formatter === null) { - $this->_errorCode = intl_get_error_code(); - $this->_errorMessage = "Message pattern is invalid: " . intl_get_error_message(); - return false; - } - $result = $formatter->format($params); - if ($result === false) { - $this->_errorCode = $formatter->getErrorCode(); - $this->_errorMessage = $formatter->getErrorMessage(); - return false; - } else { - return $result; - } - } - - /** - * Parses an input string according to an [ICU message format](http://userguide.icu-project.org/formatparse/messages) pattern. - * - * It uses the PHP intl extension's [MessageFormatter::parse()](http://www.php.net/manual/en/messageformatter.parsemessage.php) - * and adds support for named arguments. - * Usage of this method requires PHP intl extension to be installed. - * - * @param string $pattern The pattern to use for parsing the message. - * @param string $message The message to parse, conforming to the pattern. - * @param string $language The locale to use for formatting locale-dependent parts - * @return array|boolean An array containing items extracted, or `FALSE` on error. - * @throws \yii\base\NotSupportedException when PHP intl extension is not installed. - */ - public function parse($pattern, $message, $language) - { - $this->_errorCode = 0; - $this->_errorMessage = ''; - - if (!class_exists('MessageFormatter', false)) { - throw new NotSupportedException('You have to install PHP intl extension to use this feature.'); - } - - // replace named arguments - if (($tokens = $this->tokenizePattern($pattern)) === false) { - $this->_errorCode = -1; - $this->_errorMessage = "Message pattern is invalid."; - return false; - } - $map = []; - foreach($tokens as $i => $token) { - if (is_array($token)) { - $param = trim($token[0]); - if (!isset($map[$param])) { - $map[$param] = count($map); - } - $token[0] = $map[$param]; - $tokens[$i] = '{' . implode(',', $token) . '}'; - } - } - $pattern = implode('', $tokens); - $map = array_flip($map); - - $formatter = new \MessageFormatter($language, $pattern); - if ($formatter === null) { - $this->_errorCode = -1; - $this->_errorMessage = "Message pattern is invalid."; - return false; - } - $result = $formatter->parse($message); - if ($result === false) { - $this->_errorCode = $formatter->getErrorCode(); - $this->_errorMessage = $formatter->getErrorMessage(); - return false; - } else { - $values = []; - foreach($result as $key => $value) { - $values[$map[$key]] = $value; - } - return $values; - } - } - - /** - * Replace named placeholders with numeric placeholders and quote unused. - * - * @param string $pattern The pattern string to replace things into. - * @param array $args The array of values to insert into the format string. - * @return string The pattern string with placeholders replaced. - */ - private function replaceNamedArguments($pattern, $givenParams, &$resultingParams, &$map = []) - { - if (($tokens = $this->tokenizePattern($pattern)) === false) { - return false; - } - foreach($tokens as $i => $token) { - if (!is_array($token)) { - continue; - } - $param = trim($token[0]); - if (isset($givenParams[$param])) { - // if param is given, replace it with a number - if (!isset($map[$param])) { - $map[$param] = count($map); - // make sure only used params are passed to format method - $resultingParams[$map[$param]] = $givenParams[$param]; - } - $token[0] = $map[$param]; - $quote = ""; - } else { - // quote unused token - $quote = "'"; - } - $type = isset($token[1]) ? trim($token[1]) : 'none'; - // replace plural and select format recursively - if ($type == 'plural' || $type == 'select') { - if (!isset($token[2])) { - return false; - } - $subtokens = $this->tokenizePattern($token[2]); - $c = count($subtokens); - for ($k = 0; $k + 1 < $c; $k++) { - if (is_array($subtokens[$k]) || !is_array($subtokens[++$k])) { - return false; - } - $subpattern = $this->replaceNamedArguments(implode(',', $subtokens[$k]), $givenParams, $resultingParams, $map); - $subtokens[$k] = $quote . '{' . $quote . $subpattern . $quote . '}' . $quote; - } - $token[2] = implode('', $subtokens); - } - $tokens[$i] = $quote . '{' . $quote . implode(',', $token) . $quote . '}' . $quote; - } - return implode('', $tokens); - } - - /** - * Fallback implementation for MessageFormatter::formatMessage - * @param string $pattern The pattern string to insert things into. - * @param array $args The array of values to insert into the format string - * @param string $locale The locale to use for formatting locale-dependent parts - * @return string|boolean The formatted pattern string or `FALSE` if an error occurred - */ - protected function fallbackFormat($pattern, $args, $locale) - { - if (($tokens = $this->tokenizePattern($pattern)) === false) { - $this->_errorCode = -1; - $this->_errorMessage = "Message pattern is invalid."; - return false; - } - foreach($tokens as $i => $token) { - if (is_array($token)) { - if (($tokens[$i] = $this->parseToken($token, $args, $locale)) === false) { - $this->_errorCode = -1; - $this->_errorMessage = "Message pattern is invalid."; - return false; - } - } - } - return implode('', $tokens); - } - - /** - * Tokenizes a pattern by separating normal text from replaceable patterns - * @param string $pattern patter to tokenize - * @return array|bool array of tokens or false on failure - */ - private function tokenizePattern($pattern) - { - $depth = 1; - if (($start = $pos = mb_strpos($pattern, '{')) === false) { - return [$pattern]; - } - $tokens = [mb_substr($pattern, 0, $pos)]; - while (true) { - $open = mb_strpos($pattern, '{', $pos + 1); - $close = mb_strpos($pattern, '}', $pos + 1); - if ($open === false && $close === false) { - break; - } - if ($open === false) { - $open = mb_strlen($pattern); - } - if ($close > $open) { - $depth++; - $pos = $open; - } else { - $depth--; - $pos = $close; - } - if ($depth == 0) { - $tokens[] = explode(',', mb_substr($pattern, $start + 1, $pos - $start - 1), 3); - $start = $pos + 1; - $tokens[] = mb_substr($pattern, $start, $open - $start); - $start = $open; - } - } - if ($depth != 0) { - return false; - } - return $tokens; - } - - /** - * Parses a token - * @param array $token the token to parse - * @param array $args arguments to replace - * @param string $locale the locale - * @return bool|string parsed token or false on failure - * @throws \yii\base\NotSupportedException when unsupported formatting is used. - */ - private function parseToken($token, $args, $locale) - { - // parsing pattern based on ICU grammar: - // http://icu-project.org/apiref/icu4c/classMessageFormat.html#details - - $param = trim($token[0]); - if (isset($args[$param])) { - $arg = $args[$param]; - } else { - return '{' . implode(',', $token) . '}'; - } - $type = isset($token[1]) ? trim($token[1]) : 'none'; - switch($type) - { - case 'date': - case 'time': - case 'spellout': - case 'ordinal': - case 'duration': - case 'choice': - case 'selectordinal': - throw new NotSupportedException("Message format '$type' is not supported. You have to install PHP intl extension to use this feature."); - case 'number': - if (is_int($arg) && (!isset($token[2]) || trim($token[2]) == 'integer')) { - return $arg; - } - throw new NotSupportedException("Message format 'number' is only supported for integer values. You have to install PHP intl extension to use this feature."); - case 'none': return $arg; - case 'select': - /* http://icu-project.org/apiref/icu4c/classicu_1_1SelectFormat.html - selectStyle = (selector '{' message '}')+ - */ - if (!isset($token[2])) { - return false; - } - $select = static::tokenizePattern($token[2]); - $c = count($select); - $message = false; - for ($i = 0; $i + 1 < $c; $i++) { - if (is_array($select[$i]) || !is_array($select[$i + 1])) { - return false; - } - $selector = trim($select[$i++]); - if ($message === false && $selector == 'other' || $selector == $arg) { - $message = implode(',', $select[$i]); - } - } - if ($message !== false) { - return $this->fallbackFormat($message, $args, $locale); - } - break; - case 'plural': - /* http://icu-project.org/apiref/icu4c/classicu_1_1PluralFormat.html - pluralStyle = [offsetValue] (selector '{' message '}')+ - offsetValue = "offset:" number - selector = explicitValue | keyword - explicitValue = '=' number // adjacent, no white space in between - keyword = [^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+ - message: see MessageFormat - */ - if (!isset($token[2])) { - return false; - } - $plural = static::tokenizePattern($token[2]); - $c = count($plural); - $message = false; - $offset = 0; - for ($i = 0; $i + 1 < $c; $i++) { - if (is_array($plural[$i]) || !is_array($plural[$i + 1])) { - return false; - } - $selector = trim($plural[$i++]); - if ($i == 1 && substr($selector, 0, 7) == 'offset:') { - $offset = (int) trim(mb_substr($selector, 7, ($pos = mb_strpos(str_replace(["\n", "\r", "\t"], ' ', $selector), ' ', 7)) - 7)); - $selector = trim(mb_substr($selector, $pos + 1)); - } - if ($message === false && $selector == 'other' || - $selector[0] == '=' && (int) mb_substr($selector, 1) == $arg || - $selector == 'one' && $arg - $offset == 1 - ) { - $message = implode(',', str_replace('#', $arg - $offset, $plural[$i])); - } - } - if ($message !== false) { - return $this->fallbackFormat($message, $args, $locale); - } - break; - } - return false; - } -} diff --git a/framework/yii/i18n/MessageSource.php b/framework/yii/i18n/MessageSource.php deleted file mode 100644 index 07871bb..0000000 --- a/framework/yii/i18n/MessageSource.php +++ /dev/null @@ -1,120 +0,0 @@ - - * @since 2.0 - */ -class MessageSource extends Component -{ - /** - * @event MissingTranslationEvent an event that is triggered when a message translation is not found. - */ - const EVENT_MISSING_TRANSLATION = 'missingTranslation'; - - /** - * @var boolean whether to force message translation when the source and target languages are the same. - * Defaults to false, meaning translation is only performed when source and target languages are different. - */ - public $forceTranslation = false; - /** - * @var string the language that the original messages are in. If not set, it will use the value of - * [[\yii\base\Application::sourceLanguage]]. - */ - public $sourceLanguage; - - private $_messages = []; - - /** - * Initializes this component. - */ - public function init() - { - parent::init(); - if ($this->sourceLanguage === null) { - $this->sourceLanguage = Yii::$app->sourceLanguage; - } - } - - /** - * Loads the message translation for the specified language and category. - * Child classes should override this method to return the message translations of - * the specified language and category. - * @param string $category the message category - * @param string $language the target language - * @return array the loaded messages. The keys are original messages, and the values - * are translated messages. - */ - protected function loadMessages($category, $language) - { - return []; - } - - /** - * Translates a message to the specified language. - * - * Note that unless [[forceTranslation]] is true, if the target language - * is the same as the [[sourceLanguage|source language]], the message - * will NOT be translated. - * - * If a translation is not found, a [[missingTranslation]] event will be triggered. - * - * @param string $category the message category - * @param string $message the message to be translated - * @param string $language the target language - * @return string the translated message (or the original message if translation is not needed) - */ - public function translate($category, $message, $language) - { - if ($this->forceTranslation || $language !== $this->sourceLanguage) { - return $this->translateMessage($category, $message, $language); - } else { - return $message; - } - } - - /** - * Translates the specified message. - * If the message is not found, a [[missingTranslation]] event will be triggered - * and the original message will be returned. - * @param string $category the category that the message belongs to - * @param string $message the message to be translated - * @param string $language the target language - * @return string the translated message - */ - protected function translateMessage($category, $message, $language) - { - $key = $language . '/' . $category; - if (!isset($this->_messages[$key])) { - $this->_messages[$key] = $this->loadMessages($category, $language); - } - if (isset($this->_messages[$key][$message]) && $this->_messages[$key][$message] !== '') { - return $this->_messages[$key][$message]; - } elseif ($this->hasEventHandlers(self::EVENT_MISSING_TRANSLATION)) { - $event = new MissingTranslationEvent([ - 'category' => $category, - 'message' => $message, - 'language' => $language, - ]); - $this->trigger(self::EVENT_MISSING_TRANSLATION, $event); - return $this->_messages[$key] = $event->message; - } else { - return $message; - } - } -} diff --git a/framework/yii/i18n/MissingTranslationEvent.php b/framework/yii/i18n/MissingTranslationEvent.php deleted file mode 100644 index 7a22d48..0000000 --- a/framework/yii/i18n/MissingTranslationEvent.php +++ /dev/null @@ -1,33 +0,0 @@ - - * @since 2.0 - */ -class MissingTranslationEvent extends Event -{ - /** - * @var string the message to be translated. An event handler may overwrite this property - * with a translated version if possible. - */ - public $message; - /** - * @var string the category that the message belongs to - */ - public $category; - /** - * @var string the language ID (e.g. en-US) that the message is to be translated to - */ - public $language; -} diff --git a/framework/yii/i18n/PhpMessageSource.php b/framework/yii/i18n/PhpMessageSource.php deleted file mode 100644 index e105083..0000000 --- a/framework/yii/i18n/PhpMessageSource.php +++ /dev/null @@ -1,79 +0,0 @@ - 'translated message 1', - * 'original message 2' => 'translated message 2', - * ]; - * ~~~ - * - * You may use [[fileMap]] to customize the association between category names and the file names. - * - * @author Qiang Xue - * @since 2.0 - */ -class PhpMessageSource extends MessageSource -{ - /** - * @var string the base path for all translated messages. Defaults to null, meaning - * the "messages" subdirectory of the application directory (e.g. "protected/messages"). - */ - public $basePath = '@app/messages'; - /** - * @var array mapping between message categories and the corresponding message file paths. - * The file paths are relative to [[basePath]]. For example, - * - * ~~~ - * [ - * 'core' => 'core.php', - * 'ext' => 'extensions.php', - * ] - * ~~~ - */ - public $fileMap; - - /** - * Loads the message translation for the specified language and category. - * @param string $category the message category - * @param string $language the target language - * @return array the loaded messages - */ - protected function loadMessages($category, $language) - { - $messageFile = Yii::getAlias($this->basePath) . "/$language/"; - if (isset($this->fileMap[$category])) { - $messageFile .= $this->fileMap[$category]; - } else { - $messageFile .= str_replace('\\', '/', $category) . '.php'; - } - if (is_file($messageFile)) { - $messages = include($messageFile); - if (!is_array($messages)) { - $messages = []; - } - return $messages; - } else { - Yii::error("The message file for category '$category' does not exist: $messageFile", __METHOD__); - return []; - } - } -} diff --git a/framework/yii/log/DbTarget.php b/framework/yii/log/DbTarget.php deleted file mode 100644 index 59eedc6..0000000 --- a/framework/yii/log/DbTarget.php +++ /dev/null @@ -1,91 +0,0 @@ - - * @since 2.0 - */ -class DbTarget extends Target -{ - /** - * @var Connection|string the DB connection object or the application component ID of the DB connection. - * After the DbTarget object is created, if you want to change this property, you should only assign it - * with a DB connection object. - */ - public $db = 'db'; - /** - * @var string name of the DB table to store cache content. - * The table should be pre-created as follows: - * - * ~~~ - * CREATE TABLE tbl_log ( - * id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, - * level INTEGER, - * category VARCHAR(255), - * log_time INTEGER, - * message TEXT, - * INDEX idx_log_level (level), - * INDEX idx_log_category (category) - * ) - * ~~~ - * - * Note that the 'id' column must be created as an auto-incremental column. - * The above SQL uses the MySQL syntax. If you are using other DBMS, you need - * to adjust it accordingly. For example, in PostgreSQL, it should be `id SERIAL PRIMARY KEY`. - * - * The indexes declared above are not required. They are mainly used to improve the performance - * of some queries about message levels and categories. Depending on your actual needs, you may - * want to create additional indexes (e.g. index on `log_time`). - */ - public $logTable = '{{%log}}'; - - /** - * Initializes the DbTarget component. - * This method will initialize the [[db]] property to make sure it refers to a valid DB connection. - * @throws InvalidConfigException if [[db]] is invalid. - */ - public function init() - { - parent::init(); - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - } - if (!$this->db instanceof Connection) { - throw new InvalidConfigException("DbTarget::db must be either a DB connection instance or the application component ID of a DB connection."); - } - } - - /** - * Stores log messages to DB. - */ - public function export() - { - $tableName = $this->db->quoteTableName($this->logTable); - $sql = "INSERT INTO $tableName ([[level]], [[category]], [[log_time]], [[message]]) - VALUES (:level, :category, :log_time, :message)"; - $command = $this->db->createCommand($sql); - foreach ($this->messages as $message) { - $command->bindValues([ - ':level' => $message[1], - ':category' => $message[2], - ':log_time' => $message[3], - ':message' => $message[0], - ])->execute(); - } - } -} diff --git a/framework/yii/log/EmailTarget.php b/framework/yii/log/EmailTarget.php deleted file mode 100644 index c4e936a..0000000 --- a/framework/yii/log/EmailTarget.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @since 2.0 - */ -class EmailTarget extends Target -{ - /** - * @var array the configuration array for creating a [[\yii\mail\MessageInterface|message]] object. - * Note that the "to" option must be set, which specifies the destination email address(es). - */ - public $message = []; - /** - * @var MailerInterface|string the mailer object or the application component ID of the mailer object. - * After the EmailTarget object is created, if you want to change this property, you should only assign it - * with a mailer object. - */ - public $mail = 'mail'; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if (empty($this->message['to'])) { - throw new InvalidConfigException('The "to" option must be set for EmailTarget::message.'); - } - if (is_string($this->mail)) { - $this->mail = Yii::$app->getComponent($this->mail); - } - if (!$this->mail instanceof MailerInterface) { - throw new InvalidConfigException("EmailTarget::mailer must be either a mailer object or the application component ID of a mailer object."); - } - } - - /** - * Sends log messages to specified email addresses. - */ - public function export() - { - // moved initialization of subject here because of the following issue - // https://github.com/yiisoft/yii2/issues/1446 - if (empty($this->message['subject'])) { - $this->message['subject'] = 'Application Log'; - } - $messages = array_map([$this, 'formatMessage'], $this->messages); - $body = wordwrap(implode("\n", $messages), 70); - $this->composeMessage($body)->send($this->mail); - } - - /** - * Composes a mail message with the given body content. - * @param string $body the body content - * @return \yii\mail\MessageInterface $message - */ - protected function composeMessage($body) - { - $message = $this->mail->compose(); - Yii::configure($message, $this->message); - $message->setTextBody($body); - return $message; - } -} diff --git a/framework/yii/log/FileTarget.php b/framework/yii/log/FileTarget.php deleted file mode 100644 index 4382aa5..0000000 --- a/framework/yii/log/FileTarget.php +++ /dev/null @@ -1,127 +0,0 @@ - - * @since 2.0 - */ -class FileTarget extends Target -{ - /** - * @var string log file path or path alias. If not set, it will use the "runtime/logs/app.log" file. - * The directory containing the log files will be automatically created if not existing. - */ - public $logFile; - /** - * @var integer maximum log file size, in kilo-bytes. Defaults to 10240, meaning 10MB. - */ - public $maxFileSize = 10240; // in KB - /** - * @var integer number of log files used for rotation. Defaults to 5. - */ - public $maxLogFiles = 5; - /** - * @var integer the permission to be set for newly created log files. - * This value will be used by PHP chmod() function. No umask will be applied. - * If not set, the permission will be determined by the current environment. - */ - public $fileMode; - /** - * @var integer the permission to be set for newly created directories. - * This value will be used by PHP chmod() function. No umask will be applied. - * Defaults to 0775, meaning the directory is read-writable by owner and group, - * but read-only for other users. - */ - public $dirMode = 0775; - - - /** - * Initializes the route. - * This method is invoked after the route is created by the route manager. - */ - public function init() - { - parent::init(); - if ($this->logFile === null) { - $this->logFile = Yii::$app->getRuntimePath() . '/logs/app.log'; - } else { - $this->logFile = Yii::getAlias($this->logFile); - } - $logPath = dirname($this->logFile); - if (!is_dir($logPath)) { - FileHelper::createDirectory($logPath, $this->dirMode, true); - } - if ($this->maxLogFiles < 1) { - $this->maxLogFiles = 1; - } - if ($this->maxFileSize < 1) { - $this->maxFileSize = 1; - } - } - - /** - * Writes log messages to a file. - * @throws InvalidConfigException if unable to open the log file for writing - */ - public function export() - { - $text = implode("\n", array_map([$this, 'formatMessage'], $this->messages)) . "\n"; - if (($fp = @fopen($this->logFile, 'a')) === false) { - throw new InvalidConfigException("Unable to append to log file: {$this->logFile}"); - } - @flock($fp, LOCK_EX); - if (@filesize($this->logFile) > $this->maxFileSize * 1024) { - $this->rotateFiles(); - @flock($fp, LOCK_UN); - @fclose($fp); - @file_put_contents($this->logFile, $text, FILE_APPEND | LOCK_EX); - } else { - @fwrite($fp, $text); - @flock($fp, LOCK_UN); - @fclose($fp); - } - if ($this->fileMode !== null) { - @chmod($this->logFile, $this->fileMode); - } - } - - /** - * Rotates log files. - */ - protected function rotateFiles() - { - $file = $this->logFile; - for ($i = $this->maxLogFiles; $i > 0; --$i) { - $rotateFile = $file . '.' . $i; - if (is_file($rotateFile)) { - // suppress errors because it's possible multiple processes enter into this section - if ($i === $this->maxLogFiles) { - @unlink($rotateFile); - } else { - @rename($rotateFile, $file . '.' . ($i + 1)); - } - } - } - if (is_file($file)) { - @rename($file, $file . '.1'); // suppress errors because it's possible multiple processes enter into this section - } - } -} diff --git a/framework/yii/log/Logger.php b/framework/yii/log/Logger.php deleted file mode 100644 index e7c639c..0000000 --- a/framework/yii/log/Logger.php +++ /dev/null @@ -1,355 +0,0 @@ -log`. - * You can call the method [[log()]] to record a single log message. For convenience, a set of shortcut - * methods are provided for logging messages of various severity levels via the [[Yii]] class: - * - * - [[Yii::trace()]] - * - [[Yii::error()]] - * - [[Yii::warning()]] - * - [[Yii::info()]] - * - [[Yii::beginProfile()]] - * - [[Yii::endProfile()]] - * - * When enough messages are accumulated in the logger, or when the current request finishes, - * the logged messages will be sent to different [[targets]], such as log files, emails. - * - * You may configure the targets in application configuration, like the following: - * - * ~~~ - * [ - * 'components' => [ - * 'log' => [ - * 'targets' => [ - * 'file' => [ - * 'class' => 'yii\log\FileTarget', - * 'levels' => ['trace', 'info'], - * 'categories' => ['yii\*'], - * ], - * 'email' => [ - * 'class' => 'yii\log\EmailTarget', - * 'levels' => ['error', 'warning'], - * 'message' => [ - * 'to' => 'admin@example.com', - * ], - * ], - * ], - * ], - * ], - * ] - * ~~~ - * - * Each log target can have a name and can be referenced via the [[targets]] property - * as follows: - * - * ~~~ - * Yii::$app->log->targets['file']->enabled = false; - * ~~~ - * - * When the application ends or [[flushInterval]] is reached, Logger will call [[flush()]] - * to send logged messages to different log targets, such as file, email, Web. - * - * @property array $dbProfiling The first element indicates the number of SQL statements executed, and the - * second element the total time spent in SQL execution. This property is read-only. - * @property float $elapsedTime The total elapsed time in seconds for current request. This property is - * read-only. - * @property array $profiling The profiling results. Each array element has the following structure: `[$token, - * $category, $time]`. This property is read-only. - * - * @author Qiang Xue - * @since 2.0 - */ -class Logger extends Component -{ - /** - * Error message level. An error message is one that indicates the abnormal termination of the - * application and may require developer's handling. - */ - const LEVEL_ERROR = 0x01; - /** - * Warning message level. A warning message is one that indicates some abnormal happens but - * the application is able to continue to run. Developers should pay attention to this message. - */ - const LEVEL_WARNING = 0x02; - /** - * Informational message level. An informational message is one that includes certain information - * for developers to review. - */ - const LEVEL_INFO = 0x04; - /** - * Tracing message level. An tracing message is one that reveals the code execution flow. - */ - const LEVEL_TRACE = 0x08; - /** - * Profiling message level. This indicates the message is for profiling purpose. - */ - const LEVEL_PROFILE = 0x40; - /** - * Profiling message level. This indicates the message is for profiling purpose. It marks the - * beginning of a profiling block. - */ - const LEVEL_PROFILE_BEGIN = 0x50; - /** - * Profiling message level. This indicates the message is for profiling purpose. It marks the - * end of a profiling block. - */ - const LEVEL_PROFILE_END = 0x60; - - - /** - * @var array logged messages. This property is managed by [[log()]] and [[flush()]]. - * Each log message is of the following structure: - * - * ~~~ - * [ - * [0] => message (mixed, can be a string or some complex data, such as an exception object) - * [1] => level (integer) - * [2] => category (string) - * [3] => timestamp (float, obtained by microtime(true)) - * [4] => traces (array, debug backtrace, contains the application code call stacks) - * ] - * ~~~ - */ - public $messages = []; - /** - * @var array debug data. This property stores various types of debug data reported at - * different instrument places. - */ - public $data = []; - /** - * @var array|Target[] the log targets. Each array element represents a single [[Target|log target]] instance - * or the configuration for creating the log target instance. - */ - public $targets = []; - /** - * @var integer how many messages should be logged before they are flushed from memory and sent to targets. - * Defaults to 1000, meaning the [[flush]] method will be invoked once every 1000 messages logged. - * Set this property to be 0 if you don't want to flush messages until the application terminates. - * This property mainly affects how much memory will be taken by the logged messages. - * A smaller value means less memory, but will increase the execution time due to the overhead of [[flush()]]. - */ - public $flushInterval = 1000; - /** - * @var integer how much call stack information (file name and line number) should be logged for each message. - * If it is greater than 0, at most that number of call stacks will be logged. Note that only application - * call stacks are counted. - * - * If not set, it will default to 3 when `YII_ENV` is set as "dev", and 0 otherwise. - */ - public $traceLevel; - - /** - * Initializes the logger by registering [[flush()]] as a shutdown function. - */ - public function init() - { - parent::init(); - if ($this->traceLevel === null) { - $this->traceLevel = YII_ENV_DEV ? 3 : 0; - } - foreach ($this->targets as $name => $target) { - if (!$target instanceof Target) { - $this->targets[$name] = Yii::createObject($target); - } - } - register_shutdown_function([$this, 'flush'], true); - } - - /** - * Logs a message with the given type and category. - * If [[traceLevel]] is greater than 0, additional call stack information about - * the application code will be logged as well. - * @param string $message the message to be logged. - * @param integer $level the level of the message. This must be one of the following: - * `Logger::LEVEL_ERROR`, `Logger::LEVEL_WARNING`, `Logger::LEVEL_INFO`, `Logger::LEVEL_TRACE`, - * `Logger::LEVEL_PROFILE_BEGIN`, `Logger::LEVEL_PROFILE_END`. - * @param string $category the category of the message. - */ - public function log($message, $level, $category = 'application') - { - $time = microtime(true); - $traces = []; - if ($this->traceLevel > 0) { - $count = 0; - $ts = debug_backtrace(); - array_pop($ts); // remove the last trace since it would be the entry script, not very useful - foreach ($ts as $trace) { - if (isset($trace['file'], $trace['line']) && strpos($trace['file'], YII_PATH) !== 0) { - unset($trace['object'], $trace['args']); - $traces[] = $trace; - if (++$count >= $this->traceLevel) { - break; - } - } - } - } - $this->messages[] = [$message, $level, $category, $time, $traces]; - if ($this->flushInterval > 0 && count($this->messages) >= $this->flushInterval) { - $this->flush(); - } - } - - /** - * Flushes log messages from memory to targets. - * @param boolean $final whether this is a final call during a request. - */ - public function flush($final = false) - { - /** @var Target $target */ - foreach ($this->targets as $target) { - if ($target->enabled) { - $target->collect($this->messages, $final); - } - } - $this->messages = []; - } - - /** - * Returns the total elapsed time since the start of the current request. - * This method calculates the difference between now and the timestamp - * defined by constant `YII_BEGIN_TIME` which is evaluated at the beginning - * of [[BaseYii]] class file. - * @return float the total elapsed time in seconds for current request. - */ - public function getElapsedTime() - { - return microtime(true) - YII_BEGIN_TIME; - } - - /** - * Returns the profiling results. - * - * By default, all profiling results will be returned. You may provide - * `$categories` and `$excludeCategories` as parameters to retrieve the - * results that you are interested in. - * - * @param array $categories list of categories that you are interested in. - * You can use an asterisk at the end of a category to do a prefix match. - * For example, 'yii\db\*' will match categories starting with 'yii\db\', - * such as 'yii\db\Connection'. - * @param array $excludeCategories list of categories that you want to exclude - * @return array the profiling results. Each element is an array consisting of these elements: - * `info`, `category`, `timestamp`, `trace`, `level`, `duration`. - */ - public function getProfiling($categories = [], $excludeCategories = []) - { - $timings = $this->calculateTimings($this->messages); - if (empty($categories) && empty($excludeCategories)) { - return $timings; - } - - foreach ($timings as $i => $timing) { - $matched = empty($categories); - foreach ($categories as $category) { - $prefix = rtrim($category, '*'); - if (strpos($timing['category'], $prefix) === 0 && ($timing['category'] === $category || $prefix !== $category)) { - $matched = true; - break; - } - } - - if ($matched) { - foreach ($excludeCategories as $category) { - $prefix = rtrim($category, '*'); - foreach ($timings as $i => $timing) { - if (strpos($timing['category'], $prefix) === 0 && ($timing['category'] === $category || $prefix !== $category)) { - $matched = false; - break; - } - } - } - } - - if (!$matched) { - unset($timings[$i]); - } - } - return array_values($timings); - } - - /** - * Returns the statistical results of DB queries. - * The results returned include the number of SQL statements executed and - * the total time spent. - * @return array the first element indicates the number of SQL statements executed, - * and the second element the total time spent in SQL execution. - */ - public function getDbProfiling() - { - $timings = $this->getProfiling(['yii\db\Command::query', 'yii\db\Command::execute']); - $count = count($timings); - $time = 0; - foreach ($timings as $timing) { - $time += $timing['duration']; - } - return [$count, $time]; - } - - /** - * Calculates the elapsed time for the given log messages. - * @param array $messages the log messages obtained from profiling - * @return array timings. Each element is an array consisting of these elements: - * `info`, `category`, `timestamp`, `trace`, `level`, `duration`. - */ - public function calculateTimings($messages) - { - $timings = []; - $stack = []; - - foreach ($messages as $i => $log) { - list($token, $level, $category, $timestamp, $traces) = $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]] = [ - 'info' => $last[0], - 'category' => $last[2], - 'timestamp' => $last[3], - 'trace' => $last[4], - 'level' => count($stack), - 'duration' => $timestamp - $last[3], - ]; - } - } - } - - ksort($timings); - - return array_values($timings); - } - - - /** - * Returns the text display of the specified level. - * @param integer $level the message level, e.g. [[LEVEL_ERROR]], [[LEVEL_WARNING]]. - * @return string the text display of the level - */ - public static function getLevelName($level) - { - static $levels = [ - self::LEVEL_ERROR => 'error', - self::LEVEL_WARNING => 'warning', - self::LEVEL_INFO => 'info', - self::LEVEL_TRACE => 'trace', - self::LEVEL_PROFILE_BEGIN => 'profile begin', - self::LEVEL_PROFILE_END => 'profile end', - ]; - return isset($levels[$level]) ? $levels[$level] : 'unknown'; - } -} diff --git a/framework/yii/log/Target.php b/framework/yii/log/Target.php deleted file mode 100644 index d5d8e5b..0000000 --- a/framework/yii/log/Target.php +++ /dev/null @@ -1,238 +0,0 @@ - - * @since 2.0 - */ -abstract class Target extends Component -{ - /** - * @var boolean whether to enable this log target. Defaults to true. - */ - public $enabled = true; - /** - * @var array list of message categories that this target is interested in. Defaults to empty, meaning all categories. - * You can use an asterisk at the end of a category so that the category may be used to - * match those categories sharing the same common prefix. For example, 'yii\db\*' will match - * categories starting with 'yii\db\', such as 'yii\db\Connection'. - */ - public $categories = []; - /** - * @var array list of message categories that this target is NOT interested in. Defaults to empty, meaning no uninteresting messages. - * If this property is not empty, then any category listed here will be excluded from [[categories]]. - * You can use an asterisk at the end of a category so that the category can be used to - * match those categories sharing the same common prefix. For example, 'yii\db\*' will match - * categories starting with 'yii\db\', such as 'yii\db\Connection'. - * @see categories - */ - public $except = []; - /** - * @var boolean whether to log a message containing the current user name and ID. Defaults to false. - * @see \yii\web\User - */ - public $logUser = false; - /** - * @var array list of the PHP predefined variables that should be logged in a message. - * Note that a variable must be accessible via `$GLOBALS`. Otherwise it won't be logged. - * Defaults to `['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER']`. - */ - public $logVars = ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER']; - /** - * @var integer how many messages should be accumulated before they are exported. - * Defaults to 1000. Note that messages will always be exported when the application terminates. - * Set this property to be 0 if you don't want to export messages until the application terminates. - */ - public $exportInterval = 1000; - /** - * @var array the messages that are retrieved from the logger so far by this log target. - * Please refer to [[Logger::messages]] for the details about the message structure. - */ - public $messages = []; - - private $_levels = 0; - - /** - * Exports log [[messages]] to a specific destination. - * Child classes must implement this method. - */ - abstract public function export(); - - /** - * 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, $this->filterMessages($messages, $this->getLevels(), $this->categories, $this->except)); - $count = count($this->messages); - if ($count > 0 && ($final || $this->exportInterval > 0 && $count >= $this->exportInterval)) { - if (($context = $this->getContextMessage()) !== '') { - $this->messages[] = [$context, Logger::LEVEL_INFO, 'application', YII_BEGIN_TIME]; - } - $this->export(); - $this->messages = []; - } - } - - /** - * Generates the context information to be logged. - * The default implementation will dump user information, system variables, etc. - * @return string the context information. If an empty string, it means no context information. - */ - protected function getContextMessage() - { - $context = []; - if ($this->logUser && ($user = Yii::$app->getComponent('user', false)) !== null) { - /** @var \yii\web\User $user */ - $context[] = 'User: ' . $user->getId(); - } - - foreach ($this->logVars as $name) { - if (!empty($GLOBALS[$name])) { - $context[] = "\${$name} = " . var_export($GLOBALS[$name], true); - } - } - - return implode("\n\n", $context); - } - - /** - * @return integer the message levels that this target is interested in. This is a bitmap of - * level values. Defaults to 0, meaning all available levels. - */ - public function getLevels() - { - return $this->_levels; - } - - /** - * Sets the message levels that this target is interested in. - * - * The parameter can be either an array of interested level names or an integer representing - * the bitmap of the interested level values. Valid level names include: 'error', - * 'warning', 'info', 'trace' and 'profile'; valid level values include: - * [[Logger::LEVEL_ERROR]], [[Logger::LEVEL_WARNING]], [[Logger::LEVEL_INFO]], - * [[Logger::LEVEL_TRACE]] and [[Logger::LEVEL_PROFILE]]. - * - * For example, - * - * ~~~ - * ['error', 'warning'] - * // which is equivalent to: - * Logger::LEVEL_ERROR | Logger::LEVEL_WARNING - * ~~~ - * - * @param array|integer $levels message levels that this target is interested in. - * @throws InvalidConfigException if an unknown level name is given - */ - public function setLevels($levels) - { - static $levelMap = [ - 'error' => Logger::LEVEL_ERROR, - 'warning' => Logger::LEVEL_WARNING, - 'info' => Logger::LEVEL_INFO, - 'trace' => Logger::LEVEL_TRACE, - 'profile' => Logger::LEVEL_PROFILE, - ]; - if (is_array($levels)) { - $this->_levels = 0; - foreach ($levels as $level) { - if (isset($levelMap[$level])) { - $this->_levels |= $levelMap[$level]; - } else { - throw new InvalidConfigException("Unrecognized level: $level"); - } - } - } else { - $this->_levels = $levels; - } - } - - /** - * Filters the given messages according to their categories and levels. - * @param array $messages messages to be filtered - * @param integer $levels the message levels to filter by. This is a bitmap of - * level values. Value 0 means allowing all levels. - * @param array $categories the message categories to filter by. If empty, it means all categories are allowed. - * @param array $except the message categories to exclude. If empty, it means all categories are allowed. - * @return array the filtered messages. - */ - public static function filterMessages($messages, $levels = 0, $categories = [], $except = []) - { - foreach ($messages as $i => $message) { - if ($levels && !($levels & $message[1])) { - unset($messages[$i]); - continue; - } - - $matched = empty($categories); - foreach ($categories as $category) { - if ($message[2] === $category || substr($category, -1) === '*' && strpos($message[2], rtrim($category, '*')) === 0) { - $matched = true; - break; - } - } - - if ($matched) { - foreach ($except as $category) { - $prefix = rtrim($category, '*'); - if (strpos($message[2], $prefix) === 0 && ($message[2] === $category || $prefix !== $category)) { - $matched = false; - break; - } - } - } - - if (!$matched) { - unset($messages[$i]); - } - } - return $messages; - } - - /** - * Formats a log message. - * The message structure follows that in [[Logger::messages]]. - * @param array $message the log message to be formatted. - * @return string the formatted message - */ - public function formatMessage($message) - { - list($text, $level, $category, $timestamp) = $message; - $level = Logger::getLevelName($level); - if (!is_string($text)) { - $text = var_export($text, true); - } - $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1'; - return date('Y/m/d H:i:s', $timestamp) . " [$ip] [$level] [$category] $text"; - } -} diff --git a/framework/yii/mail/BaseMailer.php b/framework/yii/mail/BaseMailer.php deleted file mode 100644 index baccbe2..0000000 --- a/framework/yii/mail/BaseMailer.php +++ /dev/null @@ -1,344 +0,0 @@ - - * @since 2.0 - */ -abstract class BaseMailer extends Component implements MailerInterface, ViewContextInterface -{ - - /** - * @event \yii\base\MailEvent an event raised right before send. - * You may set [[\yii\base\MailEvent::isValid]] to be false to cancel the send. - */ - const EVENT_BEFORE_SEND = 'beforeSend'; - /** - * @event \yii\base\MailEvent an event raised right after send. - */ - const EVENT_AFTER_SEND = 'afterSend'; - /** - * @var string directory containing view files for this email messages. - * This can be specified as an absolute path or path alias. - */ - public $viewPath = '@app/mails'; - /** - * @var string|boolean HTML layout view name. This is the layout used to render HTML mail body. - * The property can take the following values: - * - * - a relative view name: a view file relative to [[viewPath]], e.g., 'layouts/html'. - * - a path alias: an absolute view file path specified as a path alias, e.g., '@app/mails/html'. - * - a boolean false: the layout is disabled. - */ - public $htmlLayout = 'layouts/html'; - /** - * @var string|boolean text layout view name. This is the layout used to render TEXT mail body. - * Please refer to [[htmlLayout]] for possible values that this property can take. - */ - public $textLayout = 'layouts/text'; - /** - * @var array the configuration that should be applied to any newly created - * email message instance by [[createMessage()]] or [[compose()]]. Any valid property defined - * by [[MessageInterface]] can be configured, such as `from`, `to`, `subject`, `textBody`, `htmlBody`, etc. - * - * For example: - * - * ~~~ - * [ - * 'charset' => 'UTF-8', - * 'from' => 'noreply@mydomain.com', - * 'bcc' => 'developer@mydomain.com', - * ] - * ~~~ - */ - public $messageConfig = []; - /** - * @var string the default class name of the new message instances created by [[createMessage()]] - */ - public $messageClass = 'yii\mail\BaseMessage'; - /** - * @var boolean whether to save email messages as files under [[fileTransportPath]] instead of sending them - * to the actual recipients. This is usually used during development for debugging purpose. - * @see fileTransportPath - */ - public $useFileTransport = false; - /** - * @var string the directory where the email messages are saved when [[useFileTransport]] is true. - */ - public $fileTransportPath = '@runtime/mail'; - /** - * @var callback a PHP callback that will be called by [[send()]] when [[useFileTransport]] is true. - * The callback should return a file name which will be used to save the email message. - * If not set, the file name will be generated based on the current timestamp. - * - * The signature of the callback is: - * - * ~~~ - * function ($mailer, $message) - * ~~~ - */ - public $fileTransportCallback; - - /** - * @var \yii\base\View|array view instance or its array configuration. - */ - private $_view = []; - - /** - * @param array|View $view view instance or its array configuration that will be used to - * render message bodies. - * @throws InvalidConfigException on invalid argument. - */ - public function setView($view) - { - if (!is_array($view) && !is_object($view)) { - throw new InvalidConfigException('"' . get_class($this) . '::view" should be either object or configuration array, "' . gettype($view) . '" given.'); - } - $this->_view = $view; - } - - /** - * @return View view instance. - */ - public function getView() - { - if (!is_object($this->_view)) { - $this->_view = $this->createView($this->_view); - } - return $this->_view; - } - - /** - * Creates view instance from given configuration. - * @param array $config view configuration. - * @return View view instance. - */ - protected function createView(array $config) - { - if (!array_key_exists('class', $config)) { - $config['class'] = View::className(); - } - return Yii::createObject($config); - } - - /** - * Creates a new message instance and optionally composes its body content via view rendering. - * - * @param string|array $view the view to be used for rendering the message body. This can be: - * - * - a string, which represents the view name or path alias for rendering the HTML body of the email. - * In this case, the text body will be generated by applying `strip_tags()` to the HTML body. - * - an array with 'html' and/or 'text' elements. The 'html' element refers to the view name or path alias - * for rendering the HTML body, while 'text' element is for rendering the text body. For example, - * `['html' => 'contact-html', 'text' => 'contact-text']`. - * - null, meaning the message instance will be returned without body content. - * - * The view to be rendered can be specified in one of the following formats: - * - * - path alias (e.g. "@app/mails/contact"); - * - a relative view name (e.g. "contact"): the actual view file will be resolved by [[findViewFile()]] - * - * @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file. - * @return MessageInterface message instance. - */ - public function compose($view = null, array $params = []) - { - $message = $this->createMessage(); - if ($view !== null) { - $params['message'] = $message; - if (is_array($view)) { - if (isset($view['html'])) { - $html = $this->render($view['html'], $params, $this->htmlLayout); - } - if (isset($view['text'])) { - $text = $this->render($view['text'], $params, $this->textLayout); - } - } else { - $html = $this->render($view, $params, $this->htmlLayout); - } - if (isset($html)) { - $message->setHtmlBody($html); - } - if (isset($text)) { - $message->setTextBody($text); - } elseif (isset($html)) { - $message->setTextBody(strip_tags($html)); - } - } - return $message; - } - - /** - * Creates a new message instance. - * The newly created instance will be initialized with the configuration specified by [[messageConfig]]. - * If the configuration does not specify a 'class', the [[messageClass]] will be used as the class - * of the new message instance. - * @return MessageInterface message instance. - */ - protected function createMessage() - { - $config = $this->messageConfig; - if (!array_key_exists('class', $config)) { - $config['class'] = $this->messageClass; - } - return Yii::createObject($config); - } - - /** - * Sends the given email message. - * This method will log a message about the email being sent. - * If [[useFileTransport]] is true, it will save the email as a file under [[fileTransportPath]]. - * Otherwise, it will call [[sendMessage()]] to send the email to its recipient(s). - * Child classes should implement [[sendMessage()]] with the actual email sending logic. - * @param MessageInterface $message email message instance to be sent - * @return boolean whether the message has been sent successfully - */ - public function send($message) - { - if (!$this->beforeSend($message)) { - return false; - } - - $address = $message->getTo(); - if (is_array($address)) { - $address = implode(', ', array_keys($address)); - } - Yii::info('Sending email "' . $message->getSubject() . '" to "' . $address . '"', __METHOD__); - - if ($this->useFileTransport) { - $isSuccessful = $this->saveMessage($message); - } else { - $isSuccessful = $this->sendMessage($message); - } - $this->afterSend($message, $isSuccessful); - return $isSuccessful; - } - - /** - * Sends multiple messages at once. - * - * The default implementation simply calls [[send()]] multiple times. - * Child classes may override this method to implement more efficient way of - * sending multiple messages. - * - * @param array $messages list of email messages, which should be sent. - * @return integer number of messages that are successfully sent. - */ - public function sendMultiple(array $messages) - { - $successCount = 0; - foreach ($messages as $message) { - if ($this->send($message)) { - $successCount++; - } - } - return $successCount; - } - - /** - * Renders the specified view with optional parameters and layout. - * The view will be rendered using the [[view]] component. - * @param string $view the view name or the path alias of the view file. - * @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file. - * @param string|boolean $layout layout view name or path alias. If false, no layout will be applied. - * @return string the rendering result. - */ - public function render($view, $params = [], $layout = false) - { - $output = $this->getView()->render($view, $params, $this); - if ($layout !== false) { - return $this->getView()->render($layout, ['content' => $output], $this); - } else { - return $output; - } - } - - /** - * Sends the specified message. - * This method should be implemented by child classes with the actual email sending logic. - * @param MessageInterface $message the message to be sent - * @return boolean whether the message is sent successfully - */ - abstract protected function sendMessage($message); - - /** - * Saves the message as a file under [[fileTransportPath]]. - * @param MessageInterface $message - * @return boolean whether the message is saved successfully - */ - protected function saveMessage($message) - { - $path = Yii::getAlias($this->fileTransportPath); - if (!is_dir(($path))) { - mkdir($path, 0777, true); - } - if ($this->fileTransportCallback !== null) { - $file = $path . '/' . call_user_func($this->fileTransportCallback, $this, $message); - } else { - $time = microtime(true); - $file = $path . '/' . date('Ymd-His-', $time) . sprintf('%04d', (int)(($time - (int)$time) * 10000)) . '-' . sprintf('%04d', mt_rand(0, 10000)) . '.eml'; - } - file_put_contents($file, $message->toString()); - return true; - } - - /** - * Finds the view file corresponding to the specified relative view name. - * This method will return the view file by prefixing the view name with [[viewPath]]. - * @param string $view a relative view name. The name does NOT start with a slash. - * @return string the view file path. Note that the file may not exist. - */ - public function findViewFile($view) - { - return Yii::getAlias($this->viewPath) . DIRECTORY_SEPARATOR . $view; - } - - /** - * This method is invoked right before mail send. - * You may override this method to do last-minute preparation for the message. - * If you override this method, please make sure you call the parent implementation first. - * @param MessageInterface $message - */ - public function beforeSend($message) - { - $event = new MailEvent(['message' => $message]); - $this->trigger(self::EVENT_BEFORE_SEND, $event); - return $event->isValid; - } - - /** - * This method is invoked right after mail was send. - * You may override this method to do some postprocessing or logging based on mail send status. - * If you override this method, please make sure you call the parent implementation first. - * @param MessageInterface $message - * @param boolean $isSuccessful - */ - public function afterSend($message, $isSuccessful) - { - $event = new MailEvent(['message' => $message, 'isSuccessful' => $isSuccessful]); - $this->trigger(self::EVENT_AFTER_SEND, $event); - } - -} diff --git a/framework/yii/mail/BaseMessage.php b/framework/yii/mail/BaseMessage.php deleted file mode 100644 index 36d3288..0000000 --- a/framework/yii/mail/BaseMessage.php +++ /dev/null @@ -1,52 +0,0 @@ - - * @since 2.0 - */ -abstract class BaseMessage extends Object implements MessageInterface -{ - /** - * @inheritdoc - */ - public function send(MailerInterface $mailer = null) - { - if ($mailer === null) { - $mailer = Yii::$app->getMail(); - } - return $mailer->send($this); - } - - /** - * PHP magic method that returns the string representation of this object. - * @return string the string representation of this object. - */ - public function __toString() - { - // __toString cannot throw exception - // use trigger_error to bypass this limitation - try { - return $this->toString(); - } catch (\Exception $e) { - trigger_error($e->getMessage() . "\n\n" . $e->getTraceAsString()); - return ''; - } - } -} diff --git a/framework/yii/mail/MailerInterface.php b/framework/yii/mail/MailerInterface.php deleted file mode 100644 index 5ee9ccd..0000000 --- a/framework/yii/mail/MailerInterface.php +++ /dev/null @@ -1,64 +0,0 @@ -mail->compose('contact/html', ['contactForm' => $form]) - * ->setFrom('from@domain.com') - * ->setTo($form->email) - * ->setSubject($form->subject) - * ->send(); - * ~~~ - * - * @see MessageInterface - * - * @author Paul Klimov - * @since 2.0 - */ -interface MailerInterface -{ - /** - * Creates a new message instance and optionally composes its body content via view rendering. - * - * @param string|array $view the view to be used for rendering the message body. This can be: - * - * - a string, which represents the view name or path alias for rendering the HTML body of the email. - * In this case, the text body will be generated by applying `strip_tags()` to the HTML body. - * - an array with 'html' and/or 'text' elements. The 'html' element refers to the view name or path alias - * for rendering the HTML body, while 'text' element is for rendering the text body. For example, - * `['html' => 'contact-html', 'text' => 'contact-text']`. - * - null, meaning the message instance will be returned without body content. - * - * @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file. - * @return MessageInterface message instance. - */ - public function compose($view = null, array $params = []); - - /** - * Sends the given email message. - * @param MessageInterface $message email message instance to be sent - * @return boolean whether the message has been sent successfully - */ - public function send($message); - - /** - * Sends multiple messages at once. - * - * This method may be implemented by some mailers which support more efficient way of sending multiple messages in the same batch. - * - * @param array $messages list of email messages, which should be sent. - * @return integer number of messages that are successfully sent. - */ - public function sendMultiple(array $messages); -} diff --git a/framework/yii/mail/MessageInterface.php b/framework/yii/mail/MessageInterface.php deleted file mode 100644 index 94cfd18..0000000 --- a/framework/yii/mail/MessageInterface.php +++ /dev/null @@ -1,218 +0,0 @@ -mail->compose() - * ->setFrom('from@domain.com') - * ->setTo($form->email) - * ->setSubject($form->subject) - * ->setTextBody('Plain text content') - * ->setHtmlBody('HTML content') - * ->send(); - * ~~~ - * - * @see MailerInterface - * - * @author Paul Klimov - * @since 2.0 - */ -interface MessageInterface -{ - /** - * Returns the character set of this message. - * @return string the character set of this message. - */ - public function getCharset(); - - /** - * Sets the character set of this message. - * @param string $charset character set name. - * @return static self reference. - */ - public function setCharset($charset); - - /** - * Returns the message sender. - * @return string the sender - */ - public function getFrom(); - - /** - * Sets the message sender. - * @param string|array $from sender email address. - * You may pass an array of addresses if this message is from multiple people. - * You may also specify sender name in addition to email address using format: - * `[email => name]`. - * @return static self reference. - */ - public function setFrom($from); - - /** - * Returns the message recipient(s). - * @return array the message recipients - */ - public function getTo(); - - /** - * Sets the message recipient(s). - * @param string|array $to receiver email address. - * You may pass an array of addresses if multiple recipients should receive this message. - * You may also specify receiver name in addition to email address using format: - * `[email => name]`. - * @return static self reference. - */ - public function setTo($to); - - /** - * Returns the reply-to address of this message. - * @return string the reply-to address of this message. - */ - public function getReplyTo(); - - /** - * Sets the reply-to address of this message. - * @param string|array $replyTo the reply-to address. - * You may pass an array of addresses if this message should be replied to multiple people. - * You may also specify reply-to name in addition to email address using format: - * `[email => name]`. - * @return static self reference. - */ - public function setReplyTo($replyTo); - - /** - * Returns the Cc (additional copy receiver) addresses of this message. - * @return array the Cc (additional copy receiver) addresses of this message. - */ - public function getCc(); - - /** - * Sets the Cc (additional copy receiver) addresses of this message. - * @param string|array $cc copy receiver email address. - * You may pass an array of addresses if multiple recipients should receive this message. - * You may also specify receiver name in addition to email address using format: - * `[email => name]`. - * @return static self reference. - */ - public function setCc($cc); - - /** - * Returns the Bcc (hidden copy receiver) addresses of this message. - * @return array the Bcc (hidden copy receiver) addresses of this message. - */ - public function getBcc(); - - /** - * Sets the Bcc (hidden copy receiver) addresses of this message. - * @param string|array $bcc hidden copy receiver email address. - * You may pass an array of addresses if multiple recipients should receive this message. - * You may also specify receiver name in addition to email address using format: - * `[email => name]`. - * @return static self reference. - */ - public function setBcc($bcc); - - /** - * Returns the message subject. - * @return string the message subject - */ - public function getSubject(); - - /** - * Sets the message subject. - * @param string $subject message subject - * @return static self reference. - */ - public function setSubject($subject); - - /** - * Sets message plain text content. - * @param string $text message plain text content. - * @return static self reference. - */ - public function setTextBody($text); - - /** - * Sets message HTML content. - * @param string $html message HTML content. - * @return static self reference. - */ - public function setHtmlBody($html); - - /** - * Attaches existing file to the email message. - * @param string $fileName full file name - * @param array $options options for embed file. Valid options are: - * - * - fileName: name, which should be used to attach file. - * - contentType: attached file MIME type. - * - * @return static self reference. - */ - public function attach($fileName, array $options = []); - - /** - * Attach specified content as file for the email message. - * @param string $content attachment file content. - * @param array $options options for embed file. Valid options are: - * - * - fileName: name, which should be used to attach file. - * - contentType: attached file MIME type. - * - * @return static self reference. - */ - public function attachContent($content, array $options = []); - - /** - * Attach a file and return it's CID source. - * This method should be used when embedding images or other data in a message. - * @param string $fileName file name. - * @param array $options options for embed file. Valid options are: - * - * - fileName: name, which should be used to attach file. - * - contentType: attached file MIME type. - * - * @return string attachment CID. - */ - public function embed($fileName, array $options = []); - - /** - * Attach a content as file and return it's CID source. - * This method should be used when embedding images or other data in a message. - * @param string $content attachment file content. - * @param array $options options for embed file. Valid options are: - * - * - fileName: name, which should be used to attach file. - * - contentType: attached file MIME type. - * - * @return string attachment CID. - */ - public function embedContent($content, array $options = []); - - /** - * Sends this email message. - * @param MailerInterface $mailer the mailer that should be used to send this message. - * If null, the "mail" application component will be used instead. - * @return boolean whether this message is sent successfully. - */ - public function send(MailerInterface $mailer = null); - - /** - * Returns string representation of this message. - * @return string the string representation of this message. - */ - public function toString(); -} diff --git a/framework/yii/messages/config.php b/framework/yii/messages/config.php deleted file mode 100644 index c7de6b9..0000000 --- a/framework/yii/messages/config.php +++ /dev/null @@ -1,45 +0,0 @@ - __DIR__ . '/..', - // string, required, root directory containing message translations. - 'messagePath' => __DIR__, - // array, required, list of language codes that the extracted messages - // should be translated to. For example, ['zh-CN', 'de']. - 'languages' => ['da', 'de', 'ru', 'pl', 'pt-BR', 'it', 'es', 'ro', 'ja'], - // string, the name of the function for translating messages. - // Defaults to 'Yii::t'. This is used as a mark to find the messages to be - // translated. You may use a string for single function name or an array for - // multiple function names. - 'translator' => 'Yii::t', - // boolean, whether to sort messages by keys when merging new messages - // with the existing ones. Defaults to false, which means the new (untranslated) - // messages will be separated from the old (translated) ones. - 'sort' => false, - // boolean, whether the message file should be overwritten with the merged messages - 'overwrite' => true, - // boolean, whether to remove messages that no longer appear in the source code. - // Defaults to false, which means each of these messages will be enclosed with a pair of '@@' marks. - 'removeUnused' => false, - // array, list of patterns that specify which files/directories should be processed. - // If empty or not set, all files/directories will be processed. - // A path matches a pattern if it contains the pattern string at its end. For example, - // '/a/b' will match all files and directories ending with '/a/b'; - // and the '.svn' will match all files and directories whose name ends with '.svn'. - // Note, the '/' characters in a pattern matches both '/' and '\'. - // If a file/directory matches both a pattern in "only" and "except", it will NOT be processed. - 'only' => ['.php'], - // array, list of patterns that specify which files/directories should NOT be processed. - // If empty or not set, all files/directories will be processed. - // Please refer to "only" for details about the patterns. - 'except' => [ - '.svn', - '.git', - '.gitignore', - '.gitkeep', - '.hgignore', - '.hgkeep', - '/messages', - ], -]; diff --git a/framework/yii/messages/da/yii.php b/framework/yii/messages/da/yii.php deleted file mode 100644 index fa3ee9f..0000000 --- a/framework/yii/messages/da/yii.php +++ /dev/null @@ -1,81 +0,0 @@ - '(ikke defineret)', - 'An internal server error occurred.' => 'Der opstod en intern server fejl.', - 'Are you sure to delete this item?' => 'Er du sikker på, at du vil slette dette element?', - 'Delete' => 'Slet', - 'Error' => 'Fejl', - 'File upload failed.' => 'Upload af fil fejlede.', - 'Home' => 'Start', - 'Invalid data received for parameter "{param}".' => 'Ugyldig data modtaget for parameteren "{param}".', - 'Login Required' => 'Login Påkrævet', - 'Missing required arguments: {params}' => 'Påkrævede argumenter mangler: {params}', - 'Missing required parameters: {params}' => 'Påkrævede parametre mangler: {params}', - 'No' => 'Nej', - 'No help for unknown command "{command}".' => 'Ingen hjælp til ukendt kommando "{command}".', - 'No help for unknown sub-command "{command}".' => 'Ingen hjælp til ukendt under-kommando "{command}".', - 'No results found.' => 'Ingen resultater fundet.', - 'Only files with these extensions are allowed: {extensions}.' => 'Kun filer med følgende filtyper er tilladte: {extensions}.', - 'Only files with these mimeTypes are allowed: {mimeTypes}.' => 'Kun filer med følgende mime-typer er tilladte: {mimeTypes}.', - 'Page not found.' => 'Siden blev ikke fundet.', - 'Please fix the following errors:' => 'Ret venligst følgende fejl:', - 'Please upload a file.' => 'Venligst upload en fil.', - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.' => 'Viser {begin, number}-{end, number} af {totalCount, number} {totalCount, plural, one{element} other{elementer}}.', - 'The file "{file}" is not an image.' => 'Filen "{file}" er ikke et billede.', - 'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Filen "{file}" er for stor. Størrelsen må ikke overstige {limit, number} {limit, plural, one{byte} other{bytes}}.', - 'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Filen "{file}" er for lille. Størrelsen må ikke være mindre end {limit, number} {limit, plural, one{byte} other{bytes}}.', - 'The format of {attribute} is invalid.' => 'Formatet af {attribute} er ugyldigt.', - 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Billedet "{file}" er for stort. Højden må ikke være større end {limit, number} {limit, plural, one{pixel} other{pixels}}.', - 'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Billedet "{file}" er for stort. Bredden må ikke være større end {limit, number} {limit, plural, one{pixel} other{pixels}}.', - 'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Billedet "{file}" er for lille. Højden må ikke være mindre end {limit, number} {limit, plural, one{pixel} other{pixels}}.', - 'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Billedet "{file}" er for lille. Bredden må ikke være mindre end {limit, number} {limit, plural, one{pixel} other{pixels}}.', - 'The verification code is incorrect.' => 'Verifikationskoden er ikke korrekt.', - 'Total {count, number} {count, plural, one{item} other{items}}.' => 'Total {count, number} {count, plural, one{element} other{elementer}}.', - 'Unable to verify your data submission.' => 'Kunne ikke verificere din data indsendelse.', - 'Unknown command "{command}".' => 'Ukendt kommando "{command}".', - 'Unknown option: --{name}' => 'Ukendt option: --{name}', - 'Update' => 'Opdatér', - 'View' => 'Vis', - 'Yes' => 'Ja', - 'You are not allowed to perform this action.' => 'Du har ikke tilladelse til at udføre denne handling.', - 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => '', - 'the input value' => 'inputværdien', - '{attribute} "{value}" has already been taken.' => '{attribute} "{value}" er allerede i brug.', - '{attribute} cannot be blank.' => '{attribute} må ikke være tom.', - '{attribute} is invalid.' => '{attribute} er ugyldig.', - '{attribute} is not a valid URL.' => '{attribute} er ikke en gyldig URL.', - '{attribute} is not a valid email address.' => '{attribute} er ikke en gyldig emailadresse.', - '{attribute} must be "{requiredValue}".' => '{attribute} skal være "{requiredValue}".', - '{attribute} must be a number.' => '{attribute} skal være et nummer.', - '{attribute} must be a string.' => '{attribute} skal være en tekst-streng.', - '{attribute} must be an integer.' => '{attribute} skal være et heltal.', - '{attribute} must be either "{true}" or "{false}".' => '{attribute} skal være enten "{true}" eller "{false}".', - '{attribute} must be greater than "{compareValue}".' => '{attribute} skal være større end "{compareValue}".', - '{attribute} must be greater than or equal to "{compareValue}".' => '{attribute} skal være større end eller lig med "{compareValue}".', - '{attribute} must be less than "{compareValue}".' => '{attribute} skal være mindre end "{compareValue}".', - '{attribute} must be less than or equal to "{compareValue}".' => '{attribute} skal være mindre end eller lig med "{compareValue}".', - '{attribute} must be no greater than {max}.' => '{attribute} må ikke være større end {max}.', - '{attribute} must be no less than {min}.' => '{attribute} må ikke være mindre end {min}.', - '{attribute} must be repeated exactly.' => '{attribute} skal være gentaget præcist.', - '{attribute} must not be equal to "{compareValue}".' => '{attribute} må ikke være lig med "{compareValue}".', - '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} skal mindst indeholde {min, number} {min, plural, one{tegn} other{tegn}}.', - '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute} skal højst indeholde {min, number} {min, plural, one{tegn} other{tegn}}.', - '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute} skal indeholde {length, number} {length, plural, one{tegn} other{tegn}}.', -); diff --git a/framework/yii/messages/de/yii.php b/framework/yii/messages/de/yii.php deleted file mode 100644 index 22e677f..0000000 --- a/framework/yii/messages/de/yii.php +++ /dev/null @@ -1,81 +0,0 @@ - 'der eingegebene Wert', - '(not set)' => '(nicht gesetzt)', - 'An internal server error occurred.' => 'Es ist ein interner Serverfehler aufgetreten.', - 'Are you sure to delete this item?' => 'Wollen Sie den Eintrag wirklich löschen?', - 'Delete' => 'Löschen', - 'Error' => 'Fehler', - 'File upload failed.' => 'Das Hochladen der Datei ist gescheitert.', - 'Home' => 'Home', - 'Invalid data received for parameter "{param}".' => 'Ungültige Daten erhalten für Parameter"{param}".', - 'Login Required' => 'Anmeldung erforderlich', - 'Missing required arguments: {params}' => 'Pflichtargumente fehlen: {params}', - 'Missing required parameters: {params}' => 'Pflichtparameter fehlen: {params}', - 'No' => 'Nein', - 'No help for unknown command "{command}".' => 'Es gibt keine Hilfe für den unbekannten Befehl "{command}".', - 'No help for unknown sub-command "{command}".' => 'Es gibt keine Hilfe für den unbekannten Unterbefehl "{command}".', - 'No results found.' => 'Keine Ergebnisse gefunden', - 'Only files with these extensions are allowed: {extensions}.' => 'Es sind nur Dateien mit folgenden Dateierweiterungen erlaubt: {extensions}.', - 'Only files with these mimeTypes are allowed: {mimeTypes}.' => 'Es sind nur Dateien mit folgenden MIME-Typen erlaubt: {mimeTypes}.', - 'Page not found.' => 'Seite nicht gefunden.', - 'Please fix the following errors:' => 'Bitte korrigieren Sie die folgenden Fehler:', - 'Please upload a file.' => 'Bitte laden Sie eine Datei hoch.', - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.' => 'Zeige {begin, number}-{end, number} von {totalCount, number} {totalCount, plural, one{Eintrag} other{Einträgen}}.', - 'The file "{file}" is not an image.' => 'Die Datei "{file}" ist kein Bild.', - 'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Die Datei "{file}" ist zu groß. Es {limit, plural, one{ist} other{sind}} maximal {limit, number} {limit, plural, one{Byte} other{Bytes}} erlaubt.', - 'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Die Datei "{file}" ist zu klein. Es {limit, plural, one{ist} other{sind}} mindestens {limit, number} {limit, plural, one{Byte} other{Bytes}} erforderlich.', - 'The format of {attribute} is invalid.' => 'Das Format von {attribute} ist ungültig.', - 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Das Bild "{file}" ist zu groß. Es darf maximal {limit, number} Pixel hoch sein.', - 'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Das Bild "{file}" ist zu groß. Es darf maximal {limit, number} Pixel breit sein.', - 'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Das Bild "{file}" ist zu klein. Es muss mindestens {limit, number} Pixel hoch sein.', - 'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Das Bild "{file}" ist zu klein. Es muss mindestens {limit, number} Pixel breit sein.', - 'The verification code is incorrect.' => 'Der Prüfcode ist falsch.', - 'Total {count, number} {count, plural, one{item} other{items}}.' => 'Insgesamt {count, number} {count, plural, one{Eintrag} other{Einträge}}.', - 'Unable to verify your data submission.' => 'Es ist nicht möglich, Ihre Dateneingabe zu prüfen.', - 'Unknown command "{command}".' => 'Unbekannter Befehl "{command}".', - 'Unknown option: --{name}' => 'Unbekannte Option: --{name}', - 'Update' => 'Bearbeiten', - 'View' => 'Anzeigen', - 'Yes' => 'Ja', - 'You are not allowed to perform this action.' => 'Sie dürfen diese Aktion nicht durchführen.', - 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Sie können maximal {limit, number} {limit, plural, one{eine Datei} other{# Dateien}} hochladen.', - '{attribute} "{value}" has already been taken.' => '{attribute} "{value}" wird bereits verwendet.', - '{attribute} cannot be blank.' => '{attribute} darf nicht leer sein.', - '{attribute} is invalid.' => '{attribute} ist ungültig.', - '{attribute} is not a valid URL.' => '{attribute} ist keine gültige URL.', - '{attribute} is not a valid email address.' => '{attribute} ist keine gültige Emailadresse.', - '{attribute} must be "{requiredValue}".' => '{attribute} muss den Wert {requiredValue} haben.', - '{attribute} must be a number.' => '{attribute} muss eine Zahl sein.', - '{attribute} must be a string.' => '{attribute} muss eine Zeichenkette sein.', - '{attribute} must be an integer.' => '{attribute} muss eine Ganzzahl sein.', - '{attribute} must be either "{true}" or "{false}".' => '{attribute} muss entweder "{true}" oder "{false}" sein.', - '{attribute} must be greater than "{compareValue}".' => '{attribute} muss größer als "{compareValue}" sein.', - '{attribute} must be greater than or equal to "{compareValue}".' => '{attribute} muss größer oder gleich "{compareValue}" sein.', - '{attribute} must be less than "{compareValue}".' => '{attribute} muss kleiner als "{compareValue}" sein.', - '{attribute} must be less than or equal to "{compareValue}".' => '{attribute} muss kleiner oder gleich "{compareValue}" sein.', - '{attribute} must be no greater than {max}.' => '{attribute} darf nicht größer als {max} sein.', - '{attribute} must be no less than {min}.' => '{attribute} darf nicht kleiner als {max} sein.', - '{attribute} must be repeated exactly.' => '{attribute} muss genau wiederholt werden.', - '{attribute} must not be equal to "{compareValue}".' => '{attribute} darf nicht "{compareValue}" sein.', - '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} muss mindestens {min, number} Zeichen enthalten.', - '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute} darf maximal {max, number} Zeichen enthalten.', - '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute} muss aus genau {length, number} Zeichen bestehen.', -); diff --git a/framework/yii/messages/es/yii.php b/framework/yii/messages/es/yii.php deleted file mode 100644 index 2c6fe93..0000000 --- a/framework/yii/messages/es/yii.php +++ /dev/null @@ -1,81 +0,0 @@ - '(no definido)', - 'An internal server error occurred.' => 'Hubo un error interno del servidor.', - 'Are you sure to delete this item?' => '¿Está seguro de eliminar este elemento?', - 'Delete' => 'Eliminar', - 'Error' => 'Error', - 'File upload failed.' => 'Falló la subida del archivo.', - 'Home' => 'Inicio', - 'Invalid data received for parameter "{param}".' => 'Se recibieron datos erróneos para el parámetro "{param}"', - 'Login Required' => 'Login Requerido', - 'Missing required arguments: {params}' => 'Argumentos requeridos ausentes: {params}', - 'Missing required parameters: {params}' => 'Parámetros requeridos ausentes: {params}', - 'No' => 'No', - 'No help for unknown command "{command}".' => 'No existe ayuda para el comando desconocido "{command}"', - 'No help for unknown sub-command "{command}".' => 'No existe ayuda para el sub-comando desconocido "{command}"', - 'No results found.' => 'No se encontraron resultados.', - 'Only files with these extensions are allowed: {extensions}.' => 'Sólo se aceptan archivos con las siguientes extensiones: {extensions}', - 'Only files with these mimeTypes are allowed: {mimeTypes}.' => 'Sólo se aceptan archivos con los siguientes tipos mime: {mimeTypes}', - 'Page not found.' => 'Página no entontrada.', - 'Please fix the following errors:' => 'Por favor corrija los siguientes errores:', - 'Please upload a file.' => 'Por favor suba un archivo.', - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.' => 'Mostrando {begin, number}-{end, number} de {totalCount, number} {totalCount, plural, one{elemento} other{elementos}}.', - 'The file "{file}" is not an image.' => 'El archivo "{file}" no es una imagen.', - 'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'El archivo "{file}" es demasiado grande. Su tamaño no puede exceder {limit, number} {limit, plural, one{byte} other{bytes}}.', - 'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'El archivo "{file}" es demasiado pequeño. Su tamaño no puede ser menor a {limit, number} {limit, plural, one{byte} other{bytes}}.', - 'The format of {attribute} is invalid.' => 'El formato de {attribute} es inválido.', - 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'La imagen "{file}" es demasiado grande. La altura no puede ser mayor a {limit, number} {limit, plural, one{píxel} other{píxeles}}.', - 'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'La imagen "{file}" es demasiado grande. La anchura no puede ser mayor a {limit, number} {limit, plural, one{píxel} other{píxeles}}.', - 'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'La imagen "{file}" es demasiado pequeña. La altura no puede ser menor a {limit, number} {limit, plural, one{píxel} other{píxeles}}.', - 'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'La imagen "{file}" es demasiado pequeña. La anchura no puede ser menor a {limit, number} {limit, plural, one{píxel} other{píxeles}}.', - 'The verification code is incorrect.' => 'El código de verificación es incorrecto.', - 'Total {count, number} {count, plural, one{item} other{items}}.' => 'Total {count, number} {count, plural, one{elemento} other{elementos}}.', - 'Unable to verify your data submission.' => 'Incapaz de verificar los datos enviados.', - 'Unknown command "{command}".' => 'Comando desconocido "{command}".', - 'Unknown option: --{name}' => 'Opción desconocida: --{name}', - 'Update' => 'Actualizar', - 'View' => 'Ver', - 'Yes' => 'Sí', - 'You are not allowed to perform this action.' => 'No tiene permitido ejecutar esta acción.', - 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Puedes subir como máximo {limit, number} {limit, plural, one{archivo} other{archivos}}.', - 'the input value' => 'el valor de entrada', - '{attribute} "{value}" has already been taken.' => '{attribute} "{value}" ya ha sido utilizado.', - '{attribute} cannot be blank.' => '{attribute} no puede estar vacío.', - '{attribute} is invalid.' => '{attribute} es inválido.', - '{attribute} is not a valid URL.' => '{attribute} no es una URL válida.', - '{attribute} is not a valid email address.' => '{attribute} no es una dirección de correo válida.', - '{attribute} must be "{requiredValue}".' => '{attribute} debe ser "{requiredValue}".', - '{attribute} must be a number.' => '{attribute} debe ser un número.', - '{attribute} must be a string.' => '{attribute} debe ser una cadena de caracteres.', - '{attribute} must be an integer.' => '{attribute} debe ser un número entero.', - '{attribute} must be either "{true}" or "{false}".' => '{attribute} debe ser "{true}" o "{false}".', - '{attribute} must be greater than "{compareValue}".' => '{attribute} debe ser mayor a "{compareValue}', - '{attribute} must be greater than or equal to "{compareValue}".' => '{attribute} debe ser mayor o igual a "{compareValue}".', - '{attribute} must be less than "{compareValue}".' => '{attribute} debe ser menor a "{compareValue}".', - '{attribute} must be less than or equal to "{compareValue}".' => '{attribute} debe ser menor o igual a "{compareValue}".', - '{attribute} must be no greater than {max}.' => '{attribute} no debe ser mayor a {max}.', - '{attribute} must be no less than {min}.' => '{attribute} no debe ser menor a {min}.', - '{attribute} must be repeated exactly.' => '{attribute} debe ser repetido exactamente igual.', - '{attribute} must not be equal to "{compareValue}".' => '{attribute} no debe ser igual a "{compareValue}".', - '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} debería contener al menos {min, number} {min, plural, one{letra} other{letras}}.', - '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute} debería contener como máximo {max, number} {max, plural, one{letra} other{letras}}.', - '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute} debería contener {length, number} {length, plural, one{letra} other{letras}}.', -); diff --git a/framework/yii/messages/it/yii.php b/framework/yii/messages/it/yii.php deleted file mode 100644 index 096c619..0000000 --- a/framework/yii/messages/it/yii.php +++ /dev/null @@ -1,105 +0,0 @@ - 'L immagine "{file}" è troppo grande. Il suo height non può essere più grande di {limit, number} {limit, plural, one{pixel} other{pixels}}.', - 'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'L immagine "{file}" è troppo grande. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.', - 'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'L immagine "{file}" è troppo piccola. Il suo height non può essere più piccolo di {limit, number} {limit, plural, one{pixel} other{pixels}}.', - 'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'L immagine "{file}" è troppo piccola. Il suo width non può essere maggiore di {limit, number} {limit, plural, one{pixel} other{pixels}}.', - '(not set)' => '(nessun valore)', - 'An internal server error occurred.' => 'Si è verificato un errore interno', - 'Are you sure to delete this item?' => 'Sei sicuro di voler cancellare questo elemento?', - 'Compile Error' => 'Errore di compilazione', - 'Compile Warning' => 'Avviso di compilazione', - 'Core Error' => 'Errore nel Core', - 'Core Warning' => 'Avviso sul Core', - 'Database Exception' => 'Database in Eccezione', - 'Delete' => 'Elimina', - 'Deprecated' => 'Deprecato', - 'Error' => 'Errore', - 'Exception' => 'Eccezione', - 'Fatal Error' => 'Errore Fatale', - 'File upload failed.' => 'Upload file fallito', - 'Home' => 'Home', - 'Invalid Call' => 'Chiamata non valida', - 'Invalid Configuration' => 'Configurazione non valida', - 'Invalid Parameter' => 'Parametro non valido', - 'Invalid Route' => 'Percorso non valido', - 'Invalid data received for parameter "{param}".' => 'Dati ricevuti non corretti per il parametro "{param}".', - 'Login Required' => 'Login Richiesto', - 'Missing required arguments: {params}' => 'Il seguente argomento è mancante: {params}', - 'Missing required parameters: {params}' => 'Il seguente parametro è mancante: {params}', - 'No' => 'No', - 'No help for unknown command "{command}".' => 'Nessun aiuto per il comando sconosciuto "{command}".', - 'No help for unknown sub-command "{command}".' => 'Nessun aiuto per il sub-comando sconosciuto "{command}".', - 'No results found.' => 'Nessun risultato trovato', - 'Not Supported' => 'Non supportato', - 'Notice' => 'Avviso', - 'Only files with these extensions are allowed: {extensions}.' => 'Solo i files con queste estensioni sono permessi: {extensions}.', - 'Only files with these mimeTypes are allowed: {mimeTypes}.' => 'Solo i files con questi mimeTypes sono permessi: {mimeTypes}.', - 'Page not found.' => 'Pagina non trovata', - 'Parse Error' => 'Errore di Parsing', - 'Please fix the following errors:' => 'Per favore correggi i seguenti errori:', - 'Please upload a file.' => 'Per favore carica il file.', - 'Recoverable Error' => 'Errore rimediabile', - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.' =>'Mostro {begin, number}-{end, number} di {totalCount, number} {totalCount, plural, one{item} other{items}}.', - 'Stale Object Exception' => 'Eccezione Oggetto Datato', - 'Strict' => 'Severo', - 'The file "{file}" is not an image.' => 'Questo file "{file}" non è una immagine.', - 'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Il file "{file}"è troppo grande. La dimensione non può superare {limit, number} {limit, plural, one{byte} other{bytes}}.', - 'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Il file "{file}" è troppo piccollo. La dimensione non può essere più piccola di {limit, number} {limit, plural, one{byte} other{bytes}}.', - 'The format of {attribute} is invalid.' => 'Il formato di {attribute} non è valido.', - 'The verification code is incorrect.' => 'Il codice di verifica non è corretto.', - 'Total {count, number} {count, plural, one{item} other{items}}.' => 'Totali {count, number} {count, plural, one{item} other{items}}.', - 'Unable to verify your data submission.' => 'Impossibile verificare i dati inviati.', - 'Unknown Class' => 'Classe Sconosciuta', - 'Unknown Method' => 'Metodo Sconosciuto', - 'Unknown Property' => 'Proprietà Sconosciuta', - 'Unknown command "{command}".' => 'Comando Sconosciuto "{command}".', - 'Unknown option: --{name}' => 'Opzione Sconosciuta: --{name}', - 'Update' => 'Aggiorna', - 'User Error' => 'Errore Utente', - 'User Warning' => 'Allarme utente', - 'View' => 'Vedi', - 'Warning' => 'Attenzione', - 'Yes' => 'Si', - 'You are not allowed to perform this action.' => 'Non sei autorizzato ad eseguire questa operazione', - 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Puoi caricare al massimo questo numero di file {limit, number} {limit, plural, one{file} other{files}}.', - 'the input value' => 'Il campo input', - '{attribute} "{value}" has already been taken.' => '{attribute} "{value}" è già presente.', - '{attribute} cannot be blank.' => '{attribute} non può essere vuoto.', - '{attribute} is invalid.' => '{attribute} non è valido.', - '{attribute} is not a valid URL.' => '{attribute} non è un URL valido.', - '{attribute} is not a valid email address.' => '{attribute} non è un email valida.', - '{attribute} must be "{requiredValue}".' => '{attribute} deve essere "{requiredValue}".', - '{attribute} must be a number.' => '{attribute} deve essere un numero', - '{attribute} must be a string.' => '{attribute} deve essere una stringa.', - '{attribute} must be an integer.' => '{attribute} deve essere un numero intero.', - '{attribute} must be either "{true}" or "{false}".' => '{attribute} deve essere "{true}" oppure "{false}".', - '{attribute} must be greater than "{compareValue}".' => '{attribute} deve essere più grande di "{compareValue}".', - '{attribute} must be greater than or equal to "{compareValue}".' => '{attribute} deve essere più grande o uguale a "{compareValue}".', - '{attribute} must be less than "{compareValue}".' => '{attribute} deve essere minore di "{compareValue}".', - '{attribute} must be less than or equal to "{compareValue}".' => '{attribute} deve essere minore o uguale a "{compareValue}".', - '{attribute} must be no greater than {max}.' => '{attribute} deve essere più grande di {max}.', - '{attribute} must be no less than {min}.' => '{attribute} deve essere minore di {min}.', - '{attribute} must be repeated exactly.' =>'{attribute} deve essere ripetuto esattamente.', - '{attribute} must not be equal to "{compareValue}".' => '{attribute} deve essere uguale a "{compareValue}".', - '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} dovrebbe contenere almeno {min, number} {min, plural, one{carattere} other{caratteri}}.', - '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute} dovrebbe contenere al massimo {max, number} {max, plural, one{carattere} other{caratteri}}.', - '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute} dovrebbe contenere {length, number} {length, plural, one{carattere} other{caratteri}}.', -); diff --git a/framework/yii/messages/ja/yii.php b/framework/yii/messages/ja/yii.php deleted file mode 100644 index a867470..0000000 --- a/framework/yii/messages/ja/yii.php +++ /dev/null @@ -1,81 +0,0 @@ - '(セットされていません)', - 'An internal server error occurred.' => 'サーバー内部エラーが発生しました。', - 'Are you sure to delete this item?' => 'この項目を削除してもよろしいですか?', - 'Delete' => '削除', - 'Error' => 'エラー', - 'File upload failed.' => 'ファイルアップロードに失敗しました。', - 'Home' => 'ホーム', - 'Invalid data received for parameter "{param}".' => 'パラメータ"{param}"に不正なデータを受け取りました。', - 'Login Required' => 'ログインが必要です', - 'Missing required arguments: {params}' => '必要な引数がありません: {params}', - 'Missing required parameters: {params}' => '必要なパラメータがありません: {params}', - 'No' => 'いいえ', - 'No help for unknown command "{command}".' => '不明なコマンド "{command}" にはヘルプがありません。', - 'No help for unknown sub-command "{command}".' => '不明なサブコマンド "{command}" にはヘルプがありません。', - 'No results found.' => '結果が得られませんでした。', - 'Only files with these extensions are allowed: {extensions}.' => '次の拡張子を持つファイルだけが許可されています : {extensions}', - 'Only files with these mimeTypes are allowed: {mimeTypes}.' => '次の MIME タイプのファイルだけが許可されています : {mimeTypes}', - 'Page not found.' => 'ページが見つかりません。', - 'Please fix the following errors:' => '次のエラーを修正してください :', - 'Please upload a file.' => 'ファイルをアップロードしてください。', - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.' => '{totalCount} 件中 {begin} から {end} までを表示しています。', - 'The file "{file}" is not an image.' => 'ファイル "{file}" は画像ではありません。', - 'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'ファイル "{file}" が大きすぎます。サイズは {limit} バイトを超えることができません。', - 'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'ファイル "{file}" が小さすぎます。サイズは {limit} バイトを下回ることができません。', - 'The format of {attribute} is invalid.' => '{attribute}の書式が正しくありません。', - 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => '画像 "{file}" が大きすぎます。高さが {limit} より大きくてはいけません。', - 'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => '画像 "{file}" が大きすぎます。幅が {limit} より大きくてはいけません。', - 'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => '画像 "{file}" が小さすぎます。高さが {limit} より小さくてはいけません。', - 'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => '画像 "{file}" が小さすぎます。幅が {limit} より小さくてはいけません。', - 'The verification code is incorrect.' => '検証コードが正しくありません。', - 'Total {count, number} {count, plural, one{item} other{items}}.' => '合計 {count} 件。', - 'Unable to verify your data submission.' => 'データ送信を検証できませんでした。', - 'Unknown command "{command}".' => '不明なコマンド "{command}" 。', - 'Unknown option: --{name}' => '不明なオプション: --{name}', - 'Update' => '更新', - 'View' => '閲覧', - 'Yes' => 'はい', - 'You are not allowed to perform this action.' => 'このアクションの実行は許可されていません。', - 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => '最大で {limit} 個のファイルをアップロードできます。', - 'the input value' => '入力値', - '{attribute} "{value}" has already been taken.' => '{attribute}で "{value}" は既に使われています。', - '{attribute} cannot be blank.' => '{attribute}は空白ではいけません。', - '{attribute} is invalid.' => '{attribute}は無効です。', - '{attribute} is not a valid URL.' => '{attribute}は有効な URL 書式ではありません。', - '{attribute} is not a valid email address.' => '{attribute}は有効なメールアドレス書式ではありません。', - '{attribute} must be "{requiredValue}".' => '{attribute}は{value}である必要があります。', - '{attribute} must be a number.' => '{attribute}は数字にしてください。', - '{attribute} must be a string.' => '{attribute}は文字列にしてください。', - '{attribute} must be an integer.' => '{attribute}は整数にしてください。', - '{attribute} must be either "{true}" or "{false}".' => '{attribute}は{true}か{false}のいずれかである必要があります。', - '{attribute} must be greater than "{compareValue}".' => '{attribute}は"{compareValue}"より大きい必要があります。', - '{attribute} must be greater than or equal to "{compareValue}".' => '{attribute}は"{compareValue}"以上である必要があります。', - '{attribute} must be less than "{compareValue}".' => '{attribute}は"{compareValue}"より小さい必要があります。', - '{attribute} must be less than or equal to "{compareValue}".' => '{attribute}は"{compareValue}"以下である必要があります。', - '{attribute} must be no greater than {max}.' => '{attribute}は"{compareValue}"より大きくてはいけません。', - '{attribute} must be no less than {min}.' => '{attribute}は"{compareValue}"より小さくてはいけません。', - '{attribute} must be repeated exactly.' => '{attribute}は正確に繰り返してください。', - '{attribute} must not be equal to "{compareValue}".' => '{attribute}は"{compareValue}"ではいけません。', - '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute}は少なくとも{min}文字なければなりません。', - '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute}は多くとも{max}文字なければなりません。', - '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute}は{length}文字でなければなりません。', -); diff --git a/framework/yii/messages/pl/yii.php b/framework/yii/messages/pl/yii.php deleted file mode 100644 index 8715534..0000000 --- a/framework/yii/messages/pl/yii.php +++ /dev/null @@ -1,81 +0,0 @@ - '(brak wartości)', - 'An internal server error occurred.' => 'Wystąpił wewnętrzny błąd serwera.', - 'Are you sure to delete this item?' => 'Na pewno usunąć ten element?', - 'Delete' => 'Usuń', - 'Error' => 'Bład', - 'File upload failed.' => 'Wgrywanie pliku nie powiodło się.', - 'Home' => 'Strona domowa', - 'Invalid data received for parameter "{param}".' => 'Otrzymano nieprawidłowe dane dla parametru "{param}".', - 'Login Required' => 'Wymagane zalogowanie się', - 'Missing required arguments: {params}' => 'Brak wymaganych argumentów: {params}', - 'Missing required parameters: {params}' => 'Brak wymaganych parametrów: {params}', - 'No' => 'Nie', - 'No help for unknown command "{command}".' => 'Brak pomocy dla nieznanego polecenia "{command}".', - 'No help for unknown sub-command "{command}".' => 'Brak pomocy dla nieznanego pod-polecenia "{command}".', - 'No results found.' => 'Brak wyników.', - 'Only files with these extensions are allowed: {extensions}.' => 'Dozwolone są tylko pliki z następującymi rozszerzeniami: {extensions}.', - 'Only files with these mimeTypes are allowed: {mimeTypes}.' => 'Dozwolone są tylko pliki o następujących typach MIME: {mimeTypes}.', - 'Page not found.' => 'Nie odnaleziono strony.', - 'Please fix the following errors:' => 'Proszę poprawić następujące błędy:', - 'Please upload a file.' => 'Proszę wgrać plik.', - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.' => 'Wyświetlone {begin, number}-{end, number} z {totalCount, number}.', - 'The file "{file}" is not an image.' => 'Plik "{file}" nie jest obrazem.', - 'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Plik "{file}" jest zbyt duży. Jego rozmiar nie może przekraczać {limit, number} {limit, plural, one{bajtu} few{bajtów} many{bajtów} other{bajta}}.', - 'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Plik "{file}" jest za mały. Jego rozmiar nie może być mniejszy niż {limit, number} {limit, plural, one{bajtu} few{bajtów} many{bajtów} other{bajta}}.', - 'The format of {attribute} is invalid.' => 'Format {attribute} jest nieprawidłowy.', - 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Obraz "{file}" jest zbyt duży. Wysokość nie może być większa niż {limit, number} {limit, plural, one{piksela} few{pikseli} many{pikseli} other{piksela}}.', - 'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Obraz "{file}" jest zbyt duży. Szerokość nie może być większa niż {limit, number} {limit, plural, one{piksela} few{pikseli} many{pikseli} other{piksela}}.', - 'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Obraz "{file}" jest za mały. Wysokość nie może być mniejsza niż {limit, number} {limit, plural, one{piksela} few{pikseli} many{pikseli} other{piksela}}.', - 'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Obraz "{file}" jest za mały. Szerokość nie może być mniejsza niż {limit, number} {limit, plural, one{piksela} few{pikseli} many{pikseli} other{piksela}}.', - 'The verification code is incorrect.' => 'Kod weryfikacyjny jest nieprawidłowy.', - 'Total {count, number} {count, plural, one{item} other{items}}.' => 'Razem {count, number} {count, plural, one{rekord} few{rekordy} many{rekordów} other{rekordu}}.', - 'Unable to verify your data submission.' => 'Nie udało się zweryfikować przesłanych danych.', - 'Unknown command "{command}".' => 'Nieznane polecenie "{command}".', - 'Unknown option: --{name}' => 'Nieznana opcja: --{name}', - 'Update' => 'Aktualizuj', - 'View' => 'Zobacz szczegóły', - 'Yes' => 'Tak', - 'You are not allowed to perform this action.' => 'Brak upoważnienia do wykonania tej czynności.', - 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Możliwe wgranie najwyżej {limit, number} {limit, plural, one{pliku} few{plików} many{plików} other{pliku}}.', - 'the input value' => 'wartość wejściowa', - '{attribute} "{value}" has already been taken.' => '{attribute} "{value}" jest już w użyciu.', - '{attribute} cannot be blank.' => '{attribute} nie może pozostać bez wartości.', - '{attribute} is invalid.' => '{attribute} zawiera nieprawidłową wartość.', - '{attribute} is not a valid URL.' => '{attribute} nie zawiera prawidłowego adresu URL.', - '{attribute} is not a valid email address.' => '{attribute} nie zawiera prawidłowego adresu email.', - '{attribute} must be "{requiredValue}".' => '{attribute} musi mieć wartość "{requiredValue}".', - '{attribute} must be a number.' => '{attribute} musi być liczbą.', - '{attribute} must be a string.' => '{attribute} musi być tekstem.', - '{attribute} must be an integer.' => '{attribute} musi być liczbą całkowitą.', - '{attribute} must be either "{true}" or "{false}".' => '{attribute} musi mieć wartość "{true}" lub "{false}".', - '{attribute} must be greater than "{compareValue}".' => '{attribute} musi mieć wartość większą od "{compareValue}".', - '{attribute} must be greater than or equal to "{compareValue}".' => '{attribute} musi mieć wartość większą lub równą "{compareValue}".', - '{attribute} must be less than "{compareValue}".' => '{attribute} musi mieć wartość mniejszą od "{compareValue}".', - '{attribute} must be less than or equal to "{compareValue}".' => '{attribute} musi mieć wartość mniejszą lub równą "{compareValue}".', - '{attribute} must be no greater than {max}.' => '{attribute} musi wynosić nie więcej niż {max}.', - '{attribute} must be no less than {min}.' => '{attribute} musi wynosić nie mniej niż {min}.', - '{attribute} must be repeated exactly.' => 'Wartość {attribute} musi być dokładnie powtórzona.', - '{attribute} must not be equal to "{compareValue}".' => '{attribute} musi mieć wartość różną od "{compareValue}".', - '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} powinien zawierać co najmniej {min, number} {min, plural, one{znak} few{znaki} many{znaków} other{znaku}}.', - '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute} powinien zawierać nie więcej niż {max, number} {min, plural, one{znak} few{znaki} many{znaków} other{znaku}}.', - '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute} powinien zawierać dokładnie {length, number} {min, plural, one{znak} few{znaki} many{znaków} other{znaku}}.', -); diff --git a/framework/yii/messages/pt-BR/yii.php b/framework/yii/messages/pt-BR/yii.php deleted file mode 100644 index 4e7073f..0000000 --- a/framework/yii/messages/pt-BR/yii.php +++ /dev/null @@ -1,81 +0,0 @@ - '', - '(not set)' => '(não definido)', - 'An internal server error occurred.' => 'Ocorreu um erro interno do servidor.', - 'Are you sure to delete this item?' => 'Tem certeza de que deseja excluir este item?', - 'Delete' => 'Excluir', - 'Error' => 'Error', - 'File upload failed.' => 'O upload do arquivo falhou.', - 'Home' => 'Página Inicial', - 'Invalid data received for parameter "{param}".' => 'Dados inválidos recebidos para o parâmetro “{param}”.', - 'Login Required' => 'Login Necessário.', - 'Missing required arguments: {params}' => 'Argumentos obrigatórios ausentes: {params}', - 'Missing required parameters: {params}' => 'Parâmetros obrigatórios ausentes: {params}', - 'No' => 'Não', - 'No help for unknown command "{command}".' => 'Não há ajuda para o comando desconhecido “{command}”.', - 'No help for unknown sub-command "{command}".' => 'Não há ajuda para o sub-comando desconhecido “{command}”.', - 'No results found.' => 'Nenhum resultado foi encontrado.', - 'Only files with these extensions are allowed: {extensions}.' => 'Só são permitidos arquivos com as seguintes extensões: {extensions}.', - 'Only files with these mimeTypes are allowed: {mimeTypes}.' => 'Só são permitidos arquivos com os seguintes mimeTypes: {mimeTypes}.', - 'Page not found.' => 'Página não encontrada.', - 'Please fix the following errors:' => 'Por favor, corrija os seguintes erros:', - 'Please upload a file.' => 'Por favor suba um arquivo.', - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.' => 'Exibindo {begin, number}-{end, number} de {totalCount, number} {totalCount, plural, one{item} other{itens}}.', - 'The file "{file}" is not an image.' => 'O arquivo “{file}” não é uma imagem.', - 'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'O arquivo “{file}” é grande demais. Seu tamanho não pode exceder {limit, number} {limit, plural, one{byte} other{bytes}}.', - 'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'O arquivo “{file}” é pequeno demais. Seu tamanho não pode ser menor do que {limit, number} {limit, plural, one{byte} other{bytes}}.', - 'The format of {attribute} is invalid.' => 'O formato de “{attribute}” é inválido.', - 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'O arquivo “{file}” é grande demais. A altura não pode ser maior do que {limit, number} {limit, plural, one{pixel} other{pixels}}.', - 'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'O arquivo “{file}” é grande demais. A largura não pode ser maior do que {limit, number} {limit, plural, one{pixel} other{pixels}}.', - 'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'O arquivo “{file}” é pequeno demais. A altura não pode ser menor do que {limit, number} {limit, plural, one{pixel} other{pixels}}.', - 'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'O arquivo “{file}” é pequeno demais. A largura não pode ser menor do que {limit, number} {limit, plural, one{pixel} other{pixels}}.', - 'The verification code is incorrect.' => 'O código de verificação está incorreto.', - 'Total {count, number} {count, plural, one{item} other{items}}.' => 'Total {count, number} {count, plural, one{item} other{itens}}.', - 'Unable to verify your data submission.' => 'Não foi possível verificar a sua submissão de dados.', - 'Unknown command "{command}".' => 'Comando desconhecido “{command}”.', - 'Unknown option: --{name}' => 'Opção desconhecida : --{name}', - 'Update' => 'Atualizar', - 'Yes' => 'Sim', - 'You are not allowed to perform this action.' => 'Você não está autorizado a realizar essa ação.', - 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Você pode fazer o upload de no máximo {limit, number} {limit, plural, one{arquivo} other{arquivos}}.', - 'the input value' => 'o valor de entrada', - '{attribute} "{value}" has already been taken.' => '{attribute} “{value}” já foi utilizado.', - '{attribute} cannot be blank.' => '“{attribute}” não pode ficar em branco.', - '{attribute} is invalid.' => '“{attribute}” é inválido.', - '{attribute} is not a valid URL.' => '“{attribute}” não é uma URL válida.', - '{attribute} is not a valid email address.' => '“{attribute}” não é um endereço de e-mail válido.', - '{attribute} must be "{requiredValue}".' => '“{attribute}” deve ser “{requiredValue}”.', - '{attribute} must be a number.' => '“{attribute}” deve ser um número.', - '{attribute} must be a string.' => '“{attribute}” deve ser uma string.', - '{attribute} must be an integer.' => '“{attribute}” deve ser um número inteiro.', - '{attribute} must be either "{true}" or "{false}".' => '“{attribute}” deve ser “{true}” ou “{false}”.', - '{attribute} must be greater than "{compareValue}".' => '“{attribute}” deve ser maior do que “{compareValue}”.', - '{attribute} must be greater than or equal to "{compareValue}".' => '“{attribute}” deve ser maior ou igual a “{compareValue}”.', - '{attribute} must be less than "{compareValue}".' => '“{attribute}” deve ser menor do que “{compareValue}”.', - '{attribute} must be less than or equal to "{compareValue}".' => '“{attribute}” deve ser menor ou igual a “{compareValue}”.', - '{attribute} must be no greater than {max}.' => '“{attribute}” não pode ser maior do que {max}.', - '{attribute} must be no less than {min}.' => '“{attribute}” não pode ser menor do que {min}.', - '{attribute} must be repeated exactly.' => '“{attribute}” deve ser repetido exatamente.', - '{attribute} must not be equal to "{compareValue}".' => '“{attribute}” não deve ser igual a “{compareValue}”.', - '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '“{attribute}” deve conter pelo menos {min, number} {min, plural, one{caractere} other{caracteres}}.', - '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '“{attribute}” deve conter no máximo {max, number} {max, plural, one{caractere} other{caracteres}}.', - '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '“{attribute}” deve conter {length, number} {length, plural, one{caractere} other{caracteres}}.', -); diff --git a/framework/yii/messages/ro/yii.php b/framework/yii/messages/ro/yii.php deleted file mode 100644 index cd1017a..0000000 --- a/framework/yii/messages/ro/yii.php +++ /dev/null @@ -1,81 +0,0 @@ - '(nu este setat)', - 'An internal server error occurred.' => 'A aparut o eroare internă de server.', - 'Are you sure to delete this item?' => 'Sunteți sigur că doriți să ștergeți acest item?', - 'Delete' => 'Șterge', - 'Error' => 'Eroare', - 'File upload failed.' => 'Încărcarea fișierului a eșuat.', - 'Home' => 'Acasă', - 'Invalid data received for parameter "{param}".' => 'Date incorecte primite pentru parametrul "{param}".', - 'Login Required' => 'Autentificare obligatorie.', - 'Missing required arguments: {params}' => 'Lipsesc argumente obligatorii: {params}', - 'Missing required parameters: {params}' => 'Lipsesc parametrii obligatori: {params}', - 'No' => 'Nu', - 'No help for unknown command "{command}".' => 'Nu sunt referințe pentru comanda necunoscută "{command}".', - 'No help for unknown sub-command "{command}".' => 'Nu sunt referințe pentru sub-comanda necunoscută "{command}".', - 'No results found.' => 'Nu a fost găsit niciun rezultat.', - 'Only files with these extensions are allowed: {extensions}.' => 'Se acceptă numai fișiere cu următoarele extensii: {extensions}.', - 'Only files with these mimeTypes are allowed: {mimeTypes}.' => 'Se acceptă numai fișiere cu următoarele tipuri MIME: {mimeTypes}.', - 'Page not found.' => 'Pagina nu a fost găsită.', - 'Please fix the following errors:' => 'Vă rugăm sa corectați următoarele erori:', - 'Please upload a file.' => 'Vă rugăm sa încărcați un fișier.', - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.' => 'Sunt afișați itemii {begin, number}-{end, number} din {totalCount, number}.', - 'The file "{file}" is not an image.' => 'Fișierul «{file}» nu este o imagine.', - 'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Fișierul «{file}» este prea mare. Dimensiunea acestuia nu trebuie să fie mai mare de {limit, number} {limit, plural, one{byte} other{bytes}}.', - 'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Fișierul «{file}» este prea mic. Dimensiunea acestuia nu trebuie sa fie mai mică de {limit, number} {limit, plural, one{byte} other{bytes}}.', - 'The format of {attribute} is invalid.' => 'Formatul «{attribute}» nu este valid.', - 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Imaginea «{file}» este prea mare. Înălțimea nu trebuie să fie mai mare de {limit, number} {limit, plural, one{pixel} other{pixeli}}.', - 'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Imaginea «{file}» este prea mare. Lățimea nu trebuie să fie mai mare de {limit, number} {limit, plural, one{pixel} other{pixeli}}.', - 'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Imaginea «{file}» este prea mică. Înălțimea nu trebuie să fie mai mică de {limit, number} {limit, plural, one{pixel} other{pixeli}}.', - 'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Imaginea «{file}» este prea mică. Lățimea nu trebuie sa fie mai mică de {limit, number} {limit, plural, one{pixel} other{pixeli}}.', - 'The verification code is incorrect.' => 'Codul de verificare este incorect.', - 'Total {count, number} {count, plural, one{item} other{items}}.' => 'Total {count, number} {count, plural, one{item} other{itemi}}.', - 'Unable to verify your data submission.' => 'Datele trimise nu au putut fi verificate.', - 'Unknown command "{command}".' => 'Comandă necunoscută "{command}".', - 'Unknown option: --{name}' => 'Opțiune necunoscută : --{name}', - 'Update' => 'Redactare', - 'View' => 'Vizualizare', - 'Yes' => 'Da', - 'You are not allowed to perform this action.' => 'Nu aveți dreptul să efectuați această acțiunea.', - 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Puteți încărca maxim {limit, number} {limit, plural, one{fișier} other{fișiere}}.', - 'the input value' => 'valoarea introdusă', - '{attribute} "{value}" has already been taken.' => '{attribute} «{value}» este deja ocupat.', - '{attribute} cannot be blank.' => '«{attribute}» nu poate fi gol.', - '{attribute} is invalid.' => '«{attribute}» este incorect.', - '{attribute} is not a valid URL.' => '«{attribute}» nu este un URL valid.', - '{attribute} is not a valid email address.' => '«{attribute}» nu este o adresă de email validă.', - '{attribute} must be "{requiredValue}".' => '«{attribute}» trebuie să fie «{requiredValue}».', - '{attribute} must be a number.' => '«{attribute}» trebuie să fie un număr.', - '{attribute} must be a string.' => '«{attribute}» trebuie să fie un șir de caractere.', - '{attribute} must be an integer.' => '«{attribute}» trebuie să fie un număr întreg.', - '{attribute} must be either "{true}" or "{false}".' => '«{attribute}» trebuie să fie «{true}» sau «{false}».', - '{attribute} must be greater than "{compareValue}".' => '«{attribute}» trebuie să fie mai mare ca «{compareValue}».', - '{attribute} must be greater than or equal to "{compareValue}".' => '«{attribute}» trebuie să fie mai mare sau egal cu «{compareValue}».', - '{attribute} must be less than "{compareValue}".' => '«{attribute}» trebuie să fie mai mic ca «{compareValue}».', - '{attribute} must be less than or equal to "{compareValue}".' => '«{attribute}» trebuie să fie mai mic sau egal cu «{compareValue}».', - '{attribute} must be no greater than {max}.' => '«{attribute}» nu trebuie să fie mai mare ca {max}.', - '{attribute} must be no less than {min}.' => '«{attribute}» nu trebuie să fie mai mic ca {min}.', - '{attribute} must be repeated exactly.' => '«{attribute}» trebuie să fie repetat exact.', - '{attribute} must not be equal to "{compareValue}".' => '«{attribute}» nu trebuie să fie egală cu «{compareValue}».', - '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '«{attribute}» trebuie să conțină minim {min, number} {min, plural, one{caracter} other{caractere}}.', - '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '«{attribute}» trebuie să conțină maxim {max, number} {max, plural, one{caracter} other{caractere}}.', - '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '«{attribute}» trebuie să conțină {length, number} {length, plural, one{caracter} other{caractere}}.', -); \ No newline at end of file diff --git a/framework/yii/messages/ru/yii.php b/framework/yii/messages/ru/yii.php deleted file mode 100644 index bcca4e9..0000000 --- a/framework/yii/messages/ru/yii.php +++ /dev/null @@ -1,81 +0,0 @@ - 'Просмотр', - '(not set)' => '(не задано)', - 'An internal server error occurred.' => 'Возникла внутренняя ошибка сервера.', - 'Are you sure to delete this item?' => 'Вы уверены, что хотите удалить этот элемент?', - 'Delete' => 'Удалить', - 'Error' => 'Ошибка', - 'File upload failed.' => 'Загрузка файла не удалась.', - 'Home' => 'Главная', - 'Invalid data received for parameter "{param}".' => 'Неправильное значение параметра "{param}".', - 'Login Required' => 'Требуется вход.', - 'Missing required arguments: {params}' => 'Отсутствуют обязательные аргументы: {params}', - 'Missing required parameters: {params}' => 'Отсутствуют обязательные параметры: {params}', - 'No' => 'Нет', - 'No help for unknown command "{command}".' => 'Справка недоступна для неизвестной команды "{command}".', - 'No help for unknown sub-command "{command}".' => 'Справка недоступна для неизвестной субкоманды "{command}".', - 'No results found.' => 'Ничего не найдено.', - 'Only files with these extensions are allowed: {extensions}.' => 'Разрешена загрузка файлов только со следующими расширениями: {extensions}.', - 'Only files with these mimeTypes are allowed: {mimeTypes}.' => 'Разрешена загрузка файлов только со следующими MIME-типами: {mimeTypes}.', - 'Page not found.' => 'Страница не найдена.', - 'Please fix the following errors:' => 'Исправьте следующие ошибки:', - 'Please upload a file.' => 'Загрузите файл.', - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.' => 'Показаны записи {begin, number}-{end, number} из {totalCount, number}.', - 'The file "{file}" is not an image.' => 'Файл «{file}» не является изображением.', - 'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Файл «{file}» слишком большой. Размер не должен превышать {limit, number} {limit, plural, one{# байт} few{# байта} many{# байт} other{# байта}}.', - 'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Файл «{file}» слишком маленький. Размер должен быть более {limit, number} {limit, plural, one{# байт} few{# байта} many{# байт} other{# байта}}.', - 'The format of {attribute} is invalid.' => 'Неверный формат значения «{attribute}».', - 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Файл «{file}» слишком большой. Высота не должна превышать {limit, number} {limit, plural, one{# пиксель} few{# пикселя} many{# пикселей} other{# пикселя}}.', - 'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Файл «{file}» слишком большой. Ширина не должна превышать {limit, number} {limit, plural, one{# пиксель} few{# пикселя} many{# пикселей} other{# пикселя}}.', - 'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Файл «{file}» слишком маленький. Высота должна быть более {limit, number} {limit, plural, one{# пиксель} few{# пикселя} many{# пикселей} other{# пикселя}}.', - 'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Файл «{file}» слишком маленький. Ширина должна быть более {limit, number} {limit, plural, one{# пиксель} few{# пикселя} many{# пикселей} other{# пикселя}}.', - 'The verification code is incorrect.' => 'Неправильный проверочный код.', - 'Total {count, number} {count, plural, one{item} other{items}}.' => 'Всего {count, number} {count, plural, one{# запись} few{# записи} many{# записей} other{# записи}}.', - 'Unable to verify your data submission.' => 'Не удалось проверить переданные данные.', - 'Unknown command "{command}".' => 'Неизвестная команда "{command}".', - 'Unknown option: --{name}' => 'Неизвестная опция : --{name}', - 'Update' => 'Редактировать', - 'Yes' => 'Да', - 'You are not allowed to perform this action.' => 'Вам не разрешено производить данное действие.', - 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Вы не можете загружать более {limit, number} {limit, plural, one{# файла} few{# файлов} many{# файлов} other{# файла}}.', - 'the input value' => 'введённое значение', - '{attribute} "{value}" has already been taken.' => '{attribute} «{value}» уже занят.', - '{attribute} cannot be blank.' => 'Необходимо заполнить «{attribute}».', - '{attribute} is invalid.' => 'Значение «{attribute}» не верно.', - '{attribute} is not a valid URL.' => 'Значение «{attribute}» не является правильным URL.', - '{attribute} is not a valid email address.' => 'Значение «{attribute}» не является правильным email адресом.', - '{attribute} must be "{requiredValue}".' => 'Значение «{attribute}» должно быть равно «{requiredValue}».', - '{attribute} must be a number.' => 'Значение «{attribute}» должно быть числом.', - '{attribute} must be a string.' => 'Значение «{attribute}» должно быть строкой.', - '{attribute} must be an integer.' => 'Значение «{attribute}» должно быть целым числом.', - '{attribute} must be either "{true}" or "{false}".' => 'Значение «{attribute}» должно быть равно «{true}» или «{false}».', - '{attribute} must be greater than "{compareValue}".' => 'Значение «{attribute}» должно быть больше значения «{compareValue}».', - '{attribute} must be greater than or equal to "{compareValue}".' => 'Значение «{attribute}» должно быть больше или равно значения «{compareValue}».', - '{attribute} must be less than "{compareValue}".' => 'Значение «{attribute}» должно быть меньше значения «{compareValue}».', - '{attribute} must be less than or equal to "{compareValue}".' => 'Значение «{attribute}» должно быть меньше или равно значения «{compareValue}».', - '{attribute} must be no greater than {max}.' => 'Значение «{attribute}» не должно превышать {max}.', - '{attribute} must be no less than {min}.' => 'Значение «{attribute}» должно быль больше {min}.', - '{attribute} must be repeated exactly.' => 'Значение «{attribute}» должно быть повторено в точности.', - '{attribute} must not be equal to "{compareValue}".' => 'Значение «{attribute}» не должно быть равно «{compareValue}».', - '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => 'Значение «{attribute}» должно содержать минимум {min, number} {min, plural, one{# символ} few{# символа} many{# символов} other{# символа}}.', - '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => 'Значение «{attribute}» должно содержать максимум {max, number} {max, plural, one{# символ} few{# символа} many{# символов} other{# символа}}.', - '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => 'Значение «{attribute}» должно содержать {length, number} {length, plural, one{# символ} few{# символа} many{# символов} other{# символа}}.', -); diff --git a/framework/yii/messages/zh_cn/yii.php b/framework/yii/messages/zh_cn/yii.php deleted file mode 100644 index 9d2ce17..0000000 --- a/framework/yii/messages/zh_cn/yii.php +++ /dev/null @@ -1,81 +0,0 @@ - '该输入', - '(not set)' => '(未设置)', - 'An internal server error occurred.' => '服务器内部错误。', - 'Are you sure to delete this item?' => '确定要删除这条数据吗?', - 'Delete' => '删除', - 'Error' => '错误', - 'File upload failed.' => '文件上传失败。', - 'Home' => '首页', - 'Invalid data received for parameter "{param}".' => '"{param}"参数接收到无效的数据。', - 'Login Required' => '需要登录', - 'Missing required arguments: {params}' => '函数缺少参数:{params}', - 'Missing required parameters: {params}' => '缺少参数:{params}', - 'No' => '否', - 'No help for unknown command "{command}".' => '命令"{command}"发生未知的错误。', - 'No help for unknown sub-command "{command}".' => '子命令"{command}"发生未知的错误。', - 'No results found.' => '没有找到数据。', - 'Only files with these extensions are allowed: {extensions}.' => '只允许使用以下文件扩展名的文件:{extensions}。', - 'Only files with these mimeTypes are allowed: {mimeTypes}.' => '只允许包含以下 mimeTypes 的文件:{mimeTypes}。', - 'Page not found.' => '页面未找到。', - 'Please fix the following errors:' => '请修复以下错误', - 'Please upload a file.' => '请上传一个文件。', - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.' => '第{begin, number}-{end, number}条,共{totalCount, number}条数据.', - 'The file "{file}" is not an image.' => '文件 "{file}" 不是一个图像文件。', - 'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => '文件"{file}"太大。它的大小不能超过{limit, number}字节。', - 'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => '该文件"{file}"太小。它的大小不得小于{limit, number}字节。', - 'The format of {attribute} is invalid.' => '属性 {attribute} 的格式无效。', - 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => '图像"{file}"太大。他的高度不得超过{limit, number}像素。', - 'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => '图像"{file}"太大。他的宽度不得超过{limit, number}像素。', - 'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => '图像"{file}"太小。他的高度不得小于{limit, number}像素。', - 'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => '图像"{file}"太小。他的宽度不得小于{limit, number}像素。', - 'The verification code is incorrect.' => '验证码不正确。', - 'Total {count, number} {count, plural, one{item} other{items}}.' => '总计{count, number}条数据。', - 'Unable to verify your data submission.' => '您提交的数据无法被验证。', - 'Unknown command "{command}".' => '未知的命令 "{command}"。', - 'Unknown option: --{name}' => '未知的选项:--{name}', - 'Update' => '更新', - 'View' => '查看', - 'Yes' => '是', - 'You are not allowed to perform this action.' => '您没有执行此操作的权限。', - 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => '您最多上传{limit, number}个文件。', - '{attribute} "{value}" has already been taken.' => '{attribute}的值"{value}"已经被占用了。', - '{attribute} cannot be blank.' => '{attribute}不能为空。', - '{attribute} is invalid.' => '{attribute}是无效的。', - '{attribute} is not a valid URL.' => '{attribute}不是一条有效的URL。', - '{attribute} is not a valid email address.' => '{attribute}不是有效的邮箱地址。', - '{attribute} must be "{requiredValue}".' => '{attribute}必须为"{requiredValue}"。', - '{attribute} must be a number.' => '{attribute}必须是一个数字。', - '{attribute} must be a string.' => '{attribute}必须是一条字符串。', - '{attribute} must be an integer.' => '{attribute}必须是整数。', - '{attribute} must be either "{true}" or "{false}".' => '{attribute}的值必须要么为"{true}",要么为"{false}"。', - '{attribute} must be greater than "{compareValue}".' => '{attribute}的值必须大于"{compareValue}"。', - '{attribute} must be greater than or equal to "{compareValue}".' => '{attribute}的值必须大于或等于"{compareValue}"。', - '{attribute} must be less than "{compareValue}".' => '{attribute}的值必须小于"{compareValue}"。', - '{attribute} must be less than or equal to "{compareValue}".' => '{attribute}的值必须小于或等于"{compareValue}"。', - '{attribute} must be no greater than {max}.' => '{attribute}的值必须不大于{max}。', - '{attribute} must be no less than {min}.' => '{attribute}的值必须不小于{max}。', - '{attribute} must be repeated exactly.' => '{attribute}必须重复。', - '{attribute} must not be equal to "{compareValue}".' => '{attribute}的值不得等于"{compareValue}"。', - '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute}应该包含至少{min, number}个字符。', - '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute}只能包含至多{max, number}个字符。', - '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute}应该包含{length, number}个字符。', -); diff --git a/framework/yii/mutex/DbMutex.php b/framework/yii/mutex/DbMutex.php deleted file mode 100644 index 3699c36..0000000 --- a/framework/yii/mutex/DbMutex.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @since 2.0 - */ -abstract class DbMutex extends Mutex -{ - /** - * @var Connection|string the DB connection object or the application component ID of the DB connection. - * After the Mutex object is created, if you want to change this property, you should only assign - * it with a DB connection object. - */ - public $db = 'db'; - - /** - * Initializes generic database table based mutex implementation. - * @throws InvalidConfigException if [[db]] is invalid. - */ - public function init() - { - parent::init(); - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - } - if (!$this->db instanceof Connection) { - throw new InvalidConfigException('Mutex::db must be either a DB connection instance or the application component ID of a DB connection.'); - } - } -} diff --git a/framework/yii/mutex/FileMutex.php b/framework/yii/mutex/FileMutex.php deleted file mode 100644 index fd5cb00..0000000 --- a/framework/yii/mutex/FileMutex.php +++ /dev/null @@ -1,104 +0,0 @@ - - * @since 2.0 - */ -class FileMutex extends Mutex -{ - /** - * @var string the directory to store mutex files. You may use path alias here. - * Defaults to the "mutex" subdirectory under the application runtime path. - */ - public $mutexPath = '@runtime/mutex'; - /** - * @var integer the permission to be set for newly created mutex files. - * This value will be used by PHP chmod() function. No umask will be applied. - * If not set, the permission will be determined by the current environment. - */ - public $fileMode; - /** - * @var integer the permission to be set for newly created directories. - * This value will be used by PHP chmod() function. No umask will be applied. - * Defaults to 0775, meaning the directory is read-writable by owner and group, - * but read-only for other users. - */ - public $dirMode = 0775; - /** - * @var resource[] stores all opened lock files. Keys are lock names and values are file handles. - */ - private $_files = []; - - - /** - * Initializes mutex component implementation dedicated for UNIX, GNU/Linux, Mac OS X, and other UNIX-like - * operating systems. - * @throws InvalidConfigException - */ - public function init() - { - if (stripos(php_uname('s'), 'win') === 0) { - throw new InvalidConfigException('FileMutex does not have MS Windows operating system support.'); - } - $this->mutexPath = Yii::getAlias($this->mutexPath); - if (!is_dir($this->mutexPath)) { - FileHelper::createDirectory($this->mutexPath, $this->dirMode, true); - } - } - - /** - * Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - */ - protected function acquireLock($name, $timeout = 0) - { - $fileName = $this->mutexPath . '/' . md5($name) . '.lock'; - $file = fopen($fileName, 'w+'); - if ($file === false) { - return false; - } - if ($this->fileMode !== null) { - @chmod($fileName, $this->fileMode); - } - $waitTime = 0; - while (!flock($file, LOCK_EX | LOCK_NB)) { - $waitTime++; - if ($waitTime > $timeout) { - fclose($file); - return false; - } - sleep(1); - } - $this->_files[$name] = $file; - return true; - } - - /** - * Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - */ - protected function releaseLock($name) - { - if (!isset($this->_files[$name]) || !flock($this->_files[$name], LOCK_UN)) { - return false; - } else { - fclose($this->_files[$name]); - unset($this->_files[$name]); - return true; - } - } -} diff --git a/framework/yii/mutex/Mutex.php b/framework/yii/mutex/Mutex.php deleted file mode 100644 index 611e725..0000000 --- a/framework/yii/mutex/Mutex.php +++ /dev/null @@ -1,95 +0,0 @@ - - * @since 2.0 - */ -abstract class Mutex extends Component -{ - /** - * @var boolean whether all locks acquired in this process (i.e. local locks) must be released automagically - * before finishing script execution. Defaults to true. Setting this property to true means that all locks - * acquire in this process must be released in any case (regardless any kind of errors or exceptions). - */ - public $autoRelease = true; - /** - * @var string[] names of the locks acquired in the current PHP process. - */ - private $_locks = []; - - - /** - * Initializes the mutex component. - */ - public function init() - { - if ($this->autoRelease) { - $locks = &$this->_locks; - register_shutdown_function(function () use (&$locks) { - foreach ($locks as $lock) { - $this->release($lock); - } - }); - } - } - - /** - * Acquires lock by given name. - * @param string $name of the lock to be acquired. Must be unique. - * @param integer $timeout to wait for lock to be released. Defaults to zero meaning that method will return - * false immediately in case lock was already acquired. - * @return boolean lock acquiring result. - */ - public function acquire($name, $timeout = 0) - { - if ($this->acquireLock($name, $timeout)) { - $this->_locks[] = $name; - return true; - } else { - return false; - } - } - - /** - * Release acquired lock. This method will return false in case named lock was not found. - * @param string $name of the lock to be released. This lock must be already created. - * @return boolean lock release result: false in case named lock was not found.. - */ - public function release($name) - { - if ($this->releaseLock($name)) { - $index = array_search($name, $this->_locks); - if ($index !== false) { - unset($this->_locks[$index]); - } - return true; - } else { - return false; - } - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - */ - abstract protected function acquireLock($name, $timeout = 0); - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - */ - abstract protected function releaseLock($name); -} diff --git a/framework/yii/mutex/MysqlMutex.php b/framework/yii/mutex/MysqlMutex.php deleted file mode 100644 index af05b9c..0000000 --- a/framework/yii/mutex/MysqlMutex.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @since 2.0 - */ -class MysqlMutex extends Mutex -{ - /** - * Initializes MySQL specific mutex component implementation. - * @throws InvalidConfigException if [[db]] is not MySQL connection. - */ - public function init() - { - parent::init(); - if ($this->db->driverName !== 'mysql') { - throw new InvalidConfigException('In order to use MysqlMutex connection must be configured to use MySQL database.'); - } - } - - /** - * Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock - */ - protected function acquireLock($name, $timeout = 0) - { - return (boolean)$this->db - ->createCommand('SELECT GET_LOCK(:name, :timeout)', [':name' => $name, ':timeout' => $timeout]) - ->queryScalar(); - } - - /** - * Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release-lock - */ - protected function releaseLock($name) - { - return (boolean)$this->db - ->createCommand('SELECT RELEASE_LOCK(:name)', [':name' => $name]) - ->queryScalar(); - } -} diff --git a/framework/yii/rbac/Assignment.php b/framework/yii/rbac/Assignment.php deleted file mode 100644 index 065aaa5..0000000 --- a/framework/yii/rbac/Assignment.php +++ /dev/null @@ -1,55 +0,0 @@ - - * @author Alexander Kochetov - * @since 2.0 - */ -class Assignment extends Object -{ - /** - * @var Manager the auth manager of this item - */ - public $manager; - /** - * @var string the business rule associated with this assignment - */ - public $bizRule; - /** - * @var mixed additional data for this assignment - */ - public $data; - /** - * @var mixed user ID (see [[User::id]]). Do not modify this property after it is populated. - * To modify the user ID of an assignment, you must remove the assignment and create a new one. - */ - public $userId; - /** - * @return string the authorization item name. Do not modify this property after it is populated. - * To modify the item name of an assignment, you must remove the assignment and create a new one. - */ - public $itemName; - - /** - * Saves the changes to an authorization assignment. - */ - public function save() - { - $this->manager->saveAssignment($this); - } -} diff --git a/framework/yii/rbac/DbManager.php b/framework/yii/rbac/DbManager.php deleted file mode 100644 index 111bf0a..0000000 --- a/framework/yii/rbac/DbManager.php +++ /dev/null @@ -1,598 +0,0 @@ - - * @author Alexander Kochetov - * @since 2.0 - */ -class DbManager extends Manager -{ - /** - * @var Connection|string the DB connection object or the application component ID of the DB connection. - * After the DbManager object is created, if you want to change this property, you should only assign it - * with a DB connection object. - */ - public $db = 'db'; - /** - * @var string the name of the table storing authorization items. Defaults to 'tbl_auth_item'. - */ - public $itemTable = '{{%auth_item}}'; - /** - * @var string the name of the table storing authorization item hierarchy. Defaults to 'tbl_auth_item_child'. - */ - public $itemChildTable = '{{%auth_item_child}}'; - /** - * @var string the name of the table storing authorization item assignments. Defaults to 'tbl_auth_assignment'. - */ - public $assignmentTable = '{{%auth_assignment}}'; - - private $_usingSqlite; - - /** - * Initializes the application component. - * This method overrides the parent implementation by establishing the database connection. - */ - public function init() - { - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - } - if (!$this->db instanceof Connection) { - throw new InvalidConfigException("DbManager::db must be either a DB connection instance or the application component ID of a DB connection."); - } - $this->_usingSqlite = !strncmp($this->db->getDriverName(), 'sqlite', 6); - parent::init(); - } - - /** - * Performs access check for the specified user. - * @param mixed $userId the user ID. This should can be either an integer or a string representing - * the unique identifier of a user. See [[User::id]]. - * @param string $itemName the name of the operation that need access check - * @param array $params name-value pairs that would be passed to biz rules associated - * with the tasks and roles assigned to the user. A param with name 'userId' is added to this array, - * which holds the value of `$userId`. - * @return boolean whether the operations can be performed by the user. - */ - public function checkAccess($userId, $itemName, $params = []) - { - $assignments = $this->getAssignments($userId); - return $this->checkAccessRecursive($userId, $itemName, $params, $assignments); - } - - /** - * Performs access check for the specified user. - * This method is internally called by [[checkAccess()]]. - * @param mixed $userId the user ID. This should can be either an integer or a string representing - * the unique identifier of a user. See [[User::id]]. - * @param string $itemName the name of the operation that need access check - * @param array $params name-value pairs that would be passed to biz rules associated - * with the tasks and roles assigned to the user. A param with name 'userId' is added to this array, - * which holds the value of `$userId`. - * @param Assignment[] $assignments the assignments to the specified user - * @return boolean whether the operations can be performed by the user. - */ - protected function checkAccessRecursive($userId, $itemName, $params, $assignments) - { - if (($item = $this->getItem($itemName)) === null) { - return false; - } - Yii::trace('Checking permission: ' . $item->getName(), __METHOD__); - if (!isset($params['userId'])) { - $params['userId'] = $userId; - } - if ($this->executeBizRule($item->bizRule, $params, $item->data)) { - if (in_array($itemName, $this->defaultRoles)) { - return true; - } - if (isset($assignments[$itemName])) { - $assignment = $assignments[$itemName]; - if ($this->executeBizRule($assignment->bizRule, $params, $assignment->data)) { - return true; - } - } - $query = new Query; - $parents = $query->select(['parent']) - ->from($this->itemChildTable) - ->where(['child' => $itemName]) - ->createCommand($this->db) - ->queryColumn(); - foreach ($parents as $parent) { - if ($this->checkAccessRecursive($userId, $parent, $params, $assignments)) { - return true; - } - } - } - return false; - } - - /** - * Adds an item as a child of another item. - * @param string $itemName the parent item name - * @param string $childName the child item name - * @return boolean whether the item is added successfully - * @throws Exception if either parent or child doesn't exist. - * @throws InvalidCallException if a loop has been detected. - */ - public function addItemChild($itemName, $childName) - { - if ($itemName === $childName) { - throw new Exception("Cannot add '$itemName' as a child of itself."); - } - $query = new Query; - $rows = $query->from($this->itemTable) - ->where(['or', 'name=:name1', 'name=:name2'], [':name1' => $itemName, ':name2' => $childName]) - ->createCommand($this->db) - ->queryAll(); - if (count($rows) == 2) { - if ($rows[0]['name'] === $itemName) { - $parentType = $rows[0]['type']; - $childType = $rows[1]['type']; - } else { - $childType = $rows[0]['type']; - $parentType = $rows[1]['type']; - } - $this->checkItemChildType($parentType, $childType); - if ($this->detectLoop($itemName, $childName)) { - throw new InvalidCallException("Cannot add '$childName' as a child of '$itemName'. A loop has been detected."); - } - $this->db->createCommand() - ->insert($this->itemChildTable, ['parent' => $itemName, 'child' => $childName]) - ->execute(); - return true; - } else { - throw new Exception("Either '$itemName' or '$childName' does not exist."); - } - } - - /** - * Removes a child from its parent. - * Note, the child item is not deleted. Only the parent-child relationship is removed. - * @param string $itemName the parent item name - * @param string $childName the child item name - * @return boolean whether the removal is successful - */ - public function removeItemChild($itemName, $childName) - { - return $this->db->createCommand() - ->delete($this->itemChildTable, ['parent' => $itemName, 'child' => $childName]) - ->execute() > 0; - } - - /** - * Returns a value indicating whether a child exists within a parent. - * @param string $itemName the parent item name - * @param string $childName the child item name - * @return boolean whether the child exists - */ - public function hasItemChild($itemName, $childName) - { - $query = new Query; - return $query->select(['parent']) - ->from($this->itemChildTable) - ->where(['parent' => $itemName, 'child' => $childName]) - ->createCommand($this->db) - ->queryScalar() !== false; - } - - /** - * Returns the children of the specified item. - * @param mixed $names the parent item name. This can be either a string or an array. - * The latter represents a list of item names. - * @return Item[] all child items of the parent - */ - public function getItemChildren($names) - { - $query = new Query; - $rows = $query->select(['name', 'type', 'description', 'biz_rule', 'data']) - ->from([$this->itemTable, $this->itemChildTable]) - ->where(['parent' => $names, 'name' => new Expression('child')]) - ->createCommand($this->db) - ->queryAll(); - $children = []; - foreach ($rows as $row) { - if (($data = @unserialize($row['data'])) === false) { - $data = null; - } - $children[$row['name']] = new Item([ - 'manager' => $this, - 'name' => $row['name'], - 'type' => $row['type'], - 'description' => $row['description'], - 'bizRule' => $row['biz_rule'], - 'data' => $data, - ]); - } - return $children; - } - - /** - * Assigns an authorization item to a user. - * @param mixed $userId the user ID (see [[User::id]]) - * @param string $itemName the item name - * @param string $bizRule the business rule to be executed when [[checkAccess()]] is called - * for this particular authorization item. - * @param mixed $data additional data associated with this assignment - * @return Assignment the authorization assignment information. - * @throws InvalidParamException if the item does not exist or if the item has already been assigned to the user - */ - public function assign($userId, $itemName, $bizRule = null, $data = null) - { - if ($this->usingSqlite() && $this->getItem($itemName) === null) { - throw new InvalidParamException("The item '$itemName' does not exist."); - } - $this->db->createCommand() - ->insert($this->assignmentTable, [ - 'user_id' => $userId, - 'item_name' => $itemName, - 'biz_rule' => $bizRule, - 'data' => serialize($data), - ]) - ->execute(); - return new Assignment([ - 'manager' => $this, - 'userId' => $userId, - 'itemName' => $itemName, - 'bizRule' => $bizRule, - 'data' => $data, - ]); - } - - /** - * Revokes an authorization assignment from a user. - * @param mixed $userId the user ID (see [[User::id]]) - * @param string $itemName the item name - * @return boolean whether removal is successful - */ - public function revoke($userId, $itemName) - { - return $this->db->createCommand() - ->delete($this->assignmentTable, ['user_id' => $userId, 'item_name' => $itemName]) - ->execute() > 0; - } - - /** - * Revokes all authorization assignments from a user. - * @param mixed $userId the user ID (see [[User::id]]) - * @return boolean whether removal is successful - */ - public function revokeAll($userId) - { - return $this->db->createCommand() - ->delete($this->assignmentTable, ['user_id' => $userId]) - ->execute() > 0; - } - - /** - * Returns a value indicating whether the item has been assigned to the user. - * @param mixed $userId the user ID (see [[User::id]]) - * @param string $itemName the item name - * @return boolean whether the item has been assigned to the user. - */ - public function isAssigned($userId, $itemName) - { - $query = new Query; - return $query->select(['item_name']) - ->from($this->assignmentTable) - ->where(['user_id' => $userId, 'item_name' => $itemName]) - ->createCommand($this->db) - ->queryScalar() !== false; - } - - /** - * Returns the item assignment information. - * @param mixed $userId the user ID (see [[User::id]]) - * @param string $itemName the item name - * @return Assignment the item assignment information. Null is returned if - * the item is not assigned to the user. - */ - public function getAssignment($userId, $itemName) - { - $query = new Query; - $row = $query->from($this->assignmentTable) - ->where(['user_id' => $userId, 'item_name' => $itemName]) - ->createCommand($this->db) - ->queryOne(); - if ($row !== false) { - if (($data = @unserialize($row['data'])) === false) { - $data = null; - } - return new Assignment([ - 'manager' => $this, - 'userId' => $row['user_id'], - 'itemName' => $row['item_name'], - 'bizRule' => $row['biz_rule'], - 'data' => $data, - ]); - } else { - return null; - } - } - - /** - * Returns the item assignments for the specified user. - * @param mixed $userId the user ID (see [[User::id]]) - * @return Assignment[] the item assignment information for the user. An empty array will be - * returned if there is no item assigned to the user. - */ - public function getAssignments($userId) - { - $query = new Query; - $rows = $query->from($this->assignmentTable) - ->where(['user_id' => $userId]) - ->createCommand($this->db) - ->queryAll(); - $assignments = []; - foreach ($rows as $row) { - if (($data = @unserialize($row['data'])) === false) { - $data = null; - } - $assignments[$row['item_name']] = new Assignment([ - 'manager' => $this, - 'userId' => $row['user_id'], - 'itemName' => $row['item_name'], - 'bizRule' => $row['biz_rule'], - 'data' => $data, - ]); - } - return $assignments; - } - - /** - * Saves the changes to an authorization assignment. - * @param Assignment $assignment the assignment that has been changed. - */ - public function saveAssignment($assignment) - { - $this->db->createCommand() - ->update($this->assignmentTable, [ - 'biz_rule' => $assignment->bizRule, - 'data' => serialize($assignment->data), - ], [ - 'user_id' => $assignment->userId, - 'item_name' => $assignment->itemName, - ]) - ->execute(); - } - - /** - * Returns the authorization items of the specific type and user. - * @param mixed $userId the user ID. Defaults to null, meaning returning all items even if - * they are not assigned to a user. - * @param integer $type the item type (0: operation, 1: task, 2: role). Defaults to null, - * meaning returning all items regardless of their type. - * @return Item[] the authorization items of the specific type. - */ - public function getItems($userId = null, $type = null) - { - $query = new Query; - if ($userId === null && $type === null) { - $command = $query->from($this->itemTable) - ->createCommand($this->db); - } elseif ($userId === null) { - $command = $query->from($this->itemTable) - ->where(['type' => $type]) - ->createCommand($this->db); - } elseif ($type === null) { - $command = $query->select(['name', 'type', 'description', 't1.biz_rule', 't1.data']) - ->from([$this->itemTable . ' t1', $this->assignmentTable . ' t2']) - ->where(['user_id' => $userId, 'name' => new Expression('item_name')]) - ->createCommand($this->db); - } else { - $command = $query->select(['name', 'type', 'description', 't1.biz_rule', 't1.data']) - ->from([$this->itemTable . ' t1', $this->assignmentTable . ' t2']) - ->where(['user_id' => $userId, 'type' => $type, 'name' => new Expression('item_name')]) - ->createCommand($this->db); - } - $items = []; - foreach ($command->queryAll() as $row) { - if (($data = @unserialize($row['data'])) === false) { - $data = null; - } - $items[$row['name']] = new Item([ - 'manager' => $this, - 'name' => $row['name'], - 'type' => $row['type'], - 'description' => $row['description'], - 'bizRule' => $row['biz_rule'], - 'data' => $data, - ]); - } - return $items; - } - - /** - * Creates an authorization item. - * An authorization item represents an action permission (e.g. creating a post). - * It has three types: operation, task and role. - * Authorization items form a hierarchy. Higher level items inheirt permissions representing - * by lower level items. - * @param string $name the item name. This must be a unique identifier. - * @param integer $type the item type (0: operation, 1: task, 2: role). - * @param string $description description of the item - * @param string $bizRule business rule associated with the item. This is a piece of - * PHP code that will be executed when [[checkAccess()]] is called for the item. - * @param mixed $data additional data associated with the item. - * @return Item the authorization item - * @throws Exception if an item with the same name already exists - */ - public function createItem($name, $type, $description = '', $bizRule = null, $data = null) - { - $this->db->createCommand() - ->insert($this->itemTable, [ - 'name' => $name, - 'type' => $type, - 'description' => $description, - 'biz_rule' => $bizRule, - 'data' => serialize($data), - ]) - ->execute(); - return new Item([ - 'manager' => $this, - 'name' => $name, - 'type' => $type, - 'description' => $description, - 'bizRule' => $bizRule, - 'data' => $data, - ]); - } - - /** - * Removes the specified authorization item. - * @param string $name the name of the item to be removed - * @return boolean whether the item exists in the storage and has been removed - */ - public function removeItem($name) - { - if ($this->usingSqlite()) { - $this->db->createCommand() - ->delete($this->itemChildTable, ['or', 'parent=:name', 'child=:name'], [':name' => $name]) - ->execute(); - $this->db->createCommand() - ->delete($this->assignmentTable, ['item_name' => $name]) - ->execute(); - } - return $this->db->createCommand() - ->delete($this->itemTable, ['name' => $name]) - ->execute() > 0; - } - - /** - * Returns the authorization item with the specified name. - * @param string $name the name of the item - * @return Item the authorization item. Null if the item cannot be found. - */ - public function getItem($name) - { - $query = new Query; - $row = $query->from($this->itemTable) - ->where(['name' => $name]) - ->createCommand($this->db) - ->queryOne(); - - if ($row !== false) { - if (($data = @unserialize($row['data'])) === false) { - $data = null; - } - return new Item([ - 'manager' => $this, - 'name' => $row['name'], - 'type' => $row['type'], - 'description' => $row['description'], - 'bizRule' => $row['biz_rule'], - 'data' => $data, - ]); - } else { - return null; - } - } - - /** - * Saves an authorization item to persistent storage. - * @param Item $item the item to be saved. - * @param string $oldName the old item name. If null, it means the item name is not changed. - */ - public function saveItem($item, $oldName = null) - { - if ($this->usingSqlite() && $oldName !== null && $item->getName() !== $oldName) { - $this->db->createCommand() - ->update($this->itemChildTable, ['parent' => $item->getName()], ['parent' => $oldName]) - ->execute(); - $this->db->createCommand() - ->update($this->itemChildTable, ['child' => $item->getName()], ['child' => $oldName]) - ->execute(); - $this->db->createCommand() - ->update($this->assignmentTable, ['item_name' => $item->getName()], ['item_name' => $oldName]) - ->execute(); - } - - $this->db->createCommand() - ->update($this->itemTable, [ - 'name' => $item->getName(), - 'type' => $item->type, - 'description' => $item->description, - 'biz_rule' => $item->bizRule, - 'data' => serialize($item->data), - ], [ - 'name' => $oldName === null ? $item->getName() : $oldName, - ]) - ->execute(); - } - - /** - * Saves the authorization data to persistent storage. - */ - public function save() - { - } - - /** - * Removes all authorization data. - */ - public function clearAll() - { - $this->clearAssignments(); - $this->db->createCommand()->delete($this->itemChildTable)->execute(); - $this->db->createCommand()->delete($this->itemTable)->execute(); - } - - /** - * Removes all authorization assignments. - */ - public function clearAssignments() - { - $this->db->createCommand()->delete($this->assignmentTable)->execute(); - } - - /** - * Checks whether there is a loop in the authorization item hierarchy. - * @param string $itemName parent item name - * @param string $childName the name of the child item that is to be added to the hierarchy - * @return boolean whether a loop exists - */ - protected function detectLoop($itemName, $childName) - { - if ($childName === $itemName) { - return true; - } - foreach ($this->getItemChildren($childName) as $child) { - if ($this->detectLoop($itemName, $child->getName())) { - return true; - } - } - return false; - } - - /** - * @return boolean whether the database is a SQLite database - */ - protected function usingSqlite() - { - return $this->_usingSqlite; - } -} diff --git a/framework/yii/rbac/Item.php b/framework/yii/rbac/Item.php deleted file mode 100644 index 2e1eb53..0000000 --- a/framework/yii/rbac/Item.php +++ /dev/null @@ -1,204 +0,0 @@ - - * @author Alexander Kochetov - * @since 2.0 - */ -class Item extends Object -{ - const TYPE_OPERATION = 0; - const TYPE_TASK = 1; - const TYPE_ROLE = 2; - - /** - * @var Manager the auth manager of this item - */ - public $manager; - /** - * @var string the item description - */ - public $description; - /** - * @var string the business rule associated with this item - */ - public $bizRule; - /** - * @var mixed the additional data associated with this item - */ - public $data; - /** - * @var integer the authorization item type. This could be 0 (operation), 1 (task) or 2 (role). - */ - public $type; - - private $_name; - private $_oldName; - - - /** - * Checks to see if the specified item is within the hierarchy starting from this item. - * This method is expected to be internally used by the actual implementations - * of the [[Manager::checkAccess()]]. - * @param string $itemName the name of the item to be checked - * @param array $params the parameters to be passed to business rule evaluation - * @return boolean whether the specified item is within the hierarchy starting from this item. - */ - public function checkAccess($itemName, $params = []) - { - Yii::trace('Checking permission: ' . $this->_name, __METHOD__); - if ($this->manager->executeBizRule($this->bizRule, $params, $this->data)) { - if ($this->_name == $itemName) { - return true; - } - foreach ($this->manager->getItemChildren($this->_name) as $item) { - if ($item->checkAccess($itemName, $params)) { - return true; - } - } - } - return false; - } - - /** - * @return string the item name - */ - public function getName() - { - return $this->_name; - } - - /** - * @param string $value the item name - */ - public function setName($value) - { - if ($this->_name !== $value) { - $this->_oldName = $this->_name; - $this->_name = $value; - } - } - - /** - * Adds a child item. - * @param string $name the name of the child item - * @return boolean whether the item is added successfully - * @throws \yii\base\Exception if either parent or child doesn't exist or if a loop has been detected. - * @see Manager::addItemChild - */ - public function addChild($name) - { - return $this->manager->addItemChild($this->_name, $name); - } - - /** - * Removes a child item. - * Note, the child item is not deleted. Only the parent-child relationship is removed. - * @param string $name the child item name - * @return boolean whether the removal is successful - * @see Manager::removeItemChild - */ - public function removeChild($name) - { - return $this->manager->removeItemChild($this->_name, $name); - } - - /** - * Returns a value indicating whether a child exists - * @param string $name the child item name - * @return boolean whether the child exists - * @see Manager::hasItemChild - */ - public function hasChild($name) - { - return $this->manager->hasItemChild($this->_name, $name); - } - - /** - * Returns the children of this item. - * @return Item[] all child items of this item. - * @see Manager::getItemChildren - */ - public function getChildren() - { - return $this->manager->getItemChildren($this->_name); - } - - /** - * Assigns this item to a user. - * @param mixed $userId the user ID (see [[User::id]]) - * @param string $bizRule the business rule to be executed when [[checkAccess()]] is called - * for this particular authorization item. - * @param mixed $data additional data associated with this assignment - * @return Assignment the authorization assignment information. - * @throws \yii\base\Exception if the item has already been assigned to the user - * @see Manager::assign - */ - public function assign($userId, $bizRule = null, $data = null) - { - return $this->manager->assign($userId, $this->_name, $bizRule, $data); - } - - /** - * Revokes an authorization assignment from a user. - * @param mixed $userId the user ID (see [[User::id]]) - * @return boolean whether removal is successful - * @see Manager::revoke - */ - public function revoke($userId) - { - return $this->manager->revoke($userId, $this->_name); - } - - /** - * Returns a value indicating whether this item has been assigned to the user. - * @param mixed $userId the user ID (see [[User::id]]) - * @return boolean whether the item has been assigned to the user. - * @see Manager::isAssigned - */ - public function isAssigned($userId) - { - return $this->manager->isAssigned($userId, $this->_name); - } - - /** - * Returns the item assignment information. - * @param mixed $userId the user ID (see [[User::id]]) - * @return Assignment the item assignment information. Null is returned if - * this item is not assigned to the user. - * @see Manager::getAssignment - */ - public function getAssignment($userId) - { - return $this->manager->getAssignment($userId, $this->_name); - } - - /** - * Saves an authorization item to persistent storage. - */ - public function save() - { - $this->manager->saveItem($this, $this->_oldName); - $this->_oldName = null; - } -} diff --git a/framework/yii/rbac/Manager.php b/framework/yii/rbac/Manager.php deleted file mode 100644 index 2f392c5..0000000 --- a/framework/yii/rbac/Manager.php +++ /dev/null @@ -1,318 +0,0 @@ - AuthItem). This property is read-only. - * @property Item[] $roles Roles (name => AuthItem). This property is read-only. - * @property Item[] $tasks Tasks (name => AuthItem). This property is read-only. - * - * @author Qiang Xue - * @author Alexander Kochetov - * @since 2.0 - */ -abstract class Manager extends Component -{ - /** - * @var boolean Enable error reporting for bizRules. - */ - public $showErrors = false; - - /** - * @var array list of role names that are assigned to all users implicitly. - * These roles do not need to be explicitly assigned to any user. - * When calling [[checkAccess()]], these roles will be checked first. - * For performance reason, you should minimize the number of such roles. - * A typical usage of such roles is to define an 'authenticated' role and associate - * it with a biz rule which checks if the current user is authenticated. - * And then declare 'authenticated' in this property so that it can be applied to - * every authenticated user. - */ - public $defaultRoles = []; - - /** - * Creates a role. - * This is a shortcut method to [[Manager::createItem()]]. - * @param string $name the item name - * @param string $description the item description. - * @param string $bizRule the business rule associated with this item - * @param mixed $data additional data to be passed when evaluating the business rule - * @return Item the authorization item - */ - public function createRole($name, $description = '', $bizRule = null, $data = null) - { - return $this->createItem($name, Item::TYPE_ROLE, $description, $bizRule, $data); - } - - /** - * Creates a task. - * This is a shortcut method to [[Manager::createItem()]]. - * @param string $name the item name - * @param string $description the item description. - * @param string $bizRule the business rule associated with this item - * @param mixed $data additional data to be passed when evaluating the business rule - * @return Item the authorization item - */ - public function createTask($name, $description = '', $bizRule = null, $data = null) - { - return $this->createItem($name, Item::TYPE_TASK, $description, $bizRule, $data); - } - - /** - * Creates an operation. - * This is a shortcut method to [[Manager::createItem()]]. - * @param string $name the item name - * @param string $description the item description. - * @param string $bizRule the business rule associated with this item - * @param mixed $data additional data to be passed when evaluating the business rule - * @return Item the authorization item - */ - public function createOperation($name, $description = '', $bizRule = null, $data = null) - { - return $this->createItem($name, Item::TYPE_OPERATION, $description, $bizRule, $data); - } - - /** - * Returns roles. - * This is a shortcut method to [[Manager::getItems()]]. - * @param mixed $userId the user ID. If not null, only the roles directly assigned to the user - * will be returned. Otherwise, all roles will be returned. - * @return Item[] roles (name => AuthItem) - */ - public function getRoles($userId = null) - { - return $this->getItems($userId, Item::TYPE_ROLE); - } - - /** - * Returns tasks. - * This is a shortcut method to [[Manager::getItems()]]. - * @param mixed $userId the user ID. If not null, only the tasks directly assigned to the user - * will be returned. Otherwise, all tasks will be returned. - * @return Item[] tasks (name => AuthItem) - */ - public function getTasks($userId = null) - { - return $this->getItems($userId, Item::TYPE_TASK); - } - - /** - * Returns operations. - * This is a shortcut method to [[Manager::getItems()]]. - * @param mixed $userId the user ID. If not null, only the operations directly assigned to the user - * will be returned. Otherwise, all operations will be returned. - * @return Item[] operations (name => AuthItem) - */ - public function getOperations($userId = null) - { - return $this->getItems($userId, Item::TYPE_OPERATION); - } - - /** - * Executes the specified business rule. - * @param string $bizRule the business rule to be executed. - * @param array $params parameters passed to [[Manager::checkAccess()]]. - * @param mixed $data additional data associated with the authorization item or assignment. - * @return boolean whether the business rule returns true. - * If the business rule is empty, it will still return true. - */ - public function executeBizRule($bizRule, $params, $data) - { - return $bizRule === '' || $bizRule === null || ($this->showErrors ? eval($bizRule) != 0 : @eval($bizRule) != 0); - } - - /** - * Checks the item types to make sure a child can be added to a parent. - * @param integer $parentType parent item type - * @param integer $childType child item type - * @throws InvalidParamException if the item cannot be added as a child due to its incompatible type. - */ - protected function checkItemChildType($parentType, $childType) - { - static $types = ['operation', 'task', 'role']; - if ($parentType < $childType) { - throw new InvalidParamException("Cannot add an item of type '{$types[$childType]}' to an item of type '{$types[$parentType]}'."); - } - } - - /** - * Performs access check for the specified user. - * @param mixed $userId the user ID. This should be either an integer or a string representing - * the unique identifier of a user. See [[User::id]]. - * @param string $itemName the name of the operation that we are checking access to - * @param array $params name-value pairs that would be passed to biz rules associated - * with the tasks and roles assigned to the user. - * @return boolean whether the operations can be performed by the user. - */ - abstract public function checkAccess($userId, $itemName, $params = []); - - /** - * Creates an authorization item. - * An authorization item represents an action permission (e.g. creating a post). - * It has three types: operation, task and role. - * Authorization items form a hierarchy. Higher level items inheirt permissions representing - * by lower level items. - * @param string $name the item name. This must be a unique identifier. - * @param integer $type the item type (0: operation, 1: task, 2: role). - * @param string $description description of the item - * @param string $bizRule business rule associated with the item. This is a piece of - * PHP code that will be executed when [[checkAccess()]] is called for the item. - * @param mixed $data additional data associated with the item. - * @throws \yii\base\Exception if an item with the same name already exists - * @return Item the authorization item - */ - abstract public function createItem($name, $type, $description = '', $bizRule = null, $data = null); - /** - * Removes the specified authorization item. - * @param string $name the name of the item to be removed - * @return boolean whether the item exists in the storage and has been removed - */ - abstract public function removeItem($name); - /** - * Returns the authorization items of the specific type and user. - * @param mixed $userId the user ID. Defaults to null, meaning returning all items even if - * they are not assigned to a user. - * @param integer $type the item type (0: operation, 1: task, 2: role). Defaults to null, - * meaning returning all items regardless of their type. - * @return Item[] the authorization items of the specific type. - */ - abstract public function getItems($userId = null, $type = null); - /** - * Returns the authorization item with the specified name. - * @param string $name the name of the item - * @return Item the authorization item. Null if the item cannot be found. - */ - abstract public function getItem($name); - /** - * Saves an authorization item to persistent storage. - * @param Item $item the item to be saved. - * @param string $oldName the old item name. If null, it means the item name is not changed. - */ - abstract public function saveItem($item, $oldName = null); - - /** - * Adds an item as a child of another item. - * @param string $itemName the parent item name - * @param string $childName the child item name - * @throws \yii\base\Exception if either parent or child doesn't exist or if a loop has been detected. - */ - abstract public function addItemChild($itemName, $childName); - /** - * Removes a child from its parent. - * Note, the child item is not deleted. Only the parent-child relationship is removed. - * @param string $itemName the parent item name - * @param string $childName the child item name - * @return boolean whether the removal is successful - */ - abstract public function removeItemChild($itemName, $childName); - /** - * Returns a value indicating whether a child exists within a parent. - * @param string $itemName the parent item name - * @param string $childName the child item name - * @return boolean whether the child exists - */ - abstract public function hasItemChild($itemName, $childName); - /** - * Returns the children of the specified item. - * @param mixed $itemName the parent item name. This can be either a string or an array. - * The latter represents a list of item names. - * @return Item[] all child items of the parent - */ - abstract public function getItemChildren($itemName); - - /** - * Assigns an authorization item to a user. - * @param mixed $userId the user ID (see [[User::id]]) - * @param string $itemName the item name - * @param string $bizRule the business rule to be executed when [[checkAccess()]] is called - * for this particular authorization item. - * @param mixed $data additional data associated with this assignment - * @return Assignment the authorization assignment information. - * @throws \yii\base\Exception if the item does not exist or if the item has already been assigned to the user - */ - abstract public function assign($userId, $itemName, $bizRule = null, $data = null); - /** - * Revokes an authorization assignment from a user. - * @param mixed $userId the user ID (see [[User::id]]) - * @param string $itemName the item name - * @return boolean whether removal is successful - */ - abstract public function revoke($userId, $itemName); - /** - * Revokes all authorization assignments from a user. - * @param mixed $userId the user ID (see [[User::id]]) - * @return boolean whether removal is successful - */ - abstract public function revokeAll($userId); - /** - * Returns a value indicating whether the item has been assigned to the user. - * @param mixed $userId the user ID (see [[User::id]]) - * @param string $itemName the item name - * @return boolean whether the item has been assigned to the user. - */ - abstract public function isAssigned($userId, $itemName); - /** - * Returns the item assignment information. - * @param mixed $userId the user ID (see [[User::id]]) - * @param string $itemName the item name - * @return Assignment the item assignment information. Null is returned if - * the item is not assigned to the user. - */ - abstract public function getAssignment($userId, $itemName); - /** - * Returns the item assignments for the specified user. - * @param mixed $userId the user ID (see [[User::id]]) - * @return Item[] the item assignment information for the user. An empty array will be - * returned if there is no item assigned to the user. - */ - abstract public function getAssignments($userId); - /** - * Saves the changes to an authorization assignment. - * @param Assignment $assignment the assignment that has been changed. - */ - abstract public function saveAssignment($assignment); - /** - * Removes all authorization data. - */ - abstract public function clearAll(); - /** - * Removes all authorization assignments. - */ - abstract public function clearAssignments(); - /** - * Saves authorization data into persistent storage. - * If any change is made to the authorization data, please make - * sure you call this method to save the changed data into persistent storage. - */ - abstract public function save(); -} diff --git a/framework/yii/rbac/PhpManager.php b/framework/yii/rbac/PhpManager.php deleted file mode 100644 index 3d02e4f..0000000 --- a/framework/yii/rbac/PhpManager.php +++ /dev/null @@ -1,554 +0,0 @@ - - * @author Alexander Kochetov - * @since 2.0 - */ -class PhpManager extends Manager -{ - /** - * @var string the path of the PHP script that contains the authorization data. - * This can be either a file path or a path alias to the file. - * Make sure this file is writable by the Web server process if the authorization needs to be changed online. - * @see loadFromFile() - * @see saveToFile() - */ - public $authFile = '@app/data/rbac.php'; - - private $_items = []; // itemName => item - private $_children = []; // itemName, childName => child - private $_assignments = []; // userId, itemName => assignment - - /** - * Initializes the application component. - * This method overrides parent implementation by loading the authorization data - * from PHP script. - */ - public function init() - { - parent::init(); - $this->authFile = Yii::getAlias($this->authFile); - $this->load(); - } - - /** - * Performs access check for the specified user. - * @param mixed $userId the user ID. This can be either an integer or a string representing - * @param string $itemName the name of the operation that need access check - * the unique identifier of a user. See [[User::id]]. - * @param array $params name-value pairs that would be passed to biz rules associated - * with the tasks and roles assigned to the user. A param with name 'userId' is added to - * this array, which holds the value of `$userId`. - * @return boolean whether the operations can be performed by the user. - */ - public function checkAccess($userId, $itemName, $params = []) - { - if (!isset($this->_items[$itemName])) { - return false; - } - /** @var Item $item */ - $item = $this->_items[$itemName]; - Yii::trace('Checking permission: ' . $item->getName(), __METHOD__); - if (!isset($params['userId'])) { - $params['userId'] = $userId; - } - if ($this->executeBizRule($item->bizRule, $params, $item->data)) { - if (in_array($itemName, $this->defaultRoles)) { - return true; - } - if (isset($this->_assignments[$userId][$itemName])) { - /** @var Assignment $assignment */ - $assignment = $this->_assignments[$userId][$itemName]; - if ($this->executeBizRule($assignment->bizRule, $params, $assignment->data)) { - return true; - } - } - foreach ($this->_children as $parentName => $children) { - if (isset($children[$itemName]) && $this->checkAccess($userId, $parentName, $params)) { - return true; - } - } - } - return false; - } - - /** - * Adds an item as a child of another item. - * @param string $itemName the parent item name - * @param string $childName the child item name - * @return boolean whether the item is added successfully - * @throws Exception if either parent or child doesn't exist. - * @throws InvalidCallException if item already has a child with $itemName or if a loop has been detected. - */ - public function addItemChild($itemName, $childName) - { - if (!isset($this->_items[$childName], $this->_items[$itemName])) { - throw new Exception("Either '$itemName' or '$childName' does not exist."); - } - /** @var Item $child */ - $child = $this->_items[$childName]; - /** @var Item $item */ - $item = $this->_items[$itemName]; - $this->checkItemChildType($item->type, $child->type); - if ($this->detectLoop($itemName, $childName)) { - throw new InvalidCallException("Cannot add '$childName' as a child of '$itemName'. A loop has been detected."); - } - if (isset($this->_children[$itemName][$childName])) { - throw new InvalidCallException("The item '$itemName' already has a child '$childName'."); - } - $this->_children[$itemName][$childName] = $this->_items[$childName]; - return true; - } - - /** - * Removes a child from its parent. - * Note, the child item is not deleted. Only the parent-child relationship is removed. - * @param string $itemName the parent item name - * @param string $childName the child item name - * @return boolean whether the removal is successful - */ - public function removeItemChild($itemName, $childName) - { - if (isset($this->_children[$itemName][$childName])) { - unset($this->_children[$itemName][$childName]); - return true; - } else { - return false; - } - } - - /** - * Returns a value indicating whether a child exists within a parent. - * @param string $itemName the parent item name - * @param string $childName the child item name - * @return boolean whether the child exists - */ - public function hasItemChild($itemName, $childName) - { - return isset($this->_children[$itemName][$childName]); - } - - /** - * Returns the children of the specified item. - * @param mixed $names the parent item name. This can be either a string or an array. - * The latter represents a list of item names. - * @return Item[] all child items of the parent - */ - public function getItemChildren($names) - { - if (is_string($names)) { - return isset($this->_children[$names]) ? $this->_children[$names] : []; - } - - $children = []; - foreach ($names as $name) { - if (isset($this->_children[$name])) { - $children = array_merge($children, $this->_children[$name]); - } - } - return $children; - } - - /** - * Assigns an authorization item to a user. - * @param mixed $userId the user ID (see [[User::id]]) - * @param string $itemName the item name - * @param string $bizRule the business rule to be executed when [[checkAccess()]] is called - * for this particular authorization item. - * @param mixed $data additional data associated with this assignment - * @return Assignment the authorization assignment information. - * @throws InvalidParamException if the item does not exist or if the item has already been assigned to the user - */ - public function assign($userId, $itemName, $bizRule = null, $data = null) - { - if (!isset($this->_items[$itemName])) { - throw new InvalidParamException("Unknown authorization item '$itemName'."); - } elseif (isset($this->_assignments[$userId][$itemName])) { - throw new InvalidParamException("Authorization item '$itemName' has already been assigned to user '$userId'."); - } else { - return $this->_assignments[$userId][$itemName] = new Assignment([ - 'manager' => $this, - 'userId' => $userId, - 'itemName' => $itemName, - 'bizRule' => $bizRule, - 'data' => $data, - ]); - } - } - - /** - * Revokes an authorization assignment from a user. - * @param mixed $userId the user ID (see [[User::id]]) - * @param string $itemName the item name - * @return boolean whether removal is successful - */ - public function revoke($userId, $itemName) - { - if (isset($this->_assignments[$userId][$itemName])) { - unset($this->_assignments[$userId][$itemName]); - return true; - } else { - return false; - } - } - - /** - * Revokes all authorization assignments from a user. - * @param mixed $userId the user ID (see [[User::id]]) - * @return boolean whether removal is successful - */ - public function revokeAll($userId) - { - if (isset($this->_assignments[$userId]) && is_array($this->_assignments[$userId])) { - foreach ($this->_assignments[$userId] as $itemName => $value) - unset($this->_assignments[$userId][$itemName]); - return true; - } else { - return false; - } - } - - /** - * Returns a value indicating whether the item has been assigned to the user. - * @param mixed $userId the user ID (see [[User::id]]) - * @param string $itemName the item name - * @return boolean whether the item has been assigned to the user. - */ - public function isAssigned($userId, $itemName) - { - return isset($this->_assignments[$userId][$itemName]); - } - - /** - * Returns the item assignment information. - * @param mixed $userId the user ID (see [[User::id]]) - * @param string $itemName the item name - * @return Assignment the item assignment information. Null is returned if - * the item is not assigned to the user. - */ - public function getAssignment($userId, $itemName) - { - return isset($this->_assignments[$userId][$itemName]) ? $this->_assignments[$userId][$itemName] : null; - } - - /** - * Returns the item assignments for the specified user. - * @param mixed $userId the user ID (see [[User::id]]) - * @return Assignment[] the item assignment information for the user. An empty array will be - * returned if there is no item assigned to the user. - */ - public function getAssignments($userId) - { - return isset($this->_assignments[$userId]) ? $this->_assignments[$userId] : []; - } - - /** - * Returns the authorization items of the specific type and user. - * @param mixed $userId the user ID. Defaults to null, meaning returning all items even if - * they are not assigned to a user. - * @param integer $type the item type (0: operation, 1: task, 2: role). Defaults to null, - * meaning returning all items regardless of their type. - * @return Item[] the authorization items of the specific type. - */ - public function getItems($userId = null, $type = null) - { - if ($userId === null && $type === null) { - return $this->_items; - } - $items = []; - if ($userId === null) { - foreach ($this->_items as $name => $item) { - /** @var Item $item */ - if ($item->type == $type) { - $items[$name] = $item; - } - } - } elseif (isset($this->_assignments[$userId])) { - foreach ($this->_assignments[$userId] as $assignment) { - /** @var Assignment $assignment */ - $name = $assignment->itemName; - if (isset($this->_items[$name]) && ($type === null || $this->_items[$name]->type == $type)) { - $items[$name] = $this->_items[$name]; - } - } - } - return $items; - } - - /** - * Creates an authorization item. - * An authorization item represents an action permission (e.g. creating a post). - * It has three types: operation, task and role. - * Authorization items form a hierarchy. Higher level items inheirt permissions representing - * by lower level items. - * @param string $name the item name. This must be a unique identifier. - * @param integer $type the item type (0: operation, 1: task, 2: role). - * @param string $description description of the item - * @param string $bizRule business rule associated with the item. This is a piece of - * PHP code that will be executed when [[checkAccess()]] is called for the item. - * @param mixed $data additional data associated with the item. - * @return Item the authorization item - * @throws Exception if an item with the same name already exists - */ - public function createItem($name, $type, $description = '', $bizRule = null, $data = null) - { - if (isset($this->_items[$name])) { - throw new Exception('Unable to add an item whose name is the same as an existing item.'); - } - return $this->_items[$name] = new Item([ - 'manager' => $this, - 'name' => $name, - 'type' => $type, - 'description' => $description, - 'bizRule' => $bizRule, - 'data' => $data, - ]); - } - - /** - * Removes the specified authorization item. - * @param string $name the name of the item to be removed - * @return boolean whether the item exists in the storage and has been removed - */ - public function removeItem($name) - { - if (isset($this->_items[$name])) { - foreach ($this->_children as &$children) { - unset($children[$name]); - } - foreach ($this->_assignments as &$assignments) { - unset($assignments[$name]); - } - unset($this->_items[$name]); - return true; - } else { - return false; - } - } - - /** - * Returns the authorization item with the specified name. - * @param string $name the name of the item - * @return Item the authorization item. Null if the item cannot be found. - */ - public function getItem($name) - { - return isset($this->_items[$name]) ? $this->_items[$name] : null; - } - - /** - * Saves an authorization item to persistent storage. - * @param Item $item the item to be saved. - * @param string $oldName the old item name. If null, it means the item name is not changed. - * @throws InvalidParamException if an item with the same name already taken - */ - public function saveItem($item, $oldName = null) - { - if ($oldName !== null && ($newName = $item->getName()) !== $oldName) { // name changed - if (isset($this->_items[$newName])) { - throw new InvalidParamException("Unable to change the item name. The name '$newName' is already used by another item."); - } - if (isset($this->_items[$oldName]) && $this->_items[$oldName] === $item) { - unset($this->_items[$oldName]); - $this->_items[$newName] = $item; - if (isset($this->_children[$oldName])) { - $this->_children[$newName] = $this->_children[$oldName]; - unset($this->_children[$oldName]); - } - foreach ($this->_children as &$children) { - if (isset($children[$oldName])) { - $children[$newName] = $children[$oldName]; - unset($children[$oldName]); - } - } - foreach ($this->_assignments as &$assignments) { - if (isset($assignments[$oldName])) { - $assignments[$newName] = $assignments[$oldName]; - unset($assignments[$oldName]); - } - } - } - } - } - - /** - * Saves the changes to an authorization assignment. - * @param Assignment $assignment the assignment that has been changed. - */ - public function saveAssignment($assignment) - { - } - - /** - * Saves authorization data into persistent storage. - * If any change is made to the authorization data, please make - * sure you call this method to save the changed data into persistent storage. - */ - public function save() - { - $items = []; - foreach ($this->_items as $name => $item) { - /** @var Item $item */ - $items[$name] = [ - 'type' => $item->type, - 'description' => $item->description, - 'bizRule' => $item->bizRule, - 'data' => $item->data, - ]; - if (isset($this->_children[$name])) { - foreach ($this->_children[$name] as $child) { - /** @var Item $child */ - $items[$name]['children'][] = $child->getName(); - } - } - } - - foreach ($this->_assignments as $userId => $assignments) { - foreach ($assignments as $name => $assignment) { - /** @var Assignment $assignment */ - if (isset($items[$name])) { - $items[$name]['assignments'][$userId] = [ - 'bizRule' => $assignment->bizRule, - 'data' => $assignment->data, - ]; - } - } - } - - $this->saveToFile($items, $this->authFile); - } - - /** - * Loads authorization data. - */ - public function load() - { - $this->clearAll(); - - $items = $this->loadFromFile($this->authFile); - - foreach ($items as $name => $item) { - $this->_items[$name] = new Item([ - 'manager' => $this, - 'name' => $name, - 'type' => $item['type'], - 'description' => $item['description'], - 'bizRule' => $item['bizRule'], - 'data' => $item['data'], - ]); - } - - foreach ($items as $name => $item) { - if (isset($item['children'])) { - foreach ($item['children'] as $childName) { - if (isset($this->_items[$childName])) { - $this->_children[$name][$childName] = $this->_items[$childName]; - } - } - } - if (isset($item['assignments'])) { - foreach ($item['assignments'] as $userId => $assignment) { - $this->_assignments[$userId][$name] = new Assignment([ - 'manager' => $this, - 'userId' => $userId, - 'itemName' => $name, - 'bizRule' => $assignment['bizRule'], - 'data' => $assignment['data'], - ]); - } - } - } - } - - /** - * Removes all authorization data. - */ - public function clearAll() - { - $this->clearAssignments(); - $this->_children = []; - $this->_items = []; - } - - /** - * Removes all authorization assignments. - */ - public function clearAssignments() - { - $this->_assignments = []; - } - - /** - * Checks whether there is a loop in the authorization item hierarchy. - * @param string $itemName parent item name - * @param string $childName the name of the child item that is to be added to the hierarchy - * @return boolean whether a loop exists - */ - protected function detectLoop($itemName, $childName) - { - if ($childName === $itemName) { - return true; - } - if (!isset($this->_children[$childName], $this->_items[$itemName])) { - return false; - } - foreach ($this->_children[$childName] as $child) { - /** @var Item $child */ - if ($this->detectLoop($itemName, $child->getName())) { - return true; - } - } - return false; - } - - /** - * Loads the authorization data from a PHP script file. - * @param string $file the file path. - * @return array the authorization data - * @see saveToFile() - */ - protected function loadFromFile($file) - { - if (is_file($file)) { - return require($file); - } else { - return []; - } - } - - /** - * Saves the authorization data to a PHP script file. - * @param array $data the authorization data - * @param string $file the file path. - * @see loadFromFile() - */ - protected function saveToFile($data, $file) - { - file_put_contents($file, " - * @author Alexander Kochetov - * @link http://www.yiiframework.com/ - * @copyright 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - * @since 2.0 - */ - -drop table if exists [tbl_auth_assignment]; -drop table if exists [tbl_auth_item_child]; -drop table if exists [tbl_auth_item]; - -create table [tbl_auth_item] -( - [name] varchar(64) not null, - [type] integer not null, - [description] text, - [biz_rule] text, - [data] text, - primary key ([name]), - key [type] ([type]) -); - -create table [tbl_auth_item_child] -( - [parent] varchar(64) not null, - [child] varchar(64) not null, - primary key ([parent],[child]), - foreign key ([parent]) references [tbl_auth_item] ([name]) on delete cascade on update cascade, - foreign key ([child]) references [tbl_auth_item] ([name]) on delete cascade on update cascade -); - -create table [tbl_auth_assignment] -( - [item_name] varchar(64) not null, - [user_id] varchar(64) not null, - [biz_rule] text, - [data] text, - primary key ([item_name],[user_id]), - foreign key ([item_name]) references [tbl_auth_item] ([name]) on delete cascade on update cascade -); diff --git a/framework/yii/rbac/schema-mysql.sql b/framework/yii/rbac/schema-mysql.sql deleted file mode 100644 index 1530409..0000000 --- a/framework/yii/rbac/schema-mysql.sql +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Database schema required by \yii\rbac\DbManager. - * - * @author Qiang Xue - * @author Alexander Kochetov - * @link http://www.yiiframework.com/ - * @copyright 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - * @since 2.0 - */ - -drop table if exists `tbl_auth_assignment`; -drop table if exists `tbl_auth_item_child`; -drop table if exists `tbl_auth_item`; - -create table `tbl_auth_item` -( - `name` varchar(64) not null, - `type` integer not null, - `description` text, - `biz_rule` text, - `data` text, - primary key (`name`), - key `type` (`type`) -) engine InnoDB; - -create table `tbl_auth_item_child` -( - `parent` varchar(64) not null, - `child` varchar(64) not null, - primary key (`parent`,`child`), - foreign key (`parent`) references `tbl_auth_item` (`name`) on delete cascade on update cascade, - foreign key (`child`) references `tbl_auth_item` (`name`) on delete cascade on update cascade -) engine InnoDB; - -create table `tbl_auth_assignment` -( - `item_name` varchar(64) not null, - `user_id` varchar(64) not null, - `biz_rule` text, - `data` text, - primary key (`item_name`,`user_id`), - foreign key (`item_name`) references `tbl_auth_item` (`name`) on delete cascade on update cascade -) engine InnoDB; diff --git a/framework/yii/rbac/schema-oci.sql b/framework/yii/rbac/schema-oci.sql deleted file mode 100644 index 78dbb3d..0000000 --- a/framework/yii/rbac/schema-oci.sql +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Database schema required by \yii\rbac\DbManager. - * - * @author Qiang Xue - * @author Alexander Kochetov - * @link http://www.yiiframework.com/ - * @copyright 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - * @since 2.0 - */ - -drop table if exists "tbl_auth_assignment"; -drop table if exists "tbl_auth_item_child"; -drop table if exists "tbl_auth_item"; - -create table "tbl_auth_item" -( - "name" varchar(64) not null, - "type" integer not null, - "description" text, - "biz_rule" text, - "data" text, - primary key ("name"), - key "type" ("type") -); - -create table "tbl_auth_item_child" -( - "parent" varchar(64) not null, - "child" varchar(64) not null, - primary key ("parent","child"), - foreign key ("parent") references "tbl_auth_item" ("name") on delete cascade on update cascade, - foreign key ("child") references "tbl_auth_item" ("name") on delete cascade on update cascade -); - -create table "tbl_auth_assignment" -( - "item_name" varchar(64) not null, - "user_id" varchar(64) not null, - "biz_rule" text, - "data" text, - primary key ("item_name","user_id"), - foreign key ("item_name") references "tbl_auth_item" ("name") on delete cascade on update cascade -); diff --git a/framework/yii/rbac/schema-pgsql.sql b/framework/yii/rbac/schema-pgsql.sql deleted file mode 100644 index bf9865f..0000000 --- a/framework/yii/rbac/schema-pgsql.sql +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Database schema required by \yii\rbac\DbManager. - * - * @author Qiang Xue - * @author Alexander Kochetov - * @link http://www.yiiframework.com/ - * @copyright 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - * @since 2.0 - */ - -drop table if exists "tbl_auth_assignment"; -drop table if exists "tbl_auth_item_child"; -drop table if exists "tbl_auth_item"; - -create table "tbl_auth_item" -( - "name" varchar(64) not null, - "type" integer not null, - "description" text, - "biz_rule" text, - "data" text, - primary key ("name") -); - -create index tbl_auth_item_type_idx on "tbl_auth_item" ("type"); - -create table "tbl_auth_item_child" -( - "parent" varchar(64) not null, - "child" varchar(64) not null, - primary key ("parent","child"), - foreign key ("parent") references "tbl_auth_item" ("name") on delete cascade on update cascade, - foreign key ("child") references "tbl_auth_item" ("name") on delete cascade on update cascade -); - -create table "tbl_auth_assignment" -( - "item_name" varchar(64) not null, - "user_id" varchar(64) not null, - "biz_rule" text, - "data" text, - primary key ("item_name","user_id"), - foreign key ("item_name") references "tbl_auth_item" ("name") on delete cascade on update cascade -); diff --git a/framework/yii/rbac/schema-sqlite.sql b/framework/yii/rbac/schema-sqlite.sql deleted file mode 100644 index 2b79bbf..0000000 --- a/framework/yii/rbac/schema-sqlite.sql +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Database schema required by \yii\rbac\DbManager. - * - * @author Qiang Xue - * @author Alexander Kochetov - * @link http://www.yiiframework.com/ - * @copyright 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - * @since 2.0 - */ - -drop table if exists 'tbl_auth_assignment'; -drop table if exists 'tbl_auth_item_child'; -drop table if exists 'tbl_auth_item'; - -create table 'tbl_auth_item' -( - "name" varchar(64) not null, - "type" integer not null, - "description" text, - "biz_rule" text, - "data" text, - primary key ("name"), - key "type" ("type") -); - -create table 'tbl_auth_item_child' -( - "parent" varchar(64) not null, - "child" varchar(64) not null, - primary key ("parent","child"), - foreign key ("parent") references 'tbl_auth_item' ("name") on delete cascade on update cascade, - foreign key ("child") references 'tbl_auth_item' ("name") on delete cascade on update cascade -); - -create table 'tbl_auth_assignment' -( - "item_name" varchar(64) not null, - "user_id" varchar(64) not null, - "biz_rule" text, - "data" text, - primary key ("item_name","user_id"), - foreign key ("item_name") references 'tbl_auth_item' ("name") on delete cascade on update cascade -); diff --git a/framework/yii/requirements/YiiRequirementChecker.php b/framework/yii/requirements/YiiRequirementChecker.php deleted file mode 100644 index 586cdce..0000000 --- a/framework/yii/requirements/YiiRequirementChecker.php +++ /dev/null @@ -1,398 +0,0 @@ - 'PHP Some Extension', - * 'mandatory' => true, - * 'condition' => extension_loaded('some_extension'), - * 'by' => 'Some application feature', - * 'memo' => 'PHP extension "some_extension" required', - * ), - * ); - * $requirementsChecker->checkYii()->check($requirements)->render(); - * ~~~ - * - * If you wish to render the report with your own representation, use [[getResult()]] instead of [[render()]] - * - * Requirement condition could be in format "eval:PHP expression". - * In this case specified PHP expression will be evaluated in the context of this class instance. - * For example: - * - * ~~~ - * $requirements = array( - * array( - * 'name' => 'Upload max file size', - * 'condition' => 'eval:$this->checkUploadMaxFileSize("5M")', - * ), - * ); - * ~~~ - * - * Note: this class definition does not match ordinary Yii style, because it should match PHP 4.3 - * and should not use features from newer PHP versions! - * - * @property array|null $result the check results, this property is for internal usage only. - * - * @author Paul Klimov - * @since 2.0 - */ -class YiiRequirementChecker -{ - /** - * Check the given requirements, collecting results into internal field. - * This method can be invoked several times checking different requirement sets. - * Use [[getResult()]] or [[render()]] to get the results. - * @param array|string $requirements requirements to be checked. - * If an array, it is treated as the set of requirements; - * If a string, it is treated as the path of the file, which contains the requirements; - * @return static self instance. - */ - function check($requirements) - { - if (is_string($requirements)) { - $requirements = require($requirements); - } - if (!is_array($requirements)) { - $this->usageError('Requirements must be an array, "' . gettype($requirements) . '" has been given!'); - } - if (!isset($this->result) || !is_array($this->result)) { - $this->result = array( - 'summary' => array( - 'total' => 0, - 'errors' => 0, - 'warnings' => 0, - ), - 'requirements' => array(), - ); - } - foreach ($requirements as $key => $rawRequirement) { - $requirement = $this->normalizeRequirement($rawRequirement, $key); - $this->result['summary']['total']++; - if (!$requirement['condition']) { - if ($requirement['mandatory']) { - $requirement['error'] = true; - $requirement['warning'] = true; - $this->result['summary']['errors']++; - } else { - $requirement['error'] = false; - $requirement['warning'] = true; - $this->result['summary']['warnings']++; - } - } else { - $requirement['error'] = false; - $requirement['warning'] = false; - } - $this->result['requirements'][] = $requirement; - } - return $this; - } - - /** - * Performs the check for the Yii core requirements. - * @return YiiRequirementChecker self instance. - */ - function checkYii() - { - return $this->check(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'requirements.php'); - } - - /** - * Return the check results. - * @return array|null check results in format: - * - * array( - * 'summary' => array( - * 'total' => total number of checks, - * 'errors' => number of errors, - * 'warnings' => number of warnings, - * ), - * 'requirements' => array( - * array( - * ... - * 'error' => is there an error, - * 'warning' => is there a warning, - * ), - * ... - * ), - * ) - * - */ - function getResult() - { - if (isset($this->result)) { - return $this->result; - } else { - return null; - } - } - - /** - * Renders the requirements check result. - * The output will vary depending is a script running from web or from console. - */ - function render() - { - if (!isset($this->result)) { - $this->usageError('Nothing to render!'); - } - $baseViewFilePath = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'views'; - if (!empty($_SERVER['argv'])) { - $viewFileName = $baseViewFilePath . DIRECTORY_SEPARATOR . 'console' . DIRECTORY_SEPARATOR . 'index.php'; - } else { - $viewFileName = $baseViewFilePath . DIRECTORY_SEPARATOR . 'web' . DIRECTORY_SEPARATOR . 'index.php'; - } - $this->renderViewFile($viewFileName, $this->result); - } - - /** - * Checks if the given PHP extension is available and its version matches the given one. - * @param string $extensionName PHP extension name. - * @param string $version required PHP extension version. - * @param string $compare comparison operator, by default '>=' - * @return boolean if PHP extension version matches. - */ - function checkPhpExtensionVersion($extensionName, $version, $compare = '>=') - { - if (!extension_loaded($extensionName)) { - return false; - } - $extensionVersion = phpversion($extensionName); - if (empty($extensionVersion)) { - return false; - } - if (strncasecmp($extensionVersion, 'PECL-', 5) == 0) { - $extensionVersion = substr($extensionVersion, 5); - } - return version_compare($extensionVersion, $version, $compare); - } - - /** - * Checks if PHP configuration option (from php.ini) is on. - * @param string $name configuration option name. - * @return boolean option is on. - */ - function checkPhpIniOn($name) - { - $value = ini_get($name); - if (empty($value)) { - return false; - } - return ((integer)$value == 1 || strtolower($value) == 'on'); - } - - /** - * Checks if PHP configuration option (from php.ini) is off. - * @param string $name configuration option name. - * @return boolean option is off. - */ - function checkPhpIniOff($name) - { - $value = ini_get($name); - if (empty($value)) { - return true; - } - return (strtolower($value) == 'off'); - } - - /** - * Compare byte sizes of values given in the verbose representation, - * like '5M', '15K' etc. - * @param string $a first value. - * @param string $b second value. - * @param string $compare comparison operator, by default '>='. - * @return boolean comparison result. - */ - function compareByteSize($a, $b, $compare = '>=') - { - $compareExpression = '(' . $this->getByteSize($a) . $compare . $this->getByteSize($b) . ')'; - return $this->evaluateExpression($compareExpression); - } - - /** - * Gets the size in bytes from verbose size representation. - * For example: '5K' => 5*1024 - * @param string $verboseSize verbose size representation. - * @return integer actual size in bytes. - */ - function getByteSize($verboseSize) - { - if (empty($verboseSize)) { - return 0; - } - if (is_numeric($verboseSize)) { - return (integer)$verboseSize; - } - $sizeUnit = trim($verboseSize, '0123456789'); - $size = str_replace($sizeUnit, '', $verboseSize); - $size = trim($size); - if (!is_numeric($size)) { - return 0; - } - switch (strtolower($sizeUnit)) { - case 'kb': - case 'k': { - return $size * 1024; - } - case 'mb': - case 'm': { - return $size * 1024 * 1024; - } - case 'gb': - case 'g': { - return $size * 1024 * 1024 * 1024; - } - default: { - return 0; - } - } - } - - /** - * Checks if upload max file size matches the given range. - * @param string|null $min verbose file size minimum required value, pass null to skip minimum check. - * @param string|null $max verbose file size maximum required value, pass null to skip maximum check. - * @return boolean success. - */ - function checkUploadMaxFileSize($min = null, $max = null) - { - $postMaxSize = ini_get('post_max_size'); - $uploadMaxFileSize = ini_get('upload_max_filesize'); - if ($min !== null) { - $minCheckResult = $this->compareByteSize($postMaxSize, $min, '>=') && $this->compareByteSize($uploadMaxFileSize, $min, '>='); - } else { - $minCheckResult = true; - } - if ($max !== null) { - var_dump($postMaxSize, $uploadMaxFileSize, $max); - $maxCheckResult = $this->compareByteSize($postMaxSize, $max, '<=') && $this->compareByteSize($uploadMaxFileSize, $max, '<='); - } else { - $maxCheckResult = true; - } - return ($minCheckResult && $maxCheckResult); - } - - /** - * Renders a view file. - * This method includes the view file as a PHP script - * and captures the display result if required. - * @param string $_viewFile_ view file - * @param array $_data_ data to be extracted and made available to the view file - * @param boolean $_return_ whether the rendering result should be returned as a string - * @return string the rendering result. Null if the rendering result is not required. - */ - function renderViewFile($_viewFile_, $_data_ = null, $_return_ = false) - { - // we use special variable names here to avoid conflict when extracting data - if (is_array($_data_)) { - extract($_data_, EXTR_PREFIX_SAME, 'data'); - } else { - $data = $_data_; - } - if ($_return_) { - ob_start(); - ob_implicit_flush(false); - require($_viewFile_); - return ob_get_clean(); - } else { - require($_viewFile_); - } - } - - /** - * Normalizes requirement ensuring it has correct format. - * @param array $requirement raw requirement. - * @param int $requirementKey requirement key in the list. - * @return array normalized requirement. - */ - function normalizeRequirement($requirement, $requirementKey = 0) - { - if (!is_array($requirement)) { - $this->usageError('Requirement must be an array!'); - } - if (!array_key_exists('condition', $requirement)) { - $this->usageError("Requirement '{$requirementKey}' has no condition!"); - } else { - $evalPrefix = 'eval:'; - if (is_string($requirement['condition']) && strpos($requirement['condition'], $evalPrefix) === 0) { - $expression = substr($requirement['condition'], strlen($evalPrefix)); - $requirement['condition'] = $this->evaluateExpression($expression); - } - } - if (!array_key_exists('name', $requirement)) { - $requirement['name'] = is_numeric($requirementKey) ? 'Requirement #' . $requirementKey : $requirementKey; - } - if (!array_key_exists('mandatory', $requirement)) { - if (array_key_exists('required', $requirement)) { - $requirement['mandatory'] = $requirement['required']; - } else { - $requirement['mandatory'] = false; - } - } - if (!array_key_exists('by', $requirement)) { - $requirement['by'] = 'Unknown'; - } - if (!array_key_exists('memo', $requirement)) { - $requirement['memo'] = ''; - } - return $requirement; - } - - /** - * Displays a usage error. - * This method will then terminate the execution of the current application. - * @param string $message the error message - */ - function usageError($message) - { - echo "Error: $message\n\n"; - exit(1); - } - - /** - * Evaluates a PHP expression under the context of this class. - * @param string $expression a PHP expression to be evaluated. - * @return mixed the expression result. - */ - function evaluateExpression($expression) - { - return eval('return ' . $expression . ';'); - } - - /** - * Returns the server information. - * @return string server information. - */ - function getServerInfo() - { - $info = isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : ''; - return $info; - } - - /** - * Returns the now date if possible in string representation. - * @return string now date. - */ - function getNowDate() - { - $nowDate = @strftime('%Y-%m-%d %H:%M', time()); - return $nowDate; - } -} diff --git a/framework/yii/requirements/requirements.php b/framework/yii/requirements/requirements.php deleted file mode 100644 index 916d6aa..0000000 --- a/framework/yii/requirements/requirements.php +++ /dev/null @@ -1,50 +0,0 @@ - 'PHP version', - 'mandatory' => true, - 'condition' => version_compare(PHP_VERSION, '5.4.0', '>='), - 'by' => 'Yii Framework', - 'memo' => 'PHP 5.4.0 or higher is required.', - ), - array( - 'name' => 'Reflection extension', - 'mandatory' => true, - 'condition' => class_exists('Reflection', false), - 'by' => 'Yii Framework', - ), - array( - 'name' => 'PCRE extension', - 'mandatory' => true, - 'condition' => extension_loaded('pcre'), - 'by' => 'Yii Framework', - ), - array( - 'name' => 'SPL extension', - 'mandatory' => true, - 'condition' => extension_loaded('SPL'), - 'by' => 'Yii Framework', - ), - array( - 'name' => 'MBString extension', - 'mandatory' => true, - 'condition' => extension_loaded('mbstring'), - 'by' => 'Multibyte string processing', - 'memo' => 'Required for multibyte encoding string processing.' - ), - array( - 'name' => 'Intl extension', - 'mandatory' => false, - 'condition' => $this->checkPhpExtensionVersion('intl', '1.0.2', '>='), - 'by' => 'Internationalization support', - 'memo' => 'PHP Intl extension 1.0.2 or higher is required when you want to use advanced parameters formatting - in Yii::t(), IDN-feature of - EmailValidator or UrlValidator or the yii\i18n\Formatter class.' - ), -); diff --git a/framework/yii/requirements/views/console/index.php b/framework/yii/requirements/views/console/index.php deleted file mode 100644 index 1d87fe9..0000000 --- a/framework/yii/requirements/views/console/index.php +++ /dev/null @@ -1,36 +0,0 @@ - $requirement) { - if ($requirement['condition']) { - echo $requirement['name'].": OK\n"; - echo "\n"; - } else { - echo $requirement['name'].': '.($requirement['mandatory'] ? 'FAILED!!!' : 'WARNING!!!')."\n"; - echo 'Required by: '.strip_tags($requirement['by'])."\n"; - $memo = strip_tags($requirement['memo']); - if (!empty($memo)) { - echo 'Memo: '.strip_tags($requirement['memo'])."\n"; - } - echo "\n"; - } -} - -$summaryString = 'Errors: '.$summary['errors'].' Warnings: '.$summary['warnings'].' Total checks: '.$summary['total']; -echo str_pad('', strlen($summaryString), '-')."\n"; -echo $summaryString; - -echo "\n\n"; diff --git a/framework/yii/requirements/views/web/css.php b/framework/yii/requirements/views/web/css.php deleted file mode 100644 index 2946a4d..0000000 --- a/framework/yii/requirements/views/web/css.php +++ /dev/null @@ -1,6807 +0,0 @@ - diff --git a/framework/yii/requirements/views/web/index.php b/framework/yii/requirements/views/web/index.php deleted file mode 100644 index 287d4bb..0000000 --- a/framework/yii/requirements/views/web/index.php +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - Yii Application Requirement Checker - renderViewFile(dirname(__FILE__) . '/css.php'); ?> - - -
        -
        -

        Yii Application Requirement Checker

        -
        -
        - -
        -

        Description

        -

        - This script checks if your server configuration meets the requirements - for running Yii application. - It checks if the server is running the right version of PHP, - if appropriate PHP extensions have been loaded, and if php.ini file settings are correct. -

        -

        - There are two kinds of requirements being checked. Mandatory requirements are those that have to be met - to allow Yii to work as expected. There are also some optional requirements beeing checked which will - show you a warning when they do not meet. You can use Yii framework without them but some specific - functionality may be not available in this case. -

        - -

        Conclusion

        - 0): ?> -
        - Unfortunately your server configuration does not satisfy the requirements by this application.
        Please refer to the table below for detailed explanation.
        -
        - 0): ?> -
        - Your server configuration satisfies the minimum requirements by this application.
        Please pay attention to the warnings listed below and check if your application will use the corresponding features.
        -
        - -
        - Congratulations! Your server configuration satisfies all requirements. -
        - - -

        Details

        - - - - - - - - - - - -
        NameResultRequired ByMemo
        - - - - - - - -
        - -
        - -
        - - -
        - - diff --git a/framework/yii/test/DbFixtureManager.php b/framework/yii/test/DbFixtureManager.php deleted file mode 100644 index 303ca6e..0000000 --- a/framework/yii/test/DbFixtureManager.php +++ /dev/null @@ -1,218 +0,0 @@ - - * @since 2.0 - */ -class DbFixtureManager extends Component -{ - /** - * @var string the init script file that should be executed before running each test. - * This should be a path relative to [[basePath]]. - */ - public $initScript = 'init.php'; - /** - * @var string the base path containing all fixtures. This can be either a directory path or path alias. - */ - public $basePath = '@app/tests/fixtures'; - /** - * @var Connection|string the DB connection object or the application component ID of the DB connection. - * After the DbFixtureManager object is created, if you want to change this property, you should only assign it - * with a DB connection object. - */ - public $db = 'db'; - /** - * @var array list of database schemas that the test tables may reside in. Defaults to - * [''], meaning using the default schema (an empty string refers to the - * default schema). This property is mainly used when turning on and off integrity checks - * so that fixture data can be populated into the database without causing problem. - */ - public $schemas = ['']; - - private $_rows; // fixture name, row alias => row - private $_models; // fixture name, row alias => record (or class name) - - - /** - * Loads the specified fixtures. - * - * This method does the following things to load the fixtures: - * - * - Run [[initScript]] if any. - * - Clean up data and models loaded in memory previously. - * - Load each specified fixture by calling [[loadFixture()]]. - * - * @param array $fixtures a list of fixtures (fixture name => table name or AR class name) to be loaded. - * Each array element can be either a table name (with schema prefix if needed), or a fully-qualified - * ActiveRecord class name (e.g. `app\models\Post`). An element can be associated with a key - * which will be treated as the fixture name. - * @return array the loaded fixture data (fixture name => table rows) - * @throws InvalidConfigException if a model class specifying a fixture is not an ActiveRecord class. - */ - public function load(array $fixtures = []) - { - $this->basePath = Yii::getAlias($this->basePath); - - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - } - if (!$this->db instanceof Connection) { - throw new InvalidConfigException("The 'db' property must be either a DB connection instance or the application component ID of a DB connection."); - } - - foreach ($fixtures as $name => $fixture) { - if (strpos($fixture, '\\') !== false) { - $model = new $fixture; - if ($model instanceof ActiveRecord) { - $fixtures[$name] = $model->getTableSchema()->name; - } else { - throw new InvalidConfigException("Fixture '$fixture' must be an ActiveRecord class."); - } - } - } - - $this->_rows = $this->_models = []; - - $this->checkIntegrity(false); - - if (!empty($this->initScript)) { - $initFile = $this->basePath . '/' . $this->initScript; - if (is_file($initFile)) { - require($initFile); - } - } - - foreach ($fixtures as $name => $tableName) { - $rows = $this->loadFixture($tableName); - if (is_array($rows)) { - $this->_rows[$name] = $rows; - } - } - $this->checkIntegrity(true); - return $this->_rows; - } - - /** - * Loads the fixture for the specified table. - * - * This method does the following tasks to load the fixture for a table: - * - * - Remove existing rows in the table. - * - If there is any auto-incremental column, the corresponding sequence will be reset to 0. - * - If a fixture file is found, it will be executed, and its return value will be treated - * as rows which will then be inserted into the table. - * - * @param string $tableName table name - * @return array|boolean the loaded fixture rows indexed by row aliases (if any). - * False is returned if the table does not have a fixture. - * @throws InvalidConfigException if the specified table does not exist - */ - public function loadFixture($tableName) - { - $table = $this->db->getSchema()->getTableSchema($tableName); - if ($table === null) { - throw new InvalidConfigException("Table does not exist: $tableName"); - } - - $this->db->createCommand()->truncateTable($tableName)->execute(); - $this->db->createCommand()->resetSequence($tableName, 1)->execute(); - - $fileName = $this->basePath . '/' . $tableName . '.php'; - if (!is_file($fileName)) { - return false; - } - - $rows = []; - foreach (require($fileName) as $alias => $row) { - $this->db->createCommand()->insert($tableName, $row)->execute(); - if ($table->sequenceName !== null) { - foreach ($table->primaryKey as $pk) { - if (!isset($row[$pk])) { - $row[$pk] = $this->db->getLastInsertID($table->sequenceName); - break; - } - } - } - $rows[$alias] = $row; - } - - return $rows; - } - - /** - * Returns the fixture data rows. - * The rows will have updated primary key values if the primary key is auto-incremental. - * @param string $fixtureName the fixture name - * @return array the fixture data rows. False is returned if there is no such fixture data. - */ - public function getRows($fixtureName) - { - return isset($this->_rows[$fixtureName]) ? $this->_rows[$fixtureName] : false; - } - - /** - * Returns the specified ActiveRecord instance in the fixture data. - * @param string $fixtureName the fixture name - * @param string $modelName the alias for the fixture data row - * @return ActiveRecord the ActiveRecord instance. Null is returned if there is no such fixture row. - */ - public function getModel($fixtureName, $modelName) - { - if (!isset($this->_rows[$fixtureName][$modelName])) { - return null; - } - if (isset($this->_models[$fixtureName][$modelName])) { - return $this->_models[$fixtureName][$modelName]; - } - $row = $this->_rows[$fixtureName][$modelName]; - /** @var ActiveRecord $modelClass */ - $modelClass = $this->_models[$fixtureName]; - /** @var ActiveRecord $model */ - $model = new $modelClass; - $keys = []; - foreach ($model->primaryKey() as $key) { - $keys[$key] = isset($row[$key]) ? $row[$key] : null; - } - return $this->_models[$fixtureName][$modelName] = $modelClass::find($keys); - } - - /** - * Enables or disables database integrity check. - * This method may be used to temporarily turn off foreign constraints check. - * @param boolean $check whether to enable database integrity check - */ - public function checkIntegrity($check) - { - foreach ($this->schemas as $schema) { - $this->db->createCommand()->checkIntegrity($check, $schema)->execute(); - } - } -} diff --git a/framework/yii/test/DbTestTrait.php b/framework/yii/test/DbTestTrait.php deleted file mode 100644 index a6d616e..0000000 --- a/framework/yii/test/DbTestTrait.php +++ /dev/null @@ -1,113 +0,0 @@ -loadFixtures([ - * 'posts' => Post::className(), - * 'users' => User::className(), - * ]); - * } - * } - * ~~~ - * - * @author Qiang Xue - * @since 2.0 - */ -trait DbTestTrait -{ - /** - * Loads the specified fixtures. - * - * This method should typically be called in the setup method of test cases so that - * the fixtures are loaded before running each test method. - * - * This method does the following things: - * - * - Run [[DbFixtureManager::initScript]] if it is found under [[DbFixtureManager::basePath]]. - * - Clean up data and models loaded in memory previously. - * - Load each specified fixture: - * * Truncate the corresponding table. - * * If a fixture file named `TableName.php` is found under [[DbFixtureManager::basePath]], - * the file will be executed, and the return value will be treated as rows which will - * then be inserted into the table. - * - * @param array $fixtures a list of fixtures (fixture name => table name or AR class name) to be loaded. - * Each array element can be either a table name (with schema prefix if needed), or a fully-qualified - * ActiveRecord class name (e.g. `app\models\Post`). An element can be optionally associated with a key - * which will be treated as the fixture name. For example, - * - * ~~~ - * [ - * 'tbl_comment', - * 'users' => 'tbl_user', // 'users' is the fixture name, 'tbl_user' is a table name - * 'posts' => 'app\models\Post, // 'app\models\Post' is a model class name - * ] - * ~~~ - * - * @return array the loaded fixture data (fixture name => table rows) - */ - public function loadFixtures(array $fixtures = []) - { - return $this->getFixtureManager()->load($fixtures); - } - - /** - * Returns the DB fixture manager. - * @return DbFixtureManager the DB fixture manager - */ - public function getFixtureManager() - { - return Yii::$app->getComponent('fixture'); - } - - /** - * Returns the table rows of the named fixture. - * @param string $fixtureName the fixture name. - * @return array the named fixture table rows. False is returned if there is no such fixture data. - */ - public function getFixtureRows($fixtureName) - { - return $this->getFixtureManager()->getRows($fixtureName); - } - - /** - * Returns the named AR instance corresponding to the named fixture. - * @param string $fixtureName the fixture name. - * @param string $modelName the name of the fixture data row - * @return \yii\db\ActiveRecord the named AR instance corresponding to the named fixture. - * Null is returned if there is no such fixture or the record cannot be found. - */ - public function getFixtureModel($fixtureName, $modelName) - { - return $this->getFixtureManager()->getModel($fixtureName, $modelName); - } -} diff --git a/framework/yii/validators/BooleanValidator.php b/framework/yii/validators/BooleanValidator.php deleted file mode 100644 index 8bca827..0000000 --- a/framework/yii/validators/BooleanValidator.php +++ /dev/null @@ -1,91 +0,0 @@ - - * @since 2.0 - */ -class BooleanValidator extends Validator -{ - /** - * @var mixed the value representing true status. Defaults to '1'. - */ - public $trueValue = '1'; - /** - * @var mixed the value representing false status. Defaults to '0'. - */ - public $falseValue = '0'; - /** - * @var boolean whether the comparison to [[trueValue]] and [[falseValue]] is strict. - * When this is true, the attribute value and type must both match those of [[trueValue]] or [[falseValue]]. - * Defaults to false, meaning only the value needs to be matched. - */ - public $strict = false; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->message === null) { - $this->message = Yii::t('yii', '{attribute} must be either "{true}" or "{false}".'); - } - } - - /** - * @inheritdoc - */ - protected function validateValue($value) - { - $valid = !$this->strict && ($value == $this->trueValue || $value == $this->falseValue) - || $this->strict && ($value === $this->trueValue || $value === $this->falseValue); - if (!$valid) { - return [$this->message, [ - 'true' => $this->trueValue, - 'false' => $this->falseValue, - ]]; - } else { - return null; - } - } - - /** - * @inheritdoc - */ - public function clientValidateAttribute($object, $attribute, $view) - { - $options = [ - 'trueValue' => $this->trueValue, - 'falseValue' => $this->falseValue, - 'message' => strtr($this->message, [ - '{attribute}' => $object->getAttributeLabel($attribute), - '{true}' => $this->trueValue, - '{false}' => $this->falseValue, - ]), - ]; - if ($this->skipOnEmpty) { - $options['skipOnEmpty'] = 1; - } - if ($this->strict) { - $options['strict'] = 1; - } - - ValidationAsset::register($view); - return 'yii.validation.boolean(value, messages, ' . json_encode($options) . ');'; - } -} diff --git a/framework/yii/validators/CompareValidator.php b/framework/yii/validators/CompareValidator.php deleted file mode 100644 index cbd12d2..0000000 --- a/framework/yii/validators/CompareValidator.php +++ /dev/null @@ -1,207 +0,0 @@ - - * @since 2.0 - */ -class CompareValidator extends Validator -{ - /** - * @var string the name of the attribute to be compared with. When both this property - * and [[compareValue]] are set, the latter takes precedence. If neither is set, - * it assumes the comparison is against another attribute whose name is formed by - * appending '_repeat' to the attribute being validated. For example, if 'password' is - * being validated, then the attribute to be compared would be 'password_repeat'. - * @see compareValue - */ - public $compareAttribute; - /** - * @var mixed the constant value to be compared with. When both this property - * and [[compareAttribute]] are set, this property takes precedence. - * @see compareAttribute - */ - public $compareValue; - /** - * @var string the operator for comparison. The following operators are supported: - * - * - '==': validates to see if the two values are equal. The comparison is done is non-strict mode. - * - '===': validates to see if the two values are equal. The comparison is done is strict mode. - * - '!=': validates to see if the two values are NOT equal. The comparison is done is non-strict mode. - * - '!==': validates to see if the two values are NOT equal. The comparison is done is strict mode. - * - `>`: validates to see if the value being validated is greater than the value being compared with. - * - `>=`: validates to see if the value being validated is greater than or equal to the value being compared with. - * - `<`: validates to see if the value being validated is less than the value being compared with. - * - `<=`: validates to see if the value being validated is less than or equal to the value being compared with. - */ - public $operator = '=='; - /** - * @var string the user-defined error message. It may contain the following placeholders which - * will be replaced accordingly by the validator: - * - * - `{attribute}`: the label of the attribute being validated - * - `{value}`: the value of the attribute being validated - * - `{compareValue}`: the value or the attribute label to be compared with - * - `{compareAttribute}`: the label of the attribute to be compared with - */ - public $message; - - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->message === null) { - switch ($this->operator) { - case '==': - $this->message = Yii::t('yii', '{attribute} must be repeated exactly.'); - break; - case '===': - $this->message = Yii::t('yii', '{attribute} must be repeated exactly.'); - break; - case '!=': - $this->message = Yii::t('yii', '{attribute} must not be equal to "{compareValue}".'); - break; - case '!==': - $this->message = Yii::t('yii', '{attribute} must not be equal to "{compareValue}".'); - break; - case '>': - $this->message = Yii::t('yii', '{attribute} must be greater than "{compareValue}".'); - break; - case '>=': - $this->message = Yii::t('yii', '{attribute} must be greater than or equal to "{compareValue}".'); - break; - case '<': - $this->message = Yii::t('yii', '{attribute} must be less than "{compareValue}".'); - break; - case '<=': - $this->message = Yii::t('yii', '{attribute} must be less than or equal to "{compareValue}".'); - break; - default: - throw new InvalidConfigException("Unknown operator: {$this->operator}"); - } - } - } - - /** - * @inheritdoc - */ - public function validateAttribute($object, $attribute) - { - $value = $object->$attribute; - if (is_array($value)) { - $this->addError($object, $attribute, Yii::t('yii', '{attribute} is invalid.')); - return; - } - if ($this->compareValue !== null) { - $compareLabel = $compareValue = $this->compareValue; - } else { - $compareAttribute = $this->compareAttribute === null ? $attribute . '_repeat' : $this->compareAttribute; - $compareValue = $object->$compareAttribute; - $compareLabel = $object->getAttributeLabel($compareAttribute); - } - - if (!$this->compareValues($this->operator, $value, $compareValue)) { - $this->addError($object, $attribute, $this->message, [ - 'compareAttribute' => $compareLabel, - 'compareValue' => $compareValue, - ]); - } - } - - /** - * @inheritdoc - */ - protected function validateValue($value) - { - if ($this->compareValue === null) { - throw new InvalidConfigException('CompareValidator::compareValue must be set.'); - } - if (!$this->compareValues($this->operator, $value, $this->compareValue)) { - return [$this->message, [ - 'compareAttribute' => $this->compareValue, - 'compareValue' => $this->compareValue, - ]]; - } else { - return null; - } - } - - /** - * Compares two values with the specified operator. - * @param string $operator the comparison operator - * @param mixed $value the value being compared - * @param mixed $compareValue another value being compared - * @return boolean whether the comparison using the specified operator is true. - */ - protected function compareValues($operator, $value, $compareValue) - { - switch ($operator) { - case '==': return $value == $compareValue; - case '===': return $value === $compareValue; - case '!=': return $value != $compareValue; - case '!==': return $value !== $compareValue; - case '>': return $value > $compareValue; - case '>=': return $value >= $compareValue; - case '<': return $value < $compareValue; - case '<=': return $value <= $compareValue; - default: return false; - } - } - - /** - * @inheritdoc - */ - public function clientValidateAttribute($object, $attribute, $view) - { - $options = ['operator' => $this->operator]; - - if ($this->compareValue !== null) { - $options['compareValue'] = $this->compareValue; - $compareValue = $this->compareValue; - } else { - $compareAttribute = $this->compareAttribute === null ? $attribute . '_repeat' : $this->compareAttribute; - $compareValue = $object->getAttributeLabel($compareAttribute); - $options['compareAttribute'] = Html::getInputId($object, $compareAttribute); - } - - if ($this->skipOnEmpty) { - $options['skipOnEmpty'] = 1; - } - - $options['message'] = strtr($this->message, [ - '{attribute}' => $object->getAttributeLabel($attribute), - '{compareAttribute}' => $compareValue, - '{compareValue}' => $compareValue, - ]); - - ValidationAsset::register($view); - return 'yii.validation.compare(value, messages, ' . json_encode($options) . ');'; - } -} diff --git a/framework/yii/validators/DateValidator.php b/framework/yii/validators/DateValidator.php deleted file mode 100644 index d79aa85..0000000 --- a/framework/yii/validators/DateValidator.php +++ /dev/null @@ -1,73 +0,0 @@ - - * @since 2.0 - */ -class DateValidator extends Validator -{ - /** - * @var string the date format that the value being validated should follow. - * Please refer to on - * supported formats. - */ - public $format = 'Y-m-d'; - /** - * @var string the name of the attribute to receive the parsing result. - * When this property is not null and the validation is successful, the named attribute will - * receive the parsing result. - */ - public $timestampAttribute; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->message === null) { - $this->message = Yii::t('yii', 'The format of {attribute} is invalid.'); - } - } - - /** - * @inheritdoc - */ - public function validateAttribute($object, $attribute) - { - $value = $object->$attribute; - $result = $this->validateValue($value); - if (!empty($result)) { - $this->addError($object, $attribute, $result[0], $result[1]); - } elseif ($this->timestampAttribute !== null) { - $date = DateTime::createFromFormat($this->format, $value); - $object->{$this->timestampAttribute} = $date->getTimestamp(); - } - } - - /** - * @inheritdoc - */ - protected function validateValue($value) - { - if (is_array($value)) { - return [$this->message, []]; - } - $date = DateTime::createFromFormat($this->format, $value); - $errors = DateTime::getLastErrors(); - $invalid = $date === false || $errors['error_count'] || $errors['warning_count']; - return $invalid ? [$this->message, []] : null; - } -} diff --git a/framework/yii/validators/DefaultValueValidator.php b/framework/yii/validators/DefaultValueValidator.php deleted file mode 100644 index 0db3a67..0000000 --- a/framework/yii/validators/DefaultValueValidator.php +++ /dev/null @@ -1,40 +0,0 @@ - - * @since 2.0 - */ -class DefaultValueValidator extends Validator -{ - /** - * @var mixed the default value to be set to the specified attributes. - */ - public $value; - /** - * @var boolean this property is overwritten to be false so that this validator will - * be applied when the value being validated is empty. - */ - public $skipOnEmpty = false; - - /** - * @inheritdoc - */ - public function validateAttribute($object, $attribute) - { - if ($this->isEmpty($object->$attribute)) { - $object->$attribute = $this->value; - } - } -} diff --git a/framework/yii/validators/EmailValidator.php b/framework/yii/validators/EmailValidator.php deleted file mode 100644 index e5d9b75..0000000 --- a/framework/yii/validators/EmailValidator.php +++ /dev/null @@ -1,116 +0,0 @@ - - * @since 2.0 - */ -class EmailValidator extends Validator -{ - /** - * @var string the regular expression used to validate the attribute value. - * @see http://www.regular-expressions.info/email.html - */ - public $pattern = '/^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/'; - /** - * @var string the regular expression used to validate email addresses with the name part. - * This property is used only when [[allowName]] is true. - * @see allowName - */ - public $fullPattern = '/^[^@]*<[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?>$/'; - /** - * @var boolean whether to allow name in the email address (e.g. "John Smith "). Defaults to false. - * @see fullPattern - */ - public $allowName = false; - /** - * @var boolean whether to check whether the emails domain exists and has either an A or MX record. - * Be aware of the fact that this check can fail due to temporary DNS problems even if the email address is - * valid and an email would be deliverable. Defaults to false. - */ - public $checkDNS = false; - /** - * @var boolean whether validation process should take into account IDN (internationalized domain - * names). Defaults to false meaning that validation of emails containing IDN will always fail. - * Note that in order to use IDN validation you have to install and enable `intl` PHP extension, - * otherwise an exception would be thrown. - */ - public $enableIDN = false; - - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->enableIDN && !function_exists('idn_to_ascii')) { - throw new InvalidConfigException('In order to use IDN validation intl extension must be installed and enabled.'); - } - if ($this->message === null) { - $this->message = Yii::t('yii', '{attribute} is not a valid email address.'); - } - } - - /** - * @inheritdoc - */ - protected function validateValue($value) - { - // make sure string length is limited to avoid DOS attacks - if (!is_string($value) || strlen($value) >= 320) { - $valid = false; - } elseif (!preg_match('/^(.*?)$/', $value, $matches)) { - $valid = false; - } else { - $domain = $matches[3]; - if ($this->enableIDN) { - $value = $matches[1] . idn_to_ascii($matches[2]) . '@' . idn_to_ascii($domain) . $matches[4]; - } - $valid = preg_match($this->pattern, $value) || $this->allowName && preg_match($this->fullPattern, $value); - if ($valid && $this->checkDNS) { - $valid = checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A'); - } - } - return $valid ? null : [$this->message, []]; - } - - /** - * @inheritdoc - */ - public function clientValidateAttribute($object, $attribute, $view) - { - $options = [ - 'pattern' => new JsExpression($this->pattern), - 'fullPattern' => new JsExpression($this->fullPattern), - 'allowName' => $this->allowName, - 'message' => strtr($this->message, [ - '{attribute}' => $object->getAttributeLabel($attribute), - ]), - 'enableIDN' => (boolean)$this->enableIDN, - ]; - if ($this->skipOnEmpty) { - $options['skipOnEmpty'] = 1; - } - - ValidationAsset::register($view); - if ($this->enableIDN) { - PunycodeAsset::register($view); - } - return 'yii.validation.email(value, messages, ' . Json::encode($options) . ');'; - } -} diff --git a/framework/yii/validators/ExistValidator.php b/framework/yii/validators/ExistValidator.php deleted file mode 100644 index caefc49..0000000 --- a/framework/yii/validators/ExistValidator.php +++ /dev/null @@ -1,122 +0,0 @@ - 'a2'] - * // a1 and a2 need to exist together, and they both will receive error message - * [['a1', 'a2'], 'exist', 'targetAttribute' => ['a1', 'a2']] - * // a1 and a2 need to exist together, only a1 will receive error message - * ['a1', 'exist', 'targetAttribute' => ['a1', 'a2']] - * // a1 needs to exist by checking the existence of both a2 and a3 (using a1 value) - * ['a1', 'exist', 'targetAttribute' => ['a2', 'a1' => 'a3']] - * ``` - * - * @author Qiang Xue - * @since 2.0 - */ -class ExistValidator extends Validator -{ - /** - * @var string the name of the ActiveRecord class that should be used to validate the existence - * of the current attribute value. It not set, it will use the ActiveRecord class of the attribute being validated. - * @see targetAttribute - */ - public $targetClass; - /** - * @var string|array the name of the ActiveRecord attribute that should be used to - * validate the existence of the current attribute value. If not set, it will use the name - * of the attribute currently being validated. You may use an array to validate the existence - * of multiple columns at the same time. The array values are the attributes that will be - * used to validate the existence, while the array keys are the attributes whose values are to be validated. - * If the key and the value are the same, you can just specify the value. - */ - public $targetAttribute; - - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->message === null) { - $this->message = Yii::t('yii', '{attribute} is invalid.'); - } - } - - /** - * @inheritdoc - */ - public function validateAttribute($object, $attribute) - { - /** @var \yii\db\ActiveRecordInterface $targetClass */ - $targetClass = $this->targetClass === null ? get_class($object) : $this->targetClass; - $targetAttribute = $this->targetAttribute === null ? $attribute : $this->targetAttribute; - - if (is_array($targetAttribute)) { - $params = []; - foreach ($targetAttribute as $k => $v) { - $params[$v] = is_integer($k) ? $object->$v : $object->$k; - } - } else { - $params = [$targetAttribute => $object->$attribute]; - } - - foreach ($params as $value) { - if (is_array($value)) { - $this->addError($object, $attribute, Yii::t('yii', '{attribute} is invalid.')); - return; - } - } - - /** @var \yii\db\ActiveRecordInterface $className */ - if (!$targetClass::find()->where($params)->exists()) { - $this->addError($object, $attribute, $this->message); - } - } - - /** - * @inheritdoc - */ - protected function validateValue($value) - { - if (is_array($value)) { - return [$this->message, []]; - } - if ($this->targetClass === null) { - throw new InvalidConfigException('The "className" property must be set.'); - } - if (!is_string($this->targetAttribute)) { - throw new InvalidConfigException('The "attributeName" property must be configured as a string.'); - } - - /** @var \yii\db\ActiveRecordInterface $targetClass */ - $targetClass = $this->targetClass; - $query = $targetClass::find(); - $query->where([$this->targetAttribute => $value]); - return $query->exists() ? null : [$this->message, []]; - } -} diff --git a/framework/yii/validators/FileValidator.php b/framework/yii/validators/FileValidator.php deleted file mode 100644 index ac323e0..0000000 --- a/framework/yii/validators/FileValidator.php +++ /dev/null @@ -1,249 +0,0 @@ - - * @since 2.0 - */ -class FileValidator extends Validator -{ - /** - * @var array|string a list of file name extensions that are allowed to be uploaded. - * This can be either an array or a string consisting of file extension names - * separated by space or comma (e.g. "gif, jpg"). - * Extension names are case-insensitive. Defaults to null, meaning all file name - * extensions are allowed. - * @see wrongType - */ - public $types; - /** - * @var integer the minimum number of bytes required for the uploaded file. - * Defaults to null, meaning no limit. - * @see tooSmall - */ - public $minSize; - /** - * @var integer the maximum number of bytes required for the uploaded file. - * Defaults to null, meaning no limit. - * Note, the size limit is also affected by 'upload_max_filesize' INI setting - * and the 'MAX_FILE_SIZE' hidden field value. - * @see tooBig - */ - public $maxSize; - /** - * @var integer the maximum file count the given attribute can hold. - * It defaults to 1, meaning single file upload. By defining a higher number, - * multiple uploads become possible. - * @see tooMany - */ - public $maxFiles = 1; - /** - * @var string the error message used when a file is not uploaded correctly. - */ - public $message; - /** - * @var string the error message used when no file is uploaded. - */ - public $uploadRequired; - /** - * @var string the error message used when the uploaded file is too large. - * You may use the following tokens in the message: - * - * - {attribute}: the attribute name - * - {file}: the uploaded file name - * - {limit}: the maximum size allowed (see [[getSizeLimit()]]) - */ - public $tooBig; - /** - * @var string the error message used when the uploaded file is too small. - * You may use the following tokens in the message: - * - * - {attribute}: the attribute name - * - {file}: the uploaded file name - * - {limit}: the value of [[minSize]] - */ - public $tooSmall; - /** - * @var string the error message used when the uploaded file has an extension name - * that is not listed in [[types]]. You may use the following tokens in the message: - * - * - {attribute}: the attribute name - * - {file}: the uploaded file name - * - {extensions}: the list of the allowed extensions. - */ - public $wrongType; - /** - * @var string the error message used if the count of multiple uploads exceeds limit. - * You may use the following tokens in the message: - * - * - {attribute}: the attribute name - * - {limit}: the value of [[maxFiles]] - */ - public $tooMany; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->message === null) { - $this->message = Yii::t('yii', 'File upload failed.'); - } - if ($this->uploadRequired === null) { - $this->uploadRequired = Yii::t('yii', 'Please upload a file.'); - } - if ($this->tooMany === null) { - $this->tooMany = Yii::t('yii', 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.'); - } - if ($this->wrongType === null) { - $this->wrongType = Yii::t('yii', 'Only files with these extensions are allowed: {extensions}.'); - } - if ($this->tooBig === null) { - $this->tooBig = Yii::t('yii', 'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.'); - } - if ($this->tooSmall === null) { - $this->tooSmall = Yii::t('yii', 'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.'); - } - if (!is_array($this->types)) { - $this->types = preg_split('/[\s,]+/', strtolower($this->types), -1, PREG_SPLIT_NO_EMPTY); - } - } - - /** - * @inheritdoc - */ - public function validateAttribute($object, $attribute) - { - if ($this->maxFiles > 1) { - $files = $object->$attribute; - if (!is_array($files)) { - $this->addError($object, $attribute, $this->uploadRequired); - return; - } - foreach ($files as $i => $file) { - if (!$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE) { - unset($files[$i]); - } - } - $object->$attribute = array_values($files); - if (empty($files)) { - $this->addError($object, $attribute, $this->uploadRequired); - } - if (count($files) > $this->maxFiles) { - $this->addError($object, $attribute, $this->tooMany, ['limit' => $this->maxFiles]); - } else { - foreach ($files as $file) { - $result = $this->validateValue($file); - if (!empty($result)) { - $this->addError($object, $attribute, $result[0], $result[1]); - } - } - } - } else { - $result = $this->validateValue($object->$attribute); - if (!empty($result)) { - $this->addError($object, $attribute, $result[0], $result[1]); - } - } - } - - /** - * @inheritdoc - */ - protected function validateValue($file) - { - if (!$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE) { - return [$this->uploadRequired, []]; - } - switch ($file->error) { - case UPLOAD_ERR_OK: - if ($this->maxSize !== null && $file->size > $this->maxSize) { - return [$this->tooBig, ['file' => $file->name, 'limit' => $this->getSizeLimit()]]; - } elseif ($this->minSize !== null && $file->size < $this->minSize) { - return [$this->tooSmall, ['file' => $file->name, 'limit' => $this->minSize]]; - } elseif (!empty($this->types) && !in_array(strtolower(pathinfo($file->name, PATHINFO_EXTENSION)), $this->types, true)) { - return [$this->wrongType, ['file' => $file->name, 'extensions' => implode(', ', $this->types)]]; - } else { - return null; - } - case UPLOAD_ERR_INI_SIZE: - case UPLOAD_ERR_FORM_SIZE: - return [$this->tooBig, ['file' => $file->name, 'limit' => $this->getSizeLimit()]]; - case UPLOAD_ERR_PARTIAL: - Yii::warning('File was only partially uploaded: ' . $file->name, __METHOD__); - break; - case UPLOAD_ERR_NO_TMP_DIR: - Yii::warning('Missing the temporary folder to store the uploaded file: ' . $file->name, __METHOD__); - break; - case UPLOAD_ERR_CANT_WRITE: - Yii::warning('Failed to write the uploaded file to disk: ' . $file->name, __METHOD__); - break; - case UPLOAD_ERR_EXTENSION: - Yii::warning('File upload was stopped by some PHP extension: ' . $file->name, __METHOD__); - break; - default: - break; - } - return [$this->message, []]; - } - - /** - * Returns the maximum size allowed for uploaded files. - * This is determined based on three factors: - * - * - 'upload_max_filesize' in php.ini - * - 'MAX_FILE_SIZE' hidden field - * - [[maxSize]] - * - * @return integer the size limit for uploaded files. - */ - public function getSizeLimit() - { - $limit = ini_get('upload_max_filesize'); - $limit = $this->sizeToBytes($limit); - if ($this->maxSize !== null && $limit > 0 && $this->maxSize < $limit) { - $limit = $this->maxSize; - } - if (isset($_POST['MAX_FILE_SIZE']) && $_POST['MAX_FILE_SIZE'] > 0 && $_POST['MAX_FILE_SIZE'] < $limit) { - $limit = (int)$_POST['MAX_FILE_SIZE']; - } - return $limit; - } - - /** - * Converts php.ini style size to bytes - * - * @param string $sizeStr $sizeStr - * @return int - */ - private 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; - } - } -} diff --git a/framework/yii/validators/FilterValidator.php b/framework/yii/validators/FilterValidator.php deleted file mode 100644 index 685faee..0000000 --- a/framework/yii/validators/FilterValidator.php +++ /dev/null @@ -1,66 +0,0 @@ - - * @since 2.0 - */ -class FilterValidator extends Validator -{ - /** - * @var callback the filter. This can be a global function name, anonymous function, etc. - * The function signature must be as follows, - * - * ~~~ - * function foo($value) {...return $newValue; } - * ~~~ - */ - public $filter; - /** - * @var boolean this property is overwritten to be false so that this validator will - * be applied when the value being validated is empty. - */ - public $skipOnEmpty = false; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->filter === null) { - throw new InvalidConfigException('The "filter" property must be set.'); - } - } - - /** - * @inheritdoc - */ - public function validateAttribute($object, $attribute) - { - $object->$attribute = call_user_func($this->filter, $object->$attribute); - } -} diff --git a/framework/yii/validators/ImageValidator.php b/framework/yii/validators/ImageValidator.php deleted file mode 100644 index 52fb235..0000000 --- a/framework/yii/validators/ImageValidator.php +++ /dev/null @@ -1,190 +0,0 @@ - - * @since 2.0 - */ -class ImageValidator extends FileValidator -{ - /** - * @var string the error message used when the uploaded file is not an image. - * You may use the following tokens in the message: - * - * - {attribute}: the attribute name - * - {file}: the uploaded file name - */ - public $notImage; - /** - * @var integer the minimum width in pixels. - * Defaults to null, meaning no limit. - * @see underWidth - */ - public $minWidth; - /** - * @var integer the maximum width in pixels. - * Defaults to null, meaning no limit. - * @see overWidth - */ - public $maxWidth; - /** - * @var integer the minimum height in pixels. - * Defaults to null, meaning no limit. - * @see underHeight - */ - public $minHeight; - /** - * @var integer the maximum width in pixels. - * Defaults to null, meaning no limit. - * @see overWidth - */ - public $maxHeight; - /** - * @var array|string a list of file mime types that are allowed to be uploaded. - * This can be either an array or a string consisting of file mime types - * separated by space or comma (e.g. "image/jpeg, image/png"). - * Mime type names are case-insensitive. Defaults to null, meaning all mime types - * are allowed. - * @see wrongMimeType - */ - public $mimeTypes; - /** - * @var string the error message used when the image is under [[minWidth]]. - * You may use the following tokens in the message: - * - * - {attribute}: the attribute name - * - {file}: the uploaded file name - * - {limit}: the value of [[minWidth]] - */ - public $underWidth; - /** - * @var string the error message used when the image is over [[maxWidth]]. - * You may use the following tokens in the message: - * - * - {attribute}: the attribute name - * - {file}: the uploaded file name - * - {limit}: the value of [[maxWidth]] - */ - public $overWidth; - /** - * @var string the error message used when the image is under [[minHeight]]. - * You may use the following tokens in the message: - * - * - {attribute}: the attribute name - * - {file}: the uploaded file name - * - {limit}: the value of [[minHeight]] - */ - public $underHeight; - /** - * @var string the error message used when the image is over [[maxHeight]]. - * You may use the following tokens in the message: - * - * - {attribute}: the attribute name - * - {file}: the uploaded file name - * - {limit}: the value of [[maxHeight]] - */ - public $overHeight; - /** - * @var string the error message used when the file has an mime type - * that is not listed in [[mimeTypes]]. - * You may use the following tokens in the message: - * - * - {attribute}: the attribute name - * - {file}: the uploaded file name - * - {mimeTypes}: the value of [[mimeTypes]] - */ - public $wrongMimeType; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - - if ($this->notImage === null) { - $this->notImage = Yii::t('yii', 'The file "{file}" is not an image.'); - } - if ($this->underWidth === null) { - $this->underWidth = Yii::t('yii', 'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.'); - } - if ($this->underHeight === null) { - $this->underHeight = Yii::t('yii', 'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.'); - } - if ($this->overWidth === null) { - $this->overWidth = Yii::t('yii', 'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.'); - } - if ($this->overHeight === null) { - $this->overHeight = Yii::t('yii', 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.'); - } - if ($this->wrongMimeType === null) { - $this->wrongMimeType = Yii::t('yii', 'Only files with these mimeTypes are allowed: {mimeTypes}.'); - } - if (!is_array($this->mimeTypes)) { - $this->mimeTypes = preg_split('/[\s,]+/', strtolower($this->mimeTypes), -1, PREG_SPLIT_NO_EMPTY); - } - } - - /** - * @inheritdoc - */ - protected function validateValue($file) - { - $result = parent::validateValue($file); - return empty($result) ? $this->validateImage($file) : $result; - } - - /** - * Validates an image file. - * @param UploadedFile $image uploaded file passed to check against a set of rules - * @return array|null the error message and the parameters to be inserted into the error message. - * Null should be returned if the data is valid. - */ - protected function validateImage($image) - { - if (!empty($this->mimeTypes) && !in_array(FileHelper::getMimeType($image->tempName), $this->mimeTypes, true)) { - return [$this->wrongMimeType, ['file' => $image->name, 'mimeTypes' => implode(', ', $this->mimeTypes)]]; - } - - if (false === ($imageInfo = getimagesize($image->tempName))) { - return [$this->notImage, ['file' => $image->name]]; - } - - list($width, $height, $type) = $imageInfo; - - if ($width == 0 || $height == 0) { - return [$this->notImage, ['file' => $image->name]]; - } - - if ($this->minWidth !== null && $width < $this->minWidth) { - return [$this->underWidth, ['file' => $image->name, 'limit' => $this->minWidth]]; - } - - if ($this->minHeight !== null && $height < $this->minHeight) { - return [$this->underHeight, ['file' => $image->name, 'limit' => $this->minHeight]]; - } - - if ($this->maxWidth !== null && $width > $this->maxWidth) { - return [$this->overWidth, ['file' => $image->name, 'limit' => $this->maxWidth]]; - } - - if ($this->maxHeight !== null && $height > $this->maxHeight) { - return [$this->overHeight, ['file' => $image->name, 'limit' => $this->maxHeight]]; - } - return null; - } -} diff --git a/framework/yii/validators/InlineValidator.php b/framework/yii/validators/InlineValidator.php deleted file mode 100644 index b769e4e..0000000 --- a/framework/yii/validators/InlineValidator.php +++ /dev/null @@ -1,84 +0,0 @@ - - * @since 2.0 - */ -class InlineValidator extends Validator -{ - /** - * @var string|\Closure an anonymous function or the name of a model class method that will be - * called to perform the actual validation. The signature of the method should be like the following: - * - * ~~~ - * function foo($attribute, $params) - * ~~~ - */ - public $method; - /** - * @var array additional parameters that are passed to the validation method - */ - public $params; - /** - * @var string|\Closure an anonymous function or the name of a model class method that returns the client validation code. - * The signature of the method should be like the following: - * - * ~~~ - * function foo($attribute, $params) - * { - * return "javascript"; - * } - * ~~~ - * - * where `$attribute` refers to the attribute name to be validated. - * - * Please refer to [[clientValidateAttribute()]] for details on how to return client validation code. - */ - public $clientValidate; - - /** - * @inheritdoc - */ - public function validateAttribute($object, $attribute) - { - $method = $this->method; - if (is_string($method)) { - $method = [$object, $method]; - } - call_user_func($method, $attribute, $this->params); - } - - /** - * @inheritdoc - */ - public function clientValidateAttribute($object, $attribute, $view) - { - if ($this->clientValidate !== null) { - $method = $this->clientValidate; - if (is_string($method)) { - $method = [$object, $method]; - } - return call_user_func($method, $attribute, $this->params); - } else { - return null; - } - } -} diff --git a/framework/yii/validators/NumberValidator.php b/framework/yii/validators/NumberValidator.php deleted file mode 100644 index 1bb2360..0000000 --- a/framework/yii/validators/NumberValidator.php +++ /dev/null @@ -1,153 +0,0 @@ - - * @since 2.0 - */ -class NumberValidator extends Validator -{ - /** - * @var boolean whether the attribute value can only be an integer. Defaults to false. - */ - public $integerOnly = false; - /** - * @var integer|float upper limit of the number. Defaults to null, meaning no upper limit. - */ - public $max; - /** - * @var integer|float lower limit of the number. Defaults to null, meaning no lower limit. - */ - public $min; - /** - * @var string user-defined error message used when the value is bigger than [[max]]. - */ - public $tooBig; - /** - * @var string user-defined error message used when the value is smaller than [[min]]. - */ - public $tooSmall; - /** - * @var string the regular expression for matching integers. - */ - public $integerPattern = '/^\s*[+-]?\d+\s*$/'; - /** - * @var string the regular expression for matching numbers. It defaults to a pattern - * that matches floating numbers with optional exponential part (e.g. -1.23e-10). - */ - public $numberPattern = '/^\s*[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\s*$/'; - - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->message === null) { - $this->message = $this->integerOnly ? Yii::t('yii', '{attribute} must be an integer.') - : Yii::t('yii', '{attribute} must be a number.'); - } - if ($this->min !== null && $this->tooSmall === null) { - $this->tooSmall = Yii::t('yii', '{attribute} must be no less than {min}.'); - } - if ($this->max !== null && $this->tooBig === null) { - $this->tooBig = Yii::t('yii', '{attribute} must be no greater than {max}.'); - } - } - - /** - * @inheritdoc - */ - public function validateAttribute($object, $attribute) - { - $value = $object->$attribute; - if (is_array($value)) { - $this->addError($object, $attribute, Yii::t('yii', '{attribute} is invalid.')); - return; - } - $pattern = $this->integerOnly ? $this->integerPattern : $this->numberPattern; - if (!preg_match($pattern, "$value")) { - $this->addError($object, $attribute, $this->message); - } - if ($this->min !== null && $value < $this->min) { - $this->addError($object, $attribute, $this->tooSmall, ['min' => $this->min]); - } - if ($this->max !== null && $value > $this->max) { - $this->addError($object, $attribute, $this->tooBig, ['max' => $this->max]); - } - } - - /** - * @inheritdoc - */ - protected function validateValue($value) - { - if (is_array($value)) { - return [Yii::t('yii', '{attribute} is invalid.'), []]; - } - $pattern = $this->integerOnly ? $this->integerPattern : $this->numberPattern; - if (!preg_match($pattern, "$value")) { - return [$this->message, []]; - } elseif ($this->min !== null && $value < $this->min) { - return [$this->tooSmall, ['min' => $this->min]]; - } elseif ($this->max !== null && $value > $this->max) { - return [$this->tooBig, ['max' => $this->max]]; - } else { - return null; - } - } - - /** - * @inheritdoc - */ - public function clientValidateAttribute($object, $attribute, $view) - { - $label = $object->getAttributeLabel($attribute); - - $options = [ - 'pattern' => new JsExpression($this->integerOnly ? $this->integerPattern : $this->numberPattern), - 'message' => strtr($this->message, [ - '{attribute}' => $label, - ]), - ]; - - if ($this->min !== null) { - $options['min'] = $this->min; - $options['tooSmall'] = strtr($this->tooSmall, [ - '{attribute}' => $label, - '{min}' => $this->min, - ]); - } - if ($this->max !== null) { - $options['max'] = $this->max; - $options['tooBig'] = strtr($this->tooBig, [ - '{attribute}' => $label, - '{max}' => $this->max, - ]); - } - if ($this->skipOnEmpty) { - $options['skipOnEmpty'] = 1; - } - - ValidationAsset::register($view); - return 'yii.validation.number(value, messages, ' . Json::encode($options) . ');'; - } -} diff --git a/framework/yii/validators/PunycodeAsset.php b/framework/yii/validators/PunycodeAsset.php deleted file mode 100644 index c0c1e2b..0000000 --- a/framework/yii/validators/PunycodeAsset.php +++ /dev/null @@ -1,23 +0,0 @@ - - * @since 2.0 - */ -class PunycodeAsset extends AssetBundle -{ - public $sourcePath = '@yii/assets'; - public $js = [ - 'punycode/punycode.js', - ]; -} diff --git a/framework/yii/validators/RangeValidator.php b/framework/yii/validators/RangeValidator.php deleted file mode 100644 index a4da139..0000000 --- a/framework/yii/validators/RangeValidator.php +++ /dev/null @@ -1,87 +0,0 @@ - - * @since 2.0 - */ -class RangeValidator extends Validator -{ - /** - * @var array list of valid values that the attribute value should be among - */ - public $range; - /** - * @var boolean whether the comparison is strict (both type and value must be the same) - */ - public $strict = false; - /** - * @var boolean whether to invert the validation logic. Defaults to false. If set to true, - * the attribute value should NOT be among the list of values defined via [[range]]. - **/ - public $not = false; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if (!is_array($this->range)) { - throw new InvalidConfigException('The "range" property must be set.'); - } - if ($this->message === null) { - $this->message = Yii::t('yii', '{attribute} is invalid.'); - } - } - - /** - * @inheritdoc - */ - protected function validateValue($value) - { - $valid = !$this->not && in_array($value, $this->range, $this->strict) - || $this->not && !in_array($value, $this->range, $this->strict); - return $valid ? null : [$this->message, []]; - } - - /** - * @inheritdoc - */ - public function clientValidateAttribute($object, $attribute, $view) - { - $range = []; - foreach ($this->range as $value) { - $range[] = (string)$value; - } - $options = [ - 'range' => $range, - 'not' => $this->not, - 'message' => strtr($this->message, [ - '{attribute}' => $object->getAttributeLabel($attribute), - ]), - ]; - if ($this->skipOnEmpty) { - $options['skipOnEmpty'] = 1; - } - - ValidationAsset::register($view); - return 'yii.validation.range(value, messages, ' . json_encode($options) . ');'; - } -} diff --git a/framework/yii/validators/RegularExpressionValidator.php b/framework/yii/validators/RegularExpressionValidator.php deleted file mode 100644 index 28e9bdc..0000000 --- a/framework/yii/validators/RegularExpressionValidator.php +++ /dev/null @@ -1,94 +0,0 @@ - - * @since 2.0 - */ -class RegularExpressionValidator extends Validator -{ - /** - * @var string the regular expression to be matched with - */ - public $pattern; - /** - * @var boolean whether to invert the validation logic. Defaults to false. If set to true, - * the regular expression defined via [[pattern]] should NOT match the attribute value. - **/ - public $not = false; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->pattern === null) { - throw new InvalidConfigException('The "pattern" property must be set.'); - } - if ($this->message === null) { - $this->message = Yii::t('yii', '{attribute} is invalid.'); - } - } - - /** - * @inheritdoc - */ - protected function validateValue($value) - { - $valid = !is_array($value) && - (!$this->not && preg_match($this->pattern, $value) - || $this->not && !preg_match($this->pattern, $value)); - return $valid ? null : [$this->message, []]; - } - - /** - * @inheritdoc - */ - public function clientValidateAttribute($object, $attribute, $view) - { - $pattern = $this->pattern; - $pattern = preg_replace('/\\\\x\{?([0-9a-fA-F]+)\}?/', '\u$1', $pattern); - $deliminator = substr($pattern, 0, 1); - $pos = strrpos($pattern, $deliminator, 1); - $flag = substr($pattern, $pos + 1); - if ($deliminator !== '/') { - $pattern = '/' . str_replace('/', '\\/', substr($pattern, 1, $pos - 1)) . '/'; - } else { - $pattern = substr($pattern, 0, $pos + 1); - } - if (!empty($flag)) { - $pattern .= preg_replace('/[^igm]/', '', $flag); - } - - $options = [ - 'pattern' => new JsExpression($pattern), - 'not' => $this->not, - 'message' => strtr($this->message, [ - '{attribute}' => $object->getAttributeLabel($attribute), - ]), - ]; - if ($this->skipOnEmpty) { - $options['skipOnEmpty'] = 1; - } - - ValidationAsset::register($view); - return 'yii.validation.regularExpression(value, messages, ' . Json::encode($options) . ');'; - } -} diff --git a/framework/yii/validators/RequiredValidator.php b/framework/yii/validators/RequiredValidator.php deleted file mode 100644 index f291f39..0000000 --- a/framework/yii/validators/RequiredValidator.php +++ /dev/null @@ -1,111 +0,0 @@ - - * @since 2.0 - */ -class RequiredValidator extends Validator -{ - /** - * @var boolean whether to skip this validator if the value being validated is empty. - */ - public $skipOnEmpty = false; - /** - * @var mixed the desired value that the attribute must have. - * If this is null, the validator will validate that the specified attribute is not empty. - * If this is set as a value that is not null, the validator will validate that - * the attribute has a value that is the same as this property value. - * Defaults to null. - * @see strict - */ - public $requiredValue; - /** - * @var boolean whether the comparison between the attribute value and [[requiredValue]] is strict. - * When this is true, both the values and types must match. - * Defaults to false, meaning only the values need to match. - * Note that when [[requiredValue]] is null, if this property is true, the validator will check - * if the attribute value is null; If this property is false, the validator will call [[isEmpty]] - * to check if the attribute value is empty. - */ - public $strict = false; - /** - * @var string the user-defined error message. It may contain the following placeholders which - * will be replaced accordingly by the validator: - * - * - `{attribute}`: the label of the attribute being validated - * - `{value}`: the value of the attribute being validated - * - `{requiredValue}`: the value of [[requiredValue]] - */ - public $message; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->message === null) { - $this->message = $this->requiredValue === null ? Yii::t('yii', '{attribute} cannot be blank.') - : Yii::t('yii', '{attribute} must be "{requiredValue}".'); - } - } - - /** - * @inheritdoc - */ - protected function validateValue($value) - { - if ($this->requiredValue === null) { - if ($this->strict && $value !== null || !$this->strict && !$this->isEmpty($value, true)) { - return null; - } - } elseif (!$this->strict && $value == $this->requiredValue || $this->strict && $value === $this->requiredValue) { - return null; - } - if ($this->requiredValue === null) { - return [$this->message, []]; - } else { - return [$this->message, [ - 'requiredValue' => $this->requiredValue, - ]]; - } - } - - /** - * @inheritdoc - */ - public function clientValidateAttribute($object, $attribute, $view) - { - $options = []; - if ($this->requiredValue !== null) { - $options['message'] = strtr($this->message, [ - '{requiredValue}' => $this->requiredValue, - ]); - $options['requiredValue'] = $this->requiredValue; - } else { - $options['message'] = $this->message; - } - if ($this->strict) { - $options['strict'] = 1; - } - - $options['message'] = strtr($options['message'], [ - '{attribute}' => $object->getAttributeLabel($attribute), - ]); - - ValidationAsset::register($view); - return 'yii.validation.required(value, messages, ' . json_encode($options) . ');'; - } -} diff --git a/framework/yii/validators/SafeValidator.php b/framework/yii/validators/SafeValidator.php deleted file mode 100644 index 25da899..0000000 --- a/framework/yii/validators/SafeValidator.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class SafeValidator extends Validator -{ - /** - * @inheritdoc - */ - public function validateAttribute($object, $attribute) - { - } -} diff --git a/framework/yii/validators/StringValidator.php b/framework/yii/validators/StringValidator.php deleted file mode 100644 index 7d15aa7..0000000 --- a/framework/yii/validators/StringValidator.php +++ /dev/null @@ -1,187 +0,0 @@ - - * @since 2.0 - */ -class StringValidator extends Validator -{ - /** - * @var integer|array specifies the length limit of the value to be validated. - * This can be specified in one of the following forms: - * - * - an integer: the exact length that the value should be of; - * - an array of one element: the minimum length that the value should be of. For example, `[8]`. - * This will overwrite [[min]]. - * - an array of two elements: the minimum and maximum lengths that the value should be of. - * For example, `[8, 128]`. This will overwrite both [[min]] and [[max]]. - */ - public $length; - /** - * @var integer maximum length. If not set, it means no maximum length limit. - */ - public $max; - /** - * @var integer minimum length. If not set, it means no minimum length limit. - */ - public $min; - /** - * @var string user-defined error message used when the value is not a string - */ - public $message; - /** - * @var string user-defined error message used when the length of the value is smaller than [[min]]. - */ - public $tooShort; - /** - * @var string user-defined error message used when the length of the value is greater than [[max]]. - */ - public $tooLong; - /** - * @var string user-defined error message used when the length of the value is not equal to [[length]]. - */ - public $notEqual; - /** - * @var string the encoding of the string value to be validated (e.g. 'UTF-8'). - * If this property is not set, [[\yii\base\Application::charset]] will be used. - */ - public $encoding; - - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if (is_array($this->length)) { - if (isset($this->length[0])) { - $this->min = $this->length[0]; - } - if (isset($this->length[1])) { - $this->max = $this->length[1]; - } - $this->length = null; - } - if ($this->encoding === null) { - $this->encoding = Yii::$app->charset; - } - if ($this->message === null) { - $this->message = Yii::t('yii', '{attribute} must be a string.'); - } - if ($this->min !== null && $this->tooShort === null) { - $this->tooShort = Yii::t('yii', '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.'); - } - if ($this->max !== null && $this->tooLong === null) { - $this->tooLong = Yii::t('yii', '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.'); - } - if ($this->length !== null && $this->notEqual === null) { - $this->notEqual = Yii::t('yii', '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.'); - } - } - - /** - * @inheritdoc - */ - public function validateAttribute($object, $attribute) - { - $value = $object->$attribute; - - if (!is_string($value)) { - $this->addError($object, $attribute, $this->message); - return; - } - - $length = mb_strlen($value, $this->encoding); - - if ($this->min !== null && $length < $this->min) { - $this->addError($object, $attribute, $this->tooShort, ['min' => $this->min]); - } - if ($this->max !== null && $length > $this->max) { - $this->addError($object, $attribute, $this->tooLong, ['max' => $this->max]); - } - if ($this->length !== null && $length !== $this->length) { - $this->addError($object, $attribute, $this->notEqual, ['length' => $this->length]); - } - } - - /** - * @inheritdoc - */ - protected function validateValue($value) - { - if (!is_string($value)) { - return [$this->message, []]; - } - - $length = mb_strlen($value, $this->encoding); - - if ($this->min !== null && $length < $this->min) { - return [$this->tooShort, ['min' => $this->min]]; - } - if ($this->max !== null && $length > $this->max) { - return [$this->tooLong, ['max' => $this->max]]; - } - if ($this->length !== null && $length !== $this->length) { - return [$this->notEqual, ['length' => $this->length]]; - } - - return null; - } - - /** - * @inheritdoc - */ - public function clientValidateAttribute($object, $attribute, $view) - { - $label = $object->getAttributeLabel($attribute); - - $options = [ - 'message' => strtr($this->message, [ - '{attribute}' => $label, - ]), - ]; - - if ($this->min !== null) { - $options['min'] = $this->min; - $options['tooShort'] = strtr($this->tooShort, [ - '{attribute}' => $label, - '{min}' => $this->min, - ]); - } - if ($this->max !== null) { - $options['max'] = $this->max; - $options['tooLong'] = strtr($this->tooLong, [ - '{attribute}' => $label, - '{max}' => $this->max, - ]); - } - if ($this->length !== null) { - $options['is'] = $this->length; - $options['notEqual'] = strtr($this->notEqual, [ - '{attribute}' => $label, - '{length}' => $this->length, - ]); - } - if ($this->skipOnEmpty) { - $options['skipOnEmpty'] = 1; - } - - ValidationAsset::register($view); - return 'yii.validation.string(value, messages, ' . json_encode($options) . ');'; - } -} diff --git a/framework/yii/validators/UniqueValidator.php b/framework/yii/validators/UniqueValidator.php deleted file mode 100644 index 51474b0..0000000 --- a/framework/yii/validators/UniqueValidator.php +++ /dev/null @@ -1,123 +0,0 @@ - 'a2'] - * // a1 and a2 need to unique together, and they both will receive error message - * [['a1', 'a2'], 'unique', 'targetAttribute' => ['a1', 'a2']] - * // a1 and a2 need to unique together, only a1 will receive error message - * ['a1', 'unique', 'targetAttribute' => ['a1', 'a2']] - * // a1 needs to be unique by checking the uniqueness of both a2 and a3 (using a1 value) - * ['a1', 'unique', 'targetAttribute' => ['a2', 'a1' => 'a3']] - * ``` - * - * @author Qiang Xue - * @since 2.0 - */ -class UniqueValidator extends Validator -{ - /** - * @var string the name of the ActiveRecord class that should be used to validate the uniqueness - * of the current attribute value. It not set, it will use the ActiveRecord class of the attribute being validated. - * @see targetAttribute - */ - public $targetClass; - /** - * @var string|array the name of the ActiveRecord attribute that should be used to - * validate the uniqueness of the current attribute value. If not set, it will use the name - * of the attribute currently being validated. You may use an array to validate the uniqueness - * of multiple columns at the same time. The array values are the attributes that will be - * used to validate the uniqueness, while the array keys are the attributes whose values are to be validated. - * If the key and the value are the same, you can just specify the value. - */ - public $targetAttribute; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->message === null) { - $this->message = Yii::t('yii', '{attribute} "{value}" has already been taken.'); - } - } - - /** - * @inheritdoc - */ - public function validateAttribute($object, $attribute) - { - /** @var ActiveRecordInterface $targetClass */ - $targetClass = $this->targetClass === null ? get_class($object) : $this->targetClass; - $targetAttribute = $this->targetAttribute === null ? $attribute : $this->targetAttribute; - - if (is_array($targetAttribute)) { - $params = []; - foreach ($targetAttribute as $k => $v) { - $params[$v] = is_integer($k) ? $object->$v : $object->$k; - } - } else { - $params = [$targetAttribute => $object->$attribute]; - } - - foreach ($params as $value) { - if (is_array($value)) { - $this->addError($object, $attribute, Yii::t('yii', '{attribute} is invalid.')); - return; - } - } - - $query = $targetClass::find(); - $query->where($params); - - if (!$object instanceof ActiveRecordInterface || $object->getIsNewRecord()) { - // if current $object isn't in the database yet then it's OK just to call exists() - $exists = $query->exists(); - } else { - // if current $object is in the database already we can't use exists() - /** @var ActiveRecordInterface[] $objects */ - $objects = $query->limit(2)->all(); - $n = count($objects); - if ($n === 1) { - $keys = array_keys($params); - $pks = $targetClass::primaryKey(); - sort($keys); - sort($pks); - if ($keys === $pks) { - // primary key is modified and not unique - $exists = $object->getOldPrimaryKey() != $object->getPrimaryKey(); - } else { - // non-primary key, need to exclude the current record based on PK - $exists = $objects[0]->getPrimaryKey() != $object->getOldPrimaryKey(); - } - } else { - $exists = $n > 1; - } - } - - if ($exists) { - $this->addError($object, $attribute, $this->message); - } - } -} diff --git a/framework/yii/validators/UrlValidator.php b/framework/yii/validators/UrlValidator.php deleted file mode 100644 index 4cb20f6..0000000 --- a/framework/yii/validators/UrlValidator.php +++ /dev/null @@ -1,142 +0,0 @@ - - * @since 2.0 - */ -class UrlValidator extends Validator -{ - /** - * @var string the regular expression used to validate the attribute value. - * The pattern may contain a `{schemes}` token that will be replaced - * by a regular expression which represents the [[validSchemes]]. - */ - public $pattern = '/^{schemes}:\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)/i'; - /** - * @var array list of URI schemes which should be considered valid. By default, http and https - * are considered to be valid schemes. - **/ - public $validSchemes = ['http', 'https']; - /** - * @var string the default URI scheme. If the input doesn't contain the scheme part, the default - * scheme will be prepended to it (thus changing the input). Defaults to null, meaning a URL must - * contain the scheme part. - **/ - public $defaultScheme; - /** - * @var boolean whether validation process should take into account IDN (internationalized - * domain names). Defaults to false meaning that validation of URLs containing IDN will always - * fail. Note that in order to use IDN validation you have to install and enable `intl` PHP - * extension, otherwise an exception would be thrown. - */ - public $enableIDN = false; - - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - if ($this->enableIDN && !function_exists('idn_to_ascii')) { - throw new InvalidConfigException('In order to use IDN validation intl extension must be installed and enabled.'); - } - if ($this->message === null) { - $this->message = Yii::t('yii', '{attribute} is not a valid URL.'); - } - } - - /** - * @inheritdoc - */ - public function validateAttribute($object, $attribute) - { - $value = $object->$attribute; - $result = $this->validateValue($value); - if (!empty($result)) { - $this->addError($object, $attribute, $result[0], $result[1]); - } elseif ($this->defaultScheme !== null && strpos($value, '://') === false) { - $object->$attribute = $this->defaultScheme . '://' . $value; - } - } - - /** - * @inheritdoc - */ - protected function validateValue($value) - { - // make sure the length is limited to avoid DOS attacks - if (is_string($value) && strlen($value) < 2000) { - if ($this->defaultScheme !== null && strpos($value, '://') === false) { - $value = $this->defaultScheme . '://' . $value; - } - - if (strpos($this->pattern, '{schemes}') !== false) { - $pattern = str_replace('{schemes}', '(' . implode('|', $this->validSchemes) . ')', $this->pattern); - } else { - $pattern = $this->pattern; - } - - if ($this->enableIDN) { - $value = preg_replace_callback('/:\/\/([^\/]+)/', function ($matches) { - return '://' . idn_to_ascii($matches[1]); - }, $value); - } - - if (preg_match($pattern, $value)) { - return null; - } - } - return [$this->message, []]; - } - - /** - * @inheritdoc - */ - public function clientValidateAttribute($object, $attribute, $view) - { - if (strpos($this->pattern, '{schemes}') !== false) { - $pattern = str_replace('{schemes}', '(' . implode('|', $this->validSchemes) . ')', $this->pattern); - } else { - $pattern = $this->pattern; - } - - $options = [ - 'pattern' => new JsExpression($pattern), - 'message' => strtr($this->message, [ - '{attribute}' => $object->getAttributeLabel($attribute), - ]), - 'enableIDN' => (boolean)$this->enableIDN, - ]; - if ($this->skipOnEmpty) { - $options['skipOnEmpty'] = 1; - } - if ($this->defaultScheme !== null) { - $options['defaultScheme'] = $this->defaultScheme; - } - - ValidationAsset::register($view); - if ($this->enableIDN) { - PunycodeAsset::register($view); - } - return 'yii.validation.url(value, messages, ' . Json::encode($options) . ');'; - } -} diff --git a/framework/yii/validators/ValidationAsset.php b/framework/yii/validators/ValidationAsset.php deleted file mode 100644 index 14d7ad0..0000000 --- a/framework/yii/validators/ValidationAsset.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @since 2.0 - */ -class ValidationAsset extends AssetBundle -{ - public $sourcePath = '@yii/assets'; - public $js = [ - 'yii.validation.js', - ]; - public $depends = [ - 'yii\web\YiiAsset', - ]; -} diff --git a/framework/yii/validators/Validator.php b/framework/yii/validators/Validator.php deleted file mode 100644 index 4b04b87..0000000 --- a/framework/yii/validators/Validator.php +++ /dev/null @@ -1,312 +0,0 @@ - - * @since 2.0 - */ -class Validator extends Component -{ - /** - * @var array list of built-in validators (name => class or configuration) - */ - public static $builtInValidators = [ - 'boolean' => 'yii\validators\BooleanValidator', - 'captcha' => 'yii\captcha\CaptchaValidator', - 'compare' => 'yii\validators\CompareValidator', - 'date' => 'yii\validators\DateValidator', - 'default' => 'yii\validators\DefaultValueValidator', - 'double' => 'yii\validators\NumberValidator', - 'email' => 'yii\validators\EmailValidator', - 'exist' => 'yii\validators\ExistValidator', - 'file' => 'yii\validators\FileValidator', - 'filter' => 'yii\validators\FilterValidator', - 'image' => 'yii\validators\ImageValidator', - 'in' => 'yii\validators\RangeValidator', - 'integer' => [ - 'class' => 'yii\validators\NumberValidator', - 'integerOnly' => true, - ], - 'match' => 'yii\validators\RegularExpressionValidator', - 'number' => 'yii\validators\NumberValidator', - 'required' => 'yii\validators\RequiredValidator', - 'safe' => 'yii\validators\SafeValidator', - 'string' => 'yii\validators\StringValidator', - 'trim' => [ - 'class' => 'yii\validators\FilterValidator', - 'filter' => 'trim', - ], - 'unique' => 'yii\validators\UniqueValidator', - 'url' => 'yii\validators\UrlValidator', - ]; - - /** - * @var array|string attributes to be validated by this validator. For multiple attributes, - * please specify them as an array; for single attribute, you may use either a string or an array. - */ - public $attributes = []; - /** - * @var string the user-defined error message. It may contain the following placeholders which - * will be replaced accordingly by the validator: - * - * - `{attribute}`: the label of the attribute being validated - * - `{value}`: the value of the attribute being validated - */ - public $message; - /** - * @var array|string scenarios that the validator can be applied to. For multiple scenarios, - * please specify them as an array; for single scenario, you may use either a string or an array. - */ - public $on = []; - /** - * @var array|string scenarios that the validator should not be applied to. For multiple scenarios, - * please specify them as an array; for single scenario, you may use either a string or an array. - */ - public $except = []; - /** - * @var boolean whether this validation rule should be skipped if the attribute being validated - * already has some validation error according to some previous rules. Defaults to true. - */ - public $skipOnError = true; - /** - * @var boolean whether this validation rule should be skipped if the attribute value - * is null or an empty string. - */ - public $skipOnEmpty = true; - /** - * @var boolean whether to enable client-side validation for this validator. - * The actual client-side validation is done via the JavaScript code returned - * by [[clientValidateAttribute()]]. If that method returns null, even if this property - * is true, no client-side validation will be done by this validator. - */ - public $enableClientValidation = true; - - - /** - * Creates a validator object. - * @param string $type the validator type. This can be a method name, - * a built-in validator name, a class name, or a path alias of the validator class. - * @param \yii\base\Model $object the data object to be validated. - * @param array|string $attributes list of attributes to be validated. This can be either an array of - * the attribute names or a string of comma-separated attribute names. - * @param array $params initial values to be applied to the validator properties - * @return Validator the validator - */ - public static function createValidator($type, $object, $attributes, $params = []) - { - $params['attributes'] = $attributes; - - if (method_exists($object, $type)) { - // method-based validator - $params['class'] = __NAMESPACE__ . '\InlineValidator'; - $params['method'] = $type; - } else { - if (isset(static::$builtInValidators[$type])) { - $type = static::$builtInValidators[$type]; - } - if (is_array($type)) { - foreach ($type as $name => $value) { - $params[$name] = $value; - } - } else { - $params['class'] = $type; - } - } - - return Yii::createObject($params); - } - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - $this->attributes = (array)$this->attributes; - $this->on = (array)$this->on; - $this->except = (array)$this->except; - } - - /** - * Validates the specified object. - * @param \yii\base\Model $object the data object being validated - * @param array|null $attributes the list of attributes to be validated. - * Note that if an attribute is not associated with the validator, - * it will be ignored. - * If this parameter is null, every attribute listed in [[attributes]] will be validated. - */ - public function validateAttributes($object, $attributes = null) - { - if (is_array($attributes)) { - $attributes = array_intersect($this->attributes, $attributes); - } else { - $attributes = $this->attributes; - } - foreach ($attributes as $attribute) { - $skip = $this->skipOnError && $object->hasErrors($attribute) - || $this->skipOnEmpty && $this->isEmpty($object->$attribute); - if (!$skip) { - $this->validateAttribute($object, $attribute); - } - } - } - - /** - * Validates a single attribute. - * Child classes must implement this method to provide the actual validation logic. - * @param \yii\base\Model $object the data object to be validated - * @param string $attribute the name of the attribute to be validated. - */ - public function validateAttribute($object, $attribute) - { - $result = $this->validateValue($object->$attribute); - if (!empty($result)) { - $this->addError($object, $attribute, $result[0], $result[1]); - } - } - - /** - * Validates a given value. - * You may use this method to validate a value out of the context of a data model. - * @param mixed $value the data value to be validated. - * @param string $error the error message to be returned, if the validation fails. - * @return boolean whether the data is valid. - */ - public function validate($value, &$error = null) - { - $result = $this->validateValue($value); - if (empty($result)) { - return true; - } else { - list($message, $params) = $result; - $params['attribute'] = Yii::t('yii', 'the input value'); - $params['value'] = is_array($value) ? 'array()' : $value; - $error = Yii::$app->getI18n()->format($message, $params, Yii::$app->language); - return false; - } - } - - /** - * Validates a value. - * A validator class can implement this method to support data validation out of the context of a data model. - * @param mixed $value the data value to be validated. - * @return array|null the error message and the parameters to be inserted into the error message. - * Null should be returned if the data is valid. - * @throws NotSupportedException if the validator does not supporting data validation without a model - */ - protected function validateValue($value) - { - throw new NotSupportedException(get_class($this) . ' does not support validateValue().'); - } - - /** - * Returns the JavaScript needed for performing client-side validation. - * - * You may override this method to return the JavaScript validation code if - * the validator can support client-side validation. - * - * The following JavaScript variables are predefined and can be used in the validation code: - * - * - `attribute`: the name of the attribute being validated. - * - `value`: the value being validated. - * - `messages`: an array used to hold the validation error messages for the attribute. - * - * @param \yii\base\Model $object the data object being validated - * @param string $attribute the name of the attribute to be validated. - * @param \yii\web\View $view the view object that is going to be used to render views or view files - * containing a model form with this validator applied. - * @return string the client-side validation script. Null if the validator does not support - * client-side validation. - * @see \yii\web\ActiveForm::enableClientValidation - */ - public function clientValidateAttribute($object, $attribute, $view) - { - return null; - } - - /** - * Returns a value indicating whether the validator is active for the given scenario and attribute. - * - * A validator is active if - * - * - the validator's `on` property is empty, or - * - the validator's `on` property contains the specified scenario - * - * @param string $scenario scenario name - * @return boolean whether the validator applies to the specified scenario. - */ - public function isActive($scenario) - { - return !in_array($scenario, $this->except, true) && (empty($this->on) || in_array($scenario, $this->on, true)); - } - - /** - * Adds an error about the specified attribute to the model object. - * This is a helper method that performs message selection and internationalization. - * @param \yii\base\Model $object the data object being validated - * @param string $attribute the attribute being validated - * @param string $message the error message - * @param array $params values for the placeholders in the error message - */ - public function addError($object, $attribute, $message, $params = []) - { - $value = $object->$attribute; - $params['attribute'] = $object->getAttributeLabel($attribute); - $params['value'] = is_array($value) ? 'array()' : $value; - $object->addError($attribute, Yii::$app->getI18n()->format($message, $params, Yii::$app->language)); - } - - /** - * Checks if the given value is empty. - * A value is considered empty if it is null, an empty array, or the trimmed result is an empty string. - * Note that this method is different from PHP empty(). It will return false when the value is 0. - * @param mixed $value the value to be checked - * @param boolean $trim whether to perform trimming before checking if the string is empty. Defaults to false. - * @return boolean whether the value is empty - */ - public function isEmpty($value, $trim = false) - { - return $value === null || $value === [] || $value === '' - || $trim && is_scalar($value) && trim($value) === ''; - } -} diff --git a/framework/yii/views/errorHandler/callStackItem.php b/framework/yii/views/errorHandler/callStackItem.php deleted file mode 100644 index 566e1d3..0000000 --- a/framework/yii/views/errorHandler/callStackItem.php +++ /dev/null @@ -1,45 +0,0 @@ - -
      • -
        -
        - . - htmlEncode($file); ?> - - - - addTypeLinks($class) . '::'; ?>addTypeLinks($method . '()') ?> - - - - -
        -
        - -
        -
        -
        -
        - -
        htmlEncode($lines[$i]);
        -					}
        -				?>
        -
        -
        - -
      • diff --git a/framework/yii/views/errorHandler/error.php b/framework/yii/views/errorHandler/error.php deleted file mode 100644 index 066d7e4..0000000 --- a/framework/yii/views/errorHandler/error.php +++ /dev/null @@ -1,86 +0,0 @@ -statusCode; -} else { - $code = $exception->getCode(); -} -if ($exception instanceof \yii\base\Exception) { - $name = $exception->getName(); -} else { - $name = 'Error'; -} -if ($code) { - $name .= " (#$code)"; -} - -if ($exception instanceof \yii\base\UserException) { - $message = $exception->getMessage(); -} else { - $message = 'An internal server error occurred.'; -} -?> -beginPage(); ?> - - - - - <?= $handler->htmlEncode($name) ?> - - - - - -

        htmlEncode($name) ?>

        -

        htmlEncode($message)) ?>

        -

        - 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. -

        -
        - -
        - endBody(); // to allow injecting code into body (mostly by Yii Debug Toolbar) ?> - - -endPage(); ?> diff --git a/framework/yii/views/errorHandler/exception.php b/framework/yii/views/errorHandler/exception.php deleted file mode 100644 index 1e37401..0000000 --- a/framework/yii/views/errorHandler/exception.php +++ /dev/null @@ -1,483 +0,0 @@ - -beginPage(); ?> - - - - - - - <?php - if ($exception instanceof \yii\web\HttpException) { - echo (int) $exception->statusCode . ' ' . $handler->htmlEncode($exception->getName()); - } elseif ($exception instanceof \yii\base\Exception) { - echo $handler->htmlEncode($exception->getName() . ' – ' . get_class($exception)); - } else { - echo $handler->htmlEncode(get_class($exception)); - } - ?> - - - - - -
        - - Error -

        - htmlEncode($exception->getName()) ?> - – addTypeLinks(get_class($exception)) ?> -

        - - Exception -

        ' . $handler->createHttpStatusLink($exception->statusCode, $handler->htmlEncode($exception->getName())) . ''; - echo ' – ' . $handler->addTypeLinks(get_class($exception)); - } elseif ($exception instanceof \yii\base\Exception) { - echo '' . $handler->htmlEncode($exception->getName()) . ''; - echo ' – ' . $handler->addTypeLinks(get_class($exception)); - } else { - echo '' . $handler->htmlEncode(get_class($exception)) . ''; - } - ?>

        - -

        htmlEncode($exception->getMessage())) ?>

        - -
        errorInfo, true) ?>
        - - renderPreviousExceptions($exception) ?> -
        - -
        -
          - renderCallStackItem($exception->getFile(), $exception->getLine(), null, null, 1) ?> - getTrace(), $length = count($trace); $i < $length; ++$i): ?> - renderCallStackItem(@$trace[$i]['file'] ?: null, @$trace[$i]['line'] ?: null, - @$trace[$i]['class'] ?: null, @$trace[$i]['function'] ?: null, $i + 2) ?> - -
        -
        - -
        -
        - renderRequest() ?> -
        -
        - - - - - - - - - endBody(); // to allow injecting code into body (mostly by Yii Debug Toolbar) ?> - - - -endPage(); ?> diff --git a/framework/yii/views/errorHandler/previousException.php b/framework/yii/views/errorHandler/previousException.php deleted file mode 100644 index 766c0a7..0000000 --- a/framework/yii/views/errorHandler/previousException.php +++ /dev/null @@ -1,21 +0,0 @@ - - diff --git a/framework/yii/views/messageConfig.php b/framework/yii/views/messageConfig.php deleted file mode 100644 index 9babb0c..0000000 --- a/framework/yii/views/messageConfig.php +++ /dev/null @@ -1,45 +0,0 @@ - __DIR__, - // string, required, root directory containing message translations. - 'messagePath' => __DIR__ . DIRECTORY_SEPARATOR . 'messages', - // array, required, list of language codes that the extracted messages - // should be translated to. For example, ['zh_cn', 'de']. - 'languages' => ['de'], - // string, the name of the function for translating messages. - // Defaults to 'Yii::t'. This is used as a mark to find the messages to be - // translated. You may use a string for single function name or an array for - // multiple function names. - 'translator' => 'Yii::t', - // boolean, whether to sort messages by keys when merging new messages - // with the existing ones. Defaults to false, which means the new (untranslated) - // messages will be separated from the old (translated) ones. - 'sort' => false, - // boolean, whether the message file should be overwritten with the merged messages - 'overwrite' => true, - // boolean, whether to remove messages that no longer appear in the source code. - // Defaults to false, which means each of these messages will be enclosed with a pair of '@@' marks. - 'removeUnused' => false, - // array, list of patterns that specify which files/directories should be processed. - // If empty or not set, all files/directories will be processed. - // A path matches a pattern if it contains the pattern string at its end. For example, - // '/a/b' will match all files and directories ending with '/a/b'; - // and the '.svn' will match all files and directories whose name ends with '.svn'. - // Note, the '/' characters in a pattern matches both '/' and '\'. - // If a file/directory matches both a pattern in "only" and "except", it will NOT be processed. - 'only' => ['.php'], - // array, list of patterns that specify which files/directories should NOT be processed. - // If empty or not set, all files/directories will be processed. - // Please refer to "only" for details about the patterns. - 'except' => [ - '.svn', - '.git', - '.gitignore', - '.gitkeep', - '.hgignore', - '.hgkeep', - '/messages', - ], -]; diff --git a/framework/yii/views/migration.php b/framework/yii/views/migration.php deleted file mode 100644 index f6add4d..0000000 --- a/framework/yii/views/migration.php +++ /dev/null @@ -1,25 +0,0 @@ - - -use yii\db\Schema; - -class extends \yii\db\Migration -{ - public function up() - { - - } - - public function down() - { - echo " cannot be reverted.\n"; - return false; - } -} diff --git a/framework/yii/web/AccessControl.php b/framework/yii/web/AccessControl.php deleted file mode 100644 index e755e80..0000000 --- a/framework/yii/web/AccessControl.php +++ /dev/null @@ -1,144 +0,0 @@ - [ - * 'class' => \yii\web\AccessControl::className(), - * 'only' => ['create', 'update'], - * 'rules' => [ - * // deny all POST requests - * [ - * 'allow' => false, - * 'verbs' => ['POST'] - * ], - * // allow authenticated users - * [ - * 'allow' => true, - * 'roles' => ['@'], - * ], - * // everything else is denied - * ], - * ], - * ]; - * } - * ~~~ - * - * @author Qiang Xue - * @since 2.0 - */ -class AccessControl extends ActionFilter -{ - /** - * @var callback a callback that will be called if the access should be denied - * to the current user. If not set, [[denyAccess()]] will be called. - * - * The signature of the callback should be as follows: - * - * ~~~ - * function ($rule, $action) - * ~~~ - * - * where `$rule` is this rule, and `$action` is the current [[Action|action]] object. - */ - public $denyCallback; - /** - * @var array the default configuration of access rules. Individual rule configurations - * specified via [[rules]] will take precedence when the same property of the rule is configured. - */ - public $ruleConfig = ['class' => 'yii\web\AccessRule']; - /** - * @var array a list of access rule objects or configuration arrays for creating the rule objects. - * If a rule is specified via a configuration array, it will be merged with [[ruleConfig]] first - * before it is used for creating the rule object. - * @see ruleConfig - */ - public $rules = []; - - /** - * Initializes the [[rules]] array by instantiating rule objects from configurations. - */ - public function init() - { - parent::init(); - foreach ($this->rules as $i => $rule) { - if (is_array($rule)) { - $this->rules[$i] = Yii::createObject(array_merge($this->ruleConfig, $rule)); - } - } - } - - /** - * This method is invoked right before an action is to be executed (after all possible filters.) - * You may override this method to do last-minute preparation for the action. - * @param Action $action the action to be executed. - * @return boolean whether the action should continue to be executed. - */ - public function beforeAction($action) - { - $user = Yii::$app->getUser(); - $request = Yii::$app->getRequest(); - /** @var AccessRule $rule */ - foreach ($this->rules as $rule) { - if ($allow = $rule->allows($action, $user, $request)) { - return true; - } elseif ($allow === false) { - if (isset($rule->denyCallback)) { - call_user_func($rule->denyCallback, $rule); - } elseif (isset($this->denyCallback)) { - call_user_func($this->denyCallback, $rule); - } else { - $this->denyAccess($user); - } - return false; - } - } - if (isset($this->denyCallback)) { - call_user_func($this->denyCallback, $rule); - } - else { - $this->denyAccess($user); - } - return false; - } - - /** - * Denies the access of the user. - * The default implementation will redirect the user to the login page if he is a guest; - * if the user is already logged, a 403 HTTP exception will be thrown. - * @param User $user the current user - * @throws AccessDeniedHttpException if the user is already logged in. - */ - protected function denyAccess($user) - { - if ($user->getIsGuest()) { - $user->loginRequired(); - } else { - throw new AccessDeniedHttpException(Yii::t('yii', 'You are not allowed to perform this action.')); - } - } -} diff --git a/framework/yii/web/AccessDeniedHttpException.php b/framework/yii/web/AccessDeniedHttpException.php deleted file mode 100644 index d83700b..0000000 --- a/framework/yii/web/AccessDeniedHttpException.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @since 2.0 - */ -class AccessDeniedHttpException extends HttpException -{ - /** - * Constructor. - * @param string $message error message - * @param integer $code error code - * @param \Exception $previous The previous exception used for the exception chaining. - */ - public function __construct($message = null, $code = 0, \Exception $previous = null) - { - parent::__construct(403, $message, $code, $previous); - } -} diff --git a/framework/yii/web/AccessRule.php b/framework/yii/web/AccessRule.php deleted file mode 100644 index 7aeaac1..0000000 --- a/framework/yii/web/AccessRule.php +++ /dev/null @@ -1,186 +0,0 @@ - - * @since 2.0 - */ -class AccessRule extends Component -{ - /** - * @var boolean whether this is an 'allow' rule or 'deny' rule. - */ - public $allow; - /** - * @var array list of action IDs that this rule applies to. The comparison is case-sensitive. - * If not set or empty, it means this rule applies to all actions. - */ - public $actions; - /** - * @var array list of controller IDs that this rule applies to. The comparison is case-sensitive. - * If not set or empty, it means this rule applies to all controllers. - */ - public $controllers; - /** - * @var array list of roles that this rule applies to. Two special roles are recognized, and - * they are checked via [[User::isGuest]]: - * - * - `?`: matches a guest user (not authenticated yet) - * - `@`: matches an authenticated user - * - * Using additional role names requires RBAC (Role-Based Access Control), and - * [[User::checkAccess()]] will be called. - * - * If this property is not set or empty, it means this rule applies to all roles. - */ - public $roles; - /** - * @var array list of user IP addresses that this rule applies to. An IP address - * can contain the wildcard `*` at the end so that it matches IP addresses with the same prefix. - * For example, '192.168.*' matches all IP addresses in the segment '192.168.'. - * If not set or empty, it means this rule applies to all IP addresses. - * @see Request::userIP - */ - public $ips; - /** - * @var array list of request methods (e.g. `GET`, `POST`) that this rule applies to. - * The request methods must be specified in uppercase. - * If not set or empty, it means this rule applies to all request methods. - * @see Request::requestMethod - */ - public $verbs; - /** - * @var callback a callback that will be called to determine if the rule should be applied. - * The signature of the callback should be as follows: - * - * ~~~ - * function ($rule, $action) - * ~~~ - * - * where `$rule` is this rule, and `$action` is the current [[Action|action]] object. - * The callback should return a boolean value indicating whether this rule should be applied. - */ - public $matchCallback; - /** - * @var callback a callback that will be called if this rule determines the access to - * the current action should be denied. If not set, the behavior will be determined by - * [[AccessControl]]. - * - * The signature of the callback should be as follows: - * - * ~~~ - * function ($rule, $action) - * ~~~ - * - * where `$rule` is this rule, and `$action` is the current [[Action|action]] object. - */ - public $denyCallback; - - - /** - * Checks whether the Web user is allowed to perform the specified action. - * @param Action $action the action to be performed - * @param User $user the user object - * @param Request $request - * @return boolean|null true if the user is allowed, false if the user is denied, null if the rule does not apply to the user - */ - public function allows($action, $user, $request) - { - if ($this->matchAction($action) - && $this->matchRole($user) - && $this->matchIP($request->getUserIP()) - && $this->matchVerb($request->getMethod()) - && $this->matchController($action->controller) - && $this->matchCustom($action) - ) { - return $this->allow ? true : false; - } else { - return null; - } - } - - /** - * @param Action $action the action - * @return boolean whether the rule applies to the action - */ - protected function matchAction($action) - { - return empty($this->actions) || in_array($action->id, $this->actions, true); - } - - /** - * @param Controller $controller the controller - * @return boolean whether the rule applies to the controller - */ - protected function matchController($controller) - { - return empty($this->controllers) || in_array($controller->uniqueId, $this->controllers, true); - } - - /** - * @param User $user the user object - * @return boolean whether the rule applies to the role - */ - protected function matchRole($user) - { - if (empty($this->roles)) { - return true; - } - foreach ($this->roles as $role) { - if ($role === '?' && $user->getIsGuest()) { - return true; - } elseif ($role === '@' && !$user->getIsGuest()) { - return true; - } elseif ($user->checkAccess($role)) { - return true; - } - } - return false; - } - - /** - * @param string $ip the IP address - * @return boolean whether the rule applies to the IP address - */ - protected function matchIP($ip) - { - if (empty($this->ips)) { - return true; - } - foreach ($this->ips as $rule) { - if ($rule === '*' || $rule === $ip || (($pos = strpos($rule, '*')) !== false && !strncmp($ip, $rule, $pos))) { - return true; - } - } - return false; - } - - /** - * @param string $verb the request method - * @return boolean whether the rule applies to the request - */ - protected function matchVerb($verb) - { - return empty($this->verbs) || in_array($verb, $this->verbs, true); - } - - /** - * @param Action $action the action to be performed - * @return boolean whether the rule should be applied - */ - protected function matchCustom($action) - { - return empty($this->matchCallback) || call_user_func($this->matchCallback, $this, $action); - } -} diff --git a/framework/yii/web/Application.php b/framework/yii/web/Application.php deleted file mode 100644 index 17c1411..0000000 --- a/framework/yii/web/Application.php +++ /dev/null @@ -1,178 +0,0 @@ - - * @since 2.0 - */ -class Application extends \yii\base\Application -{ - /** - * @var string the default route of this application. Defaults to 'site'. - */ - public $defaultRoute = 'site'; - /** - * @var array the configuration specifying a controller action which should handle - * all user requests. This is mainly used when the application is in maintenance mode - * and needs to handle all incoming requests via a single action. - * The configuration is an array whose first element specifies the route of the action. - * The rest of the array elements (key-value pairs) specify the parameters to be bound - * to the action. For example, - * - * ~~~ - * [ - * 'offline/notice', - * 'param1' => 'value1', - * 'param2' => 'value2', - * ] - * ~~~ - * - * Defaults to null, meaning catch-all is not used. - */ - public $catchAll; - /** - * @var Controller the currently active controller instance - */ - public $controller; - - - /** - * Handles the specified request. - * @param Request $request the request to be handled - * @return Response the resulting response - * @throws NotFoundHttpException if the requested route is invalid - */ - public function handleRequest($request) - { - Yii::setAlias('@webroot', dirname($request->getScriptFile())); - Yii::setAlias('@web', $request->getBaseUrl()); - - if (empty($this->catchAll)) { - list ($route, $params) = $request->resolve(); - } else { - $route = $this->catchAll[0]; - $params = array_splice($this->catchAll, 1); - } - try { - Yii::trace("Route requested: '$route'", __METHOD__); - $this->requestedRoute = $route; - $result = $this->runAction($route, $params); - if ($result instanceof Response) { - return $result; - } else { - $response = $this->getResponse(); - if ($result !== null) { - $response->data = $result; - } - return $response; - } - } catch (InvalidRouteException $e) { - throw new NotFoundHttpException($e->getMessage(), $e->getCode(), $e); - } - } - - private $_homeUrl; - - /** - * @return string the homepage URL - */ - public function getHomeUrl() - { - if ($this->_homeUrl === null) { - if ($this->getUrlManager()->showScriptName) { - return $this->getRequest()->getScriptUrl(); - } else { - return $this->getRequest()->getBaseUrl() . '/'; - } - } else { - return $this->_homeUrl; - } - } - - /** - * @param string $value the homepage URL - */ - public function setHomeUrl($value) - { - $this->_homeUrl = $value; - } - - /** - * Returns the request component. - * @return Request the request component - */ - public function getRequest() - { - return $this->getComponent('request'); - } - - /** - * Returns the response component. - * @return Response the response component - */ - public function getResponse() - { - return $this->getComponent('response'); - } - - /** - * Returns the session component. - * @return Session the session component - */ - public function getSession() - { - return $this->getComponent('session'); - } - - /** - * Returns the user component. - * @return User the user component - */ - public function getUser() - { - return $this->getComponent('user'); - } - - /** - * Returns the asset manager. - * @return AssetManager the asset manager component - */ - public function getAssetManager() - { - return $this->getComponent('assetManager'); - } - - /** - * Registers the core application components. - * @see setComponents - */ - public function registerCoreComponents() - { - parent::registerCoreComponents(); - $this->setComponents([ - 'request' => ['class' => 'yii\web\Request'], - 'response' => ['class' => 'yii\web\Response'], - 'session' => ['class' => 'yii\web\Session'], - 'user' => ['class' => 'yii\web\User'], - 'assetManager' => ['class' => 'yii\web\AssetManager'], - ]); - } -} diff --git a/framework/yii/web/AssetBundle.php b/framework/yii/web/AssetBundle.php deleted file mode 100644 index da34848..0000000 --- a/framework/yii/web/AssetBundle.php +++ /dev/null @@ -1,194 +0,0 @@ - - * @since 2.0 - */ -class AssetBundle extends Object -{ - /** - * @var string the root directory of the source asset files. A source asset file - * is a file that is part of your source code repository of your Web application. - * - * You must set this property if the directory containing the source asset files - * is not Web accessible (this is usually the case for extensions). - * - * By setting this property, the asset manager will publish the source asset files - * to a Web-accessible directory [[basePath]]. - * - * You can use either a directory or an alias of the directory. - */ - public $sourcePath; - /** - * @var string the Web-accessible directory that contains the asset files in this bundle. - * - * If [[sourcePath]] is set, this property will be *overwritten* by [[AssetManager]] - * when it publishes the asset files from [[sourcePath]]. - * - * If the bundle contains any assets that are specified in terms of relative file path, - * then this property must be set either manually or automatically (by [[AssetManager]] via - * asset publishing). - * - * You can use either a directory or an alias of the directory. - */ - public $basePath; - /** - * @var string the base URL that will be prefixed to the asset files for them to - * be accessed via Web server. - * - * If [[sourcePath]] is set, this property will be *overwritten* by [[AssetManager]] - * when it publishes the asset files from [[sourcePath]]. - * - * If the bundle contains any assets that are specified in terms of relative file path, - * then this property must be set either manually or automatically (by asset manager via - * asset publishing). - * - * You can use either a URL or an alias of the URL. - */ - public $baseUrl; - /** - * @var array list of bundle class names that this bundle depends on. - * - * For example: - * - * ```php - * public $depends = [ - * 'yii\web\YiiAsset', - * 'yii\bootstrap\BootstrapAsset', - * ]; - * ``` - */ - public $depends = []; - /** - * @var array list of JavaScript files that this bundle contains. Each JavaScript file can - * be either a file path (without leading slash) relative to [[basePath]] or a URL representing - * an external JavaScript file. - * - * Note that only forward slash "/" can be used as directory separator. - */ - public $js = []; - /** - * @var array list of CSS files that this bundle contains. Each CSS file can - * be either a file path (without leading slash) relative to [[basePath]] or a URL representing - * an external CSS file. - * - * Note that only forward slash "/" can be used as directory separator. - */ - public $css = []; - /** - * @var array the options that will be passed to [[\yii\web\View::registerJsFile()]] - * when registering the JS files in this bundle. - */ - public $jsOptions = []; - /** - * @var array the options that will be passed to [[\yii\web\View::registerCssFile()]] - * when registering the CSS files in this bundle. - */ - public $cssOptions = []; - /** - * @var array the options to be passed to [[AssetManager::publish()]] when the asset bundle - * is being published. - */ - public $publishOptions = []; - - /** - * @param View $view - * @return AssetBundle the registered asset bundle instance - */ - public static function register($view) - { - return $view->registerAssetBundle(get_called_class()); - } - - /** - * Initializes the bundle. - * If you override this method, make sure you call the parent implementation in the last. - */ - public function init() - { - if ($this->sourcePath !== null) { - $this->sourcePath = rtrim(Yii::getAlias($this->sourcePath), '/\\'); - } - if ($this->basePath !== null) { - $this->basePath = rtrim(Yii::getAlias($this->basePath), '/\\'); - } - if ($this->baseUrl !== null) { - $this->baseUrl = rtrim(Yii::getAlias($this->baseUrl), '/'); - } - } - - /** - * Registers the CSS and JS files with the given view. - * @param \yii\web\View $view the view that the asset files are to be registered with. - */ - public function registerAssetFiles($view) - { - foreach ($this->js as $js) { - if (strpos($js, '/') !== 0 && strpos($js, '://') === false) { - $view->registerJsFile($this->baseUrl . '/' . $js, [], $this->jsOptions); - } else { - $view->registerJsFile($js, [], $this->jsOptions); - } - } - foreach ($this->css as $css) { - if (strpos($css, '/') !== 0 && strpos($css, '://') === false) { - $view->registerCssFile($this->baseUrl . '/' . $css, [], $this->cssOptions); - } else { - $view->registerCssFile($css, [], $this->cssOptions); - } - } - } - - /** - * Publishes the asset bundle if its source code is not under Web-accessible directory. - * It will also try to convert non-CSS or JS files (e.g. LESS, Sass) into the corresponding - * CSS or JS files using [[AssetManager::converter|asset converter]]. - * @param AssetManager $am the asset manager to perform the asset publishing - */ - public function publish($am) - { - if ($this->sourcePath !== null && !isset($this->basePath, $this->baseUrl)) { - list ($this->basePath, $this->baseUrl) = $am->publish($this->sourcePath, $this->publishOptions); - } - $converter = $am->getConverter(); - foreach ($this->js as $i => $js) { - if (strpos($js, '/') !== 0 && strpos($js, '://') === false) { - if (isset($this->basePath, $this->baseUrl)) { - $this->js[$i] = $converter->convert($js, $this->basePath, $this->baseUrl); - } else { - $this->js[$i] = '/' . $js; - } - } - } - foreach ($this->css as $i => $css) { - if (strpos($css, '/') !== 0 && strpos($css, '://') === false) { - if (isset($this->basePath, $this->baseUrl)) { - $this->css[$i] = $converter->convert($css, $this->basePath, $this->baseUrl); - } else { - $this->css[$i] = '/' . $css; - } - } - } - } -} diff --git a/framework/yii/web/AssetConverter.php b/framework/yii/web/AssetConverter.php deleted file mode 100644 index 1b7d1c8..0000000 --- a/framework/yii/web/AssetConverter.php +++ /dev/null @@ -1,99 +0,0 @@ - - * @since 2.0 - */ -class AssetConverter extends Component implements AssetConverterInterface -{ - /** - * @var array the commands that are used to perform the asset conversion. - * The keys are the asset file extension names, and the values are the corresponding - * target script types (either "css" or "js") and the commands used for the conversion. - */ - public $commands = [ - 'less' => ['css', 'lessc {from} {to} --no-color'], - 'scss' => ['css', 'sass {from} {to}'], - 'sass' => ['css', 'sass {from} {to}'], - 'styl' => ['js', 'stylus < {from} > {to}'], - 'coffee' => ['js', 'coffee -p {from} > {to}'], - 'ts' => ['js', 'tsc --out {to} {from}'], - ]; - - /** - * Converts a given asset file into a CSS or JS file. - * @param string $asset the asset file path, relative to $basePath - * @param string $basePath the directory the $asset is relative to. - * @return string the converted asset file path, relative to $basePath. - */ - public function convert($asset, $basePath) - { - $pos = strrpos($asset, '.'); - if ($pos !== false) { - $ext = substr($asset, $pos + 1); - if (isset($this->commands[$ext])) { - list ($ext, $command) = $this->commands[$ext]; - $result = substr($asset, 0, $pos + 1) . $ext; - if (@filemtime("$basePath/$result") < filemtime("$basePath/$asset")) { - $this->runCommand($command, $basePath, $asset, $result); - } - return $result; - } - } - return $asset; - } - - /** - * Runs a command to convert asset files. - * @param string $command the command to run - * @param string $basePath asset base path and command working directory - * @param string $asset the name of the asset file - * @param string $result the name of the file to be generated by the converter command - * @return bool true on success, false on failure. Failures will be logged. - * @throws \yii\base\Exception when the command fails and YII_DEBUG is true. - * In production mode the error will be logged. - */ - protected function runCommand($command, $basePath, $asset, $result) - { - $command = strtr($command, [ - '{from}' => escapeshellarg("$basePath/$asset"), - '{to}' => escapeshellarg("$basePath/$result"), - ]); - $descriptor = [ - 1 => ['pipe', 'w'], - 2 => ['pipe', 'w'], - ]; - $pipes = []; - $proc = proc_open($command, $descriptor, $pipes, $basePath); - $stdout = stream_get_contents($pipes[1]); - $stderr = stream_get_contents($pipes[2]); - foreach($pipes as $pipe) { - fclose($pipe); - } - $status = proc_close($proc); - - if ($status === 0) { - Yii::trace("Converted $asset into $result:\nSTDOUT:\n$stdout\nSTDERR:\n$stderr", __METHOD__); - } elseif (YII_DEBUG) { - throw new Exception("AssetConverter command '$command' failed with exit code $status:\nSTDOUT:\n$stdout\nSTDERR:\n$stderr"); - } else { - Yii::error("AssetConverter command '$command' failed with exit code $status:\nSTDOUT:\n$stdout\nSTDERR:\n$stderr"); - } - return $status === 0; - } -} diff --git a/framework/yii/web/AssetConverterInterface.php b/framework/yii/web/AssetConverterInterface.php deleted file mode 100644 index 51309c6..0000000 --- a/framework/yii/web/AssetConverterInterface.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -interface AssetConverterInterface -{ - /** - * Converts a given asset file into a CSS or JS file. - * @param string $asset the asset file path, relative to $basePath - * @param string $basePath the directory the $asset is relative to. - * @return string the converted asset file path, relative to $basePath. - */ - public function convert($asset, $basePath); -} diff --git a/framework/yii/web/AssetManager.php b/framework/yii/web/AssetManager.php deleted file mode 100644 index 89e746e..0000000 --- a/framework/yii/web/AssetManager.php +++ /dev/null @@ -1,343 +0,0 @@ -assetManager`. - * - * You can modify its configuration by adding an array to your application config under `components` - * as it is shown in the following example: - * - * ~~~ - * 'assetManager' => [ - * 'bundles' => [ - * // you can override AssetBundle configs here - * ], - * //'linkAssets' => true, - * // ... - * ] - * ~~~ - * - * @property AssetConverterInterface $converter The asset converter. Note that the type of this property - * differs in getter and setter. See [[getConverter()]] and [[setConverter()]] for details. - * - * @author Qiang Xue - * @since 2.0 - */ -class AssetManager extends Component -{ - /** - * @var array list of available asset bundles. The keys are the class names (without leading backslash) - * of the asset bundles, and the values are either the configuration arrays for creating the [[AssetBundle]] - * objects or the corresponding asset bundle instances. For example, the following code disables - * the bootstrap css file used by Bootstrap widgets (because you want to use your own styles): - * - * ~~~ - * [ - * 'yii\bootstrap\BootstrapAsset' => [ - * 'css' => [], - * ], - * ] - * ~~~ - */ - public $bundles = []; - /** - * @return string the root directory storing the published asset files. - */ - public $basePath = '@webroot/assets'; - /** - * @return string the base URL through which the published asset files can be accessed. - */ - public $baseUrl = '@web/assets'; - /** - * @var boolean whether to use symbolic link to publish asset files. Defaults to false, meaning - * asset files are copied to [[basePath]]. Using symbolic links has the benefit that the published - * assets will always be consistent with the source assets and there is no copy operation required. - * This is especially useful during development. - * - * However, there are special requirements for hosting environments in order to use symbolic links. - * In particular, symbolic links are supported only on Linux/Unix, and Windows Vista/2008 or greater. - * - * Moreover, some Web servers need to be properly configured so that the linked assets are accessible - * to Web users. For example, for Apache Web server, the following configuration directive should be added - * for the Web folder: - * - * ~~~ - * Options FollowSymLinks - * ~~~ - */ - public $linkAssets = false; - /** - * @var integer the permission to be set for newly published asset files. - * This value will be used by PHP chmod() function. No umask will be applied. - * If not set, the permission will be determined by the current environment. - */ - public $fileMode; - /** - * @var integer the permission to be set for newly generated asset directories. - * This value will be used by PHP chmod() function. No umask will be applied. - * Defaults to 0775, meaning the directory is read-writable by owner and group, - * but read-only for other users. - */ - public $dirMode = 0775; - - /** - * Initializes the component. - * @throws InvalidConfigException if [[basePath]] is invalid - */ - public function init() - { - parent::init(); - $this->basePath = Yii::getAlias($this->basePath); - if (!is_dir($this->basePath)) { - throw new InvalidConfigException("The directory does not exist: {$this->basePath}"); - } elseif (!is_writable($this->basePath)) { - throw new InvalidConfigException("The directory is not writable by the Web process: {$this->basePath}"); - } else { - $this->basePath = realpath($this->basePath); - } - $this->baseUrl = rtrim(Yii::getAlias($this->baseUrl), '/'); - } - - /** - * Returns the named asset bundle. - * - * This method will first look for the bundle in [[bundles]]. If not found, - * it will treat `$name` as the class of the asset bundle and create a new instance of it. - * - * @param string $name the class name of the asset bundle - * @param boolean $publish whether to publish the asset files in the asset bundle before it is returned. - * If you set this false, you must manually call `AssetBundle::publish()` to publish the asset files. - * @return AssetBundle the asset bundle instance - * @throws InvalidConfigException if $name does not refer to a valid asset bundle - */ - public function getBundle($name, $publish = true) - { - if (isset($this->bundles[$name])) { - if ($this->bundles[$name] instanceof AssetBundle) { - return $this->bundles[$name]; - } elseif (is_array($this->bundles[$name])) { - $bundle = Yii::createObject(array_merge(['class' => $name], $this->bundles[$name])); - } else { - throw new InvalidConfigException("Invalid asset bundle: $name"); - } - } else { - $bundle = Yii::createObject($name); - } - if ($publish) { - /** @var AssetBundle $bundle */ - $bundle->publish($this); - } - return $this->bundles[$name] = $bundle; - } - - private $_converter; - - /** - * Returns the asset converter. - * @return AssetConverterInterface the asset converter. - */ - public function getConverter() - { - if ($this->_converter === null) { - $this->_converter = Yii::createObject(AssetConverter::className()); - } elseif (is_array($this->_converter) || is_string($this->_converter)) { - $this->_converter = Yii::createObject($this->_converter); - } - return $this->_converter; - } - - /** - * Sets the asset converter. - * @param array|AssetConverterInterface $value the asset converter. This can be either - * an object implementing the [[AssetConverterInterface]], or a configuration - * array that can be used to create the asset converter object. - */ - public function setConverter($value) - { - $this->_converter = $value; - } - - /** - * @var array published assets - */ - private $_published = []; - - /** - * Publishes a file or a directory. - * - * This method will copy the specified file or directory to [[basePath]] so that - * it can be accessed via the Web server. - * - * If the asset is a file, its file modification time will be checked to avoid - * unnecessary file copying. - * - * If the asset is a directory, all files and subdirectories under it will be published recursively. - * Note, in case $forceCopy is false the method only checks the existence of the target - * directory to avoid repetitive copying (which is very expensive). - * - * By default, when publishing a directory, subdirectories and files whose name starts with a dot "." - * will NOT be published. If you want to change this behavior, you may specify the "beforeCopy" option - * as explained in the `$options` parameter. - * - * Note: On rare scenario, a race condition can develop that will lead to a - * one-time-manifestation of a non-critical problem in the creation of the directory - * that holds the published assets. This problem can be avoided altogether by 'requesting' - * in advance all the resources that are supposed to trigger a 'publish()' call, and doing - * that in the application deployment phase, before system goes live. See more in the following - * discussion: http://code.google.com/p/yii/issues/detail?id=2579 - * - * @param string $path the asset (file or directory) to be published - * @param array $options the options to be applied when publishing a directory. - * The following options are supported: - * - * - beforeCopy: callback, a PHP callback that is called before copying each sub-directory or file. - * This option is used only when publishing a directory. If the callback returns false, the copy - * operation for the sub-directory or file will be cancelled. - * The signature of the callback should be: `function ($from, $to)`, where `$from` is the sub-directory or - * file to be copied from, while `$to` is the copy target. - * - afterCopy: callback, a PHP callback that is called after a sub-directory or file is successfully copied. - * This option is used only when publishing a directory. The signature of the callback is similar to that - * of `beforeCopy`. - * - forceCopy: boolean, whether the directory being published should be copied even if - * it is found in the target directory. This option is used only when publishing a directory. - * You may want to set this to be true during the development stage to make sure the published - * directory is always up-to-date. Do not set this to true on production servers as it will - * significantly degrade the performance. - * @return array the path (directory or file path) and the URL that the asset is published as. - * @throws InvalidParamException if the asset to be published does not exist. - */ - public function publish($path, $options = []) - { - if (isset($this->_published[$path])) { - return $this->_published[$path]; - } - - $src = realpath($path); - if ($src === false) { - throw new InvalidParamException("The file or directory to be published does not exist: $path"); - } - - if (is_file($src)) { - $dir = $this->hash(dirname($src) . filemtime($src)); - $fileName = basename($src); - $dstDir = $this->basePath . DIRECTORY_SEPARATOR . $dir; - $dstFile = $dstDir . DIRECTORY_SEPARATOR . $fileName; - - if (!is_dir($dstDir)) { - FileHelper::createDirectory($dstDir, $this->dirMode, true); - } - - if ($this->linkAssets) { - if (!is_file($dstFile)) { - symlink($src, $dstFile); - } - } elseif (@filemtime($dstFile) < @filemtime($src)) { - copy($src, $dstFile); - if ($this->fileMode !== null) { - @chmod($dstFile, $this->fileMode); - } - } - - return $this->_published[$path] = [$dstFile, $this->baseUrl . "/$dir/$fileName"]; - } else { - $dir = $this->hash($src . filemtime($src)); - $dstDir = $this->basePath . DIRECTORY_SEPARATOR . $dir; - if ($this->linkAssets) { - if (!is_dir($dstDir)) { - symlink($src, $dstDir); - } - } elseif (!is_dir($dstDir) || !empty($options['forceCopy'])) { - $opts = [ - 'dirMode' => $this->dirMode, - 'fileMode' => $this->fileMode, - ]; - if (isset($options['beforeCopy'])) { - $opts['beforeCopy'] = $options['beforeCopy']; - } else { - $opts['beforeCopy'] = function ($from, $to) { - return strncmp(basename($from), '.', 1) !== 0; - }; - } - if (isset($options['afterCopy'])) { - $opts['afterCopy'] = $options['afterCopy']; - } - FileHelper::copyDirectory($src, $dstDir, $opts); - } - - return $this->_published[$path] = [$dstDir, $this->baseUrl . '/' . $dir]; - } - } - - /** - * Returns the published path of a file path. - * This method does not perform any publishing. It merely tells you - * if the file or directory is published, where it will go. - * @param string $path directory or file path being published - * @return string the published file path. False if the file or directory does not exist - */ - public function getPublishedPath($path) - { - if (isset($this->_published[$path])) { - return $this->_published[$path][0]; - } - if (($path = realpath($path)) !== false) { - $base = $this->basePath . DIRECTORY_SEPARATOR; - if (is_file($path)) { - return $base . $this->hash(dirname($path) . filemtime($path)) . DIRECTORY_SEPARATOR . basename($path); - } else { - return $base . $this->hash($path . filemtime($path)); - } - } else { - return false; - } - } - - /** - * Returns the URL of a published file path. - * This method does not perform any publishing. It merely tells you - * if the file path is published, what the URL will be to access it. - * @param string $path directory or file path being published - * @return string the published URL for the file or directory. False if the file or directory does not exist. - */ - public function getPublishedUrl($path) - { - if (isset($this->_published[$path])) { - return $this->_published[$path][1]; - } - if (($path = realpath($path)) !== false) { - if (is_file($path)) { - return $this->baseUrl . '/' . $this->hash(dirname($path) . filemtime($path)) . '/' . basename($path); - } else { - return $this->baseUrl . '/' . $this->hash($path . filemtime($path)); - } - } else { - return false; - } - } - - /** - * Generate a CRC32 hash for the directory path. Collisions are higher - * than MD5 but generates a much smaller hash string. - * @param string $path string to be hashed. - * @return string hashed string. - */ - protected function hash($path) - { - return sprintf('%x', crc32($path . Yii::getVersion())); - } -} diff --git a/framework/yii/web/BadRequestHttpException.php b/framework/yii/web/BadRequestHttpException.php deleted file mode 100644 index 3a6cfbb..0000000 --- a/framework/yii/web/BadRequestHttpException.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @since 2.0 - */ -class BadRequestHttpException extends HttpException -{ - /** - * Constructor. - * @param string $message error message - * @param integer $code error code - * @param \Exception $previous The previous exception used for the exception chaining. - */ - public function __construct($message = null, $code = 0, \Exception $previous = null) - { - parent::__construct(400, $message, $code, $previous); - } -} diff --git a/framework/yii/web/CacheSession.php b/framework/yii/web/CacheSession.php deleted file mode 100644 index 7b4a98d..0000000 --- a/framework/yii/web/CacheSession.php +++ /dev/null @@ -1,118 +0,0 @@ - [ - * 'class' => 'yii\web\CacheSession', - * // 'cache' => 'mycache', - * ] - * ~~~ - * - * @property boolean $useCustomStorage Whether to use custom storage. This property is read-only. - * - * @author Qiang Xue - * @since 2.0 - */ -class CacheSession extends Session -{ - /** - * @var Cache|string the cache object or the application component ID of the cache object. - * The session data will be stored using this cache object. - * - * After the CacheSession object is created, if you want to change this property, - * you should only assign it with a cache object. - */ - public $cache = 'cache'; - - /** - * Initializes the application component. - */ - public function init() - { - if (is_string($this->cache)) { - $this->cache = Yii::$app->getComponent($this->cache); - } - if (!$this->cache instanceof Cache) { - throw new InvalidConfigException('CacheSession::cache must refer to the application component ID of a cache object.'); - } - parent::init(); - } - - /** - * Returns a value indicating whether to use custom session storage. - * This method overrides the parent implementation and always returns true. - * @return boolean whether to use custom storage. - */ - public function getUseCustomStorage() - { - return true; - } - - /** - * Session read handler. - * Do not call this method directly. - * @param string $id session ID - * @return string the session data - */ - public function readSession($id) - { - $data = $this->cache->get($this->calculateKey($id)); - return $data === false ? '' : $data; - } - - /** - * Session write handler. - * Do not call this method directly. - * @param string $id session ID - * @param string $data session data - * @return boolean whether session write is successful - */ - public function writeSession($id, $data) - { - return $this->cache->set($this->calculateKey($id), $data, $this->getTimeout()); - } - - /** - * Session destroy handler. - * Do not call this method directly. - * @param string $id session ID - * @return boolean whether session is destroyed successfully - */ - public function destroySession($id) - { - return $this->cache->delete($this->calculateKey($id)); - } - - /** - * Generates a unique key used for storing session data in cache. - * @param string $id session variable name - * @return mixed a safe cache key associated with the session variable name - */ - protected function calculateKey($id) - { - return [__CLASS__, $id]; - } -} diff --git a/framework/yii/web/Controller.php b/framework/yii/web/Controller.php deleted file mode 100644 index c569d14..0000000 --- a/framework/yii/web/Controller.php +++ /dev/null @@ -1,282 +0,0 @@ - - * @since 2.0 - */ -class Controller extends \yii\base\Controller -{ - /** - * @var boolean whether to enable CSRF validation for the actions in this controller. - * CSRF validation is enabled only when both this property and [[Request::enableCsrfValidation]] are true. - */ - public $enableCsrfValidation = true; - /** - * @var array the parameters bound to the current action. This is mainly used by [[getCanonicalUrl()]]. - */ - public $actionParams = []; - - /** - * Binds the parameters to the action. - * This method is invoked by [[Action]] when it begins to run with the given parameters. - * This method will check the parameter names that the action requires and return - * the provided parameters according to the requirement. If there is any missing parameter, - * an exception will be thrown. - * @param \yii\base\Action $action the action to be bound with parameters - * @param array $params the parameters to be bound to the action - * @return array the valid parameters that the action can run with. - * @throws HttpException if there are missing or invalid parameters. - */ - public function bindActionParams($action, $params) - { - if ($action instanceof InlineAction) { - $method = new \ReflectionMethod($this, $action->actionMethod); - } else { - $method = new \ReflectionMethod($action, 'run'); - } - - $args = []; - $missing = []; - $actionParams = []; - foreach ($method->getParameters() as $param) { - $name = $param->getName(); - if (array_key_exists($name, $params)) { - if ($param->isArray()) { - $args[] = $actionParams[$name] = is_array($params[$name]) ? $params[$name] : [$params[$name]]; - } elseif (!is_array($params[$name])) { - $args[] = $actionParams[$name] = $params[$name]; - } else { - throw new BadRequestHttpException(Yii::t('yii', 'Invalid data received for parameter "{param}".', [ - 'param' => $name, - ])); - } - unset($params[$name]); - } elseif ($param->isDefaultValueAvailable()) { - $args[] = $actionParams[$name] = $param->getDefaultValue(); - } else { - $missing[] = $name; - } - } - - if (!empty($missing)) { - throw new BadRequestHttpException(Yii::t('yii', 'Missing required parameters: {params}', [ - 'params' => implode(', ', $missing), - ])); - } - - $this->actionParams = $actionParams; - - return $args; - } - - /** - * @inheritdoc - */ - public function beforeAction($action) - { - if (parent::beforeAction($action)) { - if ($this->enableCsrfValidation && Yii::$app->exception === null && !Yii::$app->getRequest()->validateCsrfToken()) { - throw new BadRequestHttpException(Yii::t('yii', 'Unable to verify your data submission.')); - } - return true; - } else { - return false; - } - } - - /** - * Normalizes route making it suitable for UrlManager. Absolute routes are staying as is - * while relative routes are converted to absolute routes. - * - * A relative route is a route without a leading slash, such as "view", "post/view". - * - * - If the route is an empty string, the current [[route]] will be used; - * - If the route contains no slashes at all, it is considered to be an action ID - * of the current controller and will be prepended with [[uniqueId]]; - * - If the route has no leading slash, it is considered to be a route relative - * to the current module and will be prepended with the module's uniqueId. - * - * @param string $route the route. This can be either an absolute route or a relative route. - * @return string normalized route suitable for UrlManager - */ - protected function getNormalizedRoute($route) - { - if (strpos($route, '/') === false) { - // empty or an action ID - $route = $route === '' ? $this->getRoute() : $this->getUniqueId() . '/' . $route; - } elseif ($route[0] !== '/') { - // relative to module - $route = ltrim($this->module->getUniqueId() . '/' . $route, '/'); - } - return $route; - } - - /** - * Creates a relative URL using the given route and parameters. - * - * This method enhances [[UrlManager::createUrl()]] by supporting relative routes. - * A relative route is a route without a leading slash, such as "view", "post/view". - * - * - If the route is an empty string, the current [[route]] will be used; - * - If the route contains no slashes at all, it is considered to be an action ID - * of the current controller and will be prepended with [[uniqueId]]; - * - If the route has no leading slash, it is considered to be a route relative - * to the current module and will be prepended with the module's uniqueId. - * - * After this route conversion, the method calls [[UrlManager::createUrl()]] to create a URL. - * - * @param string $route the route. This can be either an absolute route or a relative route. - * @param array $params the parameters (name-value pairs) to be included in the generated URL - * @return string the created relative URL - */ - public function createUrl($route, $params = []) - { - $route = $this->getNormalizedRoute($route); - return Yii::$app->getUrlManager()->createUrl($route, $params); - } - - /** - * Creates an absolute URL using the given route and parameters. - * - * This method enhances [[UrlManager::createAbsoluteUrl()]] by supporting relative routes. - * A relative route is a route without a leading slash, such as "view", "post/view". - * - * - If the route is an empty string, the current [[route]] will be used; - * - If the route contains no slashes at all, it is considered to be an action ID - * of the current controller and will be prepended with [[uniqueId]]; - * - If the route has no leading slash, it is considered to be a route relative - * to the current module and will be prepended with the module's uniqueId. - * - * After this route conversion, the method calls [[UrlManager::createUrl()]] to create a URL. - * - * @param string $route the route. This can be either an absolute route or a relative route. - * @param array $params the parameters (name-value pairs) to be included in the generated URL - * @return string the created absolute URL - */ - public function createAbsoluteUrl($route, $params = []) - { - $route = $this->getNormalizedRoute($route); - return Yii::$app->getUrlManager()->createAbsoluteUrl($route, $params); - } - - /** - * Returns the canonical URL of the currently requested page. - * The canonical URL is constructed using [[route]] and [[actionParams]]. You may use the following code - * in the layout view to add a link tag about canonical URL: - * - * ~~~ - * $this->registerLinkTag(['rel' => 'canonical', 'href' => Yii::$app->controller->canonicalUrl]); - * ~~~ - * - * @return string the canonical URL of the currently requested page - */ - public function getCanonicalUrl() - { - return Yii::$app->getUrlManager()->createAbsoluteUrl($this->getRoute(), $this->actionParams); - } - - /** - * Redirects the browser to the specified URL. - * This method is a shortcut to [[Response::redirect()]]. - * - * You can use it in an action by returning the [[Response]] directly: - * - * ```php - * // stop executing this action and redirect to login page - * return $this->redirect(['login']); - * ``` - * - * @param string|array $url the URL to be redirected to. This can be in one of the following formats: - * - * - a string representing a URL (e.g. "http://example.com") - * - a string representing a URL alias (e.g. "@example.com") - * - an array in the format of `[$route, ...name-value pairs...]` (e.g. `['site/index', 'ref' => 1]`) - * [[Html::url()]] will be used to convert the array into a URL. - * - * Any relative URL will be converted into an absolute one by prepending it with the host info - * of the current request. - * - * @param integer $statusCode the HTTP status code. Defaults to 302. - * See - * for details about HTTP status code - * @return Response the current response object - */ - public function redirect($url, $statusCode = 302) - { - return Yii::$app->getResponse()->redirect(Html::url($url), $statusCode); - } - - /** - * Redirects the browser to the home page. - * - * You can use this method in an action by returning the [[Response]] directly: - * - * ```php - * // stop executing this action and redirect to home page - * return $this->goHome(); - * ``` - * - * @return Response the current response object - */ - public function goHome() - { - return Yii::$app->getResponse()->redirect(Yii::$app->getHomeUrl()); - } - - /** - * Redirects the browser to the last visited page. - * - * You can use this method in an action by returning the [[Response]] directly: - * - * ```php - * // stop executing this action and redirect to last visited page - * return $this->goBack(); - * ``` - * - * @param string|array $defaultUrl the default return URL in case it was not set previously. - * If this is null and the return URL was not set previously, [[Application::homeUrl]] will be redirected to. - * Please refer to [[User::setReturnUrl()]] on accepted format of the URL. - * @return Response the current response object - * @see User::getReturnUrl() - */ - public function goBack($defaultUrl = null) - { - return Yii::$app->getResponse()->redirect(Yii::$app->getUser()->getReturnUrl($defaultUrl)); - } - - /** - * Refreshes the current page. - * This method is a shortcut to [[Response::refresh()]]. - * - * You can use it in an action by returning the [[Response]] directly: - * - * ```php - * // stop executing this action and refresh the current page - * return $this->refresh(); - * ``` - * - * @param string $anchor the anchor that should be appended to the redirection URL. - * Defaults to empty. Make sure the anchor starts with '#' if you want to specify it. - * @return Response the response object itself - */ - public function refresh($anchor = '') - { - return Yii::$app->getResponse()->redirect(Yii::$app->getRequest()->getUrl() . $anchor); - } -} diff --git a/framework/yii/web/Cookie.php b/framework/yii/web/Cookie.php deleted file mode 100644 index 8cbb412..0000000 --- a/framework/yii/web/Cookie.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @since 2.0 - */ -class Cookie extends \yii\base\Object -{ - /** - * @var string name of the cookie - */ - public $name; - /** - * @var string value of the cookie - */ - public $value = ''; - /** - * @var string domain of the cookie - */ - public $domain = ''; - /** - * @var integer the timestamp at which the cookie expires. This is the server timestamp. - * Defaults to 0, meaning "until the browser is closed". - */ - public $expire = 0; - /** - * @var string the path on the server in which the cookie will be available on. The default is '/'. - */ - public $path = '/'; - /** - * @var boolean whether cookie should be sent via secure connection - */ - public $secure = false; - /** - * @var boolean whether the cookie should be accessible only through the HTTP protocol. - * By setting this property to true, the cookie will not be accessible by scripting languages, - * such as JavaScript, which can effectively help to reduce identity theft through XSS attacks. - */ - public $httpOnly = false; - - /** - * Magic method to turn a cookie object into a string without having to explicitly access [[value]]. - * - * ~~~ - * if (isset($request->cookies['name'])) { - * $value = (string)$request->cookies['name']; - * } - * ~~~ - * - * @return string The value of the cookie. If the value property is null, an empty string will be returned. - */ - public function __toString() - { - return (string)$this->value; - } -} diff --git a/framework/yii/web/CookieCollection.php b/framework/yii/web/CookieCollection.php deleted file mode 100644 index 3cf80ff..0000000 --- a/framework/yii/web/CookieCollection.php +++ /dev/null @@ -1,228 +0,0 @@ - - * @since 2.0 - */ -class CookieCollection extends Object implements \IteratorAggregate, \ArrayAccess, \Countable -{ - /** - * @var boolean whether this collection is read only. - */ - public $readOnly = false; - - /** - * @var Cookie[] the cookies in this collection (indexed by the cookie names) - */ - private $_cookies = []; - - /** - * Constructor. - * @param array $cookies the cookies that this collection initially contains. This should be - * an array of name-value pairs.s - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($cookies = [], $config = []) - { - $this->_cookies = $cookies; - parent::__construct($config); - } - - /** - * Returns an iterator for traversing the cookies in the collection. - * This method is required by the SPL interface `IteratorAggregate`. - * It will be implicitly called when you use `foreach` to traverse the collection. - * @return ArrayIterator an iterator for traversing the cookies in the collection. - */ - public function getIterator() - { - return new ArrayIterator($this->_cookies); - } - - /** - * Returns the number of cookies in the collection. - * This method is required by the SPL `Countable` interface. - * It will be implicitly called when you use `count($collection)`. - * @return integer the number of cookies in the collection. - */ - public function count() - { - return $this->getCount(); - } - - /** - * Returns the number of cookies in the collection. - * @return integer the number of cookies in the collection. - */ - public function getCount() - { - return count($this->_cookies); - } - - /** - * Returns the cookie with the specified name. - * @param string $name the cookie name - * @return Cookie the cookie with the specified name. Null if the named cookie does not exist. - * @see getValue() - */ - public function get($name) - { - return isset($this->_cookies[$name]) ? $this->_cookies[$name] : null; - } - - /** - * Returns the value of the named cookie. - * @param string $name the cookie name - * @param mixed $defaultValue the value that should be returned when the named cookie does not exist. - * @return mixed the value of the named cookie. - * @see get() - */ - public function getValue($name, $defaultValue = null) - { - return isset($this->_cookies[$name]) ? $this->_cookies[$name]->value : $defaultValue; - } - - /** - * Returns whether there is a cookie with the specified name. - * @param string $name the cookie name - * @return boolean whether the named cookie exists - */ - public function has($name) - { - return isset($this->_cookies[$name]); - } - - /** - * Adds a cookie to the collection. - * If there is already a cookie with the same name in the collection, it will be removed first. - * @param Cookie $cookie the cookie to be added - * @throws InvalidCallException if the cookie collection is read only - */ - public function add($cookie) - { - if ($this->readOnly) { - throw new InvalidCallException('The cookie collection is read only.'); - } - $this->_cookies[$cookie->name] = $cookie; - } - - /** - * Removes a cookie. - * If `$removeFromBrowser` is true, the cookie will be removed from the browser. - * In this case, a cookie with outdated expiry will be added to the collection. - * @param Cookie|string $cookie the cookie object or the name of the cookie to be removed. - * @param boolean $removeFromBrowser whether to remove the cookie from browser - * @throws InvalidCallException if the cookie collection is read only - */ - public function remove($cookie, $removeFromBrowser = true) - { - if ($this->readOnly) { - throw new InvalidCallException('The cookie collection is read only.'); - } - if ($cookie instanceof Cookie) { - $cookie->expire = 1; - $cookie->value = ''; - } else { - $cookie = new Cookie([ - 'name' => $cookie, - 'expire' => 1, - ]); - } - if ($removeFromBrowser) { - $this->_cookies[$cookie->name] = $cookie; - } else { - unset($this->_cookies[$cookie->name]); - } - } - - /** - * Removes all cookies. - * @throws InvalidCallException if the cookie collection is read only - */ - public function removeAll() - { - if ($this->readOnly) { - throw new InvalidCallException('The cookie collection is read only.'); - } - $this->_cookies = []; - } - - /** - * Returns the collection as a PHP array. - * @return array the array representation of the collection. - * The array keys are cookie names, and the array values are the corresponding - * cookie objects. - */ - public function toArray() - { - return $this->_cookies; - } - - /** - * Returns whether there is a cookie with the specified name. - * This method is required by the SPL interface `ArrayAccess`. - * It is implicitly called when you use something like `isset($collection[$name])`. - * @param string $name the cookie name - * @return boolean whether the named cookie exists - */ - public function offsetExists($name) - { - return $this->has($name); - } - - /** - * Returns the cookie with the specified name. - * This method is required by the SPL interface `ArrayAccess`. - * It is implicitly called when you use something like `$cookie = $collection[$name];`. - * This is equivalent to [[get()]]. - * @param string $name the cookie name - * @return Cookie the cookie with the specified name, null if the named cookie does not exist. - */ - public function offsetGet($name) - { - return $this->get($name); - } - - /** - * Adds the cookie to the collection. - * This method is required by the SPL interface `ArrayAccess`. - * It is implicitly called when you use something like `$collection[$name] = $cookie;`. - * This is equivalent to [[add()]]. - * @param string $name the cookie name - * @param Cookie $cookie the cookie to be added - */ - public function offsetSet($name, $cookie) - { - $this->add($cookie); - } - - /** - * Removes the named cookie. - * This method is required by the SPL interface `ArrayAccess`. - * It is implicitly called when you use something like `unset($collection[$name])`. - * This is equivalent to [[remove()]]. - * @param string $name the cookie name - */ - public function offsetUnset($name) - { - $this->remove($name); - } -} diff --git a/framework/yii/web/DbSession.php b/framework/yii/web/DbSession.php deleted file mode 100644 index 2b0b0e7..0000000 --- a/framework/yii/web/DbSession.php +++ /dev/null @@ -1,224 +0,0 @@ - [ - * 'class' => 'yii\web\DbSession', - * // 'db' => 'mydb', - * // 'sessionTable' => 'my_session', - * ] - * ~~~ - * - * @property boolean $useCustomStorage Whether to use custom storage. This property is read-only. - * - * @author Qiang Xue - * @since 2.0 - */ -class DbSession extends Session -{ - /** - * @var Connection|string the DB connection object or the application component ID of the DB connection. - * After the DbSession object is created, if you want to change this property, you should only assign it - * with a DB connection object. - */ - public $db = 'db'; - /** - * @var string the name of the DB table that stores the session data. - * The table should be pre-created as follows: - * - * ~~~ - * CREATE TABLE tbl_session - * ( - * id CHAR(40) NOT NULL PRIMARY KEY, - * expire INTEGER, - * data BLOB - * ) - * ~~~ - * - * where 'BLOB' refers to the BLOB-type of your preferred DBMS. Below are the BLOB type - * that can be used for some popular DBMS: - * - * - MySQL: LONGBLOB - * - PostgreSQL: BYTEA - * - MSSQL: BLOB - * - * When using DbSession in a production server, we recommend you create a DB index for the 'expire' - * column in the session table to improve the performance. - */ - public $sessionTable = '{{%session}}'; - - /** - * Initializes the DbSession component. - * This method will initialize the [[db]] property to make sure it refers to a valid DB connection. - * @throws InvalidConfigException if [[db]] is invalid. - */ - public function init() - { - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - } - if (!$this->db instanceof Connection) { - throw new InvalidConfigException("DbSession::db must be either a DB connection instance or the application component ID of a DB connection."); - } - parent::init(); - } - - /** - * Returns a value indicating whether to use custom session storage. - * This method overrides the parent implementation and always returns true. - * @return boolean whether to use custom storage. - */ - public function getUseCustomStorage() - { - return true; - } - - /** - * Updates the current session ID with a newly generated one . - * Please refer to for more details. - * @param boolean $deleteOldSession Whether to delete the old associated session file or not. - */ - public function regenerateID($deleteOldSession = false) - { - $oldID = session_id(); - - // if no session is started, there is nothing to regenerate - if (empty($oldID)) { - return; - } - - parent::regenerateID(false); - $newID = session_id(); - - $query = new Query; - $row = $query->from($this->sessionTable) - ->where(['id' => $oldID]) - ->createCommand($this->db) - ->queryOne(); - if ($row !== false) { - if ($deleteOldSession) { - $this->db->createCommand() - ->update($this->sessionTable, ['id' => $newID], ['id' => $oldID]) - ->execute(); - } else { - $row['id'] = $newID; - $this->db->createCommand() - ->insert($this->sessionTable, $row) - ->execute(); - } - } else { - // shouldn't reach here normally - $this->db->createCommand() - ->insert($this->sessionTable, [ - 'id' => $newID, - 'expire' => time() + $this->getTimeout(), - ])->execute(); - } - } - - /** - * Session read handler. - * Do not call this method directly. - * @param string $id session ID - * @return string the session data - */ - public function readSession($id) - { - $query = new Query; - $data = $query->select(['data']) - ->from($this->sessionTable) - ->where('[[expire]]>:expire AND [[id]]=:id', [':expire' => time(), ':id' => $id]) - ->createCommand($this->db) - ->queryScalar(); - return $data === false ? '' : $data; - } - - /** - * Session write handler. - * Do not call this method directly. - * @param string $id session ID - * @param string $data session data - * @return boolean whether session write is successful - */ - public function writeSession($id, $data) - { - // exception must be caught in session write handler - // http://us.php.net/manual/en/function.session-set-save-handler.php - try { - $expire = time() + $this->getTimeout(); - $query = new Query; - $exists = $query->select(['id']) - ->from($this->sessionTable) - ->where(['id' => $id]) - ->createCommand($this->db) - ->queryScalar(); - if ($exists === false) { - $this->db->createCommand() - ->insert($this->sessionTable, [ - 'id' => $id, - 'data' => $data, - 'expire' => $expire, - ])->execute(); - } else { - $this->db->createCommand() - ->update($this->sessionTable, ['data' => $data, 'expire' => $expire], ['id' => $id]) - ->execute(); - } - } catch (\Exception $e) { - if (YII_DEBUG) { - echo $e->getMessage(); - } - // it is too late to log an error message here - return false; - } - return true; - } - - /** - * Session destroy handler. - * Do not call this method directly. - * @param string $id session ID - * @return boolean whether session is destroyed successfully - */ - public function destroySession($id) - { - $this->db->createCommand() - ->delete($this->sessionTable, ['id' => $id]) - ->execute(); - return true; - } - - /** - * Session GC (garbage collection) handler. - * Do not call this method directly. - * @param integer $maxLifetime the number of seconds after which data will be seen as 'garbage' and cleaned up. - * @return boolean whether session is GCed successfully - */ - public function gcSession($maxLifetime) - { - $this->db->createCommand() - ->delete($this->sessionTable, '[[expire]]<:expire', [':expire' => time()]) - ->execute(); - return true; - } -} diff --git a/framework/yii/web/ErrorAction.php b/framework/yii/web/ErrorAction.php deleted file mode 100644 index 95f17be..0000000 --- a/framework/yii/web/ErrorAction.php +++ /dev/null @@ -1,106 +0,0 @@ - ['class' => 'yii\web\ErrorAction'], - * ]; - * } - * ``` - * - * Then, create a view file for this action. If the route of your error action is `site/error`, then - * the view file should be `views/site/error.php`. In this view file, the following variables are available: - * - * - `$name`: the error name - * - `$message`: the error message - * - `$exception`: the exception being handled - * - * Finally, configure the "errorHandler" application component as follows, - * - * ```php - * 'errorHandler' => [ - * 'errorAction' => 'site/error', - * ] - * ``` - * - * @author Qiang Xue - * @since 2.0 - */ -class ErrorAction extends Action -{ - /** - * @var string the view file to be rendered. If not set, it will take the value of [[id]]. - * That means, if you name the action as "error" in "SiteController", then the view name - * would be "error", and the corresponding view file would be "views/site/error.php". - */ - public $view; - /** - * @var string the name of the error when the exception name cannot be determined. - * Defaults to "Error". - */ - public $defaultName; - /** - * @var string the message to be displayed when the exception message contains sensitive information. - * Defaults to "An internal server error occurred.". - */ - public $defaultMessage; - - - public function run() - { - if (($exception = Yii::$app->exception) === null) { - return ''; - } - - if ($exception instanceof HttpException) { - $code = $exception->statusCode; - } else { - $code = $exception->getCode(); - } - if ($exception instanceof Exception) { - $name = $exception->getName(); - } else { - $name = $this->defaultName ?: Yii::t('yii', 'Error'); - } - if ($code) { - $name .= " (#$code)"; - } - - if ($exception instanceof UserException) { - $message = $exception->getMessage(); - } else { - $message = $this->defaultMessage ?: Yii::t('yii', 'An internal server error occurred.'); - } - - if (Yii::$app->getRequest()->getIsAjax()) { - return "$name: $message"; - } else { - return $this->controller->render($this->view ?: $this->id, [ - 'name' => $name, - 'message' => $message, - 'exception' => $exception, - ]); - } - } -} diff --git a/framework/yii/web/HeaderCollection.php b/framework/yii/web/HeaderCollection.php deleted file mode 100644 index e8e4f9c..0000000 --- a/framework/yii/web/HeaderCollection.php +++ /dev/null @@ -1,221 +0,0 @@ - - * @since 2.0 - */ -class HeaderCollection extends Object implements \IteratorAggregate, \ArrayAccess, \Countable -{ - /** - * @var array the headers in this collection (indexed by the header names) - */ - private $_headers = []; - - /** - * Returns an iterator for traversing the headers in the collection. - * This method is required by the SPL interface `IteratorAggregate`. - * It will be implicitly called when you use `foreach` to traverse the collection. - * @return ArrayIterator an iterator for traversing the headers in the collection. - */ - public function getIterator() - { - return new ArrayIterator($this->_headers); - } - - /** - * Returns the number of headers in the collection. - * This method is required by the SPL `Countable` interface. - * It will be implicitly called when you use `count($collection)`. - * @return integer the number of headers in the collection. - */ - public function count() - { - return $this->getCount(); - } - - /** - * Returns the number of headers in the collection. - * @return integer the number of headers in the collection. - */ - public function getCount() - { - return count($this->_headers); - } - - /** - * Returns the named header(s). - * @param string $name the name of the header to return - * @param mixed $default the value to return in case the named header does not exist - * @param boolean $first whether to only return the first header of the specified name. - * If false, all headers of the specified name will be returned. - * @return string|array the named header(s). If `$first` is true, a string will be returned; - * If `$first` is false, an array will be returned. - */ - public function get($name, $default = null, $first = true) - { - $name = strtolower($name); - if (isset($this->_headers[$name])) { - return $first ? reset($this->_headers[$name]) : $this->_headers[$name]; - } else { - return $default; - } - } - - /** - * Adds a new header. - * If there is already a header with the same name, it will be replaced. - * @param string $name the name of the header - * @param string $value the value of the header - * @return static the collection object itself - */ - public function set($name, $value = '') - { - $name = strtolower($name); - $this->_headers[$name] = (array)$value; - return $this; - } - - /** - * Adds a new header. - * If there is already a header with the same name, the new one will - * be appended to it instead of replacing it. - * @param string $name the name of the header - * @param string $value the value of the header - * @return static the collection object itself - */ - public function add($name, $value) - { - $name = strtolower($name); - $this->_headers[$name][] = $value; - return $this; - } - - /** - * Sets a new header only if it does not exist yet. - * If there is already a header with the same name, the new one will be ignored. - * @param string $name the name of the header - * @param string $value the value of the header - * @return static the collection object itself - */ - public function setDefault($name, $value) - { - $name = strtolower($name); - if (empty($this->_headers[$name])) { - $this->_headers[$name][] = $value; - } - return $this; - } - - /** - * Returns a value indicating whether the named header exists. - * @param string $name the name of the header - * @return boolean whether the named header exists - */ - public function has($name) - { - $name = strtolower($name); - return isset($this->_headers[$name]); - } - - /** - * Removes a header. - * @param string $name the name of the header to be removed. - * @return string the value of the removed header. Null is returned if the header does not exist. - */ - public function remove($name) - { - $name = strtolower($name); - if (isset($this->_headers[$name])) { - $value = $this->_headers[$name]; - unset($this->_headers[$name]); - return $value; - } else { - return null; - } - } - - /** - * Removes all headers. - */ - public function removeAll() - { - $this->_headers = []; - } - - /** - * Returns the collection as a PHP array. - * @return array the array representation of the collection. - * The array keys are header names, and the array values are the corresponding header values. - */ - public function toArray() - { - return $this->_headers; - } - - /** - * Returns whether there is a header with the specified name. - * This method is required by the SPL interface `ArrayAccess`. - * It is implicitly called when you use something like `isset($collection[$name])`. - * @param string $name the header name - * @return boolean whether the named header exists - */ - public function offsetExists($name) - { - return $this->has($name); - } - - /** - * Returns the header with the specified name. - * This method is required by the SPL interface `ArrayAccess`. - * It is implicitly called when you use something like `$header = $collection[$name];`. - * This is equivalent to [[get()]]. - * @param string $name the header name - * @return string the header value with the specified name, null if the named header does not exist. - */ - public function offsetGet($name) - { - return $this->get($name); - } - - /** - * Adds the header to the collection. - * This method is required by the SPL interface `ArrayAccess`. - * It is implicitly called when you use something like `$collection[$name] = $header;`. - * This is equivalent to [[add()]]. - * @param string $name the header name - * @param string $value the header value to be added - */ - public function offsetSet($name, $value) - { - $this->set($name, $value); - } - - /** - * Removes the named header. - * This method is required by the SPL interface `ArrayAccess`. - * It is implicitly called when you use something like `unset($collection[$name])`. - * This is equivalent to [[remove()]]. - * @param string $name the header name - */ - public function offsetUnset($name) - { - $this->remove($name); - } -} diff --git a/framework/yii/web/HttpCache.php b/framework/yii/web/HttpCache.php deleted file mode 100644 index 134df71..0000000 --- a/framework/yii/web/HttpCache.php +++ /dev/null @@ -1,160 +0,0 @@ - [ - * 'class' => \yii\web\HttpCache::className(), - * 'only' => ['list'], - * 'lastModified' => function ($action, $params) { - * $q = new Query(); - * return strtotime($q->from('users')->max('updated_timestamp')); - * }, - * // 'etagSeed' => function ($action, $params) { - * // return // generate etag seed here - * // } - * ], - * ]; - * } - * ~~~ - * - * @author Da:Sourcerer - * @author Qiang Xue - * @since 2.0 - */ -class HttpCache extends ActionFilter -{ - /** - * @var callback a PHP callback that returns the UNIX timestamp of the last modification time. - * The callback's signature should be: - * - * ~~~ - * function ($action, $params) - * ~~~ - * - * where `$action` is the [[Action]] object that this filter is currently handling; - * `$params` takes the value of [[params]]. The callback should return a UNIX timestamp. - */ - public $lastModified; - /** - * @var callback a PHP callback that generates the Etag seed string. - * The callback's signature should be: - * - * ~~~ - * function ($action, $params) - * ~~~ - * - * where `$action` is the [[Action]] object that this filter is currently handling; - * `$params` takes the value of [[params]]. The callback should return a string serving - * as the seed for generating an Etag. - */ - public $etagSeed; - /** - * @var mixed additional parameters that should be passed to the [[lastModified]] and [[etagSeed]] callbacks. - */ - public $params; - /** - * @var string HTTP cache control header. If null, the header will not be sent. - */ - public $cacheControlHeader = 'max-age=3600, public'; - - /** - * This method is invoked right before an action is to be executed (after all possible filters.) - * You may override this method to do last-minute preparation for the action. - * @param Action $action the action to be executed. - * @return boolean whether the action should continue to be executed. - */ - public function beforeAction($action) - { - $verb = Yii::$app->getRequest()->getMethod(); - if ($verb !== 'GET' && $verb !== 'HEAD' || $this->lastModified === null && $this->etagSeed === null) { - return true; - } - - $lastModified = $etag = null; - if ($this->lastModified !== null) { - $lastModified = call_user_func($this->lastModified, $action, $this->params); - } - if ($this->etagSeed !== null) { - $seed = call_user_func($this->etagSeed, $action, $this->params); - $etag = $this->generateEtag($seed); - } - - $this->sendCacheControlHeader(); - $response = Yii::$app->getResponse(); - if ($etag !== null) { - $response->getHeaders()->set('Etag', $etag); - } - - if ($this->validateCache($lastModified, $etag)) { - $response->setStatusCode(304); - return false; - } - - if ($lastModified !== null) { - $response->getHeaders()->set('Last-Modified', gmdate('D, d M Y H:i:s', $lastModified) . ' GMT'); - } - return true; - } - - /** - * Validates if the HTTP cache contains valid content. - * @param integer $lastModified the calculated Last-Modified value in terms of a UNIX timestamp. - * If null, the Last-Modified header will not be validated. - * @param string $etag the calculated ETag value. If null, the ETag header will not be validated. - * @return boolean whether the HTTP cache is still valid. - */ - protected function validateCache($lastModified, $etag) - { - if ($lastModified !== null && (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) < $lastModified)) { - return false; - } else { - return $etag === null || isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag; - } - } - - /** - * Sends the cache control header to the client - * @see cacheControl - */ - protected function sendCacheControlHeader() - { - session_cache_limiter('public'); - $headers = Yii::$app->getResponse()->getHeaders(); - $headers->set('Pragma'); - if ($this->cacheControlHeader !== null) { - $headers->set('Cache-Control', $this->cacheControlHeader); - } - } - - /** - * Generates an Etag from the given seed string. - * @param string $seed Seed for the ETag - * @return string the generated Etag - */ - protected function generateEtag($seed) - { - return '"' . base64_encode(sha1($seed, true)) . '"'; - } -} diff --git a/framework/yii/web/HttpException.php b/framework/yii/web/HttpException.php deleted file mode 100644 index 2398437..0000000 --- a/framework/yii/web/HttpException.php +++ /dev/null @@ -1,72 +0,0 @@ - - * @since 2.0 - */ -class HttpException extends UserException -{ - /** - * @var integer HTTP status code, such as 403, 404, 500, etc. - */ - public $statusCode; - - /** - * Constructor. - * @param integer $status HTTP status code, such as 404, 500, etc. - * @param string $message error message - * @param integer $code error code - * @param \Exception $previous The previous exception used for the exception chaining. - */ - public function __construct($status, $message = null, $code = 0, \Exception $previous = null) - { - $this->statusCode = $status; - parent::__construct($message, $code, $previous); - } - - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - if (isset(Response::$httpStatuses[$this->statusCode])) { - return Response::$httpStatuses[$this->statusCode]; - } else { - return 'Error'; - } - } - - /** - * Returns the array representation of this object. - * @return array the array representation of this object. - */ - public function toArray() - { - $array = parent::toArray(); - $array['status'] = $this->statusCode; - return $array; - } -} diff --git a/framework/yii/web/IdentityInterface.php b/framework/yii/web/IdentityInterface.php deleted file mode 100644 index c796b50..0000000 --- a/framework/yii/web/IdentityInterface.php +++ /dev/null @@ -1,81 +0,0 @@ -id; - * } - * - * public function getAuthKey() - * { - * return $this->authKey; - * } - * - * public function validateAuthKey($authKey) - * { - * return $this->authKey === $authKey; - * } - * } - * ~~~ - * - * @author Qiang Xue - * @since 2.0 - */ -interface IdentityInterface -{ - /** - * Finds an identity by the given ID. - * @param string|integer $id the ID to be looked for - * @return IdentityInterface the identity object that matches the given ID. - * Null should be returned if such an identity cannot be found - * or the identity is not in an active state (disabled, deleted, etc.) - */ - public static function findIdentity($id); - /** - * Returns an ID that can uniquely identify a user identity. - * @return string|integer an ID that uniquely identifies a user identity. - */ - public function getId(); - /** - * Returns a key that can be used to check the validity of a given identity ID. - * - * The key should be unique for each individual user, and should be persistent - * so that it can be used to check the validity of the user identity. - * - * The space of such keys should be big enough to defeat potential identity attacks. - * - * This is required if [[User::enableAutoLogin]] is enabled. - * @return string a key that is used to check the validity of a given identity ID. - * @see validateAuthKey() - */ - public function getAuthKey(); - /** - * Validates the given auth key. - * - * This is required if [[User::enableAutoLogin]] is enabled. - * @param string $authKey the given auth key - * @return boolean whether the given auth key is valid. - * @see getAuthKey() - */ - public function validateAuthKey($authKey); -} diff --git a/framework/yii/web/JqueryAsset.php b/framework/yii/web/JqueryAsset.php deleted file mode 100644 index 90d2df6..0000000 --- a/framework/yii/web/JqueryAsset.php +++ /dev/null @@ -1,22 +0,0 @@ - - * @since 2.0 - */ -class JqueryAsset extends AssetBundle -{ - public $sourcePath = '@vendor/yiisoft/jquery'; - public $js = [ - 'jquery.js', - ]; -} diff --git a/framework/yii/web/JsExpression.php b/framework/yii/web/JsExpression.php deleted file mode 100644 index 1d05b57..0000000 --- a/framework/yii/web/JsExpression.php +++ /dev/null @@ -1,47 +0,0 @@ - - * @since 2.0 - */ -class JsExpression extends Object -{ - /** - * @var string the JavaScript expression represented by this object - */ - public $expression; - - /** - * Constructor. - * @param string $expression the JavaScript expression represented by this object - * @param array $config additional configurations for this object - */ - public function __construct($expression, $config = []) - { - $this->expression = $expression; - parent::__construct($config); - } - - /** - * The PHP magic function converting an object into a string. - * @return string the JavaScript expression. - */ - public function __toString() - { - return $this->expression; - } -} diff --git a/framework/yii/web/MethodNotAllowedHttpException.php b/framework/yii/web/MethodNotAllowedHttpException.php deleted file mode 100644 index d894f57..0000000 --- a/framework/yii/web/MethodNotAllowedHttpException.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @since 2.0 - */ -class MethodNotAllowedHttpException extends HttpException -{ - /** - * Constructor. - * @param string $message error message - * @param integer $code error code - * @param \Exception $previous The previous exception used for the exception chaining. - */ - public function __construct($message = null, $code = 0, \Exception $previous = null) - { - parent::__construct(405, $message, $code, $previous); - } -} diff --git a/framework/yii/web/NotFoundHttpException.php b/framework/yii/web/NotFoundHttpException.php deleted file mode 100644 index 71f246d..0000000 --- a/framework/yii/web/NotFoundHttpException.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @since 2.0 - */ -class NotFoundHttpException extends HttpException -{ - /** - * Constructor. - * @param string $message error message - * @param integer $code error code - * @param \Exception $previous The previous exception used for the exception chaining. - */ - public function __construct($message = null, $code = 0, \Exception $previous = null) - { - parent::__construct(404, $message, $code, $previous); - } -} diff --git a/framework/yii/web/PageCache.php b/framework/yii/web/PageCache.php deleted file mode 100644 index 4c8cc50..0000000 --- a/framework/yii/web/PageCache.php +++ /dev/null @@ -1,150 +0,0 @@ - [ - * 'class' => \yii\web\PageCache::className(), - * 'only' => ['list'], - * 'duration' => 60, - * 'dependecy' => [ - * 'class' => 'yii\caching\DbDependency', - * 'sql' => 'SELECT COUNT(*) FROM post', - * ], - * 'variations' => [ - * Yii::$app->language, - * Yii::$app->user->id - * ] - * ], - * ]; - * } - * ~~~ - * - * @author Qiang Xue - * @since 2.0 - */ -class PageCache extends ActionFilter -{ - /** - * @var boolean whether the content being cached should be differentiated according to the route. - * A route consists of the requested controller ID and action ID. Defaults to true. - */ - public $varyByRoute = true; - /** - * @var string the application component ID of the [[\yii\caching\Cache|cache]] object. - */ - public $cache = 'cache'; - /** - * @var integer number of seconds that the data can remain valid in cache. - * Use 0 to indicate that the cached data will never expire. - */ - public $duration = 60; - /** - * @var array|Dependency the dependency that the cached content depends on. - * This can be either a [[Dependency]] object or a configuration array for creating the dependency object. - * For example, - * - * ~~~ - * [ - * 'class' => 'yii\caching\DbDependency', - * 'sql' => 'SELECT MAX(lastModified) FROM Post', - * ] - * ~~~ - * - * would make the output cache depends on the last modified time of all posts. - * If any post has its modification time changed, the cached content would be invalidated. - */ - public $dependency; - /** - * @var array list of factors that would cause the variation of the content being cached. - * Each factor is a string representing a variation (e.g. the language, a GET parameter). - * The following variation setting will cause the content to be cached in different versions - * according to the current application language: - * - * ~~~ - * [ - * Yii::$app->language, - * ] - * ~~~ - */ - public $variations; - /** - * @var boolean whether to enable the fragment cache. You may use this property to turn on and off - * the fragment cache according to specific setting (e.g. enable fragment cache only for GET requests). - */ - public $enabled = true; - /** - * @var \yii\base\View the view component to use for caching. If not set, the default application view component - * [[Application::view]] will be used. - */ - public $view; - - - public function init() - { - parent::init(); - if ($this->view === null) { - $this->view = Yii::$app->getView(); - } - } - - /** - * This method is invoked right before an action is to be executed (after all possible filters.) - * You may override this method to do last-minute preparation for the action. - * @param Action $action the action to be executed. - * @return boolean whether the action should continue to be executed. - */ - public function beforeAction($action) - { - $properties = []; - foreach (['cache', 'duration', 'dependency', 'variations', 'enabled'] as $name) { - $properties[$name] = $this->$name; - } - $id = $this->varyByRoute ? $action->getUniqueId() : __CLASS__; - ob_start(); - ob_implicit_flush(false); - if ($this->view->beginCache($id, $properties)) { - return true; - } else { - Yii::$app->getResponse()->content = ob_get_clean(); - return false; - } - } - - /** - * This method is invoked right after an action is executed. - * You may override this method to do some postprocessing for the action. - * @param Action $action the action just executed. - * @param mixed $result the action execution result - */ - public function afterAction($action, &$result) - { - echo $result; - $this->view->endCache(); - $result = ob_get_clean(); - } -} diff --git a/framework/yii/web/Request.php b/framework/yii/web/Request.php deleted file mode 100644 index f2298e6..0000000 --- a/framework/yii/web/Request.php +++ /dev/null @@ -1,1141 +0,0 @@ -request`. - * - * @property string $absoluteUrl The currently requested absolute URL. This property is read-only. - * @property string $acceptTypes User browser accept types, null if not present. This property is read-only. - * @property array $acceptedContentTypes The content types ordered by the preference level. The first element - * represents the most preferred content type. - * @property array $acceptedLanguages The languages ordered by the preference level. The first element - * represents the most preferred language. - * @property string $baseUrl The relative URL for the application. - * @property string $cookieValidationKey The secret key used for cookie validation. If it was not set - * previously, a random key will be generated and used. - * @property CookieCollection $cookies The cookie collection. This property is read-only. - * @property string $csrfToken The random token for CSRF validation. This property is read-only. - * @property string $csrfTokenFromHeader The CSRF token sent via [[CSRF_HEADER]] by browser. Null is returned - * if no such header is sent. This property is read-only. - * @property array $delete The DELETE request parameter values. This property is read-only. - * @property string $hostInfo Schema and hostname part (with port number if needed) of the request URL (e.g. - * `http://www.yiiframework.com`). - * @property boolean $isAjax Whether this is an AJAX (XMLHttpRequest) request. This property is read-only. - * @property boolean $isDelete Whether this is a DELETE request. This property is read-only. - * @property boolean $isFlash Whether this is an Adobe Flash or Adobe Flex request. This property is - * read-only. - * @property boolean $isGet Whether this is a GET request. This property is read-only. - * @property boolean $isHead Whether this is a HEAD request. This property is read-only. - * @property boolean $isOptions Whether this is a OPTIONS request. This property is read-only. - * @property boolean $isPatch Whether this is a PATCH request. This property is read-only. - * @property boolean $isPost Whether this is a POST request. This property is read-only. - * @property boolean $isPut Whether this is a PUT request. This property is read-only. - * @property boolean $isSecureConnection If the request is sent via secure channel (https). This property is - * read-only. - * @property string $maskedCsrfToken The masked CSRF token. This property is read-only. - * @property string $method Request method, such as GET, POST, HEAD, PUT, PATCH, DELETE. The value returned is - * turned into upper case. This property is read-only. - * @property array $patch The PATCH request parameter values. This property is read-only. - * @property string $pathInfo Part of the request URL that is after the entry script and before the question - * mark. Note, the returned path info is already URL-decoded. - * @property integer $port Port number for insecure requests. - * @property array $post The POST request parameter values. This property is read-only. - * @property string $preferredLanguage The language that the application should use. Null is returned if both - * [[getAcceptedLanguages()]] and `$languages` are empty. This property is read-only. - * @property array $put The PUT request parameter values. This property is read-only. - * @property string $queryString Part of the request URL that is after the question mark. This property is - * read-only. - * @property string $rawBody The request body. This property is read-only. - * @property string $referrer URL referrer, null if not present. This property is read-only. - * @property array $restParams The RESTful request parameters. - * @property string $scriptFile The entry script file path. - * @property string $scriptUrl The relative URL of the entry script. - * @property integer $securePort Port number for secure requests. - * @property string $serverName Server name. This property is read-only. - * @property integer $serverPort Server port number. This property is read-only. - * @property string $url The currently requested relative URL. Note that the URI returned is URL-encoded. - * @property string $userAgent User agent, null if not present. This property is read-only. - * @property string $userHost User host name, null if cannot be determined. This property is read-only. - * @property string $userIP User IP address. This property is read-only. - * - * @author Qiang Xue - * @since 2.0 - */ -class Request extends \yii\base\Request -{ - /** - * The name of the HTTP header for sending CSRF token. - */ - const CSRF_HEADER = 'X-CSRF-Token'; - /** - * The length of the CSRF token mask. - */ - const CSRF_MASK_LENGTH = 8; - - - /** - * @var boolean whether to enable CSRF (Cross-Site Request Forgery) validation. Defaults to true. - * When CSRF validation is enabled, forms submitted to an Yii Web application must be originated - * from the same application. If not, a 400 HTTP exception will be raised. - * - * Note, this feature requires that the user client accepts cookie. Also, to use this feature, - * forms submitted via POST method must contain a hidden input whose name is specified by [[csrfVar]]. - * You may use [[\yii\web\Html::beginForm()]] to generate his hidden input. - * - * In JavaScript, you may get the values of [[csrfVar]] and [[csrfToken]] via `yii.getCsrfVar()` and - * `yii.getCsrfToken()`, respectively. The [[\yii\web\YiiAsset]] asset must be registered. - * - * @see Controller::enableCsrfValidation - * @see http://en.wikipedia.org/wiki/Cross-site_request_forgery - */ - public $enableCsrfValidation = true; - /** - * @var string the name of the token used to prevent CSRF. Defaults to '_csrf'. - * This property is used only when [[enableCsrfValidation]] is true. - */ - public $csrfVar = '_csrf'; - /** - * @var array the configuration of the CSRF cookie. This property is used only when [[enableCsrfValidation]] is true. - * @see Cookie - */ - public $csrfCookie = ['httpOnly' => true]; - /** - * @var boolean whether cookies should be validated to ensure they are not tampered. Defaults to true. - */ - public $enableCookieValidation = true; - /** - * @var string|boolean the name of the POST parameter that is used to indicate if a request is a PUT, PATCH or DELETE - * request tunneled through POST. Default to '_method'. - * @see getMethod() - * @see getRestParams() - */ - public $restVar = '_method'; - - private $_cookies; - - - /** - * Resolves the current request into a route and the associated parameters. - * @return array the first element is the route, and the second is the associated parameters. - * @throws HttpException if the request cannot be resolved. - */ - public function resolve() - { - $result = Yii::$app->getUrlManager()->parseRequest($this); - if ($result !== false) { - list ($route, $params) = $result; - $_GET = array_merge($_GET, $params); - return [$route, $_GET]; - } else { - throw new NotFoundHttpException(Yii::t('yii', 'Page not found.')); - } - } - - /** - * Returns the method of the current request (e.g. GET, POST, HEAD, PUT, PATCH, DELETE). - * @return string request method, such as GET, POST, HEAD, PUT, PATCH, DELETE. - * The value returned is turned into upper case. - */ - public function getMethod() - { - if (isset($_POST[$this->restVar])) { - return strtoupper($_POST[$this->restVar]); - } else { - return isset($_SERVER['REQUEST_METHOD']) ? strtoupper($_SERVER['REQUEST_METHOD']) : 'GET'; - } - } - - /** - * Returns whether this is a GET request. - * @return boolean whether this is a GET request. - */ - public function getIsGet() - { - return $this->getMethod() === 'GET'; - } - - /** - * Returns whether this is an OPTIONS request. - * @return boolean whether this is a OPTIONS request. - */ - public function getIsOptions() - { - return $this->getMethod() === 'OPTIONS'; - } - - /** - * Returns whether this is a HEAD request. - * @return boolean whether this is a HEAD request. - */ - public function getIsHead() - { - return $this->getMethod() === 'HEAD'; - } - - /** - * Returns whether this is a POST request. - * @return boolean whether this is a POST request. - */ - public function getIsPost() - { - return $this->getMethod() === 'POST'; - } - - /** - * Returns whether this is a DELETE request. - * @return boolean whether this is a DELETE request. - */ - public function getIsDelete() - { - return $this->getMethod() === 'DELETE'; - } - - /** - * Returns whether this is a PUT request. - * @return boolean whether this is a PUT request. - */ - public function getIsPut() - { - return $this->getMethod() === 'PUT'; - } - - /** - * Returns whether this is a PATCH request. - * @return boolean whether this is a PATCH request. - */ - public function getIsPatch() - { - return $this->getMethod() === 'PATCH'; - } - - /** - * Returns whether this is an AJAX (XMLHttpRequest) request. - * @return boolean whether this is an AJAX (XMLHttpRequest) request. - */ - public function getIsAjax() - { - return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest'; - } - - /** - * Returns whether this is an Adobe Flash or Flex request. - * @return boolean whether this is an Adobe Flash or Adobe Flex request. - */ - public function getIsFlash() - { - return isset($_SERVER['HTTP_USER_AGENT']) && - (stripos($_SERVER['HTTP_USER_AGENT'], 'Shockwave') !== false || stripos($_SERVER['HTTP_USER_AGENT'], 'Flash') !== false); - } - - private $_restParams; - - /** - * Returns the request parameters for the RESTful request. - * @return array the RESTful request parameters - * @see getMethod() - */ - public function getRestParams() - { - if ($this->_restParams === null) { - if (isset($_POST[$this->restVar])) { - $this->_restParams = $_POST; - } else { - $this->_restParams = []; - mb_parse_str($this->getRawBody(), $this->_restParams); - } - } - return $this->_restParams; - } - - private $_rawBody; - - /** - * Returns the raw HTTP request body. - * @return string the request body - */ - public function getRawBody() - { - if ($this->_rawBody === null) { - $this->_rawBody = file_get_contents('php://input'); - } - return $this->_rawBody; - } - - /** - * Sets the RESTful parameters. - * @param array $values the RESTful parameters (name-value pairs) - */ - public function setRestParams($values) - { - $this->_restParams = $values; - } - - /** - * Returns the named RESTful parameter value. - * @param string $name the parameter name - * @param mixed $defaultValue the default parameter value if the parameter does not exist. - * @return mixed the parameter value - */ - public function getRestParam($name, $defaultValue = null) - { - $params = $this->getRestParams(); - return isset($params[$name]) ? $params[$name] : $defaultValue; - } - - /** - * Returns the named GET parameter value. - * If the GET parameter does not exist, the second parameter to this method will be returned. - * @param string $name the GET parameter name. If not specified, whole $_GET is returned. - * @param mixed $defaultValue the default parameter value if the GET parameter does not exist. - * @return mixed the GET parameter value - * @see getPost() - */ - public function get($name = null, $defaultValue = null) - { - if ($name === null) { - return $_GET; - } - return isset($_GET[$name]) ? $_GET[$name] : $defaultValue; - } - - /** - * Returns the named POST parameter value. - * If the POST parameter does not exist, the second parameter to this method will be returned. - * @param string $name the POST parameter name. If not specified, whole $_POST is returned. - * @param mixed $defaultValue the default parameter value if the POST parameter does not exist. - * @property array the POST request parameter values - * @return mixed the POST parameter value - * @see get() - */ - public function getPost($name = null, $defaultValue = null) - { - if ($name === null) { - return $_POST; - } - return isset($_POST[$name]) ? $_POST[$name] : $defaultValue; - } - - /** - * Returns the named DELETE parameter value. - * @param string $name the DELETE parameter name. If not specified, an array of DELETE parameters is returned. - * @param mixed $defaultValue the default parameter value if the DELETE parameter does not exist. - * @property array the DELETE request parameter values - * @return mixed the DELETE parameter value - */ - public function getDelete($name = null, $defaultValue = null) - { - if ($name === null) { - return $this->getRestParams(); - } - return $this->getIsDelete() ? $this->getRestParam($name, $defaultValue) : null; - } - - /** - * Returns the named PUT parameter value. - * @param string $name the PUT parameter name. If not specified, an array of PUT parameters is returned. - * @param mixed $defaultValue the default parameter value if the PUT parameter does not exist. - * @property array the PUT request parameter values - * @return mixed the PUT parameter value - */ - public function getPut($name = null, $defaultValue = null) - { - if ($name === null) { - return $this->getRestParams(); - } - return $this->getIsPut() ? $this->getRestParam($name, $defaultValue) : null; - } - - /** - * Returns the named PATCH parameter value. - * @param string $name the PATCH parameter name. If not specified, an array of PATCH parameters is returned. - * @param mixed $defaultValue the default parameter value if the PATCH parameter does not exist. - * @property array the PATCH request parameter values - * @return mixed the PATCH parameter value - */ - public function getPatch($name = null, $defaultValue = null) - { - if ($name === null) { - return $this->getRestParams(); - } - return $this->getIsPatch() ? $this->getRestParam($name, $defaultValue) : null; - } - - private $_hostInfo; - - /** - * Returns the schema and host part of the current request URL. - * The returned URL does not have an ending slash. - * By default this is determined based on the user request information. - * You may explicitly specify it by setting the [[setHostInfo()|hostInfo]] property. - * @return string schema and hostname part (with port number if needed) of the request URL (e.g. `http://www.yiiframework.com`) - * @see setHostInfo() - */ - public function getHostInfo() - { - if ($this->_hostInfo === null) { - $secure = $this->getIsSecureConnection(); - $http = $secure ? 'https' : 'http'; - if (isset($_SERVER['HTTP_HOST'])) { - $this->_hostInfo = $http . '://' . $_SERVER['HTTP_HOST']; - } else { - $this->_hostInfo = $http . '://' . $_SERVER['SERVER_NAME']; - $port = $secure ? $this->getSecurePort() : $this->getPort(); - if (($port !== 80 && !$secure) || ($port !== 443 && $secure)) { - $this->_hostInfo .= ':' . $port; - } - } - } - - return $this->_hostInfo; - } - - /** - * Sets the schema and host part of the application URL. - * This setter is provided in case the schema and hostname cannot be determined - * on certain Web servers. - * @param string $value the schema and host part of the application URL. The trailing slashes will be removed. - */ - public function setHostInfo($value) - { - $this->_hostInfo = rtrim($value, '/'); - } - - private $_baseUrl; - - /** - * Returns the relative URL for the application. - * This is similar to [[scriptUrl]] except that it does not include the script file name, - * and the ending slashes are removed. - * @return string the relative URL for the application - * @see setScriptUrl() - */ - public function getBaseUrl() - { - if ($this->_baseUrl === null) { - $this->_baseUrl = rtrim(dirname($this->getScriptUrl()), '\\/'); - } - return $this->_baseUrl; - } - - /** - * Sets the relative URL for the application. - * By default the URL is determined based on the entry script URL. - * This setter is provided in case you want to change this behavior. - * @param string $value the relative URL for the application - */ - public function setBaseUrl($value) - { - $this->_baseUrl = $value; - } - - private $_scriptUrl; - - /** - * Returns the relative URL of the entry script. - * The implementation of this method referenced Zend_Controller_Request_Http in Zend Framework. - * @return string the relative URL of the entry script. - * @throws InvalidConfigException if unable to determine the entry script URL - */ - public function getScriptUrl() - { - if ($this->_scriptUrl === null) { - $scriptFile = $this->getScriptFile(); - $scriptName = basename($scriptFile); - if (basename($_SERVER['SCRIPT_NAME']) === $scriptName) { - $this->_scriptUrl = $_SERVER['SCRIPT_NAME']; - } elseif (basename($_SERVER['PHP_SELF']) === $scriptName) { - $this->_scriptUrl = $_SERVER['PHP_SELF']; - } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $scriptName) { - $this->_scriptUrl = $_SERVER['ORIG_SCRIPT_NAME']; - } elseif (($pos = strpos($_SERVER['PHP_SELF'], '/' . $scriptName)) !== false) { - $this->_scriptUrl = substr($_SERVER['SCRIPT_NAME'], 0, $pos) . '/' . $scriptName; - } elseif (isset($_SERVER['DOCUMENT_ROOT']) && strpos($scriptFile, $_SERVER['DOCUMENT_ROOT']) === 0) { - $this->_scriptUrl = str_replace('\\', '/', str_replace($_SERVER['DOCUMENT_ROOT'], '', $scriptFile)); - } else { - throw new InvalidConfigException('Unable to determine the entry script URL.'); - } - } - return $this->_scriptUrl; - } - - /** - * Sets the relative URL for the application entry script. - * This setter is provided in case the entry script URL cannot be determined - * on certain Web servers. - * @param string $value the relative URL for the application entry script. - */ - public function setScriptUrl($value) - { - $this->_scriptUrl = '/' . trim($value, '/'); - } - - private $_scriptFile; - - /** - * Returns the entry script file path. - * The default implementation will simply return `$_SERVER['SCRIPT_FILENAME']`. - * @return string the entry script file path - */ - public function getScriptFile() - { - return isset($this->_scriptFile) ? $this->_scriptFile : $_SERVER['SCRIPT_FILENAME']; - } - - /** - * Sets the entry script file path. - * The entry script file path normally can be obtained from `$_SERVER['SCRIPT_FILENAME']`. - * If your server configuration does not return the correct value, you may configure - * this property to make it right. - * @param string $value the entry script file path. - */ - public function setScriptFile($value) - { - $this->_scriptFile = $value; - } - - private $_pathInfo; - - /** - * Returns the path info of the currently requested URL. - * A path info refers to the part that is after the entry script and before the question mark (query string). - * The starting and ending slashes are both removed. - * @return string part of the request URL that is after the entry script and before the question mark. - * Note, the returned path info is already URL-decoded. - * @throws InvalidConfigException if the path info cannot be determined due to unexpected server configuration - */ - public function getPathInfo() - { - if ($this->_pathInfo === null) { - $this->_pathInfo = $this->resolvePathInfo(); - } - return $this->_pathInfo; - } - - /** - * Sets the path info of the current request. - * This method is mainly provided for testing purpose. - * @param string $value the path info of the current request - */ - public function setPathInfo($value) - { - $this->_pathInfo = ltrim($value, '/'); - } - - /** - * Resolves the path info part of the currently requested URL. - * A path info refers to the part that is after the entry script and before the question mark (query string). - * The starting slashes are both removed (ending slashes will be kept). - * @return string part of the request URL that is after the entry script and before the question mark. - * Note, the returned path info is decoded. - * @throws InvalidConfigException if the path info cannot be determined due to unexpected server configuration - */ - protected function resolvePathInfo() - { - $pathInfo = $this->getUrl(); - - if (($pos = strpos($pathInfo, '?')) !== false) { - $pathInfo = substr($pathInfo, 0, $pos); - } - - $pathInfo = urldecode($pathInfo); - - // try to encode in UTF8 if not so - // http://w3.org/International/questions/qa-forms-utf-8.html - if (!preg_match('%^(?: - [\x09\x0A\x0D\x20-\x7E] # ASCII - | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte - | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs - | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte - | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates - | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 - | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 - | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 - )*$%xs', $pathInfo)) { - $pathInfo = utf8_encode($pathInfo); - } - - $scriptUrl = $this->getScriptUrl(); - $baseUrl = $this->getBaseUrl(); - if (strpos($pathInfo, $scriptUrl) === 0) { - $pathInfo = substr($pathInfo, strlen($scriptUrl)); - } elseif ($baseUrl === '' || strpos($pathInfo, $baseUrl) === 0) { - $pathInfo = substr($pathInfo, strlen($baseUrl)); - } elseif (isset($_SERVER['PHP_SELF']) && strpos($_SERVER['PHP_SELF'], $scriptUrl) === 0) { - $pathInfo = substr($_SERVER['PHP_SELF'], strlen($scriptUrl)); - } else { - throw new InvalidConfigException('Unable to determine the path info of the current request.'); - } - - if ($pathInfo === '/') { - $pathInfo = ''; - } else if ($pathInfo[0] === '/') { - $pathInfo = substr($pathInfo, 1); - } - - return $pathInfo; - } - - /** - * Returns the currently requested absolute URL. - * This is a shortcut to the concatenation of [[hostInfo]] and [[url]]. - * @return string the currently requested absolute URL. - */ - public function getAbsoluteUrl() - { - return $this->getHostInfo() . $this->getUrl(); - } - - private $_url; - - /** - * Returns the currently requested relative URL. - * This refers to the portion of the URL that is after the [[hostInfo]] part. - * It includes the [[queryString]] part if any. - * @return string the currently requested relative URL. Note that the URI returned is URL-encoded. - * @throws InvalidConfigException if the URL cannot be determined due to unusual server configuration - */ - public function getUrl() - { - if ($this->_url === null) { - $this->_url = $this->resolveRequestUri(); - } - return $this->_url; - } - - /** - * Sets the currently requested relative URL. - * The URI must refer to the portion that is after [[hostInfo]]. - * Note that the URI should be URL-encoded. - * @param string $value the request URI to be set - */ - public function setUrl($value) - { - $this->_url = $value; - } - - /** - * Resolves the request URI portion for the currently requested URL. - * This refers to the portion that is after the [[hostInfo]] part. It includes the [[queryString]] part if any. - * The implementation of this method referenced Zend_Controller_Request_Http in Zend Framework. - * @return string|boolean the request URI portion for the currently requested URL. - * Note that the URI returned is URL-encoded. - * @throws InvalidConfigException if the request URI cannot be determined due to unusual server configuration - */ - protected function resolveRequestUri() - { - if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // IIS - $requestUri = $_SERVER['HTTP_X_REWRITE_URL']; - } elseif (isset($_SERVER['REQUEST_URI'])) { - $requestUri = $_SERVER['REQUEST_URI']; - if ($requestUri !== '' && $requestUri[0] !== '/') { - $requestUri = preg_replace('/^(http|https):\/\/[^\/]+/i', '', $requestUri); - } - } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0 CGI - $requestUri = $_SERVER['ORIG_PATH_INFO']; - if (!empty($_SERVER['QUERY_STRING'])) { - $requestUri .= '?' . $_SERVER['QUERY_STRING']; - } - } else { - throw new InvalidConfigException('Unable to determine the request URI.'); - } - return $requestUri; - } - - /** - * Returns part of the request URL that is after the question mark. - * @return string part of the request URL that is after the question mark - */ - public function getQueryString() - { - return isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ''; - } - - /** - * Return if the request is sent via secure channel (https). - * @return boolean if the request is sent via secure channel (https) - */ - public function getIsSecureConnection() - { - return isset($_SERVER['HTTPS']) && (strcasecmp($_SERVER['HTTPS'], 'on') === 0 || $_SERVER['HTTPS'] == 1) - || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0; - } - - /** - * Returns the server name. - * @return string server name - */ - public function getServerName() - { - return $_SERVER['SERVER_NAME']; - } - - /** - * Returns the server port number. - * @return integer server port number - */ - public function getServerPort() - { - return (int)$_SERVER['SERVER_PORT']; - } - - /** - * Returns the URL referrer, null if not present - * @return string URL referrer, null if not present - */ - public function getReferrer() - { - return isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null; - } - - /** - * Returns the user agent, null if not present. - * @return string user agent, null if not present - */ - public function getUserAgent() - { - return isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null; - } - - /** - * Returns the user IP address. - * @return string user IP address - */ - public function getUserIP() - { - return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1'; - } - - /** - * Returns the user host name, null if it cannot be determined. - * @return string user host name, null if cannot be determined - */ - public function getUserHost() - { - return isset($_SERVER['REMOTE_HOST']) ? $_SERVER['REMOTE_HOST'] : null; - } - - /** - * Returns user browser accept types, null if not present. - * @return string user browser accept types, null if not present - */ - public function getAcceptTypes() - { - return isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : null; - } - - private $_port; - - /** - * Returns the port to use for insecure requests. - * Defaults to 80, or the port specified by the server if the current - * request is insecure. - * @return integer port number for insecure requests. - * @see setPort() - */ - public function getPort() - { - if ($this->_port === null) { - $this->_port = !$this->getIsSecureConnection() && isset($_SERVER['SERVER_PORT']) ? (int)$_SERVER['SERVER_PORT'] : 80; - } - return $this->_port; - } - - /** - * Sets the port to use for insecure requests. - * This setter is provided in case a custom port is necessary for certain - * server configurations. - * @param integer $value port number. - */ - public function setPort($value) - { - if ($value != $this->_port) { - $this->_port = (int)$value; - $this->_hostInfo = null; - } - } - - private $_securePort; - - /** - * Returns the port to use for secure requests. - * Defaults to 443, or the port specified by the server if the current - * request is secure. - * @return integer port number for secure requests. - * @see setSecurePort() - */ - public function getSecurePort() - { - if ($this->_securePort === null) { - $this->_securePort = $this->getIsSecureConnection() && isset($_SERVER['SERVER_PORT']) ? (int)$_SERVER['SERVER_PORT'] : 443; - } - return $this->_securePort; - } - - /** - * Sets the port to use for secure requests. - * This setter is provided in case a custom port is necessary for certain - * server configurations. - * @param integer $value port number. - */ - public function setSecurePort($value) - { - if ($value != $this->_securePort) { - $this->_securePort = (int)$value; - $this->_hostInfo = null; - } - } - - private $_contentTypes; - - /** - * Returns the content types accepted by the end user. - * This is determined by the `Accept` HTTP header. - * @return array the content types ordered by the preference level. The first element - * represents the most preferred content type. - */ - public function getAcceptedContentTypes() - { - if ($this->_contentTypes === null) { - if (isset($_SERVER['HTTP_ACCEPT'])) { - $this->_contentTypes = $this->parseAcceptHeader($_SERVER['HTTP_ACCEPT']); - } else { - $this->_contentTypes = []; - } - } - return $this->_contentTypes; - } - - /** - * @param array $value the content types that are accepted by the end user. They should - * be ordered by the preference level. - */ - public function setAcceptedContentTypes($value) - { - $this->_contentTypes = $value; - } - - private $_languages; - - /** - * Returns the languages accepted by the end user. - * This is determined by the `Accept-Language` HTTP header. - * @return array the languages ordered by the preference level. The first element - * represents the most preferred language. - */ - public function getAcceptedLanguages() - { - if ($this->_languages === null) { - if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { - $this->_languages = $this->parseAcceptHeader($_SERVER['HTTP_ACCEPT_LANGUAGE']); - } else { - $this->_languages = []; - } - } - return $this->_languages; - } - - /** - * @param array $value the languages that are accepted by the end user. They should - * be ordered by the preference level. - */ - public function setAcceptedLanguages($value) - { - $this->_languages = $value; - } - - /** - * Parses the given `Accept` (or `Accept-Language`) header. - * This method will return the accepted values ordered by their preference level. - * @param string $header the header to be parsed - * @return array the accept values ordered by their preference level. - */ - protected function parseAcceptHeader($header) - { - $accepts = []; - $n = preg_match_all('/\s*([\w\/\-\*]+)\s*(?:;\s*q\s*=\s*([\d\.]+))?[^,]*/', $header, $matches, PREG_SET_ORDER); - for ($i = 0; $i < $n; ++$i) { - if (!empty($matches[$i][1])) { - $accepts[] = [$matches[$i][1], isset($matches[$i][2]) ? (float)$matches[$i][2] : 1, $i]; - } - } - usort($accepts, function ($a, $b) { - if ($a[1] > $b[1]) { - return -1; - } elseif ($a[1] < $b[1]) { - return 1; - } elseif ($a[0] === $b[0]) { - return $a[2] > $b[2] ? 1 : -1; - } elseif ($a[0] === '*/*') { - return 1; - } elseif ($b[0] === '*/*') { - return -1; - } else { - $wa = $a[0][strlen($a[0]) - 1] === '*'; - $wb = $b[0][strlen($b[0]) - 1] === '*'; - if ($wa xor $wb) { - return $wa ? 1 : -1; - } else { - return $a[2] > $b[2] ? 1 : -1; - } - } - }); - $result = []; - foreach ($accepts as $accept) { - $result[] = $accept[0]; - } - return array_unique($result); - } - - /** - * Returns the user-preferred language that should be used by this application. - * The language resolution is based on the user preferred languages and the languages - * supported by the application. The method will try to find the best match. - * @param array $languages a list of the languages supported by the application. - * If empty, this method will return the first language returned by [[getAcceptedLanguages()]]. - * @return string the language that the application should use. Null is returned if both [[getAcceptedLanguages()]] - * and `$languages` are empty. - */ - public function getPreferredLanguage($languages = []) - { - $acceptedLanguages = $this->getAcceptedLanguages(); - if (empty($languages)) { - return isset($acceptedLanguages[0]) ? $acceptedLanguages[0] : null; - } - foreach ($acceptedLanguages as $acceptedLanguage) { - $acceptedLanguage = str_replace('_', '-', strtolower($acceptedLanguage)); - foreach ($languages as $language) { - $language = str_replace('_', '-', strtolower($language)); - // en-us==en-us, en==en-us, en-us==en - if ($language === $acceptedLanguage || strpos($acceptedLanguage, $language . '-') === 0 || strpos($language, $acceptedLanguage . '-') === 0) { - return $language; - } - } - } - return reset($languages); - } - - /** - * Returns the cookie collection. - * Through the returned cookie collection, you may access a cookie using the following syntax: - * - * ~~~ - * $cookie = $request->cookies['name'] - * if ($cookie !== null) { - * $value = $cookie->value; - * } - * - * // alternatively - * $value = $request->cookies->getValue('name'); - * ~~~ - * - * @return CookieCollection the cookie collection. - */ - public function getCookies() - { - if ($this->_cookies === null) { - $this->_cookies = new CookieCollection($this->loadCookies(), [ - 'readOnly' => true, - ]); - } - return $this->_cookies; - } - - /** - * Converts `$_COOKIE` into an array of [[Cookie]]. - * @return array the cookies obtained from request - */ - protected function loadCookies() - { - $cookies = []; - if ($this->enableCookieValidation) { - $key = $this->getCookieValidationKey(); - foreach ($_COOKIE as $name => $value) { - if (is_string($value) && ($value = Security::validateData($value, $key)) !== false) { - $cookies[$name] = new Cookie([ - 'name' => $name, - 'value' => @unserialize($value), - ]); - } - } - } else { - foreach ($_COOKIE as $name => $value) { - $cookies[$name] = new Cookie([ - 'name' => $name, - 'value' => $value, - ]); - } - } - return $cookies; - } - - private $_cookieValidationKey; - - /** - * @return string the secret key used for cookie validation. If it was not set previously, - * a random key will be generated and used. - */ - public function getCookieValidationKey() - { - if ($this->_cookieValidationKey === null) { - $this->_cookieValidationKey = Security::getSecretKey(__CLASS__ . '/' . Yii::$app->id); - } - return $this->_cookieValidationKey; - } - - /** - * Sets the secret key used for cookie validation. - * @param string $value the secret key used for cookie validation. - */ - public function setCookieValidationKey($value) - { - $this->_cookieValidationKey = $value; - } - - /** - * @var Cookie - */ - private $_csrfCookie; - - /** - * Returns the random token used to perform CSRF validation. - * The token will be read from cookie first. If not found, a new token will be generated. - * @return string the random token for CSRF validation. - * @see enableCsrfValidation - */ - public function getCsrfToken() - { - if ($this->_csrfCookie === null) { - $this->_csrfCookie = $this->getCookies()->get($this->csrfVar); - if ($this->_csrfCookie === null) { - $this->_csrfCookie = $this->createCsrfCookie(); - Yii::$app->getResponse()->getCookies()->add($this->_csrfCookie); - } - } - - return $this->_csrfCookie->value; - } - - private $_maskedCsrfToken; - - /** - * Returns the masked CSRF token. - * This method will apply a mask to [[csrfToken]] so that the resulting CSRF token - * will not be exploited by [BREACH attacks](http://breachattack.com/). - * @return string the masked CSRF token. - */ - public function getMaskedCsrfToken() - { - if ($this->_maskedCsrfToken === null) { - $token = $this->getCsrfToken(); - $mask = Security::generateRandomKey(self::CSRF_MASK_LENGTH); - // The + sign may be decoded as blank space later, which will fail the validation - $this->_maskedCsrfToken = str_replace('+', '.', base64_encode($mask . $this->xorTokens($token, $mask))); - } - return $this->_maskedCsrfToken; - } - - /** - * Returns the XOR result of two strings. - * If the two strings are of different lengths, the shorter one will be padded to the length of the longer one. - * @param string $token1 - * @param string $token2 - * @return string the XOR result - */ - private function xorTokens($token1, $token2) - { - $n1 = StringHelper::byteLength($token1); - $n2 = StringHelper::byteLength($token2); - if ($n1 > $n2) { - $token2 = str_pad($token2, $n1, $token2); - } elseif ($n1 < $n2) { - $token1 = str_pad($token1, $n2, $token1); - } - return $token1 ^ $token2; - } - - /** - * @return string the CSRF token sent via [[CSRF_HEADER]] by browser. Null is returned if no such header is sent. - */ - public function getCsrfTokenFromHeader() - { - $key = 'HTTP_' . str_replace('-', '_', strtoupper(self::CSRF_HEADER)); - return isset($_SERVER[$key]) ? $_SERVER[$key] : null; - } - - /** - * Creates a cookie with a randomly generated CSRF token. - * Initial values specified in [[csrfCookie]] will be applied to the generated cookie. - * @return Cookie the generated cookie - * @see enableCsrfValidation - */ - protected function createCsrfCookie() - { - $options = $this->csrfCookie; - $options['name'] = $this->csrfVar; - $options['value'] = Security::generateRandomKey(); - return new Cookie($options); - } - - /** - * Performs the CSRF validation. - * The method will compare the CSRF token obtained from a cookie and from a POST field. - * If they are different, a CSRF attack is detected and a 400 HTTP exception will be raised. - * This method is called in [[Controller::beforeAction()]]. - * @return boolean whether CSRF token is valid. If [[enableCsrfValidation]] is false, this method will return true. - */ - public function validateCsrfToken() - { - $method = $this->getMethod(); - if (!$this->enableCsrfValidation || !in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { - return true; - } - $trueToken = $this->getCookies()->getValue($this->csrfVar); - switch ($method) { - case 'PUT': - $token = $this->getPut($this->csrfVar); - break; - case 'PATCH': - $token = $this->getPatch($this->csrfVar); - break; - case 'DELETE': - $token = $this->getDelete($this->csrfVar); - break; - default: - $token = $this->getPost($this->csrfVar); - break; - } - return $this->validateCsrfTokenInternal($token, $trueToken) - || $this->validateCsrfTokenInternal($this->getCsrfTokenFromHeader(), $trueToken); - } - - private function validateCsrfTokenInternal($token, $trueToken) - { - $token = base64_decode(str_replace('.', '+', $token)); - $n = StringHelper::byteLength($token); - if ($n <= self::CSRF_MASK_LENGTH) { - return false; - } - $mask = StringHelper::byteSubstr($token, 0, self::CSRF_MASK_LENGTH); - $token = StringHelper::byteSubstr($token, self::CSRF_MASK_LENGTH, $n - self::CSRF_MASK_LENGTH); - $token = $this->xorTokens($mask, $token); - return $token === $trueToken; - } -} diff --git a/framework/yii/web/Response.php b/framework/yii/web/Response.php deleted file mode 100644 index 660183d..0000000 --- a/framework/yii/web/Response.php +++ /dev/null @@ -1,878 +0,0 @@ -response`. - * - * You can modify its configuration by adding an array to your application config under `components` - * as it is shown in the following example: - * - * ~~~ - * 'response' => [ - * 'format' => yii\web\Response::FORMAT_JSON, - * 'charset' => 'UTF-8', - * // ... - * ] - * ~~~ - * - * @property CookieCollection $cookies The cookie collection. This property is read-only. - * @property HeaderCollection $headers The header collection. This property is read-only. - * @property boolean $isClientError Whether this response indicates a client error. This property is - * read-only. - * @property boolean $isEmpty Whether this response is empty. This property is read-only. - * @property boolean $isForbidden Whether this response indicates the current request is forbidden. This - * property is read-only. - * @property boolean $isInformational Whether this response is informational. This property is read-only. - * @property boolean $isInvalid Whether this response has a valid [[statusCode]]. This property is read-only. - * @property boolean $isNotFound Whether this response indicates the currently requested resource is not - * found. This property is read-only. - * @property boolean $isOk Whether this response is OK. This property is read-only. - * @property boolean $isRedirection Whether this response is a redirection. This property is read-only. - * @property boolean $isServerError Whether this response indicates a server error. This property is - * read-only. - * @property boolean $isSuccessful Whether this response is successful. This property is read-only. - * @property integer $statusCode The HTTP status code to send with the response. - * - * @author Qiang Xue - * @author Carsten Brandt - * @since 2.0 - */ -class Response extends \yii\base\Response -{ - /** - * @event ResponseEvent an event that is triggered at the beginning of [[send()]]. - */ - const EVENT_BEFORE_SEND = 'beforeSend'; - /** - * @event ResponseEvent an event that is triggered at the end of [[send()]]. - */ - const EVENT_AFTER_SEND = 'afterSend'; - /** - * @event ResponseEvent an event that is triggered right after [[prepare()]] is called in [[send()]]. - * You may respond to this event to filter the response content before it is sent to the client. - */ - const EVENT_AFTER_PREPARE = 'afterPrepare'; - - const FORMAT_RAW = 'raw'; - const FORMAT_HTML = 'html'; - const FORMAT_JSON = 'json'; - const FORMAT_JSONP = 'jsonp'; - const FORMAT_XML = 'xml'; - - /** - * @var string the response format. This determines how to convert [[data]] into [[content]] - * when the latter is not set. By default, the following formats are supported: - * - * - [[FORMAT_RAW]]: the data will be treated as the response content without any conversion. - * No extra HTTP header will be added. - * - [[FORMAT_HTML]]: the data will be treated as the response content without any conversion. - * The "Content-Type" header will set as "text/html" if it is not set previously. - * - [[FORMAT_JSON]]: the data will be converted into JSON format, and the "Content-Type" - * header will be set as "application/json". - * - [[FORMAT_JSONP]]: the data will be converted into JSONP format, and the "Content-Type" - * header will be set as "text/javascript". Note that in this case `$data` must be an array - * with "data" and "callback" elements. The former refers to the actual data to be sent, - * while the latter refers to the name of the JavaScript callback. - * - [[FORMAT_XML]]: the data will be converted into XML format. Please refer to [[XmlResponseFormatter]] - * for more details. - * - * You may customize the formatting process or support additional formats by configuring [[formatters]]. - * @see formatters - */ - public $format = self::FORMAT_HTML; - /** - * @var array the formatters for converting data into the response content of the specified [[format]]. - * The array keys are the format names, and the array values are the corresponding configurations - * for creating the formatter objects. - * @see format - */ - public $formatters; - /** - * @var mixed the original response data. When this is not null, it will be converted into [[content]] - * according to [[format]] when the response is being sent out. - * @see content - */ - public $data; - /** - * @var string the response content. When [[data]] is not null, it will be converted into [[content]] - * according to [[format]] when the response is being sent out. - * @see data - */ - public $content; - /** - * @var resource|array the stream to be sent. This can be a stream handle or an array of stream handle, - * the begin position and the end position. Note that when this property is set, the [[data]] and [[content]] - * properties will be ignored by [[send()]]. - */ - public $stream; - /** - * @var string the charset of the text response. If not set, it will use - * the value of [[Application::charset]]. - */ - public $charset; - /** - * @var string the HTTP status description that comes together with the status code. - * @see httpStatuses - */ - public $statusText = 'OK'; - /** - * @var string the version of the HTTP protocol to use. If not set, it will be determined via `$_SERVER['SERVER_PROTOCOL']`, - * or '1.1' if that is not available. - */ - public $version; - /** - * @var boolean whether the response has been sent. If this is true, calling [[send()]] will do nothing. - */ - public $isSent = false; - /** - * @var array list of HTTP status codes and the corresponding texts - */ - public static $httpStatuses = [ - 100 => 'Continue', - 101 => 'Switching Protocols', - 102 => 'Processing', - 118 => 'Connection timed out', - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - 207 => 'Multi-Status', - 208 => 'Already Reported', - 210 => 'Content Different', - 226 => 'IM Used', - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 306 => 'Reserved', - 307 => 'Temporary Redirect', - 308 => 'Permanent Redirect', - 310 => 'Too many Redirect', - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Time-out', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested range unsatisfiable', - 417 => 'Expectation failed', - 418 => 'I\'m a teapot', - 422 => 'Unprocessable entity', - 423 => 'Locked', - 424 => 'Method failure', - 425 => 'Unordered Collection', - 426 => 'Upgrade Required', - 428 => 'Precondition Required', - 429 => 'Too Many Requests', - 431 => 'Request Header Fields Too Large', - 449 => 'Retry With', - 450 => 'Blocked by Windows Parental Controls', - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway ou Proxy Error', - 503 => 'Service Unavailable', - 504 => 'Gateway Time-out', - 505 => 'HTTP Version not supported', - 507 => 'Insufficient storage', - 508 => 'Loop Detected', - 509 => 'Bandwidth Limit Exceeded', - 510 => 'Not Extended', - 511 => 'Network Authentication Required', - ]; - - /** - * @var integer the HTTP status code to send with the response. - */ - private $_statusCode = 200; - /** - * @var HeaderCollection - */ - private $_headers; - - /** - * Initializes this component. - */ - public function init() - { - if ($this->version === null) { - if (isset($_SERVER['SERVER_PROTOCOL']) && $_SERVER['SERVER_PROTOCOL'] === '1.0') { - $this->version = '1.0'; - } else { - $this->version = '1.1'; - } - } - if ($this->charset === null) { - $this->charset = Yii::$app->charset; - } - } - - /** - * @return integer the HTTP status code to send with the response. - */ - public function getStatusCode() - { - return $this->_statusCode; - } - - /** - * Sets the response status code. - * This method will set the corresponding status text if `$text` is null. - * @param integer $value the status code - * @param string $text the status text. If not set, it will be set automatically based on the status code. - * @throws InvalidParamException if the status code is invalid. - */ - public function setStatusCode($value, $text = null) - { - if ($value === null) { - $value = 200; - } - $this->_statusCode = (int)$value; - if ($this->getIsInvalid()) { - throw new InvalidParamException("The HTTP status code is invalid: $value"); - } - if ($text === null) { - $this->statusText = isset(static::$httpStatuses[$this->_statusCode]) ? static::$httpStatuses[$this->_statusCode] : ''; - } else { - $this->statusText = $text; - } - } - - /** - * Returns the header collection. - * The header collection contains the currently registered HTTP headers. - * @return HeaderCollection the header collection - */ - public function getHeaders() - { - if ($this->_headers === null) { - $this->_headers = new HeaderCollection; - } - return $this->_headers; - } - - /** - * Sends the response to the client. - */ - public function send() - { - if ($this->isSent) { - return; - } else { - $this->isSent = true; - } - $this->trigger(self::EVENT_BEFORE_SEND); - $this->prepare(); - $this->trigger(self::EVENT_AFTER_PREPARE); - $this->sendHeaders(); - $this->sendContent(); - $this->trigger(self::EVENT_AFTER_SEND); - } - - /** - * Clears the headers, cookies, content, status code of the response. - */ - public function clear() - { - $this->_headers = null; - $this->_cookies = null; - $this->_statusCode = 200; - $this->statusText = 'OK'; - $this->data = null; - $this->stream = null; - $this->content = null; - $this->isSent = false; - } - - /** - * Sends the response headers to the client - */ - protected function sendHeaders() - { - if (headers_sent()) { - return; - } - $statusCode = $this->getStatusCode(); - header("HTTP/{$this->version} $statusCode {$this->statusText}"); - if ($this->_headers) { - $headers = $this->getHeaders(); - foreach ($headers as $name => $values) { - $name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $name))); - foreach ($values as $value) { - header("$name: $value", false); - } - } - } - $this->sendCookies(); - } - - /** - * Sends the cookies to the client. - */ - protected function sendCookies() - { - if ($this->_cookies === null) { - return; - } - $request = Yii::$app->getRequest(); - if ($request->enableCookieValidation) { - $validationKey = $request->getCookieValidationKey(); - } - foreach ($this->getCookies() as $cookie) { - $value = $cookie->value; - if ($cookie->expire != 1 && isset($validationKey)) { - $value = Security::hashData(serialize($value), $validationKey); - } - setcookie($cookie->name, $value, $cookie->expire, $cookie->path, $cookie->domain, $cookie->secure, $cookie->httpOnly); - } - $this->getCookies()->removeAll(); - } - - /** - * Sends the response content to the client - */ - protected function sendContent() - { - if ($this->stream === null) { - echo $this->content; - return; - } - - set_time_limit(0); // Reset time limit for big files - $chunkSize = 8 * 1024 * 1024; // 8MB per chunk - - if (is_array($this->stream)) { - list ($handle, $begin, $end) = $this->stream; - fseek($handle, $begin); - while (!feof($handle) && ($pos = ftell($handle)) <= $end) { - if ($pos + $chunkSize > $end) { - $chunkSize = $end - $pos + 1; - } - echo fread($handle, $chunkSize); - flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit. - } - fclose($handle); - } else { - while (!feof($this->stream)) { - echo fread($this->stream, $chunkSize); - flush(); - } - fclose($this->stream); - } - } - - /** - * Sends a file to the browser. - * - * Note that this method only prepares the response for file sending. The file is not sent - * until [[send()]] is called explicitly or implicitly. The latter is done after you return from a controller action. - * - * @param string $filePath the path of the file to be sent. - * @param string $attachmentName the file name shown to the user. If null, it will be determined from `$filePath`. - * @param string $mimeType the MIME type of the content. If null, it will be guessed based on `$filePath` - * @return static the response object itself - */ - public function sendFile($filePath, $attachmentName = null, $mimeType = null) - { - if ($mimeType === null && ($mimeType = FileHelper::getMimeTypeByExtension($filePath)) === null) { - $mimeType = 'application/octet-stream'; - } - if ($attachmentName === null) { - $attachmentName = basename($filePath); - } - $handle = fopen($filePath, 'rb'); - $this->sendStreamAsFile($handle, $attachmentName, $mimeType); - - return $this; - } - - /** - * Sends the specified content as a file to the browser. - * - * Note that this method only prepares the response for file sending. The file is not sent - * until [[send()]] is called explicitly or implicitly. The latter is done after you return from a controller action. - * - * @param string $content the content to be sent. The existing [[content]] will be discarded. - * @param string $attachmentName the file name shown to the user. - * @param string $mimeType the MIME type of the content. - * @return static the response object itself - * @throws HttpException if the requested range is not satisfiable - */ - public function sendContentAsFile($content, $attachmentName, $mimeType = 'application/octet-stream') - { - $headers = $this->getHeaders(); - $contentLength = StringHelper::byteLength($content); - $range = $this->getHttpRange($contentLength); - if ($range === false) { - $headers->set('Content-Range', "bytes */$contentLength"); - throw new HttpException(416, 'Requested range not satisfiable'); - } - - $headers->setDefault('Pragma', 'public') - ->setDefault('Accept-Ranges', 'bytes') - ->setDefault('Expires', '0') - ->setDefault('Content-Type', $mimeType) - ->setDefault('Cache-Control', 'must-revalidate, post-check=0, pre-check=0') - ->setDefault('Content-Transfer-Encoding', 'binary') - ->setDefault('Content-Length', StringHelper::byteLength($content)) - ->setDefault('Content-Disposition', "attachment; filename=\"$attachmentName\""); - - list($begin, $end) = $range; - if ($begin !=0 || $end != $contentLength - 1) { - $this->setStatusCode(206); - $headers->set('Content-Range', "bytes $begin-$end/$contentLength"); - $this->content = StringHelper::byteSubstr($content, $begin, $end - $begin + 1); - } else { - $this->setStatusCode(200); - $this->content = $content; - } - - $this->format = self::FORMAT_RAW; - - return $this; - } - - /** - * Sends the specified stream as a file to the browser. - * - * Note that this method only prepares the response for file sending. The file is not sent - * until [[send()]] is called explicitly or implicitly. The latter is done after you return from a controller action. - * - * @param resource $handle the handle of the stream to be sent. - * @param string $attachmentName the file name shown to the user. - * @param string $mimeType the MIME type of the stream content. - * @return static the response object itself - * @throws HttpException if the requested range cannot be satisfied. - */ - public function sendStreamAsFile($handle, $attachmentName, $mimeType = 'application/octet-stream') - { - $headers = $this->getHeaders(); - fseek($handle, 0, SEEK_END); - $fileSize = ftell($handle); - - $range = $this->getHttpRange($fileSize); - if ($range === false) { - $headers->set('Content-Range', "bytes */$fileSize"); - throw new HttpException(416, 'Requested range not satisfiable'); - } - - list($begin, $end) = $range; - if ($begin !=0 || $end != $fileSize - 1) { - $this->setStatusCode(206); - $headers->set('Content-Range', "bytes $begin-$end/$fileSize"); - } else { - $this->setStatusCode(200); - } - - $length = $end - $begin + 1; - - $headers->setDefault('Pragma', 'public') - ->setDefault('Accept-Ranges', 'bytes') - ->setDefault('Expires', '0') - ->setDefault('Content-Type', $mimeType) - ->setDefault('Cache-Control', 'must-revalidate, post-check=0, pre-check=0') - ->setDefault('Content-Transfer-Encoding', 'binary') - ->setDefault('Content-Length', $length) - ->setDefault('Content-Disposition', "attachment; filename=\"$attachmentName\""); - $this->format = self::FORMAT_RAW; - $this->stream = [$handle, $begin, $end]; - - return $this; - } - - /** - * Determines the HTTP range given in the request. - * @param integer $fileSize the size of the file that will be used to validate the requested HTTP range. - * @return array|boolean the range (begin, end), or false if the range request is invalid. - */ - protected function getHttpRange($fileSize) - { - if (!isset($_SERVER['HTTP_RANGE']) || $_SERVER['HTTP_RANGE'] === '-') { - return [0, $fileSize - 1]; - } - if (!preg_match('/^bytes=(\d*)-(\d*)$/', $_SERVER['HTTP_RANGE'], $matches)) { - return false; - } - if ($matches[1] === '') { - $start = $fileSize - $matches[2]; - $end = $fileSize - 1; - } elseif ($matches[2] !== '') { - $start = $matches[1]; - $end = $matches[2]; - if ($end >= $fileSize) { - $end = $fileSize - 1; - } - } else { - $start = $matches[1]; - $end = $fileSize - 1; - } - if ($start < 0 || $start > $end) { - return false; - } else { - return [$start, $end]; - } - } - - /** - * Sends existing file to a browser as a download using x-sendfile. - * - * X-Sendfile is a feature allowing a web application to redirect the request for a file to the webserver - * that in turn processes the request, this way eliminating the need to perform tasks like reading the file - * and sending it to the user. When dealing with a lot of files (or very big files) this can lead to a great - * increase in performance as the web application is allowed to terminate earlier while the webserver is - * handling the request. - * - * The request is sent to the server through a special non-standard HTTP-header. - * When the web server encounters the presence of such header it will discard all output and send the file - * specified by that header using web server internals including all optimizations like caching-headers. - * - * As this header directive is non-standard different directives exists for different web servers applications: - * - * - Apache: [X-Sendfile](http://tn123.org/mod_xsendfile) - * - Lighttpd v1.4: [X-LIGHTTPD-send-file](http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file) - * - Lighttpd v1.5: [X-Sendfile](http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file) - * - Nginx: [X-Accel-Redirect](http://wiki.nginx.org/XSendfile) - * - Cherokee: [X-Sendfile and X-Accel-Redirect](http://www.cherokee-project.com/doc/other_goodies.html#x-sendfile) - * - * So for this method to work the X-SENDFILE option/module should be enabled by the web server and - * a proper xHeader should be sent. - * - * **Note** - * - * This option allows to download files that are not under web folders, and even files that are otherwise protected - * (deny from all) like `.htaccess`. - * - * **Side effects** - * - * If this option is disabled by the web server, when this method is called a download configuration dialog - * will open but the downloaded file will have 0 bytes. - * - * **Known issues** - * - * There is a Bug with Internet Explorer 6, 7 and 8 when X-SENDFILE is used over an SSL connection, it will show - * an error message like this: "Internet Explorer was not able to open this Internet site. The requested site - * is either unavailable or cannot be found.". You can work around this problem by removing the `Pragma`-header. - * - * **Example** - * - * ~~~ - * Yii::$app->response->xSendFile('/home/user/Pictures/picture1.jpg'); - * ~~~ - * - * @param string $filePath file name with full path - * @param string $mimeType the MIME type of the file. If null, it will be determined based on `$filePath`. - * @param string $attachmentName file name shown to the user. If null, it will be determined from `$filePath`. - * @param string $xHeader the name of the x-sendfile header. - * @return static the response object itself - */ - public function xSendFile($filePath, $attachmentName = null, $mimeType = null, $xHeader = 'X-Sendfile') - { - if ($mimeType === null && ($mimeType = FileHelper::getMimeTypeByExtension($filePath)) === null) { - $mimeType = 'application/octet-stream'; - } - if ($attachmentName === null) { - $attachmentName = basename($filePath); - } - - $this->getHeaders() - ->setDefault($xHeader, $filePath) - ->setDefault('Content-Type', $mimeType) - ->setDefault('Content-Disposition', "attachment; filename=\"$attachmentName\""); - - return $this; - } - - /** - * Redirects the browser to the specified URL. - * - * This method adds a "Location" header to the current response. Note that it does not send out - * the header until [[send()]] is called. In a controller action you may use this method as follows: - * - * ~~~ - * return Yii::$app->getResponse()->redirect($url); - * ~~~ - * - * In other places, if you want to send out the "Location" header immediately, you should use - * the following code: - * - * ~~~ - * Yii::$app->getResponse()->redirect($url)->send(); - * return; - * ~~~ - * - * In AJAX mode, this normally will not work as expected unless there are some - * client-side JavaScript code handling the redirection. To help achieve this goal, - * this method will send out a "X-Redirect" header instead of "Location". - * - * If you use the "yii" JavaScript module, it will handle the AJAX redirection as - * described above. Otherwise, you should write the following JavaScript code to - * handle the redirection: - * - * ~~~ - * $document.ajaxComplete(function (event, xhr, settings) { - * var url = xhr.getResponseHeader('X-Redirect'); - * if (url) { - * window.location = url; - * } - * }); - * ~~~ - * - * @param string|array $url the URL to be redirected to. This can be in one of the following formats: - * - * - a string representing a URL (e.g. "http://example.com") - * - a string representing a URL alias (e.g. "@example.com") - * - an array in the format of `[$route, ...name-value pairs...]` (e.g. `['site/index', 'ref' => 1]`). - * Note that the route is with respect to the whole application, instead of relative to a controller or module. - * [[Html::url()]] will be used to convert the array into a URL. - * - * Any relative URL will be converted into an absolute one by prepending it with the host info - * of the current request. - * - * @param integer $statusCode the HTTP status code. Defaults to 302. - * See - * for details about HTTP status code - * @return static the response object itself - */ - public function redirect($url, $statusCode = 302) - { - if (is_array($url) && isset($url[0])) { - // ensure the route is absolute - $url[0] = '/' . ltrim($url[0], '/'); - } - $url = Html::url($url); - if (strpos($url, '/') === 0 && strpos($url, '//') !== 0) { - $url = Yii::$app->getRequest()->getHostInfo() . $url; - } - - if (Yii::$app->getRequest()->getIsAjax()) { - $this->getHeaders()->set('X-Redirect', $url); - } else { - $this->getHeaders()->set('Location', $url); - } - $this->setStatusCode($statusCode); - - return $this; - } - - /** - * Refreshes the current page. - * The effect of this method call is the same as the user pressing the refresh button of his browser - * (without re-posting data). - * - * In a controller action you may use this method like this: - * - * ~~~ - * return Yii::$app->getResponse()->refresh(); - * ~~~ - * - * @param string $anchor the anchor that should be appended to the redirection URL. - * Defaults to empty. Make sure the anchor starts with '#' if you want to specify it. - * @return Response the response object itself - */ - public function refresh($anchor = '') - { - return $this->redirect(Yii::$app->getRequest()->getUrl() . $anchor); - } - - private $_cookies; - - /** - * Returns the cookie collection. - * Through the returned cookie collection, you add or remove cookies as follows, - * - * ~~~ - * // add a cookie - * $response->cookies->add(new Cookie([ - * 'name' => $name, - * 'value' => $value, - * ]); - * - * // remove a cookie - * $response->cookies->remove('name'); - * // alternatively - * unset($response->cookies['name']); - * ~~~ - * - * @return CookieCollection the cookie collection. - */ - public function getCookies() - { - if ($this->_cookies === null) { - $this->_cookies = new CookieCollection; - } - return $this->_cookies; - } - - /** - * @return boolean whether this response has a valid [[statusCode]]. - */ - public function getIsInvalid() - { - return $this->getStatusCode() < 100 || $this->getStatusCode() >= 600; - } - - /** - * @return boolean whether this response is informational - */ - public function getIsInformational() - { - return $this->getStatusCode() >= 100 && $this->getStatusCode() < 200; - } - - /** - * @return boolean whether this response is successful - */ - public function getIsSuccessful() - { - return $this->getStatusCode() >= 200 && $this->getStatusCode() < 300; - } - - /** - * @return boolean whether this response is a redirection - */ - public function getIsRedirection() - { - return $this->getStatusCode() >= 300 && $this->getStatusCode() < 400; - } - - /** - * @return boolean whether this response indicates a client error - */ - public function getIsClientError() - { - return $this->getStatusCode() >= 400 && $this->getStatusCode() < 500; - } - - /** - * @return boolean whether this response indicates a server error - */ - public function getIsServerError() - { - return $this->getStatusCode() >= 500 && $this->getStatusCode() < 600; - } - - /** - * @return boolean whether this response is OK - */ - public function getIsOk() - { - return $this->getStatusCode() == 200; - } - - /** - * @return boolean whether this response indicates the current request is forbidden - */ - public function getIsForbidden() - { - return $this->getStatusCode() == 403; - } - - /** - * @return boolean whether this response indicates the currently requested resource is not found - */ - public function getIsNotFound() - { - return $this->getStatusCode() == 404; - } - - /** - * @return boolean whether this response is empty - */ - public function getIsEmpty() - { - return in_array($this->getStatusCode(), [201, 204, 304]); - } - - /** - * Prepares for sending the response. - * The default implementation will convert [[data]] into [[content]] and set headers accordingly. - * @throws InvalidConfigException if the formatter for the specified format is invalid or [[format]] is not supported - */ - protected function prepare() - { - if ($this->stream !== null || $this->data === null) { - return; - } - - if (isset($this->formatters[$this->format])) { - $formatter = $this->formatters[$this->format]; - if (!is_object($formatter)) { - $formatter = Yii::createObject($formatter); - } - if ($formatter instanceof ResponseFormatterInterface) { - $formatter->format($this); - } else { - throw new InvalidConfigException("The '{$this->format}' response formatter is invalid. It must implement the ResponseFormatterInterface."); - } - } else { - switch ($this->format) { - case self::FORMAT_HTML: - $this->getHeaders()->setDefault('Content-Type', 'text/html; charset=' . $this->charset); - $this->content = $this->data; - break; - case self::FORMAT_RAW: - $this->content = $this->data; - break; - case self::FORMAT_JSON: - $this->getHeaders()->set('Content-Type', 'application/json; charset=UTF-8'); - $this->content = Json::encode($this->data); - break; - case self::FORMAT_JSONP: - $this->getHeaders()->set('Content-Type', 'text/javascript; charset=' . $this->charset); - if (is_array($this->data) && isset($this->data['data'], $this->data['callback'])) { - $this->content = sprintf('%s(%s);', $this->data['callback'], Json::encode($this->data['data'])); - } else { - $this->content = ''; - Yii::warning("The 'jsonp' response requires that the data be an array consisting of both 'data' and 'callback' elements.", __METHOD__); - } - break; - case self::FORMAT_XML: - Yii::createObject(XmlResponseFormatter::className())->format($this); - break; - default: - throw new InvalidConfigException("Unsupported response format: {$this->format}"); - } - } - - if (is_array($this->content)) { - $this->content = 'array()'; - } elseif (is_object($this->content)) { - $this->content = method_exists($this->content, '__toString') ? $this->content->__toString() : get_class($this->content); - } - } -} diff --git a/framework/yii/web/ResponseFormatterInterface.php b/framework/yii/web/ResponseFormatterInterface.php deleted file mode 100644 index 689ee1e..0000000 --- a/framework/yii/web/ResponseFormatterInterface.php +++ /dev/null @@ -1,23 +0,0 @@ - - * @since 2.0 - */ -interface ResponseFormatterInterface -{ - /** - * Formats the specified response. - * @param Response $response the response to be formatted. - */ - public function format($response); -} diff --git a/framework/yii/web/Session.php b/framework/yii/web/Session.php deleted file mode 100644 index fc715db..0000000 --- a/framework/yii/web/Session.php +++ /dev/null @@ -1,719 +0,0 @@ -session`. - * - * To start the session, call [[open()]]; To complete and send out session data, call [[close()]]; - * To destroy the session, call [[destroy()]]. - * - * By default, [[autoStart]] is true which means the session will be started automatically - * when the session component is accessed the first time. - * - * Session can be used like an array to set and get session data. For example, - * - * ~~~ - * $session = new Session; - * $session->open(); - * $value1 = $session['name1']; // get session variable 'name1' - * $value2 = $session['name2']; // get session variable 'name2' - * foreach ($session as $name => $value) // traverse all session variables - * $session['name3'] = $value3; // set session variable 'name3' - * ~~~ - * - * Session can be extended to support customized session storage. - * To do so, override [[useCustomStorage()]] so that it returns true, and - * override these methods with the actual logic about using custom storage: - * [[openSession()]], [[closeSession()]], [[readSession()]], [[writeSession()]], - * [[destroySession()]] and [[gcSession()]]. - * - * Session also supports a special type of session data, called *flash messages*. - * A flash message is available only in the current request and the next request. - * After that, it will be deleted automatically. Flash messages are particularly - * useful for displaying confirmation messages. To use flash messages, simply - * call methods such as [[setFlash()]], [[getFlash()]]. - * - * @property array $allFlashes Flash messages (key => message). This property is read-only. - * @property array $cookieParams The session cookie parameters. This property is read-only. - * @property integer $count The number of session variables. This property is read-only. - * @property string $flash The key identifying the flash message. Note that flash messages and normal session - * variables share the same name space. If you have a normal session variable using the same name, its value will - * be overwritten by this method. This property is write-only. - * @property float $gCProbability The probability (percentage) that the GC (garbage collection) process is - * started on every session initialization, defaults to 1 meaning 1% chance. - * @property string $id The current session ID. - * @property boolean $isActive Whether the session has started. This property is read-only. - * @property SessionIterator $iterator An iterator for traversing the session variables. This property is - * read-only. - * @property string $name The current session name. - * @property string $savePath The current session save path, defaults to '/tmp'. - * @property integer $timeout The number of seconds after which data will be seen as 'garbage' and cleaned up. - * The default value is 1440 seconds (or the value of "session.gc_maxlifetime" set in php.ini). - * @property boolean|null $useCookies The value indicating whether cookies should be used to store session - * IDs. - * @property boolean $useCustomStorage Whether to use custom storage. This property is read-only. - * @property boolean $useTransparentSessionID Whether transparent sid support is enabled or not, defaults to - * false. - * - * @author Qiang Xue - * @since 2.0 - */ -class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Countable -{ - /** - * @var boolean whether the session should be automatically started when the session component is initialized. - */ - public $autoStart = true; - /** - * @var string the name of the session variable that stores the flash message data. - */ - public $flashVar = '__flash'; - /** - * @var \SessionHandlerInterface|array an object implementing the SessionHandlerInterface or a configuration array. If set, will be used to provide persistency instead of build-in methods. - */ - public $handler; - /** - * @var array parameter-value pairs to override default session cookie parameters that are used for session_set_cookie_params() function - * Array may have the following possible keys: 'lifetime', 'path', 'domain', 'secure', 'httpOnly' - * @see http://www.php.net/manual/en/function.session-set-cookie-params.php - */ - private $_cookieParams = ['httpOnly' => true]; - - /** - * Initializes the application component. - * This method is required by IApplicationComponent and is invoked by application. - */ - public function init() - { - parent::init(); - if ($this->autoStart) { - $this->open(); - } - register_shutdown_function([$this, 'close']); - } - - /** - * Returns a value indicating whether to use custom session storage. - * This method should be overridden to return true by child classes that implement custom session storage. - * To implement custom session storage, override these methods: [[openSession()]], [[closeSession()]], - * [[readSession()]], [[writeSession()]], [[destroySession()]] and [[gcSession()]]. - * @return boolean whether to use custom storage. - */ - public function getUseCustomStorage() - { - return false; - } - - /** - * Starts the session. - */ - public function open() - { - if (session_status() == PHP_SESSION_ACTIVE) { - return; - } - - if ($this->handler !== null) { - if (!is_object($this->handler)) { - $this->handler = Yii::createObject($this->handler); - } - if (!$this->handler instanceof \SessionHandlerInterface) { - throw new InvalidConfigException('"' . get_class($this) . '::handler" must implement the SessionHandlerInterface.'); - } - @session_set_save_handler($this->handler, false); - } elseif ($this->getUseCustomStorage()) { - @session_set_save_handler( - [$this, 'openSession'], - [$this, 'closeSession'], - [$this, 'readSession'], - [$this, 'writeSession'], - [$this, 'destroySession'], - [$this, 'gcSession'] - ); - } - - $this->setCookieParamsInternal(); - - @session_start(); - - if (session_id() == '') { - $error = error_get_last(); - $message = isset($error['message']) ? $error['message'] : 'Failed to start session.'; - Yii::error($message, __METHOD__); - } else { - $this->updateFlashCounters(); - } - } - - /** - * Ends the current session and store session data. - */ - public function close() - { - if (session_id() !== '') { - @session_write_close(); - } - } - - /** - * Frees all session variables and destroys all data registered to a session. - */ - public function destroy() - { - if (session_id() !== '') { - @session_unset(); - @session_destroy(); - } - } - - /** - * @return boolean whether the session has started - */ - public function getIsActive() - { - return session_status() == PHP_SESSION_ACTIVE; - } - - /** - * @return string the current session ID - */ - public function getId() - { - return session_id(); - } - - /** - * @param string $value the session ID for the current session - */ - public function setId($value) - { - session_id($value); - } - - /** - * Updates the current session ID with a newly generated one . - * Please refer to for more details. - * @param boolean $deleteOldSession Whether to delete the old associated session file or not. - */ - public function regenerateID($deleteOldSession = false) - { - session_regenerate_id($deleteOldSession); - } - - /** - * @return string the current session name - */ - public function getName() - { - return session_name(); - } - - /** - * @param string $value the session name for the current session, must be an alphanumeric string. - * It defaults to "PHPSESSID". - */ - public function setName($value) - { - session_name($value); - } - - /** - * @return string the current session save path, defaults to '/tmp'. - */ - public function getSavePath() - { - return session_save_path(); - } - - /** - * @param string $value the current session save path. This can be either a directory name or a path alias. - * @throws InvalidParamException if the path is not a valid directory - */ - public function setSavePath($value) - { - $path = Yii::getAlias($value); - if (is_dir($path)) { - session_save_path($path); - } else { - throw new InvalidParamException("Session save path is not a valid directory: $value"); - } - } - - /** - * @return array the session cookie parameters. - * @see http://us2.php.net/manual/en/function.session-get-cookie-params.php - */ - public function getCookieParams() - { - $params = session_get_cookie_params(); - if (isset($params['httponly'])) { - $params['httpOnly'] = $params['httponly']; - unset($params['httponly']); - } - return array_merge($params, $this->_cookieParams); - } - - /** - * Sets the session cookie parameters. - * The cookie parameters passed to this method will be merged with the result - * of `session_get_cookie_params()`. - * @param array $value cookie parameters, valid keys include: `lifetime`, `path`, `domain`, `secure` and `httpOnly`. - * @throws InvalidParamException if the parameters are incomplete. - * @see http://us2.php.net/manual/en/function.session-set-cookie-params.php - */ - public function setCookieParams(array $value) - { - $this->_cookieParams = $value; - } - - /** - * Sets the session cookie parameters. - * This method is called by [[open()]] when it is about to open the session. - * @throws InvalidParamException if the parameters are incomplete. - * @see http://us2.php.net/manual/en/function.session-set-cookie-params.php - */ - private function setCookieParamsInternal() - { - $data = $this->getCookieParams(); - extract($data); - if (isset($lifetime, $path, $domain, $secure, $httpOnly)) { - session_set_cookie_params($lifetime, $path, $domain, $secure, $httpOnly); - } else { - throw new InvalidParamException('Please make sure cookieParams contains these elements: lifetime, path, domain, secure and httpOnly.'); - } - } - - /** - * Returns the value indicating whether cookies should be used to store session IDs. - * @return boolean|null the value indicating whether cookies should be used to store session IDs. - * @see setUseCookies() - */ - public function getUseCookies() - { - if (ini_get('session.use_cookies') === '0') { - return false; - } elseif (ini_get('session.use_only_cookies') === '1') { - return true; - } else { - return null; - } - } - - /** - * Sets the value indicating whether cookies should be used to store session IDs. - * Three states are possible: - * - * - true: cookies and only cookies will be used to store session IDs. - * - false: cookies will not be used to store session IDs. - * - null: if possible, cookies will be used to store session IDs; if not, other mechanisms will be used (e.g. GET parameter) - * - * @param boolean|null $value the value indicating whether cookies should be used to store session IDs. - */ - public function setUseCookies($value) - { - if ($value === false) { - ini_set('session.use_cookies', '0'); - ini_set('session.use_only_cookies', '0'); - } elseif ($value === true) { - ini_set('session.use_cookies', '1'); - ini_set('session.use_only_cookies', '1'); - } else { - ini_set('session.use_cookies', '1'); - ini_set('session.use_only_cookies', '0'); - } - } - - /** - * @return float the probability (percentage) that the GC (garbage collection) process is started on every session initialization, defaults to 1 meaning 1% chance. - */ - public function getGCProbability() - { - return (float)(ini_get('session.gc_probability') / ini_get('session.gc_divisor') * 100); - } - - /** - * @param float $value the probability (percentage) that the GC (garbage collection) process is started on every session initialization. - * @throws InvalidParamException if the value is not between 0 and 100. - */ - public function setGCProbability($value) - { - if ($value >= 0 && $value <= 100) { - // percent * 21474837 / 2147483647 ≈ percent * 0.01 - ini_set('session.gc_probability', floor($value * 21474836.47)); - ini_set('session.gc_divisor', 2147483647); - } else { - throw new InvalidParamException('GCProbability must be a value between 0 and 100.'); - } - } - - /** - * @return boolean whether transparent sid support is enabled or not, defaults to false. - */ - public function getUseTransparentSessionID() - { - return ini_get('session.use_trans_sid') == 1; - } - - /** - * @param boolean $value whether transparent sid support is enabled or not. - */ - public function setUseTransparentSessionID($value) - { - ini_set('session.use_trans_sid', $value ? '1' : '0'); - } - - /** - * @return integer the number of seconds after which data will be seen as 'garbage' and cleaned up. - * The default value is 1440 seconds (or the value of "session.gc_maxlifetime" set in php.ini). - */ - public function getTimeout() - { - return (int)ini_get('session.gc_maxlifetime'); - } - - /** - * @param integer $value the number of seconds after which data will be seen as 'garbage' and cleaned up - */ - public function setTimeout($value) - { - ini_set('session.gc_maxlifetime', $value); - } - - /** - * Session open handler. - * This method should be overridden if [[useCustomStorage()]] returns true. - * Do not call this method directly. - * @param string $savePath session save path - * @param string $sessionName session name - * @return boolean whether session is opened successfully - */ - public function openSession($savePath, $sessionName) - { - return true; - } - - /** - * Session close handler. - * This method should be overridden if [[useCustomStorage()]] returns true. - * Do not call this method directly. - * @return boolean whether session is closed successfully - */ - public function closeSession() - { - return true; - } - - /** - * Session read handler. - * This method should be overridden if [[useCustomStorage()]] returns true. - * Do not call this method directly. - * @param string $id session ID - * @return string the session data - */ - public function readSession($id) - { - return ''; - } - - /** - * Session write handler. - * This method should be overridden if [[useCustomStorage()]] returns true. - * Do not call this method directly. - * @param string $id session ID - * @param string $data session data - * @return boolean whether session write is successful - */ - public function writeSession($id, $data) - { - return true; - } - - /** - * Session destroy handler. - * This method should be overridden if [[useCustomStorage()]] returns true. - * Do not call this method directly. - * @param string $id session ID - * @return boolean whether session is destroyed successfully - */ - public function destroySession($id) - { - return true; - } - - /** - * Session GC (garbage collection) handler. - * This method should be overridden if [[useCustomStorage()]] returns true. - * Do not call this method directly. - * @param integer $maxLifetime the number of seconds after which data will be seen as 'garbage' and cleaned up. - * @return boolean whether session is GCed successfully - */ - public function gcSession($maxLifetime) - { - return true; - } - - /** - * Returns an iterator for traversing the session variables. - * This method is required by the interface IteratorAggregate. - * @return SessionIterator an iterator for traversing the session variables. - */ - public function getIterator() - { - return new SessionIterator; - } - - /** - * Returns the number of items in the session. - * @return integer the number of session variables - */ - public function getCount() - { - return count($_SESSION); - } - - /** - * Returns the number of items in the session. - * This method is required by Countable interface. - * @return integer number of items in the session. - */ - public function count() - { - return $this->getCount(); - } - - /** - * Returns the session variable value with the session variable name. - * If the session variable does not exist, the `$defaultValue` will be returned. - * @param string $key the session variable name - * @param mixed $defaultValue the default value to be returned when the session variable does not exist. - * @return mixed the session variable value, or $defaultValue if the session variable does not exist. - */ - public function get($key, $defaultValue = null) - { - return isset($_SESSION[$key]) ? $_SESSION[$key] : $defaultValue; - } - - /** - * Adds a session variable. - * If the specified name already exists, the old value will be overwritten. - * @param string $key session variable name - * @param mixed $value session variable value - */ - public function set($key, $value) - { - $_SESSION[$key] = $value; - } - - /** - * Removes a session variable. - * @param string $key the name of the session variable to be removed - * @return mixed the removed value, null if no such session variable. - */ - public function remove($key) - { - if (isset($_SESSION[$key])) { - $value = $_SESSION[$key]; - unset($_SESSION[$key]); - return $value; - } else { - return null; - } - } - - /** - * Removes all session variables - */ - public function removeAll() - { - foreach (array_keys($_SESSION) as $key) { - unset($_SESSION[$key]); - } - } - - /** - * @param mixed $key session variable name - * @return boolean whether there is the named session variable - */ - public function has($key) - { - return isset($_SESSION[$key]); - } - - /** - * @return array the list of all session variables in array - */ - public function toArray() - { - return $_SESSION; - } - - /** - * Updates the counters for flash messages and removes outdated flash messages. - * This method should only be called once in [[init()]]. - */ - protected function updateFlashCounters() - { - $counters = $this->get($this->flashVar, []); - if (is_array($counters)) { - foreach ($counters as $key => $count) { - if ($count) { - unset($counters[$key], $_SESSION[$key]); - } else { - $counters[$key]++; - } - } - $_SESSION[$this->flashVar] = $counters; - } else { - // fix the unexpected problem that flashVar doesn't return an array - unset($_SESSION[$this->flashVar]); - } - } - - /** - * Returns a flash message. - * A flash message is available only in the current request and the next request. - * @param string $key the key identifying the flash message - * @param mixed $defaultValue value to be returned if the flash message does not exist. - * @param boolean $delete whether to delete this flash message right after this method is called. - * If false, the flash message will be automatically deleted after the next request. - * @return mixed the flash message - */ - public function getFlash($key, $defaultValue = null, $delete = false) - { - $counters = $this->get($this->flashVar, []); - if (isset($counters[$key])) { - $value = $this->get($key, $defaultValue); - if ($delete) { - $this->removeFlash($key); - } - return $value; - } else { - return $defaultValue; - } - } - - /** - * Returns all flash messages. - * @return array flash messages (key => message). - */ - public function getAllFlashes() - { - $counters = $this->get($this->flashVar, []); - $flashes = []; - foreach (array_keys($counters) as $key) { - if (isset($_SESSION[$key])) { - $flashes[$key] = $_SESSION[$key]; - } - } - return $flashes; - } - - /** - * Stores a flash message. - * A flash message is available only in the current request and the next request. - * @param string $key the key identifying the flash message. Note that flash messages - * and normal session variables share the same name space. If you have a normal - * session variable using the same name, its value will be overwritten by this method. - * @param mixed $value flash message - */ - public function setFlash($key, $value = true) - { - $counters = $this->get($this->flashVar, []); - $counters[$key] = 0; - $_SESSION[$key] = $value; - $_SESSION[$this->flashVar] = $counters; - } - - /** - * Removes a flash message. - * Note that flash messages will be automatically removed after the next request. - * @param string $key the key identifying the flash message. Note that flash messages - * and normal session variables share the same name space. If you have a normal - * session variable using the same name, it will be removed by this method. - * @return mixed the removed flash message. Null if the flash message does not exist. - */ - public function removeFlash($key) - { - $counters = $this->get($this->flashVar, []); - $value = isset($_SESSION[$key], $counters[$key]) ? $_SESSION[$key] : null; - unset($counters[$key], $_SESSION[$key]); - $_SESSION[$this->flashVar] = $counters; - return $value; - } - - /** - * Removes all flash messages. - * Note that flash messages and normal session variables share the same name space. - * If you have a normal session variable using the same name, it will be removed - * by this method. - */ - public function removeAllFlashes() - { - $counters = $this->get($this->flashVar, []); - foreach (array_keys($counters) as $key) { - unset($_SESSION[$key]); - } - unset($_SESSION[$this->flashVar]); - } - - /** - * Returns a value indicating whether there is a flash message associated with the specified key. - * @param string $key key identifying the flash message - * @return boolean whether the specified flash message exists - */ - public function hasFlash($key) - { - return $this->getFlash($key) !== null; - } - - /** - * This method is required by the interface ArrayAccess. - * @param mixed $offset the offset to check on - * @return boolean - */ - public function offsetExists($offset) - { - return isset($_SESSION[$offset]); - } - - /** - * This method is required by the interface ArrayAccess. - * @param integer $offset the offset to retrieve element. - * @return mixed the element at the offset, null if no element is found at the offset - */ - public function offsetGet($offset) - { - return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null; - } - - /** - * This method is required by the interface ArrayAccess. - * @param integer $offset the offset to set element - * @param mixed $item the element value - */ - public function offsetSet($offset, $item) - { - $_SESSION[$offset] = $item; - } - - /** - * This method is required by the interface ArrayAccess. - * @param mixed $offset the offset to unset element - */ - public function offsetUnset($offset) - { - unset($_SESSION[$offset]); - } -} diff --git a/framework/yii/web/SessionIterator.php b/framework/yii/web/SessionIterator.php deleted file mode 100644 index c960dd4..0000000 --- a/framework/yii/web/SessionIterator.php +++ /dev/null @@ -1,84 +0,0 @@ - - * @since 2.0 - */ -class SessionIterator implements \Iterator -{ - /** - * @var array list of keys in the map - */ - private $_keys; - /** - * @var mixed current key - */ - private $_key; - - /** - * Constructor. - */ - public function __construct() - { - $this->_keys = array_keys($_SESSION); - } - - /** - * Rewinds internal array pointer. - * This method is required by the interface Iterator. - */ - public function rewind() - { - $this->_key = reset($this->_keys); - } - - /** - * Returns the key of the current array element. - * This method is required by the interface Iterator. - * @return mixed the key of the current array element - */ - public function key() - { - return $this->_key; - } - - /** - * Returns the current array element. - * This method is required by the interface Iterator. - * @return mixed the current array element - */ - public function current() - { - return isset($_SESSION[$this->_key]) ? $_SESSION[$this->_key] : null; - } - - /** - * Moves the internal pointer to the next array element. - * This method is required by the interface Iterator. - */ - public function next() - { - do { - $this->_key = next($this->_keys); - } while (!isset($_SESSION[$this->_key]) && $this->_key !== false); - } - - /** - * Returns whether there is an element at current position. - * This method is required by the interface Iterator. - * @return boolean - */ - public function valid() - { - return $this->_key !== false; - } -} diff --git a/framework/yii/web/UploadedFile.php b/framework/yii/web/UploadedFile.php deleted file mode 100644 index 5e1e428..0000000 --- a/framework/yii/web/UploadedFile.php +++ /dev/null @@ -1,234 +0,0 @@ - - * @since 2.0 - */ -class UploadedFile extends Object -{ - private static $_files; - - /** - * @var string the original name of the file being uploaded - */ - public $name; - /** - * @var string the path of the uploaded file on the server. - * Note, this is a temporary file which will be automatically deleted by PHP - * after the current request is processed. - */ - public $tempName; - /** - * @var string the MIME-type of the uploaded file (such as "image/gif"). - * Since this MIME type is not checked on the server side, do not take this value for granted. - * Instead, use [[FileHelper::getMimeType()]] to determine the exact MIME type. - */ - public $type; - /** - * @var integer the actual size of the uploaded file in bytes - */ - public $size; - /** - * @var integer an error code describing the status of this file uploading. - * @see http://www.php.net/manual/en/features.file-upload.errors.php - */ - public $error; - - - /** - * String output. - * This is PHP magic method that returns string representation of an object. - * The implementation here returns the uploaded file's name. - * @return string the string representation of the object - */ - public function __toString() - { - return $this->name; - } - - /** - * Returns an uploaded file for the given model attribute. - * The file should be uploaded using [[ActiveForm::fileInput()]]. - * @param \yii\base\Model $model the data model - * @param string $attribute the attribute name. The attribute name may contain array indexes. - * For example, '[1]file' for tabular file uploading; and 'file[1]' for an element in a file array. - * @return UploadedFile the instance of the uploaded file. - * Null is returned if no file is uploaded for the specified model attribute. - * @see getInstanceByName() - */ - public static function getInstance($model, $attribute) - { - $name = Html::getInputName($model, $attribute); - return static::getInstanceByName($name); - } - - /** - * Returns all uploaded files for the given model attribute. - * @param \yii\base\Model $model the data model - * @param string $attribute the attribute name. The attribute name may contain array indexes - * for tabular file uploading, e.g. '[1]file'. - * @return UploadedFile[] array of UploadedFile objects. - * Empty array is returned if no available file was found for the given attribute. - */ - public static function getInstances($model, $attribute) - { - $name = Html::getInputName($model, $attribute); - return static::getInstancesByName($name); - } - - /** - * Returns an uploaded file according to the given file input name. - * The name can be a plain string or a string like an array element (e.g. 'Post[imageFile]', or 'Post[0][imageFile]'). - * @param string $name the name of the file input field. - * @return UploadedFile the instance of the uploaded file. - * Null is returned if no file is uploaded for the specified name. - */ - public static function getInstanceByName($name) - { - $files = static::loadFiles(); - return isset($files[$name]) ? $files[$name] : null; - } - - /** - * Returns an array of uploaded files corresponding to the specified file input name. - * This is mainly used when multiple files were uploaded and saved as 'files[0]', 'files[1]', - * 'files[n]'..., and you can retrieve them all by passing 'files' as the name. - * @param string $name the name of the array of files - * @return UploadedFile[] the array of CUploadedFile objects. Empty array is returned - * if no adequate upload was found. Please note that this array will contain - * all files from all sub-arrays regardless how deeply nested they are. - */ - public static function getInstancesByName($name) - { - $files = static::loadFiles(); - if (isset($files[$name])) { - return [$files[$name]]; - } - $results = []; - foreach ($files as $key => $file) { - if (strpos($key, "{$name}[") === 0) { - $results[] = self::$_files[$key]; - } - } - return $results; - } - - /** - * Cleans up the loaded UploadedFile instances. - * This method is mainly used by test scripts to set up a fixture. - */ - public static function reset() - { - self::$_files = null; - } - - /** - * Saves the uploaded file. - * Note that this method uses php's move_uploaded_file() method. If the target file `$file` - * already exists, it will be overwritten. - * @param string $file the file path used to save the uploaded file - * @param boolean $deleteTempFile whether to delete the temporary file after saving. - * If true, you will not be able to save the uploaded file again in the current request. - * @return boolean true whether the file is saved successfully - * @see error - */ - public function saveAs($file, $deleteTempFile = true) - { - if ($this->error == UPLOAD_ERR_OK) { - if ($deleteTempFile) { - return move_uploaded_file($this->tempName, $file); - } elseif (is_uploaded_file($this->tempName)) { - return copy($this->tempName, $file); - } - } - return false; - } - - /** - * @return string original file base name - */ - public function getBaseName() - { - return pathinfo($this->name, PATHINFO_FILENAME); - } - - /** - * @return string file extension - */ - public function getExtension() - { - return strtolower(pathinfo($this->name, PATHINFO_EXTENSION)); - } - - /** - * @return boolean whether there is an error with the uploaded file. - * Check [[error]] for detailed error code information. - */ - public function getHasError() - { - return $this->error != UPLOAD_ERR_OK; - } - - /** - * Creates UploadedFile instances from $_FILE. - * @return array the UploadedFile instances - */ - private static function loadFiles() - { - if (self::$_files === null) { - self::$_files = []; - if (isset($_FILES) && is_array($_FILES)) { - foreach ($_FILES as $class => $info) { - self::loadFilesRecursive($class, $info['name'], $info['tmp_name'], $info['type'], $info['size'], $info['error']); - } - } - } - return self::$_files; - } - - /** - * Creates UploadedFile instances from $_FILE recursively. - * @param string $key key for identifying uploaded file: class name and sub-array indexes - * @param mixed $names file names provided by PHP - * @param mixed $tempNames temporary file names provided by PHP - * @param mixed $types file types provided by PHP - * @param mixed $sizes file sizes provided by PHP - * @param mixed $errors uploading issues provided by PHP - */ - private static function loadFilesRecursive($key, $names, $tempNames, $types, $sizes, $errors) - { - if (is_array($names)) { - foreach ($names as $i => $name) { - self::loadFilesRecursive($key . '[' . $i . ']', $name, $tempNames[$i], $types[$i], $sizes[$i], $errors[$i]); - } - } else { - self::$_files[$key] = new static([ - 'name' => $names, - 'tempName' => $tempNames, - 'type' => $types, - 'size' => $sizes, - 'error' => $errors, - ]); - } - } -} diff --git a/framework/yii/web/UrlManager.php b/framework/yii/web/UrlManager.php deleted file mode 100644 index a2044cb..0000000 --- a/framework/yii/web/UrlManager.php +++ /dev/null @@ -1,338 +0,0 @@ -urlManager`. - * - * You can modify its configuration by adding an array to your application config under `components` - * as it is shown in the following example: - * - * ~~~ - * 'urlManager' => [ - * 'enablePrettyUrl' => true, - * 'rules' => [ - * // your rules go here - * ], - * // ... - * ] - * ~~~ - * - * @property string $baseUrl The base URL that is used by [[createUrl()]] to prepend URLs it creates. - * @property string $hostInfo The host info (e.g. "http://www.example.com") that is used by - * [[createAbsoluteUrl()]] to prepend URLs it creates. - * - * @author Qiang Xue - * @since 2.0 - */ -class UrlManager extends Component -{ - /** - * @var boolean whether to enable pretty URLs. Instead of putting all parameters in the query - * string part of a URL, pretty URLs allow using path info to represent some of the parameters - * and can thus produce more user-friendly URLs, such as "/news/Yii-is-released", instead of - * "/index.php?r=news/view&id=100". - */ - public $enablePrettyUrl = false; - /** - * @var boolean whether to enable strict parsing. If strict parsing is enabled, the incoming - * requested URL must match at least one of the [[rules]] in order to be treated as a valid request. - * Otherwise, the path info part of the request will be treated as the requested route. - * This property is used only when [[enablePrettyUrl]] is true. - */ - public $enableStrictParsing = false; - /** - * @var array the rules for creating and parsing URLs when [[enablePrettyUrl]] is true. - * This property is used only if [[enablePrettyUrl]] is true. Each element in the array - * is the configuration array for creating a single URL rule. The configuration will - * be merged with [[ruleConfig]] first before it is used for creating the rule object. - * - * A special shortcut format can be used if a rule only specifies [[UrlRule::pattern|pattern]] - * and [[UrlRule::route|route]]: `'pattern' => 'route'`. That is, instead of using a configuration - * array, one can use the key to represent the pattern and the value the corresponding route. - * For example, `'post/' => 'post/view'`. - * - * For RESTful routing the mentioned shortcut format also allows you to specify the - * [[UrlRule::verb|HTTP verb]] that the rule should apply for. - * You can do that by prepending it to the pattern, separated by space. - * For example, `'PUT post/' => 'post/update'`. - * You may specify multiple verbs by separating them with comma - * like this: `'POST,PUT post/index' => 'post/create'`. - * The supported verbs in the shortcut format are: GET, HEAD, POST, PUT, PATCH and DELETE. - * Note that [[UrlRule::mode|mode]] will be set to PARSING_ONLY when specifying verb in this way - * so you normally would not specify a verb for normal GET request. - * - * Here is an example configuration for RESTful CRUD controller: - * - * ~~~php - * [ - * 'dashboard' => 'site/index', - * - * 'POST s' => '/create', - * 's' => '/index', - * - * 'PUT /' => '/update', - * 'DELETE /' => '/delete', - * '/' => '/view', - * ]; - * ~~~ - * - * Note that if you modify this property after the UrlManager object is created, make sure - * you populate the array with rule objects instead of rule configurations. - */ - public $rules = []; - /** - * @var string the URL suffix used when in 'path' format. - * For example, ".html" can be used so that the URL looks like pointing to a static HTML page. - * This property is used only if [[enablePrettyUrl]] is true. - */ - public $suffix; - /** - * @var boolean whether to show entry script name in the constructed URL. Defaults to true. - * This property is used only if [[enablePrettyUrl]] is true. - */ - public $showScriptName = true; - /** - * @var string the GET variable name for route. This property is used only if [[enablePrettyUrl]] is false. - */ - public $routeVar = 'r'; - /** - * @var Cache|string the cache object or the application component ID of the cache object. - * Compiled URL rules will be cached through this cache object, if it is available. - * - * After the UrlManager object is created, if you want to change this property, - * you should only assign it with a cache object. - * Set this property to null if you do not want to cache the URL rules. - */ - public $cache = 'cache'; - /** - * @var array the default configuration of URL rules. Individual rule configurations - * specified via [[rules]] will take precedence when the same property of the rule is configured. - */ - public $ruleConfig = ['class' => 'yii\web\UrlRule']; - - private $_baseUrl; - private $_hostInfo; - - /** - * Initializes UrlManager. - */ - public function init() - { - parent::init(); - $this->compileRules(); - } - - /** - * Parses the URL rules. - */ - protected function compileRules() - { - if (!$this->enablePrettyUrl || empty($this->rules)) { - return; - } - if (is_string($this->cache)) { - $this->cache = Yii::$app->getComponent($this->cache); - } - if ($this->cache instanceof Cache) { - $key = __CLASS__; - $hash = md5(json_encode($this->rules)); - if (($data = $this->cache->get($key)) !== false && isset($data[1]) && $data[1] === $hash) { - $this->rules = $data[0]; - return; - } - } - - $rules = []; - foreach ($this->rules as $key => $rule) { - if (!is_array($rule)) { - $rule = ['route' => $rule]; - if (preg_match('/^((?:(GET|HEAD|POST|PUT|PATCH|DELETE),)*(GET|HEAD|POST|PUT|PATCH|DELETE))\s+(.*)$/', $key, $matches)) { - $rule['verb'] = explode(',', $matches[1]); - $rule['mode'] = UrlRule::PARSING_ONLY; - $key = $matches[4]; - } - $rule['pattern'] = $key; - } - $rules[] = Yii::createObject(array_merge($this->ruleConfig, $rule)); - } - $this->rules = $rules; - - if (isset($key, $hash)) { - $this->cache->set($key, [$this->rules, $hash]); - } - } - - /** - * Parses the user request. - * @param Request $request the request component - * @return array|boolean the route and the associated parameters. The latter is always empty - * if [[enablePrettyUrl]] is false. False is returned if the current request cannot be successfully parsed. - */ - public function parseRequest($request) - { - if ($this->enablePrettyUrl) { - $pathInfo = $request->getPathInfo(); - /** @var UrlRule $rule */ - foreach ($this->rules as $rule) { - if (($result = $rule->parseRequest($this, $request)) !== false) { - Yii::trace("Request parsed with URL rule: {$rule->name}", __METHOD__); - return $result; - } - } - - if ($this->enableStrictParsing) { - return false; - } - - Yii::trace('No matching URL rules. Using default URL parsing logic.', __METHOD__); - - $suffix = (string)$this->suffix; - if ($suffix !== '' && $pathInfo !== '') { - $n = strlen($this->suffix); - if (substr($pathInfo, -$n) === $this->suffix) { - $pathInfo = substr($pathInfo, 0, -$n); - if ($pathInfo === '') { - // suffix alone is not allowed - return false; - } - } else { - // suffix doesn't match - return false; - } - } - - return [$pathInfo, []]; - } else { - Yii::trace('Pretty URL not enabled. Using default URL parsing logic.', __METHOD__); - $route = $request->get($this->routeVar); - if (is_array($route)) { - $route = ''; - } - return [(string)$route, []]; - } - } - - /** - * Creates a URL using the given route and parameters. - * The URL created is a relative one. Use [[createAbsoluteUrl()]] to create an absolute URL. - * @param string $route the route - * @param array $params the parameters (name-value pairs) - * @return string the created URL - */ - public function createUrl($route, $params = []) - { - $anchor = isset($params['#']) ? '#' . $params['#'] : ''; - unset($params['#'], $params[$this->routeVar]); - - $route = trim($route, '/'); - $baseUrl = $this->getBaseUrl(); - - if ($this->enablePrettyUrl) { - /** @var UrlRule $rule */ - foreach ($this->rules as $rule) { - if (($url = $rule->createUrl($this, $route, $params)) !== false) { - if ($rule->host !== null) { - if ($baseUrl !== '' && ($pos = strpos($url, '/', 8)) !== false) { - return substr($url, 0, $pos) . $baseUrl . substr($url, $pos); - } else { - return $url . $baseUrl . $anchor; - } - } else { - return "$baseUrl/{$url}{$anchor}"; - } - } - } - - if ($this->suffix !== null) { - $route .= $this->suffix; - } - if (!empty($params)) { - $route .= '?' . http_build_query($params); - } - return "$baseUrl/{$route}{$anchor}"; - } else { - $url = "$baseUrl?{$this->routeVar}=$route"; - if (!empty($params)) { - $url .= '&' . http_build_query($params); - } - return $url . $anchor; - } - } - - /** - * Creates an absolute URL using the given route and parameters. - * This method prepends the URL created by [[createUrl()]] with the [[hostInfo]]. - * @param string $route the route - * @param array $params the parameters (name-value pairs) - * @return string the created URL - * @see createUrl() - */ - public function createAbsoluteUrl($route, $params = []) - { - $url = $this->createUrl($route, $params); - if (strpos($url, '://') !== false) { - return $url; - } else { - return $this->getHostInfo() . $url; - } - } - - /** - * Returns the base URL that is used by [[createUrl()]] to prepend URLs it creates. - * It defaults to [[Request::scriptUrl]] if [[showScriptName]] is true or [[enablePrettyUrl]] is false; - * otherwise, it defaults to [[Request::baseUrl]]. - * @return string the base URL that is used by [[createUrl()]] to prepend URLs it creates. - */ - public function getBaseUrl() - { - if ($this->_baseUrl === null) { - /** @var \yii\web\Request $request */ - $request = Yii::$app->getRequest(); - $this->_baseUrl = $this->showScriptName || !$this->enablePrettyUrl ? $request->getScriptUrl() : $request->getBaseUrl(); - } - return $this->_baseUrl; - } - - /** - * Sets the base URL that is used by [[createUrl()]] to prepend URLs it creates. - * @param string $value the base URL that is used by [[createUrl()]] to prepend URLs it creates. - */ - public function setBaseUrl($value) - { - $this->_baseUrl = rtrim($value, '/'); - } - - /** - * Returns the host info that is used by [[createAbsoluteUrl()]] to prepend URLs it creates. - * @return string the host info (e.g. "http://www.example.com") that is used by [[createAbsoluteUrl()]] to prepend URLs it creates. - */ - public function getHostInfo() - { - if ($this->_hostInfo === null) { - $this->_hostInfo = Yii::$app->getRequest()->getHostInfo(); - } - return $this->_hostInfo; - } - - /** - * Sets the host info that is used by [[createAbsoluteUrl()]] to prepend URLs it creates. - * @param string $value the host info (e.g. "http://www.example.com") that is used by [[createAbsoluteUrl()]] to prepend URLs it creates. - */ - public function setHostInfo($value) - { - $this->_hostInfo = rtrim($value, '/'); - } -} diff --git a/framework/yii/web/UrlRule.php b/framework/yii/web/UrlRule.php deleted file mode 100644 index 2934b26..0000000 --- a/framework/yii/web/UrlRule.php +++ /dev/null @@ -1,326 +0,0 @@ - [ - * ['class' => 'MyUrlRule', 'pattern' => '...', 'route' => 'site/index', ...], - * // ... - * ] - * ~~~ - * - * @author Qiang Xue - * @since 2.0 - */ -class UrlRule extends Object -{ - /** - * Set [[mode]] with this value to mark that this rule is for URL parsing only - */ - const PARSING_ONLY = 1; - /** - * Set [[mode]] with this value to mark that this rule is for URL creation only - */ - const CREATION_ONLY = 2; - - /** - * @var string the name of this rule. If not set, it will use [[pattern]] as the name. - */ - public $name; - /** - * @var string the pattern used to parse and create the path info part of a URL. - * @see host - */ - public $pattern; - /** - * @var string the pattern used to parse and create the host info part of a URL. - * @see pattern - */ - public $host; - /** - * @var string the route to the controller action - */ - public $route; - /** - * @var array the default GET parameters (name => value) that this rule provides. - * When this rule is used to parse the incoming request, the values declared in this property - * will be injected into $_GET. - */ - public $defaults = []; - /** - * @var string the URL suffix used for this rule. - * For example, ".html" can be used so that the URL looks like pointing to a static HTML page. - * If not, the value of [[UrlManager::suffix]] will be used. - */ - public $suffix; - /** - * @var string|array the HTTP verb (e.g. GET, POST, DELETE) that this rule should match. - * Use array to represent multiple verbs that this rule may match. - * If this property is not set, the rule can match any verb. - * Note that this property is only used when parsing a request. It is ignored for URL creation. - */ - public $verb; - /** - * @var integer a value indicating if this rule should be used for both request parsing and URL creation, - * parsing only, or creation only. - * If not set or 0, it means the rule is both request parsing and URL creation. - * If it is [[PARSING_ONLY]], the rule is for request parsing only. - * If it is [[CREATION_ONLY]], the rule is for URL creation only. - */ - public $mode; - - /** - * @var string the template for generating a new URL. This is derived from [[pattern]] and is used in generating URL. - */ - private $_template; - /** - * @var string the regex for matching the route part. This is used in generating URL. - */ - private $_routeRule; - /** - * @var array list of regex for matching parameters. This is used in generating URL. - */ - private $_paramRules = []; - /** - * @var array list of parameters used in the route. - */ - private $_routeParams = []; - - /** - * Initializes this rule. - */ - public function init() - { - if ($this->pattern === null) { - throw new InvalidConfigException('UrlRule::pattern must be set.'); - } - if ($this->route === null) { - throw new InvalidConfigException('UrlRule::route must be set.'); - } - if ($this->verb !== null) { - if (is_array($this->verb)) { - foreach ($this->verb as $i => $verb) { - $this->verb[$i] = strtoupper($verb); - } - } else { - $this->verb = [strtoupper($this->verb)]; - } - } - if ($this->name === null) { - $this->name = $this->pattern; - } - - $this->pattern = trim($this->pattern, '/'); - - if ($this->host !== null) { - $this->pattern = rtrim($this->host, '/') . rtrim('/' . $this->pattern, '/') . '/'; - } elseif ($this->pattern === '') { - $this->_template = ''; - $this->pattern = '#^$#u'; - return; - } else { - $this->pattern = '/' . $this->pattern . '/'; - } - - $this->route = trim($this->route, '/'); - if (strpos($this->route, '<') !== false && preg_match_all('/<(\w+)>/', $this->route, $matches)) { - foreach ($matches[1] as $name) { - $this->_routeParams[$name] = "<$name>"; - } - } - - $tr = [ - '.' => '\\.', - '*' => '\\*', - '$' => '\\$', - '[' => '\\[', - ']' => '\\]', - '(' => '\\(', - ')' => '\\)', - ]; - $tr2 = []; - if (preg_match_all('/<(\w+):?([^>]+)?>/', $this->pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) { - foreach ($matches as $match) { - $name = $match[1][0]; - $pattern = isset($match[2][0]) ? $match[2][0] : '[^\/]+'; - if (isset($this->defaults[$name])) { - $length = strlen($match[0][0]); - $offset = $match[0][1]; - if ($offset > 1 && $this->pattern[$offset - 1] === '/' && $this->pattern[$offset + $length] === '/') { - $tr["/<$name>"] = "(/(?P<$name>$pattern))?"; - } else { - $tr["<$name>"] = "(?P<$name>$pattern)?"; - } - } else { - $tr["<$name>"] = "(?P<$name>$pattern)"; - } - if (isset($this->_routeParams[$name])) { - $tr2["<$name>"] = "(?P<$name>$pattern)"; - } else { - $this->_paramRules[$name] = $pattern === '[^\/]+' ? '' : "#^$pattern$#"; - } - } - } - - $this->_template = preg_replace('/<(\w+):?([^>]+)?>/', '<$1>', $this->pattern); - $this->pattern = '#^' . trim(strtr($this->_template, $tr), '/') . '$#u'; - - if (!empty($this->_routeParams)) { - $this->_routeRule = '#^' . strtr($this->route, $tr2) . '$#u'; - } - } - - /** - * Parses the given request and returns the corresponding route and parameters. - * @param UrlManager $manager the URL manager - * @param Request $request the request component - * @return array|boolean the parsing result. The route and the parameters are returned as an array. - * If false, it means this rule cannot be used to parse this path info. - */ - public function parseRequest($manager, $request) - { - if ($this->mode === self::CREATION_ONLY) { - return false; - } - - if ($this->verb !== null && !in_array($request->getMethod(), $this->verb, true)) { - return false; - } - - $pathInfo = $request->getPathInfo(); - $suffix = (string)($this->suffix === null ? $manager->suffix : $this->suffix); - if ($suffix !== '' && $pathInfo !== '') { - $n = strlen($suffix); - if (substr($pathInfo, -$n) === $suffix) { - $pathInfo = substr($pathInfo, 0, -$n); - if ($pathInfo === '') { - // suffix alone is not allowed - return false; - } - } else { - return false; - } - } - - if ($this->host !== null) { - $pathInfo = strtolower($request->getHostInfo()) . '/' . $pathInfo; - } - - if (!preg_match($this->pattern, $pathInfo, $matches)) { - return false; - } - foreach ($this->defaults as $name => $value) { - if (!isset($matches[$name]) || $matches[$name] === '') { - $matches[$name] = $value; - } - } - $params = $this->defaults; - $tr = []; - foreach ($matches as $name => $value) { - if (isset($this->_routeParams[$name])) { - $tr[$this->_routeParams[$name]] = $value; - unset($params[$name]); - } elseif (isset($this->_paramRules[$name])) { - $params[$name] = $value; - } - } - if ($this->_routeRule !== null) { - $route = strtr($this->route, $tr); - } else { - $route = $this->route; - } - return [$route, $params]; - } - - /** - * Creates a URL according to the given route and parameters. - * @param UrlManager $manager the URL manager - * @param string $route the route. It should not have slashes at the beginning or the end. - * @param array $params the parameters - * @return string|boolean the created URL, or false if this rule cannot be used for creating this URL. - */ - public function createUrl($manager, $route, $params) - { - if ($this->mode === self::PARSING_ONLY) { - return false; - } - - $tr = []; - - // match the route part first - if ($route !== $this->route) { - if ($this->_routeRule !== null && preg_match($this->_routeRule, $route, $matches)) { - foreach ($this->_routeParams as $name => $token) { - if (isset($this->defaults[$name]) && strcmp($this->defaults[$name], $matches[$name]) === 0) { - $tr[$token] = ''; - } else { - $tr[$token] = $matches[$name]; - } - } - } else { - return false; - } - } - - // match default params - // if a default param is not in the route pattern, its value must also be matched - foreach ($this->defaults as $name => $value) { - if (isset($this->_routeParams[$name])) { - continue; - } - if (!isset($params[$name])) { - return false; - } elseif (strcmp($params[$name], $value) === 0) { // strcmp will do string conversion automatically - unset($params[$name]); - if (isset($this->_paramRules[$name])) { - $tr["<$name>"] = ''; - } - } elseif (!isset($this->_paramRules[$name])) { - return false; - } - } - - // match params in the pattern - foreach ($this->_paramRules as $name => $rule) { - if (isset($params[$name]) && !is_array($params[$name]) && ($rule === '' || preg_match($rule, $params[$name]))) { - $tr["<$name>"] = urlencode($params[$name]); - unset($params[$name]); - } elseif (!isset($this->defaults[$name]) || isset($params[$name])) { - return false; - } - } - - $url = trim(strtr($this->_template, $tr), '/'); - if ($this->host !== null) { - $pos = strpos($url, '/', 8); - if ($pos !== false) { - $url = substr($url, 0, $pos) . preg_replace('#/+#', '/', substr($url, $pos)); - } - } elseif (strpos($url, '//') !== false) { - $url = preg_replace('#/+#', '/', $url); - } - - if ($url !== '') { - $url .= ($this->suffix === null ? $manager->suffix : $this->suffix); - } - - if (!empty($params)) { - $url .= '?' . http_build_query($params); - } - return $url; - } -} diff --git a/framework/yii/web/User.php b/framework/yii/web/User.php deleted file mode 100644 index d6948b6..0000000 --- a/framework/yii/web/User.php +++ /dev/null @@ -1,533 +0,0 @@ -user`. - * - * You can modify its configuration by adding an array to your application config under `components` - * as it is shown in the following example: - * - * ~~~ - * 'user' => [ - * 'identityClass' => 'app\models\User', // User must implement the IdentityInterface - * 'enableAutoLogin' => true, - * // 'loginUrl' => ['user/login'], - * // ... - * ] - * ~~~ - * - * @property string|integer $id The unique identifier for the user. If null, it means the user is a guest. - * This property is read-only. - * @property IdentityInterface $identity The identity object associated with the currently logged user. Null - * is returned if the user is not logged in (not authenticated). - * @property boolean $isGuest Whether the current user is a guest. This property is read-only. - * @property string $returnUrl The URL that the user should be redirected to after login. Note that the type - * of this property differs in getter and setter. See [[getReturnUrl()]] and [[setReturnUrl()]] for details. - * - * @author Qiang Xue - * @since 2.0 - */ -class User extends Component -{ - const EVENT_BEFORE_LOGIN = 'beforeLogin'; - const EVENT_AFTER_LOGIN = 'afterLogin'; - const EVENT_BEFORE_LOGOUT = 'beforeLogout'; - const EVENT_AFTER_LOGOUT = 'afterLogout'; - - /** - * @var string the class name of the [[identity]] object. - */ - public $identityClass; - /** - * @var boolean whether to enable cookie-based login. Defaults to false. - */ - public $enableAutoLogin = false; - /** - * @var string|array the URL for login when [[loginRequired()]] is called. - * If an array is given, [[UrlManager::createUrl()]] will be called to create the corresponding URL. - * The first element of the array should be the route to the login action, and the rest of - * the name-value pairs are GET parameters used to construct the login URL. For example, - * - * ~~~ - * ['site/login', 'ref' => 1] - * ~~~ - * - * If this property is null, a 403 HTTP exception will be raised when [[loginRequired()]] is called. - */ - public $loginUrl = ['site/login']; - /** - * @var array the configuration of the identity cookie. This property is used only when [[enableAutoLogin]] is true. - * @see Cookie - */ - public $identityCookie = ['name' => '_identity', 'httpOnly' => true]; - /** - * @var integer the number of seconds in which the user will be logged out automatically if he - * remains inactive. If this property is not set, the user will be logged out after - * the current session expires (c.f. [[Session::timeout]]). - */ - public $authTimeout; - /** - * @var boolean whether to automatically renew the identity cookie each time a page is requested. - * This property is effective only when [[enableAutoLogin]] is true. - * When this is false, the identity cookie will expire after the specified duration since the user - * is initially logged in. When this is true, the identity cookie will expire after the specified duration - * since the user visits the site the last time. - * @see enableAutoLogin - */ - public $autoRenewCookie = true; - /** - * @var string the session variable name used to store the value of [[id]]. - */ - public $idVar = '__id'; - /** - * @var string the session variable name used to store the value of expiration timestamp of the authenticated state. - * This is used when [[authTimeout]] is set. - */ - public $authTimeoutVar = '__expire'; - /** - * @var string the session variable name used to store the value of [[returnUrl]]. - */ - public $returnUrlVar = '__returnUrl'; - - private $_access = []; - - - /** - * Initializes the application component. - */ - public function init() - { - parent::init(); - - if ($this->identityClass === null) { - throw new InvalidConfigException('User::identityClass must be set.'); - } - if ($this->enableAutoLogin && !isset($this->identityCookie['name'])) { - throw new InvalidConfigException('User::identityCookie must contain the "name" element.'); - } - - Yii::$app->getSession()->open(); - - $this->renewAuthStatus(); - - if ($this->enableAutoLogin) { - if ($this->getIsGuest()) { - $this->loginByCookie(); - } elseif ($this->autoRenewCookie) { - $this->renewIdentityCookie(); - } - } - } - - private $_identity = false; - - /** - * Returns the identity object associated with the currently logged user. - * @return IdentityInterface the identity object associated with the currently logged user. - * Null is returned if the user is not logged in (not authenticated). - * @see login() - * @see logout() - */ - public function getIdentity() - { - if ($this->_identity === false) { - $id = $this->getId(); - if ($id === null) { - $this->_identity = null; - } else { - /** @var IdentityInterface $class */ - $class = $this->identityClass; - $this->_identity = $class::findIdentity($id); - } - } - return $this->_identity; - } - - /** - * Sets the identity object. - * This method should be mainly be used by the User component or its child class - * to maintain the identity object. - * - * You should normally update the user identity via methods [[login()]], [[logout()]] - * or [[switchIdentity()]]. - * - * @param IdentityInterface $identity the identity object associated with the currently logged user. - */ - public function setIdentity($identity) - { - $this->_identity = $identity; - } - - /** - * Logs in a user. - * - * This method stores the necessary session information to keep track - * of the user identity information. If `$duration` is greater than 0 - * and [[enableAutoLogin]] is true, it will also send out an identity - * cookie to support cookie-based login. - * - * @param IdentityInterface $identity the user identity (which should already be authenticated) - * @param integer $duration number of seconds that the user can remain in logged-in status. - * Defaults to 0, meaning login till the user closes the browser or the session is manually destroyed. - * If greater than 0 and [[enableAutoLogin]] is true, cookie-based login will be supported. - * @return boolean whether the user is logged in - */ - public function login($identity, $duration = 0) - { - if ($this->beforeLogin($identity, false)) { - $this->switchIdentity($identity, $duration); - $id = $identity->getId(); - $ip = Yii::$app->getRequest()->getUserIP(); - Yii::info("User '$id' logged in from $ip.", __METHOD__); - $this->afterLogin($identity, false); - } - return !$this->getIsGuest(); - } - - /** - * Logs in a user by cookie. - * - * This method attempts to log in a user using the ID and authKey information - * provided by the given cookie. - */ - protected function loginByCookie() - { - $name = $this->identityCookie['name']; - $value = Yii::$app->getRequest()->getCookies()->getValue($name); - if ($value !== null) { - $data = json_decode($value, true); - if (count($data) === 3 && isset($data[0], $data[1], $data[2])) { - list ($id, $authKey, $duration) = $data; - /** @var IdentityInterface $class */ - $class = $this->identityClass; - $identity = $class::findIdentity($id); - if ($identity !== null && $identity->validateAuthKey($authKey)) { - if ($this->beforeLogin($identity, true)) { - $this->switchIdentity($identity, $this->autoRenewCookie ? $duration : 0); - $ip = Yii::$app->getRequest()->getUserIP(); - Yii::info("User '$id' logged in from $ip via cookie.", __METHOD__); - $this->afterLogin($identity, true); - } - } elseif ($identity !== null) { - Yii::warning("Invalid auth key attempted for user '$id': $authKey", __METHOD__); - } - } - } - } - - /** - * Logs out the current user. - * This will remove authentication-related session data. - * If `$destroySession` is true, all session data will be removed. - * @param boolean $destroySession whether to destroy the whole session. Defaults to true. - */ - public function logout($destroySession = true) - { - $identity = $this->getIdentity(); - if ($identity !== null && $this->beforeLogout($identity)) { - $this->switchIdentity(null); - $id = $identity->getId(); - $ip = Yii::$app->getRequest()->getUserIP(); - Yii::info("User '$id' logged out from $ip.", __METHOD__); - if ($destroySession) { - Yii::$app->getSession()->destroy(); - } - $this->afterLogout($identity); - } - } - - /** - * Returns a value indicating whether the user is a guest (not authenticated). - * @return boolean whether the current user is a guest. - */ - public function getIsGuest() - { - return $this->getIdentity() === null; - } - - /** - * Returns a value that uniquely represents the user. - * @return string|integer the unique identifier for the user. If null, it means the user is a guest. - */ - public function getId() - { - return Yii::$app->getSession()->get($this->idVar); - } - - /** - * Returns the URL that the user should be redirected to after successful login. - * This property is usually used by the login action. If the login is successful, - * the action should read this property and use it to redirect the user browser. - * @param string|array $defaultUrl the default return URL in case it was not set previously. - * If this is null and the return URL was not set previously, [[Application::homeUrl]] will be redirected to. - * Please refer to [[setReturnUrl()]] on accepted format of the URL. - * @return string the URL that the user should be redirected to after login. - * @see loginRequired() - */ - public function getReturnUrl($defaultUrl = null) - { - $url = Yii::$app->getSession()->get($this->returnUrlVar, $defaultUrl); - if (is_array($url)) { - if (isset($url[0])) { - $route = array_shift($url); - return Yii::$app->getUrlManager()->createUrl($route, $url); - } else { - $url = null; - } - } - return $url === null ? Yii::$app->getHomeUrl() : $url; - } - - /** - * @param string|array $url the URL that the user should be redirected to after login. - * If an array is given, [[UrlManager::createUrl()]] will be called to create the corresponding URL. - * The first element of the array should be the route, and the rest of - * the name-value pairs are GET parameters used to construct the URL. For example, - * - * ~~~ - * ['admin/index', 'ref' => 1] - * ~~~ - */ - public function setReturnUrl($url) - { - Yii::$app->getSession()->set($this->returnUrlVar, $url); - } - - /** - * Redirects the user browser to the login page. - * Before the redirection, the current URL (if it's not an AJAX url) will be - * kept as [[returnUrl]] so that the user browser may be redirected back - * to the current page after successful login. Make sure you set [[loginUrl]] - * so that the user browser can be redirected to the specified login URL after - * calling this method. - * - * Note that when [[loginUrl]] is set, calling this method will NOT terminate the application execution. - * - * @return Response the redirection response if [[loginUrl]] is set - * @throws AccessDeniedHttpException the "Access Denied" HTTP exception if [[loginUrl]] is not set - */ - public function loginRequired() - { - $request = Yii::$app->getRequest(); - if (!$request->getIsAjax()) { - $this->setReturnUrl($request->getUrl()); - } - if ($this->loginUrl !== null) { - return Yii::$app->getResponse()->redirect($this->loginUrl); - } else { - throw new AccessDeniedHttpException(Yii::t('yii', 'Login Required')); - } - } - - /** - * This method is called before logging in a user. - * The default implementation will trigger the [[EVENT_BEFORE_LOGIN]] event. - * If you override this method, make sure you call the parent implementation - * so that the event is triggered. - * @param IdentityInterface $identity the user identity information - * @param boolean $cookieBased whether the login is cookie-based - * @return boolean whether the user should continue to be logged in - */ - protected function beforeLogin($identity, $cookieBased) - { - $event = new UserEvent([ - 'identity' => $identity, - 'cookieBased' => $cookieBased, - ]); - $this->trigger(self::EVENT_BEFORE_LOGIN, $event); - return $event->isValid; - } - - /** - * This method is called after the user is successfully logged in. - * The default implementation will trigger the [[EVENT_AFTER_LOGIN]] event. - * If you override this method, make sure you call the parent implementation - * so that the event is triggered. - * @param IdentityInterface $identity the user identity information - * @param boolean $cookieBased whether the login is cookie-based - */ - protected function afterLogin($identity, $cookieBased) - { - $this->trigger(self::EVENT_AFTER_LOGIN, new UserEvent([ - 'identity' => $identity, - 'cookieBased' => $cookieBased, - ])); - } - - /** - * This method is invoked when calling [[logout()]] to log out a user. - * The default implementation will trigger the [[EVENT_BEFORE_LOGOUT]] event. - * If you override this method, make sure you call the parent implementation - * so that the event is triggered. - * @param IdentityInterface $identity the user identity information - * @return boolean whether the user should continue to be logged out - */ - protected function beforeLogout($identity) - { - $event = new UserEvent([ - 'identity' => $identity, - ]); - $this->trigger(self::EVENT_BEFORE_LOGOUT, $event); - return $event->isValid; - } - - /** - * This method is invoked right after a user is logged out via [[logout()]]. - * The default implementation will trigger the [[EVENT_AFTER_LOGOUT]] event. - * If you override this method, make sure you call the parent implementation - * so that the event is triggered. - * @param IdentityInterface $identity the user identity information - */ - protected function afterLogout($identity) - { - $this->trigger(self::EVENT_AFTER_LOGOUT, new UserEvent([ - 'identity' => $identity, - ])); - } - - /** - * Renews the identity cookie. - * This method will set the expiration time of the identity cookie to be the current time - * plus the originally specified cookie duration. - */ - protected function renewIdentityCookie() - { - $name = $this->identityCookie['name']; - $value = Yii::$app->getRequest()->getCookies()->getValue($name); - if ($value !== null) { - $data = json_decode($value, true); - if (is_array($data) && isset($data[2])) { - $cookie = new Cookie($this->identityCookie); - $cookie->value = $value; - $cookie->expire = time() + (int)$data[2]; - Yii::$app->getResponse()->getCookies()->add($cookie); - } - } - } - - /** - * Sends an identity cookie. - * This method is used when [[enableAutoLogin]] is true. - * It saves [[id]], [[IdentityInterface::getAuthKey()|auth key]], and the duration of cookie-based login - * information in the cookie. - * @param IdentityInterface $identity - * @param integer $duration number of seconds that the user can remain in logged-in status. - * @see loginByCookie() - */ - protected function sendIdentityCookie($identity, $duration) - { - $cookie = new Cookie($this->identityCookie); - $cookie->value = json_encode([ - $identity->getId(), - $identity->getAuthKey(), - $duration, - ]); - $cookie->expire = time() + $duration; - Yii::$app->getResponse()->getCookies()->add($cookie); - } - - /** - * Switches to a new identity for the current user. - * - * This method will save necessary session information to keep track of the user authentication status. - * If `$duration` is provided, it will also send out appropriate identity cookie - * to support cookie-based login. - * - * This method is mainly called by [[login()]], [[logout()]] and [[loginByCookie()]] - * when the current user needs to be associated with the corresponding identity information. - * - * @param IdentityInterface $identity the identity information to be associated with the current user. - * If null, it means switching to be a guest. - * @param integer $duration number of seconds that the user can remain in logged-in status. - * This parameter is used only when `$identity` is not null. - */ - public function switchIdentity($identity, $duration = 0) - { - $session = Yii::$app->getSession(); - if (!YII_ENV_TEST) { - $session->regenerateID(true); - } - $this->setIdentity($identity); - $session->remove($this->idVar); - $session->remove($this->authTimeoutVar); - if ($identity instanceof IdentityInterface) { - $session->set($this->idVar, $identity->getId()); - if ($this->authTimeout !== null) { - $session->set($this->authTimeoutVar, time() + $this->authTimeout); - } - if ($duration > 0 && $this->enableAutoLogin) { - $this->sendIdentityCookie($identity, $duration); - } - } elseif ($this->enableAutoLogin) { - Yii::$app->getResponse()->getCookies()->remove(new Cookie($this->identityCookie)); - } - } - - /** - * Updates the authentication status according to [[authTimeout]]. - * This method is called during [[init()]]. - * It will update the user's authentication status if it has not outdated yet. - * Otherwise, it will logout the user. - */ - protected function renewAuthStatus() - { - if ($this->authTimeout !== null && !$this->getIsGuest()) { - $expire = Yii::$app->getSession()->get($this->authTimeoutVar); - if ($expire !== null && $expire < time()) { - $this->logout(false); - } else { - Yii::$app->getSession()->set($this->authTimeoutVar, time() + $this->authTimeout); - } - } - } - - /** - * Performs access check for this user. - * @param string $operation the name of the operation that need access check. - * @param array $params name-value pairs that would be passed to business rules associated - * with the tasks and roles assigned to the user. A param with name 'userId' is added to - * this array, which holds the value of [[id]] when [[DbAuthManager]] or - * [[PhpAuthManager]] is used. - * @param boolean $allowCaching whether to allow caching the result of access check. - * When this parameter is true (default), if the access check of an operation was performed - * before, its result will be directly returned when calling this method to check the same - * operation. If this parameter is false, this method will always call - * [[AuthManager::checkAccess()]] to obtain the up-to-date access result. Note that this - * caching is effective only within the same request and only works when `$params = []`. - * @return boolean whether the operations can be performed by this user. - */ - public function checkAccess($operation, $params = [], $allowCaching = true) - { - $auth = Yii::$app->getAuthManager(); - if ($auth === null) { - return false; - } - if ($allowCaching && empty($params) && isset($this->_access[$operation])) { - return $this->_access[$operation]; - } - $access = $auth->checkAccess($this->getId(), $operation, $params); - if ($allowCaching && empty($params)) { - $this->_access[$operation] = $access; - } - return $access; - } -} diff --git a/framework/yii/web/UserEvent.php b/framework/yii/web/UserEvent.php deleted file mode 100644 index 8577ef5..0000000 --- a/framework/yii/web/UserEvent.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @since 2.0 - */ -class UserEvent extends Event -{ - /** - * @var IdentityInterface the identity object associated with this event - */ - public $identity; - /** - * @var boolean whether the login is cookie-based. This property is only meaningful - * for [[User::EVENT_BEFORE_LOGIN]] and [[User::EVENT_AFTER_LOGIN]] events. - */ - public $cookieBased; - /** - * @var boolean whether the login or logout should proceed. - * Event handlers may modify this property to determine whether the login or logout should proceed. - * This property is only meaningful for [[User::EVENT_BEFORE_LOGIN]] and [[User::EVENT_BEFORE_LOGOUT]] events. - */ - public $isValid = true; -} diff --git a/framework/yii/web/VerbFilter.php b/framework/yii/web/VerbFilter.php deleted file mode 100644 index 1ca08c2..0000000 --- a/framework/yii/web/VerbFilter.php +++ /dev/null @@ -1,108 +0,0 @@ - [ - * 'class' => \yii\web\VerbFilter::className(), - * 'actions' => [ - * 'index' => ['get'], - * 'view' => ['get'], - * 'create' => ['get', 'post'], - * 'update' => ['get', 'put', 'post'], - * 'delete' => ['post', 'delete'], - * ], - * ], - * ]; - * } - * ~~~ - * - * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.7 - * @author Carsten Brandt - * @since 2.0 - */ -class VerbFilter extends Behavior -{ - /** - * @var array this property defines the allowed request methods for each action. - * For each action that should only support limited set of request methods - * you add an entry with the action id as array key and an array of - * allowed methods (e.g. GET, HEAD, PUT) as the value. - * If an action is not listed all request methods are considered allowed. - * - * You can use '*' to stand for all actions. When an action is explicitly - * specified, it takes precedence over the specification given by '*'. - * - * For example, - * - * ~~~ - * [ - * 'create' => ['get', 'post'], - * 'update' => ['get', 'put', 'post'], - * 'delete' => ['post', 'delete'], - * '*' => ['get'], - * ] - * ~~~ - */ - public $actions = []; - - - /** - * Declares event handlers for the [[owner]]'s events. - * @return array events (array keys) and the corresponding event handler methods (array values). - */ - public function events() - { - return [Controller::EVENT_BEFORE_ACTION => 'beforeAction']; - } - - /** - * @param ActionEvent $event - * @return boolean - * @throws HttpException when the request method is not allowed. - */ - public function beforeAction($event) - { - $action = $event->action->id; - if (isset($this->actions[$action])) { - $verbs = $this->actions[$action]; - } elseif (isset($this->actions['*'])) { - $verbs = $this->actions['*']; - } else { - return $event->isValid; - } - - $verb = Yii::$app->getRequest()->getMethod(); - $allowed = array_map('strtoupper', $verbs); - if (!in_array($verb, array_map('strtoupper', $verbs))) { - $event->isValid = false; - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.7 - Yii::$app->getResponse()->getHeaders()->set('Allow', implode(', ', $allowed)); - throw new MethodNotAllowedHttpException('Method Not Allowed. This url can only handle the following request methods: ' . implode(', ', $allowed) . '.'); - } - - return $event->isValid; - } -} diff --git a/framework/yii/web/View.php b/framework/yii/web/View.php deleted file mode 100644 index 65addcf..0000000 --- a/framework/yii/web/View.php +++ /dev/null @@ -1,467 +0,0 @@ -view`. - * - * You can modify its configuration by adding an array to your application config under `components` - * as it is shown in the following example: - * - * ~~~ - * 'view' => [ - * 'theme' => 'app\themes\MyTheme', - * 'renderers' => [ - * // you may add Smarty or Twig renderer here - * ] - * // ... - * ] - * ~~~ - * - * @property \yii\web\AssetManager $assetManager The asset manager. Defaults to the "assetManager" application - * component. - * - * @author Qiang Xue - * @since 2.0 - */ -class View extends \yii\base\View -{ - const EVENT_BEGIN_BODY = 'beginBody'; - /** - * @event Event an event that is triggered by [[endBody()]]. - */ - const EVENT_END_BODY = 'endBody'; - - /** - * The location of registered JavaScript code block or files. - * This means the location is in the head section. - */ - const POS_HEAD = 1; - /** - * The location of registered JavaScript code block or files. - * This means the location is at the beginning of the body section. - */ - const POS_BEGIN = 2; - /** - * The location of registered JavaScript code block or files. - * This means the location is at the end of the body section. - */ - const POS_END = 3; - /** - * The location of registered JavaScript code block. - * This means the JavaScript code block will be enclosed within `jQuery(document).ready()`. - */ - const POS_READY = 4; - /** - * This is internally used as the placeholder for receiving the content registered for the head section. - */ - const PH_HEAD = ''; - /** - * This is internally used as the placeholder for receiving the content registered for the beginning of the body section. - */ - const PH_BODY_BEGIN = ''; - /** - * This is internally used as the placeholder for receiving the content registered for the end of the body section. - */ - const PH_BODY_END = ''; - - /** - * @var AssetBundle[] list of the registered asset bundles. The keys are the bundle names, and the values - * are the registered [[AssetBundle]] objects. - * @see registerAssetBundle() - */ - public $assetBundles = []; - /** - * @var string the page title - */ - public $title; - /** - * @var array the registered meta tags. - * @see registerMetaTag() - */ - public $metaTags; - /** - * @var array the registered link tags. - * @see registerLinkTag() - */ - public $linkTags; - /** - * @var array the registered CSS code blocks. - * @see registerCss() - */ - public $css; - /** - * @var array the registered CSS files. - * @see registerCssFile() - */ - public $cssFiles; - /** - * @var array the registered JS code blocks - * @see registerJs() - */ - public $js; - /** - * @var array the registered JS files. - * @see registerJsFile() - */ - public $jsFiles; - - private $_assetManager; - - /** - * Registers the asset manager being used by this view object. - * @return \yii\web\AssetManager the asset manager. Defaults to the "assetManager" application component. - */ - public function getAssetManager() - { - return $this->_assetManager ?: Yii::$app->getAssetManager(); - } - - /** - * Sets the asset manager. - * @param \yii\web\AssetManager $value the asset manager - */ - public function setAssetManager($value) - { - $this->_assetManager = $value; - } - - /** - * Marks the ending of an HTML page. - */ - public function endPage() - { - $this->trigger(self::EVENT_END_PAGE); - - $content = ob_get_clean(); - foreach (array_keys($this->assetBundles) as $bundle) { - $this->registerAssetFiles($bundle); - } - echo strtr($content, [ - self::PH_HEAD => $this->renderHeadHtml(), - self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(), - self::PH_BODY_END => $this->renderBodyEndHtml(), - ]); - - $this->metaTags = null; - $this->linkTags = null; - $this->css = null; - $this->cssFiles = null; - $this->js = null; - $this->jsFiles = null; - } - - /** - * Registers all files provided by an asset bundle including depending bundles files. - * Removes a bundle from [[assetBundles]] once files are registered. - * @param string $name name of the bundle to register - */ - private function registerAssetFiles($name) - { - if (!isset($this->assetBundles[$name])) { - return; - } - $bundle = $this->assetBundles[$name]; - if ($bundle) { - foreach ($bundle->depends as $dep) { - $this->registerAssetFiles($dep); - } - $bundle->registerAssetFiles($this); - } - unset($this->assetBundles[$name]); - } - - /** - * Marks the beginning of an HTML body section. - */ - public function beginBody() - { - echo self::PH_BODY_BEGIN; - $this->trigger(self::EVENT_BEGIN_BODY); - } - - /** - * Marks the ending of an HTML body section. - */ - public function endBody() - { - $this->trigger(self::EVENT_END_BODY); - echo self::PH_BODY_END; - } - - /** - * Marks the position of an HTML head section. - */ - public function head() - { - echo self::PH_HEAD; - } - - /** - * Registers the named asset bundle. - * All dependent asset bundles will be registered. - * @param string $name the name of the asset bundle. - * @param integer|null $position if set, this forces a minimum position for javascript files. - * This will adjust depending assets javascript file position or fail if requirement can not be met. - * If this is null, asset bundles position settings will not be changed. - * See [[registerJsFile]] for more details on javascript position. - * @return AssetBundle the registered asset bundle instance - * @throws InvalidConfigException if the asset bundle does not exist or a circular dependency is detected - */ - public function registerAssetBundle($name, $position = null) - { - if (!isset($this->assetBundles[$name])) { - $am = $this->getAssetManager(); - $bundle = $am->getBundle($name); - $this->assetBundles[$name] = false; - // register dependencies - $pos = isset($bundle->jsOptions['position']) ? $bundle->jsOptions['position'] : null; - foreach ($bundle->depends as $dep) { - $this->registerAssetBundle($dep, $pos); - } - $this->assetBundles[$name] = $bundle; - } elseif ($this->assetBundles[$name] === false) { - throw new InvalidConfigException("A circular dependency is detected for bundle '$name'."); - } else { - $bundle = $this->assetBundles[$name]; - } - - if ($position !== null) { - $pos = isset($bundle->jsOptions['position']) ? $bundle->jsOptions['position'] : null; - if ($pos === null) { - $bundle->jsOptions['position'] = $pos = $position; - } elseif ($pos > $position) { - throw new InvalidConfigException("An asset bundle that depends on '$name' has a higher javascript file position configured than '$name'."); - } - // update position for all dependencies - foreach ($bundle->depends as $dep) { - $this->registerAssetBundle($dep, $pos); - } - } - return $bundle; - } - - /** - * Registers a meta tag. - * @param array $options the HTML attributes for the meta tag. - * @param string $key the key that identifies the meta tag. If two meta tags are registered - * with the same key, the latter will overwrite the former. If this is null, the new meta tag - * will be appended to the existing ones. - */ - public function registerMetaTag($options, $key = null) - { - if ($key === null) { - $this->metaTags[] = Html::tag('meta', '', $options); - } else { - $this->metaTags[$key] = Html::tag('meta', '', $options); - } - } - - /** - * Registers a link tag. - * @param array $options the HTML attributes for the link tag. - * @param string $key the key that identifies the link tag. If two link tags are registered - * with the same key, the latter will overwrite the former. If this is null, the new link tag - * will be appended to the existing ones. - */ - public function registerLinkTag($options, $key = null) - { - if ($key === null) { - $this->linkTags[] = Html::tag('link', '', $options); - } else { - $this->linkTags[$key] = Html::tag('link', '', $options); - } - } - - /** - * Registers a CSS code block. - * @param string $css the CSS code block to be registered - * @param array $options the HTML attributes for the style tag. - * @param string $key the key that identifies the CSS code block. If null, it will use - * $css as the key. If two CSS code blocks are registered with the same key, the latter - * will overwrite the former. - */ - public function registerCss($css, $options = [], $key = null) - { - $key = $key ?: md5($css); - $this->css[$key] = Html::style($css, $options); - } - - /** - * Registers a CSS file. - * @param string $url the CSS file to be registered. - * @param array $depends the names of the asset bundles that this CSS file depends on - * @param array $options the HTML attributes for the link tag. - * @param string $key the key that identifies the CSS script file. If null, it will use - * $url as the key. If two CSS files are registered with the same key, the latter - * will overwrite the former. - */ - public function registerCssFile($url, $depends = [], $options = [], $key = null) - { - $key = $key ?: $url; - if (empty($depends)) { - $this->cssFiles[$key] = Html::cssFile($url, $options); - } else { - $am = Yii::$app->getAssetManager(); - $am->bundles[$key] = new AssetBundle([ - 'css' => [$url], - 'cssOptions' => $options, - 'depends' => (array)$depends, - ]); - $this->registerAssetBundle($key); - } - } - - /** - * Registers a JS code block. - * @param string $js the JS code block to be registered - * @param integer $position the position at which the JS script tag should be inserted - * in a page. The possible values are: - * - * - [[POS_HEAD]]: in the head section - * - [[POS_BEGIN]]: at the beginning of the body section - * - [[POS_END]]: at the end of the body section - * - [[POS_READY]]: enclosed within jQuery(document).ready(). This is the default value. - * Note that by using this position, the method will automatically register the jQuery js file. - * - * @param string $key the key that identifies the JS code block. If null, it will use - * $js as the key. If two JS code blocks are registered with the same key, the latter - * will overwrite the former. - */ - public function registerJs($js, $position = self::POS_READY, $key = null) - { - $key = $key ?: md5($js); - $this->js[$position][$key] = $js; - if ($position === self::POS_READY) { - JqueryAsset::register($this); - } - } - - /** - * Registers a JS file. - * @param string $url the JS file to be registered. - * @param array $depends the names of the asset bundles that this JS file depends on - * @param array $options the HTML attributes for the script tag. A special option - * named "position" is supported which specifies where the JS script tag should be inserted - * in a page. The possible values of "position" are: - * - * - [[POS_HEAD]]: in the head section - * - [[POS_BEGIN]]: at the beginning of the body section - * - [[POS_END]]: at the end of the body section. This is the default value. - * - * @param string $key the key that identifies the JS script file. If null, it will use - * $url as the key. If two JS files are registered with the same key, the latter - * will overwrite the former. - */ - public function registerJsFile($url, $depends = [], $options = [], $key = null) - { - $key = $key ?: $url; - if (empty($depends)) { - $position = isset($options['position']) ? $options['position'] : self::POS_END; - unset($options['position']); - $this->jsFiles[$position][$key] = Html::jsFile($url, $options); - } else { - $am = Yii::$app->getAssetManager(); - $am->bundles[$key] = new AssetBundle([ - 'js' => [$url], - 'jsOptions' => $options, - 'depends' => (array)$depends, - ]); - $this->registerAssetBundle($key); - } - } - - /** - * Renders the content to be inserted in the head section. - * The content is rendered using the registered meta tags, link tags, CSS/JS code blocks and files. - * @return string the rendered content - */ - protected function renderHeadHtml() - { - $lines = []; - if (!empty($this->metaTags)) { - $lines[] = implode("\n", $this->metaTags); - } - - $request = Yii::$app->getRequest(); - if ($request instanceof \yii\web\Request && $request->enableCsrfValidation) { - $lines[] = Html::tag('meta', '', ['name' => 'csrf-var', 'content' => $request->csrfVar]); - $lines[] = Html::tag('meta', '', ['name' => 'csrf-token', 'content' => $request->getMaskedCsrfToken()]); - } - - if (!empty($this->linkTags)) { - $lines[] = implode("\n", $this->linkTags); - } - if (!empty($this->cssFiles)) { - $lines[] = implode("\n", $this->cssFiles); - } - if (!empty($this->css)) { - $lines[] = implode("\n", $this->css); - } - if (!empty($this->jsFiles[self::POS_HEAD])) { - $lines[] = implode("\n", $this->jsFiles[self::POS_HEAD]); - } - if (!empty($this->js[self::POS_HEAD])) { - $lines[] = Html::script(implode("\n", $this->js[self::POS_HEAD]), ['type' => 'text/javascript']); - } - return empty($lines) ? '' : implode("\n", $lines); - } - - /** - * Renders the content to be inserted at the beginning of the body section. - * The content is rendered using the registered JS code blocks and files. - * @return string the rendered content - */ - protected function renderBodyBeginHtml() - { - $lines = []; - if (!empty($this->jsFiles[self::POS_BEGIN])) { - $lines[] = implode("\n", $this->jsFiles[self::POS_BEGIN]); - } - if (!empty($this->js[self::POS_BEGIN])) { - $lines[] = Html::script(implode("\n", $this->js[self::POS_BEGIN]), ['type' => 'text/javascript']); - } - return empty($lines) ? '' : implode("\n", $lines); - } - - /** - * Renders the content to be inserted at the end of the body section. - * The content is rendered using the registered JS code blocks and files. - * @return string the rendered content - */ - protected function renderBodyEndHtml() - { - $lines = []; - if (!empty($this->jsFiles[self::POS_END])) { - $lines[] = implode("\n", $this->jsFiles[self::POS_END]); - } - if (!empty($this->js[self::POS_END])) { - $lines[] = Html::script(implode("\n", $this->js[self::POS_END]), ['type' => 'text/javascript']); - } - if (!empty($this->js[self::POS_READY])) { - $js = "jQuery(document).ready(function(){\n" . implode("\n", $this->js[self::POS_READY]) . "\n});"; - $lines[] = Html::script($js, ['type' => 'text/javascript']); - } - return empty($lines) ? '' : implode("\n", $lines); - } -} diff --git a/framework/yii/web/XmlResponseFormatter.php b/framework/yii/web/XmlResponseFormatter.php deleted file mode 100644 index 292424a..0000000 --- a/framework/yii/web/XmlResponseFormatter.php +++ /dev/null @@ -1,98 +0,0 @@ - - * @since 2.0 - */ -class XmlResponseFormatter extends Component implements ResponseFormatterInterface -{ - /** - * @var string the Content-Type header for the response - */ - public $contentType = 'application/xml'; - /** - * @var string the XML version - */ - public $version = '1.0'; - /** - * @var string the XML encoding. If not set, it will use the value of [[Response::charset]]. - */ - public $encoding; - /** - * @var string the name of the root element. - */ - public $rootTag = 'response'; - /** - * @var string the name of the elements that represent the array elements with numeric keys. - */ - public $itemTag = 'item'; - - /** - * Formats the specified response. - * @param Response $response the response to be formatted. - */ - public function format($response) - { - $response->getHeaders()->set('Content-Type', $this->contentType); - $dom = new DOMDocument($this->version, $this->encoding === null ? $response->charset : $this->encoding); - $root = new DOMElement($this->rootTag); - $dom->appendChild($root); - $this->buildXml($root, $response->data); - $response->content = $dom->saveXML(); - } - - /** - * @param DOMElement $element - * @param mixed $data - */ - protected function buildXml($element, $data) - { - if (is_object($data)) { - $child = new DOMElement(StringHelper::basename(get_class($data))); - $element->appendChild($child); - if ($data instanceof Arrayable) { - $this->buildXml($child, $data->toArray()); - } else { - $array = []; - foreach ($data as $name => $value) { - $array[$name] = $value; - } - $this->buildXml($child, $array); - } - } elseif (is_array($data)) { - foreach ($data as $name => $value) { - if (is_int($name) && is_object($value)) { - $this->buildXml($element, $value); - } elseif (is_array($value) || is_object($value)) { - $child = new DOMElement(is_int($name) ? $this->itemTag : $name); - $element->appendChild($child); - $this->buildXml($child, $value); - } else { - $child = new DOMElement(is_int($name) ? $this->itemTag : $name); - $element->appendChild($child); - $child->appendChild(new DOMText((string)$value)); - } - } - } else { - $element->appendChild(new DOMText((string)$data)); - } - } -} diff --git a/framework/yii/web/YiiAsset.php b/framework/yii/web/YiiAsset.php deleted file mode 100644 index d38b711..0000000 --- a/framework/yii/web/YiiAsset.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class YiiAsset extends AssetBundle -{ - public $sourcePath = '@yii/assets'; - public $js = [ - 'yii.js', - ]; - public $depends = [ - 'yii\web\JqueryAsset', - ]; -} diff --git a/framework/yii/widgets/ActiveField.php b/framework/yii/widgets/ActiveField.php deleted file mode 100644 index 13e510e..0000000 --- a/framework/yii/widgets/ActiveField.php +++ /dev/null @@ -1,657 +0,0 @@ - - * @since 2.0 - */ -class ActiveField extends Component -{ - /** - * @var ActiveForm the form that this field is associated with. - */ - public $form; - /** - * @var Model the data model that this field is associated with - */ - public $model; - /** - * @var string the model attribute that this field is associated with - */ - public $attribute; - /** - * @var array the HTML attributes (name-value pairs) for the field container tag. - * The values will be HTML-encoded using [[Html::encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - * The following special options are recognized: - * - * - tag: the tag name of the container element. Defaults to "div". - */ - public $options = ['class' => 'form-group']; - /** - * @var string the template that is used to arrange the label, the input field, the error message and the hint text. - * The following tokens will be replaced when [[render()]] is called: `{label}`, `{input}`, `{error}` and `{hint}`. - */ - public $template = "{label}\n{input}\n{hint}\n{error}"; - /** - * @var array the default options for the input tags. The parameter passed to individual input methods - * (e.g. [[textInput()]]) will be merged with this property when rendering the input tag. - */ - public $inputOptions = ['class' => 'form-control']; - /** - * @var array the default options for the error tags. The parameter passed to [[error()]] will be - * merged with this property when rendering the error tag. - * The following special options are recognized: - * - * - tag: the tag name of the container element. Defaults to "div". - */ - public $errorOptions = ['class' => 'help-block']; - /** - * @var array the default options for the label tags. The parameter passed to [[label()]] will be - * merged with this property when rendering the label tag. - */ - public $labelOptions = ['class' => 'control-label']; - /** - * @var array the default options for the hint tags. The parameter passed to [[hint()]] will be - * merged with this property when rendering the hint tag. - * The following special options are recognized: - * - * - tag: the tag name of the container element. Defaults to "div". - */ - public $hintOptions = ['class' => 'hint-block']; - /** - * @var boolean whether to enable client-side data validation. - * If not set, it will take the value of [[ActiveForm::enableClientValidation]]. - */ - public $enableClientValidation; - /** - * @var boolean whether to enable AJAX-based data validation. - * If not set, it will take the value of [[ActiveForm::enableAjaxValidation]]. - */ - public $enableAjaxValidation; - /** - * @var boolean whether to perform validation when the input field loses focus and its value is found changed. - * If not set, it will take the value of [[ActiveForm::validateOnChange]]. - */ - public $validateOnChange; - /** - * @var boolean whether to perform validation while the user is typing in the input field. - * If not set, it will take the value of [[ActiveForm::validateOnType]]. - * @see validationDelay - */ - public $validateOnType; - /** - * @var integer number of milliseconds that the validation should be delayed when the input field - * is changed or the user types in the field. - * If not set, it will take the value of [[ActiveForm::validationDelay]]. - */ - public $validationDelay; - /** - * @var array the jQuery selectors for selecting the container, input and error tags. - * The array keys should be "container", "input", and/or "error", and the array values - * are the corresponding selectors. For example, `['input' => '#my-input']`. - * - * The container selector is used under the context of the form, while the input and the error - * selectors are used under the context of the container. - * - * You normally do not need to set this property as the default selectors should work well for most cases. - */ - public $selectors; - /** - * @var array different parts of the field (e.g. input, label). This will be used together with - * [[template]] to generate the final field HTML code. The keys are the token names in [[template]], - * while the values are the corresponding HTML code. Valid tokens include `{input}`, `{label}` and `{error}`. - * Note that you normally don't need to access this property directly as - * it is maintained by various methods of this class. - */ - public $parts = []; - - - /** - * PHP magic method that returns the string representation of this object. - * @return string the string representation of this object. - */ - public function __toString() - { - // __toString cannot throw exception - // use trigger_error to bypass this limitation - try { - return $this->render(); - } catch (\Exception $e) { - trigger_error($e->getMessage() . "\n\n" . $e->getTraceAsString()); - return ''; - } - } - - /** - * Renders the whole field. - * This method will generate the label, error tag, input tag and hint tag (if any), and - * assemble them into HTML according to [[template]]. - * @param string|callable $content the content within the field container. - * If null (not set), the default methods will be called to generate the label, error tag and input tag, - * and use them as the content. - * If a callable, it will be called to generate the content. The signature of the callable should be: - * - * ~~~ - * function ($field) { - * return $html; - * } - * ~~~ - * - * @return string the rendering result - */ - public function render($content = null) - { - if ($content === null) { - if (!isset($this->parts['{input}'])) { - $this->parts['{input}'] = Html::activeTextInput($this->model, $this->attribute, $this->inputOptions); - } - if (!isset($this->parts['{label}'])) { - $this->parts['{label}'] = Html::activeLabel($this->model, $this->attribute, $this->labelOptions); - } - if (!isset($this->parts['{error}'])) { - $this->parts['{error}'] = Html::error($this->model, $this->attribute, $this->errorOptions); - } - if (!isset($this->parts['{hint}'])) { - $this->parts['{hint}'] = ''; - } - $content = strtr($this->template, $this->parts); - } elseif (!is_string($content)) { - $content = call_user_func($content, $this); - } - return $this->begin() . "\n" . $content . "\n" . $this->end(); - } - - /** - * Renders the opening tag of the field container. - * @return string the rendering result. - */ - public function begin() - { - $clientOptions = $this->getClientOptions(); - if (!empty($clientOptions)) { - $this->form->attributes[$this->attribute] = $clientOptions; - } - - $inputID = Html::getInputId($this->model, $this->attribute); - $attribute = Html::getAttributeName($this->attribute); - $options = $this->options; - $class = isset($options['class']) ? [$options['class']] : []; - $class[] = "field-$inputID"; - if ($this->model->isAttributeRequired($attribute)) { - $class[] = $this->form->requiredCssClass; - } - if ($this->model->hasErrors($attribute)) { - $class[] = $this->form->errorCssClass; - } - $options['class'] = implode(' ', $class); - $tag = ArrayHelper::remove($options, 'tag', 'div'); - - return Html::beginTag($tag, $options); - } - - /** - * Renders the closing tag of the field container. - * @return string the rendering result. - */ - public function end() - { - return Html::endTag(isset($this->options['tag']) ? $this->options['tag'] : 'div'); - } - - /** - * Generates a label tag for [[attribute]]. - * @param string $label the label to use. If null, it will be generated via [[Model::getAttributeLabel()]]. - * Note that this will NOT be [[Html::encode()|encoded]]. - * @param array $options the tag options in terms of name-value pairs. It will be merged with [[labelOptions]]. - * The options will be rendered as the attributes of the resulting tag. The values will be HTML-encoded - * using [[Html::encode()]]. If a value is null, the corresponding attribute will not be rendered. - * @return static the field object itself - */ - public function label($label = null, $options = []) - { - $options = array_merge($this->labelOptions, $options); - if ($label !== null) { - $options['label'] = $label; - } - $this->parts['{label}'] = Html::activeLabel($this->model, $this->attribute, $options); - return $this; - } - - /** - * Generates a tag that contains the first validation error of [[attribute]]. - * Note that even if there is no validation error, this method will still return an empty error tag. - * @param array $options the tag options in terms of name-value pairs. It will be merged with [[errorOptions]]. - * The options will be rendered as the attributes of the resulting tag. The values will be HTML-encoded - * using [[Html::encode()]]. If a value is null, the corresponding attribute will not be rendered. - * - * The following options are specially handled: - * - * - tag: this specifies the tag name. If not set, "div" will be used. - * - * @return static the field object itself - */ - public function error($options = []) - { - $options = array_merge($this->errorOptions, $options); - $this->parts['{error}'] = Html::error($this->model, $this->attribute, $options); - return $this; - } - - /** - * Renders the hint tag. - * @param string $content the hint content. It will NOT be HTML-encoded. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the hint tag. The values will be HTML-encoded using [[Html::encode()]]. - * - * The following options are specially handled: - * - * - tag: this specifies the tag name. If not set, "div" will be used. - * - * @return static the field object itself - */ - public function hint($content, $options = []) - { - $options = array_merge($this->hintOptions, $options); - $tag = ArrayHelper::remove($options, 'tag', 'div'); - $this->parts['{hint}'] = Html::tag($tag, $content, $options); - return $this; - } - - /** - * Renders an input tag. - * @param string $type the input type (e.g. 'text', 'password') - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[Html::encode()]]. - * @return static the field object itself - */ - public function input($type, $options = []) - { - $options = array_merge($this->inputOptions, $options); - $this->adjustLabelFor($options); - $this->parts['{input}'] = Html::activeInput($type, $this->model, $this->attribute, $options); - return $this; - } - - /** - * Renders a text input. - * This method will generate the "name" and "value" tag attributes automatically for the model attribute - * unless they are explicitly specified in `$options`. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[Html::encode()]]. - * @return static the field object itself - */ - public function textInput($options = []) - { - $options = array_merge($this->inputOptions, $options); - $this->adjustLabelFor($options); - $this->parts['{input}'] = Html::activeTextInput($this->model, $this->attribute, $options); - return $this; - } - - /** - * Renders a password input. - * This method will generate the "name" and "value" tag attributes automatically for the model attribute - * unless they are explicitly specified in `$options`. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[Html::encode()]]. - * @return static the field object itself - */ - public function passwordInput($options = []) - { - $options = array_merge($this->inputOptions, $options); - $this->adjustLabelFor($options); - $this->parts['{input}'] = Html::activePasswordInput($this->model, $this->attribute, $options); - return $this; - } - - /** - * Renders a file input. - * This method will generate the "name" and "value" tag attributes automatically for the model attribute - * unless they are explicitly specified in `$options`. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[Html::encode()]]. - * @return static the field object itself - */ - public function fileInput($options = []) - { - // https://github.com/yiisoft/yii2/pull/795 - if ($this->inputOptions !== ['class' => 'form-control']) { - $options = array_merge($this->inputOptions, $options); - } - $this->adjustLabelFor($options); - $this->parts['{input}'] = Html::activeFileInput($this->model, $this->attribute, $options); - return $this; - } - - /** - * Renders a text area. - * The model attribute value will be used as the content in the textarea. - * @param array $options the tag options in terms of name-value pairs. These will be rendered as - * the attributes of the resulting tag. The values will be HTML-encoded using [[Html::encode()]]. - * @return static the field object itself - */ - public function textarea($options = []) - { - $options = array_merge($this->inputOptions, $options); - $this->adjustLabelFor($options); - $this->parts['{input}'] = Html::activeTextarea($this->model, $this->attribute, $options); - return $this; - } - - /** - * Renders a radio button. - * This method will generate the "checked" tag attribute according to the model attribute value. - * @param array $options the tag options in terms of name-value pairs. The following options are specially handled: - * - * - uncheck: string, the value associated with the uncheck state of the radio button. If not set, - * it will take the default value '0'. This method will render a hidden input so that if the radio button - * is not checked and is submitted, the value of this attribute will still be submitted to the server - * via the hidden input. - * - label: string, a label displayed next to the radio button. It will NOT be HTML-encoded. Therefore you can pass - * in HTML code such as an image tag. If this is is coming from end users, you should [[Html::encode()]] it to prevent XSS attacks. - * When this option is specified, the radio button will be enclosed by a label tag. - * - labelOptions: array, the HTML attributes for the label tag. This is only used when the "label" option is specified. - * - * The rest of the options will be rendered as the attributes of the resulting tag. The values will - * be HTML-encoded using [[Html::encode()]]. If a value is null, the corresponding attribute will not be rendered. - * @param boolean $enclosedByLabel whether to enclose the radio within the label. - * If true, the method will still use [[template]] to layout the checkbox and the error message - * except that the radio is enclosed by the label tag. - * @return static the field object itself - */ - public function radio($options = [], $enclosedByLabel = true) - { - if ($enclosedByLabel) { - if (!isset($options['label'])) { - $attribute = Html::getAttributeName($this->attribute); - $options['label'] = Html::encode($this->model->getAttributeLabel($attribute)); - } - $this->parts['{input}'] = Html::activeRadio($this->model, $this->attribute, $options); - $this->parts['{label}'] = ''; - } else { - $this->parts['{input}'] = Html::activeRadio($this->model, $this->attribute, $options); - } - $this->adjustLabelFor($options); - return $this; - } - - /** - * Renders a checkbox. - * This method will generate the "checked" tag attribute according to the model attribute value. - * @param array $options the tag options in terms of name-value pairs. The following options are specially handled: - * - * - uncheck: string, the value associated with the uncheck state of the radio button. If not set, - * it will take the default value '0'. This method will render a hidden input so that if the radio button - * is not checked and is submitted, the value of this attribute will still be submitted to the server - * via the hidden input. - * - label: string, a label displayed next to the checkbox. It will NOT be HTML-encoded. Therefore you can pass - * in HTML code such as an image tag. If this is is coming from end users, you should [[Html::encode()]] it to prevent XSS attacks. - * When this option is specified, the checkbox will be enclosed by a label tag. - * - labelOptions: array, the HTML attributes for the label tag. This is only used when the "label" option is specified. - * - * The rest of the options will be rendered as the attributes of the resulting tag. The values will - * be HTML-encoded using [[Html::encode()]]. If a value is null, the corresponding attribute will not be rendered. - * @param boolean $enclosedByLabel whether to enclose the checkbox within the label. - * If true, the method will still use [[template]] to layout the checkbox and the error message - * except that the checkbox is enclosed by the label tag. - * @return static the field object itself - */ - public function checkbox($options = [], $enclosedByLabel = true) - { - if ($enclosedByLabel) { - if (!isset($options['label'])) { - $attribute = Html::getAttributeName($this->attribute); - $options['label'] = Html::encode($this->model->getAttributeLabel($attribute)); - } - $this->parts['{input}'] = Html::activeCheckbox($this->model, $this->attribute, $options); - $this->parts['{label}'] = ''; - } else { - $this->parts['{input}'] = Html::activeCheckbox($this->model, $this->attribute, $options); - } - $this->adjustLabelFor($options); - return $this; - } - - /** - * Renders a drop-down list. - * The selection of the drop-down list is taken from the value of the model attribute. - * @param array $items the option data items. The array keys are option values, and the array values - * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too). - * For each sub-array, an option group will be generated whose label is the key associated with the sub-array. - * If you have a list of data models, you may convert them into the format described above using - * [[ArrayHelper::map()]]. - * - * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in - * the labels will also be HTML-encoded. - * @param array $options the tag options in terms of name-value pairs. The following options are specially handled: - * - * - prompt: string, a prompt text to be displayed as the first option; - * - options: array, the attributes for the select option tags. The array keys must be valid option values, - * and the array values are the extra attributes for the corresponding option tags. For example, - * - * ~~~ - * [ - * 'value1' => ['disabled' => true], - * 'value2' => ['label' => 'value 2'], - * ]; - * ~~~ - * - * - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options', - * except that the array keys represent the optgroup labels specified in $items. - * - * The rest of the options will be rendered as the attributes of the resulting tag. The values will - * be HTML-encoded using [[Html::encode()]]. If a value is null, the corresponding attribute will not be rendered. - * - * @return static the field object itself - */ - public function dropDownList($items, $options = []) - { - $options = array_merge($this->inputOptions, $options); - $this->adjustLabelFor($options); - $this->parts['{input}'] = Html::activeDropDownList($this->model, $this->attribute, $items, $options); - return $this; - } - - /** - * Renders a list box. - * The selection of the list box is taken from the value of the model attribute. - * @param array $items the option data items. The array keys are option values, and the array values - * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too). - * For each sub-array, an option group will be generated whose label is the key associated with the sub-array. - * If you have a list of data models, you may convert them into the format described above using - * [[\yii\helpers\ArrayHelper::map()]]. - * - * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in - * the labels will also be HTML-encoded. - * @param array $options the tag options in terms of name-value pairs. The following options are specially handled: - * - * - prompt: string, a prompt text to be displayed as the first option; - * - options: array, the attributes for the select option tags. The array keys must be valid option values, - * and the array values are the extra attributes for the corresponding option tags. For example, - * - * ~~~ - * [ - * 'value1' => ['disabled' => true], - * 'value2' => ['label' => 'value 2'], - * ]; - * ~~~ - * - * - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options', - * except that the array keys represent the optgroup labels specified in $items. - * - unselect: string, the value that will be submitted when no option is selected. - * When this attribute is set, a hidden field will be generated so that if no option is selected in multiple - * mode, we can still obtain the posted unselect value. - * - * The rest of the options will be rendered as the attributes of the resulting tag. The values will - * be HTML-encoded using [[Html::encode()]]. If a value is null, the corresponding attribute will not be rendered. - * - * @return static the field object itself - */ - public function listBox($items, $options = []) - { - $options = array_merge($this->inputOptions, $options); - $this->adjustLabelFor($options); - $this->parts['{input}'] = Html::activeListBox($this->model, $this->attribute, $items, $options); - return $this; - } - - /** - * Renders a list of checkboxes. - * A checkbox list allows multiple selection, like [[listBox()]]. - * As a result, the corresponding submitted value is an array. - * The selection of the checkbox list is taken from the value of the model attribute. - * @param array $items the data item used to generate the checkboxes. - * The array values are the labels, while the array keys are the corresponding checkbox values. - * Note that the labels will NOT be HTML-encoded, while the values will. - * @param array $options options (name => config) for the checkbox list. The following options are specially handled: - * - * - unselect: string, the value that should be submitted when none of the checkboxes is selected. - * By setting this option, a hidden input will be generated. - * - separator: string, the HTML code that separates items. - * - item: callable, a callback that can be used to customize the generation of the HTML code - * corresponding to a single item in $items. The signature of this callback must be: - * - * ~~~ - * function ($index, $label, $name, $checked, $value) - * ~~~ - * - * where $index is the zero-based index of the checkbox in the whole list; $label - * is the label for the checkbox; and $name, $value and $checked represent the name, - * value and the checked status of the checkbox input. - * @return static the field object itself - */ - public function checkboxList($items, $options = []) - { - $this->adjustLabelFor($options); - $this->parts['{input}'] = Html::activeCheckboxList($this->model, $this->attribute, $items, $options); - return $this; - } - - /** - * Renders a list of radio buttons. - * A radio button list is like a checkbox list, except that it only allows single selection. - * The selection of the radio buttons is taken from the value of the model attribute. - * @param array $items the data item used to generate the radio buttons. - * The array keys are the labels, while the array values are the corresponding radio button values. - * Note that the labels will NOT be HTML-encoded, while the values will. - * @param array $options options (name => config) for the radio button list. The following options are specially handled: - * - * - unselect: string, the value that should be submitted when none of the radio buttons is selected. - * By setting this option, a hidden input will be generated. - * - separator: string, the HTML code that separates items. - * - item: callable, a callback that can be used to customize the generation of the HTML code - * corresponding to a single item in $items. The signature of this callback must be: - * - * ~~~ - * function ($index, $label, $name, $checked, $value) - * ~~~ - * - * where $index is the zero-based index of the radio button in the whole list; $label - * is the label for the radio button; and $name, $value and $checked represent the name, - * value and the checked status of the radio button input. - * @return static the field object itself - */ - public function radioList($items, $options = []) - { - $this->adjustLabelFor($options); - $this->parts['{input}'] = Html::activeRadioList($this->model, $this->attribute, $items, $options); - return $this; - } - - /** - * Renders a widget as the input of the field. - * - * Note that the widget must have both `model` and `attribute` properties. They will - * be initialized with [[model]] and [[attribute]] of this field, respectively. - * - * If you want to use a widget that does not have `model` and `attribute` properties, - * please use [[render()]] instead. - * - * @param string $class the widget class name - * @param array $config name-value pairs that will be used to initialize the widget - * @return static the field object itself - */ - public function widget($class, $config = []) - { - /** @var \yii\base\Widget $class */ - $config['model'] = $this->model; - $config['attribute'] = $this->attribute; - $config['view'] = $this->form->getView(); - $this->parts['{input}'] = $class::widget($config); - return $this; - } - - /** - * Adjusts the "for" attribute for the label based on the input options. - * @param array $options the input options - */ - protected function adjustLabelFor($options) - { - if (isset($options['id']) && !isset($this->labelOptions['for'])) { - $this->labelOptions['for'] = $options['id']; - } - } - - /** - * Returns the JS options for the field. - * @return array the JS options - */ - protected function getClientOptions() - { - $attribute = Html::getAttributeName($this->attribute); - if (!in_array($attribute, $this->model->activeAttributes(), true)) { - return []; - } - - $enableClientValidation = $this->enableClientValidation || $this->enableClientValidation === null && $this->form->enableClientValidation; - if ($enableClientValidation) { - $validators = []; - foreach ($this->model->getActiveValidators($attribute) as $validator) { - /** @var \yii\validators\Validator $validator */ - $js = $validator->clientValidateAttribute($this->model, $attribute, $this->form->getView()); - if ($validator->enableClientValidation && $js != '') { - $validators[] = $js; - } - } - if (!empty($validators)) { - $options['validate'] = new JsExpression("function(attribute, value, messages) {" . implode('', $validators) . '}'); - } - } - - $enableAjaxValidation = $this->enableAjaxValidation || $this->enableAjaxValidation === null && $this->form->enableAjaxValidation; - if ($enableAjaxValidation) { - $options['enableAjaxValidation'] = 1; - } - - if ($enableClientValidation && !empty($options['validate']) || $enableAjaxValidation) { - $inputID = Html::getInputId($this->model, $this->attribute); - $options['name'] = $inputID; - foreach (['validateOnChange', 'validateOnType', 'validationDelay'] as $name) { - $options[$name] = $this->$name === null ? $this->form->$name : $this->$name; - } - $options['container'] = isset($this->selectors['container']) ? $this->selectors['container'] : ".field-$inputID"; - $options['input'] = isset($this->selectors['input']) ? $this->selectors['input'] : "#$inputID"; - if (isset($this->errorOptions['class'])) { - $options['error'] = '.' . implode('.', preg_split('/\s+/', $this->errorOptions['class'], -1, PREG_SPLIT_NO_EMPTY)); - } else { - $options['error'] = isset($this->errorOptions['tag']) ? $this->errorOptions['tag'] : 'span'; - } - return $options; - } else { - return []; - } - } -} diff --git a/framework/yii/widgets/ActiveForm.php b/framework/yii/widgets/ActiveForm.php deleted file mode 100644 index b218a2e..0000000 --- a/framework/yii/widgets/ActiveForm.php +++ /dev/null @@ -1,357 +0,0 @@ - - * @since 2.0 - */ -class ActiveForm extends Widget -{ - /** - * @param array|string $action the form action URL. This parameter will be processed by [[\yii\helpers\Html::url()]]. - */ - public $action = ''; - /** - * @var string the form submission method. This should be either 'post' or 'get'. - * Defaults to 'post'. - */ - public $method = 'post'; - /** - * @var array the HTML attributes (name-value pairs) for the form tag. - * The values will be HTML-encoded using [[Html::encode()]]. - * If a value is null, the corresponding attribute will not be rendered. - */ - public $options = []; - /** - * @var array the default configuration used by [[field()]] when creating a new field object. - */ - public $fieldConfig; - /** - * @var string the default CSS class for the error summary container. - * @see errorSummary() - */ - public $errorSummaryCssClass = 'error-summary'; - /** - * @var string the CSS class that is added to a field container when the associated attribute is required. - */ - public $requiredCssClass = 'required'; - /** - * @var string the CSS class that is added to a field container when the associated attribute has validation error. - */ - public $errorCssClass = 'has-error'; - /** - * @var string the CSS class that is added to a field container when the associated attribute is successfully validated. - */ - public $successCssClass = 'has-success'; - /** - * @var string the CSS class that is added to a field container when the associated attribute is being validated. - */ - public $validatingCssClass = 'validating'; - /** - * @var boolean whether to enable client-side data validation. - * If [[ActiveField::enableClientValidation]] is set, its value will take precedence for that input field. - */ - public $enableClientValidation = true; - /** - * @var boolean whether to enable AJAX-based data validation. - * If [[ActiveField::enableAjaxValidation]] is set, its value will take precedence for that input field. - */ - public $enableAjaxValidation = false; - /** - * @var array|string the URL for performing AJAX-based validation. This property will be processed by - * [[Html::url()]]. Please refer to [[Html::url()]] for more details on how to configure this property. - * If this property is not set, it will take the value of the form's action attribute. - */ - public $validationUrl; - /** - * @var boolean whether to perform validation when the form is submitted. - */ - public $validateOnSubmit = true; - /** - * @var boolean whether to perform validation when an input field loses focus and its value is found changed. - * If [[ActiveField::validateOnChange]] is set, its value will take precedence for that input field. - */ - public $validateOnChange = true; - /** - * @var boolean whether to perform validation while the user is typing in an input field. - * If [[ActiveField::validateOnType]] is set, its value will take precedence for that input field. - * @see validationDelay - */ - public $validateOnType = false; - /** - * @var integer number of milliseconds that the validation should be delayed when an input field - * is changed or the user types in the field. - * If [[ActiveField::validationDelay]] is set, its value will take precedence for that input field. - */ - public $validationDelay = 200; - /** - * @var string the name of the GET parameter indicating the validation request is an AJAX request. - */ - public $ajaxVar = 'ajax'; - /** - * @var string|JsExpression a JS callback that will be called when the form is being submitted. - * The signature of the callback should be: - * - * ~~~ - * function ($form) { - * ...return false to cancel submission... - * } - * ~~~ - */ - public $beforeSubmit; - /** - * @var string|JsExpression a JS callback that is called before validating an attribute. - * The signature of the callback should be: - * - * ~~~ - * function ($form, attribute, messages) { - * ...return false to cancel the validation... - * } - * ~~~ - */ - public $beforeValidate; - /** - * @var string|JsExpression a JS callback that is called after validating an attribute. - * The signature of the callback should be: - * - * ~~~ - * function ($form, attribute, messages) { - * } - * ~~~ - */ - public $afterValidate; - /** - * @var array the client validation options for individual attributes. Each element of the array - * represents the validation options for a particular attribute. - * @internal - */ - public $attributes = []; - - /** - * Initializes the widget. - * This renders the form open tag. - */ - public function init() - { - if (!isset($this->options['id'])) { - $this->options['id'] = $this->getId(); - } - if (!isset($this->fieldConfig['class'])) { - $this->fieldConfig['class'] = ActiveField::className(); - } - echo Html::beginForm($this->action, $this->method, $this->options); - } - - /** - * Runs the widget. - * This registers the necessary javascript code and renders the form close tag. - */ - public function run() - { - if (!empty($this->attributes)) { - $id = $this->options['id']; - $options = Json::encode($this->getClientOptions()); - $attributes = Json::encode($this->attributes); - $view = $this->getView(); - ActiveFormAsset::register($view); - $view->registerJs("jQuery('#$id').yiiActiveForm($attributes, $options);"); - } - echo Html::endForm(); - } - - /** - * Returns the options for the form JS widget. - * @return array the options - */ - protected function getClientOptions() - { - $options = [ - 'errorSummary' => '.' . $this->errorSummaryCssClass, - 'validateOnSubmit' => $this->validateOnSubmit, - 'errorCssClass' => $this->errorCssClass, - 'successCssClass' => $this->successCssClass, - 'validatingCssClass' => $this->validatingCssClass, - 'ajaxVar' => $this->ajaxVar, - ]; - if ($this->validationUrl !== null) { - $options['validationUrl'] = Html::url($this->validationUrl); - } - foreach (['beforeSubmit', 'beforeValidate', 'afterValidate'] as $name) { - if (($value = $this->$name) !== null) { - $options[$name] = $value instanceof JsExpression ? $value : new JsExpression($value); - } - } - return $options; - } - - /** - * Generates a summary of the validation errors. - * If there is no validation error, an empty error summary markup will still be generated, but it will be hidden. - * @param Model|Model[] $models the model(s) associated with this form - * @param array $options the tag options in terms of name-value pairs. The following options are specially handled: - * - * - header: string, the header HTML for the error summary. If not set, a default prompt string will be used. - * - footer: string, the footer HTML for the error summary. - * - * The rest of the options will be rendered as the attributes of the container tag. The values will - * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. - * @return string the generated error summary - */ - public function errorSummary($models, $options = []) - { - if (!is_array($models)) { - $models = [$models]; - } - - $lines = []; - foreach ($models as $model) { - /** @var Model $model */ - foreach ($model->getFirstErrors() as $error) { - $lines[] = Html::encode($error); - } - } - - $header = isset($options['header']) ? $options['header'] : '

        ' . Yii::t('yii', 'Please fix the following errors:') . '

        '; - $footer = isset($options['footer']) ? $options['footer'] : ''; - unset($options['header'], $options['footer']); - - if (!isset($options['class'])) { - $options['class'] = $this->errorSummaryCssClass; - } else { - $options['class'] .= ' ' . $this->errorSummaryCssClass; - } - - if (!empty($lines)) { - $content = "
        • " . implode("
        • \n
        • ", $lines) . "
          • "; - return Html::tag('div', $header . $content . $footer, $options); - } else { - $content = "
              "; - $options['style'] = isset($options['style']) ? rtrim($options['style'], ';') . '; display:none' : 'display:none'; - return Html::tag('div', $header . $content . $footer, $options); - } - } - - /** - * Generates a form field. - * A form field is associated with a model and an attribute. It contains a label, an input and an error message - * and use them to interact with end users to collect their inputs for the attribute. - * @param Model $model the data model - * @param string $attribute the attribute name or expression. See [[Html::getAttributeName()]] for the format - * about attribute expression. - * @param array $options the additional configurations for the field object - * @return ActiveField the created ActiveField object - * @see fieldConfig - */ - public function field($model, $attribute, $options = []) - { - return Yii::createObject(array_merge($this->fieldConfig, $options, [ - 'model' => $model, - 'attribute' => $attribute, - 'form' => $this, - ])); - } - - /** - * Validates one or several models and returns an error message array indexed by the attribute IDs. - * This is a helper method that simplifies the way of writing AJAX validation code. - * - * For example, you may use the following code in a controller action to respond - * to an AJAX validation request: - * - * ~~~ - * $model = new Post; - * $model->load($_POST); - * if (Yii::$app->request->isAjax) { - * Yii::$app->response->format = Response::FORMAT_JSON; - * return ActiveForm::validate($model); - * } - * // ... respond to non-AJAX request ... - * ~~~ - * - * To validate multiple models, simply pass each model as a parameter to this method, like - * the following: - * - * ~~~ - * ActiveForm::validate($model1, $model2, ...); - * ~~~ - * - * @param Model $model the model to be validated - * @param mixed $attributes list of attributes that should be validated. - * If this parameter is empty, it means any attribute listed in the applicable - * validation rules should be validated. - * - * When this method is used to validate multiple models, this parameter will be interpreted - * as a model. - * - * @return array the error message array indexed by the attribute IDs. - */ - public static function validate($model, $attributes = null) - { - $result = []; - if ($attributes instanceof Model) { - // validating multiple models - $models = func_get_args(); - $attributes = null; - } else { - $models = [$model]; - } - /** @var Model $model */ - foreach ($models as $model) { - $model->validate($attributes); - foreach ($model->getErrors() as $attribute => $errors) { - $result[Html::getInputId($model, $attribute)] = $errors; - } - } - return $result; - } - - /** - * Validates an array of model instances and returns an error message array indexed by the attribute IDs. - * This is a helper method that simplifies the way of writing AJAX validation code for tabular input. - * - * For example, you may use the following code in a controller action to respond - * to an AJAX validation request: - * - * ~~~ - * // ... load $models ... - * if (Yii::$app->request->isAjax) { - * Yii::$app->response->format = Response::FORMAT_JSON; - * return ActiveForm::validateMultiple($models); - * } - * // ... respond to non-AJAX request ... - * ~~~ - * - * @param array $models an array of models to be validated. - * @param mixed $attributes list of attributes that should be validated. - * If this parameter is empty, it means any attribute listed in the applicable - * validation rules should be validated. - * @return array the error message array indexed by the attribute IDs. - */ - public static function validateMultiple($models, $attributes = null) - { - $result = []; - /** @var Model $model */ - foreach ($models as $i => $model) { - $model->validate($attributes); - foreach ($model->getErrors() as $attribute => $errors) { - $result[Html::getInputId($model, "[$i]" . $attribute)] = $errors; - } - } - return $result; - } -} diff --git a/framework/yii/widgets/ActiveFormAsset.php b/framework/yii/widgets/ActiveFormAsset.php deleted file mode 100644 index 5acb5e1..0000000 --- a/framework/yii/widgets/ActiveFormAsset.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class ActiveFormAsset extends AssetBundle -{ - public $sourcePath = '@yii/assets'; - public $js = [ - 'yii.activeForm.js', - ]; - public $depends = [ - 'yii\web\YiiAsset', - ]; -} diff --git a/framework/yii/widgets/BaseListView.php b/framework/yii/widgets/BaseListView.php deleted file mode 100644 index 4c4e5a4..0000000 --- a/framework/yii/widgets/BaseListView.php +++ /dev/null @@ -1,215 +0,0 @@ - - * @since 2.0 - */ -abstract class BaseListView extends Widget -{ - /** - * @var array the HTML attributes for the container tag of the list view. - * The "tag" element specifies the tag name of the container element and defaults to "div". - */ - public $options = []; - /** - * @var \yii\data\DataProviderInterface the data provider for the view. This property is required. - */ - public $dataProvider; - /** - * @var array the configuration for the pager widget. By default, [[LinkPager]] will be - * used to render the pager. You can use a different widget class by configuring the "class" element. - */ - public $pager = []; - /** - * @var array the configuration for the sorter widget. By default, [[LinkSorter]] will be - * used to render the sorter. You can use a different widget class by configuring the "class" element. - */ - public $sorter = []; - /** - * @var string the HTML content to be displayed as the summary of the list view. - * If you do not want to show the summary, you may set it with an empty string. - * - * The following tokens will be replaced with the corresponding values: - * - * - `{begin}`: the starting row number (1-based) currently being displayed - * - `{end}`: the ending row number (1-based) currently being displayed - * - `{count}`: the number of rows currently being displayed - * - `{totalCount}`: the total number of rows available - * - `{page}`: the page number (1-based) current being displayed - * - `{pageCount}`: the number of pages available - */ - public $summary; - /** - * @var boolean whether to show the list view if [[dataProvider]] returns no data. - */ - public $showOnEmpty = false; - /** - * @var string the HTML content to be displayed when [[dataProvider]] does not have any data. - */ - public $emptyText; - /** - * @var string the layout that determines how different sections of the list view should be organized. - * The following tokens will be replaced with the corresponding section contents: - * - * - `{summary}`: the summary section. See [[renderSummary()]]. - * - `{items}`: the list items. See [[renderItems()]]. - * - `{sorter}`: the sorter. See [[renderSorter()]]. - * - `{pager}`: the pager. See [[renderPager()]]. - */ - public $layout = "{summary}\n{items}\n{pager}"; - - - /** - * Renders the data models. - * @return string the rendering result. - */ - abstract public function renderItems(); - - /** - * Initializes the view. - */ - public function init() - { - if ($this->dataProvider === null) { - throw new InvalidConfigException('The "dataProvider" property must be set.'); - } - if ($this->emptyText === null) { - $this->emptyText = Yii::t('yii', 'No results found.'); - } - $this->dataProvider->prepare(); - } - - /** - * Runs the widget. - */ - public function run() - { - if ($this->dataProvider->getCount() > 0 || $this->showOnEmpty) { - $content = preg_replace_callback("/{\\w+}/", function ($matches) { - $content = $this->renderSection($matches[0]); - return $content === false ? $matches[0] : $content; - }, $this->layout); - } else { - $content = $this->renderEmpty(); - } - $tag = ArrayHelper::remove($this->options, 'tag', 'div'); - echo Html::tag($tag, $content, $this->options); - } - - /** - * Renders a section of the specified name. - * If the named section is not supported, false will be returned. - * @param string $name the section name, e.g., `{summary}`, `{items}`. - * @return string|boolean the rendering result of the section, or false if the named section is not supported. - */ - public function renderSection($name) - { - switch ($name) { - case '{summary}': - return $this->renderSummary(); - case '{items}': - return $this->renderItems(); - case '{pager}': - return $this->renderPager(); - case '{sorter}': - return $this->renderSorter(); - default: - return false; - } - } - - /** - * Renders the HTML content indicating that the list view has no data. - * @return string the rendering result - * @see emptyText - */ - public function renderEmpty() - { - return '
              ' . ($this->emptyText === null ? Yii::t('yii', 'No results found.') : $this->emptyText) . '
              '; - } - - /** - * Renders the summary text. - */ - public function renderSummary() - { - $count = $this->dataProvider->getCount(); - if ($count <= 0) { - return ''; - } - if (($pagination = $this->dataProvider->getPagination()) !== false) { - $totalCount = $this->dataProvider->getTotalCount(); - $begin = $pagination->getPage() * $pagination->pageSize + 1; - $end = $begin + $count - 1; - if ($begin > $end) { - $begin = $end; - } - $page = $pagination->getPage() + 1; - $pageCount = $pagination->pageCount; - if (($summaryContent = $this->summary) === null) { - $summaryContent = '
              ' - . Yii::t('yii', 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.') - . '
              '; - } - } else { - $begin = $page = $pageCount = 1; - $end = $totalCount = $count; - if (($summaryContent = $this->summary) === null) { - $summaryContent = '
              ' . Yii::t('yii', 'Total {count, number} {count, plural, one{item} other{items}}.') . '
              '; - } - } - return Yii::$app->getI18n()->format($summaryContent, [ - 'begin' => $begin, - 'end' => $end, - 'count' => $count, - 'totalCount' => $totalCount, - 'page' => $page, - 'pageCount' => $pageCount, - ], Yii::$app->language); - } - - /** - * Renders the pager. - * @return string the rendering result - */ - public function renderPager() - { - $pagination = $this->dataProvider->getPagination(); - if ($pagination === false || $this->dataProvider->getCount() <= 0) { - return ''; - } - /** @var LinkPager $class */ - $class = ArrayHelper::remove($this->pager, 'class', LinkPager::className()); - $this->pager['pagination'] = $pagination; - return $class::widget($this->pager); - } - - /** - * Renders the sorter. - * @return string the rendering result - */ - public function renderSorter() - { - $sort = $this->dataProvider->getSort(); - if ($sort === false || empty($sort->attributes) || $this->dataProvider->getCount() <= 0) { - return ''; - } - /** @var LinkSorter $class */ - $class = ArrayHelper::remove($this->sorter, 'class', LinkSorter::className()); - $this->sorter['sort'] = $sort; - return $class::widget($this->sorter); - } -} diff --git a/framework/yii/widgets/Block.php b/framework/yii/widgets/Block.php deleted file mode 100644 index fdd210f..0000000 --- a/framework/yii/widgets/Block.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @since 2.0 - */ -class Block extends Widget -{ - /** - * @var string the ID of this block. - */ - public $id; - /** - * @var boolean whether to render the block content in place. Defaults to false, - * meaning the captured block content will not be displayed. - */ - public $renderInPlace = false; - - /** - * Starts recording a block. - */ - public function init() - { - ob_start(); - ob_implicit_flush(false); - } - - /** - * Ends recording a block. - * This method stops output buffering and saves the rendering result as a named block in the controller. - */ - public function run() - { - $block = ob_get_clean(); - if ($this->renderInPlace) { - echo $block; - } - $this->view->blocks[$this->id] = $block; - } -} diff --git a/framework/yii/widgets/Breadcrumbs.php b/framework/yii/widgets/Breadcrumbs.php deleted file mode 100644 index 2353845..0000000 --- a/framework/yii/widgets/Breadcrumbs.php +++ /dev/null @@ -1,141 +0,0 @@ - [ - * ['label' => 'Sample Post', 'url' => ['post/edit', 'id' => 1]], - * 'Edit', - * ], - * ]); - * ~~~ - * - * Because breadcrumbs usually appears in nearly every page of a website, you may consider placing it in a layout view. - * You can use a view parameter (e.g. `$this->params['breadcrumbs']`) to configure the links in different - * views. In the layout view, you assign this view parameter to the [[links]] property like the following: - * - * ~~~ - * // $this is the view object currently being used - * echo Breadcrumbs::widget([ - * 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], - * ]); - * ~~~ - * - * @author Qiang Xue - * @since 2.0 - */ -class Breadcrumbs extends Widget -{ - /** - * @var string the name of the breadcrumb container tag. - */ - public $tag = 'ul'; - /** - * @var array the HTML attributes for the breadcrumb container tag. - */ - public $options = ['class' => 'breadcrumb']; - /** - * @var boolean whether to HTML-encode the link labels. - */ - public $encodeLabels = true; - /** - * @var string the first hyperlink in the breadcrumbs (called home link). - * If this property is not set, it will default to a link pointing to [[\yii\web\Application::homeUrl]] - * with the label 'Home'. If this property is false, the home link will not be rendered. - */ - public $homeLink; - /** - * @var array list of links to appear in the breadcrumbs. If this property is empty, - * the widget will not render anything. Each array element represents a single link in the breadcrumbs - * with the following structure: - * - * ~~~ - * [ - * 'label' => 'label of the link', // required - * 'url' => 'url of the link', // optional, will be processed by Html::url() - * ] - * ~~~ - * - * If a link is active, you only need to specify its "label", and instead of writing `['label' => $label]`, - * you should simply use `$label`. - */ - public $links = []; - /** - * @var string the template used to render each inactive item in the breadcrumbs. The token `{link}` - * will be replaced with the actual HTML link for each inactive item. - */ - public $itemTemplate = "
            • {link}
            • \n"; - /** - * @var string the template used to render each active item in the breadcrumbs. The token `{link}` - * will be replaced with the actual HTML link for each active item. - */ - public $activeItemTemplate = "
            • {link}
            • \n"; - - /** - * Renders the widget. - */ - public function run() - { - if (empty($this->links)) { - return; - } - $links = []; - if ($this->homeLink === null) { - $links[] = $this->renderItem([ - 'label' => Yii::t('yii', 'Home'), - 'url' => Yii::$app->homeUrl, - ], $this->itemTemplate); - } elseif ($this->homeLink !== false) { - $links[] = $this->renderItem($this->homeLink, $this->itemTemplate); - } - foreach ($this->links as $link) { - if (!is_array($link)) { - $link = ['label' => $link]; - } - $links[] = $this->renderItem($link, isset($link['url']) ? $this->itemTemplate : $this->activeItemTemplate); - } - echo Html::tag($this->tag, implode('', $links), $this->options); - } - - /** - * Renders a single breadcrumb item. - * @param array $link the link to be rendered. It must contain the "label" element. The "url" element is optional. - * @param string $template the template to be used to rendered the link. The token "{link}" will be replaced by the link. - * @return string the rendering result - * @throws InvalidConfigException if `$link` does not have "label" element. - */ - protected function renderItem($link, $template) - { - if (isset($link['label'])) { - $label = $this->encodeLabels ? Html::encode($link['label']) : $link['label']; - } else { - throw new InvalidConfigException('The "label" element is required for each link.'); - } - if (isset($link['url'])) { - return strtr($template, ['{link}' => Html::a($label, $link['url'])]); - } else { - return strtr($template, ['{link}' => $label]); - } - } -} diff --git a/framework/yii/widgets/ContentDecorator.php b/framework/yii/widgets/ContentDecorator.php deleted file mode 100644 index 9224f35..0000000 --- a/framework/yii/widgets/ContentDecorator.php +++ /dev/null @@ -1,52 +0,0 @@ - - * @since 2.0 - */ -class ContentDecorator extends Widget -{ - /** - * @var string the view file that will be used to decorate the content enclosed by this widget. - * This can be specified as either the view file path or path alias. - */ - public $viewFile; - /** - * @var array the parameters (name => value) to be extracted and made available in the decorative view. - */ - public $params = []; - - /** - * Starts recording a clip. - */ - public function init() - { - if ($this->viewFile === null) { - throw new InvalidConfigException('ContentDecorator::viewFile must be set.'); - } - ob_start(); - ob_implicit_flush(false); - } - - /** - * Ends recording a clip. - * This method stops output buffering and saves the rendering result as a named clip in the controller. - */ - public function run() - { - $params = $this->params; - $params['content'] = ob_get_clean(); - // render under the existing context - echo $this->view->renderFile($this->viewFile, $params); - } -} diff --git a/framework/yii/widgets/DetailView.php b/framework/yii/widgets/DetailView.php deleted file mode 100644 index 3a45a4e..0000000 --- a/framework/yii/widgets/DetailView.php +++ /dev/null @@ -1,211 +0,0 @@ - $model, - * 'attributes' => [ - * 'title', // title attribute (in plain text) - * 'description:html', // description attribute in HTML - * [ // the owner name of the model - * 'label' => 'Owner', - * 'value' => $model->owner->name, - * ], - * ], - * ]); - * ~~~ - * - * @author Qiang Xue - * @since 2.0 - */ -class DetailView extends Widget -{ - /** - * @var array|object the data model whose details are to be displayed. This can be either a [[Model]] instance - * or an associative array. - */ - public $model; - /** - * @var array a list of attributes to be displayed in the detail view. Each array element - * represents the specification for displaying one particular attribute. - * - * An attribute can be specified as a string in the format of "Name" or "Name:Format", where "Name" refers to - * the attribute name, and "Format" represents the format of the attribute. The "Format" is passed to the [[Formatter::format()]] - * method to format an attribute value into a displayable text. Please refer to [[Formatter]] for the supported types. - * - * An attribute can also be specified in terms of an array with the following elements: - * - * - name: the attribute name. This is required if either "label" or "value" is not specified. - * - label: the label associated with the attribute. If this is not specified, it will be generated from the attribute name. - * - value: the value to be displayed. If this is not specified, it will be retrieved from [[model]] using the attribute name - * by calling [[ArrayHelper::getValue()]]. Note that this value will be formatted into a displayable text - * according to the "format" option. - * - format: the type of the value that determines how the value would be formatted into a displayable text. - * Please refer to [[Formatter]] for supported types. - * - visible: whether the attribute is visible. If set to `false`, the attribute will NOT be displayed. - */ - public $attributes; - /** - * @var string|callback the template used to render a single attribute. If a string, the token `{label}` - * and `{value}` will be replaced with the label and the value of the corresponding attribute. - * If a callback (e.g. an anonymous function), the signature must be as follows: - * - * ~~~ - * function ($attribute, $index, $widget) - * ~~~ - * - * where `$attribute` refer to the specification of the attribute being rendered, `$index` is the zero-based - * index of the attribute in the [[attributes]] array, and `$widget` refers to this widget instance. - */ - public $template = "{label}{value}"; - /** - * @var array the HTML attributes for the container tag of this widget. The "tag" option specifies - * what container tag should be used. It defaults to "table" if not set. - */ - public $options = ['class' => 'table table-striped table-bordered detail-view']; - /** - * @var array|Formatter the formatter used to format model attribute values into displayable texts. - * This can be either an instance of [[Formatter]] or an configuration array for creating the [[Formatter]] - * instance. If this property is not set, the "formatter" application component will be used. - */ - public $formatter; - - /** - * Initializes the detail view. - * This method will initialize required property values. - */ - public function init() - { - if ($this->model === null) { - throw new InvalidConfigException('Please specify the "model" property.'); - } - if ($this->formatter == null) { - $this->formatter = Yii::$app->getFormatter(); - } elseif (is_array($this->formatter)) { - $this->formatter = Yii::createObject($this->formatter); - } - if (!$this->formatter instanceof Formatter) { - throw new InvalidConfigException('The "formatter" property must be either a Format object or a configuration array.'); - } - $this->normalizeAttributes(); - } - - /** - * Renders the detail view. - * This is the main entry of the whole detail view rendering. - */ - public function run() - { - $rows = []; - $i = 0; - foreach ($this->attributes as $attribute) { - $rows[] = $this->renderAttribute($attribute, $i++); - } - - $tag = ArrayHelper::remove($this->options, 'tag', 'table'); - echo Html::tag($tag, implode("\n", $rows), $this->options); - } - - /** - * Renders a single attribute. - * @param array $attribute the specification of the attribute to be rendered. - * @param integer $index the zero-based index of the attribute in the [[attributes]] array - * @return string the rendering result - */ - protected function renderAttribute($attribute, $index) - { - if (is_string($this->template)) { - return strtr($this->template, [ - '{label}' => $attribute['label'], - '{value}' => $this->formatter->format($attribute['value'], $attribute['format']), - ]); - } else { - return call_user_func($this->template, $attribute, $index, $this); - } - } - - /** - * Normalizes the attribute specifications. - * @throws InvalidConfigException - */ - protected function normalizeAttributes() - { - if ($this->attributes === null) { - if ($this->model instanceof Model) { - $this->attributes = $this->model->attributes(); - } elseif (is_object($this->model)) { - $this->attributes = $this->model instanceof Arrayable ? $this->model->toArray() : array_keys(get_object_vars($this->model)); - } elseif (is_array($this->model)) { - $this->attributes = array_keys($this->model); - } else { - throw new InvalidConfigException('The "model" property must be either an array or an object.'); - } - sort($this->attributes); - } - - foreach ($this->attributes as $i => $attribute) { - if (is_string($attribute)) { - if (!preg_match('/^(\w+)(\s*:\s*(\w+))?$/', $attribute, $matches)) { - throw new InvalidConfigException('The attribute must be specified in the format of "Name" or "Name:Format"'); - } - $attribute = [ - 'name' => $matches[1], - 'format' => isset($matches[3]) ? $matches[3] : 'text', - ]; - } - - if (!is_array($attribute)) { - throw new InvalidConfigException('The attribute configuration must be an array.'); - } - - if (isset($attribute['visible']) && !$attribute['visible']) { - continue; - } - - if (!isset($attribute['format'])) { - $attribute['format'] = 'text'; - } - if (isset($attribute['name'])) { - $name = $attribute['name']; - if (!isset($attribute['label'])) { - $attribute['label'] = $this->model instanceof Model ? $this->model->getAttributeLabel($name) : Inflector::camel2words($name, true); - } - if (!array_key_exists('value', $attribute)) { - $attribute['value'] = ArrayHelper::getValue($this->model, $name); - } - } elseif (!isset($attribute['label']) || !array_key_exists('value', $attribute)) { - throw new InvalidConfigException('The attribute configuration requires the "name" element to determine the value and display label.'); - } - - $this->attributes[$i] = $attribute; - } - } -} diff --git a/framework/yii/widgets/FragmentCache.php b/framework/yii/widgets/FragmentCache.php deleted file mode 100644 index 57c4659..0000000 --- a/framework/yii/widgets/FragmentCache.php +++ /dev/null @@ -1,178 +0,0 @@ - - * @since 2.0 - */ -class FragmentCache extends Widget -{ - /** - * @var Cache|string the cache object or the application component ID of the cache object. - * After the FragmentCache object is created, if you want to change this property, - * you should only assign it with a cache object. - */ - public $cache = 'cache'; - /** - * @var integer number of seconds that the data can remain valid in cache. - * Use 0 to indicate that the cached data will never expire. - */ - public $duration = 60; - /** - * @var array|Dependency the dependency that the cached content depends on. - * This can be either a [[Dependency]] object or a configuration array for creating the dependency object. - * For example, - * - * ~~~ - * [ - * 'class' => 'yii\caching\DbDependency', - * 'sql' => 'SELECT MAX(lastModified) FROM Post', - * ] - * ~~~ - * - * would make the output cache depends on the last modified time of all posts. - * If any post has its modification time changed, the cached content would be invalidated. - */ - public $dependency; - /** - * @var array list of factors that would cause the variation of the content being cached. - * Each factor is a string representing a variation (e.g. the language, a GET parameter). - * The following variation setting will cause the content to be cached in different versions - * according to the current application language: - * - * ~~~ - * [ - * Yii::$app->language, - * ] - */ - public $variations; - /** - * @var boolean whether to enable the fragment cache. You may use this property to turn on and off - * the fragment cache according to specific setting (e.g. enable fragment cache only for GET requests). - */ - public $enabled = true; - /** - * @var array a list of placeholders for embedding dynamic contents. This property - * is used internally to implement the content caching feature. Do not modify it. - */ - public $dynamicPlaceholders; - - /** - * Initializes the FragmentCache object. - */ - public function init() - { - parent::init(); - - if (!$this->enabled) { - $this->cache = null; - } elseif (is_string($this->cache)) { - $this->cache = Yii::$app->getComponent($this->cache); - } - - if ($this->getCachedContent() === false) { - $this->getView()->cacheStack[] = $this; - ob_start(); - ob_implicit_flush(false); - } - } - - /** - * Marks the end of content to be cached. - * Content displayed before this method call and after [[init()]] - * will be captured and saved in cache. - * This method does nothing if valid content is already found in cache. - */ - public function run() - { - if (($content = $this->getCachedContent()) !== false) { - echo $content; - } elseif ($this->cache instanceof Cache) { - $content = ob_get_clean(); - array_pop($this->getView()->cacheStack); - if (is_array($this->dependency)) { - $this->dependency = Yii::createObject($this->dependency); - } - $data = [$content, $this->dynamicPlaceholders]; - $this->cache->set($this->calculateKey(), $data, $this->duration, $this->dependency); - - if (empty($this->getView()->cacheStack) && !empty($this->dynamicPlaceholders)) { - $content = $this->updateDynamicContent($content, $this->dynamicPlaceholders); - } - echo $content; - } - } - - /** - * @var string|boolean the cached content. False if the content is not cached. - */ - private $_content; - - /** - * Returns the cached content if available. - * @return string|boolean the cached content. False is returned if valid content is not found in the cache. - */ - public function getCachedContent() - { - if ($this->_content === null) { - $this->_content = false; - if ($this->cache instanceof Cache) { - $key = $this->calculateKey(); - $data = $this->cache->get($key); - if (is_array($data) && count($data) === 2) { - list ($content, $placeholders) = $data; - if (is_array($placeholders) && count($placeholders) > 0) { - if (empty($this->getView()->cacheStack)) { - // outermost cache: replace placeholder with dynamic content - $content = $this->updateDynamicContent($content, $placeholders); - } - foreach ($placeholders as $name => $statements) { - $this->getView()->addDynamicPlaceholder($name, $statements); - } - } - $this->_content = $content; - } - } - } - return $this->_content; - } - - protected function updateDynamicContent($content, $placeholders) - { - foreach ($placeholders as $name => $statements) { - $placeholders[$name] = $this->getView()->evaluateDynamicContent($statements); - } - return strtr($content, $placeholders); - } - - /** - * Generates a unique key used for storing the content in cache. - * The key generated depends on both [[id]] and [[variations]]. - * @return mixed a valid cache key - */ - protected function calculateKey() - { - $factors = [__CLASS__, $this->getId()]; - if (is_array($this->variations)) { - foreach ($this->variations as $factor) { - $factors[] = $factor; - } - } - return $factors; - } -} diff --git a/framework/yii/widgets/InputWidget.php b/framework/yii/widgets/InputWidget.php deleted file mode 100644 index 0a4b5b7..0000000 --- a/framework/yii/widgets/InputWidget.php +++ /dev/null @@ -1,72 +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; - /** - * @var array the HTML attributes for the input tag. - */ - public $options = []; - - - /** - * 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 (!isset($this->options['id'])) { - $this->options['id'] = $this->hasModel() ? Html::getInputId($this->model, $this->attribute) : $this->getId(); - } - 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/framework/yii/widgets/LinkPager.php b/framework/yii/widgets/LinkPager.php deleted file mode 100644 index 807a4b8..0000000 --- a/framework/yii/widgets/LinkPager.php +++ /dev/null @@ -1,193 +0,0 @@ - - * @since 2.0 - */ -class LinkPager extends Widget -{ - /** - * @var Pagination the pagination object that this pager is associated with. - * You must set this property in order to make LinkPager work. - */ - public $pagination; - /** - * @var array HTML attributes for the pager container tag. - */ - public $options = ['class' => 'pagination']; - /** - * @var string the CSS class for the "first" page button. - */ - public $firstPageCssClass = 'first'; - /** - * @var string the CSS class for the "last" page button. - */ - public $lastPageCssClass = 'last'; - /** - * @var string the CSS class for the "previous" page button. - */ - public $prevPageCssClass = 'prev'; - /** - * @var string the CSS class for the "next" page button. - */ - public $nextPageCssClass = 'next'; - /** - * @var string the CSS class for the active (currently selected) page button. - */ - public $activePageCssClass = 'active'; - /** - * @var string the CSS class for the disabled page buttons. - */ - public $disabledPageCssClass = 'disabled'; - /** - * @var integer maximum number of page buttons that can be displayed. Defaults to 10. - */ - public $maxButtonCount = 10; - /** - * @var string the label for the "next" page button. Note that this will NOT be HTML-encoded. - * If this property is null, the "next" page button will not be displayed. - */ - public $nextPageLabel = '»'; - /** - * @var string the text label for the previous page button. Note that this will NOT be HTML-encoded. - * If this property is null, the "previous" page button will not be displayed. - */ - public $prevPageLabel = '«'; - /** - * @var string the text label for the "first" page button. Note that this will NOT be HTML-encoded. - * If this property is null, the "first" page button will not be displayed. - */ - public $firstPageLabel; - /** - * @var string the text label for the "last" page button. Note that this will NOT be HTML-encoded. - * If this property is null, the "last" page button will not be displayed. - */ - public $lastPageLabel; - - - /** - * Initializes the pager. - */ - public function init() - { - if ($this->pagination === null) { - throw new InvalidConfigException('The "pagination" property must be set.'); - } - } - - /** - * Executes the widget. - * This overrides the parent implementation by displaying the generated page buttons. - */ - public function run() - { - echo $this->renderPageButtons(); - } - - /** - * Renders the page buttons. - * @return string the rendering result - */ - protected function renderPageButtons() - { - $buttons = []; - - $pageCount = $this->pagination->getPageCount(); - $currentPage = $this->pagination->getPage(); - - // first page - if ($this->firstPageLabel !== null) { - $buttons[] = $this->renderPageButton($this->firstPageLabel, 0, $this->firstPageCssClass, $currentPage <= 0, false); - } - - // prev page - if ($this->prevPageLabel !== null) { - if (($page = $currentPage - 1) < 0) { - $page = 0; - } - $buttons[] = $this->renderPageButton($this->prevPageLabel, $page, $this->prevPageCssClass, $currentPage <= 0, false); - } - - // internal pages - list($beginPage, $endPage) = $this->getPageRange(); - for ($i = $beginPage; $i <= $endPage; ++$i) { - $buttons[] = $this->renderPageButton($i + 1, $i, null, false, $i == $currentPage); - } - - // next page - if ($this->nextPageLabel !== null) { - if (($page = $currentPage + 1) >= $pageCount - 1) { - $page = $pageCount - 1; - } - $buttons[] = $this->renderPageButton($this->nextPageLabel, $page, $this->nextPageCssClass, $currentPage >= $pageCount - 1, false); - } - - // last page - if ($this->lastPageLabel !== null) { - $buttons[] = $this->renderPageButton($this->lastPageLabel, $pageCount - 1, $this->lastPageCssClass, $currentPage >= $pageCount - 1, false); - } - - return Html::tag('ul', implode("\n", $buttons), $this->options); - } - - /** - * Renders a page button. - * You may override this method to customize the generation of page buttons. - * @param string $label the text label for the button - * @param integer $page the page number - * @param string $class the CSS class for the page button. - * @param boolean $disabled whether this page button is disabled - * @param boolean $active whether this page button is active - * @return string the rendering result - */ - protected function renderPageButton($label, $page, $class, $disabled, $active) - { - $options = ['class' => $class === '' ? null : $class]; - if ($active) { - Html::addCssClass($options, $this->activePageCssClass); - } - if ($disabled) { - Html::addCssClass($options, $this->disabledPageCssClass); - return Html::tag('li', Html::tag('span', $label), $options); - } - return Html::tag('li', Html::a($label, $this->pagination->createUrl($page), ['data-page' => $page]), $options); - } - - /** - * @return array the begin and end pages that need to be displayed. - */ - protected function getPageRange() - { - $currentPage = $this->pagination->getPage(); - $pageCount = $this->pagination->getPageCount(); - - $beginPage = max(0, $currentPage - (int)($this->maxButtonCount / 2)); - if (($endPage = $beginPage + $this->maxButtonCount - 1) >= $pageCount) { - $endPage = $pageCount - 1; - $beginPage = max(0, $endPage - $this->maxButtonCount + 1); - } - return [$beginPage, $endPage]; - } -} diff --git a/framework/yii/widgets/LinkSorter.php b/framework/yii/widgets/LinkSorter.php deleted file mode 100644 index bfafcea..0000000 --- a/framework/yii/widgets/LinkSorter.php +++ /dev/null @@ -1,74 +0,0 @@ - - * @since 2.0 - */ -class LinkSorter extends Widget -{ - /** - * @var Sort the sort definition - */ - public $sort; - /** - * @var array list of the attributes that support sorting. If not set, it will be determined - * using [[Sort::attributes]]. - */ - public $attributes; - /** - * @var array HTML attributes for the sorter container tag. - * See [[yii\helpers\Html::ul()]] for special attributes. - */ - public $options = ['class' => 'sorter']; - - - /** - * Initializes the sorter. - */ - public function init() - { - if ($this->sort === null) { - throw new InvalidConfigException('The "sort" property must be set.'); - } - } - - /** - * Executes the widget. - * This method renders the sort links. - */ - public function run() - { - echo $this->renderSortLinks(); - } - - /** - * Renders the sort links. - * @return string the rendering result - */ - protected function renderSortLinks() - { - $attributes = empty($this->attributes) ? array_keys($this->sort->attributes) : $this->attributes; - $links = []; - foreach ($attributes as $name) { - $links[] = $this->sort->link($name); - } - return Html::ul($links, array_merge($this->options, ['encode' => false])); - } -} diff --git a/framework/yii/widgets/ListView.php b/framework/yii/widgets/ListView.php deleted file mode 100644 index 43eaab4..0000000 --- a/framework/yii/widgets/ListView.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @since 2.0 - */ -class ListView extends BaseListView -{ - /** - * @var array the HTML attributes for the container of the rendering result of each data model. - * The "tag" element specifies the tag name of the container element and defaults to "div". - * If "tag" is false, it means no container element will be rendered. - */ - public $itemOptions = []; - /** - * @var string|callback the name of the view for rendering each data item, or a callback (e.g. an anonymous function) - * for rendering each data item. If it specifies a view name, the following variables will - * be available in the view: - * - * - `$model`: mixed, the data model - * - `$key`: mixed, the key value associated with the data item - * - `$index`: integer, the zero-based index of the data item in the items array returned by [[dataProvider]]. - * - `$widget`: ListView, this widget instance - * - * Note that the view name is resolved into the view file by the current context of the [[view]] object. - * - * If this property is specified as a callback, it should have the following signature: - * - * ~~~ - * function ($model, $key, $index, $widget) - * ~~~ - */ - public $itemView; - /** - * @var array additional parameters to be passed to [[itemView]] when it is being rendered. - * This property is used only when [[itemView]] is a string representing a view name. - */ - public $viewParams = []; - /** - * @var string the HTML code to be displayed between any two consecutive items. - */ - public $separator = "\n"; - /** - * @var array the HTML attributes for the container tag of the list view. - * The "tag" element specifies the tag name of the container element and defaults to "div". - */ - public $options = ['class' => 'list-view']; - - - /** - * Renders all data models. - * @return string the rendering result - */ - public function renderItems() - { - $models = $this->dataProvider->getModels(); - $keys = $this->dataProvider->getKeys(); - $rows = []; - foreach (array_values($models) as $index => $model) { - $rows[] = $this->renderItem($model, $keys[$index], $index); - } - return implode($this->separator, $rows); - } - - /** - * Renders a single data model. - * @param mixed $model the data model to be rendered - * @param mixed $key the key value associated with the data model - * @param integer $index the zero-based index of the data model in the model array returned by [[dataProvider]]. - * @return string the rendering result - */ - public function renderItem($model, $key, $index) - { - if ($this->itemView === null) { - $content = $key; - } elseif (is_string($this->itemView)) { - $content = $this->getView()->render($this->itemView, array_merge([ - 'model' => $model, - 'key' => $key, - 'index' => $index, - 'widget' => $this, - ], $this->viewParams)); - } else { - $content = call_user_func($this->itemView, $model, $key, $index, $this); - } - $options = $this->itemOptions; - $tag = ArrayHelper::remove($options, 'tag', 'div'); - if ($tag !== false) { - $options['data-key'] = is_array($key) ? json_encode($key) : $key; - return Html::tag($tag, $content, $options); - } else { - return $content; - } - } -} diff --git a/framework/yii/widgets/MaskedInput.php b/framework/yii/widgets/MaskedInput.php deleted file mode 100644 index 7eb42a7..0000000 --- a/framework/yii/widgets/MaskedInput.php +++ /dev/null @@ -1,129 +0,0 @@ - 'phone', - * 'mask' => '999-999-9999', - * ]); - * ~~~ - * - * The masked text field is implemented based on the [jQuery masked input plugin](http://digitalbush.com/projects/masked-input-plugin). - * - * @author Qiang Xue - * @since 2.0 - */ -class MaskedInput extends InputWidget -{ - /** - * @var string the input mask (e.g. '99/99/9999' for date input). The following characters are predefined: - * - * - `a`: represents an alpha character (A-Z,a-z) - * - `9`: represents a numeric character (0-9) - * - `*`: represents an alphanumeric character (A-Z,a-z,0-9) - * - `?`: anything listed after '?' within the mask is considered optional user input - * - * Additional characters can be defined by specifying the [[charMap]] property. - */ - public $mask; - /** - * @var array the mapping between mask characters and the corresponding patterns. - * For example, `['~' => '[+-]']` specifies that the '~' character expects '+' or '-' input. - * Defaults to null, meaning using the map as described in [[mask]]. - */ - public $charMap; - /** - * @var string the character prompting for user input. Defaults to underscore '_'. - */ - public $placeholder; - /** - * @var string a JavaScript function callback that will be invoked when user finishes the input. - */ - public $completed; - - - /** - * Initializes the widget. - * @throws InvalidConfigException if the "mask" property is not set. - */ - public function init() - { - parent::init(); - if (empty($this->mask)) { - throw new InvalidConfigException('The "mask" property must be set.'); - } - } - - /** - * Runs the widget. - */ - public function run() - { - if ($this->hasModel()) { - echo Html::activeTextInput($this->model, $this->attribute, $this->options); - } else { - echo Html::textInput($this->name, $this->value, $this->options); - } - $this->registerClientScript(); - } - - /** - * Registers the needed JavaScript. - */ - public function registerClientScript() - { - $options = $this->getClientOptions(); - $options = empty($options) ? '' : ',' . Json::encode($options); - $js = ''; - if (is_array($this->charMap) && !empty($this->charMap)) { - $js .= 'jQuery.mask.definitions=' . Json::encode($this->charMap) . ";\n"; - } - $id = $this->options['id']; - $js .= "jQuery(\"#{$id}\").mask(\"{$this->mask}\"{$options});"; - $view = $this->getView(); - MaskedInputAsset::register($view); - $view->registerJs($js); - } - - /** - * @return array the options for the text field - */ - protected function getClientOptions() - { - $options = []; - if ($this->placeholder !== null) { - $options['placeholder'] = $this->placeholder; - } - - if ($this->completed !== null) { - if ($this->completed instanceof JsExpression) { - $options['completed'] = $this->completed; - } else { - $options['completed'] = new JsExpression($this->completed); - } - } - - return $options; - } -} diff --git a/framework/yii/widgets/MaskedInputAsset.php b/framework/yii/widgets/MaskedInputAsset.php deleted file mode 100644 index 52fa2da..0000000 --- a/framework/yii/widgets/MaskedInputAsset.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @since 2.0 - */ -class MaskedInputAsset extends AssetBundle -{ - public $sourcePath = '@yii/assets'; - public $js = [ - 'jquery.maskedinput.js', - ]; - public $depends = [ - 'yii\web\YiiAsset', - ]; -} diff --git a/framework/yii/widgets/Menu.php b/framework/yii/widgets/Menu.php deleted file mode 100644 index d5ff8ef..0000000 --- a/framework/yii/widgets/Menu.php +++ /dev/null @@ -1,307 +0,0 @@ - [ - * // Important: you need to specify url as 'controller/action', - * // not just as 'controller' even if default action is used. - * ['label' => 'Home', 'url' => ['site/index']], - * // 'Products' menu item will be selected as long as the route is 'product/index' - * ['label' => 'Products', 'url' => ['product/index'], 'items' => [ - * ['label' => 'New Arrivals', 'url' => ['product/index', 'tag' => 'new']], - * ['label' => 'Most Popular', 'url' => ['product/index', 'tag' => 'popular']], - * ]], - * ['label' => 'Login', 'url' => ['site/login'], 'visible' => Yii::$app->user->isGuest], - * ], - * ]); - * ~~~ - * - * @author Qiang Xue - * @since 2.0 - */ -class Menu extends Widget -{ - /** - * @var array list of menu items. Each menu item should be an array of the following structure: - * - * - label: string, optional, specifies the menu item label. When [[encodeLabels]] is true, the label - * will be HTML-encoded. If the label is not specified, an empty string will be used. - * - url: string or array, optional, specifies the URL of the menu item. It will be processed by [[Html::url]]. - * When this is set, the actual menu item content will be generated using [[linkTemplate]]; - * otherwise, [[labelTemplate]] will be used. - * - visible: boolean, optional, whether this menu item is visible. Defaults to true. - * - items: array, optional, specifies the sub-menu items. Its format is the same as the parent items. - * - active: boolean, optional, whether this menu item is in active state (currently selected). - * If a menu item is active, its CSS class will be appended with [[activeCssClass]]. - * If this option is not set, the menu item will be set active automatically when the current request - * is triggered by [[url]]. For more details, please refer to [[isItemActive()]]. - * - template: string, optional, the template used to render the content of this menu item. - * The token `{url}` will be replaced by the URL associated with this menu item, - * and the token `{label}` will be replaced by the label of the menu item. - * If this option is not set, [[linkTemplate]] or [[labelTemplate]] will be used instead. - * - options: array, optional, the HTML attributes for the menu container tag. - */ - public $items = []; - /** - * @var array list of HTML attributes for the menu container tag. 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 = []; - /** - * @var string the template used to render the body of a menu which is a link. - * In this template, the token `{url}` will be replaced with the corresponding link URL; - * while `{label}` will be replaced with the link text. - * This property will be overridden by the `template` option set in individual menu items via [[items]]. - */ - public $linkTemplate = '{label}'; - /** - * @var string the template used to render the body of a menu which is NOT a link. - * In this template, the token `{label}` will be replaced with the label of the menu item. - * This property will be overridden by the `template` option set in individual menu items via [[items]]. - */ - public $labelTemplate = '{label}'; - /** - * @var string the template used to render a list of sub-menus. - * In this template, the token `{items}` will be replaced with the renderer sub-menu items. - */ - public $submenuTemplate = "\n
                \n{items}\n
              \n"; - /** - * @var boolean whether the labels for menu items should be HTML-encoded. - */ - public $encodeLabels = true; - /** - * @var string the CSS class to be appended to the active menu item. - */ - public $activeCssClass = 'active'; - /** - * @var boolean whether to automatically activate items according to whether their route setting - * matches the currently requested route. - * @see isItemActive() - */ - public $activateItems = true; - /** - * @var boolean whether to activate parent menu items when one of the corresponding child menu items is active. - * The activated parent menu items will also have its CSS classes appended with [[activeCssClass]]. - */ - public $activateParents = false; - /** - * @var boolean whether to hide empty menu items. An empty menu item is one whose `url` option is not - * set and which has no visible child menu items. - */ - public $hideEmptyItems = true; - /** - * @var array the HTML attributes for the menu's container tag. The following special options are recognized: - * - * - tag: string, defaults to "ul", the tag name of the item container tags. - */ - public $options = []; - /** - * @var string the CSS class that will be assigned to the first item in the main menu or each submenu. - * Defaults to null, meaning no such CSS class will be assigned. - */ - public $firstItemCssClass; - /** - * @var string the CSS class that will be assigned to the last item in the main menu or each submenu. - * Defaults to null, meaning no such CSS class will be assigned. - */ - public $lastItemCssClass; - /** - * @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; - - - /** - * Renders the menu. - */ - public function run() - { - if ($this->route === null && Yii::$app->controller !== null) { - $this->route = Yii::$app->controller->getRoute(); - } - if ($this->params === null) { - $this->params = $_GET; - } - $items = $this->normalizeItems($this->items, $hasActiveChild); - $options = $this->options; - $tag = ArrayHelper::remove($options, 'tag', 'ul'); - echo Html::tag($tag, $this->renderItems($items), $options); - } - - /** - * Recursively renders the menu items (without the container tag). - * @param array $items the menu items to be rendered recursively - * @return string the rendering result - */ - protected function renderItems($items) - { - $n = count($items); - $lines = []; - foreach ($items as $i => $item) { - $options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', [])); - $tag = ArrayHelper::remove($options, 'tag', 'li'); - $class = []; - if ($item['active']) { - $class[] = $this->activeCssClass; - } - if ($i === 0 && $this->firstItemCssClass !== null) { - $class[] = $this->firstItemCssClass; - } - if ($i === $n - 1 && $this->lastItemCssClass !== null) { - $class[] = $this->lastItemCssClass; - } - if (!empty($class)) { - if (empty($options['class'])) { - $options['class'] = implode(' ', $class); - } else { - $options['class'] .= ' ' . implode(' ', $class); - } - } - - $menu = $this->renderItem($item); - if (!empty($item['items'])) { - $menu .= strtr($this->submenuTemplate, [ - '{items}' => $this->renderItems($item['items']), - ]); - } - $lines[] = Html::tag($tag, $menu, $options); - } - return implode("\n", $lines); - } - - /** - * Renders the content of a menu item. - * Note that the container and the sub-menus are not rendered here. - * @param array $item the menu item to be rendered. Please refer to [[items]] to see what data might be in the item. - * @return string the rendering result - */ - protected function renderItem($item) - { - if (isset($item['url'])) { - $template = ArrayHelper::getValue($item, 'template', $this->linkTemplate); - return strtr($template, [ - '{url}' => Html::url($item['url']), - '{label}' => $item['label'], - ]); - } else { - $template = ArrayHelper::getValue($item, 'template', $this->labelTemplate); - return strtr($template, [ - '{label}' => $item['label'], - ]); - } - } - - /** - * Normalizes the [[items]] property to remove invisible items and activate certain items. - * @param array $items the items to be normalized. - * @param boolean $active whether there is an active child menu item. - * @return array the normalized menu items - */ - protected function normalizeItems($items, &$active) - { - foreach ($items as $i => $item) { - if (isset($item['visible']) && !$item['visible']) { - unset($items[$i]); - continue; - } - if (!isset($item['label'])) { - $item['label'] = ''; - } - if ($this->encodeLabels) { - $items[$i]['label'] = Html::encode($item['label']); - } - $hasActiveChild = false; - if (isset($item['items'])) { - $items[$i]['items'] = $this->normalizeItems($item['items'], $hasActiveChild); - if (empty($items[$i]['items']) && $this->hideEmptyItems) { - unset($items[$i]['items']); - if (!isset($item['url'])) { - unset($items[$i]); - continue; - } - } - } - if (!isset($item['active'])) { - if ($this->activateParents && $hasActiveChild || $this->activateItems && $this->isItemActive($item)) { - $active = $items[$i]['active'] = true; - } else { - $items[$i]['active'] = false; - } - } elseif ($item['active']) { - $active = true; - } - } - return array_values($items); - } - - /** - * 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/framework/yii/widgets/Spaceless.php b/framework/yii/widgets/Spaceless.php deleted file mode 100644 index 8115f85..0000000 --- a/framework/yii/widgets/Spaceless.php +++ /dev/null @@ -1,69 +0,0 @@ - - * - * - *
              - * - *
              - * - * - * ``` - * - * This example will generate the following HTML: - * - * ```html - * - *
              - * ``` - * - * This method is not designed for content compression (you should use `gzip` output compression to - * achieve it). Main intention is to strip out extra whitespace characters between HTML tags in order - * to avoid browser rendering quirks in some circumstances (e.g. newlines between inline-block elements). - * - * Note, never use this method with `pre` or `textarea` tags. It's not that trivial to deal with such tags - * as it may seem at first sight. For this case you should consider using - * [HTML Tidy Project](http://tidy.sourceforge.net/) instead. - * - * @see http://tidy.sourceforge.net/ - * @author resurtm - * @since 2.0 - */ -class Spaceless extends Widget -{ - /** - * Starts capturing an output to be cleaned from whitespace characters between HTML tags. - */ - public function init() - { - ob_start(); - ob_implicit_flush(false); - } - - /** - * Marks the end of content to be cleaned from whitespace characters between HTML tags. - * Stops capturing an output and echoes cleaned result. - */ - public function run() - { - echo trim(preg_replace('/>\s+<', ob_get_clean())); - } -} diff --git a/framework/yii/yii b/framework/yii/yii deleted file mode 100755 index b34cfc8..0000000 --- a/framework/yii/yii +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env php - 'yii-console', - 'basePath' => __DIR__ . '/console', - 'controllerPath' => '@yii/console/controllers', -]); -$exitCode = $application->run(); -exit($exitCode); diff --git a/framework/yii/yii.bat b/framework/yii/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/framework/yii/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/phpunit.xml.dist b/phpunit.xml.dist deleted file mode 100644 index 92c0793..0000000 --- a/phpunit.xml.dist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - ./tests/unit - - - - - framework/yii/helpers/Json.php - framework/yii/helpers/StringHelper.php - framework/yii/helpers/VarDumper.php - framework/yii/helpers/Html.php - framework/yii/helpers/Inflector.php - framework/yii/helpers/FileHelper.php - framework/yii/helpers/ArrayHelper.php - framework/yii/helpers/Console.php - framework/yii/i18n/GettextFile.php - framework/yii/web/ResponseFormatterInterface.php - framework/yii/base - framework/yii/db/mssql - framework/yii/bootstrap - - - \ No newline at end of file diff --git a/tests/README.md b/tests/README.md deleted file mode 100644 index fa6b3a4..0000000 --- a/tests/README.md +++ /dev/null @@ -1,41 +0,0 @@ -Yii 2.0 Unit tests -================== - -DIRECTORY STRUCTURE -------------------- - - unit/ Unit tests to run with PHPUnit - data/ models, config and other test data - config.php this file contains configuration for database and caching backends - framework/ the framework unit tests - runtime/ the application runtime dir for the yii test app - web/ webapp for functional testing - - -HOW TO RUN THE TESTS --------------------- - -Make sure you have PHPUnit installed. - -Run PHPUnit in the yii repo base directory. - -```php -phpunit -``` - -You can run tests for specific groups only: - -```php -phpunit --group=mysql,base,i18n -``` - -You can get a list of available groups via `phpunit --list-groups`. - -TEST CONFIGURATION ------------------- - -PHPUnit configuration is in `phpunit.xml.dist` in repository root folder. -You can create your own phpunit.xml to override dist config. - -Database and other backend system configuration can be found in `unit/data/config.php` -adjust them to your needs to allow testing databases and caching in your environment. \ No newline at end of file diff --git a/tests/unit/.gitignore b/tests/unit/.gitignore deleted file mode 100644 index 34651d7..0000000 --- a/tests/unit/.gitignore +++ /dev/null @@ -1 +0,0 @@ -runtime/cache/* \ No newline at end of file diff --git a/tests/unit/TestCase.php b/tests/unit/TestCase.php deleted file mode 100644 index 88071c3..0000000 --- a/tests/unit/TestCase.php +++ /dev/null @@ -1,60 +0,0 @@ -destroyApplication(); - } - - /** - * Returns a test configuration param from /data/config.php - * @param string $name params name - * @param mixed $default default value to use when param is not set. - * @return mixed the value of the configuration param - */ - public function getParam($name, $default = null) - { - if (static::$params === null) { - static::$params = require(__DIR__ . '/data/config.php'); - } - return isset(static::$params[$name]) ? static::$params[$name] : $default; - } - - /** - * Populates Yii::$app with a new application - * The application will be destroyed on tearDown() automatically. - * @param array $config The application configuration, if needed - * @param string $appClass name of the application class to create - */ - protected function mockApplication($config = [], $appClass = '\yii\console\Application') - { - static $defaultConfig = [ - 'id' => 'testapp', - 'basePath' => __DIR__, - ]; - $defaultConfig['vendorPath'] = dirname(dirname(__DIR__)) . '/vendor'; - - new $appClass(array_merge($defaultConfig, $config)); - } - - /** - * Destroys application in Yii::$app by setting it to null. - */ - protected function destroyApplication() - { - \Yii::$app = null; - } -} diff --git a/tests/unit/VendorTestCase.php b/tests/unit/VendorTestCase.php deleted file mode 100644 index cffc1e0..0000000 --- a/tests/unit/VendorTestCase.php +++ /dev/null @@ -1,34 +0,0 @@ - - * @since 2.0 - */ -class ActiveRecord extends \yii\db\ActiveRecord -{ - public static $db; - - public static function getDb() - { - return self::$db; - } -} diff --git a/tests/unit/data/ar/Category.php b/tests/unit/data/ar/Category.php deleted file mode 100644 index cebacb0..0000000 --- a/tests/unit/data/ar/Category.php +++ /dev/null @@ -1,27 +0,0 @@ -hasMany(Item::className(), ['category_id' => 'id']); - } -} diff --git a/tests/unit/data/ar/Customer.php b/tests/unit/data/ar/Customer.php deleted file mode 100644 index 2d9618a..0000000 --- a/tests/unit/data/ar/Customer.php +++ /dev/null @@ -1,43 +0,0 @@ -hasMany(Order::className(), ['customer_id' => 'id'])->orderBy('id'); - } - - public static function active($query) - { - $query->andWhere('status=1'); - } - - public function afterSave($insert) - { - ActiveRecordTest::$afterSaveInsert = $insert; - ActiveRecordTest::$afterSaveNewRecord = $this->isNewRecord; - parent::afterSave($insert); - } -} diff --git a/tests/unit/data/ar/Item.php b/tests/unit/data/ar/Item.php deleted file mode 100644 index 2d04f9e..0000000 --- a/tests/unit/data/ar/Item.php +++ /dev/null @@ -1,23 +0,0 @@ -hasOne(Category::className(), ['id' => 'category_id']); - } -} diff --git a/tests/unit/data/ar/NullValues.php b/tests/unit/data/ar/NullValues.php deleted file mode 100644 index e6aa3b9..0000000 --- a/tests/unit/data/ar/NullValues.php +++ /dev/null @@ -1,20 +0,0 @@ -hasOne(Customer::className(), ['id' => 'customer_id']); - } - - public function getOrderItems() - { - return $this->hasMany(OrderItem::className(), ['order_id' => 'id']); - } - - public function getItems() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems', function ($q) { - // additional query configuration - })->orderBy('id'); - } - - public function getItemsInOrder1() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems', function ($q) { - $q->orderBy(['subtotal' => SORT_ASC]); - })->orderBy('name'); - } - - public function getItemsInOrder2() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems', function ($q) { - $q->orderBy(['subtotal' => SORT_DESC]); - })->orderBy('name'); - } - - public function getBooks() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->viaTable('tbl_order_item', ['order_id' => 'id']) - ->where(['category_id' => 1]); - } - - public function getBooks2() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->onCondition(['category_id' => 1]) - ->viaTable('tbl_order_item', ['order_id' => 'id']); - } - - public function beforeSave($insert) - { - if (parent::beforeSave($insert)) { - $this->create_time = time(); - return true; - } else { - return false; - } - } -} diff --git a/tests/unit/data/ar/OrderItem.php b/tests/unit/data/ar/OrderItem.php deleted file mode 100644 index b340a46..0000000 --- a/tests/unit/data/ar/OrderItem.php +++ /dev/null @@ -1,29 +0,0 @@ -hasOne(Order::className(), ['id' => 'order_id']); - } - - public function getItem() - { - return $this->hasOne(Item::className(), ['id' => 'item_id']); - } -} diff --git a/tests/unit/data/ar/elasticsearch/ActiveRecord.php b/tests/unit/data/ar/elasticsearch/ActiveRecord.php deleted file mode 100644 index aa1f304..0000000 --- a/tests/unit/data/ar/elasticsearch/ActiveRecord.php +++ /dev/null @@ -1,32 +0,0 @@ - - * @since 2.0 - */ -class ActiveRecord extends \yii\elasticsearch\ActiveRecord -{ - public static $db; - - /** - * @return \yii\elasticsearch\Connection - */ - public static function getDb() - { - return self::$db; - } - - public static function index() - { - return 'yiitest'; - } -} diff --git a/tests/unit/data/ar/elasticsearch/Customer.php b/tests/unit/data/ar/elasticsearch/Customer.php deleted file mode 100644 index 22d2c09..0000000 --- a/tests/unit/data/ar/elasticsearch/Customer.php +++ /dev/null @@ -1,70 +0,0 @@ -hasMany(Order::className(), array('customer_id' => 'id'))->orderBy('create_time'); - } - - public static function active($query) - { - $query->andWhere(array('status' => 1)); - } - - public function afterSave($insert) - { - ActiveRecordTest::$afterSaveInsert = $insert; - ActiveRecordTest::$afterSaveNewRecord = $this->isNewRecord; - parent::afterSave($insert); - } - - /** - * sets up the index for this record - * @param Command $command - */ - public static function setUpMapping($command, $statusIsBoolean = false) - { - $command->deleteMapping(static::index(), static::type()); - $command->setMapping(static::index(), static::type(), [ - static::type() => [ - "_id" => ["path" => "id", "index" => "not_analyzed", "store" => "yes"], - "properties" => [ - "name" => ["type" => "string", "index" => "not_analyzed"], - "email" => ["type" => "string", "index" => "not_analyzed"], - "address" => ["type" => "string", "index" => "analyzed"], - "status" => $statusIsBoolean ? ["type" => "boolean"] : ["type" => "integer"], - ] - ] - ]); - - } -} diff --git a/tests/unit/data/ar/elasticsearch/Item.php b/tests/unit/data/ar/elasticsearch/Item.php deleted file mode 100644 index 033c38d..0000000 --- a/tests/unit/data/ar/elasticsearch/Item.php +++ /dev/null @@ -1,43 +0,0 @@ -deleteMapping(static::index(), static::type()); - $command->setMapping(static::index(), static::type(), [ - static::type() => [ - "_id" => ["path" => "id", "index" => "not_analyzed", "store" => "yes"], - "properties" => [ - "name" => ["type" => "string", "index" => "not_analyzed"], - "category_id" => ["type" => "integer"], - ] - ] - ]); - - } -} diff --git a/tests/unit/data/ar/elasticsearch/Order.php b/tests/unit/data/ar/elasticsearch/Order.php deleted file mode 100644 index e7607cd..0000000 --- a/tests/unit/data/ar/elasticsearch/Order.php +++ /dev/null @@ -1,94 +0,0 @@ -hasOne(Customer::className(), ['id' => 'customer_id']); - } - - public function getOrderItems() - { - return $this->hasMany(OrderItem::className(), ['order_id' => 'id']); - } - - public function getItems() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems')->orderBy('id'); - } - - public function getItemsInOrder1() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems', function ($q) { - $q->orderBy(['subtotal' => SORT_ASC]); - })->orderBy('name'); - } - - public function getItemsInOrder2() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems', function ($q) { - $q->orderBy(['subtotal' => SORT_DESC]); - })->orderBy('name'); - } - -// public function getBooks() -// { -// return $this->hasMany('Item', ['id' => 'item_id']) -// ->viaTable('tbl_order_item', ['order_id' => 'id']) -// ->where(['category_id' => 1]); -// } - - public function beforeSave($insert) - { - if (parent::beforeSave($insert)) { -// $this->create_time = time(); - return true; - } else { - return false; - } - } - - /** - * sets up the index for this record - * @param Command $command - */ - public static function setUpMapping($command) - { - $command->deleteMapping(static::index(), static::type()); - $command->setMapping(static::index(), static::type(), [ - static::type() => [ - "_id" => ["path" => "id", "index" => "not_analyzed", "store" => "yes"], - "properties" => [ - "customer_id" => ["type" => "integer"], -// "create_time" => ["type" => "string", "index" => "not_analyzed"], - "total" => ["type" => "integer"], - ] - ] - ]); - - } -} diff --git a/tests/unit/data/ar/elasticsearch/OrderItem.php b/tests/unit/data/ar/elasticsearch/OrderItem.php deleted file mode 100644 index 36961d9..0000000 --- a/tests/unit/data/ar/elasticsearch/OrderItem.php +++ /dev/null @@ -1,50 +0,0 @@ -hasOne(Order::className(), ['id' => 'order_id']); - } - - public function getItem() - { - return $this->hasOne(Item::className(), ['id' => 'item_id']); - } - - /** - * sets up the index for this record - * @param Command $command - */ - public static function setUpMapping($command) - { - $command->deleteMapping(static::index(), static::type()); - $command->setMapping(static::index(), static::type(), [ - static::type() => [ - "properties" => [ - "order_id" => ["type" => "integer"], - "item_id" => ["type" => "integer"], - "quantity" => ["type" => "integer"], - "subtotal" => ["type" => "integer"], - ] - ] - ]); - - } -} diff --git a/tests/unit/data/ar/mongodb/ActiveRecord.php b/tests/unit/data/ar/mongodb/ActiveRecord.php deleted file mode 100644 index b0709a8..0000000 --- a/tests/unit/data/ar/mongodb/ActiveRecord.php +++ /dev/null @@ -1,16 +0,0 @@ -andWhere(['status' => 2]); - } - - public function getOrders() - { - return $this->hasMany(CustomerOrder::className(), ['customer_id' => '_id']); - } -} \ No newline at end of file diff --git a/tests/unit/data/ar/mongodb/CustomerOrder.php b/tests/unit/data/ar/mongodb/CustomerOrder.php deleted file mode 100644 index f037aae..0000000 --- a/tests/unit/data/ar/mongodb/CustomerOrder.php +++ /dev/null @@ -1,27 +0,0 @@ -hasOne(Customer::className(), ['_id' => 'customer_id']); - } -} \ No newline at end of file diff --git a/tests/unit/data/ar/mongodb/file/ActiveRecord.php b/tests/unit/data/ar/mongodb/file/ActiveRecord.php deleted file mode 100644 index 8ebc1b4..0000000 --- a/tests/unit/data/ar/mongodb/file/ActiveRecord.php +++ /dev/null @@ -1,16 +0,0 @@ -andWhere(['status' => 2]); - } -} \ No newline at end of file diff --git a/tests/unit/data/ar/redis/ActiveRecord.php b/tests/unit/data/ar/redis/ActiveRecord.php deleted file mode 100644 index 9f6d526..0000000 --- a/tests/unit/data/ar/redis/ActiveRecord.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @since 2.0 - */ -class ActiveRecord extends \yii\redis\ActiveRecord -{ - public static $db; - - public static function getDb() - { - return self::$db; - } -} \ No newline at end of file diff --git a/tests/unit/data/ar/redis/Customer.php b/tests/unit/data/ar/redis/Customer.php deleted file mode 100644 index 63143ff..0000000 --- a/tests/unit/data/ar/redis/Customer.php +++ /dev/null @@ -1,38 +0,0 @@ -hasMany(Order::className(), ['customer_id' => 'id']); - } - - public static function active($query) - { - $query->andWhere(['status' => 1]); - } - - public function afterSave($insert) - { - ActiveRecordTest::$afterSaveInsert = $insert; - ActiveRecordTest::$afterSaveNewRecord = $this->isNewRecord; - parent::afterSave($insert); - } -} \ No newline at end of file diff --git a/tests/unit/data/ar/redis/Item.php b/tests/unit/data/ar/redis/Item.php deleted file mode 100644 index 0bcb072..0000000 --- a/tests/unit/data/ar/redis/Item.php +++ /dev/null @@ -1,11 +0,0 @@ -hasOne(Customer::className(), ['id' => 'customer_id']); - } - - public function getOrderItems() - { - return $this->hasMany(OrderItem::className(), ['order_id' => 'id']); - } - - public function getItems() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems', function($q) { - // additional query configuration - }); - } - - public function getItemsInOrder1() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems', function ($q) { - $q->orderBy(['subtotal' => SORT_ASC]); - })->orderBy('name'); - } - - public function getItemsInOrder2() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems', function ($q) { - $q->orderBy(['subtotal' => SORT_DESC]); - })->orderBy('name'); - } - - public function getBooks() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems', ['order_id' => 'id']); - //->where(['category_id' => 1]); - } - - public function beforeSave($insert) - { - if (parent::beforeSave($insert)) { - $this->create_time = time(); - return true; - } else { - return false; - } - } -} \ No newline at end of file diff --git a/tests/unit/data/ar/redis/OrderItem.php b/tests/unit/data/ar/redis/OrderItem.php deleted file mode 100644 index a4c82b9..0000000 --- a/tests/unit/data/ar/redis/OrderItem.php +++ /dev/null @@ -1,26 +0,0 @@ -hasOne(Order::className(), ['id' => 'order_id']); - } - - public function getItem() - { - return $this->hasOne(Item::className(), ['id' => 'item_id']); - } -} \ No newline at end of file diff --git a/tests/unit/data/ar/sphinx/ActiveRecord.php b/tests/unit/data/ar/sphinx/ActiveRecord.php deleted file mode 100644 index 2e5183e..0000000 --- a/tests/unit/data/ar/sphinx/ActiveRecord.php +++ /dev/null @@ -1,16 +0,0 @@ - ArticleIndex::className(), - 'primaryModel' => $this, - 'link' => ['id' => 'id'], - 'multiple' => false, - ]; - return new ActiveRelation($config); - } -} \ No newline at end of file diff --git a/tests/unit/data/ar/sphinx/ArticleIndex.php b/tests/unit/data/ar/sphinx/ArticleIndex.php deleted file mode 100644 index ed1073d..0000000 --- a/tests/unit/data/ar/sphinx/ArticleIndex.php +++ /dev/null @@ -1,35 +0,0 @@ -andWhere('author_id=1'); - } - - public function getSource() - { - return $this->hasOne(ArticleDb::className(), ['id' => 'id']); - } - - public function getTags() - { - return $this->hasMany(TagDb::className(), ['id' => 'tag']); - } - - public function getSnippetSource() - { - return $this->source->content; - } -} \ No newline at end of file diff --git a/tests/unit/data/ar/sphinx/ItemDb.php b/tests/unit/data/ar/sphinx/ItemDb.php deleted file mode 100644 index 9cf10ad..0000000 --- a/tests/unit/data/ar/sphinx/ItemDb.php +++ /dev/null @@ -1,13 +0,0 @@ - 'Lennon'], - [['lastName'], 'required'], - [['underscore_style'], 'yii\captcha\CaptchaValidator'], - ]; - } -} diff --git a/tests/unit/data/base/Speaker.php b/tests/unit/data/base/Speaker.php deleted file mode 100644 index 7585df3..0000000 --- a/tests/unit/data/base/Speaker.php +++ /dev/null @@ -1,45 +0,0 @@ - 'This is the custom label', - ]; - } - - public function rules() - { - return []; - } - - public function scenarios() - { - return [ - 'test' => ['firstName', 'lastName', '!underscore_style'], - ]; - } -} diff --git a/tests/unit/data/config.php b/tests/unit/data/config.php deleted file mode 100644 index a3dfdd4..0000000 --- a/tests/unit/data/config.php +++ /dev/null @@ -1,60 +0,0 @@ - [ - 'cubrid' => [ - 'dsn' => 'cubrid:dbname=demodb;host=localhost;port=33000', - 'username' => 'dba', - 'password' => '', - 'fixture' => __DIR__ . '/cubrid.sql', - ], - 'mysql' => [ - 'dsn' => 'mysql:host=127.0.0.1;dbname=yiitest', - 'username' => 'travis', - 'password' => '', - 'fixture' => __DIR__ . '/mysql.sql', - ], - 'sqlite' => [ - 'dsn' => 'sqlite::memory:', - 'fixture' => __DIR__ . '/sqlite.sql', - ], - 'sqlsrv' => [ - 'dsn' => 'sqlsrv:Server=localhost;Database=test', - 'username' => '', - 'password' => '', - 'fixture' => __DIR__ . '/mssql.sql', - ], - 'pgsql' => [ - 'dsn' => 'pgsql:host=localhost;dbname=yiitest;port=5432;', - 'username' => 'postgres', - 'password' => 'postgres', - 'fixture' => __DIR__ . '/postgres.sql', - ], - 'elasticsearch' => [ - 'dsn' => 'elasticsearch://localhost:9200' - ], - 'redis' => [ - 'hostname' => 'localhost', - 'port' => 6379, - 'database' => 0, - 'password' => null, - ], - ], - 'sphinx' => [ - 'sphinx' => [ - 'dsn' => 'mysql:host=127.0.0.1;port=9306;', - 'username' => 'travis', - 'password' => '', - ], - 'db' => [ - 'dsn' => 'mysql:host=127.0.0.1;dbname=yiitest', - 'username' => 'travis', - 'password' => '', - 'fixture' => __DIR__ . '/sphinx/source.sql', - ], - ], - 'mongodb' => [ - 'dsn' => 'mongodb://travis:test@localhost:27017', - 'defaultDatabaseName' => 'yii2test', - 'options' => [], - ] -]; diff --git a/tests/unit/data/cubrid.sql b/tests/unit/data/cubrid.sql deleted file mode 100644 index 1fe75ed..0000000 --- a/tests/unit/data/cubrid.sql +++ /dev/null @@ -1,119 +0,0 @@ -/** - * This is the database schema for testing CUBRID support of Yii DAO and Active Record. - * The database setup in config.php is required to perform then relevant tests: - */ - -DROP TABLE IF EXISTS tbl_composite_fk; -DROP TABLE IF EXISTS tbl_order_item; -DROP TABLE IF EXISTS tbl_item; -DROP TABLE IF EXISTS tbl_order; -DROP TABLE IF EXISTS tbl_category; -DROP TABLE IF EXISTS tbl_customer; -DROP TABLE IF EXISTS tbl_null_values; -DROP TABLE IF EXISTS tbl_type; -DROP TABLE IF EXISTS tbl_constraints; - -CREATE TABLE `tbl_constraints` -( - `id` integer not null, - `field1` varchar(255) -); - - -CREATE TABLE `tbl_customer` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `email` varchar(128) NOT NULL, - `name` varchar(128), - `address` string, - `status` int (11) DEFAULT 0, - PRIMARY KEY (`id`) -); - -CREATE TABLE `tbl_category` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(128) NOT NULL, - PRIMARY KEY (`id`) -); - -CREATE TABLE `tbl_item` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(128) NOT NULL, - `category_id` int(11) NOT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `FK_item_category_id` FOREIGN KEY (`category_id`) REFERENCES `tbl_category` (`id`) ON DELETE CASCADE -); - -CREATE TABLE `tbl_order` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `customer_id` int(11) NOT NULL, - `create_time` int(11) NOT NULL, - `total` decimal(10,0) NOT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `FK_order_customer_id` FOREIGN KEY (`customer_id`) REFERENCES `tbl_customer` (`id`) ON DELETE CASCADE -); - -CREATE TABLE `tbl_order_item` ( - `order_id` int(11) NOT NULL, - `item_id` int(11) NOT NULL, - `quantity` int(11) NOT NULL, - `subtotal` decimal(10,0) NOT NULL, - PRIMARY KEY (`order_id`,`item_id`), - CONSTRAINT `FK_order_item_order_id` FOREIGN KEY (`order_id`) REFERENCES `tbl_order` (`id`) ON DELETE CASCADE, - CONSTRAINT `FK_order_item_item_id` FOREIGN KEY (`item_id`) REFERENCES `tbl_item` (`id`) ON DELETE CASCADE -); - -CREATE TABLE tbl_null_values ( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `var1` INT NULL, - `var2` INT NULL, - `var3` INT DEFAULT NULL, - `stringcol` VARCHAR (32) DEFAULT NULL, - PRIMARY KEY (id) -); - - -CREATE TABLE `tbl_type` ( - `int_col` int(11) NOT NULL, - `int_col2` int(11) DEFAULT '1', - `char_col` char(100) NOT NULL, - `char_col2` varchar(100) DEFAULT 'something', - `char_col3` string, - `enum_col` enum('a', 'b'), - `float_col` double NOT NULL, - `float_col2` double DEFAULT '1.23', - `blob_col` blob, - `numeric_col` decimal(5,2) DEFAULT '33.22', - `time` timestamp NOT NULL DEFAULT '2002-01-01 00:00:00' -); - -CREATE TABLE `tbl_composite_fk` ( - `id` int(11) NOT NULL, - `order_id` int(11) NOT NULL, - `item_id` int(11) NOT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `FK_composite_fk_order_item` FOREIGN KEY (`order_id`,`item_id`) REFERENCES `tbl_order_item` (`order_id`,`item_id`) ON DELETE CASCADE -); - -INSERT INTO tbl_customer (email, name, address, status) VALUES ('user1@example.com', 'user1', 'address1', 1); -INSERT INTO tbl_customer (email, name, address, status) VALUES ('user2@example.com', 'user2', 'address2', 1); -INSERT INTO tbl_customer (email, name, address, status) VALUES ('user3@example.com', 'user3', 'address3', 2); - -INSERT INTO tbl_category (name) VALUES ('Books'); -INSERT INTO tbl_category (name) VALUES ('Movies'); - -INSERT INTO tbl_item (name, category_id) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); -INSERT INTO tbl_item (name, category_id) VALUES ('Yii 1.1 Application Development Cookbook', 1); -INSERT INTO tbl_item (name, category_id) VALUES ('Ice Age', 2); -INSERT INTO tbl_item (name, category_id) VALUES ('Toy Story', 2); -INSERT INTO tbl_item (name, category_id) VALUES ('Cars', 2); - -INSERT INTO tbl_order (customer_id, create_time, total) VALUES (1, 1325282384, 110.0); -INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325334482, 33.0); -INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325502201, 40.0); - -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); diff --git a/tests/unit/data/i18n/messages/de-DE/test.php b/tests/unit/data/i18n/messages/de-DE/test.php deleted file mode 100644 index d8c5290..0000000 --- a/tests/unit/data/i18n/messages/de-DE/test.php +++ /dev/null @@ -1,9 +0,0 @@ - 'Der Hund rennt schnell.', - 'His speed is about {n} km/h.' => 'Seine Geschwindigkeit beträgt {n} km/h.', - 'His name is {name} and his speed is about {n, number} km/h.' => 'Er heißt {name} und ist {n, number} km/h schnell.', -]; \ No newline at end of file diff --git a/tests/unit/data/i18n/messages/en-US/test.php b/tests/unit/data/i18n/messages/en-US/test.php deleted file mode 100644 index 83342b0..0000000 --- a/tests/unit/data/i18n/messages/en-US/test.php +++ /dev/null @@ -1,7 +0,0 @@ - 'Der Hund rennt schell.', -]; \ No newline at end of file diff --git a/tests/unit/data/i18n/test.mo b/tests/unit/data/i18n/test.mo deleted file mode 100644 index d5f94f1..0000000 Binary files a/tests/unit/data/i18n/test.mo and /dev/null differ diff --git a/tests/unit/data/i18n/test.po b/tests/unit/data/i18n/test.po deleted file mode 100644 index fed95c9..0000000 --- a/tests/unit/data/i18n/test.po +++ /dev/null @@ -1,64 +0,0 @@ -msgid "" -msgstr "" -"Project-Id-Version: \n" -"POT-Creation-Date: \n" -"PO-Revision-Date: \n" -"Last-Translator: resurtm \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.5.5\n" - -msgctxt "context1" -msgid "" -"Aliquam tempus elit vel purus molestie placerat. In sollicitudin tincidunt\n" -"aliquet. Integer tincidunt gravida tempor. In convallis blandit dui vel " -"malesuada.\n" -"Nunc vel sapien nunc, a pretium nulla." -msgstr "" -"Олицетворение однократно. Представленный лексико-семантический анализ " -"является\n" -"психолингвистическим в своей основе, но механизм сочленений полидисперсен. " -"Впечатление\n" -"однократно. Различное расположение выбирает сюжетный механизм сочленений." - -msgctxt "context1" -msgid "String number two." -msgstr "Строка номер два." - -msgctxt "context2" -msgid "" -"The other\n" -"\n" -"context.\n" -msgstr "" -"Другой\n" -"\n" -"контекст.\n" - -msgctxt "context1" -msgid "" -"Missing\n" -"\r\t\"translation." -msgstr "" - -msgctxt "context1" -msgid "" -"Nunc vel sapien nunc, a pretium nulla.\n" -"Pellentesque habitant morbi tristique senectus et netus et malesuada fames " -"ac turpis egestas." -msgstr "Короткий перевод." - -msgid "contextless" -msgstr "" - -msgctxt "context2" -msgid "" -"test1\\ntest2\n" -"\\\n" -"test3" -msgstr "" -"тест1\\nтест2\n" -"\\\n" -"тест3" diff --git a/tests/unit/data/imagine/GothamRnd-Light.otf b/tests/unit/data/imagine/GothamRnd-Light.otf deleted file mode 100644 index 4181a78..0000000 Binary files a/tests/unit/data/imagine/GothamRnd-Light.otf and /dev/null differ diff --git a/tests/unit/data/imagine/large.jpg b/tests/unit/data/imagine/large.jpg deleted file mode 100644 index 81c47e5..0000000 Binary files a/tests/unit/data/imagine/large.jpg and /dev/null differ diff --git a/tests/unit/data/imagine/xparent.gif b/tests/unit/data/imagine/xparent.gif deleted file mode 100644 index 2e6fd66..0000000 Binary files a/tests/unit/data/imagine/xparent.gif and /dev/null differ diff --git a/tests/unit/data/mssql.sql b/tests/unit/data/mssql.sql deleted file mode 100644 index a074205..0000000 --- a/tests/unit/data/mssql.sql +++ /dev/null @@ -1,104 +0,0 @@ -IF OBJECT_ID('[dbo].[tbl_order_item]', 'U') IS NOT NULL DROP TABLE [dbo].[tbl_order_item]; -IF OBJECT_ID('[dbo].[tbl_item]', 'U') IS NOT NULL DROP TABLE [dbo].[tbl_item]; -IF OBJECT_ID('[dbo].[tbl_order]', 'U') IS NOT NULL DROP TABLE [dbo].[tbl_order]; -IF OBJECT_ID('[dbo].[tbl_category]', 'U') IS NOT NULL DROP TABLE [dbo].[tbl_category]; -IF OBJECT_ID('[dbo].[tbl_customer]', 'U') IS NOT NULL DROP TABLE [dbo].[tbl_customer]; -IF OBJECT_ID('[dbo].[tbl_type]', 'U') IS NOT NULL DROP TABLE [dbo].[tbl_type]; -IF OBJECT_ID('[dbo].[tbl_null_values]', 'U') IS NOT NULL DROP TABLE [dbo].[tbl_null_values]; - -CREATE TABLE [dbo].[tbl_customer] ( - [id] [int] IDENTITY(1,1) NOT NULL, - [email] [varchar](128) NOT NULL, - [name] [varchar](128), - [address] [text], - [status] [int] DEFAULT 0, - CONSTRAINT [PK_customer] PRIMARY KEY CLUSTERED ( - [id] ASC - ) ON [PRIMARY] -); - -CREATE TABLE [dbo].[tbl_category] ( - [id] [int] IDENTITY(1,1) NOT NULL, - [name] [varchar](128) NOT NULL, - CONSTRAINT [PK_category] PRIMARY KEY CLUSTERED ( - [id] ASC - ) ON [PRIMARY] -); - -CREATE TABLE [dbo].[tbl_item] ( - [id] [int] IDENTITY(1,1) NOT NULL, - [name] [varchar](128) NOT NULL, - [category_id] [int] NOT NULL, - CONSTRAINT [PK_item] PRIMARY KEY CLUSTERED ( - [id] ASC - ) ON [PRIMARY] -); - -CREATE TABLE [dbo].[tbl_order] ( - [id] [int] IDENTITY(1,1) NOT NULL, - [customer_id] [int] NOT NULL, - [create_time] [int] NOT NULL, - [total] [decimal](10,0) NOT NULL, - CONSTRAINT [PK_order] PRIMARY KEY CLUSTERED ( - [id] ASC - ) ON [PRIMARY] -); - -CREATE TABLE [dbo].[tbl_order_item] ( - [order_id] [int] NOT NULL, - [item_id] [int] NOT NULL, - [quantity] [int] NOT NULL, - [subtotal] [decimal](10,0) NOT NULL, - CONSTRAINT [PK_order_item] PRIMARY KEY CLUSTERED ( - [order_id] ASC, - [item_id] ASC - ) ON [PRIMARY] -); - -CREATE TABLE [dbo].[tbl_null_values] ( - id [int] UNSIGNED NOT NULL, - var1 [int] UNSIGNED NULL, - var2 [int] NULL, - var3 [int] DEFAULT NULL, - stringcol [varchar](32) DEFAULT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE [dbo].[tbl_type] ( - [int_col] [int] NOT NULL, - [int_col2] [int] DEFAULT '1', - [char_col] [char](100) NOT NULL, - [char_col2] [varchar](100) DEFAULT 'something', - [char_col3] [text], - [float_col] [decimal](4,3) NOT NULL, - [float_col2] [float] DEFAULT '1.23', - [blob_col] [varbinary](MAX), - [numeric_col] [decimal](5,2) DEFAULT '33.22', - [time] [datetime] NOT NULL DEFAULT '2002-01-01 00:00:00', - [bool_col] [tinyint] NOT NULL, - [bool_col2] [tinyint] DEFAULT '1' -); - -INSERT INTO [dbo].[tbl_customer] ([email], [name], [address], [status]) VALUES ('user1@example.com', 'user1', 'address1', 1); -INSERT INTO [dbo].[tbl_customer] ([email], [name], [address], [status]) VALUES ('user2@example.com', 'user2', 'address2', 1); -INSERT INTO [dbo].[tbl_customer] ([email], [name], [address], [status]) VALUES ('user3@example.com', 'user3', 'address3', 2); - -INSERT INTO [dbo].[tbl_category] ([name]) VALUES ('Books'); -INSERT INTO [dbo].[tbl_category] ([name]) VALUES ('Movies'); - -INSERT INTO [dbo].[tbl_item] ([name], [category_id]) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); -INSERT INTO [dbo].[tbl_item] ([name], [category_id]) VALUES ('Yii 1.1 Application Development Cookbook', 1); -INSERT INTO [dbo].[tbl_item] ([name], [category_id]) VALUES ('Ice Age', 2); -INSERT INTO [dbo].[tbl_item] ([name], [category_id]) VALUES ('Toy Story', 2); -INSERT INTO [dbo].[tbl_item] ([name], [category_id]) VALUES ('Cars', 2); - -INSERT INTO [dbo].[tbl_order] ([customer_id], [create_time], [total]) VALUES (1, 1325282384, 110.0); -INSERT INTO [dbo].[tbl_order] ([customer_id], [create_time], [total]) VALUES (2, 1325334482, 33.0); -INSERT INTO [dbo].[tbl_order] ([customer_id], [create_time], [total]) VALUES (2, 1325502201, 40.0); - -INSERT INTO [dbo].[tbl_order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (1, 1, 1, 30.0); -INSERT INTO [dbo].[tbl_order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (1, 2, 2, 40.0); -INSERT INTO [dbo].[tbl_order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 4, 1, 10.0); -INSERT INTO [dbo].[tbl_order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 5, 1, 15.0); -INSERT INTO [dbo].[tbl_order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 3, 1, 8.0); -INSERT INTO [dbo].[tbl_order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (3, 2, 1, 40.0); diff --git a/tests/unit/data/mysql.sql b/tests/unit/data/mysql.sql deleted file mode 100644 index ff5b72e..0000000 --- a/tests/unit/data/mysql.sql +++ /dev/null @@ -1,153 +0,0 @@ -/** - * This is the database schema for testing MySQL support of Yii DAO and Active Record. - * The database setup in config.php is required to perform then relevant tests: - */ - -DROP TABLE IF EXISTS tbl_composite_fk CASCADE; -DROP TABLE IF EXISTS tbl_order_item CASCADE; -DROP TABLE IF EXISTS tbl_item CASCADE; -DROP TABLE IF EXISTS tbl_order CASCADE; -DROP TABLE IF EXISTS tbl_category CASCADE; -DROP TABLE IF EXISTS tbl_customer CASCADE; -DROP TABLE IF EXISTS tbl_null_values CASCADE; -DROP TABLE IF EXISTS tbl_type CASCADE; -DROP TABLE IF EXISTS tbl_constraints CASCADE; - -CREATE TABLE `tbl_constraints` -( - `id` integer not null, - `field1` varchar(255) -); - - -CREATE TABLE `tbl_customer` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `email` varchar(128) NOT NULL, - `name` varchar(128), - `address` text, - `status` int (11) DEFAULT 0, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `tbl_category` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(128) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `tbl_item` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(128) NOT NULL, - `category_id` int(11) NOT NULL, - PRIMARY KEY (`id`), - KEY `FK_item_category_id` (`category_id`), - CONSTRAINT `FK_item_category_id` FOREIGN KEY (`category_id`) REFERENCES `tbl_category` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `tbl_order` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `customer_id` int(11) NOT NULL, - `create_time` int(11) NOT NULL, - `total` decimal(10,0) NOT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `FK_order_customer_id` FOREIGN KEY (`customer_id`) REFERENCES `tbl_customer` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `tbl_order_item` ( - `order_id` int(11) NOT NULL, - `item_id` int(11) NOT NULL, - `quantity` int(11) NOT NULL, - `subtotal` decimal(10,0) NOT NULL, - PRIMARY KEY (`order_id`,`item_id`), - KEY `FK_order_item_item_id` (`item_id`), - CONSTRAINT `FK_order_item_order_id` FOREIGN KEY (`order_id`) REFERENCES `tbl_order` (`id`) ON DELETE CASCADE, - CONSTRAINT `FK_order_item_item_id` FOREIGN KEY (`item_id`) REFERENCES `tbl_item` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `tbl_composite_fk` ( - `id` int(11) NOT NULL, - `order_id` int(11) NOT NULL, - `item_id` int(11) NOT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `FK_composite_fk_order_item` FOREIGN KEY (`order_id`,`item_id`) REFERENCES `tbl_order_item` (`order_id`,`item_id`) ON DELETE CASCADE -); - -CREATE TABLE tbl_null_values ( - `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, - `var1` INT UNSIGNED NULL, - `var2` INT NULL, - `var3` INT DEFAULT NULL, - `stringcol` VARCHAR (32) DEFAULT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE `tbl_type` ( - `int_col` int(11) NOT NULL, - `int_col2` int(11) DEFAULT '1', - `char_col` char(100) NOT NULL, - `char_col2` varchar(100) DEFAULT 'something', - `char_col3` text, - `float_col` double(4,3) NOT NULL, - `float_col2` double DEFAULT '1.23', - `blob_col` blob, - `numeric_col` decimal(5,2) DEFAULT '33.22', - `time` timestamp NOT NULL DEFAULT '2002-01-01 00:00:00', - `bool_col` tinyint(1) NOT NULL, - `bool_col2` tinyint(1) DEFAULT '1' -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -INSERT INTO tbl_customer (email, name, address, status) VALUES ('user1@example.com', 'user1', 'address1', 1); -INSERT INTO tbl_customer (email, name, address, status) VALUES ('user2@example.com', 'user2', 'address2', 1); -INSERT INTO tbl_customer (email, name, address, status) VALUES ('user3@example.com', 'user3', 'address3', 2); - -INSERT INTO tbl_category (name) VALUES ('Books'); -INSERT INTO tbl_category (name) VALUES ('Movies'); - -INSERT INTO tbl_item (name, category_id) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); -INSERT INTO tbl_item (name, category_id) VALUES ('Yii 1.1 Application Development Cookbook', 1); -INSERT INTO tbl_item (name, category_id) VALUES ('Ice Age', 2); -INSERT INTO tbl_item (name, category_id) VALUES ('Toy Story', 2); -INSERT INTO tbl_item (name, category_id) VALUES ('Cars', 2); - -INSERT INTO tbl_order (customer_id, create_time, total) VALUES (1, 1325282384, 110.0); -INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325334482, 33.0); -INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325502201, 40.0); - -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); - - -/** - * (MySQL-)Database Schema for validator tests - */ - -DROP TABLE IF EXISTS tbl_validator_main CASCADE; -DROP TABLE IF EXISTS tbl_validator_ref CASCADE; - -CREATE TABLE tbl_validator_main ( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `field1` VARCHAR(255), - PRIMARY KEY (`id`) -) ENGINE =InnoDB DEFAULT CHARSET =utf8; - -CREATE TABLE tbl_validator_ref ( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `a_field` VARCHAR(255), - `ref` INT(11), - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -INSERT INTO tbl_validator_main (id, field1) VALUES (1, 'just a string1'); -INSERT INTO tbl_validator_main (id, field1) VALUES (2, 'just a string2'); -INSERT INTO tbl_validator_main (id, field1) VALUES (3, 'just a string3'); -INSERT INTO tbl_validator_main (id, field1) VALUES (4, 'just a string4'); -INSERT INTO tbl_validator_ref (a_field, ref) VALUES ('ref_to_2', 2); -INSERT INTO tbl_validator_ref (a_field, ref) VALUES ('ref_to_2', 2); -INSERT INTO tbl_validator_ref (a_field, ref) VALUES ('ref_to_3', 3); -INSERT INTO tbl_validator_ref (a_field, ref) VALUES ('ref_to_4', 4); -INSERT INTO tbl_validator_ref (a_field, ref) VALUES ('ref_to_4', 4); -INSERT INTO tbl_validator_ref (a_field, ref) VALUES ('ref_to_5', 5); diff --git a/tests/unit/data/postgres.sql b/tests/unit/data/postgres.sql deleted file mode 100644 index 8d5cb4f..0000000 --- a/tests/unit/data/postgres.sql +++ /dev/null @@ -1,133 +0,0 @@ -/** - * This is the database schema for testing PostgreSQL support of yii Active Record. - * To test this feature, you need to create a database named 'yiitest' on 'localhost' - * and create an account 'postgres/postgres' which owns this test database. - */ - -DROP TABLE IF EXISTS tbl_order_item CASCADE; -DROP TABLE IF EXISTS tbl_item CASCADE; -DROP TABLE IF EXISTS tbl_order CASCADE; -DROP TABLE IF EXISTS tbl_category CASCADE; -DROP TABLE IF EXISTS tbl_customer CASCADE; -DROP TABLE IF EXISTS tbl_type CASCADE; -DROP TABLE IF EXISTS tbl_null_values CASCADE; -DROP TABLE IF EXISTS tbl_constraints CASCADE; - -CREATE TABLE tbl_constraints -( - id integer not null, - field1 varchar(255) -); - -CREATE TABLE tbl_customer ( - id serial not null primary key, - email varchar(128) NOT NULL, - name varchar(128), - address text, - status integer DEFAULT 0 -); - -comment on column public.tbl_customer.email is 'someone@example.com'; - -CREATE TABLE tbl_category ( - id serial not null primary key, - name varchar(128) NOT NULL -); - -CREATE TABLE tbl_item ( - id serial not null primary key, - name varchar(128) NOT NULL, - category_id integer NOT NULL references tbl_category(id) on UPDATE CASCADE on DELETE CASCADE -); - -CREATE TABLE tbl_order ( - id serial not null primary key, - customer_id integer NOT NULL references tbl_customer(id) on UPDATE CASCADE on DELETE CASCADE, - create_time integer NOT NULL, - total decimal(10,0) NOT NULL -); - -CREATE TABLE tbl_order_item ( - order_id integer NOT NULL references tbl_order(id) on UPDATE CASCADE on DELETE CASCADE, - item_id integer NOT NULL references tbl_item(id) on UPDATE CASCADE on DELETE CASCADE, - quantity integer NOT NULL, - subtotal decimal(10,0) NOT NULL, - PRIMARY KEY (order_id,item_id) -); - -CREATE TABLE tbl_null_values ( - id INT NOT NULL, - var1 INT NULL, - var2 INT NULL, - var3 INT DEFAULT NULL, - stringcol VARCHAR(32) DEFAULT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE tbl_type ( - int_col integer NOT NULL, - int_col2 integer DEFAULT '1', - char_col char(100) NOT NULL, - char_col2 varchar(100) DEFAULT 'something', - char_col3 text, - float_col double precision NOT NULL, - float_col2 double precision DEFAULT '1.23', - blob_col bytea, - numeric_col decimal(5,2) DEFAULT '33.22', - time timestamp NOT NULL DEFAULT '2002-01-01 00:00:00', - bool_col smallint NOT NULL, - bool_col2 smallint DEFAULT '1' -); - -INSERT INTO tbl_customer (email, name, address, status) VALUES ('user1@example.com', 'user1', 'address1', 1); -INSERT INTO tbl_customer (email, name, address, status) VALUES ('user2@example.com', 'user2', 'address2', 1); -INSERT INTO tbl_customer (email, name, address, status) VALUES ('user3@example.com', 'user3', 'address3', 2); - -INSERT INTO tbl_category (name) VALUES ('Books'); -INSERT INTO tbl_category (name) VALUES ('Movies'); - -INSERT INTO tbl_item (name, category_id) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); -INSERT INTO tbl_item (name, category_id) VALUES ('Yii 1.1 Application Development Cookbook', 1); -INSERT INTO tbl_item (name, category_id) VALUES ('Ice Age', 2); -INSERT INTO tbl_item (name, category_id) VALUES ('Toy Story', 2); -INSERT INTO tbl_item (name, category_id) VALUES ('Cars', 2); - -INSERT INTO tbl_order (customer_id, create_time, total) VALUES (1, 1325282384, 110.0); -INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325334482, 33.0); -INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325502201, 40.0); - -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); - -/** - * (Postgres-)Database Schema for validator tests - */ - -DROP TABLE IF EXISTS tbl_validator_main CASCADE; -DROP TABLE IF EXISTS tbl_validator_ref CASCADE; - -CREATE TABLE tbl_validator_main ( - id integer not null primary key, - field1 VARCHAR(255) -); - -CREATE TABLE tbl_validator_ref ( - id integer not null primary key, - a_field VARCHAR(255), - ref integer -); - -INSERT INTO tbl_validator_main (id, field1) VALUES (1, 'just a string1'); -INSERT INTO tbl_validator_main (id, field1) VALUES (2, 'just a string2'); -INSERT INTO tbl_validator_main (id, field1) VALUES (3, 'just a string3'); -INSERT INTO tbl_validator_main (id, field1) VALUES (4, 'just a string4'); -INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (1, 'ref_to_2', 2); -INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (2, 'ref_to_2', 2); -INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (3, 'ref_to_3', 3); -INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (4, 'ref_to_4', 4); -INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (5, 'ref_to_4', 4); -INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (6, 'ref_to_5', 5); \ No newline at end of file diff --git a/tests/unit/data/sphinx/source.sql b/tests/unit/data/sphinx/source.sql deleted file mode 100644 index cfa8642..0000000 --- a/tests/unit/data/sphinx/source.sql +++ /dev/null @@ -1,59 +0,0 @@ -/** - * This is the MySQL database schema for creation of the test Sphinx index sources. - */ - -DROP TABLE IF EXISTS yii2_test_article; -DROP TABLE IF EXISTS yii2_test_item; -DROP TABLE IF EXISTS yii2_test_tag; -DROP TABLE IF EXISTS yii2_test_article_tag; - -CREATE TABLE IF NOT EXISTS `yii2_test_article` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `title` varchar(255) NOT NULL, - `content` text NOT NULL, - `author_id` int(11) NOT NULL, - `create_date` datetime NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ; - -CREATE TABLE IF NOT EXISTS `yii2_test_item` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - `description` text NOT NULL, - `category_id` int(11) NOT NULL, - `price` float NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3; - -CREATE TABLE IF NOT EXISTS `yii2_test_tag` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=5; - -CREATE TABLE IF NOT EXISTS `yii2_test_article_tag` ( - `article_id` int(11) NOT NULL, - `tag_id` int(11) NOT NULL, - PRIMARY KEY (`article_id`,`tag_id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; - -INSERT INTO `yii2_test_article` (`id`, `title`, `content`, `author_id`, `create_date`) VALUES -(1, 'About cats', 'This article is about cats', 1, '2013-10-23 00:00:00'), -(2, 'About dogs', 'This article is about dogs', 2, '2013-11-15 00:00:00'); - -INSERT INTO `yii2_test_item` (`id`, `name`, `description`, `category_id`, `price`) VALUES -(1, 'pencil', 'Simple pencil', 1, 2.5), -(2, 'table', 'Wooden table', 2, 100); - -INSERT INTO `yii2_test_tag` (`id`, `name`) VALUES -(1, 'tag1'), -(2, 'tag2'), -(3, 'tag3'), -(4, 'tag4'); - -INSERT INTO `yii2_test_article_tag` (`article_id`, `tag_id`) VALUES -(1, 1), -(1, 2), -(1, 3), -(2, 3), -(2, 4); \ No newline at end of file diff --git a/tests/unit/data/sphinx/sphinx.conf b/tests/unit/data/sphinx/sphinx.conf deleted file mode 100644 index 5672e06..0000000 --- a/tests/unit/data/sphinx/sphinx.conf +++ /dev/null @@ -1,125 +0,0 @@ -# Sphinx configuration for the unit tests -# -# Setup test environment: -# - initialize test database source: -# mysql -D yiitest -u test < /path/to/yii/tests/unit/data/sphinx/source.sql -# - setup test Sphinx indexes: -# indexer --config /path/to/yii/tests/unit/data/sphinx/sphinx.conf --all [--rotate] -# - run the "searchd" daemon: -# searchd --config /path/to/yii/tests/unit/data/sphinx/sphinx.conf - - -source yii2_test_article_src -{ - type = mysql - - sql_host = localhost - sql_user = travis - sql_pass = - sql_db = yiitest - sql_port = 3306 # optional, default is 3306 - - sql_query = \ - SELECT *, UNIX_TIMESTAMP(create_date) AS add_date \ - FROM yii2_test_article - - sql_attr_uint = id - sql_attr_uint = author_id - sql_attr_timestamp = add_date - sql_attr_multi = uint tag from query; SELECT article_id AS id, tag_id AS tag FROM yii2_test_article_tag - - sql_query_info = SELECT * FROM yii2_test_article WHERE id=$id -} - - -source yii2_test_item_src -{ - type = mysql - - sql_host = localhost - sql_user = travis - sql_pass = - sql_db = yiitest - sql_port = 3306 # optional, default is 3306 - - sql_query = \ - SELECT *, CURRENT_TIMESTAMP() AS add_date \ - FROM yii2_test_item \ - WHERE id <= 100 - - sql_attr_uint = id - sql_attr_uint = category_id - sql_attr_float = price - sql_attr_timestamp = add_date - - sql_query_info = SELECT * FROM yii2_test_item WHERE id=$id -} - - -source yii2_test_item_delta_src : yii2_test_item_src -{ - sql_query = \ - SELECT *, CURRENT_TIMESTAMP() AS add_date \ - FROM yii2_test_item \ - WHERE id > 100 -} - - -index yii2_test_article_index -{ - source = yii2_test_article_src - path = /var/lib/sphinx/yii2_test_article - docinfo = extern - charset_type = sbcs -} - - -index yii2_test_item_index -{ - source = yii2_test_item_src - path = /var/lib/sphinx/yii2_test_item - docinfo = extern - charset_type = sbcs -} - - -index yii2_test_item_delta_index : yii2_test_item_index -{ - source = yii2_test_item_delta_src - path = /var/lib/sphinx/yii2_test_item_delta -} - - -index yii2_test_rt_index -{ - type = rt - path = /var/lib/sphinx/yii2_test_rt - rt_field = title - rt_field = content - rt_attr_uint = type_id - rt_attr_multi = category -} - - -indexer -{ - mem_limit = 32M -} - - -searchd -{ - listen = 127.0.0.1:9312 - listen = 9306:mysql41 - log = /var/log/sphinx/searchd.log - query_log = /var/log/sphinx/query.log - read_timeout = 5 - max_children = 30 - pid_file = /var/run/sphinx/searchd.pid - max_matches = 1000 - seamless_rotate = 1 - preopen_indexes = 1 - unlink_old = 1 - workers = threads # for RT to work - binlog_path = /var/lib/sphinx -} diff --git a/tests/unit/data/sqlite.sql b/tests/unit/data/sqlite.sql deleted file mode 100644 index ba8a208..0000000 --- a/tests/unit/data/sqlite.sql +++ /dev/null @@ -1,135 +0,0 @@ -/** - * This is the database schema for testing Sqlite support of Yii DAO and Active Record. - * The database setup in config.php is required to perform then relevant tests: - */ - -DROP TABLE IF EXISTS tbl_composite_fk; -DROP TABLE IF EXISTS tbl_order_item; -DROP TABLE IF EXISTS tbl_item; -DROP TABLE IF EXISTS tbl_order; -DROP TABLE IF EXISTS tbl_category; -DROP TABLE IF EXISTS tbl_customer; -DROP TABLE IF EXISTS tbl_type; -DROP TABLE IF EXISTS tbl_null_values; - -CREATE TABLE tbl_customer ( - id INTEGER NOT NULL, - email varchar(128) NOT NULL, - name varchar(128), - address text, - status INTEGER DEFAULT 0, - PRIMARY KEY (id) -); - -CREATE TABLE tbl_category ( - id INTEGER NOT NULL, - name varchar(128) NOT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE tbl_item ( - id INTEGER NOT NULL, - name varchar(128) NOT NULL, - category_id INTEGER NOT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE tbl_order ( - id INTEGER NOT NULL, - customer_id INTEGER NOT NULL, - create_time INTEGER NOT NULL, - total decimal(10,0) NOT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE tbl_order_item ( - order_id INTEGER NOT NULL, - item_id INTEGER NOT NULL, - quantity INTEGER NOT NULL, - subtotal decimal(10,0) NOT NULL, - PRIMARY KEY (order_id, item_id) -); - -CREATE TABLE `tbl_composite_fk` ( - `id` int(11) NOT NULL, - `order_id` int(11) NOT NULL, - `item_id` int(11) NOT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `FK_composite_fk_order_item` FOREIGN KEY (`order_id`,`item_id`) REFERENCES `tbl_order_item` (`order_id`,`item_id`) ON DELETE CASCADE -); - -CREATE TABLE tbl_null_values ( - id INTEGER UNSIGNED PRIMARY KEY NOT NULL, - var1 INTEGER UNSIGNED, - var2 INTEGER, - var3 INTEGER DEFAULT NULL, - stringcol VARCHAR(32) DEFAULT NULL -); - -CREATE TABLE tbl_type ( - int_col INTEGER NOT NULL, - int_col2 INTEGER DEFAULT '1', - char_col char(100) NOT NULL, - char_col2 varchar(100) DEFAULT 'something', - char_col3 text, - float_col double(4,3) NOT NULL, - float_col2 double DEFAULT '1.23', - blob_col blob, - numeric_col decimal(5,2) DEFAULT '33.22', - time timestamp NOT NULL DEFAULT '2002-01-01 00:00:00', - bool_col tinyint(1) NOT NULL, - bool_col2 tinyint(1) DEFAULT '1' -); - -INSERT INTO tbl_customer (email, name, address, status) VALUES ('user1@example.com', 'user1', 'address1', 1); -INSERT INTO tbl_customer (email, name, address, status) VALUES ('user2@example.com', 'user2', 'address2', 1); -INSERT INTO tbl_customer (email, name, address, status) VALUES ('user3@example.com', 'user3', 'address3', 2); - -INSERT INTO tbl_category (name) VALUES ('Books'); -INSERT INTO tbl_category (name) VALUES ('Movies'); - -INSERT INTO tbl_item (name, category_id) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); -INSERT INTO tbl_item (name, category_id) VALUES ('Yii 1.1 Application Development Cookbook', 1); -INSERT INTO tbl_item (name, category_id) VALUES ('Ice Age', 2); -INSERT INTO tbl_item (name, category_id) VALUES ('Toy Story', 2); -INSERT INTO tbl_item (name, category_id) VALUES ('Cars', 2); - -INSERT INTO tbl_order (customer_id, create_time, total) VALUES (1, 1325282384, 110.0); -INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325334482, 33.0); -INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325502201, 40.0); - -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); - -/** - * (SqLite-)Database Schema for validator tests - */ - -DROP TABLE IF EXISTS tbl_validator_main; -DROP TABLE IF EXISTS tbl_validator_ref; - -CREATE TABLE tbl_validator_main ( - id INTEGER PRIMARY KEY , - field1 VARCHAR(255) -); - -CREATE TABLE tbl_validator_ref ( - id INTEGER PRIMARY KEY , - a_field VARCHAR(255), - ref INT(11) -); - -INSERT INTO tbl_validator_main (id, field1) VALUES (1, 'just a string1'); -INSERT INTO tbl_validator_main (id, field1) VALUES (2, 'just a string2'); -INSERT INTO tbl_validator_main (id, field1) VALUES (3, 'just a string3'); -INSERT INTO tbl_validator_main (id, field1) VALUES (4, 'just a string4'); -INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (1, 'ref_to_2', 2); -INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (2, 'ref_to_2', 2); -INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (3, 'ref_to_3', 3); -INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (4, 'ref_to_4', 4); -INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (5, 'ref_to_4', 4); -INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (6, 'ref_to_5', 5); diff --git a/tests/unit/data/travis/README.md b/tests/unit/data/travis/README.md deleted file mode 100644 index ad9538d..0000000 --- a/tests/unit/data/travis/README.md +++ /dev/null @@ -1,14 +0,0 @@ -This directory contains scripts for automated test runs via the [Travis CI](http://travis-ci.org) build service. They are used for the preparation of worker instances by setting up needed extensions and configuring database access. - -These scripts might be used to configure your own system for test runs. But since their primary purpose remains to support Travis in running the test cases, you would be best advised to stick to the setup notes in the tests themselves. - -The scripts are: - - - [`apc-setup.sh`](apc-setup.sh) - Installs and configures the [apc pecl extension](http://pecl.php.net/package/apc) - - [`memcache-setup.sh`](memcache-setup.sh) - Compiles and installs the [memcache pecl extension](http://pecl.php.net/package/memcache) - - [`cubrid-setup.sh`](cubrid-setup.sh) - Prepares the [CUBRID](http://www.cubrid.org/) server instance by installing the server and PHP PDO driver - - [`sphinx-setup.sh`](sphinx-setup.sh) - Prepares the [Sphinx](http://sphinxsearch.com/) server instances by installing the server and attaching it to MySQL \ No newline at end of file diff --git a/tests/unit/data/travis/apc-setup.sh b/tests/unit/data/travis/apc-setup.sh deleted file mode 100755 index 3925267..0000000 --- a/tests/unit/data/travis/apc-setup.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -if [ "$(expr "$TRAVIS_PHP_VERSION" "<" "5.5")" -eq 1 ]; then - echo "extension = apc.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - echo "apc.enable_cli = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini -else - echo "Not installing APC as it is not available in PHP 5.5 anymore." -fi \ No newline at end of file diff --git a/tests/unit/data/travis/cubrid-setup.sh b/tests/unit/data/travis/cubrid-setup.sh deleted file mode 100755 index 9c3bb74..0000000 --- a/tests/unit/data/travis/cubrid-setup.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -# -# install CUBRID DBMS - -# cubrid dbms -echo 'yes' | sudo add-apt-repository ppa:cubrid/cubrid -sudo apt-get update -sudo apt-get install cubrid -/etc/profile.d/cubrid.sh -sudo apt-get install cubrid-demodb - -# cubrid pdo -install_pdo_cubrid() { - wget "http://pecl.php.net/get/PDO_CUBRID-9.2.0.0001.tgz" && - tar -zxf "PDO_CUBRID-9.2.0.0001.tgz" && - sh -c "cd PDO_CUBRID-9.2.0.0001 && phpize && ./configure && make && sudo make install" - - echo "extension=pdo_cubrid.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - - return $? -} - -install_pdo_cubrid > ~/pdo_cubrid.log || ( echo "=== PDO CUBRID BUILD FAILED ==="; cat ~/pdo_cubrid.log ) - -echo "Installed CUBRID `dpkg -s cubrid |grep Version`" diff --git a/tests/unit/data/travis/cubrid-solo.rb b/tests/unit/data/travis/cubrid-solo.rb deleted file mode 100644 index f5f0004..0000000 --- a/tests/unit/data/travis/cubrid-solo.rb +++ /dev/null @@ -1,5 +0,0 @@ -file_cache_path "/tmp/chef-solo" -data_bag_path "/tmp/chef-solo/data_bags" -encrypted_data_bag_secret "/tmp/chef-solo/data_bag_key" -cookbook_path [ "/tmp/chef-solo/cookbooks" ] -role_path "/tmp/chef-solo/roles" \ No newline at end of file diff --git a/tests/unit/data/travis/memcache-setup.sh b/tests/unit/data/travis/memcache-setup.sh deleted file mode 100755 index 6b623d6..0000000 --- a/tests/unit/data/travis/memcache-setup.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -echo "extension=memcache.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini -echo "extension=memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini diff --git a/tests/unit/data/travis/mongodb-setup.sh b/tests/unit/data/travis/mongodb-setup.sh deleted file mode 100755 index b79a897..0000000 --- a/tests/unit/data/travis/mongodb-setup.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# -# install mongodb - -echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini -sudo sh -c 'echo "setParameter = textSearchEnabled=true" >> /etc/mongodb.conf' -cat /etc/mongodb.conf - -mongod --version - -sudo service mongodb restart diff --git a/tests/unit/data/travis/sphinx-setup.sh b/tests/unit/data/travis/sphinx-setup.sh deleted file mode 100755 index c07bd04..0000000 --- a/tests/unit/data/travis/sphinx-setup.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -SCRIPT=$(readlink -f "$0") -CWD=$(dirname "$SCRIPT") - -# install sphinxsearch: -echo 'yes' | sudo add-apt-repository ppa:builds/sphinxsearch-daily -sudo apt-get update -sudo apt-get install sphinxsearch - -# log files -sudo mkdir /var/log/sphinx -sudo touch /var/log/sphinx/searchd.log -sudo touch /var/log/sphinx/query.log -sudo chmod -R 777 /var/log/sphinx # ugly (for travis) - -# spl dir -sudo mkdir /var/lib/sphinx -sudo chmod 777 /var/lib/sphinx # ugly (for travis) - -# run dir pid -sudo mkdir /var/run/sphinx -sudo chmod 777 /var/run/sphinx # ugly (for travis) - -# Setup source database -mysql -D yiitest -u travis < $CWD/../sphinx/source.sql - -# setup test Sphinx indexes: -indexer --config $CWD/../sphinx/sphinx.conf --all - -# run searchd: -searchd --config $CWD/../sphinx/sphinx.conf diff --git a/tests/unit/data/validators/TestValidator.php b/tests/unit/data/validators/TestValidator.php deleted file mode 100644 index de6fb07..0000000 --- a/tests/unit/data/validators/TestValidator.php +++ /dev/null @@ -1,44 +0,0 @@ -markAttributeValidated($attribute); - if ($this->_setErrorOnValidateAttribute == true) { - $this->addError($object, $attribute, sprintf('%s##%s', $attribute, get_class($object))); - } - } - - protected function markAttributeValidated($attr, $increaseBy = 1) - { - if (!isset($this->_validatedAttributes[$attr])) { - $this->_validatedAttributes[$attr] = 1; - } else { - $this->_validatedAttributes[$attr] = $this->_validatedAttributes[$attr] + $increaseBy; - } - } - - public function countAttributeValidations($attr) - { - return isset($this->_validatedAttributes[$attr]) ? $this->_validatedAttributes[$attr] : 0; - } - - public function isAttributeValidated($attr) - { - return isset($this->_validatedAttributes[$attr]); - } - - public function enableErrorOnValidateAttribute() - { - $this->_setErrorOnValidateAttribute = true; - } -} \ No newline at end of file diff --git a/tests/unit/data/validators/models/FakedValidationModel.php b/tests/unit/data/validators/models/FakedValidationModel.php deleted file mode 100644 index e4de44b..0000000 --- a/tests/unit/data/validators/models/FakedValidationModel.php +++ /dev/null @@ -1,63 +0,0 @@ - $value) { - $m->$attribute = $value; - } - return $m; - } - - public function rules() - { - return [ - [['val_attr_a', 'val_attr_b'], 'required', 'on' => 'reqTest'], - ['val_attr_c', 'integer'], - ]; - } - - public function inlineVal($attribute, $params = []) - { - return true; - } - - public function __get($name) - { - if (stripos($name, 'attr') === 0) { - return isset($this->attr[$name]) ? $this->attr[$name] : null; - } - - return parent::__get($name); - } - - public function __set($name, $value) - { - if (stripos($name, 'attr') === 0) { - $this->attr[$name] = $value; - } else { - parent::__set($name, $value); - } - } - - public function getAttributeLabel($attr) - { - return $attr; - } -} diff --git a/tests/unit/data/validators/models/ValidatorTestMainModel.php b/tests/unit/data/validators/models/ValidatorTestMainModel.php deleted file mode 100644 index dd6696d..0000000 --- a/tests/unit/data/validators/models/ValidatorTestMainModel.php +++ /dev/null @@ -1,21 +0,0 @@ -hasMany(ValidatorTestRefModel::className(), ['ref' => 'id']); - } -} \ No newline at end of file diff --git a/tests/unit/data/validators/models/ValidatorTestRefModel.php b/tests/unit/data/validators/models/ValidatorTestRefModel.php deleted file mode 100644 index ea86fc7..0000000 --- a/tests/unit/data/validators/models/ValidatorTestRefModel.php +++ /dev/null @@ -1,23 +0,0 @@ -hasOne(ValidatorTestMainModel::className(), ['id' => 'ref']); - } -} \ No newline at end of file diff --git a/tests/unit/data/views/layout.php b/tests/unit/data/views/layout.php deleted file mode 100644 index 97a0888..0000000 --- a/tests/unit/data/views/layout.php +++ /dev/null @@ -1,22 +0,0 @@ - -beginPage(); ?> - - - - Test - head(); ?> - - -beginBody(); ?> - - - -endBody(); ?> - - -endPage(); ?> diff --git a/tests/unit/data/views/rawlayout.php b/tests/unit/data/views/rawlayout.php deleted file mode 100644 index aaa489f..0000000 --- a/tests/unit/data/views/rawlayout.php +++ /dev/null @@ -1,5 +0,0 @@ -beginPage(); ?>1head(); ?>2beginBody(); ?>3endBody(); ?>4endPage(); ?> diff --git a/tests/unit/data/views/simple.php b/tests/unit/data/views/simple.php deleted file mode 100644 index 437ba90..0000000 --- a/tests/unit/data/views/simple.php +++ /dev/null @@ -1 +0,0 @@ -This is a damn simple view file. \ No newline at end of file diff --git a/tests/unit/data/web/assets/.gitignore b/tests/unit/data/web/assets/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/tests/unit/data/web/assets/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/tests/unit/data/web/data.txt b/tests/unit/data/web/data.txt deleted file mode 100644 index 8e58281..0000000 --- a/tests/unit/data/web/data.txt +++ /dev/null @@ -1 +0,0 @@ -12ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=? \ No newline at end of file diff --git a/tests/unit/extensions/authclient/AuthActionTest.php b/tests/unit/extensions/authclient/AuthActionTest.php deleted file mode 100644 index 955f643..0000000 --- a/tests/unit/extensions/authclient/AuthActionTest.php +++ /dev/null @@ -1,68 +0,0 @@ - [ - 'user' => [ - 'identityClass' => '\yii\web\IdentityInterface' - ], - 'request' => [ - 'hostInfo' => 'http://testdomain.com', - 'scriptUrl' => '/index.php', - ], - ] - ]; - $this->mockApplication($config, '\yii\web\Application'); - } - - public function testSetGet() - { - $action = new AuthAction(null, null); - - $successUrl = 'http://test.success.url'; - $action->setSuccessUrl($successUrl); - $this->assertEquals($successUrl, $action->getSuccessUrl(), 'Unable to setup success URL!'); - - $cancelUrl = 'http://test.cancel.url'; - $action->setCancelUrl($cancelUrl); - $this->assertEquals($cancelUrl, $action->getCancelUrl(), 'Unable to setup cancel URL!'); - } - - /** - * @depends testSetGet - */ - public function testGetDefaultSuccessUrl() - { - $action = new AuthAction(null, null); - - $this->assertNotEmpty($action->getSuccessUrl(), 'Unable to get default success URL!'); - } - - /** - * @depends testSetGet - */ - public function testGetDefaultCancelUrl() - { - $action = new AuthAction(null, null); - - $this->assertNotEmpty($action->getSuccessUrl(), 'Unable to get default cancel URL!'); - } - - public function testRedirect() - { - $action = new AuthAction(null, null); - - $url = 'http://test.url'; - $response = $action->redirect($url, true); - - $this->assertContains($url, $response->content); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/authclient/BaseClientTest.php b/tests/unit/extensions/authclient/BaseClientTest.php deleted file mode 100644 index 462d5c2..0000000 --- a/tests/unit/extensions/authclient/BaseClientTest.php +++ /dev/null @@ -1,82 +0,0 @@ -setId($id); - $this->assertEquals($id, $client->getId(), 'Unable to setup id!'); - - $name = 'test_name'; - $client->setName($name); - $this->assertEquals($name, $client->getName(), 'Unable to setup name!'); - - $title = 'test_title'; - $client->setTitle($title); - $this->assertEquals($title, $client->getTitle(), 'Unable to setup title!'); - - $userAttributes = [ - 'attribute1' => 'value1', - 'attribute2' => 'value2', - ]; - $client->setUserAttributes($userAttributes); - $this->assertEquals($userAttributes, $client->getUserAttributes(), 'Unable to setup user attributes!'); - - $normalizeUserAttributeMap = [ - 'name' => 'some/name', - 'email' => 'some/email', - ]; - $client->setNormalizeUserAttributeMap($normalizeUserAttributeMap); - $this->assertEquals($normalizeUserAttributeMap, $client->getNormalizeUserAttributeMap(), 'Unable to setup normalize user attribute map!'); - - $viewOptions = [ - 'option1' => 'value1', - 'option2' => 'value2', - ]; - $client->setViewOptions($viewOptions); - $this->assertEquals($viewOptions, $client->getViewOptions(), 'Unable to setup view options!'); - } - - public function testGetDefaults() - { - $client = new Client(); - - $this->assertNotEmpty($client->getName(), 'Unable to get default name!'); - $this->assertNotEmpty($client->getTitle(), 'Unable to get default title!'); - $this->assertNotNull($client->getViewOptions(), 'Unable to get default view options!'); - $this->assertNotNull($client->getNormalizeUserAttributeMap(), 'Unable to get default normalize user attribute map!'); - } - - /** - * @depends testSetGet - */ - public function testNormalizeUserAttributes() - { - $client = new Client(); - - $normalizeUserAttributeMap = [ - 'raw/name' => 'name', - 'raw/email' => 'email', - ]; - $client->setNormalizeUserAttributeMap($normalizeUserAttributeMap); - $rawUserAttributes = [ - 'raw/name' => 'name value', - 'raw/email' => 'email value', - ]; - $client->setUserAttributes($rawUserAttributes); - $normalizedUserAttributes = $client->getUserAttributes(); - $expectedNormalizedUserAttributes = array_combine(array_keys($normalizeUserAttributeMap), array_values($rawUserAttributes)); - $this->assertEquals($expectedNormalizedUserAttributes, $normalizedUserAttributes); - } -} - -class Client extends BaseClient -{ -} \ No newline at end of file diff --git a/tests/unit/extensions/authclient/BaseOAuthTest.php b/tests/unit/extensions/authclient/BaseOAuthTest.php deleted file mode 100644 index 00893b5..0000000 --- a/tests/unit/extensions/authclient/BaseOAuthTest.php +++ /dev/null @@ -1,251 +0,0 @@ -getMock(BaseOAuth::className(), ['setState', 'getState', 'composeRequestCurlOptions', 'refreshAccessToken', 'apiInternal']); - $oauthClient->expects($this->any())->method('setState')->will($this->returnValue($oauthClient)); - $oauthClient->expects($this->any())->method('getState')->will($this->returnValue(null)); - return $oauthClient; - } - - /** - * Invokes the OAuth client method even if it is protected. - * @param BaseOAuth $oauthClient OAuth client instance. - * @param string $methodName name of the method to be invoked. - * @param array $arguments method arguments. - * @return mixed method invoke result. - */ - protected function invokeOAuthClientMethod($oauthClient, $methodName, array $arguments = []) - { - $classReflection = new \ReflectionClass(get_class($oauthClient)); - $methodReflection = $classReflection->getMethod($methodName); - $methodReflection->setAccessible(true); - $result = $methodReflection->invokeArgs($oauthClient, $arguments); - $methodReflection->setAccessible(false); - return $result; - } - - // Tests : - - public function testSetGet() - { - $oauthClient = $this->createOAuthClient(); - - $returnUrl = 'http://test.return.url'; - $oauthClient->setReturnUrl($returnUrl); - $this->assertEquals($returnUrl, $oauthClient->getReturnUrl(), 'Unable to setup return URL!'); - - $curlOptions = [ - 'option1' => 'value1', - 'option2' => 'value2', - ]; - $oauthClient->setCurlOptions($curlOptions); - $this->assertEquals($curlOptions, $oauthClient->getCurlOptions(), 'Unable to setup cURL options!'); - } - - public function testSetupComponents() - { - $oauthClient = $this->createOAuthClient(); - - $oauthToken = new OAuthToken(); - $oauthClient->setAccessToken($oauthToken); - $this->assertEquals($oauthToken, $oauthClient->getAccessToken(), 'Unable to setup token!'); - - $oauthSignatureMethod = new PlainText(); - $oauthClient->setSignatureMethod($oauthSignatureMethod); - $this->assertEquals($oauthSignatureMethod, $oauthClient->getSignatureMethod(), 'Unable to setup signature method!'); - } - - /** - * @depends testSetupComponents - */ - public function testSetupComponentsByConfig() - { - $oauthClient = $this->createOAuthClient(); - - $oauthToken = [ - 'token' => 'test_token', - 'tokenSecret' => 'test_token_secret', - ]; - $oauthClient->setAccessToken($oauthToken); - $this->assertEquals($oauthToken['token'], $oauthClient->getAccessToken()->getToken(), 'Unable to setup token as config!'); - - $oauthSignatureMethod = [ - 'class' => 'yii\authclient\signature\PlainText' - ]; - $oauthClient->setSignatureMethod($oauthSignatureMethod); - $returnedSignatureMethod = $oauthClient->getSignatureMethod(); - $this->assertEquals($oauthSignatureMethod['class'], get_class($returnedSignatureMethod), 'Unable to setup signature method as config!'); - } - - /** - * Data provider for [[testComposeUrl()]]. - * @return array test data. - */ - public function composeUrlDataProvider() - { - return [ - [ - 'http://test.url', - [ - 'param1' => 'value1', - 'param2' => 'value2', - ], - 'http://test.url?param1=value1¶m2=value2', - ], - [ - 'http://test.url?with=some', - [ - 'param1' => 'value1', - 'param2' => 'value2', - ], - 'http://test.url?with=some¶m1=value1¶m2=value2', - ], - ]; - } - - /** - * @dataProvider composeUrlDataProvider - * - * @param string $url request URL. - * @param array $params request params - * @param string $expectedUrl expected composed URL. - */ - public function testComposeUrl($url, array $params, $expectedUrl) - { - $oauthClient = $this->createOAuthClient(); - $composedUrl = $this->invokeOAuthClientMethod($oauthClient, 'composeUrl', [$url, $params]); - $this->assertEquals($expectedUrl, $composedUrl); - } - - /** - * Data provider for {@link testDetermineContentTypeByHeaders}. - * @return array test data. - */ - public function determineContentTypeByHeadersDataProvider() - { - return [ - [ - ['content_type' => 'application/json'], - 'json' - ], - [ - ['content_type' => 'application/x-www-form-urlencoded'], - 'urlencoded' - ], - [ - ['content_type' => 'application/xml'], - 'xml' - ], - [ - ['some_header' => 'some_header_value'], - 'auto' - ], - [ - ['content_type' => 'unknown'], - 'auto' - ], - ]; - } - - /** - * @dataProvider determineContentTypeByHeadersDataProvider - * - * @param array $headers request headers. - * @param string $expectedResponseType expected response type. - */ - public function testDetermineContentTypeByHeaders(array $headers, $expectedResponseType) - { - $oauthClient = $this->createOAuthClient(); - $responseType = $this->invokeOAuthClientMethod($oauthClient, 'determineContentTypeByHeaders', [$headers]); - $this->assertEquals($expectedResponseType, $responseType); - } - - /** - * Data provider for [[testDetermineContentTypeByRaw]]. - * @return array test data. - */ - public function determineContentTypeByRawDataProvider() - { - return array( - ['{name: value}', 'json'], - ['name=value', 'urlencoded'], - ['name1=value1&name2=value2', 'urlencoded'], - ['Value', 'xml'], - ['Value', 'xml'], - ); - } - - /** - * @dataProvider determineContentTypeByRawDataProvider - * - * @param string $rawResponse raw response content. - * @param string $expectedResponseType expected response type. - */ - public function testDetermineContentTypeByRaw($rawResponse, $expectedResponseType) - { - $oauthClient = $this->createOAuthClient(); - $responseType = $this->invokeOAuthClientMethod($oauthClient, 'determineContentTypeByRaw', [$rawResponse]); - $this->assertEquals($expectedResponseType, $responseType); - } - - /** - * Data provider for [[testApiUrl]]. - * @return array test data. - */ - public function apiUrlDataProvider() - { - return [ - [ - 'http://api.base.url', - 'sub/url', - 'http://api.base.url/sub/url', - ], - [ - 'http://api.base.url', - 'http://api.base.url/sub/url', - 'http://api.base.url/sub/url', - ], - [ - 'http://api.base.url', - 'https://api.base.url/sub/url', - 'https://api.base.url/sub/url', - ], - ]; - } - - /** - * @dataProvider apiUrlDataProvider - * - * @param $apiBaseUrl - * @param $apiSubUrl - * @param $expectedApiFullUrl - */ - public function testApiUrl($apiBaseUrl, $apiSubUrl, $expectedApiFullUrl) - { - $oauthClient = $this->createOAuthClient(); - $oauthClient->expects($this->any())->method('apiInternal')->will($this->returnArgument(1)); - - $accessToken = new OAuthToken(); - $accessToken->setToken('test_access_token'); - $accessToken->setExpireDuration(1000); - $oauthClient->setAccessToken($accessToken); - - $oauthClient->apiBaseUrl = $apiBaseUrl; - - $this->assertEquals($expectedApiFullUrl, $oauthClient->api($apiSubUrl)); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/authclient/CollectionTest.php b/tests/unit/extensions/authclient/CollectionTest.php deleted file mode 100644 index 3e0f5d0..0000000 --- a/tests/unit/extensions/authclient/CollectionTest.php +++ /dev/null @@ -1,85 +0,0 @@ - new TestClient(), - 'testClient2' => new TestClient(), - ]; - $collection->setClients($clients); - $this->assertEquals($clients, $collection->getClients(), 'Unable to setup clients!'); - } - - /** - * @depends testSetGet - */ - public function testGetProviderById() - { - $collection = new Collection(); - - $clientId = 'testClientId'; - $client = new TestClient(); - $clients = [ - $clientId => $client - ]; - $collection->setClients($clients); - - $this->assertEquals($client, $collection->getClient($clientId), 'Unable to get client by id!'); - } - - /** - * @depends testGetProviderById - */ - public function testCreateProvider() - { - $collection = new Collection(); - - $clientId = 'testClientId'; - $clientClassName = TestClient::className(); - $clients = [ - $clientId => [ - 'class' => $clientClassName - ] - ]; - $collection->setClients($clients); - - $provider = $collection->getClient($clientId); - $this->assertTrue(is_object($provider), 'Unable to create client by config!'); - $this->assertTrue(is_a($provider, $clientClassName), 'Client has wrong class name!'); - } - - /** - * @depends testSetGet - */ - public function testHasProvider() - { - $collection = new Collection(); - - $clientName = 'testClientName'; - $clients = [ - $clientName => [ - 'class' => 'TestClient1' - ], - ]; - $collection->setClients($clients); - - $this->assertTrue($collection->hasClient($clientName), 'Existing client check fails!'); - $this->assertFalse($collection->hasClient('unExistingClientName'), 'Not existing client check fails!'); - } -} - -class TestClient extends BaseClient -{ -} \ No newline at end of file diff --git a/tests/unit/extensions/authclient/OAuth1Test.php b/tests/unit/extensions/authclient/OAuth1Test.php deleted file mode 100644 index e5fe8fe..0000000 --- a/tests/unit/extensions/authclient/OAuth1Test.php +++ /dev/null @@ -1,109 +0,0 @@ -mockApplication([], '\yii\web\Application'); - } - - /** - * Invokes the OAuth client method even if it is protected. - * @param OAuth1 $oauthClient OAuth client instance. - * @param string $methodName name of the method to be invoked. - * @param array $arguments method arguments. - * @return mixed method invoke result. - */ - protected function invokeOAuthClientMethod($oauthClient, $methodName, array $arguments = []) - { - $classReflection = new \ReflectionClass(get_class($oauthClient)); - $methodReflection = $classReflection->getMethod($methodName); - $methodReflection->setAccessible(true); - $result = $methodReflection->invokeArgs($oauthClient, $arguments); - $methodReflection->setAccessible(false); - return $result; - } - - // Tests : - - public function testSignRequest() - { - $oauthClient = new OAuth1(); - - $oauthSignatureMethod = new PlainText(); - $oauthClient->setSignatureMethod($oauthSignatureMethod); - - $signedParams = $this->invokeOAuthClientMethod($oauthClient, 'signRequest', ['GET', 'http://test.url', []]); - $this->assertNotEmpty($signedParams['oauth_signature'], 'Unable to sign request!'); - } - - /** - * Data provider for [[testComposeAuthorizationHeader()]]. - * @return array test data. - */ - public function composeAuthorizationHeaderDataProvider() - { - return [ - [ - '', - [ - 'oauth_test_name_1' => 'oauth_test_value_1', - 'oauth_test_name_2' => 'oauth_test_value_2', - ], - 'Authorization: OAuth oauth_test_name_1="oauth_test_value_1", oauth_test_name_2="oauth_test_value_2"' - ], - [ - 'test_realm', - [ - 'oauth_test_name_1' => 'oauth_test_value_1', - 'oauth_test_name_2' => 'oauth_test_value_2', - ], - 'Authorization: OAuth realm="test_realm", oauth_test_name_1="oauth_test_value_1", oauth_test_name_2="oauth_test_value_2"' - ], - [ - '', - [ - 'oauth_test_name_1' => 'oauth_test_value_1', - 'test_name_2' => 'test_value_2', - ], - 'Authorization: OAuth oauth_test_name_1="oauth_test_value_1"' - ], - ]; - } - - /** - * @dataProvider composeAuthorizationHeaderDataProvider - * - * @param string $realm authorization realm. - * @param array $params request params. - * @param string $expectedAuthorizationHeader expected authorization header. - */ - public function testComposeAuthorizationHeader($realm, array $params, $expectedAuthorizationHeader) - { - $oauthClient = new OAuth1(); - $authorizationHeader = $this->invokeOAuthClientMethod($oauthClient, 'composeAuthorizationHeader', [$params, $realm]); - $this->assertEquals($expectedAuthorizationHeader, $authorizationHeader); - } - - public function testBuildAuthUrl() { - $oauthClient = new OAuth1(); - $authUrl = 'http://test.auth.url'; - $oauthClient->authUrl = $authUrl; - - $requestTokenToken = 'test_request_token'; - $requestToken = new OAuthToken(); - $requestToken->setToken($requestTokenToken); - - $builtAuthUrl = $oauthClient->buildAuthUrl($requestToken); - - $this->assertContains($authUrl, $builtAuthUrl, 'No auth URL present!'); - $this->assertContains($requestTokenToken, $builtAuthUrl, 'No token present!'); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/authclient/OAuth2Test.php b/tests/unit/extensions/authclient/OAuth2Test.php deleted file mode 100644 index 69721cd..0000000 --- a/tests/unit/extensions/authclient/OAuth2Test.php +++ /dev/null @@ -1,33 +0,0 @@ -mockApplication([], '\yii\web\Application'); - } - - // Tests : - - public function testBuildAuthUrl() - { - $oauthClient = new OAuth2(); - $authUrl = 'http://test.auth.url'; - $oauthClient->authUrl = $authUrl; - $clientId = 'test_client_id'; - $oauthClient->clientId = $clientId; - $returnUrl = 'http://test.return.url'; - $oauthClient->setReturnUrl($returnUrl); - - $builtAuthUrl = $oauthClient->buildAuthUrl(); - - $this->assertContains($authUrl, $builtAuthUrl, 'No auth URL present!'); - $this->assertContains($clientId, $builtAuthUrl, 'No client id present!'); - $this->assertContains(rawurlencode($returnUrl), $builtAuthUrl, 'No return URL present!'); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/authclient/OpenIdTest.php b/tests/unit/extensions/authclient/OpenIdTest.php deleted file mode 100644 index 57dd899..0000000 --- a/tests/unit/extensions/authclient/OpenIdTest.php +++ /dev/null @@ -1,61 +0,0 @@ - [ - 'request' => [ - 'hostInfo' => 'http://testdomain.com', - 'scriptUrl' => '/index.php', - ], - ] - ]; - $this->mockApplication($config, '\yii\web\Application'); - } - - // Tests : - - public function testSetGet() - { - $client = new OpenId(); - - $trustRoot = 'http://trust.root'; - $client->setTrustRoot($trustRoot); - $this->assertEquals($trustRoot, $client->getTrustRoot(), 'Unable to setup trust root!'); - - $returnUrl = 'http://return.url'; - $client->setReturnUrl($returnUrl); - $this->assertEquals($returnUrl, $client->getReturnUrl(), 'Unable to setup return URL!'); - } - - /** - * @depends testSetGet - */ - public function testGetDefaults() - { - $client = new OpenId(); - - $this->assertNotEmpty($client->getTrustRoot(), 'Unable to get default trust root!'); - $this->assertNotEmpty($client->getReturnUrl(), 'Unable to get default return URL!'); - } - - public function testDiscover() - { - $url = 'https://www.google.com/accounts/o8/id'; - $client = new OpenId(); - $info = $client->discover($url); - $this->assertNotEmpty($info); - $this->assertNotEmpty($info['url']); - $this->assertNotEmpty($info['identity']); - $this->assertEquals(2, $info['version']); - $this->assertArrayHasKey('identifier_select', $info); - $this->assertArrayHasKey('ax', $info); - $this->assertArrayHasKey('sreg', $info); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/authclient/TestCase.php b/tests/unit/extensions/authclient/TestCase.php deleted file mode 100644 index 3a033b4..0000000 --- a/tests/unit/extensions/authclient/TestCase.php +++ /dev/null @@ -1,30 +0,0 @@ - 'test_token_param_key', - 'tokenSecretParamKey' => 'test_token_secret_param_key', - ]; - $oauthToken = new OAuthToken($config); - $this->assertTrue(is_object($oauthToken), 'Unable to create access token!'); - foreach ($config as $name => $value) { - $this->assertEquals($value, $oauthToken->$name, 'Unable to setup attributes by constructor!'); - } - $this->assertTrue($oauthToken->createTimestamp > 0, 'Unable to fill create timestamp!'); - } - - public function testSetupParams() - { - $oauthToken = new OAuthToken(); - - $params = [ - 'name_1' => 'value_1', - 'name_2' => 'value_2', - ]; - $oauthToken->setParams($params); - $this->assertEquals($params, $oauthToken->getParams(), 'Unable to setup params!'); - - $newParamName = 'new_param_name'; - $newParamValue = 'new_param_value'; - $oauthToken->setParam($newParamName, $newParamValue); - $this->assertEquals($newParamValue, $oauthToken->getParam($newParamName), 'Unable to setup param by name!'); - } - - /** - * @depends testSetupParams - */ - public function testSetupParamsShortcuts() - { - $oauthToken = new OAuthToken(); - - $token = 'test_token_value'; - $oauthToken->setToken($token); - $this->assertEquals($token, $oauthToken->getToken(), 'Unable to setup token!'); - - $tokenSecret = 'test_token_secret'; - $oauthToken->setTokenSecret($tokenSecret); - $this->assertEquals($tokenSecret, $oauthToken->getTokenSecret(), 'Unable to setup token secret!'); - - $tokenExpireDuration = rand(1000, 2000); - $oauthToken->setExpireDuration($tokenExpireDuration); - $this->assertEquals($tokenExpireDuration, $oauthToken->getExpireDuration(), 'Unable to setup expire duration!'); - } - - /** - * Data provider for {@link testAutoFetchExpireDuration}. - * @return array test data. - */ - public function autoFetchExpireDurationDataProvider() - { - return [ - [ - ['expire_in' => 123345], - 123345 - ], - [ - ['expire' => 233456], - 233456 - ], - [ - ['expiry_in' => 34567], - 34567 - ], - [ - ['expiry' => 45678], - 45678 - ], - ]; - } - - /** - * @depends testSetupParamsShortcuts - * @dataProvider autoFetchExpireDurationDataProvider - * - * @param array $params - * @param $expectedExpireDuration - */ - public function testAutoFetchExpireDuration(array $params, $expectedExpireDuration) - { - $oauthToken = new OAuthToken(); - $oauthToken->setParams($params); - $this->assertEquals($expectedExpireDuration, $oauthToken->getExpireDuration()); - } - - /** - * @depends testSetupParamsShortcuts - */ - public function testGetIsExpired() - { - $oauthToken = new OAuthToken(); - $expireDuration = 3600; - $oauthToken->setExpireDuration($expireDuration); - - $this->assertFalse($oauthToken->getIsExpired(), 'Not expired token check fails!'); - - $oauthToken->createTimestamp = $oauthToken->createTimestamp - ($expireDuration +1); - $this->assertTrue($oauthToken->getIsExpired(), 'Expired token check fails!'); - } - - /** - * @depends testGetIsExpired - */ - public function testGetIsValid() - { - $oauthToken = new OAuthToken(); - $expireDuration = 3600; - $oauthToken->setExpireDuration($expireDuration); - - $this->assertFalse($oauthToken->getIsValid(), 'Empty token is valid!'); - - $oauthToken->setToken('test_token'); - $this->assertTrue($oauthToken->getIsValid(), 'Filled up token is invalid!'); - - $oauthToken->createTimestamp = $oauthToken->createTimestamp - ($expireDuration +1); - $this->assertFalse($oauthToken->getIsValid(), 'Expired token is valid!'); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/authclient/signature/BaseMethodTest.php b/tests/unit/extensions/authclient/signature/BaseMethodTest.php deleted file mode 100644 index bb91e66..0000000 --- a/tests/unit/extensions/authclient/signature/BaseMethodTest.php +++ /dev/null @@ -1,50 +0,0 @@ -getMock('\yii\authclient\signature\BaseMethod', ['getName', 'generateSignature']); - $signatureMethod->expects($this->any())->method('getName')->will($this->returnValue('testMethodName')); - $signatureMethod->expects($this->any())->method('generateSignature')->will($this->returnValue('testSignature')); - return $signatureMethod; - } - - // Tests : - - public function testGenerateSignature() - { - $signatureMethod = $this->createTestSignatureMethod(); - - $baseString = 'test_base_string'; - $key = 'test_key'; - - $signature = $signatureMethod->generateSignature($baseString, $key); - - $this->assertNotEmpty($signature, 'Unable to generate signature!'); - } - - /** - * @depends testGenerateSignature - */ - public function testVerify() - { - $signatureMethod = $this->createTestSignatureMethod(); - - $baseString = 'test_base_string'; - $key = 'test_key'; - $signature = 'unsigned'; - $this->assertFalse($signatureMethod->verify($signature, $baseString, $key), 'Unsigned signature is valid!'); - - $generatedSignature = $signatureMethod->generateSignature($baseString, $key); - $this->assertTrue($signatureMethod->verify($generatedSignature, $baseString, $key), 'Generated signature is invalid!'); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/authclient/signature/HmacSha1Test.php b/tests/unit/extensions/authclient/signature/HmacSha1Test.php deleted file mode 100644 index 6305e03..0000000 --- a/tests/unit/extensions/authclient/signature/HmacSha1Test.php +++ /dev/null @@ -1,20 +0,0 @@ -generateSignature($baseString, $key); - $this->assertNotEmpty($signature, 'Unable to generate signature!'); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/authclient/signature/PlainTextTest.php b/tests/unit/extensions/authclient/signature/PlainTextTest.php deleted file mode 100644 index c5199a5..0000000 --- a/tests/unit/extensions/authclient/signature/PlainTextTest.php +++ /dev/null @@ -1,20 +0,0 @@ -generateSignature($baseString, $key); - $this->assertNotEmpty($signature, 'Unable to generate signature!'); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/authclient/signature/RsaSha1Test.php b/tests/unit/extensions/authclient/signature/RsaSha1Test.php deleted file mode 100644 index 0848ade..0000000 --- a/tests/unit/extensions/authclient/signature/RsaSha1Test.php +++ /dev/null @@ -1,110 +0,0 @@ -setPrivateCertificate($this->getTestPrivateCertificate()); - $signatureMethod->setPublicCertificate($this->getTestPublicCertificate()); - - $baseString = 'test_base_string'; - $key = 'test_key'; - - $signature = $signatureMethod->generateSignature($baseString, $key); - $this->assertNotEmpty($signature, 'Unable to generate signature!'); - } - - /** - * @depends testGenerateSignature - */ - public function testVerify() - { - $signatureMethod = new RsaSha1(); - $signatureMethod->setPrivateCertificate($this->getTestPrivateCertificate()); - $signatureMethod->setPublicCertificate($this->getTestPublicCertificate()); - - $baseString = 'test_base_string'; - $key = 'test_key'; - $signature = 'unsigned'; - $this->assertFalse($signatureMethod->verify($signature, $baseString, $key), 'Unsigned signature is valid!'); - - $generatedSignature = $signatureMethod->generateSignature($baseString, $key); - $this->assertTrue($signatureMethod->verify($generatedSignature, $baseString, $key), 'Generated signature is invalid!'); - } - - public function testInitPrivateCertificate() - { - $signatureMethod = new RsaSha1(); - - $certificateFileName = __FILE__; - $signatureMethod->privateCertificateFile = $certificateFileName; - $this->assertEquals(file_get_contents($certificateFileName), $signatureMethod->getPrivateCertificate(), 'Unable to fetch private certificate from file!'); - } - - public function testInitPublicCertificate() - { - $signatureMethod = new RsaSha1(); - - $certificateFileName = __FILE__; - $signatureMethod->publicCertificateFile = $certificateFileName; - $this->assertEquals(file_get_contents($certificateFileName), $signatureMethod->getPublicCertificate(), 'Unable to fetch public certificate from file!'); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/elasticsearch/ActiveRecordTest.php b/tests/unit/extensions/elasticsearch/ActiveRecordTest.php deleted file mode 100644 index 8d3db69..0000000 --- a/tests/unit/extensions/elasticsearch/ActiveRecordTest.php +++ /dev/null @@ -1,499 +0,0 @@ -getConnection()->createCommand()->flushIndex('yiitest'); - } - - public function setUp() - { - parent::setUp(); - - /** @var Connection $db */ - $db = ActiveRecord::$db = $this->getConnection(); - - // delete index - if ($db->createCommand()->indexExists('yiitest')) { - $db->createCommand()->deleteIndex('yiitest'); - } - $db->createCommand()->createIndex('yiitest'); - - $command = $db->createCommand(); - Customer::setUpMapping($command); - Item::setUpMapping($command); - Order::setUpMapping($command); - OrderItem::setUpMapping($command); - - $db->createCommand()->flushIndex('yiitest'); - - $customer = new Customer(); - $customer->id = 1; - $customer->setAttributes(['email' => 'user1@example.com', 'name' => 'user1', 'address' => 'address1', 'status' => 1], false); - $customer->save(false); - $customer = new Customer(); - $customer->id = 2; - $customer->setAttributes(['email' => 'user2@example.com', 'name' => 'user2', 'address' => 'address2', 'status' => 1], false); - $customer->save(false); - $customer = new Customer(); - $customer->id = 3; - $customer->setAttributes(['email' => 'user3@example.com', 'name' => 'user3', 'address' => 'address3', 'status' => 2], false); - $customer->save(false); - -// INSERT INTO tbl_category (name) VALUES ('Books'); -// INSERT INTO tbl_category (name) VALUES ('Movies'); - - $item = new Item(); - $item->id = 1; - $item->setAttributes(['name' => 'Agile Web Application Development with Yii1.1 and PHP5', 'category_id' => 1], false); - $item->save(false); - $item = new Item(); - $item->id = 2; - $item->setAttributes(['name' => 'Yii 1.1 Application Development Cookbook', 'category_id' => 1], false); - $item->save(false); - $item = new Item(); - $item->id = 3; - $item->setAttributes(['name' => 'Ice Age', 'category_id' => 2], false); - $item->save(false); - $item = new Item(); - $item->id = 4; - $item->setAttributes(['name' => 'Toy Story', 'category_id' => 2], false); - $item->save(false); - $item = new Item(); - $item->id = 5; - $item->setAttributes(['name' => 'Cars', 'category_id' => 2], false); - $item->save(false); - - $order = new Order(); - $order->id = 1; - $order->setAttributes(['customer_id' => 1, 'create_time' => 1325282384, 'total' => 110.0], false); - $order->save(false); - $order = new Order(); - $order->id = 2; - $order->setAttributes(['customer_id' => 2, 'create_time' => 1325334482, 'total' => 33.0], false); - $order->save(false); - $order = new Order(); - $order->id = 3; - $order->setAttributes(['customer_id' => 2, 'create_time' => 1325502201, 'total' => 40.0], false); - $order->save(false); - - $orderItem = new OrderItem(); - $orderItem->setAttributes(['order_id' => 1, 'item_id' => 1, 'quantity' => 1, 'subtotal' => 30.0], false); - $orderItem->save(false); - $orderItem = new OrderItem(); - $orderItem->setAttributes(['order_id' => 1, 'item_id' => 2, 'quantity' => 2, 'subtotal' => 40.0], false); - $orderItem->save(false); - $orderItem = new OrderItem(); - $orderItem->setAttributes(['order_id' => 2, 'item_id' => 4, 'quantity' => 1, 'subtotal' => 10.0], false); - $orderItem->save(false); - $orderItem = new OrderItem(); - $orderItem->setAttributes(['order_id' => 2, 'item_id' => 5, 'quantity' => 1, 'subtotal' => 15.0], false); - $orderItem->save(false); - $orderItem = new OrderItem(); - $orderItem->setAttributes(['order_id' => 2, 'item_id' => 3, 'quantity' => 1, 'subtotal' => 8.0], false); - $orderItem->save(false); - $orderItem = new OrderItem(); - $orderItem->setAttributes(['order_id' => 3, 'item_id' => 2, 'quantity' => 1, 'subtotal' => 40.0], false); - $orderItem->save(false); - - $db->createCommand()->flushIndex('yiitest'); - } - - public function testFindAsArray() - { - // asArray - $customer = $this->callCustomerFind()->where(['id' => 2])->asArray()->one(); - $this->assertEquals([ - 'id' => 2, - 'email' => 'user2@example.com', - 'name' => 'user2', - 'address' => 'address2', - 'status' => 1, - '_score' => 1.0 - ], $customer); - } - - public function testSearch() - { - $customers = $this->callCustomerFind()->search()['hits']; - $this->assertEquals(3, $customers['total']); - $this->assertEquals(3, count($customers['hits'])); - $this->assertTrue($customers['hits'][0] instanceof Customer); - $this->assertTrue($customers['hits'][1] instanceof Customer); - $this->assertTrue($customers['hits'][2] instanceof Customer); - - // limit vs. totalcount - $customers = $this->callCustomerFind()->limit(2)->search()['hits']; - $this->assertEquals(3, $customers['total']); - $this->assertEquals(2, count($customers['hits'])); - - // asArray - $result = $this->callCustomerFind()->asArray()->search()['hits']; - $this->assertEquals(3, $result['total']); - $customers = $result['hits']; - $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers[0]); - $this->assertArrayHasKey('name', $customers[0]); - $this->assertArrayHasKey('email', $customers[0]); - $this->assertArrayHasKey('address', $customers[0]); - $this->assertArrayHasKey('status', $customers[0]); - $this->assertArrayHasKey('id', $customers[1]); - $this->assertArrayHasKey('name', $customers[1]); - $this->assertArrayHasKey('email', $customers[1]); - $this->assertArrayHasKey('address', $customers[1]); - $this->assertArrayHasKey('status', $customers[1]); - $this->assertArrayHasKey('id', $customers[2]); - $this->assertArrayHasKey('name', $customers[2]); - $this->assertArrayHasKey('email', $customers[2]); - $this->assertArrayHasKey('address', $customers[2]); - $this->assertArrayHasKey('status', $customers[2]); - - // TODO test asArray() + fields() + indexBy() - - // find by attributes - $result = $this->callCustomerFind()->where(['name' => 'user2'])->search()['hits']; - $customer = reset($result['hits']); - $this->assertTrue($customer instanceof Customer); - $this->assertEquals(2, $customer->id); - - // TODO test query() and filter() - } - - public function testSearchFacets() - { - $result = $this->callCustomerFind()->addStatisticalFacet('status_stats', ['field' => 'status'])->search(); - $this->assertArrayHasKey('facets', $result); - $this->assertEquals(3, $result['facets']['status_stats']['count']); - $this->assertEquals(4, $result['facets']['status_stats']['total']); // sum of values - $this->assertEquals(1, $result['facets']['status_stats']['min']); - $this->assertEquals(2, $result['facets']['status_stats']['max']); - } - - public function testGetDb() - { - $this->mockApplication(['components' => ['elasticsearch' => Connection::className()]]); - $this->assertInstanceOf(Connection::className(), ActiveRecord::getDb()); - } - - public function testGet() - { - $this->assertInstanceOf(Customer::className(), Customer::get(1)); - $this->assertNull(Customer::get(5)); - } - - public function testMget() - { - $this->assertEquals([], Customer::mget([])); - - $records = Customer::mget([1]); - $this->assertEquals(1, count($records)); - $this->assertInstanceOf(Customer::className(), reset($records)); - - $records = Customer::mget([5]); - $this->assertEquals(0, count($records)); - - $records = Customer::mget([1,3,5]); - $this->assertEquals(2, count($records)); - $this->assertInstanceOf(Customer::className(), $records[0]); - $this->assertInstanceOf(Customer::className(), $records[1]); - } - - public function testFindLazy() - { - /** @var $customer Customer */ - $customer = Customer::find(2); - $orders = $customer->orders; - $this->assertEquals(2, count($orders)); - - $orders = $customer->getOrders()->where(['between', 'create_time', 1325334000, 1325400000])->all(); - $this->assertEquals(1, count($orders)); - $this->assertEquals(2, $orders[0]->id); - } - - public function testFindEagerViaRelation() - { - $orders = Order::find()->with('items')->orderBy('create_time')->all(); - $this->assertEquals(3, count($orders)); - $order = $orders[0]; - $this->assertEquals(1, $order->id); - $this->assertTrue($order->isRelationPopulated('items')); - $this->assertEquals(2, count($order->items)); - $this->assertEquals(1, $order->items[0]->id); - $this->assertEquals(2, $order->items[1]->id); - } - - public function testInsertNoPk() - { - $this->assertEquals(['id'], Customer::primaryKey()); - $pkName = 'id'; - - $customer = new Customer; - $customer->email = 'user4@example.com'; - $customer->name = 'user4'; - $customer->address = 'address4'; - - $this->assertNull($customer->primaryKey); - $this->assertNull($customer->oldPrimaryKey); - $this->assertNull($customer->$pkName); - $this->assertTrue($customer->isNewRecord); - - $customer->save(); - $this->afterSave(); - - $this->assertNotNull($customer->primaryKey); - $this->assertNotNull($customer->oldPrimaryKey); - $this->assertNotNull($customer->$pkName); - $this->assertEquals($customer->primaryKey, $customer->oldPrimaryKey); - $this->assertEquals($customer->primaryKey, $customer->$pkName); - $this->assertFalse($customer->isNewRecord); - } - - public function testInsertPk() - { - $pkName = 'id'; - - $customer = new Customer; - $customer->$pkName = 5; - $customer->email = 'user5@example.com'; - $customer->name = 'user5'; - $customer->address = 'address5'; - - $this->assertTrue($customer->isNewRecord); - - $customer->save(); - - $this->assertEquals(5, $customer->primaryKey); - $this->assertEquals(5, $customer->oldPrimaryKey); - $this->assertEquals(5, $customer->$pkName); - $this->assertFalse($customer->isNewRecord); - } - - public function testUpdatePk() - { - $pkName = 'id'; - - $orderItem = Order::find([$pkName => 2]); - $this->assertEquals(2, $orderItem->primaryKey); - $this->assertEquals(2, $orderItem->oldPrimaryKey); - $this->assertEquals(2, $orderItem->$pkName); - -// $this->setExpectedException('yii\base\InvalidCallException'); - $orderItem->$pkName = 13; - $this->assertEquals(13, $orderItem->primaryKey); - $this->assertEquals(2, $orderItem->oldPrimaryKey); - $this->assertEquals(13, $orderItem->$pkName); - $orderItem->save(); - $this->afterSave(); - $this->assertEquals(13, $orderItem->primaryKey); - $this->assertEquals(13, $orderItem->oldPrimaryKey); - $this->assertEquals(13, $orderItem->$pkName); - - $this->assertNull(Order::find([$pkName => 2])); - $this->assertNotNull(Order::find([$pkName => 13])); - } - - public function testFindLazyVia2() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - /** @var Order $order */ - $orderClass = $this->getOrderClass(); - $pkName = 'id'; - - $order = new $orderClass(); - $order->$pkName = 100; - $this->assertEquals([], $order->items); - } - - /** - * Some PDO implementations(e.g. cubrid) do not support boolean values. - * Make sure this does not affect AR layer. - */ - public function testBooleanAttribute() - { - $db = $this->getConnection(); - Customer::setUpMapping($db->createCommand(), true); - Customer::deleteAll(); - - $customerClass = $this->getCustomerClass(); - $customer = new $customerClass(); - $customer->name = 'boolean customer'; - $customer->email = 'mail@example.com'; - $customer->status = true; - $customer->save(false); - - $customer->refresh(); - $this->assertEquals(true, $customer->status); - - $customer->status = false; - $customer->save(false); - - $customer->refresh(); - $this->assertEquals(false, $customer->status); - - $customer = new Customer(); - $customer->setAttributes(['email' => 'user2b@example.com', 'name' => 'user2b', 'status' => true], false); - $customer->save(false); - $customer = new Customer(); - $customer->setAttributes(['email' => 'user3b@example.com', 'name' => 'user3b', 'status' => false], false); - $customer->save(false); - $this->afterSave(); - - $customers = $this->callCustomerFind()->where(['status' => true])->all(); - $this->assertEquals(1, count($customers)); - - $customers = $this->callCustomerFind()->where(['status' => false])->all(); - $this->assertEquals(2, count($customers)); - } - - public function testfindAsArrayFields() - { - $customerClass = $this->getCustomerClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - // indexBy + asArray - $customers = $this->callCustomerFind()->asArray()->fields(['id', 'name'])->all(); - $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers[0]); - $this->assertArrayHasKey('name', $customers[0]); - $this->assertArrayNotHasKey('email', $customers[0]); - $this->assertArrayNotHasKey('address', $customers[0]); - $this->assertArrayNotHasKey('status', $customers[0]); - $this->assertArrayHasKey('id', $customers[1]); - $this->assertArrayHasKey('name', $customers[1]); - $this->assertArrayNotHasKey('email', $customers[1]); - $this->assertArrayNotHasKey('address', $customers[1]); - $this->assertArrayNotHasKey('status', $customers[1]); - $this->assertArrayHasKey('id', $customers[2]); - $this->assertArrayHasKey('name', $customers[2]); - $this->assertArrayNotHasKey('email', $customers[2]); - $this->assertArrayNotHasKey('address', $customers[2]); - $this->assertArrayNotHasKey('status', $customers[2]); - } - - public function testfindIndexByFields() - { - $customerClass = $this->getCustomerClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - // indexBy + asArray - $customers = $this->callCustomerFind()->indexBy('name')->fields('id', 'name')->all(); - $this->assertEquals(3, count($customers)); - $this->assertTrue($customers['user1'] instanceof $customerClass); - $this->assertTrue($customers['user2'] instanceof $customerClass); - $this->assertTrue($customers['user3'] instanceof $customerClass); - $this->assertNotNull($customers['user1']->id); - $this->assertNotNull($customers['user1']->name); - $this->assertNull($customers['user1']->email); - $this->assertNull($customers['user1']->address); - $this->assertNull($customers['user1']->status); - $this->assertNotNull($customers['user2']->id); - $this->assertNotNull($customers['user2']->name); - $this->assertNull($customers['user2']->email); - $this->assertNull($customers['user2']->address); - $this->assertNull($customers['user2']->status); - $this->assertNotNull($customers['user3']->id); - $this->assertNotNull($customers['user3']->name); - $this->assertNull($customers['user3']->email); - $this->assertNull($customers['user3']->address); - $this->assertNull($customers['user3']->status); - - // indexBy callable + asArray - $customers = $this->callCustomerFind()->indexBy(function ($customer) { - return $customer->id . '-' . $customer->name; - })->fields('id', 'name')->all(); - $this->assertEquals(3, count($customers)); - $this->assertTrue($customers['1-user1'] instanceof $customerClass); - $this->assertTrue($customers['2-user2'] instanceof $customerClass); - $this->assertTrue($customers['3-user3'] instanceof $customerClass); - $this->assertNotNull($customers['1-user1']->id); - $this->assertNotNull($customers['1-user1']->name); - $this->assertNull($customers['1-user1']->email); - $this->assertNull($customers['1-user1']->address); - $this->assertNull($customers['1-user1']->status); - $this->assertNotNull($customers['2-user2']->id); - $this->assertNotNull($customers['2-user2']->name); - $this->assertNull($customers['2-user2']->email); - $this->assertNull($customers['2-user2']->address); - $this->assertNull($customers['2-user2']->status); - $this->assertNotNull($customers['3-user3']->id); - $this->assertNotNull($customers['3-user3']->name); - $this->assertNull($customers['3-user3']->email); - $this->assertNull($customers['3-user3']->address); - $this->assertNull($customers['3-user3']->status); - } - - public function testfindIndexByAsArrayFields() - { - $customerClass = $this->getCustomerClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - // indexBy + asArray - $customers = $this->callCustomerFind()->indexBy('name')->asArray()->fields('id', 'name')->all(); - $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers['user1']); - $this->assertArrayHasKey('name', $customers['user1']); - $this->assertArrayNotHasKey('email', $customers['user1']); - $this->assertArrayNotHasKey('address', $customers['user1']); - $this->assertArrayNotHasKey('status', $customers['user1']); - $this->assertArrayHasKey('id', $customers['user2']); - $this->assertArrayHasKey('name', $customers['user2']); - $this->assertArrayNotHasKey('email', $customers['user2']); - $this->assertArrayNotHasKey('address', $customers['user2']); - $this->assertArrayNotHasKey('status', $customers['user2']); - $this->assertArrayHasKey('id', $customers['user3']); - $this->assertArrayHasKey('name', $customers['user3']); - $this->assertArrayNotHasKey('email', $customers['user3']); - $this->assertArrayNotHasKey('address', $customers['user3']); - $this->assertArrayNotHasKey('status', $customers['user3']); - - // indexBy callable + asArray - $customers = $this->callCustomerFind()->indexBy(function ($customer) { - return $customer['id'] . '-' . $customer['name']; - })->asArray()->fields('id', 'name')->all(); - $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers['1-user1']); - $this->assertArrayHasKey('name', $customers['1-user1']); - $this->assertArrayNotHasKey('email', $customers['1-user1']); - $this->assertArrayNotHasKey('address', $customers['1-user1']); - $this->assertArrayNotHasKey('status', $customers['1-user1']); - $this->assertArrayHasKey('id', $customers['2-user2']); - $this->assertArrayHasKey('name', $customers['2-user2']); - $this->assertArrayNotHasKey('email', $customers['2-user2']); - $this->assertArrayNotHasKey('address', $customers['2-user2']); - $this->assertArrayNotHasKey('status', $customers['2-user2']); - $this->assertArrayHasKey('id', $customers['3-user3']); - $this->assertArrayHasKey('name', $customers['3-user3']); - $this->assertArrayNotHasKey('email', $customers['3-user3']); - $this->assertArrayNotHasKey('address', $customers['3-user3']); - $this->assertArrayNotHasKey('status', $customers['3-user3']); - } - - -} \ No newline at end of file diff --git a/tests/unit/extensions/elasticsearch/ElasticSearchConnectionTest.php b/tests/unit/extensions/elasticsearch/ElasticSearchConnectionTest.php deleted file mode 100644 index 60b2428..0000000 --- a/tests/unit/extensions/elasticsearch/ElasticSearchConnectionTest.php +++ /dev/null @@ -1,28 +0,0 @@ -autodetectCluster; - $connection->nodes = [ - ['http_address' => 'inet[/127.0.0.1:9200]'], - ]; - $this->assertNull($connection->activeNode); - $connection->open(); - $this->assertNotNull($connection->activeNode); - $this->assertArrayHasKey('name', reset($connection->nodes)); - $this->assertArrayHasKey('hostname', reset($connection->nodes)); - $this->assertArrayHasKey('version', reset($connection->nodes)); - $this->assertArrayHasKey('http_address', reset($connection->nodes)); - } - -} \ No newline at end of file diff --git a/tests/unit/extensions/elasticsearch/ElasticSearchTestCase.php b/tests/unit/extensions/elasticsearch/ElasticSearchTestCase.php deleted file mode 100644 index e68613a..0000000 --- a/tests/unit/extensions/elasticsearch/ElasticSearchTestCase.php +++ /dev/null @@ -1,51 +0,0 @@ -mockApplication(); - - $databases = $this->getParam('databases'); - $params = isset($databases['elasticsearch']) ? $databases['elasticsearch'] : null; - if ($params === null || !isset($params['dsn'])) { - $this->markTestSkipped('No elasticsearch server connection configured.'); - } - $dsn = explode('/', $params['dsn']); - $host = $dsn[2]; - if (strpos($host, ':')===false) { - $host .= ':9200'; - } - if(!@stream_socket_client($host, $errorNumber, $errorDescription, 0.5)) { - $this->markTestSkipped('No elasticsearch server running at ' . $params['dsn'] . ' : ' . $errorNumber . ' - ' . $errorDescription); - } - - parent::setUp(); - } - - /** - * @param bool $reset whether to clean up the test database - * @return Connection - */ - public function getConnection($reset = true) - { - $databases = $this->getParam('databases'); - $params = isset($databases['elasticsearch']) ? $databases['elasticsearch'] : array(); - $db = new Connection(); - if ($reset) { - $db->open(); - } - return $db; - } -} diff --git a/tests/unit/extensions/elasticsearch/QueryTest.php b/tests/unit/extensions/elasticsearch/QueryTest.php deleted file mode 100644 index 746f9a2..0000000 --- a/tests/unit/extensions/elasticsearch/QueryTest.php +++ /dev/null @@ -1,188 +0,0 @@ -getConnection()->createCommand(); - - // delete index - if ($command->indexExists('yiitest')) { - $command->deleteIndex('yiitest'); - } - - $command->insert('yiitest', 'user', ['name' => 'user1', 'email' => 'user1@example.com', 'status' => 1], 1); - $command->insert('yiitest', 'user', ['name' => 'user2', 'email' => 'user2@example.com', 'status' => 1], 2); - $command->insert('yiitest', 'user', ['name' => 'user3', 'email' => 'user3@example.com', 'status' => 2], 3); - $command->insert('yiitest', 'user', ['name' => 'user4', 'email' => 'user4@example.com', 'status' => 1], 4); - - $command->flushIndex(); - } - - public function testFields() - { - $query = new Query; - $query->from('yiitest', 'user'); - - $query->fields(['name', 'status']); - $this->assertEquals(['name', 'status'], $query->fields); - - $query->fields('name', 'status'); - $this->assertEquals(['name', 'status'], $query->fields); - - $result = $query->one($this->getConnection()); - $this->assertEquals(2, count($result['_source'])); - $this->assertArrayHasKey('status', $result['_source']); - $this->assertArrayHasKey('name', $result['_source']); - $this->assertArrayHasKey('_id', $result); - - $query->fields([]); - $this->assertEquals([], $query->fields); - - $result = $query->one($this->getConnection()); - $this->assertEquals([], $result['_source']); - $this->assertArrayHasKey('_id', $result); - - $query->fields(null); - $this->assertNull($query->fields); - - $result = $query->one($this->getConnection()); - $this->assertEquals(3, count($result['_source'])); - $this->assertArrayHasKey('status', $result['_source']); - $this->assertArrayHasKey('email', $result['_source']); - $this->assertArrayHasKey('name', $result['_source']); - $this->assertArrayHasKey('_id', $result); - } - - public function testOne() - { - $query = new Query; - $query->from('yiitest', 'user'); - - $result = $query->one($this->getConnection()); - $this->assertEquals(3, count($result['_source'])); - $this->assertArrayHasKey('status', $result['_source']); - $this->assertArrayHasKey('email', $result['_source']); - $this->assertArrayHasKey('name', $result['_source']); - $this->assertArrayHasKey('_id', $result); - - $result = $query->where(['name' => 'user1'])->one($this->getConnection()); - $this->assertEquals(3, count($result['_source'])); - $this->assertArrayHasKey('status', $result['_source']); - $this->assertArrayHasKey('email', $result['_source']); - $this->assertArrayHasKey('name', $result['_source']); - $this->assertArrayHasKey('_id', $result); - $this->assertEquals(1, $result['_id']); - - $result = $query->where(['name' => 'user5'])->one($this->getConnection()); - $this->assertFalse($result); - } - - public function testAll() - { - $query = new Query; - $query->from('yiitest', 'user'); - - $results = $query->all($this->getConnection()); - $this->assertEquals(4, count($results)); - $result = reset($results); - $this->assertEquals(3, count($result['_source'])); - $this->assertArrayHasKey('status', $result['_source']); - $this->assertArrayHasKey('email', $result['_source']); - $this->assertArrayHasKey('name', $result['_source']); - $this->assertArrayHasKey('_id', $result); - - $query = new Query; - $query->from('yiitest', 'user'); - - $results = $query->where(['name' => 'user1'])->all($this->getConnection()); - $this->assertEquals(1, count($results)); - $result = reset($results); - $this->assertEquals(3, count($result['_source'])); - $this->assertArrayHasKey('status', $result['_source']); - $this->assertArrayHasKey('email', $result['_source']); - $this->assertArrayHasKey('name', $result['_source']); - $this->assertArrayHasKey('_id', $result); - $this->assertEquals(1, $result['_id']); - - // indexBy - $query = new Query; - $query->from('yiitest', 'user'); - - $results = $query->indexBy('name')->all($this->getConnection()); - $this->assertEquals(4, count($results)); - ksort($results); - $this->assertEquals(['user1', 'user2', 'user3', 'user4'], array_keys($results)); - } - - public function testScalar() - { - $query = new Query; - $query->from('yiitest', 'user'); - - $result = $query->where(['name' => 'user1'])->scalar('name', $this->getConnection()); - $this->assertEquals('user1', $result); - $result = $query->where(['name' => 'user1'])->scalar('noname', $this->getConnection()); - $this->assertNull($result); - $result = $query->where(['name' => 'user5'])->scalar('name', $this->getConnection()); - $this->assertNull($result); - } - - public function testColumn() - { - $query = new Query; - $query->from('yiitest', 'user'); - - $result = $query->orderBy(['name' => SORT_ASC])->column('name', $this->getConnection()); - $this->assertEquals(['user1', 'user2', 'user3', 'user4'], $result); - $result = $query->column('noname', $this->getConnection()); - $this->assertEquals([null, null, null, null], $result); - $result = $query->where(['name' => 'user5'])->scalar('name', $this->getConnection()); - $this->assertNull($result); - - } - - // TODO test facets - - // TODO test complex where() every edge of QueryBuilder - - public function testOrder() - { - $query = new Query; - $query->orderBy('team'); - $this->assertEquals(['team' => SORT_ASC], $query->orderBy); - - $query->addOrderBy('company'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC], $query->orderBy); - - $query->addOrderBy('age'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_ASC], $query->orderBy); - - $query->addOrderBy(['age' => SORT_DESC]); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_DESC], $query->orderBy); - - $query->addOrderBy('age ASC, company DESC'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_DESC, 'age' => SORT_ASC], $query->orderBy); - } - - public function testLimitOffset() - { - $query = new Query; - $query->limit(10)->offset(5); - $this->assertEquals(10, $query->limit); - $this->assertEquals(5, $query->offset); - } - - public function testUnion() - { - } -} diff --git a/tests/unit/extensions/imagine/AbstractImageTest.php b/tests/unit/extensions/imagine/AbstractImageTest.php deleted file mode 100644 index 054139e..0000000 --- a/tests/unit/extensions/imagine/AbstractImageTest.php +++ /dev/null @@ -1,98 +0,0 @@ -imageFile = Yii::getAlias('@yiiunit/data/imagine/large') . '.jpg'; - $this->watermarkFile = Yii::getAlias('@yiiunit/data/imagine/xparent') . '.gif'; - $this->runtimeTextFile = Yii::getAlias('@yiiunit/runtime/image-text-test') . '.png'; - $this->runtimeWatermarkFile = Yii::getAlias('@yiiunit/runtime/image-watermark-test') . '.png'; - parent::setUp(); - } - - protected function tearDown() - { - @unlink($this->runtimeTextFile); - @unlink($this->runtimeWatermarkFile); - } - - public function testText() - { - if (!$this->isFontTestSupported()) { - $this->markTestSkipped('Skipping ImageGdTest Gd not installed'); - } - - $fontFile = Yii::getAlias('@yiiunit/data/imagine/GothamRnd-Light') . '.otf'; - - $img = Image::text($this->imageFile, 'Yii-2 Image', $fontFile, [0, 0], [ - 'size' => 12, - 'color' => '000' - ]); - - $img->save($this->runtimeTextFile); - $this->assertTrue(file_exists($this->runtimeTextFile)); - - } - - public function testCrop() - { - $point = [20, 20]; - $img = Image::crop($this->imageFile, 100, 100, $point); - - $this->assertEquals(100, $img->getSize()->getWidth()); - $this->assertEquals(100, $img->getSize()->getHeight()); - - } - - public function testWatermark() - { - $img = Image::watermark($this->imageFile, $this->watermarkFile); - $img->save($this->runtimeWatermarkFile); - $this->assertTrue(file_exists($this->runtimeWatermarkFile)); - } - - public function testFrame() - { - $frameSize = 5; - $original = Image::getImagine()->open($this->imageFile); - $originalSize = $original->getSize(); - $img = Image::frame($this->imageFile, $frameSize, '666', 0); - $size = $img->getSize(); - - $this->assertEquals($size->getWidth(), $originalSize->getWidth() + ($frameSize * 2)); - } - - public function testThumbnail() - { - $img = Image::thumbnail($this->imageFile, 120, 120); - - $this->assertEquals(120, $img->getSize()->getWidth()); - $this->assertEquals(120, $img->getSize()->getHeight()); - } - - /** - * @expectedException \yii\base\InvalidConfigException - */ - public function testShouldThrowExceptionOnDriverInvalidArgument() - { - Image::setImagine(null); - Image::$driver = 'fake-driver'; - Image::getImagine(); - } - - abstract protected function isFontTestSupported(); -} diff --git a/tests/unit/extensions/imagine/ImageGdTest.php b/tests/unit/extensions/imagine/ImageGdTest.php deleted file mode 100644 index 9eaf09e..0000000 --- a/tests/unit/extensions/imagine/ImageGdTest.php +++ /dev/null @@ -1,30 +0,0 @@ -markTestSkipped('Skipping ImageGdTest, Gd not installed'); - } else { - Image::setImagine(null); - Image::$driver = Image::DRIVER_GD2; - parent::setUp(); - } - } - - protected function isFontTestSupported() - { - $infos = gd_info(); - return isset($infos['FreeType Support']) ? $infos['FreeType Support'] : false; - } - -} diff --git a/tests/unit/extensions/imagine/ImageGmagickTest.php b/tests/unit/extensions/imagine/ImageGmagickTest.php deleted file mode 100644 index cfe6dde..0000000 --- a/tests/unit/extensions/imagine/ImageGmagickTest.php +++ /dev/null @@ -1,30 +0,0 @@ -markTestSkipped('Skipping ImageGmagickTest, Gmagick is not installed'); - } else { - Image::setImagine(null); - Image::$driver = Image::DRIVER_GMAGICK; - parent::setUp(); - } - } - - protected function isFontTestSupported() - { - return true; - } - -} diff --git a/tests/unit/extensions/imagine/ImageImagickTest.php b/tests/unit/extensions/imagine/ImageImagickTest.php deleted file mode 100644 index 51834d6..0000000 --- a/tests/unit/extensions/imagine/ImageImagickTest.php +++ /dev/null @@ -1,30 +0,0 @@ -markTestSkipped('Skipping ImageImagickTest, Imagick is not installed'); - } else { - Image::setImagine(null); - Image::$driver = Image::DRIVER_IMAGICK; - parent::setUp(); - } - } - - protected function isFontTestSupported() - { - return true; - } - -} diff --git a/tests/unit/extensions/mongodb/ActiveDataProviderTest.php b/tests/unit/extensions/mongodb/ActiveDataProviderTest.php deleted file mode 100644 index 257d3b0..0000000 --- a/tests/unit/extensions/mongodb/ActiveDataProviderTest.php +++ /dev/null @@ -1,91 +0,0 @@ -getConnection(); - $this->setUpTestRows(); - } - - protected function tearDown() - { - $this->dropCollection(Customer::collectionName()); - parent::tearDown(); - } - - /** - * Sets up test rows. - */ - protected function setUpTestRows() - { - $collection = $this->getConnection()->getCollection('customer'); - $rows = []; - for ($i = 1; $i <= 10; $i++) { - $rows[] = [ - 'name' => 'name' . $i, - 'email' => 'email' . $i, - 'address' => 'address' . $i, - 'status' => $i, - ]; - } - $collection->batchInsert($rows); - } - - // Tests : - - public function testQuery() - { - $query = new Query; - $query->from('customer'); - - $provider = new ActiveDataProvider([ - 'query' => $query, - 'db' => $this->getConnection(), - ]); - $models = $provider->getModels(); - $this->assertEquals(10, count($models)); - - $provider = new ActiveDataProvider([ - 'query' => $query, - 'db' => $this->getConnection(), - 'pagination' => [ - 'pageSize' => 5, - ] - ]); - $models = $provider->getModels(); - $this->assertEquals(5, count($models)); - } - - public function testActiveQuery() - { - $provider = new ActiveDataProvider([ - 'query' => Customer::find()->orderBy('id ASC'), - ]); - $models = $provider->getModels(); - $this->assertEquals(10, count($models)); - $this->assertTrue($models[0] instanceof Customer); - $keys = $provider->getKeys(); - $this->assertTrue($keys[0] instanceof \MongoId); - - $provider = new ActiveDataProvider([ - 'query' => Customer::find(), - 'pagination' => [ - 'pageSize' => 5, - ] - ]); - $models = $provider->getModels(); - $this->assertEquals(5, count($models)); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/mongodb/ActiveRecordTest.php b/tests/unit/extensions/mongodb/ActiveRecordTest.php deleted file mode 100644 index 177eafa..0000000 --- a/tests/unit/extensions/mongodb/ActiveRecordTest.php +++ /dev/null @@ -1,246 +0,0 @@ -getConnection(); - $this->setUpTestRows(); - } - - protected function tearDown() - { - $this->dropCollection(Customer::collectionName()); - parent::tearDown(); - } - - /** - * Sets up test rows. - */ - protected function setUpTestRows() - { - $collection = $this->getConnection()->getCollection('customer'); - $rows = []; - for ($i = 1; $i <= 10; $i++) { - $rows[] = [ - 'name' => 'name' . $i, - 'email' => 'email' . $i, - 'address' => 'address' . $i, - 'status' => $i, - ]; - } - $collection->batchInsert($rows); - $this->testRows = $rows; - } - - // Tests : - - public function testFind() - { - // find one - $result = Customer::find(); - $this->assertTrue($result instanceof ActiveQuery); - $customer = $result->one(); - $this->assertTrue($customer instanceof Customer); - - // find all - $customers = Customer::find()->all(); - $this->assertEquals(10, count($customers)); - $this->assertTrue($customers[0] instanceof Customer); - $this->assertTrue($customers[1] instanceof Customer); - - // find by _id - $testId = $this->testRows[0]['_id']; - $customer = Customer::find($testId); - $this->assertTrue($customer instanceof Customer); - $this->assertEquals($testId, $customer->_id); - - // find by column values - $customer = Customer::find(['name' => 'name5']); - $this->assertTrue($customer instanceof Customer); - $this->assertEquals($this->testRows[4]['_id'], $customer->_id); - $this->assertEquals('name5', $customer->name); - $customer = Customer::find(['name' => 'unexisting name']); - $this->assertNull($customer); - - // find by attributes - $customer = Customer::find()->where(['status' => 4])->one(); - $this->assertTrue($customer instanceof Customer); - $this->assertEquals(4, $customer->status); - - // find count, sum, average, min, max, distinct - $this->assertEquals(10, Customer::find()->count()); - $this->assertEquals(1, Customer::find()->where(['status' => 2])->count()); - $this->assertEquals((1+10)/2*10, Customer::find()->sum('status')); - $this->assertEquals((1+10)/2, Customer::find()->average('status')); - $this->assertEquals(1, Customer::find()->min('status')); - $this->assertEquals(10, Customer::find()->max('status')); - $this->assertEquals(range(1, 10), Customer::find()->distinct('status')); - - // scope - $this->assertEquals(1, Customer::find()->activeOnly()->count()); - - // asArray - $testRow = $this->testRows[2]; - $customer = Customer::find()->where(['_id' => $testRow['_id']])->asArray()->one(); - $this->assertEquals($testRow, $customer); - - // indexBy - $customers = Customer::find()->indexBy('name')->all(); - $this->assertTrue($customers['name1'] instanceof Customer); - $this->assertTrue($customers['name2'] instanceof Customer); - - // indexBy callable - $customers = Customer::find()->indexBy(function ($customer) { - return $customer->status . '-' . $customer->status; - })->all(); - $this->assertTrue($customers['1-1'] instanceof Customer); - $this->assertTrue($customers['2-2'] instanceof Customer); - } - - public function testInsert() - { - $record = new Customer; - $record->name = 'new name'; - $record->email = 'new email'; - $record->address = 'new address'; - $record->status = 7; - - $this->assertTrue($record->isNewRecord); - - $record->save(); - - $this->assertTrue($record->_id instanceof \MongoId); - $this->assertFalse($record->isNewRecord); - } - - /** - * @depends testInsert - */ - public function testUpdate() - { - $record = new Customer; - $record->name = 'new name'; - $record->email = 'new email'; - $record->address = 'new address'; - $record->status = 7; - $record->save(); - - // save - $record = Customer::find($record->_id); - $this->assertTrue($record instanceof Customer); - $this->assertEquals(7, $record->status); - $this->assertFalse($record->isNewRecord); - - $record->status = 9; - $record->save(); - $this->assertEquals(9, $record->status); - $this->assertFalse($record->isNewRecord); - $record2 = Customer::find($record->_id); - $this->assertEquals(9, $record2->status); - - // updateAll - $pk = ['_id' => $record->_id]; - $ret = Customer::updateAll(['status' => 55], $pk); - $this->assertEquals(1, $ret); - $record = Customer::find($pk); - $this->assertEquals(55, $record->status); - } - - /** - * @depends testInsert - */ - public function testDelete() - { - // delete - $record = new Customer; - $record->name = 'new name'; - $record->email = 'new email'; - $record->address = 'new address'; - $record->status = 7; - $record->save(); - - $record = Customer::find($record->_id); - $record->delete(); - $record = Customer::find($record->_id); - $this->assertNull($record); - - // deleteAll - $record = new Customer; - $record->name = 'new name'; - $record->email = 'new email'; - $record->address = 'new address'; - $record->status = 7; - $record->save(); - - $ret = Customer::deleteAll(['name' => 'new name']); - $this->assertEquals(1, $ret); - $records = Customer::find()->where(['name' => 'new name'])->all(); - $this->assertEquals(0, count($records)); - } - - public function testUpdateAllCounters() - { - $this->assertEquals(1, Customer::updateAllCounters(['status' => 10], ['status' => 10])); - - $record = Customer::find(['status' => 10]); - $this->assertNull($record); - } - - /** - * @depends testUpdateAllCounters - */ - public function testUpdateCounters() - { - $record = Customer::find($this->testRows[9]); - - $originalCounter = $record->status; - $counterIncrement = 20; - $record->updateCounters(['status' => $counterIncrement]); - $this->assertEquals($originalCounter + $counterIncrement, $record->status); - - $refreshedRecord = Customer::find($record->_id); - $this->assertEquals($originalCounter + $counterIncrement, $refreshedRecord->status); - } - - /** - * @depends testUpdate - */ - public function testUpdateNestedAttribute() - { - $record = new Customer; - $record->name = 'new name'; - $record->email = 'new email'; - $record->address = [ - 'city' => 'SomeCity', - 'street' => 'SomeStreet', - ]; - $record->status = 7; - $record->save(); - - // save - $record = Customer::find($record->_id); - $newAddress = [ - 'city' => 'AnotherCity' - ]; - $record->address = $newAddress; - $record->save(); - $record2 = Customer::find($record->_id); - $this->assertEquals($newAddress, $record2->address); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/mongodb/ActiveRelationTest.php b/tests/unit/extensions/mongodb/ActiveRelationTest.php deleted file mode 100644 index 2baeab4..0000000 --- a/tests/unit/extensions/mongodb/ActiveRelationTest.php +++ /dev/null @@ -1,86 +0,0 @@ -getConnection(); - $this->setUpTestRows(); - } - - protected function tearDown() - { - $this->dropCollection(Customer::collectionName()); - $this->dropCollection(CustomerOrder::collectionName()); - parent::tearDown(); - } - - /** - * Sets up test rows. - */ - protected function setUpTestRows() - { - $customerCollection = $this->getConnection()->getCollection('customer'); - - $customers = []; - for ($i = 1; $i <= 5; $i++) { - $customers[] = [ - 'name' => 'name' . $i, - 'email' => 'email' . $i, - 'address' => 'address' . $i, - 'status' => $i, - ]; - } - $customerCollection->batchInsert($customers); - - $customerOrderCollection = $this->getConnection()->getCollection('customer_order'); - $customerOrders = []; - foreach ($customers as $customer) { - $customerOrders[] = [ - 'customer_id' => $customer['_id'], - 'number' => $customer['status'], - ]; - $customerOrders[] = [ - 'customer_id' => $customer['_id'], - 'number' => $customer['status'] + 100, - ]; - } - $customerOrderCollection->batchInsert($customerOrders); - } - - // Tests : - - public function testFindLazy() - { - /** @var CustomerOrder $order */ - $order = CustomerOrder::find(['number' => 2]); - $this->assertFalse($order->isRelationPopulated('customer')); - $customer = $order->customer; - $this->assertTrue($order->isRelationPopulated('customer')); - $this->assertTrue($customer instanceof Customer); - $this->assertEquals((string)$customer->_id, (string)$order->customer_id); - $this->assertEquals(1, count($order->relatedRecords)); - } - - public function testFindEager() - { - $orders = CustomerOrder::find()->with('customer')->all(); - $this->assertEquals(10, count($orders)); - $this->assertTrue($orders[0]->isRelationPopulated('customer')); - $this->assertTrue($orders[1]->isRelationPopulated('customer')); - $this->assertTrue($orders[0]->customer instanceof Customer); - $this->assertEquals((string)$orders[0]->customer->_id, (string)$orders[0]->customer_id); - $this->assertTrue($orders[1]->customer instanceof Customer); - $this->assertEquals((string)$orders[1]->customer->_id, (string)$orders[1]->customer_id); - } -} diff --git a/tests/unit/extensions/mongodb/CollectionTest.php b/tests/unit/extensions/mongodb/CollectionTest.php deleted file mode 100644 index fb6238d..0000000 --- a/tests/unit/extensions/mongodb/CollectionTest.php +++ /dev/null @@ -1,319 +0,0 @@ -dropCollection('customer'); - $this->dropCollection('mapReduceOut'); - parent::tearDown(); - } - - // Tests : - - public function testGetName() - { - $collectionName = 'customer'; - $collection = $this->getConnection()->getCollection($collectionName); - $this->assertEquals($collectionName, $collection->getName()); - $this->assertEquals($this->mongoDbConfig['defaultDatabaseName'] . '.' . $collectionName, $collection->getFullName()); - } - - public function testFind() - { - $collection = $this->getConnection()->getCollection('customer'); - $cursor = $collection->find(); - $this->assertTrue($cursor instanceof \MongoCursor); - } - - public function testInsert() - { - $collection = $this->getConnection()->getCollection('customer'); - $data = [ - 'name' => 'customer 1', - 'address' => 'customer 1 address', - ]; - $id = $collection->insert($data); - $this->assertTrue($id instanceof \MongoId); - $this->assertNotEmpty($id->__toString()); - } - - /** - * @depends testInsert - * @depends testFind - */ - public function testFindAll() - { - $collection = $this->getConnection()->getCollection('customer'); - $data = [ - 'name' => 'customer 1', - 'address' => 'customer 1 address', - ]; - $id = $collection->insert($data); - - $cursor = $collection->find(); - $rows = []; - foreach ($cursor as $row) { - $rows[] = $row; - } - $this->assertEquals(1, count($rows)); - $this->assertEquals($id, $rows[0]['_id']); - } - - /** - * @depends testFind - */ - public function testBatchInsert() - { - $collection = $this->getConnection()->getCollection('customer'); - $rows = [ - [ - 'name' => 'customer 1', - 'address' => 'customer 1 address', - ], - [ - 'name' => 'customer 2', - 'address' => 'customer 2 address', - ], - ]; - $insertedRows = $collection->batchInsert($rows); - $this->assertTrue($insertedRows[0]['_id'] instanceof \MongoId); - $this->assertTrue($insertedRows[1]['_id'] instanceof \MongoId); - $this->assertEquals(count($rows), $collection->find()->count()); - } - - public function testSave() - { - $collection = $this->getConnection()->getCollection('customer'); - $data = [ - 'name' => 'customer 1', - 'address' => 'customer 1 address', - ]; - $id = $collection->save($data); - $this->assertTrue($id instanceof \MongoId); - $this->assertNotEmpty($id->__toString()); - } - - /** - * @depends testSave - */ - public function testUpdateBySave() - { - $collection = $this->getConnection()->getCollection('customer'); - $data = [ - 'name' => 'customer 1', - 'address' => 'customer 1 address', - ]; - $newId = $collection->save($data); - - $updatedId = $collection->save($data); - $this->assertEquals($newId, $updatedId, 'Unable to update data!'); - - $data['_id'] = $newId->__toString(); - $updatedId = $collection->save($data); - $this->assertEquals($newId, $updatedId, 'Unable to updated data by string id!'); - } - - /** - * @depends testFindAll - */ - public function testRemove() - { - $collection = $this->getConnection()->getCollection('customer'); - $data = [ - 'name' => 'customer 1', - 'address' => 'customer 1 address', - ]; - $id = $collection->insert($data); - - $count = $collection->remove(['_id' => $id]); - $this->assertEquals(1, $count); - - $rows = $this->findAll($collection); - $this->assertEquals(0, count($rows)); - } - - /** - * @depends testFindAll - */ - public function testUpdate() - { - $collection = $this->getConnection()->getCollection('customer'); - $data = [ - 'name' => 'customer 1', - 'address' => 'customer 1 address', - ]; - $id = $collection->insert($data); - - $newData = [ - 'name' => 'new name' - ]; - $count = $collection->update(['_id' => $id], $newData); - $this->assertEquals(1, $count); - - list($row) = $this->findAll($collection); - $this->assertEquals($newData['name'], $row['name']); - } - - /** - * @depends testBatchInsert - */ - public function testGroup() - { - $collection = $this->getConnection()->getCollection('customer'); - $rows = [ - [ - 'name' => 'customer 1', - 'address' => 'customer 1 address', - ], - [ - 'name' => 'customer 2', - 'address' => 'customer 2 address', - ], - ]; - $collection->batchInsert($rows); - - $keys = ['address' => 1]; - $initial = ['items' => []]; - $reduce = "function (obj, prev) { prev.items.push(obj.name); }"; - $result = $collection->group($keys, $initial, $reduce); - $this->assertEquals(2, count($result)); - $this->assertNotEmpty($result[0]['address']); - $this->assertNotEmpty($result[0]['items']); - } - - /** - * @depends testBatchInsert - */ - public function testMapReduce() - { - $collection = $this->getConnection()->getCollection('customer'); - $rows = [ - [ - 'name' => 'customer 1', - 'status' => 1, - 'amount' => 100, - ], - [ - 'name' => 'customer 2', - 'status' => 1, - 'amount' => 200, - ], - [ - 'name' => 'customer 2', - 'status' => 2, - 'amount' => 400, - ], - [ - 'name' => 'customer 2', - 'status' => 3, - 'amount' => 500, - ], - ]; - $collection->batchInsert($rows); - - $result = $collection->mapReduce( - 'function () {emit(this.status, this.amount)}', - 'function (key, values) {return Array.sum(values)}', - 'mapReduceOut', - ['status' => ['$lt' => 3]] - ); - $this->assertEquals('mapReduceOut', $result); - - $outputCollection = $this->getConnection()->getCollection($result); - $rows = $this->findAll($outputCollection); - $expectedRows = [ - [ - '_id' => 1, - 'value' => 300, - ], - [ - '_id' => 2, - 'value' => 400, - ], - ]; - $this->assertEquals($expectedRows, $rows); - } - - public function testCreateIndex() - { - $collection = $this->getConnection()->getCollection('customer'); - $columns = [ - 'name', - 'status' => \MongoCollection::DESCENDING, - ]; - $this->assertTrue($collection->createIndex($columns)); - $indexInfo = $collection->mongoCollection->getIndexInfo(); - $this->assertEquals(2, count($indexInfo)); - } - - /** - * @depends testCreateIndex - */ - public function testDropIndex() - { - $collection = $this->getConnection()->getCollection('customer'); - - $collection->createIndex('name'); - $this->assertTrue($collection->dropIndex('name')); - $indexInfo = $collection->mongoCollection->getIndexInfo(); - $this->assertEquals(1, count($indexInfo)); - - $this->setExpectedException('\yii\mongodb\Exception'); - $collection->dropIndex('name'); - } - - /** - * @depends testCreateIndex - */ - public function testDropAllIndexes() - { - $collection = $this->getConnection()->getCollection('customer'); - $collection->createIndex('name'); - $this->assertEquals(2, $collection->dropAllIndexes()); - $indexInfo = $collection->mongoCollection->getIndexInfo(); - $this->assertEquals(1, count($indexInfo)); - } - - /** - * @depends testBatchInsert - * @depends testCreateIndex - */ - public function testFullTextSearch() - { - if (version_compare('2.4', $this->getServerVersion(), '>')) { - $this->markTestSkipped("Mongo Server 2.4 required."); - } - - $collection = $this->getConnection()->getCollection('customer'); - - $rows = [ - [ - 'name' => 'customer 1', - 'status' => 1, - 'amount' => 100, - ], - [ - 'name' => 'some customer', - 'status' => 1, - 'amount' => 200, - ], - [ - 'name' => 'no search keyword', - 'status' => 1, - 'amount' => 200, - ], - ]; - $collection->batchInsert($rows); - $collection->createIndex(['name' => 'text']); - - $result = $collection->fullTextSearch('customer'); - $this->assertNotEmpty($result); - $this->assertCount(2, $result); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/mongodb/ConnectionTest.php b/tests/unit/extensions/mongodb/ConnectionTest.php deleted file mode 100644 index 7209752..0000000 --- a/tests/unit/extensions/mongodb/ConnectionTest.php +++ /dev/null @@ -1,119 +0,0 @@ -getConnection(false); - $params = $this->mongoDbConfig; - - $connection->open(); - - $this->assertEquals($params['dsn'], $connection->dsn); - $this->assertEquals($params['defaultDatabaseName'], $connection->defaultDatabaseName); - $this->assertEquals($params['options'], $connection->options); - } - - public function testOpenClose() - { - $connection = $this->getConnection(false, false); - - $this->assertFalse($connection->isActive); - $this->assertEquals(null, $connection->mongoClient); - - $connection->open(); - $this->assertTrue($connection->isActive); - $this->assertTrue(is_object($connection->mongoClient)); - - $connection->close(); - $this->assertFalse($connection->isActive); - $this->assertEquals(null, $connection->mongoClient); - - $connection = new Connection; - $connection->dsn = 'unknown::memory:'; - $this->setExpectedException('yii\mongodb\Exception'); - $connection->open(); - } - - public function testGetDatabase() - { - $connection = $this->getConnection(); - - $database = $connection->getDatabase($connection->defaultDatabaseName); - $this->assertTrue($database instanceof Database); - $this->assertTrue($database->mongoDb instanceof \MongoDB); - - $database2 = $connection->getDatabase($connection->defaultDatabaseName); - $this->assertTrue($database === $database2); - - $databaseRefreshed = $connection->getDatabase($connection->defaultDatabaseName, true); - $this->assertFalse($database === $databaseRefreshed); - } - - /** - * @depends testGetDatabase - */ - public function testGetDefaultDatabase() - { - $connection = new Connection(); - $connection->dsn = $this->mongoDbConfig['dsn']; - $connection->defaultDatabaseName = $this->mongoDbConfig['defaultDatabaseName']; - $database = $connection->getDatabase(); - $this->assertTrue($database instanceof Database, 'Unable to get default database!'); - - $connection = new Connection(); - $connection->dsn = $this->mongoDbConfig['dsn']; - $connection->options = ['db' => $this->mongoDbConfig['defaultDatabaseName']]; - $database = $connection->getDatabase(); - $this->assertTrue($database instanceof Database, 'Unable to determine default database from options!'); - - $connection = new Connection(); - $connection->dsn = $this->mongoDbConfig['dsn'] . '/' . $this->mongoDbConfig['defaultDatabaseName']; - $database = $connection->getDatabase(); - $this->assertTrue($database instanceof Database, 'Unable to determine default database from dsn!'); - } - - /** - * @depends testGetDefaultDatabase - */ - public function testGetCollection() - { - $connection = $this->getConnection(); - - $collection = $connection->getCollection('customer'); - $this->assertTrue($collection instanceof Collection); - - $collection2 = $connection->getCollection('customer'); - $this->assertTrue($collection === $collection2); - - $collection2 = $connection->getCollection('customer', true); - $this->assertFalse($collection === $collection2); - } - - /** - * @depends testGetDefaultDatabase - */ - public function testGetFileCollection() - { - $connection = $this->getConnection(); - - $collection = $connection->getFileCollection('testfs'); - $this->assertTrue($collection instanceof FileCollection); - - $collection2 = $connection->getFileCollection('testfs'); - $this->assertTrue($collection === $collection2); - - $collection2 = $connection->getFileCollection('testfs', true); - $this->assertFalse($collection === $collection2); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/mongodb/DatabaseTest.php b/tests/unit/extensions/mongodb/DatabaseTest.php deleted file mode 100644 index c5ed358..0000000 --- a/tests/unit/extensions/mongodb/DatabaseTest.php +++ /dev/null @@ -1,70 +0,0 @@ -dropCollection('customer'); - $this->dropFileCollection('testfs'); - parent::tearDown(); - } - - // Tests : - - public function testGetCollection() - { - $database = $connection = $this->getConnection()->getDatabase(); - - $collection = $database->getCollection('customer'); - $this->assertTrue($collection instanceof Collection); - $this->assertTrue($collection->mongoCollection instanceof \MongoCollection); - - $collection2 = $database->getCollection('customer'); - $this->assertTrue($collection === $collection2); - - $collectionRefreshed = $database->getCollection('customer', true); - $this->assertFalse($collection === $collectionRefreshed); - } - - public function testGetFileCollection() - { - $database = $connection = $this->getConnection()->getDatabase(); - - $collection = $database->getFileCollection('testfs'); - $this->assertTrue($collection instanceof FileCollection); - $this->assertTrue($collection->mongoCollection instanceof \MongoGridFS); - - $collection2 = $database->getFileCollection('testfs'); - $this->assertTrue($collection === $collection2); - - $collectionRefreshed = $database->getFileCollection('testfs', true); - $this->assertFalse($collection === $collectionRefreshed); - } - - public function testExecuteCommand() - { - $database = $connection = $this->getConnection()->getDatabase(); - - $result = $database->executeCommand([ - 'distinct' => 'customer', - 'key' => 'name' - ]); - $this->assertTrue(array_key_exists('ok', $result)); - $this->assertTrue(array_key_exists('values', $result)); - } - - public function testCreateCollection() - { - $database = $connection = $this->getConnection()->getDatabase(); - $collection = $database->createCollection('customer'); - $this->assertTrue($collection instanceof \MongoCollection); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/mongodb/MongoDbTestCase.php b/tests/unit/extensions/mongodb/MongoDbTestCase.php deleted file mode 100644 index df60b28..0000000 --- a/tests/unit/extensions/mongodb/MongoDbTestCase.php +++ /dev/null @@ -1,149 +0,0 @@ - 'mongodb://localhost:27017', - 'defaultDatabaseName' => 'yii2test', - 'options' => [], - ]; - /** - * @var Connection Mongo connection instance. - */ - protected $mongodb; - - public static function setUpBeforeClass() - { - static::loadClassMap(); - } - - protected function setUp() - { - parent::setUp(); - if (!extension_loaded('mongo')) { - $this->markTestSkipped('mongo extension required.'); - } - $config = $this->getParam('mongodb'); - if (!empty($config)) { - $this->mongoDbConfig = $config; - } - $this->mockApplication(); - static::loadClassMap(); - } - - protected function tearDown() - { - if ($this->mongodb) { - $this->mongodb->close(); - } - $this->destroyApplication(); - } - - /** - * Adds sphinx extension files to [[Yii::$classPath]], - * avoiding the necessity of usage Composer autoloader. - */ - protected static function loadClassMap() - { - $baseNameSpace = 'yii/mongodb'; - $basePath = realpath(__DIR__. '/../../../../extensions/yii/mongodb'); - $files = FileHelper::findFiles($basePath); - foreach ($files as $file) { - $classRelativePath = str_replace($basePath, '', $file); - $classFullName = str_replace(['/', '.php'], ['\\', ''], $baseNameSpace . $classRelativePath); - Yii::$classMap[$classFullName] = $file; - } - } - - /** - * @param boolean $reset whether to clean up the test database - * @param boolean $open whether to open test database - * @return \yii\mongodb\Connection - */ - public function getConnection($reset = false, $open = true) - { - if (!$reset && $this->mongodb) { - return $this->mongodb; - } - $db = new Connection; - $db->dsn = $this->mongoDbConfig['dsn']; - $db->defaultDatabaseName = $this->mongoDbConfig['defaultDatabaseName']; - if (isset($this->mongoDbConfig['options'])) { - $db->options = $this->mongoDbConfig['options']; - } - if ($open) { - $db->open(); - } - $this->mongodb = $db; - return $db; - } - - /** - * Drops the specified collection. - * @param string $name collection name. - */ - protected function dropCollection($name) - { - if ($this->mongodb) { - try { - $this->mongodb->getCollection($name)->drop(); - } catch (Exception $e) { - // shut down exception - } - } - } - - /** - * Drops the specified file collection. - * @param string $name file collection name. - */ - protected function dropFileCollection($name = 'fs') - { - if ($this->mongodb) { - try { - $this->mongodb->getFileCollection($name)->drop(); - } catch (Exception $e) { - // shut down exception - } - } - } - - /** - * Finds all records in collection. - * @param \yii\mongodb\Collection $collection - * @param array $condition - * @param array $fields - * @return array rows - */ - protected function findAll($collection, $condition = [], $fields = []) - { - $cursor = $collection->find($condition, $fields); - $result = []; - foreach ($cursor as $data) { - $result[] = $data; - } - return $result; - } - - /** - * Returns the Mongo server version. - * @return string Mongo server version. - */ - protected function getServerVersion() - { - $connection = $this->getConnection(); - $buildInfo = $connection->getDatabase()->executeCommand(['buildinfo' => true]); - return $buildInfo['version']; - } -} diff --git a/tests/unit/extensions/mongodb/QueryRunTest.php b/tests/unit/extensions/mongodb/QueryRunTest.php deleted file mode 100644 index e9255a7..0000000 --- a/tests/unit/extensions/mongodb/QueryRunTest.php +++ /dev/null @@ -1,144 +0,0 @@ -setUpTestRows(); - } - - protected function tearDown() - { - $this->dropCollection('customer'); - parent::tearDown(); - } - - /** - * Sets up test rows. - */ - protected function setUpTestRows() - { - $collection = $this->getConnection()->getCollection('customer'); - $rows = []; - for ($i = 1; $i <= 10; $i++) { - $rows[] = [ - 'name' => 'name' . $i, - 'address' => 'address' . $i, - 'avatar' => [ - 'width' => 50 + $i, - 'height' => 100 + $i, - 'url' => 'http://some.url/' . $i, - ], - ]; - } - $collection->batchInsert($rows); - } - - // Tests : - - public function testAll() - { - $connection = $this->getConnection(); - $query = new Query; - $rows = $query->from('customer')->all($connection); - $this->assertEquals(10, count($rows)); - } - - public function testDirectMatch() - { - $connection = $this->getConnection(); - $query = new Query; - $rows = $query->from('customer') - ->where(['name' => 'name1']) - ->all($connection); - $this->assertEquals(1, count($rows)); - $this->assertEquals('name1', $rows[0]['name']); - } - - public function testIndexBy() - { - $connection = $this->getConnection(); - $query = new Query; - $rows = $query->from('customer') - ->indexBy('name') - ->all($connection); - $this->assertEquals(10, count($rows)); - $this->assertNotEmpty($rows['name1']); - } - - public function testInCondition() - { - $connection = $this->getConnection(); - $query = new Query; - $rows = $query->from('customer') - ->where([ - 'name' => ['name1', 'name5'] - ]) - ->all($connection); - $this->assertEquals(2, count($rows)); - $this->assertEquals('name1', $rows[0]['name']); - $this->assertEquals('name5', $rows[1]['name']); - } - - public function testOrCondition() - { - $connection = $this->getConnection(); - $query = new Query; - $rows = $query->from('customer') - ->where(['name' => 'name1']) - ->orWhere(['address' => 'address5']) - ->all($connection); - $this->assertEquals(2, count($rows)); - $this->assertEquals('name1', $rows[0]['name']); - $this->assertEquals('address5', $rows[1]['address']); - } - - public function testOrder() - { - $connection = $this->getConnection(); - - $query = new Query; - $rows = $query->from('customer') - ->orderBy(['name' => SORT_DESC]) - ->all($connection); - $this->assertEquals('name9', $rows[0]['name']); - - $query = new Query; - $rows = $query->from('customer') - ->orderBy(['avatar.height' => SORT_DESC]) - ->all($connection); - $this->assertEquals('name10', $rows[0]['name']); - } - - public function testMatchPlainId() - { - $connection = $this->getConnection(); - $query = new Query; - $row = $query->from('customer')->one($connection); - $query = new Query; - $rows = $query->from('customer') - ->where(['_id' => $row['_id']->__toString()]) - ->all($connection); - $this->assertEquals(1, count($rows)); - } - - public function testLike() - { - $connection = $this->getConnection(); - $query = new Query; - $rows = $query->from('customer') - ->where(['LIKE', 'name', '/me1/']) - ->all($connection); - $this->assertEquals(2, count($rows)); - $this->assertEquals('name1', $rows[0]['name']); - $this->assertEquals('name10', $rows[1]['name']); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/mongodb/QueryTest.php b/tests/unit/extensions/mongodb/QueryTest.php deleted file mode 100644 index 52b993c..0000000 --- a/tests/unit/extensions/mongodb/QueryTest.php +++ /dev/null @@ -1,97 +0,0 @@ -select($select); - $this->assertEquals($select, $query->select); - - $query = new Query; - $select = ['name', 'something']; - $query->select($select); - $this->assertEquals($select, $query->select); - } - - public function testFrom() - { - $query = new Query; - $from = 'customer'; - $query->from($from); - $this->assertEquals($from, $query->from); - - $query = new Query; - $from = ['', 'customer']; - $query->from($from); - $this->assertEquals($from, $query->from); - } - - public function testWhere() - { - $query = new Query; - $query->where(['name' => 'name1']); - $this->assertEquals(['name' => 'name1'], $query->where); - - $query->andWhere(['address' => 'address1']); - $this->assertEquals( - [ - 'and', - ['name' => 'name1'], - ['address' => 'address1'] - ], - $query->where - ); - - $query->orWhere(['name' => 'name2']); - $this->assertEquals( - [ - 'or', - [ - 'and', - ['name' => 'name1'], - ['address' => 'address1'] - ], - ['name' => 'name2'] - - ], - $query->where - ); - } - - public function testOrder() - { - $query = new Query; - $query->orderBy('team'); - $this->assertEquals(['team' => SORT_ASC], $query->orderBy); - - $query->addOrderBy('company'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC], $query->orderBy); - - $query->addOrderBy('age'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_ASC], $query->orderBy); - - $query->addOrderBy(['age' => SORT_DESC]); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_DESC], $query->orderBy); - - $query->addOrderBy('age ASC, company DESC'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_DESC, 'age' => SORT_ASC], $query->orderBy); - } - - public function testLimitOffset() - { - $query = new Query; - $query->limit(10)->offset(5); - $this->assertEquals(10, $query->limit); - $this->assertEquals(5, $query->offset); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/mongodb/file/ActiveRecordTest.php b/tests/unit/extensions/mongodb/file/ActiveRecordTest.php deleted file mode 100644 index 0c4292e..0000000 --- a/tests/unit/extensions/mongodb/file/ActiveRecordTest.php +++ /dev/null @@ -1,323 +0,0 @@ -getConnection(); - $this->setUpTestRows(); - $filePath = $this->getTestFilePath(); - if (!file_exists($filePath)) { - FileHelper::createDirectory($filePath); - } - } - - protected function tearDown() - { - $filePath = $this->getTestFilePath(); - if (file_exists($filePath)) { - FileHelper::removeDirectory($filePath); - } - $this->dropFileCollection(CustomerFile::collectionName()); - parent::tearDown(); - } - - /** - * @return string test file path. - */ - protected function getTestFilePath() - { - return Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . basename(get_class($this)) . '_' . getmypid(); - } - - /** - * Sets up test rows. - */ - protected function setUpTestRows() - { - $collection = $this->getConnection()->getFileCollection(CustomerFile::collectionName()); - $rows = []; - for ($i = 1; $i <= 10; $i++) { - $record = [ - 'tag' => 'tag' . $i, - 'status' => $i, - ]; - $content = 'content' . $i; - $record['_id'] = $collection->insertFileContent($content, $record); - $record['content'] = $content; - $rows[] = $record; - } - $this->testRows = $rows; - } - - // Tests : - - public function testFind() - { - // find one - $result = CustomerFile::find(); - $this->assertTrue($result instanceof ActiveQuery); - $customer = $result->one(); - $this->assertTrue($customer instanceof CustomerFile); - - // find all - $customers = CustomerFile::find()->all(); - $this->assertEquals(10, count($customers)); - $this->assertTrue($customers[0] instanceof CustomerFile); - $this->assertTrue($customers[1] instanceof CustomerFile); - - // find by _id - $testId = $this->testRows[0]['_id']; - $customer = CustomerFile::find($testId); - $this->assertTrue($customer instanceof CustomerFile); - $this->assertEquals($testId, $customer->_id); - - // find by column values - $customer = CustomerFile::find(['tag' => 'tag5']); - $this->assertTrue($customer instanceof CustomerFile); - $this->assertEquals($this->testRows[4]['_id'], $customer->_id); - $this->assertEquals('tag5', $customer->tag); - $customer = CustomerFile::find(['tag' => 'unexisting tag']); - $this->assertNull($customer); - - // find by attributes - $customer = CustomerFile::find()->where(['status' => 4])->one(); - $this->assertTrue($customer instanceof CustomerFile); - $this->assertEquals(4, $customer->status); - - // find count, sum, average, min, max, distinct - $this->assertEquals(10, CustomerFile::find()->count()); - $this->assertEquals(1, CustomerFile::find()->where(['status' => 2])->count()); - $this->assertEquals((1+10)/2*10, CustomerFile::find()->sum('status')); - $this->assertEquals((1+10)/2, CustomerFile::find()->average('status')); - $this->assertEquals(1, CustomerFile::find()->min('status')); - $this->assertEquals(10, CustomerFile::find()->max('status')); - $this->assertEquals(range(1, 10), CustomerFile::find()->distinct('status')); - - // scope - $this->assertEquals(1, CustomerFile::find()->activeOnly()->count()); - - // asArray - $testRow = $this->testRows[2]; - $customer = CustomerFile::find()->where(['_id' => $testRow['_id']])->asArray()->one(); - $this->assertEquals($testRow['_id'], $customer['_id']); - $this->assertEquals($testRow['tag'], $customer['tag']); - $this->assertEquals($testRow['status'], $customer['status']); - - // indexBy - $customers = CustomerFile::find()->indexBy('tag')->all(); - $this->assertTrue($customers['tag1'] instanceof CustomerFile); - $this->assertTrue($customers['tag2'] instanceof CustomerFile); - - // indexBy callable - $customers = CustomerFile::find()->indexBy(function ($customer) { - return $customer->status . '-' . $customer->status; - })->all(); - $this->assertTrue($customers['1-1'] instanceof CustomerFile); - $this->assertTrue($customers['2-2'] instanceof CustomerFile); - } - - public function testInsert() - { - $record = new CustomerFile; - $record->tag = 'new new'; - $record->status = 7; - - $this->assertTrue($record->isNewRecord); - - $record->save(); - - $this->assertTrue($record->_id instanceof \MongoId); - $this->assertFalse($record->isNewRecord); - - $fileContent = $record->getFileContent(); - $this->assertEmpty($fileContent); - } - - /** - * @depends testInsert - */ - public function testInsertFile() - { - $record = new CustomerFile; - $record->tag = 'new new'; - $record->status = 7; - - $fileName = __FILE__; - $record->setAttribute('file', $fileName); - - $record->save(); - - $this->assertTrue($record->_id instanceof \MongoId); - $this->assertFalse($record->isNewRecord); - - $fileContent = $record->getFileContent(); - $this->assertEquals(file_get_contents($fileName), $fileContent); - } - - /** - * @depends testInsert - */ - public function testInsertFileContent() - { - $record = new CustomerFile; - $record->tag = 'new new'; - $record->status = 7; - - $newFileContent = 'Test new file content'; - $record->setAttribute('newFileContent', $newFileContent); - - $record->save(); - - $this->assertTrue($record->_id instanceof \MongoId); - $this->assertFalse($record->isNewRecord); - - $fileContent = $record->getFileContent(); - $this->assertEquals($newFileContent, $fileContent); - } - - /** - * @depends testInsert - */ - public function testUpdate() - { - $record = new CustomerFile; - $record->tag = 'new new'; - $record->status = 7; - $record->save(); - - // save - $record = CustomerFile::find($record->_id); - $this->assertTrue($record instanceof CustomerFile); - $this->assertEquals(7, $record->status); - $this->assertFalse($record->isNewRecord); - - $record->status = 9; - $record->save(); - $this->assertEquals(9, $record->status); - $this->assertFalse($record->isNewRecord); - $record2 = CustomerFile::find($record->_id); - $this->assertEquals(9, $record2->status); - - // updateAll - $pk = ['_id' => $record->_id]; - $ret = CustomerFile::updateAll(['status' => 55], $pk); - $this->assertEquals(1, $ret); - $record = CustomerFile::find($pk); - $this->assertEquals(55, $record->status); - } - - /** - * @depends testUpdate - * @depends testInsertFileContent - */ - public function testUpdateFile() - { - $record = new CustomerFile; - $record->tag = 'new new'; - $record->status = 7; - $newFileContent = 'Test new file content'; - $record->setAttribute('newFileContent', $newFileContent); - $record->save(); - - $updateFileName = __FILE__; - $record = CustomerFile::find($record->_id); - $record->setAttribute('file', $updateFileName); - $record->status = 55; - $record->save(); - $this->assertEquals(file_get_contents($updateFileName), $record->getFileContent()); - - $record2 = CustomerFile::find($record->_id); - $this->assertEquals($record->status, $record2->status); - $this->assertEquals(file_get_contents($updateFileName), $record2->getFileContent()); - } - - /** - * @depends testUpdate - * @depends testInsertFileContent - */ - public function testUpdateFileContent() - { - $record = new CustomerFile; - $record->tag = 'new new'; - $record->status = 7; - $newFileContent = 'Test new file content'; - $record->setAttribute('newFileContent', $newFileContent); - $record->save(); - - $updateFileContent = 'New updated file content'; - $record = CustomerFile::find($record->_id); - $record->setAttribute('newFileContent', $updateFileContent); - $record->status = 55; - $record->save(); - $this->assertEquals($updateFileContent, $record->getFileContent()); - - $record2 = CustomerFile::find($record->_id); - $this->assertEquals($record->status, $record2->status); - $this->assertEquals($updateFileContent, $record2->getFileContent()); - } - - /** - * @depends testInsertFileContent - */ - public function testWriteFile() - { - $record = new CustomerFile; - $record->tag = 'new new'; - $record->status = 7; - $newFileContent = 'Test new file content'; - $record->setAttribute('newFileContent', $newFileContent); - $record->save(); - - $outputFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . 'out.txt'; - $this->assertTrue($record->writeFile($outputFileName)); - $this->assertEquals($newFileContent, file_get_contents($outputFileName)); - - $record2 = CustomerFile::find($record->_id); - $outputFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . 'out_refreshed.txt'; - $this->assertTrue($record2->writeFile($outputFileName)); - $this->assertEquals($newFileContent, file_get_contents($outputFileName)); - } - - /** - * @depends testInsertFileContent - */ - public function testGetFileResource() - { - $record = new CustomerFile; - $record->tag = 'new new'; - $record->status = 7; - $newFileContent = 'Test new file content'; - $record->setAttribute('newFileContent', $newFileContent); - $record->save(); - - $fileResource = $record->getFileResource(); - $contents = stream_get_contents($fileResource); - fclose($fileResource); - $this->assertEquals($newFileContent, $contents); - - $record2 = CustomerFile::find($record->_id); - $fileResource = $record2->getFileResource(); - $contents = stream_get_contents($fileResource); - fclose($fileResource); - $this->assertEquals($newFileContent, $contents); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/mongodb/file/CollectionTest.php b/tests/unit/extensions/mongodb/file/CollectionTest.php deleted file mode 100644 index 550225c..0000000 --- a/tests/unit/extensions/mongodb/file/CollectionTest.php +++ /dev/null @@ -1,98 +0,0 @@ -dropFileCollection('fs'); - parent::tearDown(); - } - - // Tests : - - public function testGetChunkCollection() - { - $collection = $this->getConnection()->getFileCollection(); - $chunkCollection = $collection->getChunkCollection(); - $this->assertTrue($chunkCollection instanceof \yii\mongodb\Collection); - $this->assertTrue($chunkCollection->mongoCollection instanceof \MongoCollection); - } - - public function testFind() - { - $collection = $this->getConnection()->getFileCollection(); - $cursor = $collection->find(); - $this->assertTrue($cursor instanceof \MongoGridFSCursor); - } - - public function testInsertFile() - { - $collection = $this->getConnection()->getFileCollection(); - - $filename = __FILE__; - $id = $collection->insertFile($filename); - $this->assertTrue($id instanceof \MongoId); - - $files = $this->findAll($collection); - $this->assertEquals(1, count($files)); - - /** @var $file \MongoGridFSFile */ - $file = $files[0]; - $this->assertEquals($filename, $file->getFilename()); - $this->assertEquals(file_get_contents($filename), $file->getBytes()); - } - - public function testInsertFileContent() - { - $collection = $this->getConnection()->getFileCollection(); - - $bytes = 'Test file content'; - $id = $collection->insertFileContent($bytes); - $this->assertTrue($id instanceof \MongoId); - - $files = $this->findAll($collection); - $this->assertEquals(1, count($files)); - - /** @var $file \MongoGridFSFile */ - $file = $files[0]; - $this->assertEquals($bytes, $file->getBytes()); - } - - /** - * @depends testInsertFileContent - */ - public function testGet() - { - $collection = $this->getConnection()->getFileCollection(); - - $bytes = 'Test file content'; - $id = $collection->insertFileContent($bytes); - - $file = $collection->get($id); - $this->assertTrue($file instanceof \MongoGridFSFile); - $this->assertEquals($bytes, $file->getBytes()); - } - - /** - * @depends testGet - */ - public function testDelete() - { - $collection = $this->getConnection()->getFileCollection(); - - $bytes = 'Test file content'; - $id = $collection->insertFileContent($bytes); - - $this->assertTrue($collection->delete($id)); - - $file = $collection->get($id); - $this->assertNull($file); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/mongodb/file/QueryTest.php b/tests/unit/extensions/mongodb/file/QueryTest.php deleted file mode 100644 index 1af07fd..0000000 --- a/tests/unit/extensions/mongodb/file/QueryTest.php +++ /dev/null @@ -1,70 +0,0 @@ -setUpTestRows(); - } - - protected function tearDown() - { - $this->dropFileCollection(); - parent::tearDown(); - } - - /** - * Sets up test rows. - */ - protected function setUpTestRows() - { - $collection = $this->getConnection()->getFileCollection(); - for ($i = 1; $i <= 10; $i++) { - $collection->insertFileContent('content' . $i, [ - 'filename' => 'name' . $i, - 'file_index' => $i, - ]); - } - } - - // Tests : - - public function testAll() - { - $connection = $this->getConnection(); - $query = new Query; - $rows = $query->from('fs')->all($connection); - $this->assertEquals(10, count($rows)); - } - - public function testOne() - { - $connection = $this->getConnection(); - $query = new Query; - $row = $query->from('fs')->one($connection); - $this->assertTrue(is_array($row)); - $this->assertTrue($row['file'] instanceof \MongoGridFSFile); - } - - public function testDirectMatch() - { - $connection = $this->getConnection(); - $query = new Query; - $rows = $query->from('fs') - ->where(['file_index' => 5]) - ->all($connection); - $this->assertEquals(1, count($rows)); - /** @var $file \MongoGridFSFile */ - $file = $rows[0]; - $this->assertEquals('name5', $file['filename']); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/redis/ActiveRecordTest.php b/tests/unit/extensions/redis/ActiveRecordTest.php deleted file mode 100644 index 3916f9d..0000000 --- a/tests/unit/extensions/redis/ActiveRecordTest.php +++ /dev/null @@ -1,231 +0,0 @@ -getConnection(); - - $customer = new Customer(); - $customer->setAttributes(['email' => 'user1@example.com', 'name' => 'user1', 'address' => 'address1', 'status' => 1], false); - $customer->save(false); - $customer = new Customer(); - $customer->setAttributes(['email' => 'user2@example.com', 'name' => 'user2', 'address' => 'address2', 'status' => 1], false); - $customer->save(false); - $customer = new Customer(); - $customer->setAttributes(['email' => 'user3@example.com', 'name' => 'user3', 'address' => 'address3', 'status' => 2], false); - $customer->save(false); - -// INSERT INTO tbl_category (name) VALUES ('Books'); -// INSERT INTO tbl_category (name) VALUES ('Movies'); - - $item = new Item(); - $item->setAttributes(['name' => 'Agile Web Application Development with Yii1.1 and PHP5', 'category_id' => 1], false); - $item->save(false); - $item = new Item(); - $item->setAttributes(['name' => 'Yii 1.1 Application Development Cookbook', 'category_id' => 1], false); - $item->save(false); - $item = new Item(); - $item->setAttributes(['name' => 'Ice Age', 'category_id' => 2], false); - $item->save(false); - $item = new Item(); - $item->setAttributes(['name' => 'Toy Story', 'category_id' => 2], false); - $item->save(false); - $item = new Item(); - $item->setAttributes(['name' => 'Cars', 'category_id' => 2], false); - $item->save(false); - - $order = new Order(); - $order->setAttributes(['customer_id' => 1, 'create_time' => 1325282384, 'total' => 110.0], false); - $order->save(false); - $order = new Order(); - $order->setAttributes(['customer_id' => 2, 'create_time' => 1325334482, 'total' => 33.0], false); - $order->save(false); - $order = new Order(); - $order->setAttributes(['customer_id' => 2, 'create_time' => 1325502201, 'total' => 40.0], false); - $order->save(false); - - $orderItem = new OrderItem(); - $orderItem->setAttributes(['order_id' => 1, 'item_id' => 1, 'quantity' => 1, 'subtotal' => 30.0], false); - $orderItem->save(false); - $orderItem = new OrderItem(); - $orderItem->setAttributes(['order_id' => 1, 'item_id' => 2, 'quantity' => 2, 'subtotal' => 40.0], false); - $orderItem->save(false); - $orderItem = new OrderItem(); - $orderItem->setAttributes(['order_id' => 2, 'item_id' => 4, 'quantity' => 1, 'subtotal' => 10.0], false); - $orderItem->save(false); - $orderItem = new OrderItem(); - $orderItem->setAttributes(['order_id' => 2, 'item_id' => 5, 'quantity' => 1, 'subtotal' => 15.0], false); - $orderItem->save(false); - $orderItem = new OrderItem(); - $orderItem->setAttributes(['order_id' => 2, 'item_id' => 3, 'quantity' => 1, 'subtotal' => 8.0], false); - $orderItem->save(false); - $orderItem = new OrderItem(); - $orderItem->setAttributes(['order_id' => 3, 'item_id' => 2, 'quantity' => 1, 'subtotal' => 40.0], false); - $orderItem->save(false); - } - - public function testFindNullValues() - { - // https://github.com/yiisoft/yii2/issues/1311 - $this->markTestSkipped('Redis does not store/find null values correctly.'); - } - - public function testBooleanAttribute() - { - // https://github.com/yiisoft/yii2/issues/1311 - $this->markTestSkipped('Redis does not store/find boolean values correctly.'); - } - - public function testFindEagerViaRelationPreserveOrder() - { - $this->markTestSkipped('Redis does not support orderBy.'); - } - - public function testFindEagerViaRelationPreserveOrderB() - { - $this->markTestSkipped('Redis does not support orderBy.'); - } - - public function testSatisticalFind() - { - // find count, sum, average, min, max, scalar - $this->assertEquals(3, Customer::find()->count()); - $this->assertEquals(6, Customer::find()->sum('id')); - $this->assertEquals(2, Customer::find()->average('id')); - $this->assertEquals(1, Customer::find()->min('id')); - $this->assertEquals(3, Customer::find()->max('id')); - - $this->assertEquals(6, OrderItem::find()->count()); - $this->assertEquals(7, OrderItem::find()->sum('quantity')); - } - - public function testfindIndexBy() - { - $customerClass = $this->getCustomerClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - // indexBy - $customers = $this->callCustomerFind()->indexBy('name')/*->orderBy('id')*/->all(); - $this->assertEquals(3, count($customers)); - $this->assertTrue($customers['user1'] instanceof $customerClass); - $this->assertTrue($customers['user2'] instanceof $customerClass); - $this->assertTrue($customers['user3'] instanceof $customerClass); - - // indexBy callable - $customers = $this->callCustomerFind()->indexBy(function ($customer) { - return $customer->id . '-' . $customer->name; - })/*->orderBy('id')*/->all(); // TODO this test is duplicated because of missing orderBy support in redis - $this->assertEquals(3, count($customers)); - $this->assertTrue($customers['1-user1'] instanceof $customerClass); - $this->assertTrue($customers['2-user2'] instanceof $customerClass); - $this->assertTrue($customers['3-user3'] instanceof $customerClass); - } - - public function testFindLimit() - { - // TODO this test is duplicated because of missing orderBy support in redis - /** @var TestCase|ActiveRecordTestTrait $this */ - // all() - $customers = $this->callCustomerFind()->all(); - $this->assertEquals(3, count($customers)); - - $customers = $this->callCustomerFind()/*->orderBy('id')*/->limit(1)->all(); - $this->assertEquals(1, count($customers)); - $this->assertEquals('user1', $customers[0]->name); - - $customers = $this->callCustomerFind()/*->orderBy('id')*/->limit(1)->offset(1)->all(); - $this->assertEquals(1, count($customers)); - $this->assertEquals('user2', $customers[0]->name); - - $customers = $this->callCustomerFind()/*->orderBy('id')*/->limit(1)->offset(2)->all(); - $this->assertEquals(1, count($customers)); - $this->assertEquals('user3', $customers[0]->name); - - $customers = $this->callCustomerFind()/*->orderBy('id')*/->limit(2)->offset(1)->all(); - $this->assertEquals(2, count($customers)); - $this->assertEquals('user2', $customers[0]->name); - $this->assertEquals('user3', $customers[1]->name); - - $customers = $this->callCustomerFind()->limit(2)->offset(3)->all(); - $this->assertEquals(0, count($customers)); - - // one() - $customer = $this->callCustomerFind()/*->orderBy('id')*/->one(); - $this->assertEquals('user1', $customer->name); - - $customer = $this->callCustomerFind()/*->orderBy('id')*/->offset(0)->one(); - $this->assertEquals('user1', $customer->name); - - $customer = $this->callCustomerFind()/*->orderBy('id')*/->offset(1)->one(); - $this->assertEquals('user2', $customer->name); - - $customer = $this->callCustomerFind()/*->orderBy('id')*/->offset(2)->one(); - $this->assertEquals('user3', $customer->name); - - $customer = $this->callCustomerFind()->offset(3)->one(); - $this->assertNull($customer); - } - - public function testFindEagerViaRelation() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - $orders = $this->callOrderFind()->with('items')/*->orderBy('id')*/->all(); // TODO this test is duplicated because of missing orderBy support in redis - $this->assertEquals(3, count($orders)); - $order = $orders[0]; - $this->assertEquals(1, $order->id); - $this->assertEquals(2, count($order->items)); - $this->assertEquals(1, $order->items[0]->id); - $this->assertEquals(2, $order->items[1]->id); - } - - public function testFindColumn() - { - $this->assertEquals(['user1', 'user2', 'user3'], Customer::find()->column('name')); -// TODO $this->assertEquals(['user3', 'user2', 'user1'], Customer::find()->orderBy(['name' => SORT_DESC])->column('name')); - } - - // TODO test serial column incr - - public function testUpdatePk() - { - // updateCounters - $pk = ['order_id' => 2, 'item_id' => 4]; - $orderItem = OrderItem::find($pk); - $this->assertEquals(2, $orderItem->order_id); - $this->assertEquals(4, $orderItem->item_id); - - $orderItem->order_id = 2; - $orderItem->item_id = 10; - $orderItem->save(); - - $this->assertNull(OrderItem::find($pk)); - $this->assertNotNull(OrderItem::find(['order_id' => 2, 'item_id' => 10])); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/redis/RedisCacheTest.php b/tests/unit/extensions/redis/RedisCacheTest.php deleted file mode 100644 index 4122947..0000000 --- a/tests/unit/extensions/redis/RedisCacheTest.php +++ /dev/null @@ -1,101 +0,0 @@ -getParam('databases'); - $params = isset($databases['redis']) ? $databases['redis'] : null; - if ($params === null) { - $this->markTestSkipped('No redis server connection configured.'); - } - $connection = new Connection($params); - if(!@stream_socket_client($connection->hostname . ':' . $connection->port, $errorNumber, $errorDescription, 0.5)) { - $this->markTestSkipped('No redis server running at ' . $connection->hostname . ':' . $connection->port . ' : ' . $errorNumber . ' - ' . $errorDescription); - } - - $this->mockApplication(['components' => ['redis' => $connection]]); - - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new Cache(); - } - return $this->_cacheInstance; - } - - public function testExpireMilliseconds() - { - $cache = $this->getCacheInstance(); - - $this->assertTrue($cache->set('expire_test_ms', 'expire_test_ms', 0.2)); - usleep(100000); - $this->assertEquals('expire_test_ms', $cache->get('expire_test_ms')); - usleep(300000); - $this->assertFalse($cache->get('expire_test_ms')); - } - - public function testExpireAddMilliseconds() - { - $cache = $this->getCacheInstance(); - - $this->assertTrue($cache->add('expire_testa_ms', 'expire_testa_ms', 0.2)); - usleep(100000); - $this->assertEquals('expire_testa_ms', $cache->get('expire_testa_ms')); - usleep(300000); - $this->assertFalse($cache->get('expire_testa_ms')); - } - - /** - * Store a value that is 2 times buffer size big - * https://github.com/yiisoft/yii2/issues/743 - */ - public function testLargeData() - { - $cache = $this->getCacheInstance(); - - $data=str_repeat('XX',8192); // http://www.php.net/manual/en/function.fread.php - $key='bigdata1'; - - $this->assertFalse($cache->get($key)); - $cache->set($key,$data); - $this->assertTrue($cache->get($key)===$data); - - // try with multibyte string - $data=str_repeat('ЖЫ',8192); // http://www.php.net/manual/en/function.fread.php - $key='bigdata2'; - - $this->assertFalse($cache->get($key)); - $cache->set($key,$data); - $this->assertTrue($cache->get($key)===$data); - } - - public function testMultiByteGetAndSet() - { - $cache = $this->getCacheInstance(); - - $data=['abc'=>'ежик',2=>'def']; - $key='data1'; - - $this->assertFalse($cache->get($key)); - $cache->set($key,$data); - $this->assertTrue($cache->get($key)===$data); - } - -} diff --git a/tests/unit/extensions/redis/RedisConnectionTest.php b/tests/unit/extensions/redis/RedisConnectionTest.php deleted file mode 100644 index 7a6bd91..0000000 --- a/tests/unit/extensions/redis/RedisConnectionTest.php +++ /dev/null @@ -1,58 +0,0 @@ -getConnection(false); - $db->open(); - $this->assertTrue($db->ping()); - $db->set('YIITESTKEY', 'YIITESTVALUE'); - $db->close(); - - $db = $this->getConnection(false); - $db->database = 0; - $db->open(); - $this->assertEquals('YIITESTVALUE', $db->get('YIITESTKEY')); - $db->close(); - - $db = $this->getConnection(false); - $db->database = 1; - $db->open(); - $this->assertNull($db->get('YIITESTKEY')); - $db->close(); - } - - public function keyValueData() - { - return array( - array(123), - array(-123), - array(0), - array('test'), - array("test\r\ntest"), - array(''), - ); - } - - /** - * @dataProvider keyValueData - */ - public function testStoreGet($data) - { - $db = $this->getConnection(true); - - $db->set('hi', $data); - $this->assertEquals($data, $db->get('hi')); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/redis/RedisTestCase.php b/tests/unit/extensions/redis/RedisTestCase.php deleted file mode 100644 index fd37a10..0000000 --- a/tests/unit/extensions/redis/RedisTestCase.php +++ /dev/null @@ -1,48 +0,0 @@ -getParam('databases'); - $params = isset($databases['redis']) ? $databases['redis'] : null; - if ($params === null) { - $this->markTestSkipped('No redis server connection configured.'); - } - $connection = new Connection($params); - if(!@stream_socket_client($connection->hostname . ':' . $connection->port, $errorNumber, $errorDescription, 0.5)) { - $this->markTestSkipped('No redis server running at ' . $connection->hostname . ':' . $connection->port . ' : ' . $errorNumber . ' - ' . $errorDescription); - } - - $this->mockApplication(['components' => ['redis' => $connection]]); - - parent::setUp(); - } - - /** - * @param bool $reset whether to clean up the test database - * @return Connection - */ - public function getConnection($reset = true) - { - $databases = $this->getParam('databases'); - $params = isset($databases['redis']) ? $databases['redis'] : []; - $db = new Connection($params); - if ($reset) { - $db->open(); - $db->flushdb(); - } - return $db; - } -} diff --git a/tests/unit/extensions/sphinx/ActiveDataProviderTest.php b/tests/unit/extensions/sphinx/ActiveDataProviderTest.php deleted file mode 100644 index dbf8184..0000000 --- a/tests/unit/extensions/sphinx/ActiveDataProviderTest.php +++ /dev/null @@ -1,66 +0,0 @@ -getConnection(); - } - - // Tests : - - public function testQuery() - { - $query = new Query; - $query->from('yii2_test_article_index'); - - $provider = new ActiveDataProvider([ - 'query' => $query, - 'db' => $this->getConnection(), - ]); - $models = $provider->getModels(); - $this->assertEquals(2, count($models)); - - $provider = new ActiveDataProvider([ - 'query' => $query, - 'db' => $this->getConnection(), - 'pagination' => [ - 'pageSize' => 1, - ] - ]); - $models = $provider->getModels(); - $this->assertEquals(1, count($models)); - } - - public function testActiveQuery() - { - $provider = new ActiveDataProvider([ - 'query' => ArticleIndex::find()->orderBy('id ASC'), - ]); - $models = $provider->getModels(); - $this->assertEquals(2, count($models)); - $this->assertTrue($models[0] instanceof ArticleIndex); - $this->assertTrue($models[1] instanceof ArticleIndex); - $this->assertEquals([1, 2], $provider->getKeys()); - - $provider = new ActiveDataProvider([ - 'query' => ArticleIndex::find(), - 'pagination' => [ - 'pageSize' => 1, - ] - ]); - $models = $provider->getModels(); - $this->assertEquals(1, count($models)); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/sphinx/ActiveRecordTest.php b/tests/unit/extensions/sphinx/ActiveRecordTest.php deleted file mode 100644 index 67afe27..0000000 --- a/tests/unit/extensions/sphinx/ActiveRecordTest.php +++ /dev/null @@ -1,237 +0,0 @@ -getConnection(); - } - - protected function tearDown() - { - $this->truncateRuntimeIndex('yii2_test_rt_index'); - parent::tearDown(); - } - - // Tests : - - public function testFind() - { - // find one - $result = ArticleIndex::find(); - $this->assertTrue($result instanceof ActiveQuery); - $article = $result->one(); - $this->assertTrue($article instanceof ArticleIndex); - - // find all - $articles = ArticleIndex::find()->all(); - $this->assertEquals(2, count($articles)); - $this->assertTrue($articles[0] instanceof ArticleIndex); - $this->assertTrue($articles[1] instanceof ArticleIndex); - - // find fulltext - $article = ArticleIndex::find(2); - $this->assertTrue($article instanceof ArticleIndex); - $this->assertEquals(2, $article->id); - - // find by column values - $article = ArticleIndex::find(['id' => 2, 'author_id' => 2]); - $this->assertTrue($article instanceof ArticleIndex); - $this->assertEquals(2, $article->id); - $this->assertEquals(2, $article->author_id); - $article = ArticleIndex::find(['id' => 2, 'author_id' => 1]); - $this->assertNull($article); - - // find by attributes - $article = ArticleIndex::find()->where(['author_id' => 2])->one(); - $this->assertTrue($article instanceof ArticleIndex); - $this->assertEquals(2, $article->id); - - // find custom column - $article = ArticleIndex::find()->select(['*', '(5*2) AS custom_column']) - ->where(['author_id' => 1])->one(); - $this->assertEquals(1, $article->id); - $this->assertEquals(10, $article->custom_column); - - // find count, sum, average, min, max, scalar - $this->assertEquals(2, ArticleIndex::find()->count()); - $this->assertEquals(1, ArticleIndex::find()->where('id=1')->count()); - $this->assertEquals(3, ArticleIndex::find()->sum('id')); - $this->assertEquals(1.5, ArticleIndex::find()->average('id')); - $this->assertEquals(1, ArticleIndex::find()->min('id')); - $this->assertEquals(2, ArticleIndex::find()->max('id')); - $this->assertEquals(2, ArticleIndex::find()->select('COUNT(*)')->scalar()); - - // scope - $this->assertEquals(1, ArticleIndex::find()->favoriteAuthor()->count()); - - // asArray - $article = ArticleIndex::find()->where('id=2')->asArray()->one(); - unset($article['add_date']); - $this->assertEquals([ - 'id' => '2', - 'author_id' => '2', - 'tag' => '3,4', - ], $article); - - // indexBy - $articles = ArticleIndex::find()->indexBy('author_id')->orderBy('id DESC')->all(); - $this->assertEquals(2, count($articles)); - $this->assertTrue($articles['1'] instanceof ArticleIndex); - $this->assertTrue($articles['2'] instanceof ArticleIndex); - - // indexBy callable - $articles = ArticleIndex::find()->indexBy(function ($article) { - return $article->id . '-' . $article->author_id; - })->orderBy('id DESC')->all(); - $this->assertEquals(2, count($articles)); - $this->assertTrue($articles['1-1'] instanceof ArticleIndex); - $this->assertTrue($articles['2-2'] instanceof ArticleIndex); - } - - public function testFindBySql() - { - // find one - $article = ArticleIndex::findBySql('SELECT * FROM yii2_test_article_index ORDER BY id DESC')->one(); - $this->assertTrue($article instanceof ArticleIndex); - $this->assertEquals(2, $article->author_id); - - // find all - $articles = ArticleIndex::findBySql('SELECT * FROM yii2_test_article_index')->all(); - $this->assertEquals(2, count($articles)); - - // find with parameter binding - $article = ArticleIndex::findBySql('SELECT * FROM yii2_test_article_index WHERE id=:id', [':id' => 2])->one(); - $this->assertTrue($article instanceof ArticleIndex); - $this->assertEquals(2, $article->author_id); - } - - public function testInsert() - { - $record = new RuntimeIndex; - $record->id = 15; - $record->title = 'test title'; - $record->content = 'test content'; - $record->type_id = 7; - $record->category = [1, 2]; - - $this->assertTrue($record->isNewRecord); - - $record->save(); - - $this->assertEquals(15, $record->id); - $this->assertFalse($record->isNewRecord); - } - - /** - * @depends testInsert - */ - public function testUpdate() - { - $record = new RuntimeIndex; - $record->id = 2; - $record->title = 'test title'; - $record->content = 'test content'; - $record->type_id = 7; - $record->category = [1, 2]; - $record->save(); - - // save - $record = RuntimeIndex::find(['id' => 2]); - $this->assertTrue($record instanceof RuntimeIndex); - $this->assertEquals(7, $record->type_id); - $this->assertFalse($record->isNewRecord); - - $record->type_id = 9; - $record->save(); - $this->assertEquals(9, $record->type_id); - $this->assertFalse($record->isNewRecord); - $record2 = RuntimeIndex::find(['id' => 2]); - $this->assertEquals(9, $record2->type_id); - - // replace - $query = 'replace'; - $rows = RuntimeIndex::find($query); - $this->assertEmpty($rows); - $record = RuntimeIndex::find(['id' => 2]); - $record->content = 'Test content with ' . $query; - $record->save(); - $rows = RuntimeIndex::find()->match($query); - $this->assertNotEmpty($rows); - - // updateAll - $pk = ['id' => 2]; - $ret = RuntimeIndex::updateAll(['type_id' => 55], $pk); - $this->assertEquals(1, $ret); - $record = RuntimeIndex::find($pk); - $this->assertEquals(55, $record->type_id); - } - - /** - * @depends testInsert - */ - public function testDelete() - { - // delete - $record = new RuntimeIndex; - $record->id = 2; - $record->title = 'test title'; - $record->content = 'test content'; - $record->type_id = 7; - $record->category = [1, 2]; - $record->save(); - - $record = RuntimeIndex::find(['id' => 2]); - $record->delete(); - $record = RuntimeIndex::find(['id' => 2]); - $this->assertNull($record); - - // deleteAll - $record = new RuntimeIndex; - $record->id = 2; - $record->title = 'test title'; - $record->content = 'test content'; - $record->type_id = 7; - $record->category = [1, 2]; - $record->save(); - - $ret = RuntimeIndex::deleteAll('id = 2'); - $this->assertEquals(1, $ret); - $records = RuntimeIndex::find()->all(); - $this->assertEquals(0, count($records)); - } - - public function testCallSnippets() - { - $query = 'pencil'; - $source = 'Some data sentence about ' . $query; - - $snippet = ArticleIndex::callSnippets($source, $query); - $this->assertNotEmpty($snippet, 'Unable to call snippets!'); - $this->assertContains('' . $query . '', $snippet, 'Query not present in the snippet!'); - - $rows = ArticleIndex::callSnippets([$source], $query); - $this->assertNotEmpty($rows, 'Unable to call snippets!'); - $this->assertContains('' . $query . '', $rows[0], 'Query not present in the snippet!'); - } - - public function testCallKeywords() - { - $text = 'table pencil'; - $rows = ArticleIndex::callKeywords($text); - $this->assertNotEmpty($rows, 'Unable to call keywords!'); - $this->assertArrayHasKey('tokenized', $rows[0], 'No tokenized keyword!'); - $this->assertArrayHasKey('normalized', $rows[0], 'No normalized keyword!'); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/sphinx/ActiveRelationTest.php b/tests/unit/extensions/sphinx/ActiveRelationTest.php deleted file mode 100644 index d85c6b9..0000000 --- a/tests/unit/extensions/sphinx/ActiveRelationTest.php +++ /dev/null @@ -1,45 +0,0 @@ -getConnection(); - ActiveRecordDb::$db = $this->getDbConnection(); - } - - // Tests : - - public function testFindLazy() - { - /** @var ArticleDb $article */ - $article = ArticleDb::find(['id' => 2]); - $this->assertFalse($article->isRelationPopulated('index')); - $index = $article->index; - $this->assertTrue($article->isRelationPopulated('index')); - $this->assertTrue($index instanceof ArticleIndex); - $this->assertEquals(1, count($article->relatedRecords)); - $this->assertEquals($article->id, $index->id); - } - - public function testFindEager() - { - $articles = ArticleDb::find()->with('index')->all(); - $this->assertEquals(2, count($articles)); - $this->assertTrue($articles[0]->isRelationPopulated('index')); - $this->assertTrue($articles[1]->isRelationPopulated('index')); - $this->assertTrue($articles[0]->index instanceof ArticleIndex); - $this->assertTrue($articles[1]->index instanceof ArticleIndex); - } -} diff --git a/tests/unit/extensions/sphinx/ColumnSchemaTest.php b/tests/unit/extensions/sphinx/ColumnSchemaTest.php deleted file mode 100644 index 7d62c1d..0000000 --- a/tests/unit/extensions/sphinx/ColumnSchemaTest.php +++ /dev/null @@ -1,55 +0,0 @@ -type = $type; - $columnSchema->phpType = $phpType; - $this->assertEquals($expectedResult, $columnSchema->typecast($value)); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/sphinx/CommandTest.php b/tests/unit/extensions/sphinx/CommandTest.php deleted file mode 100644 index b2346ef..0000000 --- a/tests/unit/extensions/sphinx/CommandTest.php +++ /dev/null @@ -1,409 +0,0 @@ -truncateRuntimeIndex('yii2_test_rt_index'); - parent::tearDown(); - } - - // Tests : - - public function testConstruct() - { - $db = $this->getConnection(false); - - // null - $command = $db->createCommand(); - $this->assertEquals(null, $command->sql); - - // string - $sql = 'SELECT * FROM yii2_test_item_index'; - $params = [ - 'name' => 'value' - ]; - $command = $db->createCommand($sql, $params); - $this->assertEquals($sql, $command->sql); - $this->assertEquals($params, $command->params); - } - - public function testGetSetSql() - { - $db = $this->getConnection(false); - - $sql = 'SELECT * FROM yii2_test_item_index'; - $command = $db->createCommand($sql); - $this->assertEquals($sql, $command->sql); - - $sql2 = 'SELECT * FROM yii2_test_item_index'; - $command->sql = $sql2; - $this->assertEquals($sql2, $command->sql); - } - - public function testAutoQuoting() - { - $db = $this->getConnection(false); - - $sql = 'SELECT [[id]], [[t.name]] FROM {{yii2_test_item_index}} t'; - $command = $db->createCommand($sql); - $this->assertEquals("SELECT `id`, `t`.`name` FROM `yii2_test_item_index` t", $command->sql); - } - - public function testPrepareCancel() - { - $db = $this->getConnection(false); - - $command = $db->createCommand('SELECT * FROM yii2_test_item_index'); - $this->assertEquals(null, $command->pdoStatement); - $command->prepare(); - $this->assertNotEquals(null, $command->pdoStatement); - $command->cancel(); - $this->assertEquals(null, $command->pdoStatement); - } - - public function testExecute() - { - $db = $this->getConnection(); - - $sql = 'SELECT COUNT(*) FROM yii2_test_item_index WHERE MATCH(\'wooden\')'; - $command = $db->createCommand($sql); - $this->assertEquals(1, $command->queryScalar()); - - $command = $db->createCommand('bad SQL'); - $this->setExpectedException('\yii\db\Exception'); - $command->execute(); - } - - public function testQuery() - { - $db = $this->getConnection(); - - // query - $sql = 'SELECT * FROM yii2_test_item_index'; - $reader = $db->createCommand($sql)->query(); - $this->assertTrue($reader instanceof DataReader); - - // queryAll - $rows = $db->createCommand('SELECT * FROM yii2_test_item_index')->queryAll(); - $this->assertEquals(2, count($rows)); - $row = $rows[1]; - $this->assertEquals(2, $row['id']); - $this->assertEquals(2, $row['category_id']); - - $rows = $db->createCommand('SELECT * FROM yii2_test_item_index WHERE id=10')->queryAll(); - $this->assertEquals([], $rows); - - // queryOne - $sql = 'SELECT * FROM yii2_test_item_index ORDER BY id ASC'; - $row = $db->createCommand($sql)->queryOne(); - $this->assertEquals(1, $row['id']); - $this->assertEquals(1, $row['category_id']); - - $sql = 'SELECT * FROM yii2_test_item_index ORDER BY id ASC'; - $command = $db->createCommand($sql); - $command->prepare(); - $row = $command->queryOne(); - $this->assertEquals(1, $row['id']); - $this->assertEquals(1, $row['category_id']); - - $sql = 'SELECT * FROM yii2_test_item_index WHERE id=10'; - $command = $db->createCommand($sql); - $this->assertFalse($command->queryOne()); - - // queryColumn - $sql = 'SELECT * FROM yii2_test_item_index'; - $column = $db->createCommand($sql)->queryColumn(); - $this->assertEquals(range(1, 2), $column); - - $command = $db->createCommand('SELECT id FROM yii2_test_item_index WHERE id=10'); - $this->assertEquals([], $command->queryColumn()); - - // queryScalar - $sql = 'SELECT * FROM yii2_test_item_index ORDER BY id ASC'; - $this->assertEquals($db->createCommand($sql)->queryScalar(), 1); - - $sql = 'SELECT id FROM yii2_test_item_index ORDER BY id ASC'; - $command = $db->createCommand($sql); - $command->prepare(); - $this->assertEquals(1, $command->queryScalar()); - - $command = $db->createCommand('SELECT id FROM yii2_test_item_index WHERE id=10'); - $this->assertFalse($command->queryScalar()); - - $command = $db->createCommand('bad SQL'); - $this->setExpectedException('\yii\db\Exception'); - $command->query(); - } - - /** - * @depends testQuery - */ - public function testInsert() - { - $db = $this->getConnection(); - - $command = $db->createCommand()->insert('yii2_test_rt_index', [ - 'title' => 'Test title', - 'content' => 'Test content', - 'type_id' => 2, - 'category' => [1, 2], - 'id' => 1, - ]); - $this->assertEquals(1, $command->execute(), 'Unable to execute insert!'); - - $rows = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll(); - $this->assertEquals(1, count($rows), 'No row inserted!'); - } - - /** - * @depends testInsert - */ - public function testBatchInsert() - { - $db = $this->getConnection(); - - $command = $db->createCommand()->batchInsert( - 'yii2_test_rt_index', - [ - 'title', - 'content', - 'type_id', - 'category', - 'id', - ], - [ - [ - 'Test title 1', - 'Test content 1', - 1, - [1, 2], - 1, - ], - [ - 'Test title 2', - 'Test content 2', - 2, - [3, 4], - 2, - ], - ] - ); - $this->assertEquals(2, $command->execute(), 'Unable to execute batch insert!'); - - $rows = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll(); - $this->assertEquals(2, count($rows), 'No rows inserted!'); - } - - /** - * @depends testInsert - */ - public function testReplace() - { - $db = $this->getConnection(); - - $command = $db->createCommand()->replace('yii2_test_rt_index', [ - 'title' => 'Test title', - 'content' => 'Test content', - 'type_id' => 2, - 'category' => [1, 2], - 'id' => 1, - ]); - $this->assertEquals(1, $command->execute(), 'Unable to execute replace!'); - - $rows = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll(); - $this->assertEquals(1, count($rows), 'No row inserted!'); - - $newTypeId = 5; - $command = $db->createCommand()->replace('yii2_test_rt_index',[ - 'type_id' => $newTypeId, - 'category' => [3, 4], - 'id' => 1, - ]); - $this->assertEquals(1, $command->execute(), 'Unable to update via replace!'); - - list($row) = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll(); - $this->assertEquals($newTypeId, $row['type_id'], 'Unable to update attribute value!'); - } - - /** - * @depends testReplace - */ - public function testBatchReplace() - { - $db = $this->getConnection(); - - $command = $db->createCommand()->batchReplace( - 'yii2_test_rt_index', - [ - 'title', - 'content', - 'type_id', - 'category', - 'id', - ], - [ - [ - 'Test title 1', - 'Test content 1', - 1, - [1, 2], - 1, - ], - [ - 'Test title 2', - 'Test content 2', - 2, - [3, 4], - 2, - ], - ] - ); - $this->assertEquals(2, $command->execute(), 'Unable to execute batch replace!'); - - $rows = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll(); - $this->assertEquals(2, count($rows), 'No rows inserted!'); - - $newTypeId = 5; - $command = $db->createCommand()->replace('yii2_test_rt_index',[ - 'type_id' => $newTypeId, - 'id' => 1, - ]); - $this->assertEquals(1, $command->execute(), 'Unable to update via replace!'); - list($row) = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll(); - $this->assertEquals($newTypeId, $row['type_id'], 'Unable to update attribute value!'); - } - - /** - * @depends testInsert - */ - public function testUpdate() - { - $db = $this->getConnection(); - - $db->createCommand()->insert('yii2_test_rt_index', [ - 'title' => 'Test title', - 'content' => 'Test content', - 'type_id' => 2, - 'id' => 1, - ])->execute(); - - $newTypeId = 5; - $command = $db->createCommand()->update( - 'yii2_test_rt_index', - [ - 'type_id' => $newTypeId, - 'category' => [3, 4], - ], - 'id = 1' - ); - $this->assertEquals(1, $command->execute(), 'Unable to execute update!'); - - list($row) = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll(); - $this->assertEquals($newTypeId, $row['type_id'], 'Unable to update attribute value!'); - } - - /** - * @depends testUpdate - */ - public function testUpdateWithOptions() - { - $db = $this->getConnection(); - - $db->createCommand()->insert('yii2_test_rt_index', [ - 'title' => 'Test title', - 'content' => 'Test content', - 'type_id' => 2, - 'id' => 1, - ])->execute(); - - $newTypeId = 5; - $command = $db->createCommand()->update( - 'yii2_test_rt_index', - [ - 'type_id' => $newTypeId, - 'non_existing_attribute' => 10, - ], - 'id = 1', - [], - [ - 'ignore_nonexistent_columns' => 1 - ] - ); - $this->assertEquals(1, $command->execute(), 'Unable to execute update!'); - } - - /** - * @depends testInsert - */ - public function testDelete() - { - $db = $this->getConnection(); - - $db->createCommand()->insert('yii2_test_rt_index', [ - 'title' => 'Test title', - 'content' => 'Test content', - 'type_id' => 2, - 'id' => 1, - ])->execute(); - - $command = $db->createCommand()->delete('yii2_test_rt_index', 'id = 1'); - $this->assertEquals(1, $command->execute(), 'Unable to execute delete!'); - - $rows = $db->createCommand('SELECT * FROM yii2_test_rt_index')->queryAll(); - $this->assertEquals(0, count($rows), 'Unable to delete record!'); - } - - /** - * @depends testQuery - */ - public function testCallSnippets() - { - $db = $this->getConnection(); - - $query = 'pencil'; - $source = 'Some data sentence about ' . $query; - - $rows = $db->createCommand()->callSnippets('yii2_test_item_index', $source, $query)->queryColumn(); - $this->assertNotEmpty($rows, 'Unable to call snippets!'); - $this->assertContains('' . $query . '', $rows[0], 'Query not present in the snippet!'); - - $rows = $db->createCommand()->callSnippets('yii2_test_item_index', [$source], $query)->queryColumn(); - $this->assertNotEmpty($rows, 'Unable to call snippets for array source!'); - - $options = [ - 'before_match' => '[', - 'after_match' => ']', - 'limit' => 20, - ]; - $snippet = $db->createCommand()->callSnippets('yii2_test_item_index', $source, $query, $options)->queryScalar(); - $this->assertContains($options['before_match'] . $query . $options['after_match'], $snippet, 'Unable to apply options!'); - } - - /** - * @depends testQuery - */ - public function testCallKeywords() - { - $db = $this->getConnection(); - - $text = 'table pencil'; - $rows = $db->createCommand()->callKeywords('yii2_test_item_index', $text)->queryAll(); - $this->assertNotEmpty($rows, 'Unable to call keywords!'); - $this->assertArrayHasKey('tokenized', $rows[0], 'No tokenized keyword!'); - $this->assertArrayHasKey('normalized', $rows[0], 'No normalized keyword!'); - - $text = 'table pencil'; - $rows = $db->createCommand()->callKeywords('yii2_test_item_index', $text, true)->queryAll(); - $this->assertNotEmpty($rows, 'Unable to call keywords with statistic!'); - $this->assertArrayHasKey('docs', $rows[0], 'No docs!'); - $this->assertArrayHasKey('hits', $rows[0], 'No hits!'); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/sphinx/ConnectionTest.php b/tests/unit/extensions/sphinx/ConnectionTest.php deleted file mode 100644 index 803f627..0000000 --- a/tests/unit/extensions/sphinx/ConnectionTest.php +++ /dev/null @@ -1,42 +0,0 @@ -getConnection(false); - $params = $this->sphinxConfig; - - $this->assertEquals($params['dsn'], $connection->dsn); - $this->assertEquals($params['username'], $connection->username); - $this->assertEquals($params['password'], $connection->password); - } - - public function testOpenClose() - { - $connection = $this->getConnection(false, false); - - $this->assertFalse($connection->isActive); - $this->assertEquals(null, $connection->pdo); - - $connection->open(); - $this->assertTrue($connection->isActive); - $this->assertTrue($connection->pdo instanceof \PDO); - - $connection->close(); - $this->assertFalse($connection->isActive); - $this->assertEquals(null, $connection->pdo); - - $connection = new Connection; - $connection->dsn = 'unknown::memory:'; - $this->setExpectedException('yii\db\Exception'); - $connection->open(); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/sphinx/ExternalActiveRelationTest.php b/tests/unit/extensions/sphinx/ExternalActiveRelationTest.php deleted file mode 100644 index 1740c42..0000000 --- a/tests/unit/extensions/sphinx/ExternalActiveRelationTest.php +++ /dev/null @@ -1,74 +0,0 @@ -getConnection(); - ActiveRecordDb::$db = $this->getDbConnection(); - } - - // Tests : - - public function testFindLazy() - { - /** @var ArticleIndex $article */ - $article = ArticleIndex::find(['id' => 2]); - - // has one : - $this->assertFalse($article->isRelationPopulated('source')); - $source = $article->source; - $this->assertTrue($article->isRelationPopulated('source')); - $this->assertTrue($source instanceof ArticleDb); - $this->assertEquals(1, count($article->relatedRecords)); - - // has many : - /*$this->assertFalse($article->isRelationPopulated('tags')); - $tags = $article->tags; - $this->assertTrue($article->isRelationPopulated('tags')); - $this->assertEquals(3, count($tags)); - $this->assertTrue($tags[0] instanceof TagDb);*/ - } - - public function testFindEager() - { - // has one : - $articles = ArticleIndex::find()->with('source')->all(); - $this->assertEquals(2, count($articles)); - $this->assertTrue($articles[0]->isRelationPopulated('source')); - $this->assertTrue($articles[1]->isRelationPopulated('source')); - $this->assertTrue($articles[0]->source instanceof ArticleDb); - $this->assertTrue($articles[1]->source instanceof ArticleDb); - - // has many : - /*$articles = ArticleIndex::find()->with('tags')->all(); - $this->assertEquals(2, count($articles)); - $this->assertTrue($articles[0]->isRelationPopulated('tags')); - $this->assertTrue($articles[1]->isRelationPopulated('tags'));*/ - } - - /** - * @depends testFindEager - */ - public function testFindWithSnippets() - { - $articles = ArticleIndex::find() - ->match('about') - ->with('source') - ->snippetByModel() - ->all(); - $this->assertEquals(2, count($articles)); - } -} diff --git a/tests/unit/extensions/sphinx/QueryTest.php b/tests/unit/extensions/sphinx/QueryTest.php deleted file mode 100644 index 59a8595..0000000 --- a/tests/unit/extensions/sphinx/QueryTest.php +++ /dev/null @@ -1,187 +0,0 @@ -select('*'); - $this->assertEquals(['*'], $query->select); - $this->assertNull($query->distinct); - $this->assertEquals(null, $query->selectOption); - - $query = new Query; - $query->select('id, name', 'something')->distinct(true); - $this->assertEquals(['id', 'name'], $query->select); - $this->assertTrue($query->distinct); - $this->assertEquals('something', $query->selectOption); - } - - public function testFrom() - { - $query = new Query; - $query->from('tbl_user'); - $this->assertEquals(['tbl_user'], $query->from); - } - - public function testMatch() - { - $query = new Query; - $match = 'test match'; - $query->match($match); - $this->assertEquals($match, $query->match); - - $command = $query->createCommand($this->getConnection(false)); - $this->assertContains('MATCH(', $command->getSql(), 'No MATCH operator present!'); - $this->assertContains($match, $command->params, 'No match query among params!'); - } - - public function testWhere() - { - $query = new Query; - $query->where('id = :id', [':id' => 1]); - $this->assertEquals('id = :id', $query->where); - $this->assertEquals([':id' => 1], $query->params); - - $query->andWhere('name = :name', [':name' => 'something']); - $this->assertEquals(['and', 'id = :id', 'name = :name'], $query->where); - $this->assertEquals([':id' => 1, ':name' => 'something'], $query->params); - - $query->orWhere('age = :age', [':age' => '30']); - $this->assertEquals(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->where); - $this->assertEquals([':id' => 1, ':name' => 'something', ':age' => '30'], $query->params); - } - - public function testGroup() - { - $query = new Query; - $query->groupBy('team'); - $this->assertEquals(['team'], $query->groupBy); - - $query->addGroupBy('company'); - $this->assertEquals(['team', 'company'], $query->groupBy); - - $query->addGroupBy('age'); - $this->assertEquals(['team', 'company', 'age'], $query->groupBy); - } - - public function testOrder() - { - $query = new Query; - $query->orderBy('team'); - $this->assertEquals(['team' => SORT_ASC], $query->orderBy); - - $query->addOrderBy('company'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC], $query->orderBy); - - $query->addOrderBy('age'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_ASC], $query->orderBy); - - $query->addOrderBy(['age' => SORT_DESC]); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_DESC], $query->orderBy); - - $query->addOrderBy('age ASC, company DESC'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_DESC, 'age' => SORT_ASC], $query->orderBy); - } - - public function testLimitOffset() - { - $query = new Query; - $query->limit(10)->offset(5); - $this->assertEquals(10, $query->limit); - $this->assertEquals(5, $query->offset); - } - - public function testWithin() - { - $query = new Query; - $query->within('team'); - $this->assertEquals(['team' => SORT_ASC], $query->within); - - $query->addWithin('company'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC], $query->within); - - $query->addWithin('age'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_ASC], $query->within); - - $query->addWithin(['age' => SORT_DESC]); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_DESC], $query->within); - - $query->addWithin('age ASC, company DESC'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_DESC, 'age' => SORT_ASC], $query->within); - } - - public function testOptions() - { - $query = new Query; - $options = [ - 'cutoff' => 50, - 'max_matches' => 50, - ]; - $query->options($options); - $this->assertEquals($options, $query->options); - - $newMaxMatches = $options['max_matches'] + 10; - $query->addOptions(['max_matches' => $newMaxMatches]); - $this->assertEquals($newMaxMatches, $query->options['max_matches']); - } - - public function testRun() - { - $connection = $this->getConnection(); - - $query = new Query; - $rows = $query->from('yii2_test_article_index') - ->match('about') - ->options([ - 'cutoff' => 50, - 'field_weights' => [ - 'title' => 10, - 'content' => 3, - ], - ]) - ->all($connection); - $this->assertNotEmpty($rows); - } - - /** - * @depends testRun - */ - public function testSnippet() - { - $connection = $this->getConnection(); - - $match = 'about'; - $snippetPrefix = 'snippet#'; - $snippetCallback = function() use ($match, $snippetPrefix) { - return [ - $snippetPrefix . '1: ' . $match, - $snippetPrefix . '2: ' . $match, - ]; - }; - $snippetOptions = [ - 'before_match' => '[', - 'after_match' => ']', - ]; - - $query = new Query; - $rows = $query->from('yii2_test_article_index') - ->match($match) - ->snippetCallback($snippetCallback) - ->snippetOptions($snippetOptions) - ->all($connection); - $this->assertNotEmpty($rows); - foreach ($rows as $row) { - $this->assertContains($snippetPrefix, $row['snippet'], 'Snippet source not present!'); - $this->assertContains($snippetOptions['before_match'] . $match, $row['snippet'] . $snippetOptions['after_match'], 'Options not applied!'); - } - } -} \ No newline at end of file diff --git a/tests/unit/extensions/sphinx/SchemaTest.php b/tests/unit/extensions/sphinx/SchemaTest.php deleted file mode 100644 index 2cc3ff9..0000000 --- a/tests/unit/extensions/sphinx/SchemaTest.php +++ /dev/null @@ -1,84 +0,0 @@ -getConnection()->schema; - - $indexes = $schema->getIndexNames(); - $this->assertContains('yii2_test_article_index', $indexes); - $this->assertContains('yii2_test_item_index', $indexes); - $this->assertContains('yii2_test_rt_index', $indexes); - } - - public function testGetIndexSchemas() - { - $schema = $this->getConnection()->schema; - - $indexes = $schema->getIndexSchemas(); - $this->assertEquals(count($schema->getIndexNames()), count($indexes)); - foreach($indexes as $index) { - $this->assertInstanceOf('yii\sphinx\IndexSchema', $index); - } - } - - public function testGetNonExistingIndexSchema() - { - $this->assertNull($this->getConnection()->schema->getIndexSchema('non_existing_index')); - } - - public function testSchemaRefresh() - { - $schema = $this->getConnection()->schema; - - $schema->db->enableSchemaCache = true; - $schema->db->schemaCache = new FileCache(); - $noCacheIndex = $schema->getIndexSchema('yii2_test_rt_index', true); - $cachedIndex = $schema->getIndexSchema('yii2_test_rt_index', true); - $this->assertEquals($noCacheIndex, $cachedIndex); - } - - public function testGetPDOType() - { - $values = [ - [null, \PDO::PARAM_NULL], - ['', \PDO::PARAM_STR], - ['hello', \PDO::PARAM_STR], - [0, \PDO::PARAM_INT], - [1, \PDO::PARAM_INT], - [1337, \PDO::PARAM_INT], - [true, \PDO::PARAM_BOOL], - [false, \PDO::PARAM_BOOL], - [$fp=fopen(__FILE__, 'rb'), \PDO::PARAM_LOB], - ]; - - $schema = $this->getConnection()->schema; - - foreach($values as $value) { - $this->assertEquals($value[1], $schema->getPdoType($value[0])); - } - fclose($fp); - } - - public function testIndexType() - { - $schema = $this->getConnection()->schema; - - $index = $schema->getIndexSchema('yii2_test_article_index'); - $this->assertEquals('local', $index->type); - $this->assertFalse($index->isRuntime); - - $index = $schema->getIndexSchema('yii2_test_rt_index'); - $this->assertEquals('rt', $index->type); - $this->assertTrue($index->isRuntime); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/sphinx/SphinxTestCase.php b/tests/unit/extensions/sphinx/SphinxTestCase.php deleted file mode 100644 index c8c2ae5..0000000 --- a/tests/unit/extensions/sphinx/SphinxTestCase.php +++ /dev/null @@ -1,154 +0,0 @@ - 'mysql:host=127.0.0.1;port=9306;', - 'username' => '', - 'password' => '', - ]; - /** - * @var Connection Sphinx connection instance. - */ - protected $sphinx; - /** - * @var array Database connection configuration. - */ - protected $dbConfig = [ - 'dsn' => 'mysql:host=127.0.0.1;', - 'username' => '', - 'password' => '', - ]; - /** - * @var \yii\db\Connection database connection instance. - */ - protected $db; - - public static function setUpBeforeClass() - { - static::loadClassMap(); - } - - protected function setUp() - { - parent::setUp(); - if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) { - $this->markTestSkipped('pdo and pdo_mysql extension are required.'); - } - $config = $this->getParam('sphinx'); - if (!empty($config)) { - $this->sphinxConfig = $config['sphinx']; - $this->dbConfig = $config['db']; - } - $this->mockApplication(); - static::loadClassMap(); - } - - protected function tearDown() - { - if ($this->sphinx) { - $this->sphinx->close(); - } - $this->destroyApplication(); - } - - /** - * Adds sphinx extension files to [[Yii::$classPath]], - * avoiding the necessity of usage Composer autoloader. - */ - protected static function loadClassMap() - { - $baseNameSpace = 'yii/sphinx'; - $basePath = realpath(__DIR__. '/../../../../extensions/yii/sphinx'); - $files = FileHelper::findFiles($basePath); - foreach ($files as $file) { - $classRelativePath = str_replace($basePath, '', $file); - $classFullName = str_replace(['/', '.php'], ['\\', ''], $baseNameSpace . $classRelativePath); - Yii::$classMap[$classFullName] = $file; - } - } - - /** - * @param bool $reset whether to clean up the test database - * @param bool $open whether to open test database - * @return \yii\sphinx\Connection - */ - public function getConnection($reset = false, $open = true) - { - if (!$reset && $this->sphinx) { - return $this->sphinx; - } - $db = new Connection; - $db->dsn = $this->sphinxConfig['dsn']; - if (isset($this->sphinxConfig['username'])) { - $db->username = $this->sphinxConfig['username']; - $db->password = $this->sphinxConfig['password']; - } - if (isset($this->sphinxConfig['attributes'])) { - $db->attributes = $this->sphinxConfig['attributes']; - } - if ($open) { - $db->open(); - } - $this->sphinx = $db; - return $db; - } - - /** - * Truncates the runtime index. - * @param string $indexName index name. - */ - protected function truncateRuntimeIndex($indexName) - { - if ($this->sphinx) { - $this->sphinx->createCommand('TRUNCATE RTINDEX ' . $indexName)->execute(); - } - } - - /** - * @param bool $reset whether to clean up the test database - * @param bool $open whether to open and populate test database - * @return \yii\db\Connection - */ - public function getDbConnection($reset = true, $open = true) - { - if (!$reset && $this->db) { - return $this->db; - } - $db = new \yii\db\Connection; - $db->dsn = $this->dbConfig['dsn']; - if (isset($this->dbConfig['username'])) { - $db->username = $this->dbConfig['username']; - $db->password = $this->dbConfig['password']; - } - if (isset($this->dbConfig['attributes'])) { - $db->attributes = $this->dbConfig['attributes']; - } - if ($open) { - $db->open(); - if (!empty($this->dbConfig['fixture'])) { - $lines = explode(';', file_get_contents($this->dbConfig['fixture'])); - foreach ($lines as $line) { - if (trim($line) !== '') { - $db->pdo->exec($line); - } - } - } - } - $this->db = $db; - return $db; - } -} diff --git a/tests/unit/extensions/swiftmailer/MailerTest.php b/tests/unit/extensions/swiftmailer/MailerTest.php deleted file mode 100644 index 90edeaf..0000000 --- a/tests/unit/extensions/swiftmailer/MailerTest.php +++ /dev/null @@ -1,124 +0,0 @@ -mockApplication([ - 'components' => [ - 'email' => $this->createTestEmailComponent() - ] - ]); - } - - /** - * @return Mailer test email component instance. - */ - protected function createTestEmailComponent() - { - $component = new Mailer(); - return $component; - } - - // Tests : - - public function testSetupTransport() - { - $mailer = new Mailer(); - - $transport = \Swift_MailTransport::newInstance(); - $mailer->setTransport($transport); - $this->assertEquals($transport, $mailer->getTransport(), 'Unable to setup transport!'); - } - - /** - * @depends testSetupTransport - */ - public function testConfigureTransport() - { - $mailer = new Mailer(); - - $transportConfig = [ - 'class' => 'Swift_SmtpTransport', - 'host' => 'localhost', - 'username' => 'username', - 'password' => 'password', - ]; - $mailer->setTransport($transportConfig); - $transport = $mailer->getTransport(); - $this->assertTrue(is_object($transport), 'Unable to setup transport via config!'); - $this->assertEquals($transportConfig['class'], get_class($transport), 'Invalid transport class!'); - $this->assertEquals($transportConfig['host'], $transport->getHost(), 'Invalid transport host!'); - } - - /** - * @depends testConfigureTransport - */ - public function testConfigureTransportConstruct() - { - $mailer = new Mailer(); - - $class = 'Swift_SmtpTransport'; - $host = 'some.test.host'; - $port = 999; - $transportConfig = [ - 'class' => $class, - 'constructArgs' => [ - $host, - $port, - ], - ]; - $mailer->setTransport($transportConfig); - $transport = $mailer->getTransport(); - $this->assertTrue(is_object($transport), 'Unable to setup transport via config!'); - $this->assertEquals($class, get_class($transport), 'Invalid transport class!'); - $this->assertEquals($host, $transport->getHost(), 'Invalid transport host!'); - $this->assertEquals($port, $transport->getPort(), 'Invalid transport host!'); - } - - /** - * @depends testConfigureTransportConstruct - */ - public function testConfigureTransportWithPlugins() - { - $mailer = new Mailer(); - - $pluginClass = 'Swift_Plugins_ThrottlerPlugin'; - $rate = 10; - - $transportConfig = [ - 'class' => 'Swift_SmtpTransport', - 'plugins' => [ - [ - 'class' => $pluginClass, - 'constructArgs' => [ - $rate, - ], - ], - ], - ]; - $mailer->setTransport($transportConfig); - $transport = $mailer->getTransport(); - $this->assertTrue(is_object($transport), 'Unable to setup transport via config!'); - $this->assertContains(':' . $pluginClass . ':', print_r($transport, true), 'Plugin not added'); - } - - public function testGetSwiftMailer() - { - $mailer = new Mailer(); - $this->assertTrue(is_object($mailer->getSwiftMailer()), 'Unable to get Swift mailer instance!'); - } -} diff --git a/tests/unit/extensions/swiftmailer/MessageTest.php b/tests/unit/extensions/swiftmailer/MessageTest.php deleted file mode 100644 index b095cf0..0000000 --- a/tests/unit/extensions/swiftmailer/MessageTest.php +++ /dev/null @@ -1,363 +0,0 @@ -mockApplication([ - 'components' => [ - 'mail' => $this->createTestEmailComponent() - ] - ]); - $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 createTestEmailComponent() - { - $component = new Mailer([ - 'useFileTransport' => true, - ]); - return $component; - } - - /** - * @return Message test message instance. - */ - protected function createTestMessage() - { - return Yii::$app->getComponent('mail')->compose(); - } - - /** - * Creates image file with given text. - * @param string $fileName file name. - * @param string $text text to be applied on image. - * @return string image file full name. - */ - protected function createImageFile($fileName = 'test.jpg', $text = 'Test Image') - { - if (!function_exists('imagecreatetruecolor')) { - $this->markTestSkipped('GD lib required.'); - } - $fileFullName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . $fileName; - $image = imagecreatetruecolor(120, 20); - $textColor = imagecolorallocate($image, 233, 14, 91); - imagestring($image, 1, 5, 5, $text, $textColor); - imagejpeg($image, $fileFullName); - imagedestroy($image); - return $fileFullName; - } - - /** - * Finds the attachment object in the message. - * @param Message $message message instance - * @return null|\Swift_Mime_Attachment attachment instance. - */ - protected function getAttachment(Message $message) - { - $messageParts = $message->getSwiftMessage()->getChildren(); - $attachment = null; - foreach ($messageParts as $part) { - if ($part instanceof \Swift_Mime_Attachment) { - $attachment = $part; - break; - } - } - return $attachment; - } - - // Tests : - - public function testGetSwiftMessage() - { - $message = new Message(); - $this->assertTrue(is_object($message->getSwiftMessage()), 'Unable to get Swift message!'); - } - - /** - * @depends testGetSwiftMessage - */ - public function testSetGet() - { - $message = new Message(); - - $charset = 'utf-16'; - $message->setCharset($charset); - $this->assertEquals($charset, $message->getCharset(), 'Unable to set charset!'); - - $subject = 'Test Subject'; - $message->setSubject($subject); - $this->assertEquals($subject, $message->getSubject(), 'Unable to set subject!'); - - $from = 'from@somedomain.com'; - $message->setFrom($from); - $this->assertContains($from, array_keys($message->getFrom()), 'Unable to set from!'); - - $replyTo = 'reply-to@somedomain.com'; - $message->setReplyTo($replyTo); - $this->assertContains($replyTo, array_keys($message->getReplyTo()), 'Unable to set replyTo!'); - - $to = 'someuser@somedomain.com'; - $message->setTo($to); - $this->assertContains($to, array_keys($message->getTo()), 'Unable to set to!'); - - $cc = 'ccuser@somedomain.com'; - $message->setCc($cc); - $this->assertContains($cc, array_keys($message->getCc()), 'Unable to set cc!'); - - $bcc = 'bccuser@somedomain.com'; - $message->setBcc($bcc); - $this->assertContains($bcc, array_keys($message->getBcc()), 'Unable to set bcc!'); - } - - /** - * @depends testGetSwiftMessage - */ - public function testSetupHeaders() - { - $charset = 'utf-16'; - $subject = 'Test Subject'; - $from = 'from@somedomain.com'; - $replyTo = 'reply-to@somedomain.com'; - $to = 'someuser@somedomain.com'; - $cc = 'ccuser@somedomain.com'; - $bcc = 'bccuser@somedomain.com'; - - $messageString = $this->createTestMessage() - ->setCharset($charset) - ->setSubject($subject) - ->setFrom($from) - ->setReplyTo($replyTo) - ->setTo($to) - ->setCc($cc) - ->setBcc($bcc) - ->toString(); - - $this->assertContains('charset=' . $charset, $messageString, 'Incorrect charset!'); - $this->assertContains('Subject: ' . $subject, $messageString, 'Incorrect "Subject" header!'); - $this->assertContains('From: ' . $from, $messageString, 'Incorrect "From" header!'); - $this->assertContains('Reply-To: ' . $replyTo, $messageString, 'Incorrect "Reply-To" header!'); - $this->assertContains('To: ' . $to, $messageString, 'Incorrect "To" header!'); - $this->assertContains('Cc: ' . $cc, $messageString, 'Incorrect "Cc" header!'); - $this->assertContains('Bcc: ' . $bcc, $messageString, 'Incorrect "Bcc" header!'); - } - - /** - * @depends testGetSwiftMessage - */ - public function testSend() - { - $message = $this->createTestMessage(); - $message->setTo($this->testEmailReceiver); - $message->setFrom('someuser@somedomain.com'); - $message->setSubject('Yii Swift Test'); - $message->setTextBody('Yii Swift Test body'); - $this->assertTrue($message->send()); - } - - /** - * @depends testSend - */ - public function testAttachFile() - { - $message = $this->createTestMessage(); - - $message->setTo($this->testEmailReceiver); - $message->setFrom('someuser@somedomain.com'); - $message->setSubject('Yii Swift Attach File Test'); - $message->setTextBody('Yii Swift Attach File Test body'); - $fileName = __FILE__; - $message->attach($fileName); - - $this->assertTrue($message->send()); - - $attachment = $this->getAttachment($message); - $this->assertTrue(is_object($attachment), 'No attachment found!'); - $this->assertContains($attachment->getFilename(), $fileName, 'Invalid file name!'); - } - - /** - * @depends testSend - */ - public function testAttachContent() - { - $message = $this->createTestMessage(); - - $message->setTo($this->testEmailReceiver); - $message->setFrom('someuser@somedomain.com'); - $message->setSubject('Yii Swift Create Attachment Test'); - $message->setTextBody('Yii Swift Create Attachment Test body'); - $fileName = 'test.txt'; - $fileContent = 'Test attachment content'; - $message->attachContent($fileContent, ['fileName' => $fileName]); - - $this->assertTrue($message->send()); - - $attachment = $this->getAttachment($message); - $this->assertTrue(is_object($attachment), 'No attachment found!'); - $this->assertEquals($fileName, $attachment->getFilename(), 'Invalid file name!'); - } - - /** - * @depends testSend - */ - public function testEmbedFile() - { - $fileName = $this->createImageFile('embed_file.jpg', 'Embed Image File'); - - $message = $this->createTestMessage(); - - $cid = $message->embed($fileName); - - $message->setTo($this->testEmailReceiver); - $message->setFrom('someuser@somedomain.com'); - $message->setSubject('Yii Swift Embed File Test'); - $message->setHtmlBody('Embed image: pic'); - - $this->assertTrue($message->send()); - - $attachment = $this->getAttachment($message); - $this->assertTrue(is_object($attachment), 'No attachment found!'); - $this->assertContains($attachment->getFilename(), $fileName, 'Invalid file name!'); - } - - /** - * @depends testSend - */ - public function testEmbedContent() - { - $fileFullName = $this->createImageFile('embed_file.jpg', 'Embed Image File'); - $message = $this->createTestMessage(); - - $fileName = basename($fileFullName); - $contentType = 'image/jpeg'; - $fileContent = file_get_contents($fileFullName); - - $cid = $message->embedContent($fileContent, ['fileName' => $fileName, 'contentType' => $contentType]); - - $message->setTo($this->testEmailReceiver); - $message->setFrom('someuser@somedomain.com'); - $message->setSubject('Yii Swift Embed File Test'); - $message->setHtmlBody('Embed image: pic'); - - $this->assertTrue($message->send()); - - $attachment = $this->getAttachment($message); - $this->assertTrue(is_object($attachment), 'No attachment found!'); - $this->assertEquals($fileName, $attachment->getFilename(), 'Invalid file name!'); - $this->assertEquals($contentType, $attachment->getContentType(), 'Invalid content type!'); - } - - /** - * @depends testSend - */ - public function testSendAlternativeBody() - { - $message = $this->createTestMessage(); - - $message->setTo($this->testEmailReceiver); - $message->setFrom('someuser@somedomain.com'); - $message->setSubject('Yii Swift Alternative Body Test'); - $message->setHtmlBody('Yii Swift test HTML body'); - $message->setTextBody('Yii Swift test plain text body'); - - $this->assertTrue($message->send()); - - $messageParts = $message->getSwiftMessage()->getChildren(); - $textPresent = false; - $htmlPresent = false; - foreach ($messageParts as $part) { - if (!($part instanceof \Swift_Mime_Attachment)) { - /* @var \Swift_Mime_MimePart $part */ - if ($part->getContentType() == 'text/plain') { - $textPresent = true; - } - if ($part->getContentType() == 'text/html') { - $htmlPresent = true; - } - } - } - $this->assertTrue($textPresent, 'No text!'); - $this->assertTrue($htmlPresent, 'No HTML!'); - } - - /** - * @depends testGetSwiftMessage - */ - public function testSerialize() - { - $message = $this->createTestMessage(); - - $message->setTo($this->testEmailReceiver); - $message->setFrom('someuser@somedomain.com'); - $message->setSubject('Yii Swift Alternative Body Test'); - $message->setTextBody('Yii Swift test plain text body'); - - $serializedMessage = serialize($message); - $this->assertNotEmpty($serializedMessage, 'Unable to serialize message!'); - - $unserializedMessaage = unserialize($serializedMessage); - $this->assertEquals($message, $unserializedMessaage, 'Unable to unserialize message!'); - } - - /** - * @depends testSendAlternativeBody - */ - public function testAlternativeBodyCharset() - { - $message = $this->createTestMessage(); - $charset = 'windows-1251'; - $message->setCharset($charset); - - $message->setTextBody('some text'); - $message->setHtmlBody('some html'); - $content = $message->toString(); - $this->assertEquals(2, substr_count($content, $charset), 'Wrong charset for alternative body.'); - - $message->setTextBody('some text override'); - $content = $message->toString(); - $this->assertEquals(2, substr_count($content, $charset), 'Wrong charset for alternative body override.'); - } -} diff --git a/tests/unit/extensions/twig/ViewRendererTest.php b/tests/unit/extensions/twig/ViewRendererTest.php deleted file mode 100644 index 88ca9f7..0000000 --- a/tests/unit/extensions/twig/ViewRendererTest.php +++ /dev/null @@ -1,74 +0,0 @@ - - */ - -namespace yiiunit\extensions\twig; - - -use yii\web\AssetManager; -use yii\web\JqueryAsset; -use yii\web\View; -use Yii; -use yiiunit\TestCase; - -/** - * @group twig - */ -class ViewRendererTest extends TestCase -{ - protected function setUp() - { - $this->mockApplication(); - } - - /** - * https://github.com/yiisoft/yii2/issues/1755 - */ - public function testLayoutAssets() - { - $view = $this->mockView(); - JqueryAsset::register($view); - $content = $view->renderFile('@yiiunit/extensions/twig/views/layout.twig'); - - $this->assertEquals(1, preg_match('#\s*#', $content), 'content does not contain the jquery js:' . $content); - } - - protected function mockView() - { - return new View([ - 'renderers' => [ - 'twig' => [ - 'class' => 'yii\twig\ViewRenderer', - //'cachePath' => '@runtime/Twig/cache', - 'options' => [ - 'cache' => false - ], - 'globals' => [ - 'html' => '\yii\helpers\Html', - 'pos_begin' => View::POS_BEGIN - ], - 'functions' => [ - 't' => '\Yii::t', - 'json_encode' => '\yii\helpers\Json::encode' - ] - ], - ], - 'assetManager' => $this->mockAssetManager(), - ]); - } - - protected function mockAssetManager() - { - $assetDir = Yii::getAlias('@runtime/assets'); - if (!is_dir($assetDir)) { - mkdir($assetDir, 0777, true); - } - return new AssetManager([ - 'basePath' => $assetDir, - 'baseUrl' => '/assets', - ]); - } -} \ No newline at end of file diff --git a/tests/unit/extensions/twig/views/layout.twig b/tests/unit/extensions/twig/views/layout.twig deleted file mode 100644 index 7a53832..0000000 --- a/tests/unit/extensions/twig/views/layout.twig +++ /dev/null @@ -1,14 +0,0 @@ -{{ this.beginPage() }} - - - - - {{ html.encode(this.title) }} - {{ this.head() }} - - -{{ this.beginBody() }} - body -{{ this.endBody() }} - -{{ this.endPage() }} diff --git a/tests/unit/framework/BaseYiiTest.php b/tests/unit/framework/BaseYiiTest.php deleted file mode 100644 index 6011f6b..0000000 --- a/tests/unit/framework/BaseYiiTest.php +++ /dev/null @@ -1,63 +0,0 @@ -aliases = Yii::$aliases; - } - - protected function tearDown() - { - parent::tearDown(); - Yii::$aliases = $this->aliases; - } - - public function testAlias() - { - $this->assertEquals(YII_PATH, Yii::getAlias('@yii')); - - Yii::$aliases = []; - $this->assertFalse(Yii::getAlias('@yii', false)); - - Yii::setAlias('@yii', '/yii/framework'); - $this->assertEquals('/yii/framework', Yii::getAlias('@yii')); - $this->assertEquals('/yii/framework/test/file', Yii::getAlias('@yii/test/file')); - Yii::setAlias('@yii/gii', '/yii/gii'); - $this->assertEquals('/yii/framework', Yii::getAlias('@yii')); - $this->assertEquals('/yii/framework/test/file', Yii::getAlias('@yii/test/file')); - $this->assertEquals('/yii/gii', Yii::getAlias('@yii/gii')); - $this->assertEquals('/yii/gii/file', Yii::getAlias('@yii/gii/file')); - - Yii::setAlias('@tii', '@yii/test'); - $this->assertEquals('/yii/framework/test', Yii::getAlias('@tii')); - - Yii::setAlias('@yii', null); - $this->assertFalse(Yii::getAlias('@yii', false)); - $this->assertEquals('/yii/gii/file', Yii::getAlias('@yii/gii/file')); - - Yii::setAlias('@some/alias', '/www'); - $this->assertEquals('/www', Yii::getAlias('@some/alias')); - } - - public function testGetVersion() - { - $this->assertTrue((boolean)preg_match('~\d+\.\d+(?:\.\d+)?(?:-\w+)?~', \Yii::getVersion())); - } - - public function testPowered() - { - $this->assertTrue(is_string(Yii::powered())); - } -} diff --git a/tests/unit/framework/ar/ActiveRecordTestTrait.php b/tests/unit/framework/ar/ActiveRecordTestTrait.php deleted file mode 100644 index 959b8c9..0000000 --- a/tests/unit/framework/ar/ActiveRecordTestTrait.php +++ /dev/null @@ -1,838 +0,0 @@ - - */ - -namespace yiiunit\framework\ar; - -use yii\db\ActiveQueryInterface; -use yiiunit\TestCase; -use yiiunit\data\ar\Customer; -use yiiunit\data\ar\Order; - -/** - * This trait provides unit tests shared by the differen AR implementations - * - * @var TestCase $this - */ -trait ActiveRecordTestTrait -{ - /** - * This method should call Customer::find($q) - * @param $q - * @return mixed - */ - public abstract function callCustomerFind($q = null); - - /** - * This method should call Order::find($q) - * @param $q - * @return mixed - */ - public abstract function callOrderFind($q = null); - - /** - * This method should call OrderItem::find($q) - * @param $q - * @return mixed - */ - public abstract function callOrderItemFind($q = null); - - /** - * This method should call Item::find($q) - * @param $q - * @return mixed - */ - public abstract function callItemFind($q = null); - - /** - * This method should return the classname of Customer class - * @return string - */ - public abstract function getCustomerClass(); - - /** - * This method should return the classname of Order class - * @return string - */ - public abstract function getOrderClass(); - - /** - * This method should return the classname of OrderItem class - * @return string - */ - public abstract function getOrderItemClass(); - - /** - * This method should return the classname of Item class - * @return string - */ - public abstract function getItemClass(); - - /** - * can be overridden to do things after save() - */ - public function afterSave() - { - } - - - public function testFind() - { - $customerClass = $this->getCustomerClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - // find one - $result = $this->callCustomerFind(); - $this->assertTrue($result instanceof ActiveQueryInterface); - $customer = $result->one(); - $this->assertTrue($customer instanceof $customerClass); - - // find all - $customers = $this->callCustomerFind()->all(); - $this->assertEquals(3, count($customers)); - $this->assertTrue($customers[0] instanceof $customerClass); - $this->assertTrue($customers[1] instanceof $customerClass); - $this->assertTrue($customers[2] instanceof $customerClass); - - // find all asArray - $customers = $this->callCustomerFind()->asArray()->all(); - $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers[0]); - $this->assertArrayHasKey('name', $customers[0]); - $this->assertArrayHasKey('email', $customers[0]); - $this->assertArrayHasKey('address', $customers[0]); - $this->assertArrayHasKey('status', $customers[0]); - $this->assertArrayHasKey('id', $customers[1]); - $this->assertArrayHasKey('name', $customers[1]); - $this->assertArrayHasKey('email', $customers[1]); - $this->assertArrayHasKey('address', $customers[1]); - $this->assertArrayHasKey('status', $customers[1]); - $this->assertArrayHasKey('id', $customers[2]); - $this->assertArrayHasKey('name', $customers[2]); - $this->assertArrayHasKey('email', $customers[2]); - $this->assertArrayHasKey('address', $customers[2]); - $this->assertArrayHasKey('status', $customers[2]); - - // find by a single primary key - $customer = $this->callCustomerFind(2); - $this->assertTrue($customer instanceof $customerClass); - $this->assertEquals('user2', $customer->name); - $customer = $this->callCustomerFind(5); - $this->assertNull($customer); - $customer = $this->callCustomerFind(['id' => [5, 6, 1]]); - $this->assertEquals(1, count($customer)); - $customer = $this->callCustomerFind()->where(['id' => [5, 6, 1]])->one(); - $this->assertNotNull($customer); - - // find by column values - $customer = $this->callCustomerFind(['id' => 2, 'name' => 'user2']); - $this->assertTrue($customer instanceof $customerClass); - $this->assertEquals('user2', $customer->name); - $customer = $this->callCustomerFind(['id' => 2, 'name' => 'user1']); - $this->assertNull($customer); - $customer = $this->callCustomerFind(['id' => 5]); - $this->assertNull($customer); - $customer = $this->callCustomerFind(['name' => 'user5']); - $this->assertNull($customer); - - // find by attributes - $customer = $this->callCustomerFind()->where(['name' => 'user2'])->one(); - $this->assertTrue($customer instanceof $customerClass); - $this->assertEquals(2, $customer->id); - - // scope - $this->assertEquals(2, count($this->callCustomerFind()->active()->all())); - $this->assertEquals(2, $this->callCustomerFind()->active()->count()); - } - - public function testFindAsArray() - { - // asArray - $customer = $this->callCustomerFind()->where(['id' => 2])->asArray()->one(); - $this->assertEquals([ - 'id' => '2', - 'email' => 'user2@example.com', - 'name' => 'user2', - 'address' => 'address2', - 'status' => '1', - ], $customer); - } - - public function testFindScalar() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - // query scalar - $customerName = $this->callCustomerFind()->where(['id' => 2])->scalar('name'); - $this->assertEquals('user2', $customerName); - $customerName = $this->callCustomerFind()->where(['status' => 2])->scalar('name'); - $this->assertEquals('user3', $customerName); - $customerName = $this->callCustomerFind()->where(['status' => 2])->scalar('noname'); - $this->assertNull($customerName); - $customerId = $this->callCustomerFind()->where(['status' => 2])->scalar('id'); - $this->assertEquals(3, $customerId); - } - - public function testFindColumn() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - $this->assertEquals(['user1', 'user2', 'user3'], $this->callCustomerFind()->orderBy(['name' => SORT_ASC])->column('name')); - $this->assertEquals(['user3', 'user2', 'user1'], $this->callCustomerFind()->orderBy(['name' => SORT_DESC])->column('name')); - } - - public function testfindIndexBy() - { - $customerClass = $this->getCustomerClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - // indexBy - $customers = $this->callCustomerFind()->indexBy('name')->orderBy('id')->all(); - $this->assertEquals(3, count($customers)); - $this->assertTrue($customers['user1'] instanceof $customerClass); - $this->assertTrue($customers['user2'] instanceof $customerClass); - $this->assertTrue($customers['user3'] instanceof $customerClass); - - // indexBy callable - $customers = $this->callCustomerFind()->indexBy(function ($customer) { - return $customer->id . '-' . $customer->name; - })->orderBy('id')->all(); - $this->assertEquals(3, count($customers)); - $this->assertTrue($customers['1-user1'] instanceof $customerClass); - $this->assertTrue($customers['2-user2'] instanceof $customerClass); - $this->assertTrue($customers['3-user3'] instanceof $customerClass); - } - - public function testfindIndexByAsArray() - { - $customerClass = $this->getCustomerClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - // indexBy + asArray - $customers = $this->callCustomerFind()->asArray()->indexBy('name')->all(); - $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers['user1']); - $this->assertArrayHasKey('name', $customers['user1']); - $this->assertArrayHasKey('email', $customers['user1']); - $this->assertArrayHasKey('address', $customers['user1']); - $this->assertArrayHasKey('status', $customers['user1']); - $this->assertArrayHasKey('id', $customers['user2']); - $this->assertArrayHasKey('name', $customers['user2']); - $this->assertArrayHasKey('email', $customers['user2']); - $this->assertArrayHasKey('address', $customers['user2']); - $this->assertArrayHasKey('status', $customers['user2']); - $this->assertArrayHasKey('id', $customers['user3']); - $this->assertArrayHasKey('name', $customers['user3']); - $this->assertArrayHasKey('email', $customers['user3']); - $this->assertArrayHasKey('address', $customers['user3']); - $this->assertArrayHasKey('status', $customers['user3']); - - // indexBy callable + asArray - $customers = $this->callCustomerFind()->indexBy(function ($customer) { - return $customer['id'] . '-' . $customer['name']; - })->asArray()->all(); - $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers['1-user1']); - $this->assertArrayHasKey('name', $customers['1-user1']); - $this->assertArrayHasKey('email', $customers['1-user1']); - $this->assertArrayHasKey('address', $customers['1-user1']); - $this->assertArrayHasKey('status', $customers['1-user1']); - $this->assertArrayHasKey('id', $customers['2-user2']); - $this->assertArrayHasKey('name', $customers['2-user2']); - $this->assertArrayHasKey('email', $customers['2-user2']); - $this->assertArrayHasKey('address', $customers['2-user2']); - $this->assertArrayHasKey('status', $customers['2-user2']); - $this->assertArrayHasKey('id', $customers['3-user3']); - $this->assertArrayHasKey('name', $customers['3-user3']); - $this->assertArrayHasKey('email', $customers['3-user3']); - $this->assertArrayHasKey('address', $customers['3-user3']); - $this->assertArrayHasKey('status', $customers['3-user3']); - } - - public function testRefresh() - { - $customerClass = $this->getCustomerClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - $customer = new $customerClass(); - $this->assertFalse($customer->refresh()); - - $customer = $this->callCustomerFind(1); - $customer->name = 'to be refreshed'; - $this->assertTrue($customer->refresh()); - $this->assertEquals('user1', $customer->name); - } - - public function testEquals() - { - $customerClass = $this->getCustomerClass(); - $itemClass = $this->getItemClass(); - - /** @var TestCase|ActiveRecordTestTrait $this */ - $customerA = new $customerClass(); - $customerB = new $customerClass(); - $this->assertFalse($customerA->equals($customerB)); - - $customerA = new $customerClass(); - $customerB = new $itemClass(); - $this->assertFalse($customerA->equals($customerB)); - - $customerA = $this->callCustomerFind(1); - $customerB = $this->callCustomerFind(2); - $this->assertFalse($customerA->equals($customerB)); - - $customerB = $this->callCustomerFind(1); - $this->assertTrue($customerA->equals($customerB)); - - $customerA = $this->callCustomerFind(1); - $customerB = $this->callItemFind(1); - $this->assertFalse($customerA->equals($customerB)); - } - - public function testFindCount() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - $this->assertEquals(3, $this->callCustomerFind()->count()); - - $this->assertEquals(1, $this->callCustomerFind()->where(['id' => 1])->count()); - $this->assertEquals(2, $this->callCustomerFind()->where(['id' => [1, 2]])->count()); - $this->assertEquals(2, $this->callCustomerFind()->where(['id' => [1, 2]])->offset(1)->count()); - $this->assertEquals(2, $this->callCustomerFind()->where(['id' => [1, 2]])->offset(2)->count()); - - // limit should have no effect on count() - $this->assertEquals(3, $this->callCustomerFind()->limit(1)->count()); - $this->assertEquals(3, $this->callCustomerFind()->limit(2)->count()); - $this->assertEquals(3, $this->callCustomerFind()->limit(10)->count()); - $this->assertEquals(3, $this->callCustomerFind()->offset(2)->limit(2)->count()); - } - - public function testFindLimit() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - // all() - $customers = $this->callCustomerFind()->all(); - $this->assertEquals(3, count($customers)); - - $customers = $this->callCustomerFind()->orderBy('id')->limit(1)->all(); - $this->assertEquals(1, count($customers)); - $this->assertEquals('user1', $customers[0]->name); - - $customers = $this->callCustomerFind()->orderBy('id')->limit(1)->offset(1)->all(); - $this->assertEquals(1, count($customers)); - $this->assertEquals('user2', $customers[0]->name); - - $customers = $this->callCustomerFind()->orderBy('id')->limit(1)->offset(2)->all(); - $this->assertEquals(1, count($customers)); - $this->assertEquals('user3', $customers[0]->name); - - $customers = $this->callCustomerFind()->orderBy('id')->limit(2)->offset(1)->all(); - $this->assertEquals(2, count($customers)); - $this->assertEquals('user2', $customers[0]->name); - $this->assertEquals('user3', $customers[1]->name); - - $customers = $this->callCustomerFind()->limit(2)->offset(3)->all(); - $this->assertEquals(0, count($customers)); - - // one() - $customer = $this->callCustomerFind()->orderBy('id')->one(); - $this->assertEquals('user1', $customer->name); - - $customer = $this->callCustomerFind()->orderBy('id')->offset(0)->one(); - $this->assertEquals('user1', $customer->name); - - $customer = $this->callCustomerFind()->orderBy('id')->offset(1)->one(); - $this->assertEquals('user2', $customer->name); - - $customer = $this->callCustomerFind()->orderBy('id')->offset(2)->one(); - $this->assertEquals('user3', $customer->name); - - $customer = $this->callCustomerFind()->offset(3)->one(); - $this->assertNull($customer); - - } - - public function testFindComplexCondition() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - $this->assertEquals(2, $this->callCustomerFind()->where(['OR', ['name' => 'user1'], ['name' => 'user2']])->count()); - $this->assertEquals(2, count($this->callCustomerFind()->where(['OR', ['name' => 'user1'], ['name' => 'user2']])->all())); - - $this->assertEquals(2, $this->callCustomerFind()->where(['name' => ['user1','user2']])->count()); - $this->assertEquals(2, count($this->callCustomerFind()->where(['name' => ['user1','user2']])->all())); - - $this->assertEquals(1, $this->callCustomerFind()->where(['AND', ['name' => ['user2','user3']], ['BETWEEN', 'status', 2, 4]])->count()); - $this->assertEquals(1, count($this->callCustomerFind()->where(['AND', ['name' => ['user2','user3']], ['BETWEEN', 'status', 2, 4]])->all())); - } - - public function testFindNullValues() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - $customer = $this->callCustomerFind(2); - $customer->name = null; - $customer->save(false); - $this->afterSave(); - - $result = $this->callCustomerFind()->where(['name' => null])->all(); - $this->assertEquals(1, count($result)); - $this->assertEquals(2, reset($result)->primaryKey); - } - - public function testExists() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - $this->assertTrue($this->callCustomerFind()->where(['id' => 2])->exists()); - $this->assertFalse($this->callCustomerFind()->where(['id' => 5])->exists()); - $this->assertTrue($this->callCustomerFind()->where(['name' => 'user1'])->exists()); - $this->assertFalse($this->callCustomerFind()->where(['name' => 'user5'])->exists()); - - $this->assertTrue($this->callCustomerFind()->where(['id' => [2,3]])->exists()); - $this->assertTrue($this->callCustomerFind()->where(['id' => [2,3]])->offset(1)->exists()); - $this->assertFalse($this->callCustomerFind()->where(['id' => [2,3]])->offset(2)->exists()); - } - - public function testFindLazy() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - $customer = $this->callCustomerFind(2); - $this->assertFalse($customer->isRelationPopulated('orders')); - $orders = $customer->orders; - $this->assertTrue($customer->isRelationPopulated('orders')); - $this->assertEquals(2, count($orders)); - $this->assertEquals(1, count($customer->relatedRecords)); - - /** @var Customer $customer */ - $customer = $this->callCustomerFind(2); - $this->assertFalse($customer->isRelationPopulated('orders')); - $orders = $customer->getOrders()->where(['id' => 3])->all(); - $this->assertFalse($customer->isRelationPopulated('orders')); - $this->assertEquals(0, count($customer->relatedRecords)); - - $this->assertEquals(1, count($orders)); - $this->assertEquals(3, $orders[0]->id); - } - - public function testFindEager() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - $customers = $this->callCustomerFind()->with('orders')->indexBy('id')->all(); - ksort($customers); - $this->assertEquals(3, count($customers)); - $this->assertTrue($customers[1]->isRelationPopulated('orders')); - $this->assertTrue($customers[2]->isRelationPopulated('orders')); - $this->assertTrue($customers[3]->isRelationPopulated('orders')); - $this->assertEquals(1, count($customers[1]->orders)); - $this->assertEquals(2, count($customers[2]->orders)); - $this->assertEquals(0, count($customers[3]->orders)); - - $customer = $this->callCustomerFind()->where(['id' => 1])->with('orders')->one(); - $this->assertTrue($customer->isRelationPopulated('orders')); - $this->assertEquals(1, count($customer->orders)); - $this->assertEquals(1, count($customer->relatedRecords)); - - // multiple with() calls - $orders = $this->callOrderFind()->with('customer', 'items')->all(); - $this->assertEquals(3, count($orders)); - $this->assertTrue($orders[0]->isRelationPopulated('customer')); - $this->assertTrue($orders[0]->isRelationPopulated('items')); - $orders = $this->callOrderFind()->with('customer')->with('items')->all(); - $this->assertEquals(3, count($orders)); - $this->assertTrue($orders[0]->isRelationPopulated('customer')); - $this->assertTrue($orders[0]->isRelationPopulated('items')); - } - - public function testFindLazyVia() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - /** @var Order $order */ - $order = $this->callOrderFind(1); - $this->assertEquals(1, $order->id); - $this->assertEquals(2, count($order->items)); - $this->assertEquals(1, $order->items[0]->id); - $this->assertEquals(2, $order->items[1]->id); - } - - public function testFindLazyVia2() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - /** @var Order $order */ - $order = $this->callOrderFind(1); - $order->id = 100; - $this->assertEquals([], $order->items); - } - - public function testFindEagerViaRelation() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - $orders = $this->callOrderFind()->with('items')->orderBy('id')->all(); - $this->assertEquals(3, count($orders)); - $order = $orders[0]; - $this->assertEquals(1, $order->id); - $this->assertTrue($order->isRelationPopulated('items')); - $this->assertEquals(2, count($order->items)); - $this->assertEquals(1, $order->items[0]->id); - $this->assertEquals(2, $order->items[1]->id); - } - - public function testFindNestedRelation() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - $customers = $this->callCustomerFind()->with('orders', 'orders.items')->indexBy('id')->all(); - ksort($customers); - $this->assertEquals(3, count($customers)); - $this->assertTrue($customers[1]->isRelationPopulated('orders')); - $this->assertTrue($customers[2]->isRelationPopulated('orders')); - $this->assertTrue($customers[3]->isRelationPopulated('orders')); - $this->assertEquals(1, count($customers[1]->orders)); - $this->assertEquals(2, count($customers[2]->orders)); - $this->assertEquals(0, count($customers[3]->orders)); - $this->assertTrue($customers[1]->orders[0]->isRelationPopulated('items')); - $this->assertTrue($customers[2]->orders[0]->isRelationPopulated('items')); - $this->assertTrue($customers[2]->orders[1]->isRelationPopulated('items')); - $this->assertEquals(2, count($customers[1]->orders[0]->items)); - $this->assertEquals(3, count($customers[2]->orders[0]->items)); - $this->assertEquals(1, count($customers[2]->orders[1]->items)); - } - - /** - * Ensure ActiveRelation does preserve order of items on find via() - * https://github.com/yiisoft/yii2/issues/1310 - */ - public function testFindEagerViaRelationPreserveOrder() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - - /* - Item (name, category_id) - Order (customer_id, create_time, total) - OrderItem (order_id, item_id, quantity, subtotal) - - Result should be the following: - - Order 1: 1, 1325282384, 110.0 - - orderItems: - OrderItem: 1, 1, 1, 30.0 - OrderItem: 1, 2, 2, 40.0 - - itemsInOrder: - Item 1: 'Agile Web Application Development with Yii1.1 and PHP5', 1 - Item 2: 'Yii 1.1 Application Development Cookbook', 1 - - Order 2: 2, 1325334482, 33.0 - - orderItems: - OrderItem: 2, 3, 1, 8.0 - OrderItem: 2, 4, 1, 10.0 - OrderItem: 2, 5, 1, 15.0 - - itemsInOrder: - Item 5: 'Cars', 2 - Item 3: 'Ice Age', 2 - Item 4: 'Toy Story', 2 - Order 3: 2, 1325502201, 40.0 - - orderItems: - OrderItem: 3, 2, 1, 40.0 - - itemsInOrder: - Item 3: 'Ice Age', 2 - */ - $orders = $this->callOrderFind()->with('itemsInOrder1')->orderBy('create_time')->all(); - $this->assertEquals(3, count($orders)); - - $order = $orders[0]; - $this->assertEquals(1, $order->id); - $this->assertTrue($order->isRelationPopulated('itemsInOrder1')); - $this->assertEquals(2, count($order->itemsInOrder1)); - $this->assertEquals(1, $order->itemsInOrder1[0]->id); - $this->assertEquals(2, $order->itemsInOrder1[1]->id); - - $order = $orders[1]; - $this->assertEquals(2, $order->id); - $this->assertTrue($order->isRelationPopulated('itemsInOrder1')); - $this->assertEquals(3, count($order->itemsInOrder1)); - $this->assertEquals(5, $order->itemsInOrder1[0]->id); - $this->assertEquals(3, $order->itemsInOrder1[1]->id); - $this->assertEquals(4, $order->itemsInOrder1[2]->id); - - $order = $orders[2]; - $this->assertEquals(3, $order->id); - $this->assertTrue($order->isRelationPopulated('itemsInOrder1')); - $this->assertEquals(1, count($order->itemsInOrder1)); - $this->assertEquals(2, $order->itemsInOrder1[0]->id); - } - - // different order in via table - public function testFindEagerViaRelationPreserveOrderB() - { - $orders = $this->callOrderFind()->with('itemsInOrder2')->orderBy('create_time')->all(); - $this->assertEquals(3, count($orders)); - - $order = $orders[0]; - $this->assertEquals(1, $order->id); - $this->assertTrue($order->isRelationPopulated('itemsInOrder2')); - $this->assertEquals(2, count($order->itemsInOrder2)); - $this->assertEquals(1, $order->itemsInOrder2[0]->id); - $this->assertEquals(2, $order->itemsInOrder2[1]->id); - - $order = $orders[1]; - $this->assertEquals(2, $order->id); - $this->assertTrue($order->isRelationPopulated('itemsInOrder2')); - $this->assertEquals(3, count($order->itemsInOrder2)); - $this->assertEquals(5, $order->itemsInOrder2[0]->id); - $this->assertEquals(3, $order->itemsInOrder2[1]->id); - $this->assertEquals(4, $order->itemsInOrder2[2]->id); - - $order = $orders[2]; - $this->assertEquals(3, $order->id); - $this->assertTrue($order->isRelationPopulated('itemsInOrder2')); - $this->assertEquals(1, count($order->itemsInOrder2)); - $this->assertEquals(2, $order->itemsInOrder2[0]->id); - } - - public function testLink() - { - $orderClass = $this->getOrderClass(); - $orderItemClass = $this->getOrderItemClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - $customer = $this->callCustomerFind(2); - $this->assertEquals(2, count($customer->orders)); - - // has many - $order = new $orderClass; - $order->total = 100; - $this->assertTrue($order->isNewRecord); - $customer->link('orders', $order); - $this->afterSave(); - $this->assertEquals(3, count($customer->orders)); - $this->assertFalse($order->isNewRecord); - $this->assertEquals(3, count($customer->getOrders()->all())); - $this->assertEquals(2, $order->customer_id); - - // belongs to - $order = new $orderClass; - $order->total = 100; - $this->assertTrue($order->isNewRecord); - $customer = $this->callCustomerFind(1); - $this->assertNull($order->customer); - $order->link('customer', $customer); - $this->assertFalse($order->isNewRecord); - $this->assertEquals(1, $order->customer_id); - $this->assertEquals(1, $order->customer->primaryKey); - - // via model - $order = $this->callOrderFind(1); - $this->assertEquals(2, count($order->items)); - $this->assertEquals(2, count($order->orderItems)); - $orderItem = $this->callOrderItemFind(['order_id' => 1, 'item_id' => 3]); - $this->assertNull($orderItem); - $item = $this->callItemFind(3); - $order->link('items', $item, ['quantity' => 10, 'subtotal' => 100]); - $this->afterSave(); - $this->assertEquals(3, count($order->items)); - $this->assertEquals(3, count($order->orderItems)); - $orderItem = $this->callOrderItemFind(['order_id' => 1, 'item_id' => 3]); - $this->assertTrue($orderItem instanceof $orderItemClass); - $this->assertEquals(10, $orderItem->quantity); - $this->assertEquals(100, $orderItem->subtotal); - } - - public function testUnlink() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - // has many - $customer = $this->callCustomerFind(2); - $this->assertEquals(2, count($customer->orders)); - $customer->unlink('orders', $customer->orders[1], true); - $this->afterSave(); - $this->assertEquals(1, count($customer->orders)); - $this->assertNull($this->callOrderFind(3)); - - // via model - $order = $this->callOrderFind(2); - $this->assertEquals(3, count($order->items)); - $this->assertEquals(3, count($order->orderItems)); - $order->unlink('items', $order->items[2], true); - $this->afterSave(); - $this->assertEquals(2, count($order->items)); - $this->assertEquals(2, count($order->orderItems)); - } - - public static $afterSaveNewRecord; - public static $afterSaveInsert; - - public function testInsert() - { - $customerClass = $this->getCustomerClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - $customer = new $customerClass; - $customer->email = 'user4@example.com'; - $customer->name = 'user4'; - $customer->address = 'address4'; - - $this->assertNull($customer->id); - $this->assertTrue($customer->isNewRecord); - static::$afterSaveNewRecord = null; - static::$afterSaveInsert = null; - - $customer->save(); - $this->afterSave(); - - $this->assertNotNull($customer->id); - $this->assertFalse(static::$afterSaveNewRecord); - $this->assertTrue(static::$afterSaveInsert); - $this->assertFalse($customer->isNewRecord); - } - - public function testUpdate() - { - $customerClass = $this->getCustomerClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - // save - $customer = $this->callCustomerFind(2); - $this->assertTrue($customer instanceof $customerClass); - $this->assertEquals('user2', $customer->name); - $this->assertFalse($customer->isNewRecord); - static::$afterSaveNewRecord = null; - static::$afterSaveInsert = null; - - $customer->name = 'user2x'; - $customer->save(); - $this->afterSave(); - $this->assertEquals('user2x', $customer->name); - $this->assertFalse($customer->isNewRecord); - $this->assertFalse(static::$afterSaveNewRecord); - $this->assertFalse(static::$afterSaveInsert); - $customer2 = $this->callCustomerFind(2); - $this->assertEquals('user2x', $customer2->name); - - // updateAll - $customer = $this->callCustomerFind(3); - $this->assertEquals('user3', $customer->name); - $ret = $customerClass::updateAll(['name' => 'temp'], ['id' => 3]); - $this->afterSave(); - $this->assertEquals(1, $ret); - $customer = $this->callCustomerFind(3); - $this->assertEquals('temp', $customer->name); - - $ret = $customerClass::updateAll(['name' => 'tempX']); - $this->afterSave(); - $this->assertEquals(3, $ret); - - $ret = $customerClass::updateAll(['name' => 'temp'], ['name' => 'user6']); - $this->afterSave(); - $this->assertEquals(0, $ret); - } - - public function testUpdateAttributes() - { - $customerClass = $this->getCustomerClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - // save - $customer = $this->callCustomerFind(2); - $this->assertTrue($customer instanceof $customerClass); - $this->assertEquals('user2', $customer->name); - $this->assertFalse($customer->isNewRecord); - static::$afterSaveNewRecord = null; - static::$afterSaveInsert = null; - - $customer->updateAttributes(['name' => 'user2x']); - $this->afterSave(); - $this->assertEquals('user2x', $customer->name); - $this->assertFalse($customer->isNewRecord); - $this->assertFalse(static::$afterSaveNewRecord); - $this->assertFalse(static::$afterSaveInsert); - $customer2 = $this->callCustomerFind(2); - $this->assertEquals('user2x', $customer2->name); - - $customer = $this->callCustomerFind(1); - $this->assertEquals('user1', $customer->name); - $this->assertEquals(1, $customer->status); - $customer->name = 'user1x'; - $customer->status = 2; - $customer->updateAttributes(['name']); - $this->assertEquals('user1x', $customer->name); - $this->assertEquals(2, $customer->status); - $customer = $this->callCustomerFind(1); - $this->assertEquals('user1x', $customer->name); - $this->assertEquals(1, $customer->status); - } - - public function testUpdateCounters() - { - $orderItemClass = $this->getOrderItemClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - // updateCounters - $pk = ['order_id' => 2, 'item_id' => 4]; - $orderItem = $this->callOrderItemFind($pk); - $this->assertEquals(1, $orderItem->quantity); - $ret = $orderItem->updateCounters(['quantity' => -1]); - $this->afterSave(); - $this->assertEquals(1, $ret); - $this->assertEquals(0, $orderItem->quantity); - $orderItem = $this->callOrderItemFind($pk); - $this->assertEquals(0, $orderItem->quantity); - - // updateAllCounters - $pk = ['order_id' => 1, 'item_id' => 2]; - $orderItem = $this->callOrderItemFind($pk); - $this->assertEquals(2, $orderItem->quantity); - $ret = $orderItemClass::updateAllCounters([ - 'quantity' => 3, - 'subtotal' => -10, - ], $pk); - $this->afterSave(); - $this->assertEquals(1, $ret); - $orderItem = $this->callOrderItemFind($pk); - $this->assertEquals(5, $orderItem->quantity); - $this->assertEquals(30, $orderItem->subtotal); - } - - public function testDelete() - { - $customerClass = $this->getCustomerClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - // delete - $customer = $this->callCustomerFind(2); - $this->assertTrue($customer instanceof $customerClass); - $this->assertEquals('user2', $customer->name); - $customer->delete(); - $this->afterSave(); - $customer = $this->callCustomerFind(2); - $this->assertNull($customer); - - // deleteAll - $customers = $this->callCustomerFind()->all(); - $this->assertEquals(2, count($customers)); - $ret = $customerClass::deleteAll(); - $this->afterSave(); - $this->assertEquals(2, $ret); - $customers = $this->callCustomerFind()->all(); - $this->assertEquals(0, count($customers)); - - $ret = $customerClass::deleteAll(); - $this->afterSave(); - $this->assertEquals(0, $ret); - } - - /** - * Some PDO implementations(e.g. cubrid) do not support boolean values. - * Make sure this does not affect AR layer. - */ - public function testBooleanAttribute() - { - $customerClass = $this->getCustomerClass(); - /** @var TestCase|ActiveRecordTestTrait $this */ - $customer = new $customerClass(); - $customer->name = 'boolean customer'; - $customer->email = 'mail@example.com'; - $customer->status = true; - $customer->save(false); - - $customer->refresh(); - $this->assertEquals(1, $customer->status); - - $customer->status = false; - $customer->save(false); - - $customer->refresh(); - $this->assertEquals(0, $customer->status); - - $customers = $this->callCustomerFind()->where(['status' => true])->all(); - $this->assertEquals(2, count($customers)); - - $customers = $this->callCustomerFind()->where(['status' => false])->all(); - $this->assertEquals(1, count($customers)); - } -} diff --git a/tests/unit/framework/base/BehaviorTest.php b/tests/unit/framework/base/BehaviorTest.php deleted file mode 100644 index 9e1d0a5..0000000 --- a/tests/unit/framework/base/BehaviorTest.php +++ /dev/null @@ -1,106 +0,0 @@ - __NAMESPACE__ . '\BarBehavior', - ]; - } -} - -class BarBehavior extends Behavior -{ - public $behaviorProperty = 'behavior property'; - - public function behaviorMethod() - { - return 'behavior method'; - } - - public function __call($name, $params) - { - if ($name == 'magicBehaviorMethod') { - return 'Magic Behavior Method Result!'; - } - return parent::__call($name, $params); - } - - public function hasMethod($name) - { - if ($name == 'magicBehaviorMethod') { - return true; - } - return parent::hasMethod($name); - } -} - -/** - * @group base - */ -class BehaviorTest extends TestCase -{ - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - - public function testAttachAndAccessing() - { - $bar = new BarClass(); - $behavior = new BarBehavior(); - $bar->attachBehavior('bar', $behavior); - $this->assertEquals('behavior property', $bar->behaviorProperty); - $this->assertEquals('behavior method', $bar->behaviorMethod()); - $this->assertEquals('behavior property', $bar->getBehavior('bar')->behaviorProperty); - $this->assertEquals('behavior method', $bar->getBehavior('bar')->behaviorMethod()); - - $behavior = new BarBehavior(['behaviorProperty' => 'reattached']); - $bar->attachBehavior('bar', $behavior); - $this->assertEquals('reattached', $bar->behaviorProperty); - } - - public function testAutomaticAttach() - { - $foo = new FooClass(); - $this->assertEquals('behavior property', $foo->behaviorProperty); - $this->assertEquals('behavior method', $foo->behaviorMethod()); - } - - public function testMagicMethods() - { - $bar = new BarClass(); - $behavior = new BarBehavior(); - - $this->assertFalse($bar->hasMethod('magicBehaviorMethod')); - $bar->attachBehavior('bar', $behavior); - $this->assertFalse($bar->hasMethod('magicBehaviorMethod', false)); - $this->assertTrue($bar->hasMethod('magicBehaviorMethod')); - - $this->assertEquals('Magic Behavior Method Result!', $bar->magicBehaviorMethod()); - } - - public function testCallUnknownMethod() - { - $bar = new BarClass(); - $behavior = new BarBehavior(); - $this->setExpectedException('yii\base\UnknownMethodException'); - - $this->assertFalse($bar->hasMethod('nomagicBehaviorMethod')); - $bar->attachBehavior('bar', $behavior); - $bar->nomagicBehaviorMethod(); - } - -} diff --git a/tests/unit/framework/base/ComponentTest.php b/tests/unit/framework/base/ComponentTest.php deleted file mode 100644 index 2cad56d..0000000 --- a/tests/unit/framework/base/ComponentTest.php +++ /dev/null @@ -1,395 +0,0 @@ -sender->eventHandled = true; -} - -function globalEventHandler2($event) -{ - $event->sender->eventHandled = true; - $event->handled = true; -} - -/** - * @group base - */ -class ComponentTest extends TestCase -{ - /** - * @var NewComponent - */ - protected $component; - - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - $this->component = new NewComponent(); - } - - protected function tearDown() - { - parent::tearDown(); - $this->component = null; - } - - public function testClone() - { - $component = new NewComponent(); - $behavior = new NewBehavior(); - $component->attachBehavior('a', $behavior); - $this->assertSame($behavior, $component->getBehavior('a')); - $component->on('test', 'fake'); - $this->assertTrue($component->hasEventHandlers('test')); - - $clone = clone $component; - $this->assertNotSame($component, $clone); - $this->assertNull($clone->getBehavior('a')); - $this->assertFalse($clone->hasEventHandlers('test')); - } - - public function testHasProperty() - { - $this->assertTrue($this->component->hasProperty('Text')); - $this->assertTrue($this->component->hasProperty('text')); - $this->assertFalse($this->component->hasProperty('Caption')); - $this->assertTrue($this->component->hasProperty('content')); - $this->assertFalse($this->component->hasProperty('content', false)); - $this->assertFalse($this->component->hasProperty('Content')); - } - - public function testCanGetProperty() - { - $this->assertTrue($this->component->canGetProperty('Text')); - $this->assertTrue($this->component->canGetProperty('text')); - $this->assertFalse($this->component->canGetProperty('Caption')); - $this->assertTrue($this->component->canGetProperty('content')); - $this->assertFalse($this->component->canGetProperty('content', false)); - $this->assertFalse($this->component->canGetProperty('Content')); - } - - public function testCanSetProperty() - { - $this->assertTrue($this->component->canSetProperty('Text')); - $this->assertTrue($this->component->canSetProperty('text')); - $this->assertFalse($this->component->canSetProperty('Object')); - $this->assertFalse($this->component->canSetProperty('Caption')); - $this->assertTrue($this->component->canSetProperty('content')); - $this->assertFalse($this->component->canSetProperty('content', false)); - $this->assertFalse($this->component->canSetProperty('Content')); - - // behavior - $this->assertFalse($this->component->canSetProperty('p2')); - $behavior = new NewBehavior(); - $this->component->attachBehavior('a', $behavior); - $this->assertTrue($this->component->canSetProperty('p2')); - $this->component->detachBehavior('a'); - } - - public function testGetProperty() - { - $this->assertTrue('default' === $this->component->Text); - $this->setExpectedException('yii\base\UnknownPropertyException'); - $value2 = $this->component->Caption; - } - - public function testSetProperty() - { - $value = 'new value'; - $this->component->Text = $value; - $this->assertEquals($value, $this->component->Text); - $this->setExpectedException('yii\base\UnknownPropertyException'); - $this->component->NewMember = $value; - } - - public function testIsset() - { - $this->assertTrue(isset($this->component->Text)); - $this->assertFalse(empty($this->component->Text)); - - $this->component->Text = ''; - $this->assertTrue(isset($this->component->Text)); - $this->assertTrue(empty($this->component->Text)); - - $this->component->Text = null; - $this->assertFalse(isset($this->component->Text)); - $this->assertTrue(empty($this->component->Text)); - - - $this->assertFalse(isset($this->component->p2)); - $this->component->attachBehavior('a', new NewBehavior()); - $this->component->setP2('test'); - $this->assertTrue(isset($this->component->p2)); - } - - public function testCallUnknownMethod() - { - $this->setExpectedException('yii\base\UnknownMethodException'); - $this->component->unknownMethod(); - } - - public function testUnset() - { - unset($this->component->Text); - $this->assertFalse(isset($this->component->Text)); - $this->assertTrue(empty($this->component->Text)); - - $this->component->attachBehavior('a', new NewBehavior()); - $this->component->setP2('test'); - $this->assertEquals('test', $this->component->getP2()); - - unset($this->component->p2); - $this->assertNull($this->component->getP2()); - } - - public function testUnsetReadonly() - { - $this->setExpectedException('yii\base\InvalidCallException'); - unset($this->component->object); - } - - public function testOn() - { - $this->assertFalse($this->component->hasEventHandlers('click')); - $this->component->on('click', 'foo'); - $this->assertTrue($this->component->hasEventHandlers('click')); - - $this->assertFalse($this->component->hasEventHandlers('click2')); - $p = 'on click2'; - $this->component->$p = 'foo2'; - $this->assertTrue($this->component->hasEventHandlers('click2')); - } - - public function testOff() - { - $this->assertFalse($this->component->hasEventHandlers('click')); - $this->component->on('click', 'foo'); - $this->assertTrue($this->component->hasEventHandlers('click')); - $this->component->off('click', 'foo'); - $this->assertFalse($this->component->hasEventHandlers('click')); - - $this->component->on('click2', 'foo'); - $this->component->on('click2', 'foo2'); - $this->component->on('click2', 'foo3'); - $this->assertTrue($this->component->hasEventHandlers('click2')); - $this->component->off('click2', 'foo3'); - $this->assertTrue($this->component->hasEventHandlers('click2')); - $this->component->off('click2'); - $this->assertFalse($this->component->hasEventHandlers('click2')); - } - - public function testTrigger() - { - $this->component->on('click', [$this->component, 'myEventHandler']); - $this->assertFalse($this->component->eventHandled); - $this->assertNull($this->component->event); - $this->component->raiseEvent(); - $this->assertTrue($this->component->eventHandled); - $this->assertEquals('click', $this->component->event->name); - $this->assertEquals($this->component, $this->component->event->sender); - $this->assertFalse($this->component->event->handled); - - $eventRaised = false; - $this->component->on('click', function ($event) use (&$eventRaised) { - $eventRaised = true; - }); - $this->component->raiseEvent(); - $this->assertTrue($eventRaised); - - // raise event w/o parameters - $eventRaised = false; - $this->component->on('test', function ($event) use (&$eventRaised) { - $eventRaised = true; - }); - $this->component->trigger('test'); - $this->assertTrue($eventRaised); - } - - public function testHasEventHandlers() - { - $this->assertFalse($this->component->hasEventHandlers('click')); - $this->component->on('click', 'foo'); - $this->assertTrue($this->component->hasEventHandlers('click')); - } - - public function testStopEvent() - { - $component = new NewComponent; - $component->on('click', 'yiiunit\framework\base\globalEventHandler2'); - $component->on('click', [$this->component, 'myEventHandler']); - $component->raiseEvent(); - $this->assertTrue($component->eventHandled); - $this->assertFalse($this->component->eventHandled); - } - - public function testAttachBehavior() - { - $component = new NewComponent; - $this->assertFalse($component->hasProperty('p')); - $this->assertFalse($component->behaviorCalled); - $this->assertNull($component->getBehavior('a')); - - $behavior = new NewBehavior; - $component->attachBehavior('a', $behavior); - $this->assertSame($behavior, $component->getBehavior('a')); - $this->assertTrue($component->hasProperty('p')); - $component->test(); - $this->assertTrue($component->behaviorCalled); - - $this->assertSame($behavior, $component->detachBehavior('a')); - $this->assertFalse($component->hasProperty('p')); - $this->setExpectedException('yii\base\UnknownMethodException'); - $component->test(); - - $p = 'as b'; - $component = new NewComponent; - $component->$p = ['class' => 'NewBehavior']; - $this->assertSame($behavior, $component->getBehavior('a')); - $this->assertTrue($component->hasProperty('p')); - $component->test(); - $this->assertTrue($component->behaviorCalled); - } - - public function testAttachBehaviors() - { - $component = new NewComponent; - $this->assertNull($component->getBehavior('a')); - $this->assertNull($component->getBehavior('b')); - - $behavior = new NewBehavior; - - $component->attachBehaviors([ - 'a' => $behavior, - 'b' => $behavior, - ]); - - $this->assertSame(['a' => $behavior, 'b' => $behavior], $component->getBehaviors()); - } - - public function testDetachBehavior() - { - $component = new NewComponent; - $behavior = new NewBehavior; - - $component->attachBehavior('a', $behavior); - $this->assertSame($behavior, $component->getBehavior('a')); - - $detachedBehavior = $component->detachBehavior('a'); - $this->assertSame($detachedBehavior, $behavior); - $this->assertNull($component->getBehavior('a')); - - $detachedBehavior = $component->detachBehavior('z'); - $this->assertNull($detachedBehavior); - } - - public function testDetachBehaviors() - { - $component = new NewComponent; - $behavior = new NewBehavior; - - $component->attachBehavior('a', $behavior); - $this->assertSame($behavior, $component->getBehavior('a')); - $component->attachBehavior('b', $behavior); - $this->assertSame($behavior, $component->getBehavior('b')); - - $component->detachBehaviors(); - $this->assertNull($component->getBehavior('a')); - $this->assertNull($component->getBehavior('b')); - } -} - -class NewComponent extends Component -{ - private $_object = null; - private $_text = 'default'; - private $_items = []; - public $content; - - public function getText() - { - return $this->_text; - } - - public function setText($value) - { - $this->_text = $value; - } - - public function getObject() - { - if (!$this->_object) { - $this->_object = new self; - $this->_object->_text = 'object text'; - } - return $this->_object; - } - - public function getExecute() - { - return function ($param) { - return $param * 2; - }; - } - - public function getItems() - { - return $this->_items; - } - - public $eventHandled = false; - public $event; - public $behaviorCalled = false; - - public function myEventHandler($event) - { - $this->eventHandled = true; - $this->event = $event; - } - - public function raiseEvent() - { - $this->trigger('click', new Event); - } -} - -class NewBehavior extends Behavior -{ - public $p; - private $p2; - - public function getP2() - { - return $this->p2; - } - - public function setP2($value) - { - $this->p2 = $value; - } - - public function test() - { - $this->owner->behaviorCalled = true; - return 2; - } -} - -class NewComponent2 extends Component -{ - public $a; - public $b; - public $c; - - public function __construct($b, $c) - { - $this->b = $b; - $this->c = $c; - } -} diff --git a/tests/unit/framework/base/EventTest.php b/tests/unit/framework/base/EventTest.php deleted file mode 100644 index 6226793..0000000 --- a/tests/unit/framework/base/EventTest.php +++ /dev/null @@ -1,93 +0,0 @@ - - * @since 2.0 - */ -class EventTest extends TestCase -{ - public $counter; - - public function setUp() - { - $this->counter = 0; - Event::off(ActiveRecord::className(), 'save'); - Event::off(Post::className(), 'save'); - Event::off(User::className(), 'save'); - } - - public function testOn() - { - Event::on(Post::className(), 'save', function ($event) { - $this->counter += 1; - }); - Event::on(ActiveRecord::className(), 'save', function ($event) { - $this->counter += 3; - }); - $this->assertEquals(0, $this->counter); - $post = new Post; - $post->save(); - $this->assertEquals(4, $this->counter); - $user = new User; - $user->save(); - $this->assertEquals(7, $this->counter); - } - - public function testOff() - { - $handler = function ($event) { - $this->counter ++; - }; - $this->assertFalse(Event::hasHandlers(Post::className(), 'save')); - Event::on(Post::className(), 'save', $handler); - $this->assertTrue(Event::hasHandlers(Post::className(), 'save')); - Event::off(Post::className(), 'save', $handler); - $this->assertFalse(Event::hasHandlers(Post::className(), 'save')); - } - - public function testHasHandlers() - { - $this->assertFalse(Event::hasHandlers(Post::className(), 'save')); - $this->assertFalse(Event::hasHandlers(ActiveRecord::className(), 'save')); - Event::on(Post::className(), 'save', function ($event) { - $this->counter += 1; - }); - $this->assertTrue(Event::hasHandlers(Post::className(), 'save')); - $this->assertFalse(Event::hasHandlers(ActiveRecord::className(), 'save')); - - $this->assertFalse(Event::hasHandlers(User::className(), 'save')); - Event::on(ActiveRecord::className(), 'save', function ($event) { - $this->counter += 1; - }); - $this->assertTrue(Event::hasHandlers(User::className(), 'save')); - $this->assertTrue(Event::hasHandlers(ActiveRecord::className(), 'save')); - } -} - -class ActiveRecord extends Component -{ - public function save() - { - $this->trigger('save'); - } -} - -class Post extends ActiveRecord -{ -} - -class User extends ActiveRecord -{ - -} diff --git a/tests/unit/framework/base/ExceptionTest.php b/tests/unit/framework/base/ExceptionTest.php deleted file mode 100644 index 635b55c..0000000 --- a/tests/unit/framework/base/ExceptionTest.php +++ /dev/null @@ -1,23 +0,0 @@ -toArray(); - $this->assertEquals('bar', $array['message']); - $this->assertEquals('foo', $array['previous']['message']); - - $e = new InvalidCallException('bar', 0 ,new UserException('foo')); - $array = $e->toArray(); - $this->assertEquals('bar', $array['message']); - $this->assertEquals('foo', $array['previous']['message']); - } -} diff --git a/tests/unit/framework/base/FormatterTest.php b/tests/unit/framework/base/FormatterTest.php deleted file mode 100644 index 322b751..0000000 --- a/tests/unit/framework/base/FormatterTest.php +++ /dev/null @@ -1,200 +0,0 @@ -mockApplication(); - $this->formatter = new Formatter(); - } - - protected function tearDown() - { - parent::tearDown(); - $this->formatter = null; - } - - public function testAsRaw() - { - $value = '123'; - $this->assertSame($value, $this->formatter->asRaw($value)); - $value = 123; - $this->assertSame($value, $this->formatter->asRaw($value)); - $value = '<>'; - $this->assertSame($value, $this->formatter->asRaw($value)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asRaw(null)); - } - - public function testAsText() - { - $value = '123'; - $this->assertSame($value, $this->formatter->asText($value)); - $value = 123; - $this->assertSame("$value", $this->formatter->asText($value)); - $value = '<>'; - $this->assertSame('<>', $this->formatter->asText($value)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asText(null)); - } - - public function testAsNtext() - { - $value = '123'; - $this->assertSame($value, $this->formatter->asNtext($value)); - $value = 123; - $this->assertSame("$value", $this->formatter->asNtext($value)); - $value = '<>'; - $this->assertSame('<>', $this->formatter->asNtext($value)); - $value = "123\n456"; - $this->assertSame("123
              \n456", $this->formatter->asNtext($value)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asNtext(null)); - } - - public function testAsParagraphs() - { - $value = '123'; - $this->assertSame("

              $value

              ", $this->formatter->asParagraphs($value)); - $value = 123; - $this->assertSame("

              $value

              ", $this->formatter->asParagraphs($value)); - $value = '<>'; - $this->assertSame('

              <>

              ', $this->formatter->asParagraphs($value)); - $value = "123\n456"; - $this->assertSame("

              123\n456

              ", $this->formatter->asParagraphs($value)); - $value = "123\n\n456"; - $this->assertSame("

              123

              \n

              456

              ", $this->formatter->asParagraphs($value)); - $value = "123\n\n\n456"; - $this->assertSame("

              123

              \n

              456

              ", $this->formatter->asParagraphs($value)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asParagraphs(null)); - } - - public function testAsHtml() - { - // todo: dependency on HtmlPurifier - } - - public function testAsEmail() - { - $value = 'test@sample.com'; - $this->assertSame("$value", $this->formatter->asEmail($value)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asEmail(null)); - } - - public function testAsImage() - { - $value = 'http://sample.com/img.jpg'; - $this->assertSame("\"\"", $this->formatter->asImage($value)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asImage(null)); - } - - public function testAsBoolean() - { - $value = true; - $this->assertSame('Yes', $this->formatter->asBoolean($value)); - $value = false; - $this->assertSame('No', $this->formatter->asBoolean($value)); - $value = "111"; - $this->assertSame('Yes', $this->formatter->asBoolean($value)); - $value = ""; - $this->assertSame('No', $this->formatter->asBoolean($value)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asBoolean(null)); - } - - public function testAsDate() - { - $value = time(); - $this->assertSame(date('Y/m/d', $value), $this->formatter->asDate($value)); - $this->assertSame(date('Y-m-d', $value), $this->formatter->asDate($value, 'Y-m-d')); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asDate(null)); - } - - public function testAsTime() - { - $value = time(); - $this->assertSame(date('h:i:s A', $value), $this->formatter->asTime($value)); - $this->assertSame(date('h:i:s', $value), $this->formatter->asTime($value, 'h:i:s')); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asTime(null)); - } - - public function testAsDatetime() - { - $value = time(); - $this->assertSame(date('Y/m/d h:i:s A', $value), $this->formatter->asDatetime($value)); - $this->assertSame(date('Y-m-d h:i:s', $value), $this->formatter->asDatetime($value, 'Y-m-d h:i:s')); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asDatetime(null)); - } - - public function testAsInteger() - { - $value = 123; - $this->assertSame("$value", $this->formatter->asInteger($value)); - $value = 123.23; - $this->assertSame("123", $this->formatter->asInteger($value)); - $value = 'a'; - $this->assertSame("0", $this->formatter->asInteger($value)); - $value = -123.23; - $this->assertSame("-123", $this->formatter->asInteger($value)); - $value = "-123abc"; - $this->assertSame("-123", $this->formatter->asInteger($value)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asInteger(null)); - } - - public function testAsDouble() - { - $value = 123.12; - $this->assertSame("123.12", $this->formatter->asDouble($value)); - $this->assertSame("123.1", $this->formatter->asDouble($value, 1)); - $this->assertSame("123", $this->formatter->asDouble($value, 0)); - $value = 123; - $this->assertSame("123.00", $this->formatter->asDouble($value)); - $this->formatter->decimalSeparator = ','; - $value = 123.12; - $this->assertSame("123,12", $this->formatter->asDouble($value)); - $this->assertSame("123,1", $this->formatter->asDouble($value, 1)); - $this->assertSame("123", $this->formatter->asDouble($value, 0)); - $value = 123123.123; - $this->assertSame("123123,12", $this->formatter->asDouble($value)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asDouble(null)); - } - - public function testAsNumber() - { - $value = 123123.123; - $this->assertSame("123,123", $this->formatter->asNumber($value)); - $this->assertSame("123,123.12", $this->formatter->asNumber($value, 2)); - $this->formatter->decimalSeparator = ','; - $this->formatter->thousandSeparator = ' '; - $this->assertSame("123 123", $this->formatter->asNumber($value)); - $this->assertSame("123 123,12", $this->formatter->asNumber($value, 2)); - $this->formatter->thousandSeparator = ''; - $this->assertSame("123123", $this->formatter->asNumber($value)); - $this->assertSame("123123,12", $this->formatter->asNumber($value, 2)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asNumber(null)); - } - - public function testFormat() - { - $value = time(); - $this->assertSame(date('Y/m/d', $value), $this->formatter->format($value, 'date')); - $this->assertSame(date('Y/m/d', $value), $this->formatter->format($value, 'DATE')); - $this->assertSame(date('Y-m-d', $value), $this->formatter->format($value, ['date', 'Y-m-d'])); - $this->setExpectedException('\yii\base\InvalidParamException'); - $this->assertSame(date('Y-m-d', $value), $this->formatter->format($value, 'data')); - } -} diff --git a/tests/unit/framework/base/ModelTest.php b/tests/unit/framework/base/ModelTest.php deleted file mode 100644 index d304741..0000000 --- a/tests/unit/framework/base/ModelTest.php +++ /dev/null @@ -1,274 +0,0 @@ -mockApplication(); - } - - public function testGetAttributeLabel() - { - $speaker = new Speaker(); - $this->assertEquals('First Name', $speaker->getAttributeLabel('firstName')); - $this->assertEquals('This is the custom label', $speaker->getAttributeLabel('customLabel')); - $this->assertEquals('Underscore Style', $speaker->getAttributeLabel('underscore_style')); - } - - public function testGetAttributes() - { - $speaker = new Speaker(); - $speaker->firstName = 'Qiang'; - $speaker->lastName = 'Xue'; - - $this->assertEquals([ - 'firstName' => 'Qiang', - 'lastName' => 'Xue', - 'customLabel' => null, - 'underscore_style' => null, - ], $speaker->getAttributes()); - - $this->assertEquals([ - 'firstName' => 'Qiang', - 'lastName' => 'Xue', - ], $speaker->getAttributes(['firstName', 'lastName'])); - - $this->assertEquals([ - 'firstName' => 'Qiang', - 'lastName' => 'Xue', - ], $speaker->getAttributes(null, ['customLabel', 'underscore_style'])); - - $this->assertEquals([ - 'firstName' => 'Qiang', - ], $speaker->getAttributes(['firstName', 'lastName'], ['lastName', 'customLabel', 'underscore_style'])); - } - - public function testSetAttributes() - { - // by default mass assignment doesn't work at all - $speaker = new Speaker(); - $speaker->setAttributes(['firstName' => 'Qiang', 'underscore_style' => 'test']); - $this->assertNull($speaker->firstName); - $this->assertNull($speaker->underscore_style); - - // in the test scenario - $speaker = new Speaker(); - $speaker->setScenario('test'); - $speaker->setAttributes(['firstName' => 'Qiang', 'underscore_style' => 'test']); - $this->assertNull($speaker->underscore_style); - $this->assertEquals('Qiang', $speaker->firstName); - - $speaker->setAttributes(['firstName' => 'Qiang', 'underscore_style' => 'test'], false); - $this->assertEquals('test', $speaker->underscore_style); - $this->assertEquals('Qiang', $speaker->firstName); - } - - public function testLoad() - { - $singer = new Singer(); - $this->assertEquals('Singer', $singer->formName()); - - $post = ['firstName' => 'Qiang']; - - Speaker::$formName = ''; - $model = new Speaker(); - $model->setScenario('test'); - $this->assertTrue($model->load($post)); - $this->assertEquals('Qiang', $model->firstName); - - Speaker::$formName = 'Speaker'; - $model = new Speaker(); - $model->setScenario('test'); - $this->assertTrue($model->load(['Speaker' => $post])); - $this->assertEquals('Qiang', $model->firstName); - - Speaker::$formName = 'Speaker'; - $model = new Speaker(); - $model->setScenario('test'); - $this->assertFalse($model->load(['Example' => []])); - $this->assertEquals('', $model->firstName); - } - - public function testActiveAttributes() - { - // by default mass assignment doesn't work at all - $speaker = new Speaker(); - $this->assertEmpty($speaker->activeAttributes()); - - $speaker = new Speaker(); - $speaker->setScenario('test'); - $this->assertEquals(['firstName', 'lastName', 'underscore_style'], $speaker->activeAttributes()); - } - - public function testIsAttributeSafe() - { - // by default mass assignment doesn't work at all - $speaker = new Speaker(); - $this->assertFalse($speaker->isAttributeSafe('firstName')); - - $speaker = new Speaker(); - $speaker->setScenario('test'); - $this->assertTrue($speaker->isAttributeSafe('firstName')); - - } - - public function testErrors() - { - $speaker = new Speaker(); - - $this->assertEmpty($speaker->getErrors()); - $this->assertEmpty($speaker->getErrors('firstName')); - $this->assertEmpty($speaker->getFirstErrors()); - - $this->assertFalse($speaker->hasErrors()); - $this->assertFalse($speaker->hasErrors('firstName')); - - $speaker->addError('firstName', 'Something is wrong!'); - $this->assertEquals(['firstName' => ['Something is wrong!']], $speaker->getErrors()); - $this->assertEquals(['Something is wrong!'], $speaker->getErrors('firstName')); - - $speaker->addError('firstName', 'Totally wrong!'); - $this->assertEquals(['firstName' => ['Something is wrong!', 'Totally wrong!']], $speaker->getErrors()); - $this->assertEquals(['Something is wrong!', 'Totally wrong!'], $speaker->getErrors('firstName')); - - $this->assertTrue($speaker->hasErrors()); - $this->assertTrue($speaker->hasErrors('firstName')); - $this->assertFalse($speaker->hasErrors('lastName')); - - $this->assertEquals(['Something is wrong!'], $speaker->getFirstErrors()); - $this->assertEquals('Something is wrong!', $speaker->getFirstError('firstName')); - $this->assertNull($speaker->getFirstError('lastName')); - - $speaker->addError('lastName', 'Another one!'); - $this->assertEquals([ - 'firstName' => [ - 'Something is wrong!', - 'Totally wrong!', - ], - 'lastName' => ['Another one!'], - ], $speaker->getErrors()); - - $speaker->clearErrors('firstName'); - $this->assertEquals([ - 'lastName' => ['Another one!'], - ], $speaker->getErrors()); - - $speaker->clearErrors(); - $this->assertEmpty($speaker->getErrors()); - $this->assertFalse($speaker->hasErrors()); - } - - public function testArraySyntax() - { - $speaker = new Speaker(); - - // get - $this->assertNull($speaker['firstName']); - - // isset - $this->assertFalse(isset($speaker['firstName'])); - - // set - $speaker['firstName'] = 'Qiang'; - - $this->assertEquals('Qiang', $speaker['firstName']); - $this->assertTrue(isset($speaker['firstName'])); - - // iteration - $attributes = []; - foreach ($speaker as $key => $attribute) { - $attributes[$key] = $attribute; - } - $this->assertEquals([ - 'firstName' => 'Qiang', - 'lastName' => null, - 'customLabel' => null, - 'underscore_style' => null, - ], $attributes); - - // unset - unset($speaker['firstName']); - - // exception isn't expected here - $this->assertNull($speaker['firstName']); - $this->assertFalse(isset($speaker['firstName'])); - } - - public function testDefaults() - { - $singer = new Model(); - $this->assertEquals([], $singer->rules()); - $this->assertEquals([], $singer->attributeLabels()); - } - - public function testDefaultScenarios() - { - $singer = new Singer(); - $this->assertEquals(['default' => ['lastName', 'underscore_style']], $singer->scenarios()); - - $scenarios = [ - 'default' => ['id', 'name', 'description'], - 'administration' => ['name', 'description', 'is_disabled'], - ]; - $model = new ComplexModel1(); - $this->assertEquals($scenarios, $model->scenarios()); - $scenarios = [ - 'default' => ['id', 'name', 'description'], - 'suddenlyUnexpectedScenario' => ['name', 'description'], - 'administration' => ['id', 'name', 'description', 'is_disabled'], - ]; - $model = new ComplexModel2(); - $this->assertEquals($scenarios, $model->scenarios()); - } - - public function testIsAttributeRequired() - { - $singer = new Singer(); - $this->assertFalse($singer->isAttributeRequired('firstName')); - $this->assertTrue($singer->isAttributeRequired('lastName')); - } - - public function testCreateValidators() - { - $this->setExpectedException('yii\base\InvalidConfigException', 'Invalid validation rule: a rule must specify both attribute names and validator type.'); - - $invalid = new InvalidRulesModel(); - $invalid->createValidators(); - } -} - -class ComplexModel1 extends Model -{ - public function rules() - { - return [ - [['id'], 'required', 'except' => 'administration'], - [['name', 'description'], 'filter', 'filter' => 'trim'], - [['is_disabled'], 'boolean', 'on' => 'administration'], - ]; - } -} - -class ComplexModel2 extends Model -{ - public function rules() - { - return [ - [['id'], 'required', 'except' => 'suddenlyUnexpectedScenario'], - [['name', 'description'], 'filter', 'filter' => 'trim'], - [['is_disabled'], 'boolean', 'on' => 'administration'], - ]; - } -} diff --git a/tests/unit/framework/base/ObjectTest.php b/tests/unit/framework/base/ObjectTest.php deleted file mode 100644 index a889f42..0000000 --- a/tests/unit/framework/base/ObjectTest.php +++ /dev/null @@ -1,182 +0,0 @@ -mockApplication(); - $this->object = new NewObject; - } - - protected function tearDown() - { - parent::tearDown(); - $this->object = null; - } - - public function testHasProperty() - { - $this->assertTrue($this->object->hasProperty('Text')); - $this->assertTrue($this->object->hasProperty('text')); - $this->assertFalse($this->object->hasProperty('Caption')); - $this->assertTrue($this->object->hasProperty('content')); - $this->assertFalse($this->object->hasProperty('content', false)); - $this->assertFalse($this->object->hasProperty('Content')); - } - - public function testCanGetProperty() - { - $this->assertTrue($this->object->canGetProperty('Text')); - $this->assertTrue($this->object->canGetProperty('text')); - $this->assertFalse($this->object->canGetProperty('Caption')); - $this->assertTrue($this->object->canGetProperty('content')); - $this->assertFalse($this->object->canGetProperty('content', false)); - $this->assertFalse($this->object->canGetProperty('Content')); - } - - public function testCanSetProperty() - { - $this->assertTrue($this->object->canSetProperty('Text')); - $this->assertTrue($this->object->canSetProperty('text')); - $this->assertFalse($this->object->canSetProperty('Object')); - $this->assertFalse($this->object->canSetProperty('Caption')); - $this->assertTrue($this->object->canSetProperty('content')); - $this->assertFalse($this->object->canSetProperty('content', false)); - $this->assertFalse($this->object->canSetProperty('Content')); - } - - public function testGetProperty() - { - $this->assertTrue('default' === $this->object->Text); - $this->setExpectedException('yii\base\UnknownPropertyException'); - $value2 = $this->object->Caption; - } - - public function testSetProperty() - { - $value = 'new value'; - $this->object->Text = $value; - $this->assertEquals($value, $this->object->Text); - $this->setExpectedException('yii\base\UnknownPropertyException'); - $this->object->NewMember = $value; - } - - public function testSetReadOnlyProperty() - { - $this->setExpectedException('yii\base\InvalidCallException'); - $this->object->object = 'test'; - } - - public function testIsset() - { - $this->assertTrue(isset($this->object->Text)); - $this->assertFalse(empty($this->object->Text)); - - $this->object->Text = ''; - $this->assertTrue(isset($this->object->Text)); - $this->assertTrue(empty($this->object->Text)); - - $this->object->Text = null; - $this->assertFalse(isset($this->object->Text)); - $this->assertTrue(empty($this->object->Text)); - - $this->assertFalse(isset($this->object->unknownProperty)); - $this->assertTrue(empty($this->object->unknownProperty)); - } - - public function testUnset() - { - unset($this->object->Text); - $this->assertFalse(isset($this->object->Text)); - $this->assertTrue(empty($this->object->Text)); - } - - public function testUnsetReadOnlyProperty() - { - $this->setExpectedException('yii\base\InvalidCallException'); - unset($this->object->object); - } - - public function testCallUnknownMethod() - { - $this->setExpectedException('yii\base\UnknownMethodException'); - $this->object->unknownMethod(); - } - - public function testArrayProperty() - { - $this->assertEquals([], $this->object->items); - // the following won't work - /* - $this->object->items[] = 1; - $this->assertEquals([1], $this->object->items); - */ - } - - public function testObjectProperty() - { - $this->assertTrue($this->object->object instanceof NewObject); - $this->assertEquals('object text', $this->object->object->text); - $this->object->object->text = 'new text'; - $this->assertEquals('new text', $this->object->object->text); - } - - public function testConstruct() - { - $object = new NewObject(['text' => 'test text']); - $this->assertEquals('test text', $object->getText()); - } -} - - -class NewObject extends Object -{ - private $_object = null; - private $_text = 'default'; - private $_items = []; - public $content; - - public function getText() - { - return $this->_text; - } - - public function setText($value) - { - $this->_text = $value; - } - - public function getObject() - { - if (!$this->_object) { - $this->_object = new self; - $this->_object->_text = 'object text'; - } - return $this->_object; - } - - public function getExecute() - { - return function ($param) { - return $param * 2; - }; - } - - public function getItems() - { - return $this->_items; - } -} diff --git a/tests/unit/framework/behaviors/AutoTimestampTest.php b/tests/unit/framework/behaviors/AutoTimestampTest.php deleted file mode 100644 index ca1217b..0000000 --- a/tests/unit/framework/behaviors/AutoTimestampTest.php +++ /dev/null @@ -1,116 +0,0 @@ -mockApplication([ - 'components' => [ - 'db' => [ - 'class' => '\yii\db\Connection', - 'dsn' => 'sqlite::memory:', - ] - ] - ]); - - $columns = [ - 'id' => 'pk', - 'create_time' => 'integer', - 'update_time' => 'integer', - ]; - Yii::$app->getDb()->createCommand()->createTable('test_auto_timestamp', $columns)->execute(); - } - - public function tearDown() - { - Yii::$app->getDb()->close(); - parent::tearDown(); - } - - // Tests : - - public function testNewRecord() - { - $currentTime = time(); - - $model = new ActiveRecordAutoTimestamp(); - $model->save(false); - - $this->assertTrue($model->create_time >= $currentTime); - $this->assertTrue($model->update_time >= $currentTime); - } - - /** - * @depends testNewRecord - */ - public function testUpdateRecord() - { - $currentTime = time(); - - $model = new ActiveRecordAutoTimestamp(); - $model->save(false); - - $enforcedTime = $currentTime - 100; - - $model->create_time = $enforcedTime; - $model->update_time = $enforcedTime; - $model->save(false); - - $this->assertEquals($enforcedTime, $model->create_time, 'Create time has been set on update!'); - $this->assertTrue($model->update_time >= $currentTime, 'Update time has NOT been set on update!'); - } -} - -/** - * Test Active Record class with [[AutoTimestamp]] behavior attached. - * - * @property integer $id - * @property integer $create_time - * @property integer $update_time - */ -class ActiveRecordAutoTimestamp extends ActiveRecord -{ - public function behaviors() - { - return [ - 'timestamp' => [ - 'class' => AutoTimestamp::className(), - 'attributes' => [ - static::EVENT_BEFORE_INSERT => ['create_time', 'update_time'], - static::EVENT_BEFORE_UPDATE => 'update_time', - ], - ], - ]; - } - - public static function tableName() - { - return 'test_auto_timestamp'; - } -} diff --git a/tests/unit/framework/caching/ApcCacheTest.php b/tests/unit/framework/caching/ApcCacheTest.php deleted file mode 100644 index b65ec41..0000000 --- a/tests/unit/framework/caching/ApcCacheTest.php +++ /dev/null @@ -1,45 +0,0 @@ -markTestSkipped("APC not installed. Skipping."); - } elseif ('cli' === PHP_SAPI && !ini_get('apc.enable_cli')) { - $this->markTestSkipped("APC cli is not enabled. Skipping."); - } - - if (!ini_get("apc.enabled") || !ini_get("apc.enable_cli")) { - $this->markTestSkipped("APC is installed but not enabled. Skipping."); - } - - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new ApcCache(); - } - return $this->_cacheInstance; - } - - public function testExpire() - { - $this->markTestSkipped("APC keys are expiring only on the next request."); - } - - public function testExpireAdd() - { - $this->markTestSkipped("APC keys are expiring only on the next request."); - } -} diff --git a/tests/unit/framework/caching/CacheTestCase.php b/tests/unit/framework/caching/CacheTestCase.php deleted file mode 100644 index afd514d..0000000 --- a/tests/unit/framework/caching/CacheTestCase.php +++ /dev/null @@ -1,239 +0,0 @@ -mockApplication(); - } - - protected function tearDown() - { - static::$time = null; - } - - /** - * @return Cache - */ - public function prepare() - { - $cache = $this->getCacheInstance(); - - $cache->flush(); - $cache->set('string_test', 'string_test'); - $cache->set('number_test', 42); - $cache->set('array_test', ['array_test' => 'array_test']); - $cache['arrayaccess_test'] = new \stdClass(); - - return $cache; - } - - /** - * default value of cache prefix is application id - */ - public function testKeyPrefix() - { - $cache = $this->getCacheInstance(); - $this->assertNotNull(\Yii::$app->id); - $this->assertNotNull($cache->keyPrefix); - } - - public function testSet() - { - $cache = $this->getCacheInstance(); - - $this->assertTrue($cache->set('string_test', 'string_test')); - $this->assertTrue($cache->set('number_test', 42)); - $this->assertTrue($cache->set('array_test', ['array_test' => 'array_test'])); - } - - public function testGet() - { - $cache = $this->prepare(); - - $this->assertEquals('string_test', $cache->get('string_test')); - - $this->assertEquals(42, $cache->get('number_test')); - - $array = $cache->get('array_test'); - $this->assertArrayHasKey('array_test', $array); - $this->assertEquals('array_test', $array['array_test']); - } - - /** - * @return array testing mset with and without expiry - */ - public function msetExpiry() - { - return [[0], [2]]; - } - - /** - * @dataProvider msetExpiry - */ - public function testMset($expiry) - { - $cache = $this->getCacheInstance(); - $cache->flush(); - - $cache->mset([ - 'string_test' => 'string_test', - 'number_test' => 42, - 'array_test' => ['array_test' => 'array_test'], - ], $expiry); - - $this->assertEquals('string_test', $cache->get('string_test')); - - $this->assertEquals(42, $cache->get('number_test')); - - $array = $cache->get('array_test'); - $this->assertArrayHasKey('array_test', $array); - $this->assertEquals('array_test', $array['array_test']); - } - - public function testExists() - { - $cache = $this->prepare(); - - $this->assertTrue($cache->exists('string_test')); - // check whether exists affects the value - $this->assertEquals('string_test', $cache->get('string_test')); - - $this->assertTrue($cache->exists('number_test')); - $this->assertFalse($cache->exists('not_exists')); - } - - public function testArrayAccess() - { - $cache = $this->getCacheInstance(); - - $cache['arrayaccess_test'] = new \stdClass(); - $this->assertInstanceOf('stdClass', $cache['arrayaccess_test']); - } - - public function testGetNonExistent() - { - $cache = $this->getCacheInstance(); - - $this->assertFalse($cache->get('non_existent_key')); - } - - public function testStoreSpecialValues() - { - $cache = $this->getCacheInstance(); - - $this->assertTrue($cache->set('null_value', null)); - $this->assertNull($cache->get('null_value')); - - $this->assertTrue($cache->set('bool_value', true)); - $this->assertTrue($cache->get('bool_value')); - } - - public function testMget() - { - $cache = $this->prepare(); - - $this->assertEquals(['string_test' => 'string_test', 'number_test' => 42], $cache->mget(['string_test', 'number_test'])); - // ensure that order does not matter - $this->assertEquals(['number_test' => 42, 'string_test' => 'string_test'], $cache->mget(['number_test', 'string_test'])); - $this->assertEquals(['number_test' => 42, 'non_existent_key' => null], $cache->mget(['number_test', 'non_existent_key'])); - } - - public function testExpire() - { - $cache = $this->getCacheInstance(); - - $this->assertTrue($cache->set('expire_test', 'expire_test', 2)); - usleep(500000); - $this->assertEquals('expire_test', $cache->get('expire_test')); - usleep(2500000); - $this->assertFalse($cache->get('expire_test')); - } - - public function testExpireAdd() - { - $cache = $this->getCacheInstance(); - - $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2)); - usleep(500000); - $this->assertEquals('expire_testa', $cache->get('expire_testa')); - usleep(2500000); - $this->assertFalse($cache->get('expire_testa')); - } - - public function testAdd() - { - $cache = $this->prepare(); - - // should not change existing keys - $this->assertFalse($cache->add('number_test', 13)); - $this->assertEquals(42, $cache->get('number_test')); - - // should store data if it's not there yet - $this->assertFalse($cache->get('add_test')); - $this->assertTrue($cache->add('add_test', 13)); - $this->assertEquals(13, $cache->get('add_test')); - } - - public function testMadd() - { - $cache = $this->prepare(); - - $this->assertFalse($cache->get('add_test')); - - $cache->madd([ - 'number_test' => 13, - 'add_test' => 13, - ]); - - $this->assertEquals(42, $cache->get('number_test')); - $this->assertEquals(13, $cache->get('add_test')); - } - - public function testDelete() - { - $cache = $this->prepare(); - - $this->assertNotNull($cache->get('number_test')); - $this->assertTrue($cache->delete('number_test')); - $this->assertFalse($cache->get('number_test')); - } - - public function testFlush() - { - $cache = $this->prepare(); - $this->assertTrue($cache->flush()); - $this->assertFalse($cache->get('number_test')); - } -} diff --git a/tests/unit/framework/caching/DbCacheTest.php b/tests/unit/framework/caching/DbCacheTest.php deleted file mode 100644 index c2d03e2..0000000 --- a/tests/unit/framework/caching/DbCacheTest.php +++ /dev/null @@ -1,98 +0,0 @@ -markTestSkipped('pdo and pdo_mysql extensions are required.'); - } - - parent::setUp(); - - $this->getConnection()->createCommand(" - CREATE TABLE IF NOT EXISTS tbl_cache ( - id char(128) NOT NULL, - expire int(11) DEFAULT NULL, - data LONGBLOB, - PRIMARY KEY (id), - KEY expire (expire) - ); - ")->execute(); - } - - /** - * @param bool $reset whether to clean up the test database - * @return \yii\db\Connection - */ - public function getConnection($reset = true) - { - if ($this->_connection === null) { - $databases = $this->getParam('databases'); - $params = $databases['mysql']; - $db = new \yii\db\Connection; - $db->dsn = $params['dsn']; - $db->username = $params['username']; - $db->password = $params['password']; - if ($reset) { - $db->open(); - $lines = explode(';', file_get_contents($params['fixture'])); - foreach ($lines as $line) { - if (trim($line) !== '') { - $db->pdo->exec($line); - } - } - } - $this->_connection = $db; - } - return $this->_connection; - } - - - /** - * @return DbCache - */ - protected function getCacheInstance() - { - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new DbCache(['db' => $this->getConnection()]); - } - return $this->_cacheInstance; - } - - public function testExpire() - { - $cache = $this->getCacheInstance(); - - static::$time = \time(); - $this->assertTrue($cache->set('expire_test', 'expire_test', 2)); - static::$time++; - $this->assertEquals('expire_test', $cache->get('expire_test')); - static::$time++; - $this->assertFalse($cache->get('expire_test')); - } - - public function testExpireAdd() - { - $cache = $this->getCacheInstance(); - - static::$time = \time(); - $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2)); - static::$time++; - $this->assertEquals('expire_testa', $cache->get('expire_testa')); - static::$time++; - $this->assertFalse($cache->get('expire_testa')); - } -} diff --git a/tests/unit/framework/caching/FileCacheTest.php b/tests/unit/framework/caching/FileCacheTest.php deleted file mode 100644 index f102614..0000000 --- a/tests/unit/framework/caching/FileCacheTest.php +++ /dev/null @@ -1,48 +0,0 @@ -_cacheInstance === null) { - $this->_cacheInstance = new FileCache(['cachePath' => '@yiiunit/runtime/cache']); - } - return $this->_cacheInstance; - } - - public function testExpire() - { - $cache = $this->getCacheInstance(); - - static::$time = \time(); - $this->assertTrue($cache->set('expire_test', 'expire_test', 2)); - static::$time++; - $this->assertEquals('expire_test', $cache->get('expire_test')); - static::$time++; - $this->assertFalse($cache->get('expire_test')); - } - - public function testExpireAdd() - { - $cache = $this->getCacheInstance(); - - static::$time = \time(); - $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2)); - static::$time++; - $this->assertEquals('expire_testa', $cache->get('expire_testa')); - static::$time++; - $this->assertFalse($cache->get('expire_testa')); - } -} diff --git a/tests/unit/framework/caching/MemCacheTest.php b/tests/unit/framework/caching/MemCacheTest.php deleted file mode 100644 index 63f8be1..0000000 --- a/tests/unit/framework/caching/MemCacheTest.php +++ /dev/null @@ -1,45 +0,0 @@ -markTestSkipped("memcache not installed. Skipping."); - } - - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new MemCache(); - } - return $this->_cacheInstance; - } - - public function testExpire() - { - if (getenv('TRAVIS') == 'true') { - $this->markTestSkipped('Can not reliably test memcache expiry on travis-ci.'); - } - parent::testExpire(); - } - - public function testExpireAdd() - { - if (getenv('TRAVIS') == 'true') { - $this->markTestSkipped('Can not reliably test memcache expiry on travis-ci.'); - } - parent::testExpireAdd(); - } -} diff --git a/tests/unit/framework/caching/MemCachedTest.php b/tests/unit/framework/caching/MemCachedTest.php deleted file mode 100644 index 3a9d415..0000000 --- a/tests/unit/framework/caching/MemCachedTest.php +++ /dev/null @@ -1,45 +0,0 @@ -markTestSkipped("memcached not installed. Skipping."); - } - - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new MemCache(['useMemcached' => true]); - } - return $this->_cacheInstance; - } - - public function testExpire() - { - if (getenv('TRAVIS') == 'true') { - $this->markTestSkipped('Can not reliably test memcached expiry on travis-ci.'); - } - parent::testExpire(); - } - - public function testExpireAdd() - { - if (getenv('TRAVIS') == 'true') { - $this->markTestSkipped('Can not reliably test memcached expiry on travis-ci.'); - } - parent::testExpireAdd(); - } -} diff --git a/tests/unit/framework/caching/WinCacheTest.php b/tests/unit/framework/caching/WinCacheTest.php deleted file mode 100644 index 1bce102..0000000 --- a/tests/unit/framework/caching/WinCacheTest.php +++ /dev/null @@ -1,33 +0,0 @@ -markTestSkipped("Wincache not installed. Skipping."); - } - - if (!ini_get('wincache.ucenabled')) { - $this->markTestSkipped("Wincache user cache disabled. Skipping."); - } - - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new WinCache(); - } - return $this->_cacheInstance; - } -} diff --git a/tests/unit/framework/caching/XCacheTest.php b/tests/unit/framework/caching/XCacheTest.php deleted file mode 100644 index 989765d..0000000 --- a/tests/unit/framework/caching/XCacheTest.php +++ /dev/null @@ -1,29 +0,0 @@ -markTestSkipped("XCache not installed. Skipping."); - } - - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new XCache(); - } - return $this->_cacheInstance; - } -} diff --git a/tests/unit/framework/caching/ZendDataCacheTest.php b/tests/unit/framework/caching/ZendDataCacheTest.php deleted file mode 100644 index 2a0af9f..0000000 --- a/tests/unit/framework/caching/ZendDataCacheTest.php +++ /dev/null @@ -1,29 +0,0 @@ -markTestSkipped("Zend Data cache not installed. Skipping."); - } - - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new ZendDataCache(); - } - return $this->_cacheInstance; - } -} diff --git a/tests/unit/framework/console/controllers/AssetControllerTest.php b/tests/unit/framework/console/controllers/AssetControllerTest.php deleted file mode 100644 index e694dd4..0000000 --- a/tests/unit/framework/console/controllers/AssetControllerTest.php +++ /dev/null @@ -1,319 +0,0 @@ -mockApplication(); - $this->testFilePath = Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . get_class($this); - $this->createDir($this->testFilePath); - $this->testAssetsBasePath = $this->testFilePath . DIRECTORY_SEPARATOR . 'assets'; - $this->createDir($this->testAssetsBasePath); - } - - public function tearDown() - { - $this->removeDir($this->testFilePath); - } - - /** - * Creates directory. - * @param string $dirName directory full name. - */ - protected function createDir($dirName) - { - if (!file_exists($dirName)) { - mkdir($dirName, 0777, true); - } - } - - /** - * Removes directory. - * @param string $dirName directory full name - */ - protected function removeDir($dirName) - { - if (!empty($dirName) && file_exists($dirName)) { - exec("rm -rf {$dirName}"); - } - } - - /** - * Creates test asset controller instance. - * @return AssetController - */ - protected function createAssetController() - { - $module = $this->getMock('yii\\base\\Module', ['fake'], ['console']); - $assetController = new AssetController('asset', $module); - $assetController->interactive = false; - $assetController->jsCompressor = 'cp {from} {to}'; - $assetController->cssCompressor = 'cp {from} {to}'; - return $assetController; - } - - /** - * Emulates running of the asset controller action. - * @param string $actionId id of action to be run. - * @param array $args action arguments. - * @return string command output. - */ - protected function runAssetControllerAction($actionId, array $args = []) - { - $controller = $this->createAssetController(); - ob_start(); - ob_implicit_flush(false); - $controller->run($actionId, $args); - return ob_get_clean(); - } - - /** - * Creates test compress config. - * @param array[] $bundles asset bundles config. - * @return array config array. - */ - protected function createCompressConfig(array $bundles) - { - $baseUrl = '/test'; - $config = [ - 'bundles' => $this->createBundleConfig($bundles), - 'targets' => [ - 'all' => [ - 'basePath' => $this->testAssetsBasePath, - 'baseUrl' => $baseUrl, - 'js' => 'all.js', - 'css' => 'all.css', - ], - ], - 'assetManager' => [ - 'basePath' => $this->testAssetsBasePath, - 'baseUrl' => '', - ], - ]; - return $config; - } - - /** - * Creates test bundle configuration. - * @param array[] $bundles asset bundles config. - * @return array bundle config. - */ - protected function createBundleConfig(array $bundles) - { - foreach ($bundles as $name => $config) { - if (!array_key_exists('basePath', $config)) { - $bundles[$name]['basePath'] = $this->testFilePath; - } - if (!array_key_exists('baseUrl', $config)) { - $bundles[$name]['baseUrl'] = ''; - } - } - return $bundles; - } - - /** - * Creates test compress config file. - * @param string $fileName output file name. - * @param array[] $bundles asset bundles config. - * @throws Exception on failure. - */ - protected function createCompressConfigFile($fileName, array $bundles) - { - $content = 'createCompressConfig($bundles), true) . ';'; - if (file_put_contents($fileName, $content) <= 0) { - throw new \Exception("Unable to create file '{$fileName}'!"); - } - } - - /** - * Creates test asset file. - * @param string $fileRelativeName file name relative to [[testFilePath]] - * @param string $content file content - * @throws Exception on failure. - */ - protected function createAssetSourceFile($fileRelativeName, $content) - { - $fileFullName = $this->testFilePath . DIRECTORY_SEPARATOR . $fileRelativeName; - $this->createDir(dirname($fileFullName)); - if (file_put_contents($fileFullName, $content) <= 0) { - throw new \Exception("Unable to create file '{$fileFullName}'!"); - } - } - - /** - * Creates a list of asset source files. - * @param array $files assert source files in format: file/relative/name => fileContent - */ - protected function createAssetSourceFiles(array $files) - { - foreach ($files as $name => $content) { - $this->createAssetSourceFile($name, $content); - } - } - - /** - * Invokes the asset controller method even if it is protected. - * @param string $methodName name of the method to be invoked. - * @param array $args method arguments. - * @return mixed method invoke result. - */ - protected function invokeAssetControllerMethod($methodName, array $args = []) - { - $controller = $this->createAssetController(); - $controllerClassReflection = new ReflectionClass(get_class($controller)); - $methodReflection = $controllerClassReflection->getMethod($methodName); - $methodReflection->setAccessible(true); - $result = $methodReflection->invokeArgs($controller, $args); - $methodReflection->setAccessible(false); - return $result; - } - - // Tests : - - public function testActionTemplate() - { - $configFileName = $this->testFilePath . DIRECTORY_SEPARATOR . 'config.php'; - $this->runAssetControllerAction('template', [$configFileName]); - $this->assertTrue(file_exists($configFileName), 'Unable to create config file template!'); - } - - public function atestActionCompress() - { - // Given : - $cssFiles = [ - 'css/test_body.css' => 'body { - padding-top: 20px; - padding-bottom: 60px; - }', - 'css/test_footer.css' => '.footer { - margin: 20px; - display: block; - }', - ]; - $this->createAssetSourceFiles($cssFiles); - - $jsFiles = [ - 'js/test_alert.js' => "function test() { - alert('Test message'); - }", - 'js/test_sum_ab.js' => "function sumAB(a, b) { - return a + b; - }", - ]; - $this->createAssetSourceFiles($jsFiles); - - $bundles = [ - 'app' => [ - 'css' => array_keys($cssFiles), - 'js' => array_keys($jsFiles), - 'depends' => [ - 'yii', - ], - ], - ]; - $bundleFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'bundle.php'; - - $configFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'config.php'; - $this->createCompressConfigFile($configFile, $bundles); - - // When : - $this->runAssetControllerAction('compress', [$configFile, $bundleFile]); - - // Then : - $this->assertTrue(file_exists($bundleFile), 'Unable to create output bundle file!'); - $this->assertTrue(is_array(require($bundleFile)), 'Output bundle file has incorrect format!'); - - $compressedCssFileName = $this->testAssetsBasePath . DIRECTORY_SEPARATOR . 'all.css'; - $this->assertTrue(file_exists($compressedCssFileName), 'Unable to compress CSS files!'); - $compressedJsFileName = $this->testAssetsBasePath . DIRECTORY_SEPARATOR . 'all.js'; - $this->assertTrue(file_exists($compressedJsFileName), 'Unable to compress JS files!'); - - $compressedCssFileContent = file_get_contents($compressedCssFileName); - foreach ($cssFiles as $name => $content) { - $this->assertContains($content, $compressedCssFileContent, "Source of '{$name}' is missing in combined file!"); - } - $compressedJsFileContent = file_get_contents($compressedJsFileName); - foreach ($jsFiles as $name => $content) { - $this->assertContains($content, $compressedJsFileContent, "Source of '{$name}' is missing in combined file!"); - } - } - - /** - * Data provider for [[testAdjustCssUrl()]]. - * @return array test data. - */ - public function adjustCssUrlDataProvider() - { - return [ - [ - '.published-same-dir-class {background-image: url(published_same_dir.png);}', - '/test/base/path/assets/input', - '/test/base/path/assets/output', - '.published-same-dir-class {background-image: url(../input/published_same_dir.png);}', - ], - [ - '.published-relative-dir-class {background-image: url(../img/published_relative_dir.png);}', - '/test/base/path/assets/input', - '/test/base/path/assets/output', - '.published-relative-dir-class {background-image: url(../img/published_relative_dir.png);}', - ], - [ - '.static-same-dir-class {background-image: url(\'static_same_dir.png\');}', - '/test/base/path/css', - '/test/base/path/assets/output', - '.static-same-dir-class {background-image: url(\'../../css/static_same_dir.png\');}', - ], - [ - '.static-relative-dir-class {background-image: url("../img/static_relative_dir.png");}', - '/test/base/path/css', - '/test/base/path/assets/output', - '.static-relative-dir-class {background-image: url("../../img/static_relative_dir.png");}', - ], - [ - '.absolute-url-class {background-image: url(http://domain.com/img/image.gif);}', - '/test/base/path/assets/input', - '/test/base/path/assets/output', - '.absolute-url-class {background-image: url(http://domain.com/img/image.gif);}', - ], - [ - '.absolute-url-secure-class {background-image: url(https://secure.domain.com/img/image.gif);}', - '/test/base/path/assets/input', - '/test/base/path/assets/output', - '.absolute-url-secure-class {background-image: url(https://secure.domain.com/img/image.gif);}', - ], - ]; - } - - /** - * @dataProvider adjustCssUrlDataProvider - * - * @param $cssContent - * @param $inputFilePath - * @param $outputFilePath - * @param $expectedCssContent - */ - public function testAdjustCssUrl($cssContent, $inputFilePath, $outputFilePath, $expectedCssContent) - { - $adjustedCssContent = $this->invokeAssetControllerMethod('adjustCssUrl', [$cssContent, $inputFilePath, $outputFilePath]); - - $this->assertEquals($expectedCssContent, $adjustedCssContent, 'Unable to adjust CSS correctly!'); - } -} diff --git a/tests/unit/framework/console/controllers/MessageControllerTest.php b/tests/unit/framework/console/controllers/MessageControllerTest.php deleted file mode 100644 index 465294f..0000000 --- a/tests/unit/framework/console/controllers/MessageControllerTest.php +++ /dev/null @@ -1,369 +0,0 @@ -mockApplication(); - $this->sourcePath = Yii::getAlias('@yiiunit/runtime/test_source'); - $this->createDir($this->sourcePath); - if (!file_exists($this->sourcePath)) { - $this->markTestIncomplete('Unit tests runtime directory should have writable permissions!'); - } - $this->messagePath = Yii::getAlias('@yiiunit/runtime/test_messages'); - $this->createDir($this->messagePath); - $this->configFileName = Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . 'message_controller_test_config.php'; - } - - public function tearDown() - { - $this->removeDir($this->sourcePath); - $this->removeDir($this->messagePath); - if (file_exists($this->configFileName)) { - unlink($this->configFileName); - } - } - - /** - * Creates directory. - * @param $dirName directory full name - */ - protected function createDir($dirName) - { - if (!file_exists($dirName)) { - mkdir($dirName, 0777, true); - } - } - - /** - * Removes directory. - * @param $dirName directory full name - */ - protected function removeDir($dirName) - { - if (!empty($dirName) && file_exists($dirName)) { - $this->removeFileSystemObject($dirName); - } - } - - /** - * Removes file system object: directory or file. - * @param string $fileSystemObjectFullName file system object full name. - */ - protected function removeFileSystemObject($fileSystemObjectFullName) - { - if (!is_dir($fileSystemObjectFullName)) { - unlink($fileSystemObjectFullName); - } else { - $dirHandle = opendir($fileSystemObjectFullName); - while (($fileSystemObjectName = readdir($dirHandle)) !== false) { - if ($fileSystemObjectName==='.' || $fileSystemObjectName==='..') { - continue; - } - $this->removeFileSystemObject($fileSystemObjectFullName . DIRECTORY_SEPARATOR . $fileSystemObjectName); - } - closedir($dirHandle); - rmdir($fileSystemObjectFullName); - } - } - - /** - * Creates test message controller instance. - * @return MessageController message command instance. - */ - protected function createMessageController() - { - $module = $this->getMock('yii\\base\\Module', ['fake'], ['console']); - $messageController = new MessageController('message', $module); - $messageController->interactive = false; - return $messageController; - } - - /** - * Emulates running of the message controller action. - * @param string $actionId id of action to be run. - * @param array $args action arguments. - * @return string command output. - */ - protected function runMessageControllerAction($actionId, array $args = []) - { - $controller = $this->createMessageController(); - ob_start(); - ob_implicit_flush(false); - $controller->run($actionId, $args); - return ob_get_clean(); - } - - /** - * Creates message command config file named as [[configFileName]]. - * @param array $config message command config. - */ - protected function composeConfigFile(array $config) - { - if (file_exists($this->configFileName)) { - unlink($this->configFileName); - } - $fileContent = 'configFileName, $fileContent); - } - - /** - * Creates source file with given content - * @param string $content file content - * @param string|null $name file self name - */ - protected function createSourceFile($content, $name = null) - { - if (empty($name)) { - $name = md5(uniqid()) . '.php'; - } - file_put_contents($this->sourcePath . DIRECTORY_SEPARATOR . $name, $content); - } - - /** - * Creates message file with given messages. - * @param string $name file name - * @param array $messages messages. - */ - protected function createMessageFile($name, array $messages = []) - { - $fileName = $this->messagePath . DIRECTORY_SEPARATOR . $name; - if (file_exists($fileName)) { - unlink($fileName); - } else { - $dirName = dirname($fileName); - if (!file_exists($dirName)) { - mkdir($dirName, 0777, true); - } - } - $fileContent = 'configFileName; - $this->runMessageControllerAction('config', [$configFileName]); - $this->assertTrue(file_exists($configFileName), 'Unable to create config file template!'); - } - - public function testConfigFileNotExist() - { - $this->setExpectedException('yii\\console\\Exception'); - $this->runMessageControllerAction('extract', ['not_existing_file.php']); - } - - public function testCreateTranslation() - { - $language = 'en'; - - $category = 'test_category'; - $message = 'test message'; - $sourceFileContent = "Yii::t('{$category}', '{$message}')"; - $this->createSourceFile($sourceFileContent); - - $this->composeConfigFile([ - 'languages' => [$language], - 'sourcePath' => $this->sourcePath, - 'messagePath' => $this->messagePath, - ]); - $this->runMessageControllerAction('extract', [$this->configFileName]); - - $this->assertTrue(file_exists($this->messagePath . DIRECTORY_SEPARATOR . $language), 'No language dir created!'); - $messageFileName = $this->messagePath . DIRECTORY_SEPARATOR . $language . DIRECTORY_SEPARATOR . $category . '.php'; - $this->assertTrue(file_exists($messageFileName), 'No message file created!'); - $messages = require($messageFileName); - $this->assertTrue(is_array($messages), 'Unable to compose messages!'); - $this->assertTrue(array_key_exists($message, $messages), 'Source message is missing!'); - } - - /** - * @depends testCreateTranslation - */ - public function testNothingNew() - { - $language = 'en'; - - $category = 'test_category'; - $message = 'test message'; - $sourceFileContent = "Yii::t('{$category}', '{$message}')"; - $this->createSourceFile($sourceFileContent); - - $this->composeConfigFile([ - 'languages' => [$language], - 'sourcePath' => $this->sourcePath, - 'messagePath' => $this->messagePath, - ]); - $this->runMessageControllerAction('extract', [$this->configFileName]); - - $messageFileName = $this->messagePath . DIRECTORY_SEPARATOR . $language . DIRECTORY_SEPARATOR . $category . '.php'; - - // check file not overwritten: - $messageFileContent = file_get_contents($messageFileName); - $messageFileContent .= '// some not generated by command content'; - file_put_contents($messageFileName, $messageFileContent); - - $this->runMessageControllerAction('extract', [$this->configFileName]); - - $this->assertEquals($messageFileContent, file_get_contents($messageFileName)); - } - - /** - * @depends testCreateTranslation - */ - public function testMerge() - { - $language = 'en'; - $category = 'test_category'; - $messageFileName = $language . DIRECTORY_SEPARATOR . $category . '.php'; - - $existingMessage = 'test existing message'; - $existingMessageContent = 'test existing message content'; - $this->createMessageFile($messageFileName, [ - $existingMessage => $existingMessageContent - ]); - - $newMessage = 'test new message'; - $sourceFileContent = "Yii::t('{$category}', '{$existingMessage}')"; - $sourceFileContent .= "Yii::t('{$category}', '{$newMessage}')"; - $this->createSourceFile($sourceFileContent); - - $this->composeConfigFile([ - 'languages' => [$language], - 'sourcePath' => $this->sourcePath, - 'messagePath' => $this->messagePath, - 'overwrite' => true, - ]); - $this->runMessageControllerAction('extract', [$this->configFileName]); - - $messages = require($this->messagePath . DIRECTORY_SEPARATOR . $messageFileName); - $this->assertTrue(array_key_exists($newMessage, $messages), 'Unable to add new message!'); - $this->assertTrue(array_key_exists($existingMessage, $messages), 'Unable to keep existing message!'); - $this->assertEquals('', $messages[$newMessage], 'Wrong new message content!'); - $this->assertEquals($existingMessageContent, $messages[$existingMessage], 'Unable to keep existing message content!'); - } - - /** - * @depends testMerge - */ - public function testNoLongerNeedTranslation() - { - $language = 'en'; - $category = 'test_category'; - $messageFileName = $language . DIRECTORY_SEPARATOR . $category . '.php'; - - $oldMessage = 'test old message'; - $oldMessageContent = 'test old message content'; - $this->createMessageFile($messageFileName, [ - $oldMessage => $oldMessageContent - ]); - - $sourceFileContent = "Yii::t('{$category}', 'some new message')"; - $this->createSourceFile($sourceFileContent); - - $this->composeConfigFile([ - 'languages' => [$language], - 'sourcePath' => $this->sourcePath, - 'messagePath' => $this->messagePath, - 'overwrite' => true, - 'removeUnused' => false, - ]); - $this->runMessageControllerAction('extract', [$this->configFileName]); - - $messages = require($this->messagePath . DIRECTORY_SEPARATOR . $messageFileName); - - $this->assertTrue(array_key_exists($oldMessage, $messages), 'No longer needed message removed!'); - $this->assertEquals('@@' . $oldMessageContent . '@@', $messages[$oldMessage], 'No longer needed message content does not marked properly!'); - } - - /** - * @depends testMerge - */ - public function testMergeWithContentZero() - { - $language = 'en'; - $category = 'test_category'; - $messageFileName = $language . DIRECTORY_SEPARATOR . $category . '.php'; - - $zeroMessage = 'test zero message'; - $zeroMessageContent = '0'; - $falseMessage = 'test false message'; - $falseMessageContent = 'false'; - $this->createMessageFile($messageFileName, [ - $zeroMessage => $zeroMessageContent, - $falseMessage => $falseMessageContent, - ]); - - $newMessage = 'test new message'; - $sourceFileContent = "Yii::t('{$category}', '{$zeroMessage}')"; - $sourceFileContent .= "Yii::t('{$category}', '{$falseMessage}')"; - $sourceFileContent .= "Yii::t('{$category}', '{$newMessage}')"; - $this->createSourceFile($sourceFileContent); - - $this->composeConfigFile([ - 'languages' => [$language], - 'sourcePath' => $this->sourcePath, - 'messagePath' => $this->messagePath, - 'overwrite' => true, - ]); - $this->runMessageControllerAction('extract', [$this->configFileName]); - - $messages = require($this->messagePath . DIRECTORY_SEPARATOR . $messageFileName); - $this->assertTrue($zeroMessageContent === $messages[$zeroMessage], 'Message content "0" is lost!'); - $this->assertTrue($falseMessageContent === $messages[$falseMessage], 'Message content "false" is lost!'); - } - - /** - * @depends testCreateTranslation - */ - public function testMultiplyTranslators() - { - $language = 'en'; - $category = 'test_category'; - - $translators = [ - 'Yii::t', - 'Custom::translate', - ]; - - $sourceMessages = [ - 'first message', - 'second message', - ]; - $sourceFileContent = ''; - foreach ($sourceMessages as $key => $message) { - $sourceFileContent .= $translators[$key] . "('{$category}', '{$message}');\n"; - } - $this->createSourceFile($sourceFileContent); - - $this->composeConfigFile([ - 'languages' => [$language], - 'sourcePath' => $this->sourcePath, - 'messagePath' => $this->messagePath, - 'translator' => $translators, - ]); - $this->runMessageControllerAction('extract', [$this->configFileName]); - - $messageFileName = $this->messagePath . DIRECTORY_SEPARATOR . $language . DIRECTORY_SEPARATOR . $category . '.php'; - $messages = require($messageFileName); - - foreach ($sourceMessages as $sourceMessage) { - $this->assertTrue(array_key_exists($sourceMessage, $messages)); - } - } -} diff --git a/tests/unit/framework/data/ActiveDataProviderTest.php b/tests/unit/framework/data/ActiveDataProviderTest.php deleted file mode 100644 index a58deab..0000000 --- a/tests/unit/framework/data/ActiveDataProviderTest.php +++ /dev/null @@ -1,180 +0,0 @@ - - * @since 2.0 - * - * @group data - * @group db - */ -class ActiveDataProviderTest extends DatabaseTestCase -{ - protected function setUp() - { - parent::setUp(); - ActiveRecord::$db = $this->getConnection(); - } - - public function testActiveQuery() - { - $provider = new ActiveDataProvider([ - 'query' => Order::find()->orderBy('id'), - ]); - $orders = $provider->getModels(); - $this->assertEquals(3, count($orders)); - $this->assertTrue($orders[0] instanceof Order); - $this->assertTrue($orders[1] instanceof Order); - $this->assertTrue($orders[2] instanceof Order); - $this->assertEquals([1, 2, 3], $provider->getKeys()); - - $provider = new ActiveDataProvider([ - 'query' => Order::find(), - 'pagination' => [ - 'pageSize' => 2, - ] - ]); - $orders = $provider->getModels(); - $this->assertEquals(2, count($orders)); - } - - public function testActiveRelation() - { - /** @var Customer $customer */ - $customer = Customer::find(2); - $provider = new ActiveDataProvider([ - 'query' => $customer->getOrders(), - ]); - $orders = $provider->getModels(); - $this->assertEquals(2, count($orders)); - $this->assertTrue($orders[0] instanceof Order); - $this->assertTrue($orders[1] instanceof Order); - $this->assertEquals([2, 3], $provider->getKeys()); - - $provider = new ActiveDataProvider([ - 'query' => $customer->getOrders(), - 'pagination' => [ - 'pageSize' => 1, - ] - ]); - $orders = $provider->getModels(); - $this->assertEquals(1, count($orders)); - } - - public function testActiveRelationVia() - { - /** @var Order $order */ - $order = Order::find(2); - $provider = new ActiveDataProvider([ - 'query' => $order->getItems(), - ]); - $items = $provider->getModels(); - $this->assertEquals(3, count($items)); - $this->assertTrue($items[0] instanceof Item); - $this->assertTrue($items[1] instanceof Item); - $this->assertTrue($items[2] instanceof Item); - $this->assertEquals([3, 4, 5], $provider->getKeys()); - - $provider = new ActiveDataProvider([ - 'query' => $order->getItems(), - 'pagination' => [ - 'pageSize' => 2, - ] - ]); - $items = $provider->getModels(); - $this->assertEquals(2, count($items)); - } - - public function testActiveRelationViaTable() - { - /** @var Order $order */ - $order = Order::find(1); - $provider = new ActiveDataProvider([ - 'query' => $order->getBooks(), - ]); - $items = $provider->getModels(); - $this->assertEquals(2, count($items)); - $this->assertTrue($items[0] instanceof Item); - $this->assertTrue($items[1] instanceof Item); - - $provider = new ActiveDataProvider([ - 'query' => $order->getBooks(), - 'pagination' => [ - 'pageSize' => 1, - ] - ]); - $items = $provider->getModels(); - $this->assertEquals(1, count($items)); - } - - public function testQuery() - { - $query = new Query; - $provider = new ActiveDataProvider([ - 'db' => $this->getConnection(), - 'query' => $query->from('tbl_order')->orderBy('id'), - ]); - $orders = $provider->getModels(); - $this->assertEquals(3, count($orders)); - $this->assertTrue(is_array($orders[0])); - $this->assertEquals([0, 1, 2], $provider->getKeys()); - - $query = new Query; - $provider = new ActiveDataProvider([ - 'db' => $this->getConnection(), - 'query' => $query->from('tbl_order'), - 'pagination' => [ - 'pageSize' => 2, - ] - ]); - $orders = $provider->getModels(); - $this->assertEquals(2, count($orders)); - } - - public function testRefresh() - { - $query = new Query; - $provider = new ActiveDataProvider([ - 'db' => $this->getConnection(), - 'query' => $query->from('tbl_order')->orderBy('id'), - ]); - $this->assertEquals(3, count($provider->getModels())); - - $provider->getPagination()->pageSize = 2; - $this->assertEquals(3, count($provider->getModels())); - $provider->refresh(); - $this->assertEquals(2, count($provider->getModels())); - } - - public function testPaginationBeforeModels() - { - $query = new Query; - $provider = new ActiveDataProvider([ - 'db' => $this->getConnection(), - 'query' => $query->from('tbl_order')->orderBy('id'), - ]); - $pagination = $provider->getPagination(); - $this->assertEquals(0, $pagination->getPageCount()); - $this->assertCount(3, $provider->getModels()); - $this->assertEquals(1, $pagination->getPageCount()); - - $provider->getPagination()->pageSize = 2; - $this->assertEquals(3, count($provider->getModels())); - $provider->refresh(); - $this->assertEquals(2, count($provider->getModels())); - } -} diff --git a/tests/unit/framework/data/SortTest.php b/tests/unit/framework/data/SortTest.php deleted file mode 100644 index c21990e..0000000 --- a/tests/unit/framework/data/SortTest.php +++ /dev/null @@ -1,178 +0,0 @@ - - * @since 2.0 - * - * @group data - */ -class SortTest extends TestCase -{ - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - - public function testGetOrders() - { - $sort = new Sort([ - 'attributes' => [ - 'age', - 'name' => [ - 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - ], - ], - 'params' => [ - 'sort' => 'age.name-desc' - ], - 'enableMultiSort' => true, - ]); - - $orders = $sort->getOrders(); - $this->assertEquals(3, count($orders)); - $this->assertEquals(SORT_ASC, $orders['age']); - $this->assertEquals(SORT_DESC, $orders['first_name']); - $this->assertEquals(SORT_DESC, $orders['last_name']); - - $sort->enableMultiSort = false; - $orders = $sort->getOrders(true); - $this->assertEquals(1, count($orders)); - $this->assertEquals(SORT_ASC, $orders['age']); - } - - public function testGetAttributeOrders() - { - $sort = new Sort([ - 'attributes' => [ - 'age', - 'name' => [ - 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - ], - ], - 'params' => [ - 'sort' => 'age.name-desc' - ], - 'enableMultiSort' => true, - ]); - - $orders = $sort->getAttributeOrders(); - $this->assertEquals(2, count($orders)); - $this->assertEquals(SORT_ASC, $orders['age']); - $this->assertEquals(SORT_DESC, $orders['name']); - - $sort->enableMultiSort = false; - $orders = $sort->getAttributeOrders(true); - $this->assertEquals(1, count($orders)); - $this->assertEquals(SORT_ASC, $orders['age']); - } - - public function testGetAttributeOrder() - { - $sort = new Sort([ - 'attributes' => [ - 'age', - 'name' => [ - 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - ], - ], - 'params' => [ - 'sort' => 'age.name-desc' - ], - 'enableMultiSort' => true, - ]); - - $this->assertEquals(SORT_ASC, $sort->getAttributeOrder('age')); - $this->assertEquals(SORT_DESC, $sort->getAttributeOrder('name')); - $this->assertNull($sort->getAttributeOrder('xyz')); - } - - public function testCreateSortVar() - { - $sort = new Sort([ - 'attributes' => [ - 'age', - 'name' => [ - 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - ], - ], - 'params' => [ - 'sort' => 'age.name-desc' - ], - 'enableMultiSort' => true, - 'route' => 'site/index', - ]); - - $this->assertEquals('age-desc.name-desc', $sort->createSortVar('age')); - $this->assertEquals('name.age', $sort->createSortVar('name')); - } - - public function testCreateUrl() - { - $manager = new UrlManager([ - 'baseUrl' => '/index.php', - 'cache' => null, - ]); - - $sort = new Sort([ - 'attributes' => [ - 'age', - 'name' => [ - 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - ], - ], - 'params' => [ - 'sort' => 'age.name-desc' - ], - 'enableMultiSort' => true, - 'urlManager' => $manager, - 'route' => 'site/index', - ]); - - $this->assertEquals('/index.php?r=site/index&sort=age-desc.name-desc', $sort->createUrl('age')); - $this->assertEquals('/index.php?r=site/index&sort=name.age', $sort->createUrl('name')); - } - - public function testLink() - { - $this->mockApplication(); - $manager = new UrlManager([ - 'baseUrl' => '/index.php', - 'cache' => null, - ]); - - $sort = new Sort([ - 'attributes' => [ - 'age', - 'name' => [ - 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - ], - ], - 'params' => [ - 'sort' => 'age.name-desc' - ], - 'enableMultiSort' => true, - 'urlManager' => $manager, - 'route' => 'site/index', - ]); - - $this->assertEquals('Age', $sort->link('age')); - } -} diff --git a/tests/unit/framework/db/ActiveRecordTest.php b/tests/unit/framework/db/ActiveRecordTest.php deleted file mode 100644 index 37339dc..0000000 --- a/tests/unit/framework/db/ActiveRecordTest.php +++ /dev/null @@ -1,328 +0,0 @@ -getConnection(); - } - - public function callCustomerFind($q = null) { return Customer::find($q); } - public function callOrderFind($q = null) { return Order::find($q); } - public function callOrderItemFind($q = null) { return OrderItem::find($q); } - public function callItemFind($q = null) { return Item::find($q); } - - public function getCustomerClass() { return Customer::className(); } - public function getItemClass() { return Item::className(); } - public function getOrderClass() { return Order::className(); } - public function getOrderItemClass() { return OrderItem::className(); } - - public function testCustomColumns() - { - // find custom column - $customer = $this->callCustomerFind()->select(['*', '(status*2) AS status2']) - ->where(['name' => 'user3'])->one(); - $this->assertEquals(3, $customer->id); - $this->assertEquals(4, $customer->status2); - } - - public function testStatisticalFind() - { - // find count, sum, average, min, max, scalar - $this->assertEquals(3, $this->callCustomerFind()->count()); - $this->assertEquals(2, $this->callCustomerFind()->where('id=1 OR id=2')->count()); - $this->assertEquals(6, $this->callCustomerFind()->sum('id')); - $this->assertEquals(2, $this->callCustomerFind()->average('id')); - $this->assertEquals(1, $this->callCustomerFind()->min('id')); - $this->assertEquals(3, $this->callCustomerFind()->max('id')); - $this->assertEquals(3, $this->callCustomerFind()->select('COUNT(*)')->scalar()); - } - - public function testFindScalar() - { - // query scalar - $customerName = $this->callCustomerFind()->where(array('id' => 2))->select('name')->scalar(); - $this->assertEquals('user2', $customerName); - } - - public function testFindColumn() - { - /** @var TestCase|ActiveRecordTestTrait $this */ - $this->assertEquals(['user1', 'user2', 'user3'], Customer::find()->select('name')->column()); - $this->assertEquals(['user3', 'user2', 'user1'], Customer::find()->orderBy(['name' => SORT_DESC])->select('name')->column()); - } - - public function testFindBySql() - { - // find one - $customer = Customer::findBySql('SELECT * FROM tbl_customer ORDER BY id DESC')->one(); - $this->assertTrue($customer instanceof Customer); - $this->assertEquals('user3', $customer->name); - - // find all - $customers = Customer::findBySql('SELECT * FROM tbl_customer')->all(); - $this->assertEquals(3, count($customers)); - - // find with parameter binding - $customer = Customer::findBySql('SELECT * FROM tbl_customer WHERE id=:id', [':id' => 2])->one(); - $this->assertTrue($customer instanceof Customer); - $this->assertEquals('user2', $customer->name); - } - - public function testFindLazyViaTable() - { - /** @var Order $order */ - $order = Order::find(1); - $this->assertEquals(1, $order->id); - $this->assertEquals(2, count($order->books)); - $this->assertEquals(1, $order->items[0]->id); - $this->assertEquals(2, $order->items[1]->id); - - $order = Order::find(2); - $this->assertEquals(2, $order->id); - $this->assertEquals(0, count($order->books)); - } - - public function testFindEagerViaTable() - { - $orders = Order::find()->with('books')->orderBy('id')->all(); - $this->assertEquals(3, count($orders)); - - $order = $orders[0]; - $this->assertEquals(1, $order->id); - $this->assertEquals(2, count($order->books)); - $this->assertEquals(1, $order->books[0]->id); - $this->assertEquals(2, $order->books[1]->id); - - $order = $orders[1]; - $this->assertEquals(2, $order->id); - $this->assertEquals(0, count($order->books)); - - $order = $orders[2]; - $this->assertEquals(3, $order->id); - $this->assertEquals(1, count($order->books)); - $this->assertEquals(2, $order->books[0]->id); - - // https://github.com/yiisoft/yii2/issues/1402 - $orders = Order::find()->with('books')->orderBy('id')->asArray()->all(); - $this->assertEquals(3, count($orders)); - - $order = $orders[0]; - $this->assertTrue(is_array($order)); - $this->assertEquals(1, $order['id']); - $this->assertEquals(2, count($order['books'])); - $this->assertEquals(1, $order['books'][0]['id']); - $this->assertEquals(2, $order['books'][1]['id']); - } - - public function testStoreNull() - { - $record = new NullValues(); - $this->assertNull($record->var1); - $this->assertNull($record->var2); - $this->assertNull($record->var3); - $this->assertNull($record->stringcol); - - $record->id = 1; - - $record->var1 = 123; - $record->var2 = 456; - $record->var3 = 789; - $record->stringcol = 'hello!'; - - $record->save(false); - $this->assertTrue($record->refresh()); - - $this->assertEquals(123, $record->var1); - $this->assertEquals(456, $record->var2); - $this->assertEquals(789, $record->var3); - $this->assertEquals('hello!', $record->stringcol); - - $record->var1 = null; - $record->var2 = null; - $record->var3 = null; - $record->stringcol = null; - - $record->save(false); - $this->assertTrue($record->refresh()); - - $this->assertNull($record->var1); - $this->assertNull($record->var2); - $this->assertNull($record->var3); - $this->assertNull($record->stringcol); - - $record->var1 = 0; - $record->var2 = 0; - $record->var3 = 0; - $record->stringcol = ''; - - $record->save(false); - $this->assertTrue($record->refresh()); - - $this->assertEquals(0, $record->var1); - $this->assertEquals(0, $record->var2); - $this->assertEquals(0, $record->var3); - $this->assertEquals('', $record->stringcol); - } - - public function testStoreEmpty() - { - $record = new NullValues(); - $record->id = 1; - - // this is to simulate empty html form submission - $record->var1 = ''; - $record->var2 = ''; - $record->var3 = ''; - $record->stringcol = ''; - - $record->save(false); - $this->assertTrue($record->refresh()); - - // https://github.com/yiisoft/yii2/commit/34945b0b69011bc7cab684c7f7095d837892a0d4#commitcomment-4458225 - $this->assertTrue($record->var1 === $record->var2); - $this->assertTrue($record->var2 === $record->var3); - } - - public function testIsPrimaryKey() - { - $this->assertFalse(Customer::isPrimaryKey([])); - $this->assertTrue(Customer::isPrimaryKey(['id'])); - $this->assertFalse(Customer::isPrimaryKey(['id', 'name'])); - $this->assertFalse(Customer::isPrimaryKey(['name'])); - $this->assertFalse(Customer::isPrimaryKey(['name', 'email'])); - - $this->assertFalse(OrderItem::isPrimaryKey([])); - $this->assertFalse(OrderItem::isPrimaryKey(['order_id'])); - $this->assertFalse(OrderItem::isPrimaryKey(['item_id'])); - $this->assertFalse(OrderItem::isPrimaryKey(['quantity'])); - $this->assertFalse(OrderItem::isPrimaryKey(['quantity', 'subtotal'])); - $this->assertTrue(OrderItem::isPrimaryKey(['order_id', 'item_id'])); - $this->assertFalse(OrderItem::isPrimaryKey(['order_id', 'item_id', 'quantity'])); - } - - public function testJoinWith() - { - // left join and eager loading - $orders = Order::find()->joinWith('customer')->orderBy('tbl_customer.id DESC, tbl_order.id')->all(); - $this->assertEquals(3, count($orders)); - $this->assertEquals(2, $orders[0]->id); - $this->assertEquals(3, $orders[1]->id); - $this->assertEquals(1, $orders[2]->id); - $this->assertTrue($orders[0]->isRelationPopulated('customer')); - $this->assertTrue($orders[1]->isRelationPopulated('customer')); - $this->assertTrue($orders[2]->isRelationPopulated('customer')); - - // inner join filtering and eager loading - $orders = Order::find()->innerJoinWith([ - 'customer' => function ($query) { - $query->where('tbl_customer.id=2'); - }, - ])->orderBy('tbl_order.id')->all(); - $this->assertEquals(2, count($orders)); - $this->assertEquals(2, $orders[0]->id); - $this->assertEquals(3, $orders[1]->id); - $this->assertTrue($orders[0]->isRelationPopulated('customer')); - $this->assertTrue($orders[1]->isRelationPopulated('customer')); - - // inner join filtering without eager loading - $orders = Order::find()->innerJoinWith([ - 'customer' => function ($query) { - $query->where('tbl_customer.id=2'); - }, - ], false)->orderBy('tbl_order.id')->all(); - $this->assertEquals(2, count($orders)); - $this->assertEquals(2, $orders[0]->id); - $this->assertEquals(3, $orders[1]->id); - $this->assertFalse($orders[0]->isRelationPopulated('customer')); - $this->assertFalse($orders[1]->isRelationPopulated('customer')); - - // join with via-relation - $orders = Order::find()->innerJoinWith('books')->orderBy('tbl_order.id')->all(); - $this->assertEquals(2, count($orders)); - $this->assertEquals(1, $orders[0]->id); - $this->assertEquals(3, $orders[1]->id); - $this->assertTrue($orders[0]->isRelationPopulated('books')); - $this->assertTrue($orders[1]->isRelationPopulated('books')); - $this->assertEquals(2, count($orders[0]->books)); - $this->assertEquals(1, count($orders[1]->books)); - - // join with sub-relation - $orders = Order::find()->innerJoinWith([ - 'items.category' => function ($q) { - $q->where('tbl_category.id = 2'); - }, - ])->orderBy('tbl_order.id')->all(); - $this->assertEquals(1, count($orders)); - $this->assertTrue($orders[0]->isRelationPopulated('items')); - $this->assertEquals(2, $orders[0]->id); - $this->assertEquals(3, count($orders[0]->items)); - $this->assertTrue($orders[0]->items[0]->isRelationPopulated('category')); - $this->assertEquals(2, $orders[0]->items[0]->category->id); - - // join with table alias - $orders = Order::find()->joinWith([ - 'customer' => function ($q) { - $q->from('tbl_customer c'); - } - ])->orderBy('c.id DESC, tbl_order.id')->all(); - $this->assertEquals(3, count($orders)); - $this->assertEquals(2, $orders[0]->id); - $this->assertEquals(3, $orders[1]->id); - $this->assertEquals(1, $orders[2]->id); - $this->assertTrue($orders[0]->isRelationPopulated('customer')); - $this->assertTrue($orders[1]->isRelationPopulated('customer')); - $this->assertTrue($orders[2]->isRelationPopulated('customer')); - - // join with ON condition - $orders = Order::find()->joinWith('books2')->orderBy('tbl_order.id')->all(); - $this->assertEquals(3, count($orders)); - $this->assertEquals(1, $orders[0]->id); - $this->assertEquals(2, $orders[1]->id); - $this->assertEquals(3, $orders[2]->id); - $this->assertTrue($orders[0]->isRelationPopulated('books2')); - $this->assertTrue($orders[1]->isRelationPopulated('books2')); - $this->assertTrue($orders[2]->isRelationPopulated('books2')); - $this->assertEquals(2, count($orders[0]->books2)); - $this->assertEquals(0, count($orders[1]->books2)); - $this->assertEquals(1, count($orders[2]->books2)); - - // lazy loading with ON condition - $order = Order::find(1); - $this->assertEquals(2, count($order->books2)); - $order = Order::find(2); - $this->assertEquals(0, count($order->books2)); - $order = Order::find(3); - $this->assertEquals(1, count($order->books2)); - - // eager loading with ON condition - $orders = Order::find()->with('books2')->all(); - $this->assertEquals(3, count($orders)); - $this->assertEquals(1, $orders[0]->id); - $this->assertEquals(2, $orders[1]->id); - $this->assertEquals(3, $orders[2]->id); - $this->assertTrue($orders[0]->isRelationPopulated('books2')); - $this->assertTrue($orders[1]->isRelationPopulated('books2')); - $this->assertTrue($orders[2]->isRelationPopulated('books2')); - $this->assertEquals(2, count($orders[0]->books2)); - $this->assertEquals(0, count($orders[1]->books2)); - $this->assertEquals(1, count($orders[2]->books2)); - } -} diff --git a/tests/unit/framework/db/CommandTest.php b/tests/unit/framework/db/CommandTest.php deleted file mode 100644 index 64eb2df..0000000 --- a/tests/unit/framework/db/CommandTest.php +++ /dev/null @@ -1,278 +0,0 @@ -getConnection(false); - - // null - $command = $db->createCommand(); - $this->assertEquals(null, $command->sql); - - // string - $sql = 'SELECT * FROM tbl_customer'; - $command = $db->createCommand($sql); - $this->assertEquals($sql, $command->sql); - } - - public function testGetSetSql() - { - $db = $this->getConnection(false); - - $sql = 'SELECT * FROM tbl_customer'; - $command = $db->createCommand($sql); - $this->assertEquals($sql, $command->sql); - - $sql2 = 'SELECT * FROM tbl_order'; - $command->sql = $sql2; - $this->assertEquals($sql2, $command->sql); - } - - public function testAutoQuoting() - { - $db = $this->getConnection(false); - - $sql = 'SELECT [[id]], [[t.name]] FROM {{tbl_customer}} t'; - $command = $db->createCommand($sql); - $this->assertEquals("SELECT `id`, `t`.`name` FROM `tbl_customer` t", $command->sql); - } - - public function testPrepareCancel() - { - $db = $this->getConnection(false); - - $command = $db->createCommand('SELECT * FROM tbl_customer'); - $this->assertEquals(null, $command->pdoStatement); - $command->prepare(); - $this->assertNotEquals(null, $command->pdoStatement); - $command->cancel(); - $this->assertEquals(null, $command->pdoStatement); - } - - public function testExecute() - { - $db = $this->getConnection(); - - $sql = 'INSERT INTO tbl_customer(email, name , address) VALUES (\'user4@example.com\', \'user4\', \'address4\')'; - $command = $db->createCommand($sql); - $this->assertEquals(1, $command->execute()); - - $sql = 'SELECT COUNT(*) FROM tbl_customer WHERE name =\'user4\''; - $command = $db->createCommand($sql); - $this->assertEquals(1, $command->queryScalar()); - - $command = $db->createCommand('bad SQL'); - $this->setExpectedException('\yii\db\Exception'); - $command->execute(); - } - - public function testQuery() - { - $db = $this->getConnection(); - - // query - $sql = 'SELECT * FROM tbl_customer'; - $reader = $db->createCommand($sql)->query(); - $this->assertTrue($reader instanceof DataReader); - - // queryAll - $rows = $db->createCommand('SELECT * FROM tbl_customer')->queryAll(); - $this->assertEquals(3, count($rows)); - $row = $rows[2]; - $this->assertEquals(3, $row['id']); - $this->assertEquals('user3', $row['name']); - - $rows = $db->createCommand('SELECT * FROM tbl_customer WHERE id=10')->queryAll(); - $this->assertEquals([], $rows); - - // queryOne - $sql = 'SELECT * FROM tbl_customer ORDER BY id'; - $row = $db->createCommand($sql)->queryOne(); - $this->assertEquals(1, $row['id']); - $this->assertEquals('user1', $row['name']); - - $sql = 'SELECT * FROM tbl_customer ORDER BY id'; - $command = $db->createCommand($sql); - $command->prepare(); - $row = $command->queryOne(); - $this->assertEquals(1, $row['id']); - $this->assertEquals('user1', $row['name']); - - $sql = 'SELECT * FROM tbl_customer WHERE id=10'; - $command = $db->createCommand($sql); - $this->assertFalse($command->queryOne()); - - // queryColumn - $sql = 'SELECT * FROM tbl_customer'; - $column = $db->createCommand($sql)->queryColumn(); - $this->assertEquals(range(1, 3), $column); - - $command = $db->createCommand('SELECT id FROM tbl_customer WHERE id=10'); - $this->assertEquals([], $command->queryColumn()); - - // queryScalar - $sql = 'SELECT * FROM tbl_customer ORDER BY id'; - $this->assertEquals($db->createCommand($sql)->queryScalar(), 1); - - $sql = 'SELECT id FROM tbl_customer ORDER BY id'; - $command = $db->createCommand($sql); - $command->prepare(); - $this->assertEquals(1, $command->queryScalar()); - - $command = $db->createCommand('SELECT id FROM tbl_customer WHERE id=10'); - $this->assertFalse($command->queryScalar()); - - $command = $db->createCommand('bad SQL'); - $this->setExpectedException('\yii\db\Exception'); - $command->query(); - } - - public function testBindParamValue() - { - $db = $this->getConnection(); - - // bindParam - $sql = 'INSERT INTO tbl_customer(email, name, address) VALUES (:email, :name, :address)'; - $command = $db->createCommand($sql); - $email = 'user4@example.com'; - $name = 'user4'; - $address = 'address4'; - $command->bindParam(':email', $email); - $command->bindParam(':name', $name); - $command->bindParam(':address', $address); - $command->execute(); - - $sql = 'SELECT name FROM tbl_customer WHERE email=:email'; - $command = $db->createCommand($sql); - $command->bindParam(':email', $email); - $this->assertEquals($name, $command->queryScalar()); - - $sql = 'INSERT INTO tbl_type (int_col, char_col, float_col, blob_col, numeric_col, bool_col) VALUES (:int_col, :char_col, :float_col, :blob_col, :numeric_col, :bool_col)'; - $command = $db->createCommand($sql); - $intCol = 123; - $charCol = 'abc'; - $floatCol = 1.23; - $blobCol = "\x10\x11\x12"; - $numericCol = '1.23'; - $boolCol = false; - $command->bindParam(':int_col', $intCol); - $command->bindParam(':char_col', $charCol); - $command->bindParam(':float_col', $floatCol); - $command->bindParam(':blob_col', $blobCol); - $command->bindParam(':numeric_col', $numericCol); - $command->bindParam(':bool_col', $boolCol); - $this->assertEquals(1, $command->execute()); - - $sql = 'SELECT * FROM tbl_type'; - $row = $db->createCommand($sql)->queryOne(); - $this->assertEquals($intCol, $row['int_col']); - $this->assertEquals($charCol, $row['char_col']); - $this->assertEquals($floatCol, $row['float_col']); - $this->assertEquals($blobCol, $row['blob_col']); - $this->assertEquals($numericCol, $row['numeric_col']); - - // bindValue - $sql = 'INSERT INTO tbl_customer(email, name, address) VALUES (:email, \'user5\', \'address5\')'; - $command = $db->createCommand($sql); - $command->bindValue(':email', 'user5@example.com'); - $command->execute(); - - $sql = 'SELECT email FROM tbl_customer WHERE name=:name'; - $command = $db->createCommand($sql); - $command->bindValue(':name', 'user5'); - $this->assertEquals('user5@example.com', $command->queryScalar()); - } - - public function testFetchMode() - { - $db = $this->getConnection(); - - // default: FETCH_ASSOC - $sql = 'SELECT * FROM tbl_customer'; - $command = $db->createCommand($sql); - $result = $command->queryOne(); - $this->assertTrue(is_array($result) && isset($result['id'])); - - // FETCH_OBJ, customized via fetchMode property - $sql = 'SELECT * FROM tbl_customer'; - $command = $db->createCommand($sql); - $command->fetchMode = \PDO::FETCH_OBJ; - $result = $command->queryOne(); - $this->assertTrue(is_object($result)); - - // FETCH_NUM, customized in query method - $sql = 'SELECT * FROM tbl_customer'; - $command = $db->createCommand($sql); - $result = $command->queryOne([], \PDO::FETCH_NUM); - $this->assertTrue(is_array($result) && isset($result[0])); - } - - public function testInsert() - { - } - - public function testUpdate() - { - } - - public function testDelete() - { - } - - public function testCreateTable() - { - } - - public function testRenameTable() - { - } - - public function testDropTable() - { - } - - public function testTruncateTable() - { - } - - public function testAddColumn() - { - } - - public function testDropColumn() - { - } - - public function testRenameColumn() - { - } - - public function testAlterColumn() - { - } - - public function testAddForeignKey() - { - } - - public function testDropForeignKey() - { - } - - public function testCreateIndex() - { - } - - public function testDropIndex() - { - } -} diff --git a/tests/unit/framework/db/ConnectionTest.php b/tests/unit/framework/db/ConnectionTest.php deleted file mode 100644 index 04c5d53..0000000 --- a/tests/unit/framework/db/ConnectionTest.php +++ /dev/null @@ -1,80 +0,0 @@ -getConnection(false); - $params = $this->database; - - $this->assertEquals($params['dsn'], $connection->dsn); - $this->assertEquals($params['username'], $connection->username); - $this->assertEquals($params['password'], $connection->password); - } - - public function testOpenClose() - { - $connection = $this->getConnection(false, false); - - $this->assertFalse($connection->isActive); - $this->assertEquals(null, $connection->pdo); - - $connection->open(); - $this->assertTrue($connection->isActive); - $this->assertTrue($connection->pdo instanceof \PDO); - - $connection->close(); - $this->assertFalse($connection->isActive); - $this->assertEquals(null, $connection->pdo); - - $connection = new Connection; - $connection->dsn = 'unknown::memory:'; - $this->setExpectedException('yii\db\Exception'); - $connection->open(); - } - - public function testGetDriverName() - { - $connection = $this->getConnection(false, false); - $this->assertEquals($this->driverName, $connection->driverName); - } - - public function testQuoteValue() - { - $connection = $this->getConnection(false); - $this->assertEquals(123, $connection->quoteValue(123)); - $this->assertEquals("'string'", $connection->quoteValue('string')); - $this->assertEquals("'It\\'s interesting'", $connection->quoteValue("It's interesting")); - } - - public function testQuoteTableName() - { - $connection = $this->getConnection(false); - $this->assertEquals('`table`', $connection->quoteTableName('table')); - $this->assertEquals('`table`', $connection->quoteTableName('`table`')); - $this->assertEquals('`schema`.`table`', $connection->quoteTableName('schema.table')); - $this->assertEquals('`schema`.`table`', $connection->quoteTableName('schema.`table`')); - $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); - $this->assertEquals('(table)', $connection->quoteTableName('(table)')); - } - - public function testQuoteColumnName() - { - $connection = $this->getConnection(false); - $this->assertEquals('`column`', $connection->quoteColumnName('column')); - $this->assertEquals('`column`', $connection->quoteColumnName('`column`')); - $this->assertEquals('`table`.`column`', $connection->quoteColumnName('table.column')); - $this->assertEquals('`table`.`column`', $connection->quoteColumnName('table.`column`')); - $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); - $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); - $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); - } -} diff --git a/tests/unit/framework/db/DatabaseTestCase.php b/tests/unit/framework/db/DatabaseTestCase.php deleted file mode 100644 index 8ef1234..0000000 --- a/tests/unit/framework/db/DatabaseTestCase.php +++ /dev/null @@ -1,68 +0,0 @@ -getParam('databases'); - $this->database = $databases[$this->driverName]; - $pdo_database = 'pdo_'.$this->driverName; - - if (!extension_loaded('pdo') || !extension_loaded($pdo_database)) { - $this->markTestSkipped('pdo and '.$pdo_database.' extension are required.'); - } - $this->mockApplication(); - } - - protected function tearDown() - { - if ($this->db) { - $this->db->close(); - } - $this->destroyApplication(); - } - - /** - * @param bool $reset whether to clean up the test database - * @param bool $open whether to open and populate test database - * @return \yii\db\Connection - */ - public function getConnection($reset = true, $open = true) - { - if (!$reset && $this->db) { - return $this->db; - } - $db = new \yii\db\Connection; - $db->dsn = $this->database['dsn']; - if (isset($this->database['username'])) { - $db->username = $this->database['username']; - $db->password = $this->database['password']; - } - if (isset($this->database['attributes'])) { - $db->attributes = $this->database['attributes']; - } - if ($open) { - $db->open(); - $lines = explode(';', file_get_contents($this->database['fixture'])); - foreach ($lines as $line) { - if (trim($line) !== '') { - $db->pdo->exec($line); - } - } - } - $this->db = $db; - return $db; - } -} diff --git a/tests/unit/framework/db/QueryBuilderTest.php b/tests/unit/framework/db/QueryBuilderTest.php deleted file mode 100644 index b8eefe0..0000000 --- a/tests/unit/framework/db/QueryBuilderTest.php +++ /dev/null @@ -1,133 +0,0 @@ -driverName) { - case 'mysql': - return new MysqlQueryBuilder($this->getConnection()); - case 'sqlite': - return new SqliteQueryBuilder($this->getConnection()); - case 'mssql': - return new MssqlQueryBuilder($this->getConnection()); - case 'pgsql': - return new PgsqlQueryBuilder($this->getConnection()); - case 'cubrid': - return new CubridQueryBuilder($this->getConnection()); - } - throw new \Exception('Test is not implemented for ' . $this->driverName); - } - - /** - * this is not used as a dataprovider for testGetColumnType to speed up the test - * when used as dataprovider every single line will cause a reconnect with the database which is not needed here - */ - public function columnTypes() - { - return [ - [Schema::TYPE_PK, 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY'], - [Schema::TYPE_PK . '(8)', 'int(8) NOT NULL AUTO_INCREMENT PRIMARY KEY'], - [Schema::TYPE_PK . ' CHECK (value > 5)', 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'], - [Schema::TYPE_PK . '(8) CHECK (value > 5)', 'int(8) NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'], - [Schema::TYPE_STRING, 'varchar(255)'], - [Schema::TYPE_STRING . '(32)', 'varchar(32)'], - [Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'], - [Schema::TYPE_STRING . '(32) CHECK (value LIKE "test%")', 'varchar(32) CHECK (value LIKE "test%")'], - [Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'], - [Schema::TYPE_TEXT, 'text'], - [Schema::TYPE_TEXT . '(255)', 'text'], - [Schema::TYPE_TEXT . ' CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'], - [Schema::TYPE_TEXT . '(255) CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'], - [Schema::TYPE_TEXT . ' NOT NULL', 'text NOT NULL'], - [Schema::TYPE_TEXT . '(255) NOT NULL', 'text NOT NULL'], - [Schema::TYPE_SMALLINT, 'smallint(6)'], - [Schema::TYPE_SMALLINT . '(8)', 'smallint(8)'], - [Schema::TYPE_INTEGER, 'int(11)'], - [Schema::TYPE_INTEGER . '(8)', 'int(8)'], - [Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'int(11) CHECK (value > 5)'], - [Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'int(8) CHECK (value > 5)'], - [Schema::TYPE_INTEGER . ' NOT NULL', 'int(11) NOT NULL'], - [Schema::TYPE_BIGINT, 'bigint(20)'], - [Schema::TYPE_BIGINT . '(8)', 'bigint(8)'], - [Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint(20) CHECK (value > 5)'], - [Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint(8) CHECK (value > 5)'], - [Schema::TYPE_BIGINT . ' NOT NULL', 'bigint(20) NOT NULL'], - [Schema::TYPE_FLOAT, 'float'], - [Schema::TYPE_FLOAT . '(16,5)', 'float'], - [Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'float CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . '(16,5) CHECK (value > 5.6)', 'float CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . ' NOT NULL', 'float NOT NULL'], - [Schema::TYPE_DECIMAL, 'decimal(10,0)'], - [Schema::TYPE_DECIMAL . '(12,4)', 'decimal(12,4)'], - [Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'decimal(10,0) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'decimal(12,4) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . ' NOT NULL', 'decimal(10,0) NOT NULL'], - [Schema::TYPE_DATETIME, 'datetime'], - [Schema::TYPE_DATETIME . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "datetime CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATETIME . ' NOT NULL', 'datetime NOT NULL'], - [Schema::TYPE_TIMESTAMP, 'timestamp'], - [Schema::TYPE_TIMESTAMP . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp NOT NULL'], - [Schema::TYPE_TIME, 'time'], - [Schema::TYPE_TIME . " CHECK(value BETWEEN '12:00:00' AND '13:01:01')", "time CHECK(value BETWEEN '12:00:00' AND '13:01:01')"], - [Schema::TYPE_TIME . ' NOT NULL', 'time NOT NULL'], - [Schema::TYPE_DATE, 'date'], - [Schema::TYPE_DATE . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'], - [Schema::TYPE_BINARY, 'blob'], - [Schema::TYPE_BOOLEAN, 'tinyint(1)'], - [Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'tinyint(1) NOT NULL DEFAULT 1'], - [Schema::TYPE_MONEY, 'decimal(19,4)'], - [Schema::TYPE_MONEY . '(16,2)', 'decimal(16,2)'], - [Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'decimal(19,4) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'decimal(16,2) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . ' NOT NULL', 'decimal(19,4) NOT NULL'], - ]; - } - - public function testGetColumnType() - { - $qb = $this->getQueryBuilder(); - foreach ($this->columnTypes() as $item) { - list ($column, $expected) = $item; - $this->assertEquals($expected, $qb->getColumnType($column)); - } - } - - public function testAddDropPrimaryKey() - { - $tableName = 'tbl_constraints'; - $pkeyName = $tableName . "_pkey"; - - // ADD - $qb = $this->getQueryBuilder(); - $qb->db->createCommand()->addPrimaryKey($pkeyName, $tableName, ['id'])->execute(); - $tableSchema = $qb->db->getSchema()->getTableSchema($tableName); - $this->assertEquals(1, count($tableSchema->primaryKey)); - - //DROP - $qb->db->createCommand()->dropPrimaryKey($pkeyName, $tableName)->execute(); - $qb = $this->getQueryBuilder(); // resets the schema - $tableSchema = $qb->db->getSchema()->getTableSchema($tableName); - $this->assertEquals(0, count($tableSchema->primaryKey)); - } -} diff --git a/tests/unit/framework/db/QueryTest.php b/tests/unit/framework/db/QueryTest.php deleted file mode 100644 index 199b6a2..0000000 --- a/tests/unit/framework/db/QueryTest.php +++ /dev/null @@ -1,126 +0,0 @@ -select('*'); - $this->assertEquals(['*'], $query->select); - $this->assertNull($query->distinct); - $this->assertEquals(null, $query->selectOption); - - $query = new Query; - $query->select('id, name', 'something')->distinct(true); - $this->assertEquals(['id', 'name'], $query->select); - $this->assertTrue($query->distinct); - $this->assertEquals('something', $query->selectOption); - } - - public function testFrom() - { - $query = new Query; - $query->from('tbl_user'); - $this->assertEquals(['tbl_user'], $query->from); - } - - public function testWhere() - { - $query = new Query; - $query->where('id = :id', [':id' => 1]); - $this->assertEquals('id = :id', $query->where); - $this->assertEquals([':id' => 1], $query->params); - - $query->andWhere('name = :name', [':name' => 'something']); - $this->assertEquals(['and', 'id = :id', 'name = :name'], $query->where); - $this->assertEquals([':id' => 1, ':name' => 'something'], $query->params); - - $query->orWhere('age = :age', [':age' => '30']); - $this->assertEquals(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->where); - $this->assertEquals([':id' => 1, ':name' => 'something', ':age' => '30'], $query->params); - } - - public function testJoin() - { - } - - public function testGroup() - { - $query = new Query; - $query->groupBy('team'); - $this->assertEquals(['team'], $query->groupBy); - - $query->addGroupBy('company'); - $this->assertEquals(['team', 'company'], $query->groupBy); - - $query->addGroupBy('age'); - $this->assertEquals(['team', 'company', 'age'], $query->groupBy); - } - - public function testHaving() - { - $query = new Query; - $query->having('id = :id', [':id' => 1]); - $this->assertEquals('id = :id', $query->having); - $this->assertEquals([':id' => 1], $query->params); - - $query->andHaving('name = :name', [':name' => 'something']); - $this->assertEquals(['and', 'id = :id', 'name = :name'], $query->having); - $this->assertEquals([':id' => 1, ':name' => 'something'], $query->params); - - $query->orHaving('age = :age', [':age' => '30']); - $this->assertEquals(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->having); - $this->assertEquals([':id' => 1, ':name' => 'something', ':age' => '30'], $query->params); - } - - public function testOrder() - { - $query = new Query; - $query->orderBy('team'); - $this->assertEquals(['team' => SORT_ASC], $query->orderBy); - - $query->addOrderBy('company'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC], $query->orderBy); - - $query->addOrderBy('age'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_ASC], $query->orderBy); - - $query->addOrderBy(['age' => SORT_DESC]); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_DESC], $query->orderBy); - - $query->addOrderBy('age ASC, company DESC'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_DESC, 'age' => SORT_ASC], $query->orderBy); - } - - public function testLimitOffset() - { - $query = new Query; - $query->limit(10)->offset(5); - $this->assertEquals(10, $query->limit); - $this->assertEquals(5, $query->offset); - } - - public function testUnion() - { - } - - public function testOne() - { - $db = $this->getConnection(); - - $result = (new Query)->from('tbl_customer')->where(['status' => 2])->one($db); - $this->assertEquals('user3', $result['name']); - - $result = (new Query)->from('tbl_customer')->where(['status' => 3])->one($db); - $this->assertFalse($result); - } -} diff --git a/tests/unit/framework/db/SchemaTest.php b/tests/unit/framework/db/SchemaTest.php deleted file mode 100644 index 05a0ff2..0000000 --- a/tests/unit/framework/db/SchemaTest.php +++ /dev/null @@ -1,93 +0,0 @@ -getConnection()->schema; - - $tables = $schema->getTableNames(); - $this->assertTrue(in_array('tbl_customer', $tables)); - $this->assertTrue(in_array('tbl_category', $tables)); - $this->assertTrue(in_array('tbl_item', $tables)); - $this->assertTrue(in_array('tbl_order', $tables)); - $this->assertTrue(in_array('tbl_order_item', $tables)); - $this->assertTrue(in_array('tbl_type', $tables)); - } - - public function testGetTableSchemas() - { - /** @var Schema $schema */ - $schema = $this->getConnection()->schema; - - $tables = $schema->getTableSchemas(); - $this->assertEquals(count($schema->getTableNames()), count($tables)); - foreach($tables as $table) { - $this->assertInstanceOf('yii\db\TableSchema', $table); - } - } - - public function testGetNonExistingTableSchema() - { - $this->assertNull($this->getConnection()->schema->getTableSchema('nonexisting_table')); - } - - public function testSchemaCache() - { - /** @var Schema $schema */ - $schema = $this->getConnection()->schema; - - $schema->db->enableSchemaCache = true; - $schema->db->schemaCache = new FileCache(); - $noCacheTable = $schema->getTableSchema('tbl_type', true); - $cachedTable = $schema->getTableSchema('tbl_type', true); - $this->assertEquals($noCacheTable, $cachedTable); - } - - public function testCompositeFk() - { - /** @var Schema $schema */ - $schema = $this->getConnection()->schema; - - $table = $schema->getTableSchema('tbl_composite_fk'); - - $this->assertCount(1, $table->foreignKeys); - $this->assertTrue(isset($table->foreignKeys[0])); - $this->assertEquals('tbl_order_item', $table->foreignKeys[0][0]); - $this->assertEquals('order_id', $table->foreignKeys[0]['order_id']); - $this->assertEquals('item_id', $table->foreignKeys[0]['item_id']); - } - - public function testGetPDOType() - { - $values = [ - [null, \PDO::PARAM_NULL], - ['', \PDO::PARAM_STR], - ['hello', \PDO::PARAM_STR], - [0, \PDO::PARAM_INT], - [1, \PDO::PARAM_INT], - [1337, \PDO::PARAM_INT], - [true, \PDO::PARAM_BOOL], - [false, \PDO::PARAM_BOOL], - [$fp=fopen(__FILE__, 'rb'), \PDO::PARAM_LOB], - ]; - - /** @var Schema $schema */ - $schema = $this->getConnection()->schema; - - foreach($values as $value) { - $this->assertEquals($value[1], $schema->getPdoType($value[0])); - } - fclose($fp); - } -} diff --git a/tests/unit/framework/db/cubrid/CubridActiveDataProviderTest.php b/tests/unit/framework/db/cubrid/CubridActiveDataProviderTest.php deleted file mode 100644 index 191442a..0000000 --- a/tests/unit/framework/db/cubrid/CubridActiveDataProviderTest.php +++ /dev/null @@ -1,14 +0,0 @@ -getConnection(); - - // bindParam - $sql = 'INSERT INTO tbl_customer(email, name, address) VALUES (:email, :name, :address)'; - $command = $db->createCommand($sql); - $email = 'user4@example.com'; - $name = 'user4'; - $address = 'address4'; - $command->bindParam(':email', $email); - $command->bindParam(':name', $name); - $command->bindParam(':address', $address); - $command->execute(); - - $sql = 'SELECT name FROM tbl_customer WHERE email=:email'; - $command = $db->createCommand($sql); - $command->bindParam(':email', $email); - $this->assertEquals($name, $command->queryScalar()); - - $sql = "INSERT INTO tbl_type (int_col, char_col, char_col2, enum_col, float_col, blob_col, numeric_col) VALUES (:int_col, '', :char_col, :enum_col, :float_col, CHAR_TO_BLOB(:blob_col), :numeric_col)"; - $command = $db->createCommand($sql); - $intCol = 123; - $charCol = 'abc'; - $enumCol = 'a'; - $floatCol = 1.23; - $blobCol = "\x10\x11\x12"; - $numericCol = '1.23'; - $command->bindParam(':int_col', $intCol); - $command->bindParam(':char_col', $charCol); - $command->bindParam(':enum_col', $enumCol); - $command->bindParam(':float_col', $floatCol); - $command->bindParam(':blob_col', $blobCol); - $command->bindParam(':numeric_col', $numericCol); - $this->assertEquals(1, $command->execute()); - - $sql = 'SELECT * FROM tbl_type'; - $row = $db->createCommand($sql)->queryOne(); - $this->assertEquals($intCol, $row['int_col']); - $this->assertEquals($enumCol, $row['enum_col']); - $this->assertEquals($charCol, $row['char_col2']); - $this->assertEquals($floatCol, $row['float_col']); - $this->assertEquals($blobCol, fread($row['blob_col'], 3)); - $this->assertEquals($numericCol, $row['numeric_col']); - - // bindValue - $sql = 'INSERT INTO tbl_customer(email, name, address) VALUES (:email, \'user5\', \'address5\')'; - $command = $db->createCommand($sql); - $command->bindValue(':email', 'user5@example.com'); - $command->execute(); - - $sql = 'SELECT email FROM tbl_customer WHERE name=:name'; - $command = $db->createCommand($sql); - $command->bindValue(':name', 'user5'); - $this->assertEquals('user5@example.com', $command->queryScalar()); - } - - public function testAutoQuoting() - { - $db = $this->getConnection(false); - - $sql = 'SELECT [[id]], [[t.name]] FROM {{tbl_customer}} t'; - $command = $db->createCommand($sql); - $this->assertEquals('SELECT "id", "t"."name" FROM "tbl_customer" t', $command->sql); - } -} diff --git a/tests/unit/framework/db/cubrid/CubridConnectionTest.php b/tests/unit/framework/db/cubrid/CubridConnectionTest.php deleted file mode 100644 index 4cd6e20..0000000 --- a/tests/unit/framework/db/cubrid/CubridConnectionTest.php +++ /dev/null @@ -1,44 +0,0 @@ -getConnection(false); - $this->assertEquals(123, $connection->quoteValue(123)); - $this->assertEquals("'string'", $connection->quoteValue('string')); - $this->assertEquals("'It''s interesting'", $connection->quoteValue("It's interesting")); - } - - public function testQuoteTableName() - { - $connection = $this->getConnection(false); - $this->assertEquals('"table"', $connection->quoteTableName('table')); - $this->assertEquals('"table"', $connection->quoteTableName('"table"')); - $this->assertEquals('"schema"."table"', $connection->quoteTableName('schema.table')); - $this->assertEquals('"schema"."table"', $connection->quoteTableName('schema."table"')); - $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); - $this->assertEquals('(table)', $connection->quoteTableName('(table)')); - } - - public function testQuoteColumnName() - { - $connection = $this->getConnection(false); - $this->assertEquals('"column"', $connection->quoteColumnName('column')); - $this->assertEquals('"column"', $connection->quoteColumnName('"column"')); - $this->assertEquals('"table"."column"', $connection->quoteColumnName('table.column')); - $this->assertEquals('"table"."column"', $connection->quoteColumnName('table."column"')); - $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); - $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); - $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); - } -} diff --git a/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php b/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php deleted file mode 100644 index 5fe6e45..0000000 --- a/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php +++ /dev/null @@ -1,83 +0,0 @@ - 5)', 'int NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'], - [Schema::TYPE_PK . '(8) CHECK (value > 5)', 'int NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'], - [Schema::TYPE_STRING, 'varchar(255)'], - [Schema::TYPE_STRING . '(32)', 'varchar(32)'], - [Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'], - [Schema::TYPE_STRING . '(32) CHECK (value LIKE "test%")', 'varchar(32) CHECK (value LIKE "test%")'], - [Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'], - [Schema::TYPE_TEXT, 'varchar'], - [Schema::TYPE_TEXT . '(255)', 'varchar'], - [Schema::TYPE_TEXT . ' CHECK (value LIKE "test%")', 'varchar CHECK (value LIKE "test%")'], - [Schema::TYPE_TEXT . '(255) CHECK (value LIKE "test%")', 'varchar CHECK (value LIKE "test%")'], - [Schema::TYPE_TEXT . ' NOT NULL', 'varchar NOT NULL'], - [Schema::TYPE_TEXT . '(255) NOT NULL', 'varchar NOT NULL'], - [Schema::TYPE_SMALLINT, 'smallint'], - [Schema::TYPE_SMALLINT . '(8)', 'smallint'], - [Schema::TYPE_INTEGER, 'int'], - [Schema::TYPE_INTEGER . '(8)', 'int'], - [Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'int CHECK (value > 5)'], - [Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'int CHECK (value > 5)'], - [Schema::TYPE_INTEGER . ' NOT NULL', 'int NOT NULL'], - [Schema::TYPE_BIGINT, 'bigint'], - [Schema::TYPE_BIGINT . '(8)', 'bigint'], - [Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint CHECK (value > 5)'], - [Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint CHECK (value > 5)'], - [Schema::TYPE_BIGINT . ' NOT NULL', 'bigint NOT NULL'], - [Schema::TYPE_FLOAT, 'float(7)'], - [Schema::TYPE_FLOAT . '(16)', 'float(16)'], - [Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'float(7) CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . '(16) CHECK (value > 5.6)', 'float(16) CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . ' NOT NULL', 'float(7) NOT NULL'], - [Schema::TYPE_DECIMAL, 'decimal(10,0)'], - [Schema::TYPE_DECIMAL . '(12,4)', 'decimal(12,4)'], - [Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'decimal(10,0) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'decimal(12,4) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . ' NOT NULL', 'decimal(10,0) NOT NULL'], - [Schema::TYPE_DATETIME, 'datetime'], - [Schema::TYPE_DATETIME . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "datetime CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATETIME . ' NOT NULL', 'datetime NOT NULL'], - [Schema::TYPE_TIMESTAMP, 'timestamp'], - [Schema::TYPE_TIMESTAMP . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp NOT NULL'], - [Schema::TYPE_TIME, 'time'], - [Schema::TYPE_TIME . " CHECK(value BETWEEN '12:00:00' AND '13:01:01')", "time CHECK(value BETWEEN '12:00:00' AND '13:01:01')"], - [Schema::TYPE_TIME . ' NOT NULL', 'time NOT NULL'], - [Schema::TYPE_DATE, 'date'], - [Schema::TYPE_DATE . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'], - [Schema::TYPE_BINARY, 'blob'], - [Schema::TYPE_BOOLEAN, 'smallint'], - [Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'smallint NOT NULL DEFAULT 1'], - [Schema::TYPE_MONEY, 'decimal(19,4)'], - [Schema::TYPE_MONEY . '(16,2)', 'decimal(16,2)'], - [Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'decimal(19,4) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'decimal(16,2) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . ' NOT NULL', 'decimal(19,4) NOT NULL'], - ]; - } - -} diff --git a/tests/unit/framework/db/cubrid/CubridQueryTest.php b/tests/unit/framework/db/cubrid/CubridQueryTest.php deleted file mode 100644 index b7c9009..0000000 --- a/tests/unit/framework/db/cubrid/CubridQueryTest.php +++ /dev/null @@ -1,13 +0,0 @@ -getConnection()->schema; - - foreach($values as $value) { - $this->assertEquals($value[1], $schema->getPdoType($value[0])); - } - fclose($fp); - } -} diff --git a/tests/unit/framework/db/mssql/MssqlActiveDataProviderTest.php b/tests/unit/framework/db/mssql/MssqlActiveDataProviderTest.php deleted file mode 100644 index 001b660..0000000 --- a/tests/unit/framework/db/mssql/MssqlActiveDataProviderTest.php +++ /dev/null @@ -1,14 +0,0 @@ -getConnection(false); - - $sql = 'SELECT [[id]], [[t.name]] FROM {{tbl_customer}} t'; - $command = $db->createCommand($sql); - $this->assertEquals("SELECT [id], [t].[name] FROM [tbl_customer] t", $command->sql); - } - - public function testPrepareCancel() - { - $this->markTestSkipped('MSSQL driver does not support this feature.'); - } - - public function testBindParamValue() - { - $db = $this->getConnection(); - - // bindParam - $sql = 'INSERT INTO tbl_customer(email, name, address) VALUES (:email, :name, :address)'; - $command = $db->createCommand($sql); - $email = 'user4@example.com'; - $name = 'user4'; - $address = 'address4'; - $command->bindParam(':email', $email); - $command->bindParam(':name', $name); - $command->bindParam(':address', $address); - $command->execute(); - - $sql = 'SELECT name FROM tbl_customer WHERE email=:email'; - $command = $db->createCommand($sql); - $command->bindParam(':email', $email); - $this->assertEquals($name, $command->queryScalar()); - - $sql = 'INSERT INTO tbl_type (int_col, char_col, float_col, blob_col, numeric_col, bool_col) VALUES (:int_col, :char_col, :float_col, CONVERT([varbinary], :blob_col), :numeric_col, :bool_col)'; - $command = $db->createCommand($sql); - $intCol = 123; - $charCol = 'abc'; - $floatCol = 1.23; - $blobCol = "\x10\x11\x12"; - $numericCol = '1.23'; - $boolCol = false; - $command->bindParam(':int_col', $intCol); - $command->bindParam(':char_col', $charCol); - $command->bindParam(':float_col', $floatCol); - $command->bindParam(':blob_col', $blobCol); - $command->bindParam(':numeric_col', $numericCol); - $command->bindParam(':bool_col', $boolCol); - $this->assertEquals(1, $command->execute()); - - $sql = 'SELECT int_col, char_col, float_col, CONVERT([nvarchar], blob_col) AS blob_col, numeric_col FROM tbl_type'; - $row = $db->createCommand($sql)->queryOne(); - $this->assertEquals($intCol, $row['int_col']); - $this->assertEquals($charCol, trim($row['char_col'])); - $this->assertEquals($floatCol, $row['float_col']); - $this->assertEquals($blobCol, $row['blob_col']); - $this->assertEquals($numericCol, $row['numeric_col']); - - // bindValue - $sql = 'INSERT INTO tbl_customer(email, name, address) VALUES (:email, \'user5\', \'address5\')'; - $command = $db->createCommand($sql); - $command->bindValue(':email', 'user5@example.com'); - $command->execute(); - - $sql = 'SELECT email FROM tbl_customer WHERE name=:name'; - $command = $db->createCommand($sql); - $command->bindValue(':name', 'user5'); - $this->assertEquals('user5@example.com', $command->queryScalar()); - } -} diff --git a/tests/unit/framework/db/mssql/MssqlConnectionTest.php b/tests/unit/framework/db/mssql/MssqlConnectionTest.php deleted file mode 100644 index 6531f83..0000000 --- a/tests/unit/framework/db/mssql/MssqlConnectionTest.php +++ /dev/null @@ -1,45 +0,0 @@ -getConnection(false); - $this->assertEquals(123, $connection->quoteValue(123)); - $this->assertEquals("'string'", $connection->quoteValue('string')); - $this->assertEquals("'It''s interesting'", $connection->quoteValue("It's interesting")); - } - - public function testQuoteTableName() - { - $connection = $this->getConnection(false); - $this->assertEquals('[table]', $connection->quoteTableName('table')); - $this->assertEquals('[table]', $connection->quoteTableName('[table]')); - $this->assertEquals('[schema].[table]', $connection->quoteTableName('schema.table')); - $this->assertEquals('[schema].[table]', $connection->quoteTableName('schema.[table]')); - $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); - $this->assertEquals('(table)', $connection->quoteTableName('(table)')); - } - - public function testQuoteColumnName() - { - $connection = $this->getConnection(false); - $this->assertEquals('[column]', $connection->quoteColumnName('column')); - $this->assertEquals('[column]', $connection->quoteColumnName('[column]')); - $this->assertEquals('[table].[column]', $connection->quoteColumnName('table.column')); - $this->assertEquals('[table].[column]', $connection->quoteColumnName('table.[column]')); - $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); - $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); - $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); - } -} diff --git a/tests/unit/framework/db/mssql/MssqlQueryTest.php b/tests/unit/framework/db/mssql/MssqlQueryTest.php deleted file mode 100644 index a2cb019..0000000 --- a/tests/unit/framework/db/mssql/MssqlQueryTest.php +++ /dev/null @@ -1,14 +0,0 @@ -getConnection(true); - } - - public function testQuoteValue() - { - $connection = $this->getConnection(false); - $this->assertEquals(123, $connection->quoteValue(123)); - $this->assertEquals("'string'", $connection->quoteValue('string')); - $this->assertEquals("'It''s interesting'", $connection->quoteValue("It's interesting")); - } - - public function testQuoteTableName() - { - $connection = $this->getConnection(false); - $this->assertEquals('"table"', $connection->quoteTableName('table')); - $this->assertEquals('"table"', $connection->quoteTableName('"table"')); - $this->assertEquals('"schema"."table"', $connection->quoteTableName('schema.table')); - $this->assertEquals('"schema"."table"', $connection->quoteTableName('schema."table"')); - $this->assertEquals('"schema"."table"', $connection->quoteTableName('"schema"."table"')); - $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); - $this->assertEquals('(table)', $connection->quoteTableName('(table)')); - } - - public function testQuoteColumnName() - { - $connection = $this->getConnection(false); - $this->assertEquals('"column"', $connection->quoteColumnName('column')); - $this->assertEquals('"column"', $connection->quoteColumnName('"column"')); - $this->assertEquals('"table"."column"', $connection->quoteColumnName('table.column')); - $this->assertEquals('"table"."column"', $connection->quoteColumnName('table."column"')); - $this->assertEquals('"table"."column"', $connection->quoteColumnName('"table"."column"')); - $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); - $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); - $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); - } -} diff --git a/tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php b/tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php deleted file mode 100644 index e2a62d0..0000000 --- a/tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php +++ /dev/null @@ -1,77 +0,0 @@ - 5)', 'serial NOT NULL PRIMARY KEY CHECK (value > 5)'], - [Schema::TYPE_PK . '(8) CHECK (value > 5)', 'serial NOT NULL PRIMARY KEY CHECK (value > 5)'], - [Schema::TYPE_STRING, 'varchar(255)'], - [Schema::TYPE_STRING . '(32)', 'varchar(32)'], - [Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'], - [Schema::TYPE_STRING . '(32) CHECK (value LIKE "test%")', 'varchar(32) CHECK (value LIKE "test%")'], - [Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'], - [Schema::TYPE_TEXT, 'text'], - [Schema::TYPE_TEXT . '(255)', 'text'], - [Schema::TYPE_TEXT . ' CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'], - [Schema::TYPE_TEXT . '(255) CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'], - [Schema::TYPE_TEXT . ' NOT NULL', 'text NOT NULL'], - [Schema::TYPE_TEXT . '(255) NOT NULL', 'text NOT NULL'], - [Schema::TYPE_SMALLINT, 'smallint'], - [Schema::TYPE_SMALLINT . '(8)', 'smallint'], - [Schema::TYPE_INTEGER, 'integer'], - [Schema::TYPE_INTEGER . '(8)', 'integer'], - [Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'integer CHECK (value > 5)'], - [Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'integer CHECK (value > 5)'], - [Schema::TYPE_INTEGER . ' NOT NULL', 'integer NOT NULL'], - [Schema::TYPE_BIGINT, 'bigint'], - [Schema::TYPE_BIGINT . '(8)', 'bigint'], - [Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint CHECK (value > 5)'], - [Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint CHECK (value > 5)'], - [Schema::TYPE_BIGINT . ' NOT NULL', 'bigint NOT NULL'], - [Schema::TYPE_FLOAT, 'double precision'], - [Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'double precision CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . '(16,5) CHECK (value > 5.6)', 'double precision CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . ' NOT NULL', 'double precision NOT NULL'], - [Schema::TYPE_DECIMAL, 'numeric(10,0)'], - [Schema::TYPE_DECIMAL . '(12,4)', 'numeric(12,4)'], - [Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'numeric(10,0) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'numeric(12,4) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . ' NOT NULL', 'numeric(10,0) NOT NULL'], - [Schema::TYPE_DATETIME, 'timestamp'], - [Schema::TYPE_DATETIME . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATETIME . ' NOT NULL', 'timestamp NOT NULL'], - [Schema::TYPE_TIMESTAMP, 'timestamp'], - [Schema::TYPE_TIMESTAMP . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp NOT NULL'], - [Schema::TYPE_TIME, 'time'], - [Schema::TYPE_TIME . " CHECK(value BETWEEN '12:00:00' AND '13:01:01')", "time CHECK(value BETWEEN '12:00:00' AND '13:01:01')"], - [Schema::TYPE_TIME . ' NOT NULL', 'time NOT NULL'], - [Schema::TYPE_DATE, 'date'], - [Schema::TYPE_DATE . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'], - [Schema::TYPE_BINARY, 'bytea'], - [Schema::TYPE_BOOLEAN, 'boolean'], - [Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'boolean NOT NULL DEFAULT 1'], - [Schema::TYPE_MONEY, 'numeric(19,4)'], - [Schema::TYPE_MONEY . '(16,2)', 'numeric(16,2)'], - [Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'numeric(19,4) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'numeric(16,2) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . ' NOT NULL', 'numeric(19,4) NOT NULL'], - ]; - } -} diff --git a/tests/unit/framework/db/sqlite/SqliteActiveDataProviderTest.php b/tests/unit/framework/db/sqlite/SqliteActiveDataProviderTest.php deleted file mode 100644 index 660b14d..0000000 --- a/tests/unit/framework/db/sqlite/SqliteActiveDataProviderTest.php +++ /dev/null @@ -1,14 +0,0 @@ -getConnection(false); - - $sql = 'SELECT [[id]], [[t.name]] FROM {{tbl_customer}} t'; - $command = $db->createCommand($sql); - $this->assertEquals("SELECT `id`, `t`.`name` FROM `tbl_customer` t", $command->sql); - } -} diff --git a/tests/unit/framework/db/sqlite/SqliteConnectionTest.php b/tests/unit/framework/db/sqlite/SqliteConnectionTest.php deleted file mode 100644 index ea74f81..0000000 --- a/tests/unit/framework/db/sqlite/SqliteConnectionTest.php +++ /dev/null @@ -1,48 +0,0 @@ -getConnection(false); - $params = $this->database; - - $this->assertEquals($params['dsn'], $connection->dsn); - } - - public function testQuoteValue() - { - $connection = $this->getConnection(false); - $this->assertEquals(123, $connection->quoteValue(123)); - $this->assertEquals("'string'", $connection->quoteValue('string')); - $this->assertEquals("'It''s interesting'", $connection->quoteValue("It's interesting")); - } - - public function testQuoteTableName() - { - $connection = $this->getConnection(false); - $this->assertEquals("`table`", $connection->quoteTableName('table')); - $this->assertEquals("`schema`.`table`", $connection->quoteTableName('schema.table')); - $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); - $this->assertEquals('(table)', $connection->quoteTableName('(table)')); - } - - public function testQuoteColumnName() - { - $connection = $this->getConnection(false); - $this->assertEquals('`column`', $connection->quoteColumnName('column')); - $this->assertEquals("`table`.`column`", $connection->quoteColumnName('table.column')); - $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); - $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); - $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); - } -} diff --git a/tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php b/tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php deleted file mode 100644 index a2408a6..0000000 --- a/tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php +++ /dev/null @@ -1,90 +0,0 @@ - 5)', 'integer PRIMARY KEY AUTOINCREMENT NOT NULL CHECK (value > 5)'], - [Schema::TYPE_PK . '(8) CHECK (value > 5)', 'integer PRIMARY KEY AUTOINCREMENT NOT NULL CHECK (value > 5)'], - [Schema::TYPE_STRING, 'varchar(255)'], - [Schema::TYPE_STRING . '(32)', 'varchar(32)'], - [Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'], - [Schema::TYPE_STRING . '(32) CHECK (value LIKE "test%")', 'varchar(32) CHECK (value LIKE "test%")'], - [Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'], - [Schema::TYPE_TEXT, 'text'], - [Schema::TYPE_TEXT . '(255)', 'text'], - [Schema::TYPE_TEXT . ' CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'], - [Schema::TYPE_TEXT . '(255) CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'], - [Schema::TYPE_TEXT . ' NOT NULL', 'text NOT NULL'], - [Schema::TYPE_TEXT . '(255) NOT NULL', 'text NOT NULL'], - [Schema::TYPE_SMALLINT, 'smallint'], - [Schema::TYPE_SMALLINT . '(8)', 'smallint'], - [Schema::TYPE_INTEGER, 'integer'], - [Schema::TYPE_INTEGER . '(8)', 'integer'], - [Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'integer CHECK (value > 5)'], - [Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'integer CHECK (value > 5)'], - [Schema::TYPE_INTEGER . ' NOT NULL', 'integer NOT NULL'], - [Schema::TYPE_BIGINT, 'bigint'], - [Schema::TYPE_BIGINT . '(8)', 'bigint'], - [Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint CHECK (value > 5)'], - [Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint CHECK (value > 5)'], - [Schema::TYPE_BIGINT . ' NOT NULL', 'bigint NOT NULL'], - [Schema::TYPE_FLOAT, 'float'], - [Schema::TYPE_FLOAT . '(16,5)', 'float'], - [Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'float CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . '(16,5) CHECK (value > 5.6)', 'float CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . ' NOT NULL', 'float NOT NULL'], - [Schema::TYPE_DECIMAL, 'decimal(10,0)'], - [Schema::TYPE_DECIMAL . '(12,4)', 'decimal(12,4)'], - [Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'decimal(10,0) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'decimal(12,4) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . ' NOT NULL', 'decimal(10,0) NOT NULL'], - [Schema::TYPE_DATETIME, 'datetime'], - [Schema::TYPE_DATETIME . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "datetime CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATETIME . ' NOT NULL', 'datetime NOT NULL'], - [Schema::TYPE_TIMESTAMP, 'timestamp'], - [Schema::TYPE_TIMESTAMP . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp NOT NULL'], - [Schema::TYPE_TIME, 'time'], - [Schema::TYPE_TIME . " CHECK(value BETWEEN '12:00:00' AND '13:01:01')", "time CHECK(value BETWEEN '12:00:00' AND '13:01:01')"], - [Schema::TYPE_TIME . ' NOT NULL', 'time NOT NULL'], - [Schema::TYPE_DATE, 'date'], - [Schema::TYPE_DATE . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'], - [Schema::TYPE_BINARY, 'blob'], - [Schema::TYPE_BOOLEAN, 'boolean'], - [Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'boolean NOT NULL DEFAULT 1'], - [Schema::TYPE_MONEY, 'decimal(19,4)'], - [Schema::TYPE_MONEY . '(16,2)', 'decimal(16,2)'], - [Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'decimal(19,4) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'decimal(16,2) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . ' NOT NULL', 'decimal(19,4) NOT NULL'], - ]; - } - - public function testAddDropPrimaryKey() - { - $this->setExpectedException('yii\base\NotSupportedException'); - parent::testAddDropPrimaryKey(); - } - - public function testBatchInsert() - { - $sql = $this->getQueryBuilder()->batchInsert('{{tbl_customer}} t', ['t.id','t.name'], array(array(1,'a'), array(2,'b'))); - $this->assertEquals("INSERT INTO {{tbl_customer}} t (`t`.`id`, `t`.`name`) SELECT 1, 'a' UNION ALL 2, 'b'", $sql); - } -} diff --git a/tests/unit/framework/db/sqlite/SqliteQueryTest.php b/tests/unit/framework/db/sqlite/SqliteQueryTest.php deleted file mode 100644 index f1db36b..0000000 --- a/tests/unit/framework/db/sqlite/SqliteQueryTest.php +++ /dev/null @@ -1,13 +0,0 @@ -secret; - } -} - -class Post3 extends Object -{ - public $id = 33; - public $subObject; - - public function init() - { - $this->subObject = new Post2(); - } -} - -/** - * @group helpers - */ -class ArrayHelperTest extends TestCase -{ - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - - public function testToArray() - { - $object = new Post1; - $this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object)); - $object = new Post2; - $this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object)); - - $object1 = new Post1; - $object2 = new Post2; - $this->assertEquals([ - get_object_vars($object1), - get_object_vars($object2), - ], ArrayHelper::toArray([ - $object1, - $object2, - ])); - - $object = new Post2; - $this->assertEquals([ - 'id' => 123, - 'secret' => 's', - '_content' => 'test', - 'length' => 4, - ], ArrayHelper::toArray($object, [ - $object->className() => [ - 'id', 'secret', - '_content' => 'content', - 'length' => function ($post) { - return strlen($post->content); - } - ] - ])); - - $object = new Post3(); - $this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object, [], false)); - $this->assertEquals([ - 'id' => 33, - 'subObject' => [ - 'id' => 123, - 'content' => 'test', - ], - ], ArrayHelper::toArray($object)); - } - - public function testRemove() - { - $array = ['name' => 'b', 'age' => 3]; - $name = ArrayHelper::remove($array, 'name'); - - $this->assertEquals($name, 'b'); - $this->assertEquals($array, ['age' => 3]); - - $default = ArrayHelper::remove($array, 'nonExisting', 'defaultValue'); - $this->assertEquals('defaultValue', $default); - } - - - public function testMultisort() - { - // single key - $array = [ - ['name' => 'b', 'age' => 3], - ['name' => 'a', 'age' => 1], - ['name' => 'c', 'age' => 2], - ]; - ArrayHelper::multisort($array, 'name'); - $this->assertEquals(['name' => 'a', 'age' => 1], $array[0]); - $this->assertEquals(['name' => 'b', 'age' => 3], $array[1]); - $this->assertEquals(['name' => 'c', 'age' => 2], $array[2]); - - // multiple keys - $array = [ - ['name' => 'b', 'age' => 3], - ['name' => 'a', 'age' => 2], - ['name' => 'a', 'age' => 1], - ]; - ArrayHelper::multisort($array, ['name', 'age']); - $this->assertEquals(['name' => 'a', 'age' => 1], $array[0]); - $this->assertEquals(['name' => 'a', 'age' => 2], $array[1]); - $this->assertEquals(['name' => 'b', 'age' => 3], $array[2]); - - // case-insensitive - $array = [ - ['name' => 'a', 'age' => 3], - ['name' => 'b', 'age' => 2], - ['name' => 'B', 'age' => 4], - ['name' => 'A', 'age' => 1], - ]; - - ArrayHelper::multisort($array, ['name', 'age'], SORT_ASC, [SORT_STRING, SORT_REGULAR]); - $this->assertEquals(['name' => 'A', 'age' => 1], $array[0]); - $this->assertEquals(['name' => 'B', 'age' => 4], $array[1]); - $this->assertEquals(['name' => 'a', 'age' => 3], $array[2]); - $this->assertEquals(['name' => 'b', 'age' => 2], $array[3]); - - ArrayHelper::multisort($array, ['name', 'age'], SORT_ASC, [SORT_STRING | SORT_FLAG_CASE, SORT_REGULAR]); - $this->assertEquals(['name' => 'A', 'age' => 1], $array[0]); - $this->assertEquals(['name' => 'a', 'age' => 3], $array[1]); - $this->assertEquals(['name' => 'b', 'age' => 2], $array[2]); - $this->assertEquals(['name' => 'B', 'age' => 4], $array[3]); - } - - public function testMultisortUseSort() - { - // single key - $sort = new Sort([ - 'attributes' => ['name', 'age'], - 'defaultOrder' => ['name' => SORT_ASC], - ]); - $orders = $sort->getOrders(); - - $array = [ - ['name' => 'b', 'age' => 3], - ['name' => 'a', 'age' => 1], - ['name' => 'c', 'age' => 2], - ]; - ArrayHelper::multisort($array, array_keys($orders), array_values($orders)); - $this->assertEquals(['name' => 'a', 'age' => 1], $array[0]); - $this->assertEquals(['name' => 'b', 'age' => 3], $array[1]); - $this->assertEquals(['name' => 'c', 'age' => 2], $array[2]); - - // multiple keys - $sort = new Sort([ - 'attributes' => ['name', 'age'], - 'defaultOrder' => ['name' => SORT_ASC, 'age' => SORT_DESC], - ]); - $orders = $sort->getOrders(); - - $array = [ - ['name' => 'b', 'age' => 3], - ['name' => 'a', 'age' => 2], - ['name' => 'a', 'age' => 1], - ]; - ArrayHelper::multisort($array, array_keys($orders), array_values($orders)); - $this->assertEquals(['name' => 'a', 'age' => 2], $array[0]); - $this->assertEquals(['name' => 'a', 'age' => 1], $array[1]); - $this->assertEquals(['name' => 'b', 'age' => 3], $array[2]); - } - - public function testMerge() - { - $a = [ - 'name' => 'Yii', - 'version' => '1.0', - 'options' => [ - 'namespace' => false, - 'unittest' => false, - ], - 'features' => [ - 'mvc', - ], - ]; - $b = [ - 'version' => '1.1', - 'options' => [ - 'unittest' => true, - ], - 'features' => [ - 'gii', - ], - ]; - $c = [ - 'version' => '2.0', - 'options' => [ - 'namespace' => true, - ], - 'features' => [ - 'debug', - ], - ]; - - $result = ArrayHelper::merge($a, $b, $c); - $expected = [ - 'name' => 'Yii', - 'version' => '2.0', - 'options' => [ - 'namespace' => true, - 'unittest' => true, - ], - 'features' => [ - 'mvc', - 'gii', - 'debug', - ], - ]; - - $this->assertEquals($expected, $result); - } - - public function testIndex() - { - $array = [ - ['id' => '123', 'data' => 'abc'], - ['id' => '345', 'data' => 'def'], - ]; - $result = ArrayHelper::index($array, 'id'); - $this->assertEquals([ - '123' => ['id' => '123', 'data' => 'abc'], - '345' => ['id' => '345', 'data' => 'def'], - ], $result); - - $result = ArrayHelper::index($array, function ($element) { - return $element['data']; - }); - $this->assertEquals([ - 'abc' => ['id' => '123', 'data' => 'abc'], - 'def' => ['id' => '345', 'data' => 'def'], - ], $result); - } - - public function testGetColumn() - { - $array = [ - 'a' => ['id' => '123', 'data' => 'abc'], - 'b' => ['id' => '345', 'data' => 'def'], - ]; - $result = ArrayHelper::getColumn($array, 'id'); - $this->assertEquals(['a' => '123', 'b' => '345'], $result); - $result = ArrayHelper::getColumn($array, 'id', false); - $this->assertEquals(['123', '345'], $result); - - $result = ArrayHelper::getColumn($array, function ($element) { - return $element['data']; - }); - $this->assertEquals(['a' => 'abc', 'b' => 'def'], $result); - $result = ArrayHelper::getColumn($array, function ($element) { - return $element['data']; - }, false); - $this->assertEquals(['abc', 'def'], $result); - } - - public function testMap() - { - $array = [ - ['id' => '123', 'name' => 'aaa', 'class' => 'x'], - ['id' => '124', 'name' => 'bbb', 'class' => 'x'], - ['id' => '345', 'name' => 'ccc', 'class' => 'y'], - ]; - - $result = ArrayHelper::map($array, 'id', 'name'); - $this->assertEquals([ - '123' => 'aaa', - '124' => 'bbb', - '345' => 'ccc', - ], $result); - - $result = ArrayHelper::map($array, 'id', 'name', 'class'); - $this->assertEquals([ - 'x' => [ - '123' => 'aaa', - '124' => 'bbb', - ], - 'y' => [ - '345' => 'ccc', - ], - ], $result); - } - - public function testKeyExists() - { - $array = [ - 'a' => 1, - 'B' => 2, - ]; - $this->assertTrue(ArrayHelper::keyExists('a', $array)); - $this->assertFalse(ArrayHelper::keyExists('b', $array)); - $this->assertTrue(ArrayHelper::keyExists('B', $array)); - $this->assertFalse(ArrayHelper::keyExists('c', $array)); - - $this->assertTrue(ArrayHelper::keyExists('a', $array, false)); - $this->assertTrue(ArrayHelper::keyExists('b', $array, false)); - $this->assertTrue(ArrayHelper::keyExists('B', $array, false)); - $this->assertFalse(ArrayHelper::keyExists('c', $array, false)); - } - - public function valueProvider() - { - return [ - ['name', 'test'], - ['noname', null], - ['noname', 'test', 'test'], - ['post.id', 5], - ['post.id', 5, 'test'], - ['nopost.id', null], - ['nopost.id', 'test', 'test'], - ['post.author.name', 'cebe'], - ['post.author.noname', null], - ['post.author.noname', 'test', 'test'], - ['post.author.profile.title', '1337'], - ['admin.firstname', 'Qiang'], - ['admin.firstname', 'Qiang', 'test'], - ['admin.lastname', 'Xue'], - [ - function ($array, $defaultValue) { - return $array['date'] . $defaultValue; - }, - '31-12-2113test', - 'test' - ], - ]; - } - - /** - * @dataProvider valueProvider - * - * @param $key - * @param $expected - * @param null $default - */ - public function testGetValue($key, $expected, $default = null) - { - $array = [ - 'name' => 'test', - 'date' => '31-12-2113', - 'post' => [ - 'id' => 5, - 'author' => [ - 'name' => 'cebe', - 'profile' => [ - 'title' => '1337', - ], - ], - ], - 'admin.firstname' => 'Qiang', - 'admin.lastname' => 'Xue', - 'admin' => [ - 'lastname' => 'cebe', - ], - ]; - - $this->assertEquals($expected, ArrayHelper::getValue($array, $key, $default)); - } -} diff --git a/tests/unit/framework/helpers/ConsoleTest.php b/tests/unit/framework/helpers/ConsoleTest.php deleted file mode 100644 index ce6d3fe..0000000 --- a/tests/unit/framework/helpers/ConsoleTest.php +++ /dev/null @@ -1,82 +0,0 @@ -assertEquals(str_repeat('a', 25), $ouput); - } - -/* public function testScreenSize() - { - for ($i = 1; $i < 20; $i++) { - echo implode(', ', Console::getScreenSize(true)) . "\n"; - ob_flush(); - sleep(1); - } - }*/ -} diff --git a/tests/unit/framework/helpers/FileHelperTest.php b/tests/unit/framework/helpers/FileHelperTest.php deleted file mode 100644 index 8ad977f..0000000 --- a/tests/unit/framework/helpers/FileHelperTest.php +++ /dev/null @@ -1,341 +0,0 @@ -testFilePath = Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . get_class($this); - $this->createDir($this->testFilePath); - if (!file_exists($this->testFilePath)) { - $this->markTestIncomplete('Unit tests runtime directory should have writable permissions!'); - } - } - - public function tearDown() - { - $this->removeDir($this->testFilePath); - } - - /** - * Creates directory. - * @param string $dirName directory full name. - */ - protected function createDir($dirName) - { - if (!file_exists($dirName)) { - mkdir($dirName, 0777, true); - } - } - - /** - * Removes directory. - * @param string $dirName directory full name. - */ - protected function removeDir($dirName) - { - if (!empty($dirName) && is_dir($dirName)) { - if ($handle = opendir($dirName)) { - while (false !== ($entry = readdir($handle))) { - if ($entry != '.' && $entry != '..') { - if (is_dir($dirName . DIRECTORY_SEPARATOR . $entry) === true) { - $this->removeDir($dirName . DIRECTORY_SEPARATOR . $entry); - } else { - unlink($dirName . DIRECTORY_SEPARATOR . $entry); - } - } - } - closedir($handle); - rmdir($dirName); - } - } - } - - /** - * Get file permission mode. - * @param string $file file name. - * @return string permission mode. - */ - protected function getMode($file) - { - return substr(sprintf('%o', fileperms($file)), -4); - } - - /** - * Creates test files structure, - * @param array $items file system objects to be created in format: objectName => objectContent - * Arrays specifies directories, other values - files. - * @param string $basePath structure base file path. - */ - protected function createFileStructure(array $items, $basePath = '') - { - if (empty($basePath)) { - $basePath = $this->testFilePath; - } - foreach ($items as $name => $content) { - $itemName = $basePath . DIRECTORY_SEPARATOR . $name; - if (is_array($content)) { - mkdir($itemName, 0777, true); - $this->createFileStructure($content, $itemName); - } else { - file_put_contents($itemName, $content); - } - } - } - - /** - * Asserts that file has specific permission mode. - * @param integer $expectedMode expected file permission mode. - * @param string $fileName file name. - * @param string $message error message - */ - protected function assertFileMode($expectedMode, $fileName, $message = '') - { - $expectedMode = sprintf('%o', $expectedMode); - $this->assertEquals($expectedMode, $this->getMode($fileName), $message); - } - - // Tests : - - public function testCopyDirectory() - { - $srcDirName = 'test_src_dir'; - $files = [ - 'file1.txt' => 'file 1 content', - 'file2.txt' => 'file 2 content', - ]; - $this->createFileStructure([ - $srcDirName => $files - ]); - - $basePath = $this->testFilePath; - $srcDirName = $basePath . DIRECTORY_SEPARATOR . $srcDirName; - $dstDirName = $basePath . DIRECTORY_SEPARATOR . 'test_dst_dir'; - - FileHelper::copyDirectory($srcDirName, $dstDirName); - - $this->assertFileExists($dstDirName, 'Destination directory does not exist!'); - foreach ($files as $name => $content) { - $fileName = $dstDirName . DIRECTORY_SEPARATOR . $name; - $this->assertFileExists($fileName); - $this->assertEquals($content, file_get_contents($fileName), 'Incorrect file content!'); - } - } - - /** - * @depends testCopyDirectory - */ - public function testCopyDirectoryPermissions() - { - if (substr(PHP_OS, 0, 3) == 'WIN') { - $this->markTestSkipped("Can't reliably test it on Windows because fileperms() always return 0777."); - } - - $srcDirName = 'test_src_dir'; - $subDirName = 'test_sub_dir'; - $fileName = 'test_file.txt'; - $this->createFileStructure([ - $srcDirName => [ - $subDirName => [], - $fileName => 'test file content', - ], - ]); - - $basePath = $this->testFilePath; - $srcDirName = $basePath . DIRECTORY_SEPARATOR . $srcDirName; - $dstDirName = $basePath . DIRECTORY_SEPARATOR . 'test_dst_dir'; - - $dirMode = 0755; - $fileMode = 0755; - $options = [ - 'dirMode' => $dirMode, - 'fileMode' => $fileMode, - ]; - FileHelper::copyDirectory($srcDirName, $dstDirName, $options); - - $this->assertFileMode($dirMode, $dstDirName, 'Destination directory has wrong mode!'); - $this->assertFileMode($dirMode, $dstDirName . DIRECTORY_SEPARATOR . $subDirName, 'Copied sub directory has wrong mode!'); - $this->assertFileMode($fileMode, $dstDirName . DIRECTORY_SEPARATOR . $fileName, 'Copied file has wrong mode!'); - } - - public function testRemoveDirectory() - { - $dirName = 'test_dir_for_remove'; - $this->createFileStructure([ - $dirName => [ - 'file1.txt' => 'file 1 content', - 'file2.txt' => 'file 2 content', - 'test_sub_dir' => [ - 'sub_dir_file_1.txt' => 'sub dir file 1 content', - 'sub_dir_file_2.txt' => 'sub dir file 2 content', - ], - ], - ]); - - $basePath = $this->testFilePath; - $dirName = $basePath . DIRECTORY_SEPARATOR . $dirName; - - FileHelper::removeDirectory($dirName); - - $this->assertFileNotExists($dirName, 'Unable to remove directory!'); - - // should be silent about non-existing directories - FileHelper::removeDirectory($basePath . DIRECTORY_SEPARATOR . 'nonExisting'); - } - - public function testFindFiles() - { - $dirName = 'test_dir'; - $this->createFileStructure([ - $dirName => [ - 'file_1.txt' => 'file 1 content', - 'file_2.txt' => 'file 2 content', - 'test_sub_dir' => [ - 'file_1_1.txt' => 'sub dir file 1 content', - 'file_1_2.txt' => 'sub dir file 2 content', - ], - ], - ]); - $basePath = $this->testFilePath; - $dirName = $basePath . DIRECTORY_SEPARATOR . $dirName; - $expectedFiles = [ - $dirName . DIRECTORY_SEPARATOR . 'file_1.txt', - $dirName . DIRECTORY_SEPARATOR . 'file_2.txt', - $dirName . DIRECTORY_SEPARATOR . 'test_sub_dir' . DIRECTORY_SEPARATOR . 'file_1_1.txt', - $dirName . DIRECTORY_SEPARATOR . 'test_sub_dir' . DIRECTORY_SEPARATOR . 'file_1_2.txt', - ]; - - $foundFiles = FileHelper::findFiles($dirName); - sort($expectedFiles); - sort($foundFiles); - $this->assertEquals($expectedFiles, $foundFiles); - } - - /** - * @depends testFindFiles - */ - public function testFindFileFilter() - { - $dirName = 'test_dir'; - $passedFileName = 'passed.txt'; - $this->createFileStructure([ - $dirName => [ - $passedFileName => 'passed file content', - 'declined.txt' => 'declined file content', - ], - ]); - $basePath = $this->testFilePath; - $dirName = $basePath . DIRECTORY_SEPARATOR . $dirName; - - $options = [ - 'filter' => function ($path) use ($passedFileName) { - return $passedFileName == basename($path); - } - ]; - $foundFiles = FileHelper::findFiles($dirName, $options); - $this->assertEquals([$dirName . DIRECTORY_SEPARATOR . $passedFileName], $foundFiles); - } - - /** - * @depends testFindFiles - */ - public function testFindFilesExclude() - { - $dirName = 'test_dir'; - $fileName = 'test_file.txt'; - $excludeFileName = 'exclude_file.txt'; - $this->createFileStructure([ - $dirName => [ - $fileName => 'file content', - $excludeFileName => 'exclude file content', - ], - ]); - $basePath = $this->testFilePath; - $dirName = $basePath . DIRECTORY_SEPARATOR . $dirName; - - $options = [ - 'except' => [$excludeFileName], - ]; - $foundFiles = FileHelper::findFiles($dirName, $options); - $this->assertEquals([$dirName . DIRECTORY_SEPARATOR . $fileName], $foundFiles); - } - - public function testCreateDirectory() - { - $basePath = $this->testFilePath; - $dirName = $basePath . DIRECTORY_SEPARATOR . 'test_dir_level_1' . DIRECTORY_SEPARATOR . 'test_dir_level_2'; - $this->assertTrue(FileHelper::createDirectory($dirName), 'FileHelper::createDirectory should return true if directory was created!'); - $this->assertFileExists($dirName, 'Unable to create directory recursively!'); - $this->assertTrue(FileHelper::createDirectory($dirName), 'FileHelper::createDirectory should return true for already existing directories!'); - } - - public function testGetMimeTypeByExtension() - { - $magicFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'mime_type.php'; - $mimeTypeMap = [ - 'txa' => 'application/json', - 'txb' => 'another/mime', - ]; - $magicFileContent = ' $mimeType) { - $fileName = 'test.' . $extension; - $this->assertNull(FileHelper::getMimeTypeByExtension($fileName)); - $this->assertEquals($mimeType, FileHelper::getMimeTypeByExtension($fileName, $magicFile)); - } - } - - public function testGetMimeType() - { - $file = $this->testFilePath . DIRECTORY_SEPARATOR . 'mime_type_test.txt'; - file_put_contents($file, 'some text'); - $this->assertEquals('text/plain', FileHelper::getMimeType($file)); - - $file = $this->testFilePath . DIRECTORY_SEPARATOR . 'mime_type_test.json'; - file_put_contents($file, '{"a": "b"}'); - $this->assertEquals('text/plain', FileHelper::getMimeType($file)); - } - - public function testNormalizePath() - { - $this->assertEquals(DIRECTORY_SEPARATOR.'home'.DIRECTORY_SEPARATOR.'demo', FileHelper::normalizePath('/home\demo/')); - } - - public function testLocalizedDirectory() - { - $this->createFileStructure([ - 'views' => [ - 'faq.php' => 'English FAQ', - 'de-DE' => [ - 'faq.php' => 'German FAQ', - ], - ], - ]); - $viewFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'faq.php'; - $sourceLanguage = 'en-US'; - - // Source language and target language are same. The view path should be unchanged. - $currentLanguage = $sourceLanguage; - $this->assertSame($viewFile, FileHelper::localize($viewFile, $currentLanguage, $sourceLanguage)); - - // Source language and target language are different. The view path should be changed. - $currentLanguage = 'de-DE'; - $this->assertSame( - $this->testFilePath . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . $currentLanguage . DIRECTORY_SEPARATOR . 'faq.php', - FileHelper::localize($viewFile, $currentLanguage, $sourceLanguage) - ); - } -} diff --git a/tests/unit/framework/helpers/HtmlTest.php b/tests/unit/framework/helpers/HtmlTest.php deleted file mode 100644 index 7781958..0000000 --- a/tests/unit/framework/helpers/HtmlTest.php +++ /dev/null @@ -1,554 +0,0 @@ -mockApplication([ - 'components' => [ - 'request' => [ - 'class' => 'yii\web\Request', - 'url' => '/test', - 'enableCsrfValidation' => false, - ], - 'response' => [ - 'class' => 'yii\web\Response', - ], - ], - ]); - } - - public function assertEqualsWithoutLE($expected, $actual) - { - $expected = str_replace("\r\n", "\n", $expected); - $actual = str_replace("\r\n", "\n", $actual); - - $this->assertEquals($expected, $actual); - } - - public function testEncode() - { - $this->assertEquals("a<>&"'", Html::encode("a<>&\"'")); - } - - public function testDecode() - { - $this->assertEquals("a<>&\"'", Html::decode("a<>&"'")); - } - - public function testTag() - { - $this->assertEquals('
              ', Html::tag('br')); - $this->assertEquals('', Html::tag('span')); - $this->assertEquals('
              content
              ', Html::tag('div', 'content')); - $this->assertEquals('', Html::tag('input', '', ['type' => 'text', 'name' => 'test', 'value' => '<>'])); - $this->assertEquals('', Html::tag('span', '', ['disabled' => true])); - } - - public function testBeginTag() - { - $this->assertEquals('
              ', Html::beginTag('br')); - $this->assertEquals('', Html::beginTag('span', ['id' => 'test', 'class' => 'title'])); - } - - public function testEndTag() - { - $this->assertEquals('
              ', Html::endTag('br')); - $this->assertEquals('
              ', Html::endTag('span')); - } - - public function testStyle() - { - $content = 'a <>'; - $this->assertEquals("", Html::style($content)); - $this->assertEquals("", Html::style($content, ['type' => 'text/less'])); - } - - public function testScript() - { - $content = 'a <>'; - $this->assertEquals("", Html::script($content)); - $this->assertEquals("", Html::script($content, ['type' => 'text/js'])); - } - - public function testCssFile() - { - $this->assertEquals('', Html::cssFile('http://example.com')); - $this->assertEquals('', Html::cssFile('')); - } - - public function testJsFile() - { - $this->assertEquals('', Html::jsFile('http://example.com')); - $this->assertEquals('', Html::jsFile('')); - } - - public function testBeginForm() - { - $this->assertEquals('
              ', Html::beginForm()); - $this->assertEquals('', Html::beginForm('/example', 'get')); - $hiddens = [ - '', - '', - ]; - $this->assertEquals('' . "\n" . implode("\n", $hiddens), Html::beginForm('/example?id=1&title=%3C', 'get')); - } - - public function testEndForm() - { - $this->assertEquals('
              ', Html::endForm()); - } - - public function testA() - { - $this->assertEquals('something<>', Html::a('something<>')); - $this->assertEquals('something', Html::a('something', '/example')); - $this->assertEquals('something', Html::a('something', '')); - } - - public function testMailto() - { - $this->assertEquals('test<>', Html::mailto('test<>')); - $this->assertEquals('test<>', Html::mailto('test<>', 'test>')); - } - - public function testImg() - { - $this->assertEquals('', Html::img('/example')); - $this->assertEquals('', Html::img('')); - $this->assertEquals('something', Html::img('/example', ['alt' => 'something', 'width' => 10])); - } - - public function testLabel() - { - $this->assertEquals('', Html::label('something<>')); - $this->assertEquals('', Html::label('something<>', 'a')); - $this->assertEquals('', Html::label('something<>', 'a', ['class' => 'test'])); - } - - public function testButton() - { - $this->assertEquals('', Html::button()); - $this->assertEquals('', Html::button('content<>', ['name' => 'test', 'value' => 'value'])); - $this->assertEquals('', Html::button('content<>', ['type' => 'submit', 'name' => 'test', 'value' => 'value', 'class' => "t"])); - } - - public function testSubmitButton() - { - $this->assertEquals('', Html::submitButton()); - $this->assertEquals('', Html::submitButton('content<>', ['name' => 'test', 'value' => 'value', 'class' => 't'])); - } - - public function testResetButton() - { - $this->assertEquals('', Html::resetButton()); - $this->assertEquals('', Html::resetButton('content<>', ['name' => 'test', 'value' => 'value', 'class' => 't'])); - } - - public function testInput() - { - $this->assertEquals('', Html::input('text')); - $this->assertEquals('', Html::input('text', 'test', 'value', ['class' => 't'])); - } - - public function testButtonInput() - { - $this->assertEquals('', Html::buttonInput()); - $this->assertEquals('', Html::buttonInput('text', ['name' => 'test', 'class' => 'a'])); - } - - public function testSubmitInput() - { - $this->assertEquals('', Html::submitInput()); - $this->assertEquals('', Html::submitInput('text', ['name' => 'test', 'class' => 'a'])); - } - - public function testResetInput() - { - $this->assertEquals('', Html::resetInput()); - $this->assertEquals('', Html::resetInput('text', ['name' => 'test', 'class' => 'a'])); - } - - public function testTextInput() - { - $this->assertEquals('', Html::textInput('test')); - $this->assertEquals('', Html::textInput('test', 'value', ['class' => 't'])); - } - - public function testHiddenInput() - { - $this->assertEquals('', Html::hiddenInput('test')); - $this->assertEquals('', Html::hiddenInput('test', 'value', ['class' => 't'])); - } - - public function testPasswordInput() - { - $this->assertEquals('', Html::passwordInput('test')); - $this->assertEquals('', Html::passwordInput('test', 'value', ['class' => 't'])); - } - - public function testFileInput() - { - $this->assertEquals('', Html::fileInput('test')); - $this->assertEquals('', Html::fileInput('test', 'value', ['class' => 't'])); - } - - public function testTextarea() - { - $this->assertEquals('', Html::textarea('test')); - $this->assertEquals('', Html::textarea('test', 'value<>', ['class' => 't'])); - } - - public function testRadio() - { - $this->assertEquals('', Html::radio('test')); - $this->assertEquals('', Html::radio('test', true, ['class' => 'a', 'value' => null])); - $this->assertEquals('', Html::radio('test', true, ['class' => 'a' , 'uncheck' => '0', 'value' => 2])); - - $this->assertEquals('
              ', Html::radio('test', true, [ - 'class' => 'a', - 'value' => null, - 'label' => 'ccc', - 'labelOptions' => ['class' =>'bbb'], - ])); - $this->assertEquals('
              ', Html::radio('test', true, [ - 'class' => 'a', - 'uncheck' => '0', - 'label' => 'ccc', - 'value' => 2, - ])); - } - - public function testCheckbox() - { - $this->assertEquals('', Html::checkbox('test')); - $this->assertEquals('', Html::checkbox('test', true, ['class' => 'a', 'value' => null])); - $this->assertEquals('', Html::checkbox('test', true, ['class' => 'a', 'uncheck' => '0', 'value' => 2])); - - $this->assertEquals('
              ', Html::checkbox('test', true, [ - 'class' => 'a', - 'value' => null, - 'label' => 'ccc', - 'labelOptions' => ['class' =>'bbb'], - ])); - $this->assertEquals('
              ', Html::checkbox('test', true, [ - 'class' => 'a', - 'uncheck' => '0', - 'label' => 'ccc', - 'value' => 2, - ])); - } - - public function testDropDownList() - { - $expected = << - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::dropDownList('test')); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::dropDownList('test', null, $this->getDataItems())); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::dropDownList('test', 'value2', $this->getDataItems())); - } - - public function testListBox() - { - $expected = << - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test')); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, $this->getDataItems(), ['size' => 5])); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, $this->getDataItems2())); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', 'value2', $this->getDataItems())); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', ['value1', 'value2'], $this->getDataItems())); - - $expected = << - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, [], ['multiple' => true])); - $expected = << -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', '', [], ['unselect' => '0'])); - } - - public function testCheckboxList() - { - $this->assertEquals('
              ', Html::checkboxList('test')); - - $expected = <<
              -
          -EOD; - $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $this->getDataItems())); - - $expected = <<
          -
          -EOD; - $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $this->getDataItems2())); - - $expected = <<

          -
          -EOD; - $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $this->getDataItems(), [ - 'separator' => "
          \n", - 'unselect' => '0', - ])); - - $expected = <<0 -1
          -EOD; - $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $this->getDataItems(), [ - 'item' => function ($index, $label, $name, $checked, $value) { - return $index . Html::label($label . ' ' . Html::checkbox($name, $checked, ['value' => $value])); - } - ])); - } - - public function testRadioList() - { - $this->assertEquals('
          ', Html::radioList('test')); - - $expected = <<
          -
          -EOD; - $this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $this->getDataItems())); - - $expected = <<
          -
        -EOD; - $this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $this->getDataItems2())); - - $expected = <<

        -
        -EOD; - $this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $this->getDataItems(), [ - 'separator' => "
        \n", - 'unselect' => '0', - ])); - - $expected = <<0 -1
        -EOD; - $this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $this->getDataItems(), [ - 'item' => function ($index, $label, $name, $checked, $value) { - return $index . Html::label($label . ' ' . Html::radio($name, $checked, ['value' => $value])); - } - ])); - } - - public function testUl() - { - $data = [ - 1, 'abc', '<>', - ]; - $expected = << -
      • 1
      • -
      • abc
      • -
      • <>
      • -
      -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 @@ -