diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000000..7747344767f
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,32 @@
+; This file is for unifying the coding style for different editors and IDEs.
+; More information at http://editorconfig.org
+
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.bat]
+end_of_line = crlf
+
+[*.yml]
+indent_size = 2
+
+[psalm-baseline.xml]
+indent_size = 2
+
+[phars.xml]
+indent_size = 2
+
+[Makefile]
+indent_style = tab
+
+[*.neon]
+indent_style = tab
+
+[*.neon.dist]
+indent_style = tab
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 00000000000..094e5ecf896
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,8 @@
+# Use HTTPS for the cakefoundation.org URL
+c61ab5ee95cbf30a1720457c961337b200ab0c73
+# Run phpcbf for PSR2 CS fixers
+be845a3a01e3271fc075e49dcb81d73b0ec169c5
+# CS: Trailing comma on function calls (#18032)
+df42951a67281549f5ccdf9a65cfe4c2c8c69a6e
+# CS: Trailing comma (#18047)
+6a0a69422e86bbea3d0ea9b591949727410e6fcb
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000000..30832ef77b1
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,49 @@
+# Define the line ending behavior of the different file extensions
+# Set default behavior, in case users don't have core.autocrlf set.
+* text text=auto eol=lf
+
+.php diff=php
+
+# Declare files that will always have CRLF line endings on checkout.
+*.bat eol=crlf
+
+# Declare files that will always have LF line endings on checkout.
+*.pem eol=lf
+
+# Denote all files that are truly binary and should not be modified.
+*.png binary
+*.jpg binary
+*.gif binary
+*.ico binary
+*.mo binary
+*.pdf binary
+*.phar binary
+*.woff binary
+*.woff2 binary
+*.ttf binary
+*.otf binary
+*.eot binary
+
+# Remove files for archives generated using `git archive`
+.github export-ignore
+.phive export-ignore
+contrib export-ignore
+tests/test_app export-ignore
+tests/TestCase export-ignore
+
+.editorconfig export-ignore
+.gitattributes export-ignore
+.gitignore export-ignore
+.mailmap export-ignore
+.stickler.yml export-ignore
+Makefile export-ignore
+phpcs.xml export-ignore
+phpstan.neon.dist export-ignore
+phpstan-baseline.neon export-ignore
+phpunit.xml.dist export-ignore
+rector.php export-ignore
+
+# Split package files
+src/Validation/.gitattributes export-ignore
+src/Validation/phpstan.neon.dist export-ignore
+src/Validation/tests/ export-ignore
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 00000000000..0199bc8e717
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,108 @@
+# How to contribute
+
+CakePHP loves to welcome your contributions. There are several ways to help out:
+
+* Create an [issue](https://github.com/cakephp/cakephp/issues) on GitHub, if you have found a bug
+* Write test cases for open bug issues
+* Write patches for open bug/feature issues, preferably with test cases included
+* Contribute to the [documentation](https://github.com/cakephp/docs)
+
+There are a few guidelines that we need contributors to follow so that we have a
+chance of keeping on top of things.
+
+## Code of Conduct
+
+Help us keep CakePHP open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cakephp/code-of-conduct/blob/master/CODE_OF_CONDUCT.md).
+
+## Getting Started
+
+* Make sure you have a [GitHub account](https://github.com/signup/free).
+* Submit an [issue](https://github.com/cakephp/cakephp/issues), assuming one does not already exist.
+ * Clearly describe the issue including steps to reproduce when it is a bug.
+ * Make sure you fill in the earliest version that you know has the issue.
+* Fork the repository on GitHub.
+
+## Making Changes
+
+* Create a topic branch from where you want to base your work.
+ * This is usually the current default branch - `5.x` right now.
+ * To quickly create a topic branch based on `5.x`
+ `git branch 5.x/my_contribution 5.x` then checkout the new branch with `git
+ checkout 5.x/my_contribution`. Better avoid working directly on the
+ `5.x` branch, to avoid conflicts if you pull in updates from origin.
+* Make commits of logical units.
+* Check for unnecessary whitespace with `git diff --check` before committing.
+* Use descriptive commit messages and reference the #issue number.
+* [Core test cases, static analysis and codesniffer](#test-cases-codesniffer-and-static-analysis) should continue to pass.
+* Your work should apply the [CakePHP coding standards](https://book.cakephp.org/4/en/contributing/cakephp-coding-conventions.html).
+
+## Which branch to base the work
+
+* Bugfix branches will be based on the current default branch - `5.x` right now.
+* New features that are **backwards compatible** will be based on the appropriate `next` branch. For example if you want to contribute to the next 5.x branch, you should base your changes on `5.next`.
+* New features or other **non backwards compatible** changes will go in the next major release branch.
+
+## What is "backwards compatible" (BC)
+
+`BC breaking` code changes mean, that a given PR introduces code changes which can't be performed by everyone without the need to manually adjust code.
+
+Here are some rules which **prevent** `BC breaking` code changes:
+
+* Configuration doesn't need to change
+* Public API doesn't change. For example, any user land code using/overriding public methods shouldn't break.
+
+Also see our current [Release Policy](https://book.cakephp.org/4/en/release-policy.html)
+
+## Submitting Changes
+
+* Push your changes to a topic branch in your fork of the repository.
+* Submit a pull request to the repository in the CakePHP organization, with the
+ correct target branch.
+
+## Test cases, codesniffer and static analysis
+
+To run the test cases locally use the following command:
+
+ composer test
+
+You can copy file `phpunit.xml.dist` to `phpunit.xml` and modify the database
+driver settings as required to run tests for a particular database.
+
+To run the sniffs for CakePHP coding standards:
+
+ composer cs-check
+
+Check the [cakephp-codesniffer](https://github.com/cakephp/cakephp-codesniffer)
+repository to set up the CakePHP standard. The [README](https://github.com/cakephp/cakephp-codesniffer/blob/master/README.md) contains installation info
+for the sniff and phpcs.
+
+To run static analysis tools [PHPStan](https://github.com/phpstan/phpstan) and [Psalm](https://github.com/vimeo/psalm) you first have to install the additional packages via [phive](https://phar.io).
+
+ composer stan-setup
+
+The currently used PHPStan and Psalm versions can be found in `.phive/phars.xml`.
+
+After that you can perform the checks via:
+
+ composer stan
+
+Note that updating the baselines need to be done with the same PHP version it is run online.
+That is usually the minimum version.
+Make sure to "composer install" and set up the stan tools with it and then also execute them.
+
+## Reporting a Security Issue
+
+If you've found a security related issue in CakePHP, please don't open an issue in github. Instead, contact us at security@cakephp.org. For more information on how we handle security issues, [see the CakePHP Security Issue Process](https://book.cakephp.org/4/en/contributing/tickets.html#reporting-security-issues).
+
+# Additional Resources
+
+* [CakePHP coding standards](https://book.cakephp.org/4/en/contributing/cakephp-coding-conventions.html)
+* [Existing issues](https://github.com/cakephp/cakephp/issues)
+* [Development Roadmaps](https://github.com/cakephp/cakephp/wiki#roadmaps)
+* [General GitHub documentation](https://help.github.com/)
+* [GitHub pull request documentation](https://help.github.com/articles/creating-a-pull-request/)
+* [Forum](https://discourse.cakephp.org/)
+* [Stackoverflow](https://stackoverflow.com/tags/cakephp)
+* [IRC channel #cakephp](https://kiwiirc.com/client/irc.freenode.net#cakephp)
+* [Slack](https://slack-invite.cakephp.org/)
+* [Discord](https://discord.gg/k4trEMPebj)
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 00000000000..e04b3cc08a4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,29 @@
+name: Bug Report
+description: Create a bug report
+type: bug
+labels: ["defect"]
+body:
+ - type: textarea
+ attributes:
+ label: Description
+ description: "Please provide a description and way to reproduce the problem."
+ placeholder: |
+ This issue tracker is *not* a support forum.
+ Please use the CakePHP Slack channel, Discord channel or Discourse forum for support questions.
+ https://book.cakephp.org/5/en/intro/where-to-get-help.html
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: CakePHP Version
+ description: "The CakePHP version used."
+ placeholder: "5.0"
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: PHP Version
+ description: "The php version used, if needed."
+ placeholder: "8.0"
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000000..07a7d060184
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Community Support
+ url: https://cakephp.org/get-involved#getHelp
+ about: Please use the CakePHP Slack channel, Discord channel or IRC channel for questions.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 00000000000..d893e9eff95
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,18 @@
+name: Feature Request
+description: Create a feature request
+type: enhancement
+labels: ["enhancement"]
+body:
+ - type: textarea
+ attributes:
+ label: Description
+ description: "Please provide a description of the feature or enhancement."
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: CakePHP Version
+ description: "The CakePHP version if for a specific major/minor."
+ placeholder: "5.0"
+ validations:
+ required: false
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 00000000000..316acf5a64c
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,7 @@
+
diff --git a/.github/SECURITY.md b/.github/SECURITY.md
new file mode 100644
index 00000000000..6b168892c37
--- /dev/null
+++ b/.github/SECURITY.md
@@ -0,0 +1,34 @@
+# Security Policy
+
+## Supported Versions
+
+We support fixing security issues on the following releases:
+
+| Version | Supported | Security fixes until
+| ------- | ------------------ | --------------------
+| 5.0 | :white_check_mark: | The release of 5.2
+| 4.5 | :white_check_mark: | 36 Months after the release of 5.0 (09 Sep 2026)
+| 4.4 | :white_check_mark: | 36 Months after the release of 5.0 (09 Sep 2026)
+| 4.3 | :white_check_mark: | 36 Months after the release of 5.0 (09 Sep 2026)
+| 4.2 | :x: | No longer supported
+| 4.1 | :x: | No longer supported
+| 4.0 | :x: | No longer supported
+| 3.10.x | :x: | No longer supported
+| 2.10.x | :x: | No longer supported
+
+## Reporting a Vulnerability
+
+If you’ve found a security issue in CakePHP, please use the following procedure
+instead of the normal bug reporting system. Instead of using the bug tracker,
+or one of the support forums please send an email to security [at] cakephp.org. Emails
+sent to this address go to the CakePHP core team on a private mailing list.
+
+For each report, we try to first confirm the vulnerability. Once confirmed,
+the CakePHP team will take the following actions:
+
+* Acknowledge to the reporter that we’ve received the issue, and are
+ working on a fix. We ask that the reporter keep the issue confidential until we announce it.
+* Get a fix/patch prepared.
+* Prepare a post describing the vulnerability, and the possible exploits.
+* Release new versions of all affected versions.
+* Prominently feature the problem in the release announcement
diff --git a/.github/codecov.yml b/.github/codecov.yml
new file mode 100644
index 00000000000..0d79235e357
--- /dev/null
+++ b/.github/codecov.yml
@@ -0,0 +1,7 @@
+codecov:
+ require_ci_to_pass: yes
+
+coverage:
+ range: "90...100"
+
+comment: false
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000000..6647c42863e
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,12 @@
+version: 2
+updates:
+- package-ecosystem: composer
+ directory: "/"
+ schedule:
+ interval: weekly
+ open-pull-requests-limit: 10
+- package-ecosystem: github-actions
+ directory: "/"
+ schedule:
+ interval: weekly
+ open-pull-requests-limit: 10
diff --git a/.github/workflows/api-docs.yml b/.github/workflows/api-docs.yml
new file mode 100644
index 00000000000..6a4e37236dd
--- /dev/null
+++ b/.github/workflows/api-docs.yml
@@ -0,0 +1,31 @@
+---
+name: 'api-docs-deploy'
+
+on:
+ push:
+ tags:
+ - 4.*
+ - 5.*
+ workflow_dispatch:
+
+permissions: {}
+
+jobs:
+ trigger-api:
+ runs-on: ubuntu-24.04
+ steps:
+ - name: Get Cakebot App Token
+ id: app-token
+ uses: getsentry/action-github-app-token@v3
+ with:
+ app_id: ${{ secrets.CAKEBOT_APP_ID }}
+ private_key: ${{ secrets.CAKEBOT_APP_PRIVATE_KEY }}
+
+ - name: Trigger API build
+ run: >
+ curl -XPOST
+ -H 'Authorization: Bearer ${{ steps.app-token.outputs.token }}'
+ -H 'Accept: application/vnd.github.v3+json'
+ -H 'Content-Type: application/json'
+ https://api.github.com/repos/cakephp/cakephp-api-docs/actions/workflows/deploy_2x.yml/dispatches
+ --data '{"ref":"2.x"}'
diff --git a/.github/workflows/cancel.yml b/.github/workflows/cancel.yml
new file mode 100644
index 00000000000..263c669071d
--- /dev/null
+++ b/.github/workflows/cancel.yml
@@ -0,0 +1,18 @@
+name: Cancel
+on:
+ workflow_run:
+ workflows: ["CI"]
+ types:
+ - requested
+permissions:
+ contents: read
+
+jobs:
+ cancel:
+ permissions:
+ actions: write # for styfle/cancel-workflow-action to cancel/stop running workflows
+ runs-on: ubuntu-latest
+ steps:
+ - uses: styfle/cancel-workflow-action@0.13.1
+ with:
+ workflow_id: ${{ github.event.workflow.id }}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000000..bd265c7261f
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,370 @@
+name: CI
+
+on:
+ push:
+ branches:
+ - '4.x'
+ - '5.x'
+ - '5.next'
+ pull_request:
+ branches:
+ - '*'
+ workflow_dispatch:
+
+permissions:
+ contents: read # to fetch code (actions/checkout)
+
+jobs:
+ testsuite:
+ runs-on: ubuntu-24.04
+ strategy:
+ fail-fast: false
+ matrix:
+ php-version: ['8.2', '8.5']
+ db-type: [sqlite, pgsql]
+ dependencies: ['highest']
+ include:
+ - php-version: '8.2'
+ db-type: 'mariadb'
+ dependencies: highest
+
+ - php-version: '8.2'
+ db-type: 'mysql'
+ dependencies: 'lowest'
+
+ - php-version: '8.2'
+ db-type: 'mysql'
+ dependencies: highest
+
+ - php-version: '8.3'
+ db-type: 'mysql'
+ dependencies: highest
+
+ - php-version: '8.4'
+ db-type: 'mysql'
+ dependencies: highest
+
+ - php-version: '8.5'
+ db-type: 'mysql'
+ dependencies: highest
+
+ services:
+ redis:
+ image: redis
+ ports:
+ - 6379/tcp
+ memcached:
+ image: memcached
+ ports:
+ - 11211/tcp
+ redis-cluster:
+ image: grokzen/redis-cluster:6.2.1
+ ports:
+ - 7000:7000
+ - 7001:7001
+ options: >-
+ --health-cmd "redis-cli -p 7000 ping"
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ steps:
+ - name: Setup MySQL 8.4
+ if: matrix.db-type == 'mysql' && matrix.dependencies == 'highest' && matrix.php-version != '8.3'
+ run: docker run --rm --name=mysqld -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=cakephp -p 3306:3306 -d mysql:8.4
+
+ - name: Setup MySQL 8.0
+ if: matrix.db-type == 'mysql' && matrix.dependencies == 'highest' && matrix.php-version == '8.3'
+ run: |
+ sudo service mysql start
+ mysql -h 127.0.0.1 -u root -proot -e 'CREATE DATABASE cakephp;'
+
+ - name: Setup MySQL 5.7
+ if: matrix.db-type == 'mysql' && matrix.dependencies == 'lowest'
+ run: docker run --rm --name=mysqld -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=cakephp -p 3306:3306 -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
+
+ - name: Setup PostgreSQL with PostGIS
+ if: matrix.db-type == 'pgsql'
+ run: docker run --rm --name=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=cakephp -p 5432:5432 -d postgis/postgis:18-3.6
+
+ - name: Setup MariaDB 11.8
+ if: matrix.db-type == 'mariadb'
+ run: |
+ docker run -d --name=mariadb \
+ -e MARIADB_ROOT_PASSWORD=root \
+ -e MARIADB_DATABASE=cakephp \
+ -p 3306:3306 \
+ --health-cmd="mariadb-admin ping -h 127.0.0.1 -proot || exit 1" \
+ --health-interval=10s \
+ --health-timeout=5s \
+ --health-retries=10 \
+ mariadb:11.8
+
+ echo "Waiting for MariaDB to be ready..."
+ for i in {1..60}; do
+ if docker exec mariadb mariadb-admin ping -h 127.0.0.1 -proot >/dev/null 2>&1; then
+ echo "MariaDB is responding."
+ break
+ fi
+
+ sleep 2
+ done
+
+ - uses: actions/checkout@v6
+ with:
+ persist-credentials: false
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-version }}
+ extensions: mbstring, intl, apcu, memcached, redis, pdo_${{ matrix.db-type }}
+ ini-values: apc.enable_cli = 1, zend.assertions = 1
+ coverage: pcov
+
+ - name: Install packages
+ run: |
+ sudo locale-gen da_DK.UTF-8
+ sudo locale-gen de_DE.UTF-8
+
+ - name: Composer install
+ uses: ramsey/composer-install@v4
+ with:
+ dependency-versions: ${{ matrix.dependencies }}
+ composer-options: "${{ matrix.composer-options }}"
+
+ - name: Setup problem matchers for PHPUnit
+ if: matrix.php-version == '8.2' && matrix.db-type == 'mysql'
+ run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
+
+ - name: Run PHPUnit
+ env:
+ REDIS_PORT: ${{ job.services.redis.ports['6379'] }}
+ MEMCACHED_PORT: ${{ job.services.memcached.ports['11211'] }}
+ REDIS_CLUSTER_NODES: "127.0.0.1:7000,127.0.0.1:7001"
+ run: |
+ if [[ ${{ matrix.db-type }} == 'sqlite' ]]; then export DB_URL='sqlite:///:memory:'; fi
+ if [[ ${{ matrix.db-type }} == 'mysql' ]]; then export DB_URL='mysql://root:root@127.0.0.1/cakephp'; fi
+ if [[ ${{ matrix.db-type }} == 'mariadb' ]]; then export DB_URL='mysql://root:root@127.0.0.1/cakephp'; fi
+ if [[ ${{ matrix.db-type }} == 'pgsql' ]]; then export DB_URL='postgres://postgres:postgres@127.0.0.1/postgres'; fi
+
+ if [[ ${{ matrix.php-version }} == '8.2' && ${{ matrix.dependencies }} == 'highest' ]]; then
+ export CODECOVERAGE=1
+ vendor/bin/phpunit --display-all-issues --fail-on-all-issues --do-not-fail-on-skipped --do-not-fail-on-incomplete --testsuite=cakephp --coverage-clover=coverage.xml
+ vendor/bin/phpunit --display-all-issues --fail-on-all-issues --do-not-fail-on-skipped --do-not-fail-on-incomplete --testsuite=database --coverage-clover=coverage-database.xml
+ CAKE_TEST_AUTOQUOTE=1 vendor/bin/phpunit --display-all-issues --fail-on-all-issues --do-not-fail-on-skipped --do-not-fail-on-incomplete --testsuite=database
+ vendor/bin/phpunit --display-all-issues --fail-on-all-issues --do-not-fail-on-skipped --do-not-fail-on-incomplete --do-not-fail-on-warning --testsuite=globalfunctions --coverage-clover=coverage-functions.xml
+ elif [[ ${{ matrix.php-version }} == '8.2' && ${{ matrix.dependencies }} == 'lowest' ]]; then
+ vendor/bin/phpunit
+ CAKE_TEST_AUTOQUOTE=1 vendor/bin/phpunit --testsuite=database
+ else
+ vendor/bin/phpunit --display-phpunit-notices --display-phpunit-deprecations --display-deprecations --display-warnings
+ CAKE_TEST_AUTOQUOTE=1 vendor/bin/phpunit --display-phpunit-notices --display-phpunit-deprecations --display-deprecations --display-warnings --testsuite=database
+ fi
+
+ - name: Submit code coverage
+ if: matrix.php-version == '8.2'
+ uses: codecov/codecov-action@v6
+ with:
+ files: coverage.xml,coverage-database.xml,coverage-functions.xml
+ token: ${{ secrets.CODECOV_TOKEN }}
+
+ testsuite-windows:
+ runs-on: windows-2022
+ name: Windows - PHP 8.2 & SQL Server
+
+ env:
+ EXTENSIONS: mbstring, intl, apcu, redis, pdo_sqlsrv
+ PHP_VERSION: '8.2'
+
+ steps:
+ - uses: actions/checkout@v6
+ with:
+ persist-credentials: false
+
+ - name: Get date part for cache key
+ id: key-date
+ run: echo "date=$(date +'%Y-%m')" >> $env:GITHUB_OUTPUT
+
+ - name: Setup PHP extensions cache
+ id: php-ext-cache
+ uses: shivammathur/cache-extensions@v1
+ with:
+ php-version: ${{ env.PHP_VERSION }}
+ extensions: ${{ env.EXTENSIONS }}
+ key: ${{ steps.key-date.outputs.date }}
+
+ - name: Cache PHP extensions
+ uses: actions/cache@v5
+ with:
+ path: ${{ steps.php-ext-cache.outputs.dir }}
+ key: ${{ runner.os }}-php-ext-${{ steps.php-ext-cache.outputs.key }}
+ restore-keys: ${{ runner.os }}-php-ext-${{ steps.php-ext-cache.outputs.key }}
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ env.PHP_VERSION }}
+ extensions: ${{ env.EXTENSIONS }}
+ ini-values: apc.enable_cli = 1, zend.assertions = 1, extension = php_fileinfo.dll
+ coverage: none
+
+ - name: Setup SQLServer
+ run: |
+ # MSSQLLocalDB is the default SQL LocalDB instance
+ SqlLocalDB start MSSQLLocalDB
+ SqlLocalDB info MSSQLLocalDB
+ sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "create database cakephp;"
+
+ - name: Composer install
+ uses: ramsey/composer-install@v4
+
+ - name: Run PHPUnit
+ env:
+ DB_URL: 'sqlserver://@(localdb)\MSSQLLocalDB/cakephp'
+ run: |
+ set CAKE_DISABLE_GLOBAL_FUNCS=1
+ vendor/bin/phpunit --display-incomplete
+
+ - name: Run PHPUnit (autoquote enabled)
+ env:
+ DB_URL: 'sqlserver://@(localdb)\MSSQLLocalDB/cakephp'
+ run: |
+ set CAKE_TEST_AUTOQUOTE=1
+ vendor/bin/phpunit --display-incomplete --testsuite=database
+
+ cs-stan:
+ name: Coding Standard & Static Analysis
+ runs-on: ubuntu-24.04
+
+ env:
+ PHIVE_KEYS: 'CF1A108D0E7AE720,51C67305FFC2E5C0,12CE0F1D262429A5,99BF4D9A33D65E1E'
+ PHPSTAN_TESTS: 1
+
+ steps:
+ - uses: actions/checkout@v6
+ with:
+ persist-credentials: false
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: '8.2'
+ extensions: mbstring, intl, pcntl
+ coverage: none
+ tools: phive, cs2pr
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Composer install
+ uses: ramsey/composer-install@v4
+
+ - name: Cache phive tools
+ uses: actions/cache@v5
+ with:
+ path: |
+ ~/.phive
+ tools
+ key: ${{ runner.os }}-phive-${{ hashFiles('.phive/phars.xml') }}
+ restore-keys: ${{ runner.os }}-phive-
+
+ - name: Install PHP tools with phive.
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: 'phive install --trust-gpg-keys "$PHIVE_KEYS"'
+
+ - name: Run phpstan
+ if: always()
+ run: tools/phpstan analyse --error-format=github
+
+ - name: Run Psalm
+ if: always()
+ run: tools/psalm --output-format=github
+
+ - name: Setup phpcs cache
+ if: always()
+ uses: actions/cache@v5
+ with:
+ path: ${{ runner.temp }}/phpcs.cache
+ key: ${{ runner.os }}-phpcs-${{ hashFiles('phpcs.xml', 'composer.lock') }}
+ restore-keys: ${{ runner.os }}-phpcs-
+
+ - name: Run phpcs
+ if: always()
+ run: vendor/bin/phpcs --parallel=8 --cache=${{ runner.temp }}/phpcs.cache --report=checkstyle | cs2pr
+
+ - name: Run phpstan for tests
+ if: env.PHPSTAN_TESTS
+ run: tools/phpstan analyse -c tests/phpstan.neon --error-format=github
+
+ - name: Run class deprecation aliasing validation script
+ if: always()
+ run: php contrib/validate-deprecation-aliases.php
+
+ - name: Run composer.json validation for split packages
+ if: always()
+ run: php contrib/validate-split-packages.php
+
+ - name: Prefer lowest check
+ if: matrix.prefer-lowest == 'prefer-lowest'
+ run: composer require --dev dereuromark/composer-prefer-lowest && vendor/bin/validate-prefer-lowest -m
+
+ - name: Setup rector cache
+ if: always()
+ uses: actions/cache@v5
+ with:
+ path: ${{ runner.temp }}/rector
+ key: ${{ runner.os }}-rector-${{ hashFiles('rector.php', 'composer.lock') }}
+ restore-keys: ${{ runner.os }}-rector-
+
+ - name: Create rector cache dir
+ if: always()
+ run: mkdir -p ${{ runner.temp }}/rector
+
+ - name: Run rector
+ if: always()
+ env:
+ RECTOR_CACHE_DIR: ${{ runner.temp }}/rector
+ run: composer rector-setup && composer rector-check
+
+ split-packages-stan:
+ name: Static Analysis for Split Packages
+ runs-on: ubuntu-24.04
+
+ env:
+ PHIVE_KEYS: 'CF1A108D0E7AE720,51C67305FFC2E5C0,12CE0F1D262429A5,99BF4D9A33D65E1E'
+
+ steps:
+ - uses: actions/checkout@v6
+ with:
+ persist-credentials: false
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: '8.2'
+ extensions: mbstring, intl
+ coverage: none
+ tools: phive
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Composer install
+ uses: ramsey/composer-install@v4
+
+ - name: Cache phive tools
+ uses: actions/cache@v5
+ with:
+ path: |
+ ~/.phive
+ tools
+ key: ${{ runner.os }}-phive-${{ hashFiles('.phive/phars.xml') }}
+ restore-keys: ${{ runner.os }}-phive-
+
+ - name: Install PHP tools with phive.
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: 'phive install --trust-gpg-keys "$PHIVE_KEYS"'
+
+ - name: Run phpstan for split packages
+ run: php contrib/validate-split-packages-phpstan.php
diff --git a/.github/workflows/split-packages.yml b/.github/workflows/split-packages.yml
new file mode 100644
index 00000000000..3d1dea6588f
--- /dev/null
+++ b/.github/workflows/split-packages.yml
@@ -0,0 +1,34 @@
+name: Split Packages
+
+on:
+ push:
+ branches:
+ - '5.x'
+ - '5.next'
+ - '6.x'
+
+permissions:
+ contents: read # to fetch code (actions/checkout)
+
+jobs:
+ split-packages:
+ runs-on: ubuntu-24.04
+
+ steps:
+ - uses: actions/checkout@v6
+ with:
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: Configure git to use token over HTTPS
+ env:
+ GITHUB_TOKEN: ${{ secrets.GH_SPLIT_PACKAGES_WRITE_TOKEN }}
+ run: |
+ git config --global url."https://x-access-token:${GITHUB_TOKEN}@github.com/".insteadOf "git@github.com:"
+
+ - name: Push split packages
+ env:
+ GITHUB_TOKEN: ${{ secrets.GH_SPLIT_PACKAGES_WRITE_TOKEN }}
+ run: |
+ make CURRENT_BRANCH=${{ github.ref_name }} components
+ make clean-components-branches
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
new file mode 100644
index 00000000000..b450d4bc4d7
--- /dev/null
+++ b/.github/workflows/stale.yml
@@ -0,0 +1,29 @@
+name: Mark stale issues and pull requests
+
+on:
+ schedule:
+ - cron: "0 0 * * *"
+
+permissions:
+ contents: read
+
+jobs:
+ stale:
+
+ permissions:
+ issues: write # for actions/stale to close stale issues
+ pull-requests: write # for actions/stale to close stale PRs
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/stale@v10
+ with:
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ stale-issue-message: 'This issue is stale because it has been open for 120 days with no activity. Remove the `stale` label or comment or this will be closed in 15 days'
+ stale-pr-message: 'This pull request is stale because it has been open 30 days with no activity. Remove the `stale` label or comment on this issue, or it will be closed in 15 days'
+ stale-issue-label: 'stale'
+ stale-pr-label: 'stale'
+ days-before-stale: 120
+ days-before-close: 15
+ exempt-issue-labels: 'pinned'
+ exempt-pr-labels: 'pinned'
diff --git a/.gitignore b/.gitignore
index 6fb2a3bda2b..4135ceccf21 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,50 @@
-/app/Config
-/app/tmp
-/lib/Cake/Console/Templates/skel/tmp/
-/plugins
-/vendors
+# User specific & automatically generated files #
+#################################################
/build
/dist
+/tags
+/composer.lock
+/phpunit.xml
+/phpstan.neon
+/tools
+/vendor
+/composer.phar
+*.mo
+debug.log
+error.log
+.phpunit.result.cache
+.phpunit.cache
+.phpcs.cache
+
+# OS generated files #
+######################
.DS_Store
-tags
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+Icon?
+ehthumbs.db
+Thumbs.db
+
+# Tool specific files #
+#######################
+# vim
+*~
+*.swp
+*.swo
+# sublime text & textmate
+*.sublime-*
+*.stTheme.cache
+*.tmlanguage.cache
+*.tmPreferences.cache
+# Eclipse
+.settings/*
+/.project
+/.buildpath
+# JetBrains, aka PHPStorm, IntelliJ IDEA
+.idea/*
+# NetBeans
+nbproject/*
+# Visual Studio Code
+.vscode
diff --git a/.htaccess b/.htaccess
deleted file mode 100644
index f23dbaf6686..00000000000
--- a/.htaccess
+++ /dev/null
@@ -1,5 +0,0 @@
-
- RewriteEngine on
- RewriteRule ^$ app/webroot/ [L]
- RewriteRule (.*) app/webroot/$1 [L]
-
\ No newline at end of file
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 00000000000..8d2c15681dc
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,134 @@
+Mark Story
+Mark Story
+Mark Story
+José Lorenzo Rodríguez
+José Lorenzo Rodríguez
+José Lorenzo Rodríguez José Lorenzo Rodríguez Urdaneta
+ADmad
+Mathew Foscarini
+Mathew Foscarini
+Ceeram
+Ceeram
+Walther Lalk
+Walther Lalk
+Walther Lalk
+Walther Lalk
+Walther Lalk
+Mark Scherer
+Mark Scherer
+Mark Scherer
+Mark Scherer
+phpnut
+phpnut
+AD7six
+AD7six
+predominant
+mariano.iglesias
+mariano.iglesias
+antograssiot
+Florian Krämer
+Florian Krämer
+Florian Krämer
+Rachman Chavik
+Rachman Chavik
+jperras
+renan.saddam
+Ber Clausen
+Marc Würth
+Jad Bitar
+Jad Bitar
+Jad Bitar
+Yves P
+dogmatic69
+Majna
+Robert Pustułka
+Robert Pustułka
+Robert Pustułka
+Thomas Ploch
+Tigran Gabrielyan
+Bryan Crowe
+Bryan Crowe
+Sam
+Jorge González
+Saleh Souzanchi
+Yevgeny Tomenko
+Ricardo Arturo Cabral
+Cauan Cabral
+pirouet
+davidsteinsland
+jamiemill
+Stefan Dickmann
+Benjamin Tamási
+Gordon Pettey (petteyg)
+Mathieu de Ruiter
+Cees-Jan Kiewiet
+Fiblan
+Haithem BEN GHORBAL
+Pedro Perejón
+Algirdas Gurevicius
+Calin
+Mikaël Capelle
+OKINAKA Kenshin
+Walter Nasich
+mstra001
+Aymeric Derbois
+Daniel
+James Michael DuPont
+James Michael DuPont
+Jan Dorsman
+Pierre Martin
+Jeremy Harris
+Jeremy Harris
+Christian Winther
+Christian Winther
+Christian Winther
+Jose Diaz-Gonzalez
+Jose Diaz-Gonzalez
+Jose Diaz-Gonzalez
+Frank de Graaf
+Frank de Graaf Frank de Graaf
+Frank de Graaf
+Marlin Cremers
+Marlin Cremers
+Marlin Cremers
+David Yell
+James Watts
+Jonas Hartmann
+Jonas Hartmann
+Jonas Hartmann
+Thom Seddon
+Thom Seddon
+Robbert Noordzij
+Robbert Noordzij
+Simon East
+Simon East
+Matt Alexander
+Matt Alexander
+Mark van Driel
+Mark van Driel
+Juan Basso
+Juan Basso
+antograssiot
+antograssiot
+Patrick Conroy
+Patrick Conroy
+saeideng
+saeideng
+Albert Cansado Solà
+Albert Cansado Solà
+Albert Cansado Solà
+Albert Cansado Solà
+Alejandro Ibarra
+Andreas Kristiansen
+Bob Fanger
+Cees-Jan Kiewiet
+Cees-Jan Kiewiet
+Dmitriy Romanov
+Dmitrii Romanov
+Dmitrii Romanov
+Dmitrii Romanov
+Edgaras Janušauskas
+Eric Büttner
+Eric Büttner
+Eric Büttner
+Hideki Kinjyo
diff --git a/.phive/phars.xml b/.phive/phars.xml
new file mode 100644
index 00000000000..f648a9f744f
--- /dev/null
+++ b/.phive/phars.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 714d4a82759..00000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,110 +0,0 @@
-language: php
-
-php:
- - 5.3
- - 5.4
-
-env:
- - DB=mysql
- - DB=pgsql
- - DB=sqlite
-
-before_script:
- - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE cakephp_test;'; fi"
- - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE cakephp_test2;'; fi"
- - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE cakephp_test3;'; fi"
- - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'CREATE DATABASE cakephp_test;' -U postgres; fi"
- - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'CREATE SCHEMA test2;' -U postgres -d cakephp_test; fi"
- - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'CREATE SCHEMA test3;' -U postgres -d cakephp_test; fi"
- - chmod -R 777 ./app/tmp
- - echo "var net = require('net');
- var server = net.createServer();
- server.listen(80, 'localhost');
- console.log('TCP server listening on port 80 at localhost.');" > app/tmp/socket.js
- - sudo node ./app/tmp/socket.js &
- - set +H
- - echo " array(
- 'datasource' => 'Database/Mysql',
- 'host' => '0.0.0.0',
- 'login' => 'travis'
- ),
- 'pgsql' => array(
- 'datasource' => 'Database/Postgres',
- 'host' => '127.0.0.1',
- 'login' => 'postgres',
- 'database' => 'cakephp_test',
- 'schema' => array(
- 'default' => 'public',
- 'test' => 'public',
- 'test2' => 'test2',
- 'test_database_three' => 'test3'
- )
- ),
- 'sqlite' => array(
- 'datasource' => 'Database/Sqlite',
- 'database' => array(
- 'default' => ':memory:',
- 'test' => ':memory:',
- 'test2' => '/tmp/cakephp_test2.db',
- 'test_database_three' => '/tmp/cakephp_test3.db'
- ),
- )
- );
- public \$default = array(
- 'persistent' => false,
- 'host' => '',
- 'login' => '',
- 'password' => '',
- 'database' => 'cakephp_test',
- 'prefix' => ''
- );
- public \$test = array(
- 'persistent' => false,
- 'host' => '',
- 'login' => '',
- 'password' => '',
- 'database' => 'cakephp_test',
- 'prefix' => ''
- );
- public \$test2 = array(
- 'persistent' => false,
- 'host' => '',
- 'login' => '',
- 'password' => '',
- 'database' => 'cakephp_test2',
- 'prefix' => ''
- );
- public \$test_database_three = array(
- 'persistent' => false,
- 'host' => '',
- 'login' => '',
- 'password' => '',
- 'database' => 'cakephp_test3',
- 'prefix' => ''
- );
- public function __construct() {
- \$db = 'mysql';
- if (!empty(\$_SERVER['DB'])) {
- \$db = \$_SERVER['DB'];
- }
- foreach (array('default', 'test', 'test2', 'test_database_three') as \$source) {
- \$config = array_merge(\$this->{\$source}, \$this->identities[\$db]);
- if (is_array(\$config['database'])) {
- \$config['database'] = \$config['database'][\$source];
- }
- if (!empty(\$config['schema']) && is_array(\$config['schema'])) {
- \$config['schema'] = \$config['schema'][\$source];
- }
- \$this->{\$source} = \$config;
- }
- }
- }" > app/Config/database.php
-
-script:
- - ./lib/Cake/Console/cake test core AllTests --stderr
-
-notifications:
- email: false
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000000..291d80e1bad
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2005-present, Cake Software Foundation, Inc. (https://cakefoundation.org)
+
+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/Makefile b/Makefile
new file mode 100644
index 00000000000..6227133dc26
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,203 @@
+# The following env variables need to be set:
+# - VERSION
+# - GITHUB_TOKEN personal access API token for github.
+
+# Use the version number to figure out if the release
+# is a pre-release
+PRERELEASE=$(shell echo $(VERSION) | grep -E 'dev|rc|alpha|beta' --quiet && echo 'true' || echo 'false')
+COMPONENTS=cache console core collection database datasource event filesystem form http i18n log ORM utility validation
+CURRENT_BRANCH=$(shell git branch | grep '*' | tr -d '* ')
+
+# Github settings
+UPLOAD_HOST=https://uploads.github.com
+API_HOST=https://api.github.com
+OWNER=cakephp
+REMOTE=origin
+
+ifdef GITHUB_TOKEN
+ AUTH=-H 'Authorization: token $(GITHUB_TOKEN)'
+endif
+
+DASH_VERSION=$(shell echo $(VERSION) | sed -e s/\\./-/g)
+
+# Used when building packages for older 3.x packages.
+# The build scripts clone cakephp/app, and this var selects the
+# correct tag in that repo.
+# For 3.1.x use 3.1.2
+# For 3.0.x use 3.0.5
+APP_VERSION:=5.x
+
+# The branch name of the 'next' branch that will also have package
+# splits updated during a release.
+NEXT_BRANCH=5.next
+
+ALL: help
+
+help:
+ @echo "CakePHP Makefile"
+ @echo "================"
+ @echo ""
+ @echo "release VERSION=x.y.z"
+ @echo " Create a new release of CakePHP. Requires the VERSION and GITHUB_TOKEN parameter."
+ @echo " Packages up a new app skeleton tarball and uploads it to github."
+ @echo ""
+ @echo "package"
+ @echo " Build the app package with all its dependencies."
+ @echo ""
+ @echo "publish"
+ @echo " Publish the dist/cakephp-VERSION.zip to GitHub."
+ @echo ""
+ @echo "components"
+ @echo " Split each of the public namespaces into separate repos and push the to GitHub."
+ @echo " Can be run with CURRENT_BRANCH=xx to split a specific branch."
+ @echo ""
+ @echo "clean-components CURRENT_BRANCH=xx"
+ @echo " Delete branch xx from each subsplit. Useful when cleaning up after a security release."
+ @echo ""
+ @echo "test"
+ @echo " Run the tests for CakePHP."
+ @echo ""
+ @echo "All other tasks are not intended to be run directly."
+.PHONY: help
+
+
+test: install
+ vendor/bin/phpunit
+.PHONY: test
+
+
+# Utility target for checking required parameters
+guard-%:
+ @if [ "$($*)" = '' ]; then \
+ echo "Missing required $* variable."; \
+ exit 1; \
+ fi;
+
+
+# Download composer
+composer.phar:
+ curl -sS https://getcomposer.org/installer | php
+
+# Install dependencies
+install: composer.phar
+ php composer.phar install
+.PHONY: install
+
+
+
+# Version bumping & tagging for CakePHP itself
+# Update VERSION.txt to new version.
+bump-version: guard-VERSION
+ @echo "Update VERSION.txt to $(VERSION)"
+ # Work around sed being bad.
+ mv VERSION.txt VERSION.old
+ cat VERSION.old | sed s'/^[0-9]\.[0-9]\.[0-9].*/$(VERSION)/' > VERSION.txt
+ rm VERSION.old
+ git add VERSION.txt
+ git commit -m "Update version number to $(VERSION)"
+.PHONY: bump-version
+
+# Tag a release
+tag-release: guard-VERSION bump-version
+ @echo "Tagging $(VERSION)"
+ git tag -s $(VERSION) -m "CakePHP $(VERSION)"
+ git push $(REMOTE)
+ git push $(REMOTE) --tags
+
+
+
+# Tasks for tagging the app skeleton and
+# creating a zipball of a fully built app skeleton.
+clean:
+ rm -rf build
+.PHONY: clean
+
+build:
+ mkdir -p build
+
+build/app: build
+ git clone git@github.com:$(OWNER)/app.git build/app/
+ cd build/app && git checkout $(APP_VERSION)
+
+build/cakephp: build
+ git checkout $(VERSION)
+ git checkout-index -a -f --prefix=build/cakephp/
+ git checkout -
+
+dist/cakephp-$(DASH_VERSION).zip: build/app build/cakephp composer.phar
+ mkdir -p dist
+ @echo "Installing app dependencies with composer"
+ # Install deps with composer
+ cd build/app && php ../../composer.phar install && ../../composer.phar run-script post-install-cmd --no-interaction
+ # Copy the current cakephp libs up so we don't have to wait
+ # for packagist to refresh.
+ rm -rf build/app/vendor/cakephp/cakephp
+ cp -r build/cakephp build/app/vendor/cakephp/cakephp
+ # Make a zipball of all the files that are not in .git dirs
+ # Including .git will make zip balls huge, and the zipball is
+ # intended for quick start non-git, non-cli users
+ @echo "Building zipball for $(VERSION)"
+ cd build/app && find . -not -path '*.git*' | zip ../../dist/cakephp-$(DASH_VERSION).zip -@
+
+# Easier to type alias for zip balls
+package: clean dist/cakephp-$(DASH_VERSION).zip
+.PHONY: package
+
+# Publish app skeleton with dependencies zipballs to Github.
+publish: guard-VERSION dist/cakephp-$(DASH_VERSION).zip
+ @echo "Creating draft release for $(VERSION). prerelease=$(PRERELEASE)"
+ curl $(AUTH) -XPOST $(API_HOST)/repos/$(OWNER)/cakephp/releases -d '{"tag_name": "$(VERSION)", "name": "CakePHP $(VERSION) released", "draft": true, "prerelease": $(PRERELEASE)}' > release.json
+ # Extract id out of response json.
+ php -r '$$f = file_get_contents("./release.json"); $$d = json_decode($$f, true); file_put_contents("./id.txt", $$d["id"]);'
+ @echo "Uploading zip file to github."
+ curl $(AUTH) -XPOST \
+ $(UPLOAD_HOST)/repos/$(OWNER)/cakephp/releases/`cat ./id.txt`/assets?name=cakephp-$(DASH_VERSION).zip \
+ -H "Accept: application/vnd.github.manifold-preview" \
+ -H 'Content-Type: application/zip' \
+ --data-binary '@dist/cakephp-$(DASH_VERSION).zip'
+ # Cleanup files.
+ rm release.json
+ rm id.txt
+.PHONY: publish
+
+# Tasks for publishing separate repositories out of each CakePHP namespace
+components: $(foreach component, $(COMPONENTS), component-$(component))
+.PHONY: components
+
+components-tag: $(foreach component, $(COMPONENTS), tag-component-$(component))
+.PHONY: components-tag
+
+component-%:
+ git checkout $(CURRENT_BRANCH) > /dev/null
+ - (git remote add pkg-$* git@github.com:$(OWNER)/$*.git -f 2> /dev/null)
+ - (git branch -D $* 2> /dev/null)
+ git branch $* $(CURRENT_BRANCH)
+ python3 contrib/git-filter-repo --subdirectory-filter src/$(shell php -r "echo ucfirst('$*');") --refs refs/heads/$* --force
+ git push -f pkg-$* $*:$(CURRENT_BRANCH)
+
+tag-component-%: component-% guard-VERSION guard-GITHUB_TOKEN
+ @echo "Creating tag for the $* component"
+ git checkout $*
+ curl $(AUTH) -XPOST $(API_HOST)/repos/$(OWNER)/$*/git/refs -d '{"ref": "refs\/tags\/$(VERSION)", "sha": "$(shell git rev-parse $*)"}'
+ git checkout $(CURRENT_BRANCH) > /dev/null
+ make clean-component-branch-$*
+
+# Task for cleaning up branches and remotes after updating split packages
+clean-components-branches: $(foreach component, $(COMPONENTS), clean-component-branch-$(component))
+.PHONY: clean-components-branches
+
+clean-component-branch-%:
+ git branch -D $*
+ git remote rm pkg-$*
+
+# Tasks for cleaning up branches created by security fixes to old branches.
+components-clean: $(foreach component, $(COMPONENTS), clean-component-$(component))
+clean-component-%:
+ - (git remote add pkg-$* git@github.com:$(OWNER)/$*.git -f 2> /dev/null)
+ - (git branch -D $* 2> /dev/null)
+ - git push -f pkg-$* :$(CURRENT_BRANCH)
+.PHONY: components-clean
+
+# Top level alias for doing a release.
+release: guard-VERSION tag-release components-tag package publish
+.PHONY: release
diff --git a/README b/README
deleted file mode 100644
index ddf42020f55..00000000000
--- a/README
+++ /dev/null
@@ -1,28 +0,0 @@
-CakePHP is a rapid development framework for PHP which uses commonly known design patterns like Active Record, Association Data Mapping, Front Controller and MVC. Our primary goal is to provide a structured framework that enables PHP users at all levels to rapidly develop robust web applications, without any loss to flexibility.
-
-The Cake Software Foundation - promoting development related to CakePHP
-http://cakefoundation.org/
-
-CakePHP - the rapid development PHP framework
-http://www.cakephp.org
-
-Cookbook - user documentation for learning about CakePHP
-http://book.cakephp.org
-
-API - quick reference to CakePHP
-http://api.cakephp.org
-
-The Bakery - everything CakePHP
-http://bakery.cakephp.org
-
-The Show - live and archived podcasts about CakePHP and more
-http://live.cakephp.org
-
-CakePHP TV - screen casts from events and video tutorials
-http://tv.cakephp.org
-
-CakePHP Google Group - community mailing list and forum
-http://groups.google.com/group/cake-php
-
-#cakephp on irc.freenode.net - chat with CakePHP developers
-irc://irc.freenode.net/cakephp
diff --git a/README.md b/README.md
new file mode 100644
index 00000000000..90514947435
--- /dev/null
+++ b/README.md
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[CakePHP](https://cakephp.org) is a rapid development framework for PHP which
+uses commonly known design patterns like Associative Data
+Mapping, Front Controller, and MVC. Our primary goal is to provide a structured
+framework that enables PHP users at all levels to rapidly develop robust web
+applications, without any loss to flexibility.
+
+## Installing CakePHP via Composer
+
+You can install CakePHP into your project using
+[Composer](https://getcomposer.org). If you're starting a new project, we
+recommend using the [app skeleton](https://github.com/cakephp/app) as
+a starting point. For existing applications you can run the following:
+
+``` bash
+composer require cakephp/cakephp
+```
+
+For details on the (minimum/maximum) PHP version see [version map](https://github.com/cakephp/cakephp/wiki#version-map).
+
+## Running Tests
+
+Assuming you have PHPUnit installed (`composer install`), you can run the tests for CakePHP by doing the following:
+
+1. Copy `phpunit.xml.dist` to `phpunit.xml`.
+2. Add the relevant database credentials to your `phpunit.xml` if you want to run tests against
+ a non-SQLite datasource.
+3. Run `vendor/bin/phpunit`.
+
+## Learn More
+
+* [CakePHP](https://cakephp.org) - The home of the CakePHP project.
+* [Book](https://book.cakephp.org) - The CakePHP documentation; start learning here!
+* [API](https://api.cakephp.org) - A reference to CakePHP's classes and API documentation.
+* [Awesome CakePHP](https://github.com/FriendsOfCake/awesome-cakephp) - A curated list of featured resources around the framework.
+* [The Bakery](https://bakery.cakephp.org) - Tips, tutorials and articles.
+* [Community Center](https://community.cakephp.org) - A source for everything community related.
+* [Training](https://training.cakephp.org) - Join a live session and get skilled with the framework.
+* [CakeFest](https://cakefest.org) - Don't miss our annual CakePHP conference.
+* [Cake Software Foundation](https://cakefoundation.org) - Promoting development related to CakePHP.
+
+## Get Support!
+
+* [Slack](https://slack-invite.cakephp.org/) - Join us on Slack.
+* [Discord](https://discord.gg/k4trEMPebj) - Join us on Discord.
+* [#cakephp](https://webchat.freenode.net/?channels=#cakephp) on irc.freenode.net - Come chat with us, we have cake.
+* [Forum](https://discourse.cakephp.org/) - Official CakePHP forum.
+* [GitHub Issues](https://github.com/cakephp/cakephp/issues) - Got issues? Please tell us!
+* [Roadmaps](https://github.com/cakephp/cakephp/wiki#roadmaps) - Want to contribute? Get involved!
+
+## Contributing
+
+* [CONTRIBUTING.md](.github/CONTRIBUTING.md) - Quick pointers for contributing to the CakePHP project.
+* [CookBook "Contributing" Section](https://book.cakephp.org/5/en/contributing.html) - Details about contributing to the project.
+
+# Security
+
+If you’ve found a security issue in CakePHP, please use the procedure
+described in [SECURITY.md](.github/SECURITY.md).
diff --git a/VERSION.txt b/VERSION.txt
new file mode 100644
index 00000000000..53a18289616
--- /dev/null
+++ b/VERSION.txt
@@ -0,0 +1,19 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// +--------------------------------------------------------------------------------------------+ //
+// CakePHP Version
+//
+// Holds a static string representing the current version of CakePHP
+//
+// CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
+// Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+//
+// Licensed under The MIT License
+// Redistributions of files must retain the above copyright notice.
+//
+// @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+// @link https://cakephp.org
+// @since CakePHP(tm) v 0.2.9
+// @license https://opensource.org/licenses/mit-license.php MIT License
+// +--------------------------------------------------------------------------------------------+ //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+5.3.6
diff --git a/app/.htaccess b/app/.htaccess
deleted file mode 100644
index fc3aac4b296..00000000000
--- a/app/.htaccess
+++ /dev/null
@@ -1,5 +0,0 @@
-
- RewriteEngine on
- RewriteRule ^$ webroot/ [L]
- RewriteRule (.*) webroot/$1 [L]
-
\ No newline at end of file
diff --git a/app/Config/Schema/db_acl.php b/app/Config/Schema/db_acl.php
deleted file mode 100644
index e03a8950f4d..00000000000
--- a/app/Config/Schema/db_acl.php
+++ /dev/null
@@ -1,74 +0,0 @@
- array('type'=>'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary'),
- 'parent_id' => array('type'=>'integer', 'null' => true, 'default' => NULL, 'length' => 10),
- 'model' => array('type'=>'string', 'null' => true),
- 'foreign_key' => array('type'=>'integer', 'null' => true, 'default' => NULL, 'length' => 10),
- 'alias' => array('type'=>'string', 'null' => true),
- 'lft' => array('type'=>'integer', 'null' => true, 'default' => NULL, 'length' => 10),
- 'rght' => array('type'=>'integer', 'null' => true, 'default' => NULL, 'length' => 10),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
- );
-
- public $aros = array(
- 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary'),
- 'parent_id' => array('type'=>'integer', 'null' => true, 'default' => NULL, 'length' => 10),
- 'model' => array('type'=>'string', 'null' => true),
- 'foreign_key' => array('type'=>'integer', 'null' => true, 'default' => NULL, 'length' => 10),
- 'alias' => array('type'=>'string', 'null' => true),
- 'lft' => array('type'=>'integer', 'null' => true, 'default' => NULL, 'length' => 10),
- 'rght' => array('type'=>'integer', 'null' => true, 'default' => NULL, 'length' => 10),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
- );
-
- public $aros_acos = array(
- 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary'),
- 'aro_id' => array('type'=>'integer', 'null' => false, 'length' => 10, 'key' => 'index'),
- 'aco_id' => array('type'=>'integer', 'null' => false, 'length' => 10),
- '_create' => array('type'=>'string', 'null' => false, 'default' => '0', 'length' => 2),
- '_read' => array('type'=>'string', 'null' => false, 'default' => '0', 'length' => 2),
- '_update' => array('type'=>'string', 'null' => false, 'default' => '0', 'length' => 2),
- '_delete' => array('type'=>'string', 'null' => false, 'default' => '0', 'length' => 2),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'ARO_ACO_KEY' => array('column' => array('aro_id', 'aco_id'), 'unique' => 1))
- );
-
-}
diff --git a/app/Config/Schema/db_acl.sql b/app/Config/Schema/db_acl.sql
deleted file mode 100644
index f50f3921e8c..00000000000
--- a/app/Config/Schema/db_acl.sql
+++ /dev/null
@@ -1,40 +0,0 @@
-# $Id$
-#
-# Copyright 2005-2012, Cake Software Foundation, Inc.
-#
-# Licensed under The MIT License
-# Redistributions of files must retain the above copyright notice.
-# MIT License (http://www.opensource.org/licenses/mit-license.php)
-
-CREATE TABLE acos (
- id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
- parent_id INTEGER(10) DEFAULT NULL,
- model VARCHAR(255) DEFAULT '',
- foreign_key INTEGER(10) UNSIGNED DEFAULT NULL,
- alias VARCHAR(255) DEFAULT '',
- lft INTEGER(10) DEFAULT NULL,
- rght INTEGER(10) DEFAULT NULL,
- PRIMARY KEY (id)
-);
-
-CREATE TABLE aros_acos (
- id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
- aro_id INTEGER(10) UNSIGNED NOT NULL,
- aco_id INTEGER(10) UNSIGNED NOT NULL,
- _create CHAR(2) NOT NULL DEFAULT 0,
- _read CHAR(2) NOT NULL DEFAULT 0,
- _update CHAR(2) NOT NULL DEFAULT 0,
- _delete CHAR(2) NOT NULL DEFAULT 0,
- PRIMARY KEY(id)
-);
-
-CREATE TABLE aros (
- id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
- parent_id INTEGER(10) DEFAULT NULL,
- model VARCHAR(255) DEFAULT '',
- foreign_key INTEGER(10) UNSIGNED DEFAULT NULL,
- alias VARCHAR(255) DEFAULT '',
- lft INTEGER(10) DEFAULT NULL,
- rght INTEGER(10) DEFAULT NULL,
- PRIMARY KEY (id)
-);
\ No newline at end of file
diff --git a/app/Config/Schema/i18n.php b/app/Config/Schema/i18n.php
deleted file mode 100644
index 8ca081c99b9..00000000000
--- a/app/Config/Schema/i18n.php
+++ /dev/null
@@ -1,51 +0,0 @@
- array('type'=>'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary'),
- 'locale' => array('type'=>'string', 'null' => false, 'length' => 6, 'key' => 'index'),
- 'model' => array('type'=>'string', 'null' => false, 'key' => 'index'),
- 'foreign_key' => array('type'=>'integer', 'null' => false, 'length' => 10, 'key' => 'index'),
- 'field' => array('type'=>'string', 'null' => false, 'key' => 'index'),
- 'content' => array('type'=>'text', 'null' => true, 'default' => NULL),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'locale' => array('column' => 'locale', 'unique' => 0), 'model' => array('column' => 'model', 'unique' => 0), 'row_id' => array('column' => 'foreign_key', 'unique' => 0), 'field' => array('column' => 'field', 'unique' => 0))
- );
-
-}
diff --git a/app/Config/Schema/i18n.sql b/app/Config/Schema/i18n.sql
deleted file mode 100644
index 239e146230a..00000000000
--- a/app/Config/Schema/i18n.sql
+++ /dev/null
@@ -1,26 +0,0 @@
-# $Id$
-#
-# Copyright 2005-2012, Cake Software Foundation, Inc.
-#
-# Licensed under The MIT License
-# Redistributions of files must retain the above copyright notice.
-# MIT License (http://www.opensource.org/licenses/mit-license.php)
-
-CREATE TABLE i18n (
- id int(10) NOT NULL auto_increment,
- locale varchar(6) NOT NULL,
- model varchar(255) NOT NULL,
- foreign_key int(10) NOT NULL,
- field varchar(255) NOT NULL,
- content mediumtext,
- PRIMARY KEY (id),
-# UNIQUE INDEX I18N_LOCALE_FIELD(locale, model, foreign_key, field),
-# INDEX I18N_LOCALE_ROW(locale, model, foreign_key),
-# INDEX I18N_LOCALE_MODEL(locale, model),
-# INDEX I18N_FIELD(model, foreign_key, field),
-# INDEX I18N_ROW(model, foreign_key),
- INDEX locale (locale),
- INDEX model (model),
- INDEX row_id (foreign_key),
- INDEX field (field)
-);
\ No newline at end of file
diff --git a/app/Config/Schema/sessions.php b/app/Config/Schema/sessions.php
deleted file mode 100644
index 7b7db69ab32..00000000000
--- a/app/Config/Schema/sessions.php
+++ /dev/null
@@ -1,48 +0,0 @@
- array('type'=>'string', 'null' => false, 'key' => 'primary'),
- 'data' => array('type'=>'text', 'null' => true, 'default' => NULL),
- 'expires' => array('type'=>'integer', 'null' => true, 'default' => NULL),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
- );
-
-}
diff --git a/app/Config/Schema/sessions.sql b/app/Config/Schema/sessions.sql
deleted file mode 100644
index b8951b6f5d4..00000000000
--- a/app/Config/Schema/sessions.sql
+++ /dev/null
@@ -1,16 +0,0 @@
-# $Id$
-#
-# Copyright 2005-2012, Cake Software Foundation, Inc.
-# 1785 E. Sahara Avenue, Suite 490-204
-# Las Vegas, Nevada 89104
-#
-# Licensed under The MIT License
-# Redistributions of files must retain the above copyright notice.
-# MIT License (http://www.opensource.org/licenses/mit-license.php)
-
-CREATE TABLE cake_sessions (
- id varchar(255) NOT NULL default '',
- data text,
- expires int(11) default NULL,
- PRIMARY KEY (id)
-);
\ No newline at end of file
diff --git a/app/Config/acl.ini.php b/app/Config/acl.ini.php
deleted file mode 100644
index 11ce65b5723..00000000000
--- a/app/Config/acl.ini.php
+++ /dev/null
@@ -1,68 +0,0 @@
-;
-;/**
-; * ACL Configuration
-; *
-; *
-; * PHP 5
-; *
-; * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
-; * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
-; *
-; * Licensed under The MIT License
-; * Redistributions of files must retain the above copyright notice.
-; *
-; * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
-; * @link http://cakephp.org CakePHP(tm) Project
-; * @package app.Config
-; * @since CakePHP(tm) v 0.10.0.1076
-; * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
-; */
-
-; acl.ini.php - Cake ACL Configuration
-; ---------------------------------------------------------------------
-; Use this file to specify user permissions.
-; aco = access control object (something in your application)
-; aro = access request object (something requesting access)
-;
-; User records are added as follows:
-;
-; [uid]
-; groups = group1, group2, group3
-; allow = aco1, aco2, aco3
-; deny = aco4, aco5, aco6
-;
-; Group records are added in a similar manner:
-;
-; [gid]
-; allow = aco1, aco2, aco3
-; deny = aco4, aco5, aco6
-;
-; The allow, deny, and groups sections are all optional.
-; NOTE: groups names *cannot* ever be the same as usernames!
-;
-; ACL permissions are checked in the following order:
-; 1. Check for user denies (and DENY if specified)
-; 2. Check for user allows (and ALLOW if specified)
-; 3. Gather user's groups
-; 4. Check group denies (and DENY if specified)
-; 5. Check group allows (and ALLOW if specified)
-; 6. If no aro, aco, or group information is found, DENY
-;
-; ---------------------------------------------------------------------
-
-;-------------------------------------
-;Users
-;-------------------------------------
-
-[username-goes-here]
-groups = group1, group2
-deny = aco1, aco2
-allow = aco3, aco4
-
-;-------------------------------------
-;Groups
-;-------------------------------------
-
-[groupname-goes-here]
-deny = aco5, aco6
-allow = aco7, aco8
diff --git a/app/Config/acl.php b/app/Config/acl.php
deleted file mode 100644
index 21f8ddaa7dd..00000000000
--- a/app/Config/acl.php
+++ /dev/null
@@ -1,134 +0,0 @@
-Auth->authorize = array('Actions' => array('actionPath' => 'controllers/'),...)
- *
- * Now, when a user (i.e. jeff) authenticates successfully and requests a controller action (i.e. /invoices/delete)
- * that is not allowed by default (e.g. via $this->Auth->allow('edit') in the Invoices controller) then AuthComponent
- * will ask the configured ACL interface if access is granted. Under the assumptions 1. and 2. this will be
- * done via a call to Acl->check() with
- *
- * array('User' => array('username' => 'jeff', 'group_id' => 4, ...))
- *
- * as ARO and
- *
- * '/controllers/invoices/delete'
- *
- * as ACO.
- *
- * If the configured map looks like
- *
- * $config['map'] = array(
- * 'User' => 'User/username',
- * 'Role' => 'User/group_id',
- * );
- *
- * then PhpAcl will lookup if we defined a role like User/jeff. If that role is not found, PhpAcl will try to
- * find a definition for Role/4. If the definition isn't found then a default role (Role/default) will be used to
- * check rules for the given ACO. The search can be expanded by defining aliases in the alias configuration.
- * E.g. if you want to use a more readable name than Role/4 in your definitions you can define an alias like
- *
- * $config['alias'] = array(
- * 'Role/4' => 'Role/editor',
- * );
- *
- * In the roles configuration you can define roles on the lhs and inherited roles on the rhs:
- *
- * $config['roles'] = array(
- * 'Role/admin' => null,
- * 'Role/accountant' => null,
- * 'Role/editor' => null,
- * 'Role/manager' => 'Role/editor, Role/accountant',
- * 'User/jeff' => 'Role/manager',
- * );
- *
- * In this example manager inherits all rules from editor and accountant. Role/admin doesn't inherit from any role.
- * Lets define some rules:
- *
- * $config['rules'] = array(
- * 'allow' => array(
- * '*' => 'Role/admin',
- * 'controllers/users/(dashboard|profile)' => 'Role/default',
- * 'controllers/invoices/*' => 'Role/accountant',
- * 'controllers/articles/*' => 'Role/editor',
- * 'controllers/users/*' => 'Role/manager',
- * 'controllers/invoices/delete' => 'Role/manager',
- * ),
- * 'deny' => array(
- * 'controllers/invoices/delete' => 'Role/accountant, User/jeff',
- * 'controllers/articles/(delete|publish)' => 'Role/editor',
- * ),
- * );
- *
- * Ok, so as jeff inherits from Role/manager he's matched every rule that references User/jeff, Role/manager,
- * Role/editor, Role/accountant and Role/default. However, for jeff, rules for User/jeff are more specific than
- * rules for Role/manager, rules for Role/manager are more specific than rules for Role/editor and so on.
- * This is important when allow and deny rules match for a role. E.g. Role/accountant is allowed
- * controllers/invoices/* but at the same time controllers/invoices/delete is denied. But there is a more
- * specific rule defined for Role/manager which is allowed controllers/invoices/delete. However, the most specific
- * rule denies access to the delete action explicitly for User/jeff, so he'll be denied access to the resource.
- *
- * If we would remove the role definition for User/jeff, then jeff would be granted access as he would be resolved
- * to Role/manager and Role/manager has an allow rule.
- */
-
-/**
- * The role map defines how to resolve the user record from your application
- * to the roles you defined in the roles configuration.
- */
-$config['map'] = array(
- 'User' => 'User/username',
- 'Role' => 'User/group_id',
-);
-
-/**
- * define aliases to map your model information to
- * the roles defined in your role configuration.
- */
-$config['alias'] = array(
- 'Role/4' => 'Role/editor',
-);
-
-/**
- * role configuration
- */
-$config['roles'] = array(
- 'Role/admin' => null,
-);
-
-/**
- * rule configuration
- */
-$config['rules'] = array(
- 'allow' => array(
- '*' => 'Role/admin',
- ),
- 'deny' => array(),
-);
diff --git a/app/Config/bootstrap.php b/app/Config/bootstrap.php
deleted file mode 100644
index 4c54746488d..00000000000
--- a/app/Config/bootstrap.php
+++ /dev/null
@@ -1,124 +0,0 @@
- 'File', //[required]
- * 'duration'=> 3600, //[optional]
- * 'probability'=> 100, //[optional]
- * 'path' => CACHE, //[optional] use system tmp directory - remember to use absolute path
- * 'prefix' => 'cake_', //[optional] prefix every cache file with this string
- * 'lock' => false, //[optional] use file locking
- * 'serialize' => true, // [optional]
- * 'mask' => 0666, // [optional] permission mask to use when creating cache files
- * ));
- *
- * APC (http://pecl.php.net/package/APC)
- *
- * Cache::config('default', array(
- * 'engine' => 'Apc', //[required]
- * 'duration'=> 3600, //[optional]
- * 'probability'=> 100, //[optional]
- * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
- * ));
- *
- * Xcache (http://xcache.lighttpd.net/)
- *
- * Cache::config('default', array(
- * 'engine' => 'Xcache', //[required]
- * 'duration'=> 3600, //[optional]
- * 'probability'=> 100, //[optional]
- * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
- * 'user' => 'user', //user from xcache.admin.user settings
- * 'password' => 'password', //plaintext password (xcache.admin.pass)
- * ));
- *
- * Memcache (http://memcached.org/)
- *
- * Cache::config('default', array(
- * 'engine' => 'Memcache', //[required]
- * 'duration'=> 3600, //[optional]
- * 'probability'=> 100, //[optional]
- * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
- * 'servers' => array(
- * '127.0.0.1:11211' // localhost, default port 11211
- * ), //[optional]
- * 'persistent' => true, // [optional] set this to false for non-persistent connections
- * 'compress' => false, // [optional] compress data in Memcache (slower, but uses less memory)
- * ));
- *
- * Wincache (http://php.net/wincache)
- *
- * Cache::config('default', array(
- * 'engine' => 'Wincache', //[required]
- * 'duration'=> 3600, //[optional]
- * 'probability'=> 100, //[optional]
- * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
- * ));
- */
-Cache::config('default', array('engine' => 'File'));
-
-/**
- * The settings below can be used to set additional paths to models, views and controllers.
- *
- * App::build(array(
- * 'Plugin' => array('/full/path/to/plugins/', '/next/full/path/to/plugins/'),
- * 'Model' => array('/full/path/to/models/', '/next/full/path/to/models/'),
- * 'View' => array('/full/path/to/views/', '/next/full/path/to/views/'),
- * 'Controller' => array('/full/path/to/controllers/', '/next/full/path/to/controllers/'),
- * 'Model/Datasource' => array('/full/path/to/datasources/', '/next/full/path/to/datasources/'),
- * 'Model/Behavior' => array('/full/path/to/behaviors/', '/next/full/path/to/behaviors/'),
- * 'Controller/Component' => array('/full/path/to/components/', '/next/full/path/to/components/'),
- * 'View/Helper' => array('/full/path/to/helpers/', '/next/full/path/to/helpers/'),
- * 'Vendor' => array('/full/path/to/vendors/', '/next/full/path/to/vendors/'),
- * 'Console/Command' => array('/full/path/to/shells/', '/next/full/path/to/shells/'),
- * 'Locale' => array('/full/path/to/locale/', '/next/full/path/to/locale/')
- * ));
- *
- */
-
-/**
- * Custom Inflector rules, can be set to correctly pluralize or singularize table, model, controller names or whatever other
- * string is passed to the inflection functions
- *
- * Inflector::rules('singular', array('rules' => array(), 'irregular' => array(), 'uninflected' => array()));
- * Inflector::rules('plural', array('rules' => array(), 'irregular' => array(), 'uninflected' => array()));
- *
- */
-
-/**
- * Plugins need to be loaded manually, you can either load them one by one or all of them in a single call
- * Uncomment one of the lines below, as you need. make sure you read the documentation on CakePlugin to use more
- * advanced ways of loading plugins
- *
- * CakePlugin::loadAll(); // Loads all plugins at once
- * CakePlugin::load('DebugKit'); //Loads a single plugin named DebugKit
- *
- */
diff --git a/app/Config/core.php b/app/Config/core.php
deleted file mode 100644
index 044dba4bed8..00000000000
--- a/app/Config/core.php
+++ /dev/null
@@ -1,278 +0,0 @@
- 0
- * and log errors with CakeLog when debug = 0.
- *
- * Options:
- *
- * - `handler` - callback - The callback to handle errors. You can set this to any callback type,
- * including anonymous functions.
- * - `level` - int - The level of errors you are interested in capturing.
- * - `trace` - boolean - Include stack traces for errors in log files.
- *
- * @see ErrorHandler for more information on error handling and configuration.
- */
- Configure::write('Error', array(
- 'handler' => 'ErrorHandler::handleError',
- 'level' => E_ALL & ~E_DEPRECATED,
- 'trace' => true
- ));
-
-/**
- * Configure the Exception handler used for uncaught exceptions. By default,
- * ErrorHandler::handleException() is used. It will display a HTML page for the exception, and
- * while debug > 0, framework errors like Missing Controller will be displayed. When debug = 0,
- * framework errors will be coerced into generic HTTP errors.
- *
- * Options:
- *
- * - `handler` - callback - The callback to handle exceptions. You can set this to any callback type,
- * including anonymous functions.
- * - `renderer` - string - The class responsible for rendering uncaught exceptions. If you choose a custom class you
- * should place the file for that class in app/Lib/Error. This class needs to implement a render method.
- * - `log` - boolean - Should Exceptions be logged?
- *
- * @see ErrorHandler for more information on exception handling and configuration.
- */
- Configure::write('Exception', array(
- 'handler' => 'ErrorHandler::handleException',
- 'renderer' => 'ExceptionRenderer',
- 'log' => true
- ));
-
-/**
- * Application wide charset encoding
- */
- Configure::write('App.encoding', 'UTF-8');
-
-/**
- * To configure CakePHP *not* to use mod_rewrite and to
- * use CakePHP pretty URLs, remove these .htaccess
- * files:
- *
- * /.htaccess
- * /app/.htaccess
- * /app/webroot/.htaccess
- *
- * And uncomment the App.baseUrl below:
- */
- //Configure::write('App.baseUrl', env('SCRIPT_NAME'));
-
-/**
- * Uncomment the define below to use CakePHP prefix routes.
- *
- * The value of the define determines the names of the routes
- * and their associated controller actions:
- *
- * Set to an array of prefixes you want to use in your application. Use for
- * admin or other prefixed routes.
- *
- * Routing.prefixes = array('admin', 'manager');
- *
- * Enables:
- * `admin_index()` and `/admin/controller/index`
- * `manager_index()` and `/manager/controller/index`
- *
- */
- //Configure::write('Routing.prefixes', array('admin'));
-
-/**
- * Turn off all caching application-wide.
- *
- */
- //Configure::write('Cache.disable', true);
-
-/**
- * Enable cache checking.
- *
- * If set to true, for view caching you must still use the controller
- * public $cacheAction inside your controllers to define caching settings.
- * You can either set it controller-wide by setting public $cacheAction = true,
- * or in each action using $this->cacheAction = true.
- *
- */
- //Configure::write('Cache.check', true);
-
-/**
- * Defines the default error type when using the log() function. Used for
- * differentiating error logging and debugging. Currently PHP supports LOG_DEBUG.
- */
- define('LOG_ERROR', 2);
-
-/**
- * Session configuration.
- *
- * Contains an array of settings to use for session configuration. The defaults key is
- * used to define a default preset to use for sessions, any settings declared here will override
- * the settings of the default config.
- *
- * ## Options
- *
- * - `Session.cookie` - The name of the cookie to use. Defaults to 'CAKEPHP'
- * - `Session.timeout` - The number of minutes you want sessions to live for. This timeout is handled by CakePHP
- * - `Session.cookieTimeout` - The number of minutes you want session cookies to live for.
- * - `Session.checkAgent` - Do you want the user agent to be checked when starting sessions? You might want to set the
- * value to false, when dealing with older versions of IE, Chrome Frame or certain web-browsing devices and AJAX
- * - `Session.defaults` - The default configuration set to use as a basis for your session.
- * There are four builtins: php, cake, cache, database.
- * - `Session.handler` - Can be used to enable a custom session handler. Expects an array of of callables,
- * that can be used with `session_save_handler`. Using this option will automatically add `session.save_handler`
- * to the ini array.
- * - `Session.autoRegenerate` - Enabling this setting, turns on automatic renewal of sessions, and
- * sessionids that change frequently. See CakeSession::$requestCountdown.
- * - `Session.ini` - An associative array of additional ini values to set.
- *
- * The built in defaults are:
- *
- * - 'php' - Uses settings defined in your php.ini.
- * - 'cake' - Saves session files in CakePHP's /tmp directory.
- * - 'database' - Uses CakePHP's database sessions.
- * - 'cache' - Use the Cache class to save sessions.
- *
- * To define a custom session handler, save it at /app/Model/Datasource/Session/.php.
- * Make sure the class implements `CakeSessionHandlerInterface` and set Session.handler to
- *
- * To use database sessions, run the app/Config/Schema/sessions.php schema using
- * the cake shell command: cake schema create Sessions
- *
- */
- Configure::write('Session', array(
- 'defaults' => 'php'
- ));
-
-/**
- * The level of CakePHP security.
- */
- Configure::write('Security.level', 'medium');
-
-/**
- * A random string used in security hashing methods.
- */
- Configure::write('Security.salt', 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi');
-
-/**
- * A random numeric string (digits only) used to encrypt/decrypt strings.
- */
- Configure::write('Security.cipherSeed', '76859309657453542496749683645');
-
-/**
- * Apply timestamps with the last modified time to static assets (js, css, images).
- * Will append a querystring parameter containing the time the file was modified. This is
- * useful for invalidating browser caches.
- *
- * Set to `true` to apply timestamps when debug > 0. Set to 'force' to always enable
- * timestamping regardless of debug value.
- */
- //Configure::write('Asset.timestamp', true);
-
-/**
- * Compress CSS output by removing comments, whitespace, repeating tags, etc.
- * This requires a/var/cache directory to be writable by the web server for caching.
- * and /vendors/csspp/csspp.php
- *
- * To use, prefix the CSS link URL with '/ccss/' instead of '/css/' or use HtmlHelper::css().
- */
- //Configure::write('Asset.filter.css', 'css.php');
-
-/**
- * Plug in your own custom JavaScript compressor by dropping a script in your webroot to handle the
- * output, and setting the config below to the name of the script.
- *
- * To use, prefix your JavaScript link URLs with '/cjs/' instead of '/js/' or use JavaScriptHelper::link().
- */
- //Configure::write('Asset.filter.js', 'custom_javascript_output_filter.php');
-
-/**
- * The classname and database used in CakePHP's
- * access control lists.
- */
- Configure::write('Acl.classname', 'DbAcl');
- Configure::write('Acl.database', 'default');
-
-/**
- * Uncomment this line and correct your server timezone to fix
- * any date & time related errors.
- */
- //date_default_timezone_set('UTC');
-
-/**
- * Pick the caching engine to use. If APC is enabled use it.
- * If running via cli - apc is disabled by default. ensure it's available and enabled in this case
- *
- * Note: 'default' and other application caches should be configured in app/Config/bootstrap.php.
- * Please check the comments in boostrap.php for more info on the cache engines available
- * and their setttings.
- */
-$engine = 'File';
-if (extension_loaded('apc') && function_exists('apc_dec') && (php_sapi_name() !== 'cli' || ini_get('apc.enable_cli'))) {
- $engine = 'Apc';
-}
-
-// In development mode, caches should expire quickly.
-$duration = '+999 days';
-if (Configure::read('debug') >= 1) {
- $duration = '+10 seconds';
-}
-
-// Prefix each application on the same server with a different string, to avoid Memcache and APC conflicts.
-$prefix = 'myapp_';
-
-/**
- * Configure the cache used for general framework caching. Path information,
- * object listings, and translation cache files are stored with this configuration.
- */
-Cache::config('_cake_core_', array(
- 'engine' => $engine,
- 'prefix' => $prefix . 'cake_core_',
- 'path' => CACHE . 'persistent' . DS,
- 'serialize' => ($engine === 'File'),
- 'duration' => $duration
-));
-
-/**
- * Configure the cache for model and datasource caches. This cache configuration
- * is used to store schema descriptions, and table listings in connections.
- */
-Cache::config('_cake_model_', array(
- 'engine' => $engine,
- 'prefix' => $prefix . 'cake_model_',
- 'path' => CACHE . 'models' . DS,
- 'serialize' => ($engine === 'File'),
- 'duration' => $duration
-));
diff --git a/app/Config/database.php.default b/app/Config/database.php.default
deleted file mode 100644
index d0aeb1f1399..00000000000
--- a/app/Config/database.php.default
+++ /dev/null
@@ -1,83 +0,0 @@
- The name of a supported datasource; valid options are as follows:
- * Database/Mysql - MySQL 4 & 5,
- * Database/Sqlite - SQLite (PHP5 only),
- * Database/Postgres - PostgreSQL 7 and higher,
- * Database/Sqlserver - Microsoft SQL Server 2005 and higher
- *
- * You can add custom database datasources (or override existing datasources) by adding the
- * appropriate file to app/Model/Datasource/Database. Datasources should be named 'MyDatasource.php',
- *
- *
- * persistent => true / false
- * Determines whether or not the database should use a persistent connection
- *
- * host =>
- * the host you connect to the database. To add a socket or port number, use 'port' => #
- *
- * prefix =>
- * Uses the given prefix for all the tables in this database. This setting can be overridden
- * on a per-table basis with the Model::$tablePrefix property.
- *
- * schema =>
- * For Postgres specifies which schema you would like to use the tables in. Postgres defaults to 'public'.
- *
- * encoding =>
- * For MySQL, Postgres specifies the character encoding to use when connecting to the
- * database. Uses database default not specified.
- *
- * unix_socket =>
- * For MySQL to connect via socket specify the `unix_socket` parameter instead of `host` and `port`
- */
-class DATABASE_CONFIG {
-
- public $default = array(
- 'datasource' => 'Database/Mysql',
- 'persistent' => false,
- 'host' => 'localhost',
- 'login' => 'user',
- 'password' => 'password',
- 'database' => 'database_name',
- 'prefix' => '',
- //'encoding' => 'utf8',
- );
-
- public $test = array(
- 'datasource' => 'Database/Mysql',
- 'persistent' => false,
- 'host' => 'localhost',
- 'login' => 'user',
- 'password' => 'password',
- 'database' => 'test_database_name',
- 'prefix' => '',
- //'encoding' => 'utf8',
- );
-}
diff --git a/app/Config/email.php.default b/app/Config/email.php.default
deleted file mode 100644
index c423f782f29..00000000000
--- a/app/Config/email.php.default
+++ /dev/null
@@ -1,97 +0,0 @@
- The name of a supported transport; valid options are as follows:
- * Mail - Send using PHP mail function
- * Smtp - Send using SMTP
- * Debug - Do not send the email, just return the result
- *
- * You can add custom transports (or override existing transports) by adding the
- * appropriate file to app/Network/Email. Transports should be named 'YourTransport.php',
- * where 'Your' is the name of the transport.
- *
- * from =>
- * The origin email. See CakeEmail::from() about the valid values
- *
- */
-class EmailConfig {
-
- public $default = array(
- 'transport' => 'Mail',
- 'from' => 'you@localhost',
- //'charset' => 'utf-8',
- //'headerCharset' => 'utf-8',
- );
-
- public $smtp = array(
- 'transport' => 'Smtp',
- 'from' => array('site@localhost' => 'My Site'),
- 'host' => 'localhost',
- 'port' => 25,
- 'timeout' => 30,
- 'username' => 'user',
- 'password' => 'secret',
- 'client' => null,
- 'log' => false
- //'charset' => 'utf-8',
- //'headerCharset' => 'utf-8',
- );
-
- public $fast = array(
- 'from' => 'you@localhost',
- 'sender' => null,
- 'to' => null,
- 'cc' => null,
- 'bcc' => null,
- 'replyTo' => null,
- 'readReceipt' => null,
- 'returnPath' => null,
- 'messageId' => true,
- 'subject' => null,
- 'message' => null,
- 'headers' => null,
- 'viewRender' => null,
- 'template' => false,
- 'layout' => false,
- 'viewVars' => null,
- 'attachments' => null,
- 'emailFormat' => null,
- 'transport' => 'Smtp',
- 'host' => 'localhost',
- 'port' => 25,
- 'timeout' => 30,
- 'username' => 'user',
- 'password' => 'secret',
- 'client' => null,
- 'log' => true,
- //'charset' => 'utf-8',
- //'headerCharset' => 'utf-8',
- );
-
-}
diff --git a/app/Config/routes.php b/app/Config/routes.php
deleted file mode 100644
index b3823779e11..00000000000
--- a/app/Config/routes.php
+++ /dev/null
@@ -1,44 +0,0 @@
- 'pages', 'action' => 'display', 'home'));
-/**
- * ...and connect the rest of 'Pages' controller's urls.
- */
- Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
-
-/**
- * Load all plugin routes. See the CakePlugin documentation on
- * how to customize the loading of plugin routes.
- */
- CakePlugin::routes();
-
-/**
- * Load the CakePHP default routes. Remove this if you do not want to use
- * the built-in default routes.
- */
- require CAKE . 'Config' . DS . 'routes.php';
diff --git a/app/Console/Command/AppShell.php b/app/Console/Command/AppShell.php
deleted file mode 100644
index 5cc915f6bfe..00000000000
--- a/app/Console/Command/AppShell.php
+++ /dev/null
@@ -1,31 +0,0 @@
-redirect('/');
- }
- $page = $subpage = $title_for_layout = null;
-
- if (!empty($path[0])) {
- $page = $path[0];
- }
- if (!empty($path[1])) {
- $subpage = $path[1];
- }
- if (!empty($path[$count - 1])) {
- $title_for_layout = Inflector::humanize($path[$count - 1]);
- }
- $this->set(compact('page', 'subpage', 'title_for_layout'));
- $this->render(implode('/', $path));
- }
-}
diff --git a/app/Model/AppModel.php b/app/Model/AppModel.php
deleted file mode 100644
index 94e5e5f39d1..00000000000
--- a/app/Model/AppModel.php
+++ /dev/null
@@ -1,34 +0,0 @@
-
- ' . $line . "
\n";
-endforeach;
-?>
\ No newline at end of file
diff --git a/app/View/Emails/text/default.ctp b/app/View/Emails/text/default.ctp
deleted file mode 100644
index 56be8c13a1e..00000000000
--- a/app/View/Emails/text/default.ctp
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/View/Errors/error400.ctp b/app/View/Errors/error400.ctp
deleted file mode 100644
index 6d508604c7c..00000000000
--- a/app/View/Errors/error400.ctp
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
- :
- '{$url}'"
- ); ?>
-
- 0 ):
- echo $this->element('exception_stack_trace');
-endif;
-?>
diff --git a/app/View/Errors/error500.ctp b/app/View/Errors/error500.ctp
deleted file mode 100644
index 4e1f36ece56..00000000000
--- a/app/View/Errors/error500.ctp
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
- :
-
-
- 0 ):
- echo $this->element('exception_stack_trace');
-endif;
-?>
diff --git a/app/View/Helper/AppHelper.php b/app/View/Helper/AppHelper.php
deleted file mode 100644
index 0fddaea2016..00000000000
--- a/app/View/Helper/AppHelper.php
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
-
-
-
-
- This email was sent using the CakePHP Framework
-
-
\ No newline at end of file
diff --git a/app/View/Layouts/Emails/text/default.ctp b/app/View/Layouts/Emails/text/default.ctp
deleted file mode 100644
index 94ed2224956..00000000000
--- a/app/View/Layouts/Emails/text/default.ctp
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-This email was sent using the CakePHP Framework, http://cakephp.org.
diff --git a/app/View/Layouts/ajax.ctp b/app/View/Layouts/ajax.ctp
deleted file mode 100644
index c0ca27058ff..00000000000
--- a/app/View/Layouts/ajax.ctp
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/View/Layouts/default.ctp b/app/View/Layouts/default.ctp
deleted file mode 100644
index 39704bf4411..00000000000
--- a/app/View/Layouts/default.ctp
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
- Html->charset(); ?>
-
- :
-
-
- Html->meta('icon');
-
- echo $this->Html->css('cake.generic');
-
- echo $this->fetch('meta');
- echo $this->fetch('css');
- echo $this->fetch('script');
- ?>
-
-
-
-
-
-
- Session->flash(); ?>
-
- fetch('content'); ?>
-
-
-
- element('sql_dump'); ?>
-
-
diff --git a/app/View/Layouts/flash.ctp b/app/View/Layouts/flash.ctp
deleted file mode 100644
index 76fae349600..00000000000
--- a/app/View/Layouts/flash.ctp
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-Html->charset(); ?>
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/View/Layouts/js/default.ctp b/app/View/Layouts/js/default.ctp
deleted file mode 100644
index d94dc903a57..00000000000
--- a/app/View/Layouts/js/default.ctp
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/View/Layouts/rss/default.ctp b/app/View/Layouts/rss/default.ctp
deleted file mode 100644
index d57624e1a90..00000000000
--- a/app/View/Layouts/rss/default.ctp
+++ /dev/null
@@ -1,14 +0,0 @@
-Rss->document(
- $this->Rss->channel(
- array(), $channel, $content_for_layout
- )
-);
-?>
diff --git a/app/View/Layouts/xml/default.ctp b/app/View/Layouts/xml/default.ctp
deleted file mode 100644
index 27f20316b37..00000000000
--- a/app/View/Layouts/xml/default.ctp
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/app/View/Pages/home.ctp b/app/View/Pages/home.ctp
deleted file mode 100644
index 6661e9a6240..00000000000
--- a/app/View/Pages/home.ctp
+++ /dev/null
@@ -1,188 +0,0 @@
-
-
-
-
- 0):
- Debugger::checkSecurityKeys();
-endif;
-?>
-
-
- 1) Help me configure it
- 2) I don't / can't use URL rewriting
-
-
-=')):
- echo '';
- echo __d('cake_dev', 'Your version of PHP is 5.2.8 or higher.');
- echo ' ';
- else:
- echo '';
- echo __d('cake_dev', 'Your version of PHP is too low. You need PHP 5.2.8 or higher to use CakePHP.');
- echo ' ';
- endif;
-?>
-
-
- ';
- echo __d('cake_dev', 'Your tmp directory is writable.');
- echo '';
- else:
- echo '';
- echo __d('cake_dev', 'Your tmp directory is NOT writable.');
- echo ' ';
- endif;
- ?>
-
-
- ';
- echo __d('cake_dev', 'The %s is being used for core caching. To change the config edit APP/Config/core.php ', ''. $settings['engine'] . 'Engine ');
- echo '';
- else:
- echo '';
- echo __d('cake_dev', 'Your cache is NOT working. Please check the settings in APP/Config/core.php');
- echo ' ';
- endif;
- ?>
-
-
- ';
- echo __d('cake_dev', 'Your database configuration file is present.');
- $filePresent = true;
- echo '';
- else:
- echo '';
- echo __d('cake_dev', 'Your database configuration file is NOT present.');
- echo ' ';
- echo __d('cake_dev', 'Rename APP/Config/database.php.default to APP/Config/database.php');
- echo ' ';
- endif;
- ?>
-
-
-
- isConnected()):
- echo '';
- echo __d('cake_dev', 'Cake is able to connect to the database.');
- echo ' ';
- else:
- echo '';
- echo __d('cake_dev', 'Cake is NOT able to connect to the database.');
- echo ' ';
- echo $connectionError->getMessage();
- echo ' ';
- endif;
- ?>
-
-
-';
- echo __d('cake_dev', 'PCRE has not been compiled with Unicode support.');
- echo ' ';
- echo __d('cake_dev', 'Recompile PCRE with Unicode support by adding --enable-unicode-properties when configuring');
- echo ' ';
- }
-?>
-
-
-
-To change its layout, create: APP/View/Layouts/default.ctp.
-You can also add some CSS styles for your pages at: APP/webroot/css.');
-?>
-
-
-
-
- Html->link(
- sprintf('%s %s', __d('cake_dev', 'New'), __d('cake_dev', 'CakePHP 2.0 Docs')),
- 'http://book.cakephp.org/2.0/en/',
- array('target' => '_blank', 'escape' => false)
- );
- ?>
-
-
- Html->link(
- __d('cake_dev', 'The 15 min Blog Tutorial'),
- 'http://book.cakephp.org/2.0/en/tutorials-and-examples/blog/blog.html',
- array('target' => '_blank', 'escape' => false)
- );
- ?>
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/View/Scaffolds/empty b/app/View/Scaffolds/empty
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/app/index.php b/app/index.php
deleted file mode 100644
index 29f2c572852..00000000000
--- a/app/index.php
+++ /dev/null
@@ -1,17 +0,0 @@
-
- RewriteEngine On
- RewriteCond %{REQUEST_FILENAME} !-d
- RewriteCond %{REQUEST_FILENAME} !-f
- RewriteRule ^(.*)$ index.php [QSA,L]
-
diff --git a/app/webroot/css/cake.generic.css b/app/webroot/css/cake.generic.css
deleted file mode 100644
index 2244ad2f868..00000000000
--- a/app/webroot/css/cake.generic.css
+++ /dev/null
@@ -1,739 +0,0 @@
-@charset "utf-8";
-/**
- *
- * Generic CSS for CakePHP
- *
- * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://cakephp.org CakePHP(tm) Project
- * @package app.webroot.css
- * @since CakePHP(tm)
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-* {
- margin:0;
- padding:0;
-}
-
-/** General Style Info **/
-body {
- background: #003d4c;
- color: #fff;
- font-family:'lucida grande',verdana,helvetica,arial,sans-serif;
- font-size:90%;
- margin: 0;
-}
-a {
- color: #003d4c;
- text-decoration: underline;
- font-weight: bold;
-}
-a:hover {
- color: #367889;
- text-decoration:none;
-}
-a img {
- border:none;
-}
-h1, h2, h3, h4 {
- font-weight: normal;
- margin-bottom:0.5em;
-}
-h1 {
- background:#fff;
- color: #003d4c;
- font-size: 100%;
-}
-h2 {
- background:#fff;
- color: #e32;
- font-family:'Gill Sans','lucida grande', helvetica, arial, sans-serif;
- font-size: 190%;
-}
-h3 {
- color: #2c6877;
- font-family:'Gill Sans','lucida grande', helvetica, arial, sans-serif;
- font-size: 165%;
-}
-h4 {
- color: #993;
- font-weight: normal;
-}
-ul, li {
- margin: 0 12px;
-}
-p {
- margin: 0 0 1em 0;
-}
-
-/** Layout **/
-#container {
- text-align: left;
-}
-
-#header{
- padding: 10px 20px;
-}
-#header h1 {
- line-height:20px;
- background: #003d4c url('../img/cake.icon.png') no-repeat left;
- color: #fff;
- padding: 0px 30px;
-}
-#header h1 a {
- color: #fff;
- background: #003d4c;
- font-weight: normal;
- text-decoration: none;
-}
-#header h1 a:hover {
- color: #fff;
- background: #003d4c;
- text-decoration: underline;
-}
-#content{
- background: #fff;
- clear: both;
- color: #333;
- padding: 10px 20px 40px 20px;
- overflow: auto;
-}
-#footer {
- clear: both;
- padding: 6px 10px;
- text-align: right;
-}
-
-/** containers **/
-div.form,
-div.index,
-div.view {
- float:right;
- width:76%;
- border-left:1px solid #666;
- padding:10px 2%;
-}
-div.actions {
- float:left;
- width:16%;
- padding:10px 1.5%;
-}
-div.actions h3 {
- padding-top:0;
- color:#777;
-}
-
-
-/** Tables **/
-table {
- border-right:0;
- clear: both;
- color: #333;
- margin-bottom: 10px;
- width: 100%;
-}
-th {
- border:0;
- border-bottom:2px solid #555;
- text-align: left;
- padding:4px;
-}
-th a {
- display: block;
- padding: 2px 4px;
- text-decoration: none;
-}
-th a.asc:after {
- content: ' ⇣';
-}
-th a.desc:after {
- content: ' ⇡';
-}
-table tr td {
- padding: 6px;
- text-align: left;
- vertical-align: top;
- border-bottom:1px solid #ddd;
-}
-table tr:nth-child(even) {
- background: #f9f9f9;
-}
-td.actions {
- text-align: center;
- white-space: nowrap;
-}
-table td.actions a {
- margin: 0px 6px;
- padding:2px 5px;
-}
-
-/* SQL log */
-.cake-sql-log {
- background: #fff;
-}
-.cake-sql-log td {
- padding: 4px 8px;
- text-align: left;
- font-family: Monaco, Consolas, "Courier New", monospaced;
-}
-.cake-sql-log caption {
- color:#fff;
-}
-
-/** Paging **/
-.paging {
- background:#fff;
- color: #ccc;
- margin-top: 1em;
- clear:both;
-}
-.paging .current,
-.paging .disabled,
-.paging a {
- text-decoration: none;
- padding: 5px 8px;
- display: inline-block
-}
-.paging > span {
- display: inline-block;
- border: 1px solid #ccc;
- border-left: 0;
-}
-.paging > span:hover {
- background: #efefef;
-}
-.paging .prev {
- border-left: 1px solid #ccc;
- -moz-border-radius: 4px 0 0 4px;
- -webkit-border-radius: 4px 0 0 4px;
- border-radius: 4px 0 0 4px;
-}
-.paging .next {
- -moz-border-radius: 0 4px 4px 0;
- -webkit-border-radius: 0 4px 4px 0;
- border-radius: 0 4px 4px 0;
-}
-.paging .disabled {
- color: #ddd;
-}
-.paging .disabled:hover {
- background: transparent;
-}
-.paging .current {
- background: #efefef;
- color: #c73e14;
-}
-
-/** Scaffold View **/
-dl {
- line-height: 2em;
- margin: 0em 0em;
- width: 60%;
-}
-dl dd:nth-child(4n+2),
-dl dt:nth-child(4n+1) {
- background: #f4f4f4;
-}
-
-dt {
- font-weight: bold;
- padding-left: 4px;
- vertical-align: top;
- width: 10em;
-}
-dd {
- margin-left: 10em;
- margin-top: -2em;
- vertical-align: top;
-}
-
-/** Forms **/
-form {
- clear: both;
- margin-right: 20px;
- padding: 0;
- width: 95%;
-}
-fieldset {
- border: none;
- margin-bottom: 1em;
- padding: 16px 10px;
-}
-fieldset legend {
- color: #e32;
- font-size: 160%;
- font-weight: bold;
-}
-fieldset fieldset {
- margin-top: 0;
- padding: 10px 0 0;
-}
-fieldset fieldset legend {
- font-size: 120%;
- font-weight: normal;
-}
-fieldset fieldset div {
- clear: left;
- margin: 0 20px;
-}
-form div {
- clear: both;
- margin-bottom: 1em;
- padding: .5em;
- vertical-align: text-top;
-}
-form .input {
- color: #444;
-}
-form .required {
- font-weight: bold;
-}
-form .required label:after {
- color: #e32;
- content: '*';
- display:inline;
-}
-form div.submit {
- border: 0;
- clear: both;
- margin-top: 10px;
-}
-label {
- display: block;
- font-size: 110%;
- margin-bottom:3px;
-}
-input, textarea {
- clear: both;
- font-size: 140%;
- font-family: "frutiger linotype", "lucida grande", "verdana", sans-serif;
- padding: 1%;
- width:98%;
-}
-select {
- clear: both;
- font-size: 120%;
- vertical-align: text-bottom;
-}
-select[multiple=multiple] {
- width: 100%;
-}
-option {
- font-size: 120%;
- padding: 0 3px;
-}
-input[type=checkbox] {
- clear: left;
- float: left;
- margin: 0px 6px 7px 2px;
- width: auto;
-}
-div.checkbox label {
- display: inline;
-}
-input[type=radio] {
- float:left;
- width:auto;
- margin: 6px 0;
- padding: 0;
- line-height: 26px;
-}
-.radio label {
- margin: 0 0 6px 20px;
- line-height: 26px;
-}
-input[type=submit] {
- display: inline;
- font-size: 110%;
- width: auto;
-}
-form .submit input[type=submit] {
- background:#62af56;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#76BF6B), to(#3B8230));
- background-image: -webkit-linear-gradient(top, #76BF6B, #3B8230);
- background-image: -moz-linear-gradient(top, #76BF6B, #3B8230);
- border-color: #2d6324;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px;
- padding: 8px 10px;
-}
-form .submit input[type=submit]:hover {
- background: #5BA150;
-}
-/* Form errors */
-form .error {
- background: #FFDACC;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- border-radius: 4px;
- font-weight: normal;
-}
-form .error-message {
- -moz-border-radius: none;
- -webkit-border-radius: none;
- border-radius: none;
- border: none;
- background: none;
- margin: 0;
- padding-left: 4px;
- padding-right: 0;
-}
-form .error,
-form .error-message {
- color: #9E2424;
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- -ms-box-shadow: none;
- -o-box-shadow: none;
- box-shadow: none;
- text-shadow: none;
-}
-
-/** Notices and Errors **/
-.message {
- clear: both;
- color: #fff;
- font-size: 140%;
- font-weight: bold;
- margin: 0 0 1em 0;
- padding: 5px;
-}
-
-.success,
-.message,
-.cake-error,
-.cake-debug,
-.notice,
-p.error,
-.error-message {
- background: #ffcc00;
- background-repeat: repeat-x;
- background-image: -moz-linear-gradient(top, #ffcc00, #E6B800);
- background-image: -ms-linear-gradient(top, #ffcc00, #E6B800);
- background-image: -webkit-gradient(linear, left top, left bottom, from(#ffcc00), to(#E6B800));
- background-image: -webkit-linear-gradient(top, #ffcc00, #E6B800);
- background-image: -o-linear-gradient(top, #ffcc00, #E6B800);
- background-image: linear-gradient(top, #ffcc00, #E6B800);
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
- border: 1px solid rgba(0, 0, 0, 0.2);
- margin-bottom: 18px;
- padding: 7px 14px;
- color: #404040;
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
-}
-.success,
-.message,
-.cake-error,
-p.error,
-.error-message {
- clear: both;
- color: #fff;
- background: #c43c35;
- border: 1px solid rgba(0, 0, 0, 0.5);
- background-repeat: repeat-x;
- background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
- background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
- background-image: -webkit-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));
- background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
- background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
- background-image: linear-gradient(top, #ee5f5b, #c43c35);
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
-}
-.success {
- clear: both;
- color: #fff;
- border: 1px solid rgba(0, 0, 0, 0.5);
- background: #3B8230;
- background-repeat: repeat-x;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#76BF6B), to(#3B8230));
- background-image: -webkit-linear-gradient(top, #76BF6B, #3B8230);
- background-image: -moz-linear-gradient(top, #76BF6B, #3B8230);
- background-image: -ms-linear-gradient(top, #76BF6B, #3B8230);
- background-image: -o-linear-gradient(top, #76BF6B, #3B8230);
- background-image: linear-gradient(top, #76BF6B, #3B8230);
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
-}
-p.error {
- font-family: Monaco, Consolas, Courier, monospace;
- font-size: 120%;
- padding: 0.8em;
- margin: 1em 0;
-}
-p.error em {
- font-weight: normal;
- line-height: 140%;
-}
-.notice {
- color: #000;
- display: block;
- font-size: 120%;
- padding: 0.8em;
- margin: 1em 0;
-}
-.success {
- color: #fff;
-}
-
-/** Actions **/
-.actions ul {
- margin: 0;
- padding: 0;
-}
-.actions li {
- margin:0 0 0.5em 0;
- list-style-type: none;
- white-space: nowrap;
- padding: 0;
-}
-.actions ul li a {
- font-weight: normal;
- display: block;
- clear: both;
-}
-
-/* Buttons and button links */
-input[type=submit],
-.actions ul li a,
-.actions a {
- font-weight:normal;
- padding: 4px 8px;
- background: #dcdcdc;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#fefefe), to(#dcdcdc));
- background-image: -webkit-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: -moz-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: -ms-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: -o-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: linear-gradient(top, #fefefe, #dcdcdc);
- color:#333;
- border:1px solid #bbb;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- text-decoration: none;
- text-shadow: #fff 0px 1px 0px;
- min-width: 0;
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0px 1px 1px rgba(0, 0, 0, 0.2);
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0px 1px 1px rgba(0, 0, 0, 0.2);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0px 1px 1px rgba(0, 0, 0, 0.2);
- -webkit-user-select: none;
- user-select: none;
-}
-.actions ul li a:hover,
-.actions a:hover {
- background: #ededed;
- border-color: #acacac;
- text-decoration: none;
-}
-input[type=submit]:active,
-.actions ul li a:active,
-.actions a:active {
- background: #eee;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#dfdfdf), to(#eee));
- background-image: -webkit-linear-gradient(top, #dfdfdf, #eee);
- background-image: -moz-linear-gradient(top, #dfdfdf, #eee);
- background-image: -ms-linear-gradient(top, #dfdfdf, #eee);
- background-image: -o-linear-gradient(top, #dfdfdf, #eee);
- background-image: linear-gradient(top, #dfdfdf, #eee);
- text-shadow: #eee 0px 1px 0px;
- -moz-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3);
- -webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3);
- box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3);
- border-color: #aaa;
- text-decoration: none;
-}
-
-/** Related **/
-.related {
- clear: both;
- display: block;
-}
-
-/** Debugging **/
-pre {
- color: #000;
- background: #f0f0f0;
- padding: 15px;
- -moz-box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
- -webkit-box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
- box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
-}
-.cake-debug-output {
- padding: 0;
- position: relative;
-}
-.cake-debug-output > span {
- position: absolute;
- top: 5px;
- right: 5px;
- background: rgba(255, 255, 255, 0.3);
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- border-radius: 4px;
- padding: 5px 6px;
- color: #000;
- display: block;
- float: left;
- -moz-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.25), 0 1px 0 rgba(255, 255, 255, 0.5);
- -webkit-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.25), 0 1px 0 rgba(255, 255, 255, 0.5);
- box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.25), 0 1px 0 rgba(255, 255, 255, 0.5);
- text-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
-}
-.cake-debug,
-.cake-error {
- font-size: 16px;
- line-height: 20px;
- clear: both;
-}
-.cake-error > a {
- text-shadow: none;
-}
-.cake-error {
- white-space: normal;
-}
-.cake-stack-trace {
- background: rgba(255, 255, 255, 0.7);
- color: #333;
- margin: 10px 0 5px 0;
- padding: 10px 10px 0 10px;
- font-size: 120%;
- line-height: 140%;
- overflow: auto;
- position: relative;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- border-radius: 4px;
-}
-.cake-stack-trace a {
- text-shadow: none;
- background: rgba(255, 255, 255, 0.7);
- padding: 5px;
- -moz-border-radius: 10px;
- -webkit-border-radius: 10px;
- border-radius: 10px;
- margin: 0px 4px 10px 2px;
- font-family: sans-serif;
- font-size: 14px;
- line-height: 14px;
- display: inline-block;
- text-decoration: none;
- -moz-box-shadow: inset 0px 1px 0 rgba(0, 0, 0, 0.3);
- -webkit-box-shadow: inset 0px 1px 0 rgba(0, 0, 0, 0.3);
- box-shadow: inset 0px 1px 0 rgba(0, 0, 0, 0.3);
-}
-.cake-code-dump pre {
- position: relative;
- overflow: auto;
-}
-.cake-context {
- margin-bottom: 10px;
-}
-.cake-stack-trace pre {
- color: #000;
- background-color: #F0F0F0;
- margin: 0px 0 10px 0;
- padding: 1em;
- overflow: auto;
- text-shadow: none;
-}
-.cake-stack-trace li {
- padding: 10px 5px 0px;
- margin: 0 0 4px 0;
- font-family: monospace;
- border: 1px solid #bbb;
- -moz-border-radius: 4px;
- -wekbkit-border-radius: 4px;
- border-radius: 4px;
- background: #dcdcdc;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#fefefe), to(#dcdcdc));
- background-image: -webkit-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: -moz-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: -ms-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: -o-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: linear-gradient(top, #fefefe, #dcdcdc);
-}
-/* excerpt */
-.cake-code-dump pre,
-.cake-code-dump pre code {
- clear: both;
- font-size: 12px;
- line-height: 15px;
- margin: 4px 2px;
- padding: 4px;
- overflow: auto;
-}
-.cake-code-dump .code-highlight {
- display: block;
- background-color: rgba(255, 255, 0, 0.5);
-}
-.code-coverage-results div.code-line {
- padding-left:5px;
- display:block;
- margin-left:10px;
-}
-.code-coverage-results div.uncovered span.content {
- background:#ecc;
-}
-.code-coverage-results div.covered span.content {
- background:#cec;
-}
-.code-coverage-results div.ignored span.content {
- color:#aaa;
-}
-.code-coverage-results span.line-num {
- color:#666;
- display:block;
- float:left;
- width:20px;
- text-align:right;
- margin-right:5px;
-}
-.code-coverage-results span.line-num strong {
- color:#666;
-}
-.code-coverage-results div.start {
- border:1px solid #aaa;
- border-width:1px 1px 0px 1px;
- margin-top:30px;
- padding-top:5px;
-}
-.code-coverage-results div.end {
- border:1px solid #aaa;
- border-width:0px 1px 1px 1px;
- margin-bottom:30px;
- padding-bottom:5px;
-}
-.code-coverage-results div.realstart {
- margin-top:0px;
-}
-.code-coverage-results p.note {
- color:#bbb;
- padding:5px;
- margin:5px 0 10px;
- font-size:10px;
-}
-.code-coverage-results span.result-bad {
- color: #a00;
-}
-.code-coverage-results span.result-ok {
- color: #fa0;
-}
-.code-coverage-results span.result-good {
- color: #0a0;
-}
-
-/** Elements **/
-#url-rewriting-warning {
- display:none;
-}
diff --git a/app/webroot/favicon.ico b/app/webroot/favicon.ico
deleted file mode 100644
index b36e81f2f35..00000000000
Binary files a/app/webroot/favicon.ico and /dev/null differ
diff --git a/app/webroot/files/empty b/app/webroot/files/empty
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/app/webroot/img/test-error-icon.png b/app/webroot/img/test-error-icon.png
deleted file mode 100644
index 07bb1241143..00000000000
Binary files a/app/webroot/img/test-error-icon.png and /dev/null differ
diff --git a/app/webroot/img/test-fail-icon.png b/app/webroot/img/test-fail-icon.png
deleted file mode 100644
index f9d2f147ec4..00000000000
Binary files a/app/webroot/img/test-fail-icon.png and /dev/null differ
diff --git a/app/webroot/img/test-pass-icon.png b/app/webroot/img/test-pass-icon.png
deleted file mode 100644
index 99c5eb05ad2..00000000000
Binary files a/app/webroot/img/test-pass-icon.png and /dev/null differ
diff --git a/app/webroot/img/test-skip-icon.png b/app/webroot/img/test-skip-icon.png
deleted file mode 100644
index 749771c9895..00000000000
Binary files a/app/webroot/img/test-skip-icon.png and /dev/null differ
diff --git a/app/webroot/index.php b/app/webroot/index.php
deleted file mode 100644
index 14ba634724f..00000000000
--- a/app/webroot/index.php
+++ /dev/null
@@ -1,96 +0,0 @@
-dispatch(new CakeRequest(), new CakeResponse(array('charset' => Configure::read('App.encoding'))));
diff --git a/app/webroot/js/empty b/app/webroot/js/empty
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/app/webroot/test.php b/app/webroot/test.php
deleted file mode 100644
index 9a3a072add3..00000000000
--- a/app/webroot/test.php
+++ /dev/null
@@ -1,92 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing
- * @package app.webroot
- * @since CakePHP(tm) v 1.2.0.4433
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-set_time_limit(0);
-ini_set('display_errors', 1);
-/**
- * Use the DS to separate the directories in other defines
- */
- if (!defined('DS')) {
- define('DS', DIRECTORY_SEPARATOR);
- }
-/**
- * These defines should only be edited if you have cake installed in
- * a directory layout other than the way it is distributed.
- * When using custom settings be sure to use the DS and do not add a trailing DS.
- */
-
-/**
- * The full path to the directory which holds "app", WITHOUT a trailing DS.
- *
- */
- if (!defined('ROOT')) {
- define('ROOT', dirname(dirname(dirname(__FILE__))));
- }
-/**
- * The actual directory name for the "app".
- *
- */
- if (!defined('APP_DIR')) {
- define('APP_DIR', basename(dirname(dirname(__FILE__))));
- }
-
-/**
- * The absolute path to the "Cake" directory, WITHOUT a trailing DS.
- *
- * For ease of development CakePHP uses PHP's include_path. If you
- * need to cannot modify your include_path, you can set this path.
- *
- * Leaving this constant undefined will result in it being defined in Cake/bootstrap.php
- */
- //define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib');
-
-/**
- * Editing below this line should not be necessary.
- * Change at your own risk.
- *
- */
-if (!defined('WEBROOT_DIR')) {
- define('WEBROOT_DIR', basename(dirname(__FILE__)));
-}
-if (!defined('WWW_ROOT')) {
- define('WWW_ROOT', dirname(__FILE__) . DS);
-}
-
-if (!defined('CAKE_CORE_INCLUDE_PATH')) {
- if (function_exists('ini_set')) {
- ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path'));
- }
- if (!include('Cake' . DS . 'bootstrap.php')) {
- $failed = true;
- }
-} else {
- if (!include(CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'bootstrap.php')) {
- $failed = true;
- }
-}
-if (!empty($failed)) {
- trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR);
-}
-
-if (Configure::read('debug') < 1) {
- die(__d('cake_dev', 'Debug setting does not allow access to this url.'));
-}
-
-require_once CAKE . 'TestSuite' . DS . 'CakeTestSuiteDispatcher.php';
-
-CakeTestSuiteDispatcher::run();
diff --git a/build.properties b/build.properties
deleted file mode 100644
index e3c99ca9177..00000000000
--- a/build.properties
+++ /dev/null
@@ -1,12 +0,0 @@
-# Name
-project.name = CakePHP
-
-# Git stuff
-git.remote = changeme!
-
-# Directories
-build.dir = build
-dist.dir = dist
-
-# Server
-pirum.dir = /home/cakephp/www-live/pear.cakephp.org
diff --git a/build.xml b/build.xml
deleted file mode 100644
index c6542643826..00000000000
--- a/build.xml
+++ /dev/null
@@ -1,214 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- CakePHP
- CakePHP Rapid Development Framework
- pear.cakephp.org
- CakePHP is an application development framework for PHP 5.2+
-
-
-
-
-
-
-
-
-
-
-
-
- MIT License
-
-
- http://github.com/cakephp/cakephp/blob/master/README
-
-
-
-
-
- script
- php
- php
- php
- php
-
-
-
-
-
- php
- php
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/composer.json b/composer.json
new file mode 100644
index 00000000000..e64e685c727
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,153 @@
+{
+ "name": "cakephp/cakephp",
+ "type": "library",
+ "description": "The CakePHP framework",
+ "keywords": [
+ "framework",
+ "mvc",
+ "rapid-development",
+ "conventions over configuration",
+ "dry",
+ "orm",
+ "form",
+ "validation",
+ "psr-7"
+ ],
+ "homepage": "https://cakephp.org",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "CakePHP Community",
+ "homepage": "https://github.com/cakephp/cakephp/graphs/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=8.2",
+ "ext-intl": "*",
+ "ext-json": "*",
+ "ext-mbstring": "*",
+ "cakephp/chronos": "^3.3",
+ "composer/ca-bundle": "^1.5",
+ "laminas/laminas-diactoros": "^3.8",
+ "laminas/laminas-httphandlerrunner": "^2.6",
+ "league/container": "^5.1",
+ "psr/container": "^1.1 || ^2.0",
+ "psr/http-client": "^1.0.2",
+ "psr/http-factory": "^1.1",
+ "psr/http-message": "^1.1 || ^2.0",
+ "psr/http-server-handler": "^1.0.2",
+ "psr/http-server-middleware": "^1.0.2",
+ "psr/log": "^3.0",
+ "psr/simple-cache": "^2.0 || ^3.0"
+ },
+ "replace": {
+ "cakephp/cache": "self.version",
+ "cakephp/collection": "self.version",
+ "cakephp/console": "self.version",
+ "cakephp/core": "self.version",
+ "cakephp/database": "self.version",
+ "cakephp/datasource": "self.version",
+ "cakephp/event": "self.version",
+ "cakephp/form": "self.version",
+ "cakephp/http": "self.version",
+ "cakephp/i18n": "self.version",
+ "cakephp/log": "self.version",
+ "cakephp/orm": "self.version",
+ "cakephp/utility": "self.version",
+ "cakephp/validation": "self.version"
+ },
+ "require-dev": {
+ "cakephp/cakephp-codesniffer": "^5.3",
+ "http-interop/http-factory-tests": "^2.0",
+ "mikey179/vfsstream": "^1.6.12",
+ "mockery/mockery": "^1.6",
+ "paragonie/csp-builder": "^2.3 || ^3.0",
+ "phpunit/phpunit": "^11.5.3 || ^12.1.3 || ^13.0"
+ },
+ "suggest": {
+ "ext-curl": "To enable more efficient network calls in Http\\Client.",
+ "ext-openssl": "To use Security::encrypt() or have secure CSRF token generation.",
+ "paragonie/csp-builder": "CSP builder, to use the CSP Middleware"
+ },
+ "provide": {
+ "psr/container-implementation": "^2.0",
+ "psr/http-client-implementation": "^1.0",
+ "psr/http-factory-implementation": "^1.0",
+ "psr/http-server-handler-implementation": "^1.0",
+ "psr/http-server-middleware-implementation": "^1.0",
+ "psr/log-implementation": "^3.0",
+ "psr/simple-cache-implementation": "^3.0"
+ },
+ "config": {
+ "lock": false,
+ "process-timeout": 900,
+ "sort-packages": true,
+ "allow-plugins": {
+ "dealerdirect/phpcodesniffer-composer-installer": true,
+ "phpstan/extension-installer": true
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Cake\\": "src/"
+ },
+ "files": [
+ "src/Core/functions.php",
+ "src/Error/functions.php",
+ "src/Collection/functions.php",
+ "src/I18n/functions.php",
+ "src/ORM/bootstrap.php",
+ "src/Routing/functions.php",
+ "src/Utility/bootstrap.php"
+ ]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Cake\\PHPStan\\": "tests/PHPStan/",
+ "Cake\\Test\\": "tests/",
+ "TestApp\\": "tests/test_app/TestApp/",
+ "TestApp\\Test\\": "tests/test_app/TestApp/tests/",
+ "TestPlugin\\": "tests/test_app/Plugin/TestPlugin/src/",
+ "TestPlugin\\Test\\": "tests/test_app/Plugin/TestPlugin/tests/",
+ "TestPluginTwo\\": "tests/test_app/Plugin/TestPluginTwo/src/",
+ "Company\\TestPluginThree\\": "tests/test_app/Plugin/Company/TestPluginThree/src/",
+ "Company\\TestPluginThree\\Test\\": "tests/test_app/Plugin/Company/TestPluginThree/tests/",
+ "Named\\": "tests/test_app/Plugin/Named/src/",
+ "TestTheme\\": "tests/test_app/Plugin/TestTheme/src/",
+ "PluginJs\\": "tests/test_app/Plugin/PluginJs/src/"
+ }
+ },
+ "scripts": {
+ "check": [
+ "@cs-check",
+ "@test"
+ ],
+ "cs-check": "phpcs",
+ "cs-fix": "phpcbf",
+ "stan": [
+ "tools/phpstan analyse",
+ "tools/psalm"
+ ],
+ "stan-tests": "tools/phpstan analyze -c tests/phpstan.neon",
+ "stan-baseline": "tools/phpstan --generate-baseline",
+ "stan-setup": "phive install",
+ "psalm-baseline": "tools/psalm --set-baseline=psalm-baseline.xml",
+ "lowest": "validate-prefer-lowest",
+ "lowest-setup": "composer update --prefer-lowest --prefer-stable --prefer-dist --no-interaction && cp composer.json composer.backup && composer require --dev dereuromark/composer-prefer-lowest && mv composer.backup composer.json",
+ "rector-setup": "cp composer.json composer.backup && composer require --dev rector/rector:\"~2.4.0\" && mv composer.backup composer.json",
+ "rector-check": "vendor/bin/rector process --dry-run",
+ "rector-fix": "vendor/bin/rector process",
+ "test": "phpunit",
+ "test-coverage": "phpunit --coverage-clover=clover.xml"
+ },
+ "support": {
+ "issues": "https://github.com/cakephp/cakephp/issues",
+ "forum": "https://discourse.cakephp.org/",
+ "source": "https://github.com/cakephp/cakephp"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-5.next": "5.4.x-dev"
+ }
+ }
+}
diff --git a/config/bootstrap.php b/config/bootstrap.php
new file mode 100644
index 00000000000..4e95849bc2c
--- /dev/null
+++ b/config/bootstrap.php
@@ -0,0 +1,21 @@
+ trim(array_pop($versionFile)),
+];
diff --git a/contrib/git-filter-repo b/contrib/git-filter-repo
new file mode 100644
index 00000000000..fb3de42e428
--- /dev/null
+++ b/contrib/git-filter-repo
@@ -0,0 +1,4989 @@
+#!/usr/bin/env python3
+
+"""
+git-filter-repo filters git repositories, similar to git filter-branch, BFG
+repo cleaner, and others. The basic idea is that it works by running
+ git fast-export | filter | git fast-import
+where this program not only launches the whole pipeline but also serves as
+the 'filter' in the middle. It does a few additional things on top as well
+in order to make it into a well-rounded filtering tool.
+
+git-filter-repo can also be used as a library for more involved filtering
+operations; however:
+ ***** API BACKWARD COMPATIBILITY CAVEAT *****
+ Programs using git-filter-repo as a library can reach pretty far into its
+ internals, but I am not prepared to guarantee backward compatibility of
+ all APIs. I suspect changes will be rare, but I reserve the right to
+ change any API. Since it is assumed that repository filtering is
+ something one would do very rarely, and in particular that it's a
+ one-shot operation, this should not be a problem in practice for anyone.
+ However, if you want to re-use a program you have written that uses
+ git-filter-repo as a library (or makes use of one of its --*-callback
+ arguments), you should either make sure you are using the same version of
+ git and git-filter-repo, or make sure to re-test it.
+
+ If there are particular pieces of the API you are concerned about, and
+ there is not already a testcase for it in t9391-lib-usage.sh or
+ t9392-python-callback.sh, please contribute a testcase. That will not
+ prevent me from changing the API, but it will allow you to look at the
+ history of a testcase to see whether and how the API changed.
+ ***** END API BACKWARD COMPATIBILITY CAVEAT *****
+"""
+
+import argparse
+import collections
+import fnmatch
+import gettext
+import io
+import os
+import platform
+import re
+import shutil
+import subprocess
+import sys
+import time
+import textwrap
+
+from datetime import tzinfo, timedelta, datetime
+
+__all__ = ["Blob", "Reset", "FileChange", "Commit", "Tag", "Progress",
+ "Checkpoint", "FastExportParser", "ProgressWriter",
+ "string_to_date", "date_to_string",
+ "record_id_rename", "GitUtils", "FilteringOptions", "RepoFilter"]
+
+# The globals to make visible to callbacks. They will see all our imports for
+# free, as well as our public API.
+public_globals = ["__builtins__", "argparse", "collections", "fnmatch",
+ "gettext", "io", "os", "platform", "re", "shutil",
+ "subprocess", "sys", "time", "textwrap", "tzinfo",
+ "timedelta", "datetime"] + __all__
+
+deleted_hash = b'0'*40
+write_marks = True
+date_format_permissive = True
+
+def gettext_poison(msg):
+ if "GIT_TEST_GETTEXT_POISON" in os.environ: # pragma: no cover
+ return "# GETTEXT POISON #"
+ return gettext.gettext(msg)
+
+_ = gettext_poison
+
+def setup_gettext():
+ TEXTDOMAIN="git-filter-repo"
+ podir = os.environ.get("GIT_TEXTDOMAINDIR") or "@@LOCALEDIR@@"
+ if not os.path.isdir(podir): # pragma: no cover
+ podir = None # Python has its own fallback; use that
+
+ ## This looks like the most straightforward translation of the relevant
+ ## code in git.git:gettext.c and git.git:perl/Git/I18n.pm:
+ #import locale
+ #locale.setlocale(locale.LC_MESSAGES, "");
+ #locale.setlocale(locale.LC_TIME, "");
+ #locale.textdomain(TEXTDOMAIN);
+ #locale.bindtextdomain(TEXTDOMAIN, podir);
+ ## but the python docs suggest using the gettext module (which doesn't
+ ## have setlocale()) instead, so:
+ gettext.textdomain(TEXTDOMAIN);
+ gettext.bindtextdomain(TEXTDOMAIN, podir);
+
+def _timedelta_to_seconds(delta):
+ """
+ Converts timedelta to seconds
+ """
+ offset = delta.days*86400 + delta.seconds + (delta.microseconds+0.0)/1000000
+ return round(offset)
+
+class FixedTimeZone(tzinfo):
+ """
+ Fixed offset in minutes east from UTC.
+ """
+
+ tz_re = re.compile(br'^([-+]?)(\d\d)(\d\d)$')
+
+ def __init__(self, offset_string):
+ tzinfo.__init__(self)
+ sign, hh, mm = FixedTimeZone.tz_re.match(offset_string).groups()
+ factor = -1 if (sign and sign == b'-') else 1
+ self._offset = timedelta(minutes = factor*(60*int(hh) + int(mm)))
+ self._offset_string = offset_string
+
+ def utcoffset(self, dt):
+ return self._offset
+
+ def tzname(self, dt):
+ return self._offset_string
+
+ def dst(self, dt):
+ return timedelta(0)
+
+def string_to_date(datestring):
+ (unix_timestamp, tz_offset) = datestring.split()
+ return datetime.fromtimestamp(int(unix_timestamp),
+ FixedTimeZone(tz_offset))
+
+def date_to_string(dateobj):
+ epoch = datetime.fromtimestamp(0, dateobj.tzinfo)
+ return(b'%d %s' % (int(_timedelta_to_seconds(dateobj - epoch)),
+ dateobj.tzinfo.tzname(0)))
+
+def decode(bytestr):
+ 'Try to convert bytestr to utf-8 for outputting as an error message.'
+ return bytestr.decode('utf-8', 'backslashreplace')
+
+def glob_to_regex(glob_bytestr):
+ 'Translate glob_bytestr into a regex on bytestrings'
+
+ # fnmatch.translate is idiotic and won't accept bytestrings
+ if (decode(glob_bytestr).encode() != glob_bytestr): # pragma: no cover
+ raise SystemExit(_("Error: Cannot handle glob %s").format(glob_bytestr))
+
+ # Create regex operating on string
+ regex = fnmatch.translate(decode(glob_bytestr))
+
+ # FIXME: This is an ugly hack...
+ # fnmatch.translate tries to do multi-line matching and wants the glob to
+ # match up to the end of the input, which isn't relevant for us, so we
+ # have to modify the regex. fnmatch.translate has used different regex
+ # constructs to achieve this with different python versions, so we have
+ # to check for each of them and then fix it up. It would be much better
+ # if fnmatch.translate could just take some flags to allow us to specify
+ # what we want rather than employing this hackery, but since it
+ # doesn't...
+ if regex.endswith(r'\Z(?ms)'): # pragma: no cover
+ regex = regex[0:-7]
+ elif regex.startswith(r'(?s:') and regex.endswith(r')\Z'): # pragma: no cover
+ regex = regex[4:-3]
+ elif regex.startswith(r'(?s:') and regex.endswith(r')\z'): # pragma: no cover
+ # Yaay, python3.14 for senselessly duplicating \Z as \z...
+ regex = regex[4:-3]
+
+ # Finally, convert back to regex operating on bytestr
+ return regex.encode()
+
+class PathQuoting:
+ _unescape = {b'a': b'\a',
+ b'b': b'\b',
+ b'f': b'\f',
+ b'n': b'\n',
+ b'r': b'\r',
+ b't': b'\t',
+ b'v': b'\v',
+ b'"': b'"',
+ b'\\':b'\\'}
+ _unescape_re = re.compile(br'\\([a-z"\\]|[0-9]{3})')
+ _escape = [bytes([x]) for x in range(127)]+[
+ b'\\'+bytes(ord(c) for c in oct(x)[2:]) for x in range(127,256)]
+ _reverse = dict(map(reversed, _unescape.items()))
+ for x in _reverse:
+ _escape[ord(x)] = b'\\'+_reverse[x]
+ _special_chars = [len(x) > 1 for x in _escape]
+
+ @staticmethod
+ def unescape_sequence(orig):
+ seq = orig.group(1)
+ return PathQuoting._unescape[seq] if len(seq) == 1 else bytes([int(seq, 8)])
+
+ @staticmethod
+ def dequote(quoted_string):
+ if quoted_string.startswith(b'"'):
+ assert quoted_string.endswith(b'"')
+ return PathQuoting._unescape_re.sub(PathQuoting.unescape_sequence,
+ quoted_string[1:-1])
+ return quoted_string
+
+ @staticmethod
+ def enquote(unquoted_string):
+ # Option 1: Quoting when fast-export would:
+ # pqsc = PathQuoting._special_chars
+ # if any(pqsc[x] for x in set(unquoted_string)):
+ # Option 2, perf hack: do minimal amount of quoting required by fast-import
+ if unquoted_string.startswith(b'"') or b'\n' in unquoted_string:
+ pqe = PathQuoting._escape
+ return b'"' + b''.join(pqe[x] for x in unquoted_string) + b'"'
+ return unquoted_string
+
+class AncestryGraph(object):
+ """
+ A class that maintains a direct acycle graph of commits for the purpose of
+ determining if one commit is the ancestor of another.
+
+ A note about identifiers in Commit objects:
+ * Commit objects have 2 identifiers: commit.old_id and commit.id, because:
+ * The original fast-export stream identified commits by an identifier.
+ This is often an integer, but is sometimes a hash (particularly when
+ --reference-excluded-parents is provided)
+ * The new fast-import stream we use may not use the same identifiers.
+ If new blobs or commits are inserted (such as lint-history does), then
+ the integer (or hash) are no longer valid.
+
+ A note about identifiers in AncestryGraph objects, of which there are three:
+ * A given AncestryGraph is based on either commit.old_id or commit.id, but
+ not both. These are the keys for self.value.
+ * Using full hashes (occasionally) for children in self.graph felt
+ wasteful, so we use our own internal integer within self.graph.
+ self.value maps from commit {old_}id to our internal integer id.
+ * When working with commit.old_id, it is also sometimes useful to be able
+ to map these to the original hash, i.e. commit.original_id. So, we
+ also have self.git_hash for mapping from commit.old_id to git's commit
+ hash.
+ """
+
+ def __init__(self):
+ # The next internal identifier we will use; increments with every commit
+ # added to the AncestryGraph
+ self.cur_value = 0
+
+ # A mapping from the external identifers given to us to the simple integers
+ # we use in self.graph
+ self.value = {}
+
+ # A tuple of (depth, list-of-ancestors). Values and keys in this graph are
+ # all integers from the (values of the) self.value dict. The depth of a
+ # commit is one more than the max depth of any of its ancestors.
+ self.graph = {}
+
+ # A mapping from external identifier (i.e. from the keys of self.value) to
+ # the hash of the given commit. Only populated for graphs based on
+ # commit.old_id, since we won't know until later what the git_hash for
+ # graphs based on commit.id (since we have to wait for fast-import to
+ # create the commit and notify us of its hash; see _pending_renames).
+ # elsewhere
+ self.git_hash = {}
+
+ # Reverse maps; only populated if needed. Caller responsible to check
+ # and ensure they are populated
+ self._reverse_value = {}
+ self._hash_to_id = {}
+
+ # Cached results from previous calls to is_ancestor().
+ self._cached_is_ancestor = {}
+
+ def record_external_commits(self, external_commits):
+ """
+ Record in graph that each commit in external_commits exists, and is
+ treated as a root commit with no parents.
+ """
+ for c in external_commits:
+ if c not in self.value:
+ self.cur_value += 1
+ self.value[c] = self.cur_value
+ self.graph[self.cur_value] = (1, [])
+ self.git_hash[c] = c
+
+ def add_commit_and_parents(self, commit, parents, githash = None):
+ """
+ Record in graph that commit has the given parents (all identified by
+ fast export stream identifiers, usually integers but sometimes hashes).
+ parents _MUST_ have been first recorded. commit _MUST_ not have been
+ recorded yet. Also, record the mapping between commit and githash, if
+ githash is given.
+ """
+ assert all(p in self.value for p in parents)
+ assert commit not in self.value
+
+ # Get values for commit and parents
+ self.cur_value += 1
+ self.value[commit] = self.cur_value
+ if githash:
+ self.git_hash[commit] = githash
+ graph_parents = [self.value[x] for x in parents]
+
+ # Determine depth for commit, then insert the info into the graph
+ depth = 1
+ if parents:
+ depth += max(self.graph[p][0] for p in graph_parents)
+ self.graph[self.cur_value] = (depth, graph_parents)
+
+ def record_hash(self, commit_id, githash):
+ '''
+ If a githash was not recorded for commit_id, when add_commit_and_parents
+ was called, add it now.
+ '''
+ assert commit_id in self.value
+ assert commit_id not in self.git_hash
+ self.git_hash[commit_id] = githash
+
+ def _ensure_reverse_maps_populated(self):
+ if not self._hash_to_id:
+ assert not self._reverse_value
+ self._hash_to_id = {v: k for k, v in self.git_hash.items()}
+ self._reverse_value = {v: k for k, v in self.value.items()}
+
+ def get_parent_hashes(self, commit_hash):
+ '''
+ Given a commit_hash, return its parents hashes
+ '''
+ #
+ # We have to map:
+ # commit hash -> fast export stream id -> graph id
+ # then lookup
+ # parent graph ids for given graph id
+ # then we need to map
+ # parent graph ids -> parent fast export ids -> parent commit hashes
+ #
+ self._ensure_reverse_maps_populated()
+ commit_fast_export_id = self._hash_to_id[commit_hash]
+ commit_graph_id = self.value[commit_fast_export_id]
+ parent_graph_ids = self.graph[commit_graph_id][1]
+ parent_fast_export_ids = [self._reverse_value[x] for x in parent_graph_ids]
+ parent_hashes = [self.git_hash[x] for x in parent_fast_export_ids]
+ return parent_hashes
+
+ def map_to_hash(self, commit_id):
+ '''
+ Given a commit (by fast export stream id), return its hash
+ '''
+ return self.git_hash.get(commit_id, None)
+
+ def is_ancestor(self, possible_ancestor, check):
+ """
+ Return whether possible_ancestor is an ancestor of check
+ """
+ a, b = self.value[possible_ancestor], self.value[check]
+ original_pair = (a,b)
+ a_depth = self.graph[a][0]
+ ancestors = [b]
+ visited = set()
+ while ancestors:
+ ancestor = ancestors.pop()
+ prev_pair = (a, ancestor)
+ if prev_pair in self._cached_is_ancestor:
+ if not self._cached_is_ancestor[prev_pair]:
+ continue
+ self._cached_is_ancestor[original_pair] = True
+ return True
+ if ancestor in visited:
+ continue
+ visited.add(ancestor)
+ depth, more_ancestors = self.graph[ancestor]
+ if ancestor == a:
+ self._cached_is_ancestor[original_pair] = True
+ return True
+ elif depth <= a_depth:
+ continue
+ ancestors.extend(more_ancestors)
+ self._cached_is_ancestor[original_pair] = False
+ return False
+
+class MailmapInfo(object):
+ def __init__(self, filename):
+ self.changes = {}
+ self._parse_file(filename)
+
+ def _parse_file(self, filename):
+ name_and_email_re = re.compile(br'(.*?)\s*<([^>]*)>\s*')
+ comment_re = re.compile(br'\s*#.*')
+ if not os.access(filename, os.R_OK):
+ raise SystemExit(_("Cannot read %s") % decode(filename))
+ with open(filename, 'br') as f:
+ count = 0
+ for line in f:
+ count += 1
+ err = "Unparseable mailmap file: line #{} is bad: {}".format(count, line)
+ # Remove comments
+ line = comment_re.sub(b'', line)
+ # Remove leading and trailing whitespace
+ line = line.strip()
+ if not line:
+ continue
+
+ m = name_and_email_re.match(line)
+ if not m:
+ raise SystemExit(err)
+ proper_name, proper_email = m.groups()
+ if len(line) == m.end():
+ self.changes[(None, proper_email)] = (proper_name, proper_email)
+ continue
+ rest = line[m.end():]
+ m = name_and_email_re.match(rest)
+ if m:
+ commit_name, commit_email = m.groups()
+ if len(rest) != m.end():
+ raise SystemExit(err)
+ else:
+ commit_name, commit_email = rest, None
+ self.changes[(commit_name, commit_email)] = (proper_name, proper_email)
+
+ def translate(self, name, email):
+ ''' Given a name and email, return the expected new name and email from the
+ mailmap if there is a translation rule for it, otherwise just return
+ the given name and email.'''
+ for old, new in self.changes.items():
+ old_name, old_email = old
+ new_name, new_email = new
+ if (old_email is None or email.lower() == old_email.lower()) and (
+ name == old_name or not old_name):
+ return (new_name or name, new_email or email)
+ return (name, email)
+
+class ProgressWriter(object):
+ def __init__(self):
+ self._last_progress_update = time.time()
+ self._last_message = None
+
+ def show(self, msg):
+ self._last_message = msg
+ now = time.time()
+ if now - self._last_progress_update > .1:
+ self._last_progress_update = now
+ sys.stdout.write("\r{}".format(msg))
+ sys.stdout.flush()
+
+ def finish(self):
+ self._last_progress_update = 0
+ if self._last_message:
+ self.show(self._last_message)
+ sys.stdout.write("\n")
+
+class _IDs(object):
+ """
+ A class that maintains the 'name domain' of all the 'marks' (short int
+ id for a blob/commit git object). There are two reasons this mechanism
+ is necessary:
+ (1) the output text of fast-export may refer to an object using a different
+ mark than the mark that was assigned to that object using IDS.new().
+ (This class allows you to translate the fast-export marks, "old" to
+ the marks assigned from IDS.new(), "new").
+ (2) when we prune a commit, its "old" id becomes invalid. Any commits
+ which had that commit as a parent needs to use the nearest unpruned
+ ancestor as its parent instead.
+
+ Note that for purpose (1) above, this typically comes about because the user
+ manually creates Blob or Commit objects (for insertion into the stream).
+ It could also come about if we attempt to read the data from two different
+ repositories and trying to combine the data (git fast-export will number ids
+ from 1...n, and having two 1's, two 2's, two 3's, causes issues; granted, we
+ this scheme doesn't handle the two streams perfectly either, but if the first
+ fast export stream is entirely processed and handled before the second stream
+ is started, this mechanism may be sufficient to handle it).
+ """
+
+ def __init__(self):
+ """
+ Init
+ """
+ # The id for the next created blob/commit object
+ self._next_id = 1
+
+ # A map of old-ids to new-ids (1:1 map)
+ self._translation = {}
+
+ # A map of new-ids to every old-id that points to the new-id (1:N map)
+ self._reverse_translation = {}
+
+ def has_renames(self):
+ """
+ Return whether there have been ids remapped to new values
+ """
+ return bool(self._translation)
+
+ def new(self):
+ """
+ Should be called whenever a new blob or commit object is created. The
+ returned value should be used as the id/mark for that object.
+ """
+ rv = self._next_id
+ self._next_id += 1
+ return rv
+
+ def record_rename(self, old_id, new_id, handle_transitivity = False):
+ """
+ Record that old_id is being renamed to new_id.
+ """
+ if old_id != new_id or old_id in self._translation:
+ # old_id -> new_id
+ self._translation[old_id] = new_id
+
+ # Transitivity will be needed if new commits are being inserted mid-way
+ # through a branch.
+ if handle_transitivity:
+ # Anything that points to old_id should point to new_id
+ if old_id in self._reverse_translation:
+ for id_ in self._reverse_translation[old_id]:
+ self._translation[id_] = new_id
+
+ # Record that new_id is pointed to by old_id
+ if new_id not in self._reverse_translation:
+ self._reverse_translation[new_id] = []
+ self._reverse_translation[new_id].append(old_id)
+
+ def translate(self, old_id):
+ """
+ If old_id has been mapped to an alternate id, return the alternate id.
+ """
+ if old_id in self._translation:
+ return self._translation[old_id]
+ else:
+ return old_id
+
+ def __str__(self):
+ """
+ Convert IDs to string; used for debugging
+ """
+ rv = "Current count: %d\nTranslation:\n" % self._next_id
+ for k in sorted(self._translation):
+ rv += " %d -> %s\n" % (k, self._translation[k])
+
+ rv += "Reverse translation:\n"
+ reverse_keys = list(self._reverse_translation.keys())
+ if None in reverse_keys: # pragma: no cover
+ reverse_keys.remove(None)
+ reverse_keys = sorted(reverse_keys)
+ reverse_keys.append(None)
+ for k in reverse_keys:
+ rv += " " + str(k) + " -> " + str(self._reverse_translation[k]) + "\n"
+
+ return rv
+
+class _GitElement(object):
+ """
+ The base class for all git elements that we create.
+ """
+
+ def __init__(self):
+ # A string that describes what type of Git element this is
+ self.type = None
+
+ # A flag telling us if this Git element has been dumped
+ # (i.e. printed) or skipped. Typically elements that have been
+ # dumped or skipped will not be dumped again.
+ self.dumped = 0
+
+ def dump(self, file_):
+ """
+ This version should never be called. Derived classes need to
+ override! We should note that subclasses should implement this
+ method such that the output would match the format produced by
+ fast-export.
+ """
+ raise SystemExit(_("Unimplemented function: %s") % type(self).__name__
+ +".dump()") # pragma: no cover
+
+ def __bytes__(self):
+ """
+ Convert GitElement to bytestring; used for debugging
+ """
+ old_dumped = self.dumped
+ writeme = io.BytesIO()
+ self.dump(writeme)
+ output_lines = writeme.getvalue().splitlines()
+ writeme.close()
+ self.dumped = old_dumped
+ return b"%s:\n %s" % (type(self).__name__.encode(),
+ b"\n ".join(output_lines))
+
+ def skip(self, new_id=None):
+ """
+ Ensures this element will not be written to output
+ """
+ self.dumped = 2
+
+class _GitElementWithId(_GitElement):
+ """
+ The base class for Git elements that have IDs (commits and blobs)
+ """
+
+ def __init__(self):
+ _GitElement.__init__(self)
+
+ # The mark (short, portable id) for this element
+ self.id = _IDS.new()
+
+ # The previous mark for this element
+ self.old_id = None
+
+ def skip(self, new_id=None):
+ """
+ This element will no longer be automatically written to output. When a
+ commit gets skipped, it's ID will need to be translated to that of its
+ parent.
+ """
+ self.dumped = 2
+
+ _IDS.record_rename(self.old_id or self.id, new_id)
+
+class Blob(_GitElementWithId):
+ """
+ This class defines our representation of git blob elements (i.e. our
+ way of representing file contents).
+ """
+
+ def __init__(self, data, original_id = None):
+ _GitElementWithId.__init__(self)
+
+ # Denote that this is a blob
+ self.type = 'blob'
+
+ # Record original id
+ self.original_id = original_id
+
+ # Stores the blob's data
+ assert(type(data) == bytes)
+ self.data = data
+
+ def dump(self, file_):
+ """
+ Write this blob element to a file.
+ """
+ self.dumped = 1
+ BLOB_HASH_TO_NEW_ID[self.original_id] = self.id
+ BLOB_NEW_ID_TO_HASH[self.id] = self.original_id
+
+ file_.write(b'blob\n')
+ file_.write(b'mark :%d\n' % self.id)
+ file_.write(b'data %d\n%s' % (len(self.data), self.data))
+ file_.write(b'\n')
+
+
+class Reset(_GitElement):
+ """
+ This class defines our representation of git reset elements. A reset
+ event is the creation (or recreation) of a named branch, optionally
+ starting from a specific revision).
+ """
+
+ def __init__(self, ref, from_ref = None):
+ _GitElement.__init__(self)
+
+ # Denote that this is a reset
+ self.type = 'reset'
+
+ # The name of the branch being (re)created
+ self.ref = ref
+
+ # Some reference to the branch/commit we are resetting from
+ self.from_ref = from_ref
+
+ def dump(self, file_):
+ """
+ Write this reset element to a file
+ """
+ self.dumped = 1
+
+ file_.write(b'reset %s\n' % self.ref)
+ if self.from_ref:
+ if isinstance(self.from_ref, int):
+ file_.write(b'from :%d\n' % self.from_ref)
+ else:
+ file_.write(b'from %s\n' % self.from_ref)
+ file_.write(b'\n')
+
+class FileChange(_GitElement):
+ """
+ This class defines our representation of file change elements. File change
+ elements are components within a Commit element.
+ """
+
+ def __init__(self, type_, filename = None, id_ = None, mode = None):
+ _GitElement.__init__(self)
+
+ # Denote the type of file-change (b'M' for modify, b'D' for delete, etc)
+ # We could
+ # assert(type(type_) == bytes)
+ # here but I don't just due to worries about performance overhead...
+ self.type = type_
+
+ # Record the name of the file being changed
+ self.filename = filename
+
+ # Record the mode (mode describes type of file entry (non-executable,
+ # executable, or symlink)).
+ self.mode = mode
+
+ # blob_id is the id (mark) of the affected blob
+ self.blob_id = id_
+
+ if type_ == b'DELETEALL':
+ assert filename is None and id_ is None and mode is None
+ self.filename = b'' # Just so PathQuoting.enquote doesn't die
+ else:
+ assert filename is not None
+
+ if type_ == b'M':
+ assert id_ is not None and mode is not None
+ elif type_ == b'D':
+ assert id_ is None and mode is None
+ elif type_ == b'R': # pragma: no cover (now avoid fast-export renames)
+ assert mode is None
+ if id_ is None:
+ raise SystemExit(_("new name needed for rename of %s") % filename)
+ self.filename = (self.filename, id_)
+ self.blob_id = None
+
+ def dump(self, file_):
+ """
+ Write this file-change element to a file
+ """
+ skipped_blob = (self.type == b'M' and self.blob_id is None)
+ if skipped_blob: return
+ self.dumped = 1
+
+ quoted_filename = PathQuoting.enquote(self.filename)
+ if self.type == b'M' and isinstance(self.blob_id, int):
+ file_.write(b'M %s :%d %s\n' % (self.mode, self.blob_id, quoted_filename))
+ elif self.type == b'M':
+ file_.write(b'M %s %s %s\n' % (self.mode, self.blob_id, quoted_filename))
+ elif self.type == b'D':
+ file_.write(b'D %s\n' % quoted_filename)
+ elif self.type == b'DELETEALL':
+ file_.write(b'deleteall\n')
+ else:
+ raise SystemExit(_("Unhandled filechange type: %s") % self.type) # pragma: no cover
+
+class Commit(_GitElementWithId):
+ """
+ This class defines our representation of commit elements. Commit elements
+ contain all the information associated with a commit.
+ """
+
+ def __init__(self, branch,
+ author_name, author_email, author_date,
+ committer_name, committer_email, committer_date,
+ message,
+ file_changes,
+ parents,
+ original_id = None,
+ encoding = None, # encoding for message; None implies UTF-8
+ **kwargs):
+ _GitElementWithId.__init__(self)
+ self.old_id = self.id
+
+ # Denote that this is a commit element
+ self.type = 'commit'
+
+ # Record the affected branch
+ self.branch = branch
+
+ # Record original id
+ self.original_id = original_id
+
+ # Record author's name
+ self.author_name = author_name
+
+ # Record author's email
+ self.author_email = author_email
+
+ # Record date of authoring
+ self.author_date = author_date
+
+ # Record committer's name
+ self.committer_name = committer_name
+
+ # Record committer's email
+ self.committer_email = committer_email
+
+ # Record date the commit was made
+ self.committer_date = committer_date
+
+ # Record commit message and its encoding
+ self.encoding = encoding
+ self.message = message
+
+ # List of file-changes associated with this commit. Note that file-changes
+ # are also represented as git elements
+ self.file_changes = file_changes
+
+ self.parents = parents
+
+ def dump(self, file_):
+ """
+ Write this commit element to a file.
+ """
+ self.dumped = 1
+
+ # Make output to fast-import slightly easier for humans to read if the
+ # message has no trailing newline of its own; cosmetic, but a nice touch...
+ extra_newline = b'\n'
+ if self.message.endswith(b'\n') or not (self.parents or self.file_changes):
+ extra_newline = b''
+
+ if not self.parents:
+ file_.write(b'reset %s\n' % self.branch)
+ file_.write((b'commit %s\n'
+ b'mark :%d\n'
+ b'author %s <%s> %s\n'
+ b'committer %s <%s> %s\n'
+ ) % (
+ self.branch, self.id,
+ self.author_name, self.author_email, self.author_date,
+ self.committer_name, self.committer_email, self.committer_date
+ ))
+ if self.encoding:
+ file_.write(b'encoding %s\n' % self.encoding)
+ file_.write(b'data %d\n%s%s' %
+ (len(self.message), self.message, extra_newline))
+ for i, parent in enumerate(self.parents):
+ file_.write(b'from ' if i==0 else b'merge ')
+ if isinstance(parent, int):
+ file_.write(b':%d\n' % parent)
+ else:
+ file_.write(b'%s\n' % parent)
+ for change in self.file_changes:
+ change.dump(file_)
+ if not self.parents and not self.file_changes:
+ # Workaround a bug in pre-git-2.22 versions of fast-import with
+ # the get-mark directive.
+ file_.write(b'\n')
+ file_.write(b'\n')
+
+ def first_parent(self):
+ """
+ Return first parent commit
+ """
+ if self.parents:
+ return self.parents[0]
+ return None
+
+ def skip(self, new_id=None):
+ _SKIPPED_COMMITS.add(self.old_id or self.id)
+ _GitElementWithId.skip(self, new_id)
+
+class Tag(_GitElementWithId):
+ """
+ This class defines our representation of annotated tag elements.
+ """
+
+ def __init__(self, ref, from_ref,
+ tagger_name, tagger_email, tagger_date, tag_msg,
+ original_id = None):
+ _GitElementWithId.__init__(self)
+ self.old_id = self.id
+
+ # Denote that this is a tag element
+ self.type = 'tag'
+
+ # Store the name of the tag
+ self.ref = ref
+
+ # Store the entity being tagged (this should be a commit)
+ self.from_ref = from_ref
+
+ # Record original id
+ self.original_id = original_id
+
+ # Store the name of the tagger
+ self.tagger_name = tagger_name
+
+ # Store the email of the tagger
+ self.tagger_email = tagger_email
+
+ # Store the date
+ self.tagger_date = tagger_date
+
+ # Store the tag message
+ self.message = tag_msg
+
+ def dump(self, file_):
+ """
+ Write this tag element to a file
+ """
+
+ self.dumped = 1
+
+ file_.write(b'tag %s\n' % self.ref)
+ if (write_marks and self.id):
+ file_.write(b'mark :%d\n' % self.id)
+ markfmt = b'from :%d\n' if isinstance(self.from_ref, int) else b'from %s\n'
+ file_.write(markfmt % self.from_ref)
+ if self.tagger_name:
+ file_.write(b'tagger %s <%s> ' % (self.tagger_name, self.tagger_email))
+ file_.write(self.tagger_date)
+ file_.write(b'\n')
+ file_.write(b'data %d\n%s' % (len(self.message), self.message))
+ file_.write(b'\n')
+
+class Progress(_GitElement):
+ """
+ This class defines our representation of progress elements. The progress
+ element only contains a progress message, which is printed by fast-import
+ when it processes the progress output.
+ """
+
+ def __init__(self, message):
+ _GitElement.__init__(self)
+
+ # Denote that this is a progress element
+ self.type = 'progress'
+
+ # Store the progress message
+ self.message = message
+
+ def dump(self, file_):
+ """
+ Write this progress element to a file
+ """
+ self.dumped = 1
+
+ file_.write(b'progress %s\n' % self.message)
+ file_.write(b'\n')
+
+class Checkpoint(_GitElement):
+ """
+ This class defines our representation of checkpoint elements. These
+ elements represent events which force fast-import to close the current
+ packfile, start a new one, and to save out all current branch refs, tags
+ and marks.
+ """
+
+ def __init__(self):
+ _GitElement.__init__(self)
+
+ # Denote that this is a checkpoint element
+ self.type = 'checkpoint'
+
+ def dump(self, file_):
+ """
+ Write this checkpoint element to a file
+ """
+ self.dumped = 1
+
+ file_.write(b'checkpoint\n')
+ file_.write(b'\n')
+
+class LiteralCommand(_GitElement):
+ """
+ This class defines our representation of commands. The literal command
+ includes only a single line, and is not processed in any special way.
+ """
+
+ def __init__(self, line):
+ _GitElement.__init__(self)
+
+ # Denote that this is a literal element
+ self.type = 'literal'
+
+ # Store the command
+ self.line = line
+
+ def dump(self, file_):
+ """
+ Write this progress element to a file
+ """
+ self.dumped = 1
+
+ file_.write(self.line)
+
+class Alias(_GitElement):
+ """
+ This class defines our representation of fast-import alias elements. An
+ alias element is the setting of one mark to the same sha1sum as another,
+ usually because the newer mark corresponded to a pruned commit.
+ """
+
+ def __init__(self, ref, to_ref):
+ _GitElement.__init__(self)
+ # Denote that this is a reset
+ self.type = 'alias'
+
+ self.ref = ref
+ self.to_ref = to_ref
+
+ def dump(self, file_):
+ """
+ Write this reset element to a file
+ """
+ self.dumped = 1
+
+ file_.write(b'alias\nmark :%d\nto :%d\n\n' % (self.ref, self.to_ref))
+
+class FastExportParser(object):
+ """
+ A class for parsing and handling the output from fast-export. This
+ class allows the user to register callbacks when various types of
+ data are encountered in the fast-export output. The basic idea is that,
+ FastExportParser takes fast-export output, creates the various objects
+ as it encounters them, the user gets to use/modify these objects via
+ callbacks, and finally FastExportParser outputs the modified objects
+ in fast-import format (presumably so they can be used to create a new
+ repo).
+ """
+
+ def __init__(self,
+ tag_callback = None, commit_callback = None,
+ blob_callback = None, progress_callback = None,
+ reset_callback = None, checkpoint_callback = None,
+ done_callback = None):
+ # Members below simply store callback functions for the various git
+ # elements
+ self._tag_callback = tag_callback
+ self._blob_callback = blob_callback
+ self._reset_callback = reset_callback
+ self._commit_callback = commit_callback
+ self._progress_callback = progress_callback
+ self._checkpoint_callback = checkpoint_callback
+ self._done_callback = done_callback
+
+ # Keep track of which refs appear from the export, and which make it to
+ # the import (pruning of empty commits, renaming of refs, and creating
+ # new manual objects and inserting them can cause these to differ).
+ self._exported_refs = set()
+ self._imported_refs = set()
+
+ # A list of the branches we've seen, plus the last known commit they
+ # pointed to. An entry in latest_*commit will be deleted if we get a
+ # reset for that branch. These are used because of fast-import's weird
+ # decision to allow having an implicit parent via naming the branch
+ # instead of requiring branches to be specified via 'from' directives.
+ self._latest_commit = {}
+ self._latest_orig_commit = {}
+
+ # A handle to the input source for the fast-export data
+ self._input = None
+
+ # A handle to the output file for the output we generate (we call dump
+ # on many of the git elements we create).
+ self._output = None
+
+ # Stores the contents of the current line of input being parsed
+ self._currentline = ''
+
+ # Tracks LFS objects we have found
+ self._lfs_object_tracker = None
+
+ # Compile some regexes and cache those
+ self._mark_re = re.compile(br'mark :(\d+)\n$')
+ self._parent_regexes = {}
+ parent_regex_rules = (br' :(\d+)\n$', br' ([0-9a-f]{40})\n')
+ for parent_refname in (b'from', b'merge'):
+ ans = [re.compile(parent_refname+x) for x in parent_regex_rules]
+ self._parent_regexes[parent_refname] = ans
+ self._quoted_string_re = re.compile(br'"(?:[^"\\]|\\.)*"')
+ self._refline_regexes = {}
+ for refline_name in (b'reset', b'commit', b'tag', b'progress'):
+ self._refline_regexes[refline_name] = re.compile(refline_name+b' (.*)\n$')
+ self._user_regexes = {}
+ for user in (b'author', b'committer', b'tagger'):
+ self._user_regexes[user] = re.compile(user + b' (.*?) <(.*?)> (.*)\n$')
+
+ def _advance_currentline(self):
+ """
+ Grab the next line of input
+ """
+ self._currentline = self._input.readline()
+
+ def _parse_optional_mark(self):
+ """
+ If the current line contains a mark, parse it and advance to the
+ next line; return None otherwise
+ """
+ mark = None
+ matches = self._mark_re.match(self._currentline)
+ if matches:
+ mark = int(matches.group(1))
+ self._advance_currentline()
+ return mark
+
+ def _parse_optional_parent_ref(self, refname):
+ """
+ If the current line contains a reference to a parent commit, then
+ parse it and advance the current line; otherwise return None. Note
+ that the name of the reference ('from', 'merge') must match the
+ refname arg.
+ """
+ orig_baseref, baseref = None, None
+ rule, altrule = self._parent_regexes[refname]
+ matches = rule.match(self._currentline)
+ if matches:
+ orig_baseref = int(matches.group(1))
+ # We translate the parent commit mark to what it needs to be in
+ # our mark namespace
+ baseref = _IDS.translate(orig_baseref)
+ self._advance_currentline()
+ else:
+ matches = altrule.match(self._currentline)
+ if matches:
+ orig_baseref = matches.group(1)
+ baseref = orig_baseref
+ self._advance_currentline()
+ return orig_baseref, baseref
+
+ def _parse_optional_filechange(self):
+ """
+ If the current line contains a file-change object, then parse it
+ and advance the current line; otherwise return None. We only care
+ about file changes of type b'M' and b'D' (these are the only types
+ of file-changes that fast-export will provide).
+ """
+ filechange = None
+ changetype = self._currentline[0:1]
+ if changetype == b'M':
+ (changetype, mode, idnum, path) = self._currentline.split(None, 3)
+ if idnum[0:1] == b':':
+ idnum = idnum[1:]
+ path = path.rstrip(b'\n')
+ # Check for LFS objects from sources before we might toss this filechange
+ if mode != b'160000' and self._lfs_object_tracker:
+ value = int(idnum) if len(idnum) != 40 else idnum
+ self._lfs_object_tracker.check_file_change_data(value, True)
+ # We translate the idnum to our id system
+ if len(idnum) != 40:
+ idnum = _IDS.translate( int(idnum) )
+ if idnum is not None:
+ if path.startswith(b'"'):
+ path = PathQuoting.dequote(path)
+ filechange = FileChange(b'M', path, idnum, mode)
+ else:
+ filechange = b'skipped'
+ self._advance_currentline()
+ elif changetype == b'D':
+ (changetype, path) = self._currentline.split(None, 1)
+ path = path.rstrip(b'\n')
+ if path.startswith(b'"'):
+ path = PathQuoting.dequote(path)
+ filechange = FileChange(b'D', path)
+ self._advance_currentline()
+ elif changetype == b'R': # pragma: no cover (now avoid fast-export renames)
+ rest = self._currentline[2:-1]
+ if rest.startswith(b'"'):
+ m = self._quoted_string_re.match(rest)
+ if not m:
+ raise SystemExit(_("Couldn't parse rename source"))
+ orig = PathQuoting.dequote(m.group(0))
+ new = rest[m.end()+1:]
+ else:
+ orig, new = rest.split(b' ', 1)
+ if new.startswith(b'"'):
+ new = PathQuoting.dequote(new)
+ filechange = FileChange(b'R', orig, new)
+ self._advance_currentline()
+ return filechange
+
+ def _parse_original_id(self):
+ original_id = self._currentline[len(b'original-oid '):].rstrip()
+ self._advance_currentline()
+ return original_id
+
+ def _parse_encoding(self):
+ encoding = self._currentline[len(b'encoding '):].rstrip()
+ self._advance_currentline()
+ return encoding
+
+ def _parse_ref_line(self, refname):
+ """
+ Parses string data (often a branch name) from current-line. The name of
+ the string data must match the refname arg. The program will crash if
+ current-line does not match, so current-line will always be advanced if
+ this method returns.
+ """
+ matches = self._refline_regexes[refname].match(self._currentline)
+ if not matches:
+ raise SystemExit(_("Malformed %(refname)s line: '%(line)s'") %
+ ({'refname': refname, 'line':self._currentline})
+ ) # pragma: no cover
+ ref = matches.group(1)
+ self._advance_currentline()
+ return ref
+
+ def _parse_user(self, usertype):
+ """
+ Get user name, email, datestamp from current-line. Current-line will
+ be advanced.
+ """
+ user_regex = self._user_regexes[usertype]
+ (name, email, when) = user_regex.match(self._currentline).groups()
+
+ self._advance_currentline()
+ return (name, email, when)
+
+ def _parse_data(self):
+ """
+ Reads data from _input. Current-line will be advanced until it is beyond
+ the data.
+ """
+ fields = self._currentline.split()
+ assert fields[0] == b'data'
+ size = int(fields[1])
+ data = self._input.read(size)
+ self._advance_currentline()
+ if self._currentline == b'\n':
+ self._advance_currentline()
+ return data
+
+ def _parse_blob(self):
+ """
+ Parse input data into a Blob object. Once the Blob has been created, it
+ will be handed off to the appropriate callbacks. Current-line will be
+ advanced until it is beyond this blob's data. The Blob will be dumped
+ to _output once everything else is done (unless it has been skipped by
+ the callback).
+ """
+ # Parse the Blob
+ self._advance_currentline()
+ id_ = self._parse_optional_mark()
+
+ original_id = None
+ if self._currentline.startswith(b'original-oid'):
+ original_id = self._parse_original_id();
+
+ data = self._parse_data()
+ if self._currentline == b'\n':
+ self._advance_currentline()
+
+ # Create the blob
+ blob = Blob(data, original_id)
+
+ # If fast-export text had a mark for this blob, need to make sure this
+ # mark translates to the blob's true id.
+ if id_:
+ blob.old_id = id_
+ _IDS.record_rename(id_, blob.id)
+
+ # Check for LFS objects
+ if self._lfs_object_tracker:
+ self._lfs_object_tracker.check_blob_data(data, blob.old_id, True)
+
+ # Call any user callback to allow them to use/modify the blob
+ if self._blob_callback:
+ self._blob_callback(blob)
+
+ # Now print the resulting blob
+ if not blob.dumped:
+ blob.dump(self._output)
+
+ def _parse_reset(self):
+ """
+ Parse input data into a Reset object. Once the Reset has been created,
+ it will be handed off to the appropriate callbacks. Current-line will
+ be advanced until it is beyond the reset data. The Reset will be dumped
+ to _output once everything else is done (unless it has been skipped by
+ the callback).
+ """
+ # Parse the Reset
+ ref = self._parse_ref_line(b'reset')
+ self._exported_refs.add(ref)
+ ignoreme, from_ref = self._parse_optional_parent_ref(b'from')
+ if self._currentline == b'\n':
+ self._advance_currentline()
+
+ # fast-export likes to print extraneous resets that serve no purpose.
+ # While we could continue processing such resets, that is a waste of
+ # resources. Also, we want to avoid recording that this ref was
+ # seen in such cases, since this ref could be rewritten to nothing.
+ if not from_ref:
+ self._latest_commit.pop(ref, None)
+ self._latest_orig_commit.pop(ref, None)
+ return
+
+ # Create the reset
+ reset = Reset(ref, from_ref)
+
+ # Call any user callback to allow them to modify the reset
+ if self._reset_callback:
+ self._reset_callback(reset)
+
+ # Update metadata
+ self._latest_commit[reset.ref] = reset.from_ref
+ self._latest_orig_commit[reset.ref] = reset.from_ref
+
+ # Now print the resulting reset
+ if not reset.dumped:
+ self._imported_refs.add(reset.ref)
+ reset.dump(self._output)
+
+ def _parse_commit(self):
+ """
+ Parse input data into a Commit object. Once the Commit has been created,
+ it will be handed off to the appropriate callbacks. Current-line will
+ be advanced until it is beyond the commit data. The Commit will be dumped
+ to _output once everything else is done (unless it has been skipped by
+ the callback OR the callback has removed all file-changes from the commit).
+ """
+ # Parse the Commit. This may look involved, but it's pretty simple; it only
+ # looks bad because a commit object contains many pieces of data.
+ branch = self._parse_ref_line(b'commit')
+ self._exported_refs.add(branch)
+ id_ = self._parse_optional_mark()
+
+ original_id = None
+ if self._currentline.startswith(b'original-oid'):
+ original_id = self._parse_original_id();
+
+ author_name = None
+ author_email = None
+ if self._currentline.startswith(b'author'):
+ (author_name, author_email, author_date) = self._parse_user(b'author')
+
+ (committer_name, committer_email, committer_date) = \
+ self._parse_user(b'committer')
+
+ if not author_name and not author_email:
+ (author_name, author_email, author_date) = \
+ (committer_name, committer_email, committer_date)
+
+ encoding = None
+ if self._currentline.startswith(b'encoding '):
+ encoding = self._parse_encoding()
+
+ commit_msg = self._parse_data()
+
+ pinfo = [self._parse_optional_parent_ref(b'from')]
+ # Due to empty pruning, we can have real 'from' and 'merge' lines that
+ # due to commit rewriting map to a parent of None. We need to record
+ # 'from' if its non-None, and we need to parse all 'merge' lines.
+ while self._currentline.startswith(b'merge '):
+ pinfo.append(self._parse_optional_parent_ref(b'merge'))
+ orig_parents, parents = [list(tmp) for tmp in zip(*pinfo)]
+
+ # No parents is oddly represented as [None] instead of [], due to the
+ # special 'from' handling. Convert it here to a more canonical form.
+ if parents == [None]:
+ parents = []
+ if orig_parents == [None]:
+ orig_parents = []
+
+ # fast-import format is kinda stupid in that it allows implicit parents
+ # based on the branch name instead of requiring them to be specified by
+ # 'from' directives. The only way to get no parent is by using a reset
+ # directive first, which clears the latest_commit_for_this_branch tracking.
+ if not orig_parents and self._latest_commit.get(branch):
+ parents = [self._latest_commit[branch]]
+ if not orig_parents and self._latest_orig_commit.get(branch):
+ orig_parents = [self._latest_orig_commit[branch]]
+
+ # Get the list of file changes
+ file_changes = []
+ file_change = self._parse_optional_filechange()
+ had_file_changes = file_change is not None
+ while file_change:
+ if not (type(file_change) == bytes and file_change == b'skipped'):
+ file_changes.append(file_change)
+ file_change = self._parse_optional_filechange()
+ if self._currentline == b'\n':
+ self._advance_currentline()
+
+ # Okay, now we can finally create the Commit object
+ commit = Commit(branch,
+ author_name, author_email, author_date,
+ committer_name, committer_email, committer_date,
+ commit_msg, file_changes, parents, original_id, encoding)
+
+ # If fast-export text had a mark for this commit, need to make sure this
+ # mark translates to the commit's true id.
+ if id_:
+ commit.old_id = id_
+ _IDS.record_rename(id_, commit.id)
+
+ # refs/notes/ put commit-message-related material in blobs, and name their
+ # files according to the hash of other commits. That totally messes with
+ # all normal callbacks; fast-export should really export these as different
+ # kinds of objects. Until then, let's just pass these commits through as-is
+ # and hope the blob callbacks don't mess things up.
+ if commit.branch.startswith(b'refs/notes/'):
+ self._imported_refs.add(commit.branch)
+ commit.dump(self._output)
+ return
+
+ # Call any user callback to allow them to modify the commit
+ aux_info = {'orig_parents': orig_parents,
+ 'had_file_changes': had_file_changes}
+ if self._commit_callback:
+ self._commit_callback(commit, aux_info)
+
+ # Now print the resulting commit, or if prunable skip it
+ self._latest_orig_commit[branch] = commit.id
+ if not (commit.old_id or commit.id) in _SKIPPED_COMMITS:
+ self._latest_commit[branch] = commit.id
+ if not commit.dumped:
+ self._imported_refs.add(commit.branch)
+ commit.dump(self._output)
+
+ def _parse_tag(self):
+ """
+ Parse input data into a Tag object. Once the Tag has been created,
+ it will be handed off to the appropriate callbacks. Current-line will
+ be advanced until it is beyond the tag data. The Tag will be dumped
+ to _output once everything else is done (unless it has been skipped by
+ the callback).
+ """
+ # Parse the Tag
+ tag = self._parse_ref_line(b'tag')
+ self._exported_refs.add(b'refs/tags/'+tag)
+ id_ = self._parse_optional_mark()
+ ignoreme, from_ref = self._parse_optional_parent_ref(b'from')
+
+ original_id = None
+ if self._currentline.startswith(b'original-oid'):
+ original_id = self._parse_original_id();
+
+ tagger_name, tagger_email, tagger_date = None, None, None
+ if self._currentline.startswith(b'tagger'):
+ (tagger_name, tagger_email, tagger_date) = self._parse_user(b'tagger')
+ tag_msg = self._parse_data()
+ if self._currentline == b'\n':
+ self._advance_currentline()
+
+ # Create the tag
+ tag = Tag(tag, from_ref,
+ tagger_name, tagger_email, tagger_date, tag_msg,
+ original_id)
+
+ # If fast-export text had a mark for this tag, need to make sure this
+ # mark translates to the tag's true id.
+ if id_:
+ tag.old_id = id_
+ _IDS.record_rename(id_, tag.id)
+
+ # Call any user callback to allow them to modify the tag
+ if self._tag_callback:
+ self._tag_callback(tag)
+
+ # The tag might not point at anything that still exists (self.from_ref
+ # will be None if the commit it pointed to and all its ancestors were
+ # pruned due to being empty)
+ if tag.from_ref:
+ # Print out this tag's information
+ if not tag.dumped:
+ self._imported_refs.add(b'refs/tags/'+tag.ref)
+ tag.dump(self._output)
+ else:
+ tag.skip()
+
+ def _parse_progress(self):
+ """
+ Parse input data into a Progress object. Once the Progress has
+ been created, it will be handed off to the appropriate
+ callbacks. Current-line will be advanced until it is beyond the
+ progress data. The Progress will be dumped to _output once
+ everything else is done (unless it has been skipped by the callback).
+ """
+ # Parse the Progress
+ message = self._parse_ref_line(b'progress')
+ if self._currentline == b'\n':
+ self._advance_currentline()
+
+ # Create the progress message
+ progress = Progress(message)
+
+ # Call any user callback to allow them to modify the progress messsage
+ if self._progress_callback:
+ self._progress_callback(progress)
+
+ # NOTE: By default, we do NOT print the progress message; git
+ # fast-import would write it to fast_import_pipes which could mess with
+ # our parsing of output from the 'ls' and 'get-mark' directives we send
+ # to fast-import. If users want these messages, they need to process
+ # and handle them in the appropriate callback above.
+
+ def _parse_checkpoint(self):
+ """
+ Parse input data into a Checkpoint object. Once the Checkpoint has
+ been created, it will be handed off to the appropriate
+ callbacks. Current-line will be advanced until it is beyond the
+ checkpoint data. The Checkpoint will be dumped to _output once
+ everything else is done (unless it has been skipped by the callback).
+ """
+ # Parse the Checkpoint
+ self._advance_currentline()
+ if self._currentline == b'\n':
+ self._advance_currentline()
+
+ # Create the checkpoint
+ checkpoint = Checkpoint()
+
+ # Call any user callback to allow them to drop the checkpoint
+ if self._checkpoint_callback:
+ self._checkpoint_callback(checkpoint)
+
+ # NOTE: By default, we do NOT print the checkpoint message; although it
+ # we would only realistically get them with --stdin, the fact that we
+ # are filtering makes me think the checkpointing is less likely to be
+ # reasonable. In fact, I don't think it's necessary in general. If
+ # users do want it, they should process it in the checkpoint_callback.
+
+ def _parse_literal_command(self):
+ """
+ Parse literal command. Then just dump the line as is.
+ """
+ # Create the literal command object
+ command = LiteralCommand(self._currentline)
+ self._advance_currentline()
+
+ # Now print the resulting literal command
+ if not command.dumped:
+ command.dump(self._output)
+
+ def insert(self, obj):
+ assert not obj.dumped
+ obj.dump(self._output)
+ if type(obj) == Commit:
+ self._imported_refs.add(obj.branch)
+ elif type(obj) in (Reset, Tag):
+ self._imported_refs.add(obj.ref)
+
+ def run(self, input, output):
+ """
+ This method filters fast export output.
+ """
+ # Set input. If no args provided, use stdin.
+ self._input = input
+ self._output = output
+
+ # Run over the input and do the filtering
+ self._advance_currentline()
+ while self._currentline:
+ if self._currentline.startswith(b'blob'):
+ self._parse_blob()
+ elif self._currentline.startswith(b'reset'):
+ self._parse_reset()
+ elif self._currentline.startswith(b'commit'):
+ self._parse_commit()
+ elif self._currentline.startswith(b'tag'):
+ self._parse_tag()
+ elif self._currentline.startswith(b'progress'):
+ self._parse_progress()
+ elif self._currentline.startswith(b'checkpoint'):
+ self._parse_checkpoint()
+ elif self._currentline.startswith(b'feature'):
+ self._parse_literal_command()
+ elif self._currentline.startswith(b'option'):
+ self._parse_literal_command()
+ elif self._currentline.startswith(b'done'):
+ if self._done_callback:
+ self._done_callback()
+ self._parse_literal_command()
+ # Prevent confusion from others writing additional stuff that'll just
+ # be ignored
+ self._output.close()
+ elif self._currentline.startswith(b'#'):
+ self._parse_literal_command()
+ elif self._currentline.startswith(b'get-mark') or \
+ self._currentline.startswith(b'cat-blob') or \
+ self._currentline.startswith(b'ls'):
+ raise SystemExit(_("Unsupported command: '%s'") % self._currentline)
+ else:
+ raise SystemExit(_("Could not parse line: '%s'") % self._currentline)
+
+ def get_exported_and_imported_refs(self):
+ return self._exported_refs, self._imported_refs
+
+def record_id_rename(old_id, new_id):
+ """
+ Register a new translation
+ """
+ handle_transitivity = True
+ _IDS.record_rename(old_id, new_id, handle_transitivity)
+
+# Internal globals
+_IDS = _IDs()
+_SKIPPED_COMMITS = set()
+BLOB_HASH_TO_NEW_ID = {}
+BLOB_NEW_ID_TO_HASH = {}
+sdr_next_steps = _("""
+NEXT STEPS FOR YOUR SENSITIVE DATA REMOVAL:
+ * If you are doing your rewrite in multiple steps, ignore these next steps
+ until you have completed all your invocations of git-filter-repo.
+ * See the "Sensitive Data Removal" subsection of the "DISCUSSION" section
+ of the manual for more details about any of the steps below.
+ * Inspect this repository and verify that the sensitive data is indeed
+ completely removed from all commits.
+ * Force push the rewritten history to the server:
+ %s
+ * Contact the server admins for additional steps they need to take; the
+ First Changed Commit(s)%s may come in handy here.
+ * Have other colleagues with a clone either discard their clone and reclone
+ OR follow the detailed steps in the manual to repeatedly rebase and
+ purge the sensitive data from their copy. Again, the First Changed
+ Commit(s)%s may come in handy.
+ * See the "Prevent repeats and avoid future sensitive data spills" section
+ of the manual.
+"""[1:])
+
+class SubprocessWrapper(object):
+ @staticmethod
+ def decodify(args):
+ if type(args) == str:
+ return args
+ else:
+ assert type(args) == list
+ return [decode(x) if type(x)==bytes else x for x in args]
+
+ @staticmethod
+ def call(*args, **kwargs):
+ if 'cwd' in kwargs:
+ kwargs['cwd'] = decode(kwargs['cwd'])
+ return subprocess.call(SubprocessWrapper.decodify(*args), **kwargs)
+
+ @staticmethod
+ def check_output(*args, **kwargs):
+ if 'cwd' in kwargs:
+ kwargs['cwd'] = decode(kwargs['cwd'])
+ return subprocess.check_output(SubprocessWrapper.decodify(*args), **kwargs)
+
+ @staticmethod
+ def check_call(*args, **kwargs): # pragma: no cover # used by filter-lamely
+ if 'cwd' in kwargs:
+ kwargs['cwd'] = decode(kwargs['cwd'])
+ return subprocess.check_call(SubprocessWrapper.decodify(*args), **kwargs)
+
+ @staticmethod
+ def Popen(*args, **kwargs):
+ if 'cwd' in kwargs:
+ kwargs['cwd'] = decode(kwargs['cwd'])
+ return subprocess.Popen(SubprocessWrapper.decodify(*args), **kwargs)
+
+subproc = subprocess
+if platform.system() == 'Windows' or 'PRETEND_UNICODE_ARGS' in os.environ:
+ subproc = SubprocessWrapper
+
+class GitUtils(object):
+ @staticmethod
+ def get_commit_count(repo, *args):
+ """
+ Return the number of commits that have been made on repo.
+ """
+ if not args:
+ args = ['--all']
+ if len(args) == 1 and isinstance(args[0], list):
+ args = args[0]
+ p = subproc.Popen(["git", "rev-list", "--count"] + args,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ cwd=repo)
+ if p.wait() != 0:
+ raise SystemExit(_("%s does not appear to be a valid git repository")
+ % decode(repo))
+ return int(p.stdout.read())
+
+ @staticmethod
+ def get_total_objects(repo):
+ """
+ Return the number of objects (both packed and unpacked)
+ """
+ p1 = subproc.Popen(["git", "count-objects", "-v"],
+ stdout=subprocess.PIPE, cwd=repo)
+ lines = p1.stdout.read().splitlines()
+ # Return unpacked objects + packed-objects
+ return int(lines[0].split()[1]) + int(lines[2].split()[1])
+
+ @staticmethod
+ def is_repository_bare(repo_working_dir):
+ out = subproc.check_output('git rev-parse --is-bare-repository'.split(),
+ cwd=repo_working_dir)
+ return (out.strip() == b'true')
+
+ @staticmethod
+ def determine_git_dir(repo_working_dir):
+ d = subproc.check_output('git rev-parse --git-dir'.split(),
+ cwd=repo_working_dir).strip()
+ if repo_working_dir==b'.' or d.startswith(b'/'):
+ return d
+ return os.path.join(repo_working_dir, d)
+
+ @staticmethod
+ def get_refs(repo_working_dir):
+ try:
+ output = subproc.check_output('git show-ref'.split(),
+ cwd=repo_working_dir)
+ except subprocess.CalledProcessError as e:
+ # If error code is 1, there just aren't any refs; i.e. new repo.
+ # If error code is other than 1, some other error (e.g. not a git repo)
+ if e.returncode != 1:
+ raise SystemExit('fatal: {}'.format(e))
+ output = ''
+ return dict(reversed(x.split()) for x in output.splitlines())
+
+ @staticmethod
+ def get_config_settings(repo_working_dir):
+ output = ''
+ try:
+ output = subproc.check_output('git config --list --null'.split(),
+ cwd=repo_working_dir)
+ except subprocess.CalledProcessError as e: # pragma: no cover
+ raise SystemExit('fatal: {}'.format(e))
+
+ # FIXME: Ignores multi-valued keys, just let them overwrite for now
+ return dict(item.split(b'\n', maxsplit=1)
+ for item in output.strip().split(b"\0") if item)
+
+ @staticmethod
+ def get_blob_sizes(quiet = False):
+ blob_size_progress = ProgressWriter()
+ num_blobs = 0
+ processed_blobs_msg = _("Processed %d blob sizes")
+
+ # Get sizes of blobs by sha1
+ cmd = '--batch-check=%(objectname) %(objecttype) ' + \
+ '%(objectsize) %(objectsize:disk)'
+ cf = subproc.Popen(['git', 'cat-file', '--batch-all-objects', cmd],
+ bufsize = -1,
+ stdout = subprocess.PIPE)
+ unpacked_size = {}
+ packed_size = {}
+ for line in cf.stdout:
+ try:
+ sha, objtype, objsize, objdisksize = line.split()
+ objsize, objdisksize = int(objsize), int(objdisksize)
+ if objtype == b'blob':
+ unpacked_size[sha] = objsize
+ packed_size[sha] = objdisksize
+ num_blobs += 1
+ except ValueError: # pragma: no cover
+ sys.stderr.write(_("Error: unexpected `git cat-file` output: \"%s\"\n") % line)
+ if not quiet:
+ blob_size_progress.show(processed_blobs_msg % num_blobs)
+ cf.wait()
+ if not quiet:
+ blob_size_progress.finish()
+ return unpacked_size, packed_size
+
+ @staticmethod
+ def get_file_changes(repo, parent_hash, commit_hash):
+ """
+ Return a FileChanges list with the differences between parent_hash
+ and commit_hash
+ """
+ file_changes = []
+
+ cmd = ["git", "diff-tree", "-r", parent_hash, commit_hash]
+ output = subproc.check_output(cmd, cwd=repo)
+ for line in output.splitlines():
+ fileinfo, path = line.split(b'\t', 1)
+ if path.startswith(b'"'):
+ path = PathQuoting.dequote(path)
+ oldmode, mode, oldhash, newhash, changetype = fileinfo.split()
+ if changetype == b'D':
+ file_changes.append(FileChange(b'D', path))
+ elif changetype in (b'A', b'M', b'T'):
+ identifier = BLOB_HASH_TO_NEW_ID.get(newhash, newhash)
+ file_changes.append(FileChange(b'M', path, identifier, mode))
+ else: # pragma: no cover
+ raise SystemExit("Unknown change type for line {}".format(line))
+
+ return file_changes
+
+ @staticmethod
+ def print_my_version():
+ with open(__file__, 'br') as f:
+ contents = f.read()
+ # If people replaced @@LOCALEDIR@@ string to point at their local
+ # directory, undo it so we can get original source version.
+ contents = re.sub(br'\A#\!.*',
+ br'#!/usr/bin/env python3', contents)
+ contents = re.sub(br'(\("GIT_TEXTDOMAINDIR"\) or ").*"',
+ br'\1@@LOCALEDIR@@"', contents)
+
+ cmd = 'git hash-object --stdin'.split()
+ version = subproc.check_output(cmd, input=contents).strip()
+ print(decode(version[0:12]))
+
+class FilteringOptions(object):
+ default_replace_text = b'***REMOVED***'
+ class AppendFilter(argparse.Action):
+ def __call__(self, parser, namespace, values, option_string=None):
+ user_path = values
+ suffix = option_string[len('--path-'):] or 'match'
+ if suffix.startswith('rename'):
+ mod_type = 'rename'
+ match_type = option_string[len('--path-rename-'):] or 'match'
+ values = values.split(b':')
+ if len(values) != 2:
+ raise SystemExit(_("Error: --path-rename expects one colon in its"
+ " argument: ."))
+ if values[0] and values[1] and not (
+ values[0].endswith(b'/') == values[1].endswith(b'/')):
+ raise SystemExit(_("Error: With --path-rename, if OLD_NAME and "
+ "NEW_NAME are both non-empty and either ends "
+ "with a slash then both must."))
+ if any(v.startswith(b'/') for v in values):
+ raise SystemExit(_("Error: Pathnames cannot begin with a '/'"))
+ components = values[0].split(b'/') + values[1].split(b'/')
+ else:
+ mod_type = 'filter'
+ match_type = suffix
+ components = values.split(b'/')
+ if values.startswith(b'/'):
+ raise SystemExit(_("Error: Pathnames cannot begin with a '/'"))
+ for illegal_path in [b'.', b'..']:
+ if illegal_path in components:
+ raise SystemExit(_("Error: Invalid path component '%s' found in '%s'")
+ % (decode(illegal_path), decode(user_path)))
+ if match_type == 'regex':
+ values = re.compile(values)
+ items = getattr(namespace, self.dest, []) or []
+ items.append((mod_type, match_type, values))
+ if (match_type, mod_type) == ('glob', 'filter'):
+ if not values.endswith(b'*'):
+ extension = b'*' if values.endswith(b'/') else b'/*'
+ items.append((mod_type, match_type, values+extension))
+ setattr(namespace, self.dest, items)
+
+ class HelperFilter(argparse.Action):
+ def __call__(self, parser, namespace, values, option_string=None):
+ af = FilteringOptions.AppendFilter(dest='path_changes',
+ option_strings=None)
+ dirname = values if values[-1:] == b'/' else values+b'/'
+ if option_string == '--subdirectory-filter':
+ af(parser, namespace, dirname, '--path-match')
+ af(parser, namespace, dirname+b':', '--path-rename')
+ elif option_string == '--to-subdirectory-filter':
+ af(parser, namespace, b':'+dirname, '--path-rename')
+ else:
+ raise SystemExit(_("Error: HelperFilter given invalid option_string: %s")
+ % option_string) # pragma: no cover
+
+ class FileWithPathsFilter(argparse.Action):
+ def __call__(self, parser, namespace, values, option_string=None):
+ if not namespace.path_changes:
+ namespace.path_changes = []
+ namespace.path_changes += FilteringOptions.get_paths_from_file(values)
+
+ @staticmethod
+ def create_arg_parser():
+ # Include usage in the summary, so we can put the description first
+ summary = _('''Rewrite (or analyze) repository history
+
+ git-filter-repo destructively rewrites history (unless --analyze or
+ --dry-run are given) according to specified rules. It refuses to do any
+ rewriting unless either run from a clean fresh clone, or --force was
+ given.
+
+ Basic Usage:
+ git-filter-repo --analyze
+ git-filter-repo [FILTER/RENAME/CONTROL OPTIONS]
+
+ See EXAMPLES section for details.
+ ''').rstrip()
+
+ # Provide a long helpful examples section
+ example_text = _('''CALLBACKS
+
+ Most callback functions are of the same general format. For a command line
+ argument like
+ --foo-callback 'BODY'
+
+ the following code will be compiled and called:
+ def foo_callback(foo):
+ BODY
+
+ The exception on callbacks is the --file-info-callback, which will be
+ discussed further below.
+
+ Given the callback style, we can thus make a simple callback to replace
+ 'Jon' with 'John' in author/committer/tagger names:
+ git filter-repo --name-callback 'return name.replace(b"Jon", b"John")'
+
+ To remove all 'Tested-by' tags in commit (or tag) messages:
+ git filter-repo --message-callback 'return re.sub(br"\\nTested-by:.*", "", message)'
+
+ To remove all .DS_Store files:
+ git filter-repo --filename-callback 'return None if os.path.basename(filename) == b".DS_Store" else filename'
+
+ Note that if BODY resolves to a filename, then the contents of that file
+ will be used as the BODY in the callback function.
+
+ The --file-info-callback has a more involved function callback; for it the
+ following code will be compiled and called:
+ def file_info_callback(filename, mode, blob_id, value):
+ BODY
+
+ It is designed to be used in cases where filtering depends on both
+ filename and contents (and maybe mode). It is called for file changes
+ other than deletions (since deletions have no file contents to operate
+ on). This callback is expected to return a tuple of (filename, mode,
+ blob_id). It can make use of the following functions from the value
+ instance:
+ value.get_contents_by_identifier(blob_id) -> contents (bytestring)
+ value.get_size_by_identifier(blob_id) -> size_of_blob (int)
+ value.insert_file_with_contents(contents) -> blob_id
+ value.is_binary(contents) -> bool
+ value.apply_replace_text(contents) -> new_contents (bytestring)
+ and can read/write the following data member from the value instance:
+ value.data (dict)
+
+ The filename can be used for renaming the file similar to
+ --filename-callback (or None to drop the change), and mode is one
+ of b'100644', b'100755', b'120000', or b'160000'.
+
+ For more detailed examples and explanations AND caveats, see
+ https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html#CALLBACKS
+
+EXAMPLES
+
+ To get a bunch of reports mentioning renames that have occurred in
+ your repo and listing sizes of objects aggregated by any of path,
+ directory, extension, or blob-id:
+ git filter-repo --analyze
+
+ (These reports can help you choose how to filter your repo; it can
+ be useful to re-run this command after filtering to regenerate the
+ report and verify the changes look correct.)
+
+ To extract the history that touched just 'guides' and 'tools/releases':
+ git filter-repo --path guides/ --path tools/releases
+
+ To remove foo.zip and bar/baz/zips from every revision in history:
+ git filter-repo --path foo.zip --path bar/baz/zips/ --invert-paths
+
+ To replace the text 'password' with 'p455w0rd':
+ git filter-repo --replace-text <(echo "password==>p455w0rd")
+
+ To use the current version of the .mailmap file to update authors,
+ committers, and taggers throughout history and make it permanent:
+ git filter-repo --use-mailmap
+
+ To extract the history of 'src/', rename all files to have a new leading
+ directory 'my-module' (e.g. src/foo.java -> my-module/src/foo.java), and
+ add a 'my-module-' prefix to all tags:
+ git filter-repo --path src/ --to-subdirectory-filter my-module --tag-rename '':'my-module-'
+
+ For more detailed examples and explanations, see
+ https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html#EXAMPLES''')
+
+ # Create the basic parser
+ parser = argparse.ArgumentParser(description=summary,
+ usage = argparse.SUPPRESS,
+ add_help = False,
+ epilog = example_text,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+
+ analyze = parser.add_argument_group(title=_("Analysis"))
+ analyze.add_argument('--analyze', action='store_true',
+ help=_("Analyze repository history and create a report that may be "
+ "useful in determining what to filter in a subsequent run. "
+ "Will not modify your repo."))
+ analyze.add_argument('--report-dir',
+ metavar='DIR_OR_FILE',
+ type=os.fsencode,
+ dest='report_dir',
+ help=_("Directory to write report, defaults to GIT_DIR/filter_repo/analysis,"
+ "refuses to run if exists, --force delete existing dir first."))
+
+ path = parser.add_argument_group(title=_("Filtering based on paths "
+ "(see also --filename-callback)"),
+ description=textwrap.dedent(_("""
+ These options specify the paths to select. Note that much like git
+ itself, renames are NOT followed so you may need to specify multiple
+ paths, e.g. `--path olddir/ --path newdir/`
+ """[1:])))
+
+ path.add_argument('--invert-paths', action='store_false', dest='inclusive',
+ help=_("Invert the selection of files from the specified "
+ "--path-{match,glob,regex} options below, i.e. only select "
+ "files matching none of those options."))
+
+ path.add_argument('--path-match', '--path', metavar='DIR_OR_FILE',
+ type=os.fsencode,
+ action=FilteringOptions.AppendFilter, dest='path_changes',
+ help=_("Exact paths (files or directories) to include in filtered "
+ "history. Multiple --path options can be specified to get "
+ "a union of paths."))
+ path.add_argument('--path-glob', metavar='GLOB', type=os.fsencode,
+ action=FilteringOptions.AppendFilter, dest='path_changes',
+ help=_("Glob of paths to include in filtered history. Multiple "
+ "--path-glob options can be specified to get a union of "
+ "paths."))
+ path.add_argument('--path-regex', metavar='REGEX', type=os.fsencode,
+ action=FilteringOptions.AppendFilter, dest='path_changes',
+ help=_("Regex of paths to include in filtered history. Multiple "
+ "--path-regex options can be specified to get a union of "
+ "paths"))
+ path.add_argument('--use-base-name', action='store_true',
+ help=_("Match on file base name instead of full path from the top "
+ "of the repo. Incompatible with --path-rename, and "
+ "incompatible with matching against directory names."))
+
+ rename = parser.add_argument_group(title=_("Renaming based on paths "
+ "(see also --filename-callback)"))
+ rename.add_argument('--path-rename', '--path-rename-match',
+ metavar='OLD_NAME:NEW_NAME', dest='path_changes', type=os.fsencode,
+ action=FilteringOptions.AppendFilter,
+ help=_("Path to rename; if filename or directory matches OLD_NAME "
+ "rename to NEW_NAME. Multiple --path-rename options can be "
+ "specified. NOTE: If you combine filtering options with "
+ "renaming ones, do not rely on a rename argument to select "
+ "paths; you also need a filter to select them."))
+
+ helpers = parser.add_argument_group(title=_("Path shortcuts"))
+ helpers.add_argument('--paths', help=argparse.SUPPRESS, metavar='IGNORE')
+ helpers.add_argument('--paths-from-file', metavar='FILENAME',
+ type=os.fsencode,
+ action=FilteringOptions.FileWithPathsFilter, dest='path_changes',
+ help=_("Specify several path filtering and renaming directives, one "
+ "per line. Lines with '==>' in them specify path renames, "
+ "and lines can begin with 'literal:' (the default), 'glob:', "
+ "or 'regex:' to specify different matching styles. Blank "
+ "lines and lines starting with a '#' are ignored."))
+ helpers.add_argument('--subdirectory-filter', metavar='DIRECTORY',
+ action=FilteringOptions.HelperFilter, type=os.fsencode,
+ help=_("Only look at history that touches the given subdirectory "
+ "and treat that directory as the project root. Equivalent "
+ "to using '--path DIRECTORY/ --path-rename DIRECTORY/:'"))
+ helpers.add_argument('--to-subdirectory-filter', metavar='DIRECTORY',
+ action=FilteringOptions.HelperFilter, type=os.fsencode,
+ help=_("Treat the project root as if it were under DIRECTORY. "
+ "Equivalent to using '--path-rename :DIRECTORY/'"))
+
+ contents = parser.add_argument_group(title=_("Content editing filters "
+ "(see also --blob-callback)"))
+ contents.add_argument('--replace-text', metavar='EXPRESSIONS_FILE',
+ help=_("A file with expressions that, if found, will be replaced. "
+ "By default, each expression is treated as literal text, "
+ "but 'regex:' and 'glob:' prefixes are supported. You can "
+ "end the line with '==>' and some replacement text to "
+ "choose a replacement choice other than the default of '{}'."
+ .format(decode(FilteringOptions.default_replace_text))))
+ contents.add_argument('--strip-blobs-bigger-than', metavar='SIZE',
+ dest='max_blob_size', default=0,
+ help=_("Strip blobs (files) bigger than specified size (e.g. '5M', "
+ "'2G', etc)"))
+ contents.add_argument('--strip-blobs-with-ids', metavar='BLOB-ID-FILENAME',
+ help=_("Read git object ids from each line of the given file, and "
+ "strip all of them from history"))
+
+ refrename = parser.add_argument_group(title=_("Renaming of refs "
+ "(see also --refname-callback)"))
+ refrename.add_argument('--tag-rename', metavar='OLD:NEW', type=os.fsencode,
+ help=_("Rename tags starting with OLD to start with NEW. For "
+ "example, --tag-rename foo:bar will rename tag foo-1.2.3 "
+ "to bar-1.2.3; either OLD or NEW can be empty."))
+
+ messages = parser.add_argument_group(title=_("Filtering of commit messages "
+ "(see also --message-callback)"))
+ messages.add_argument('--replace-message', metavar='EXPRESSIONS_FILE',
+ help=_("A file with expressions that, if found in commit or tag "
+ "messages, will be replaced. This file uses the same syntax "
+ "as --replace-text."))
+ messages.add_argument('--preserve-commit-hashes', action='store_true',
+ help=_("By default, since commits are rewritten and thus gain new "
+ "hashes, references to old commit hashes in commit messages "
+ "are replaced with new commit hashes (abbreviated to the same "
+ "length as the old reference). Use this flag to turn off "
+ "updating commit hashes in commit messages."))
+ messages.add_argument('--preserve-commit-encoding', action='store_true',
+ help=_("Do not reencode commit messages into UTF-8. By default, if "
+ "the commit object specifies an encoding for the commit "
+ "message, the message is re-encoded into UTF-8."))
+
+ people = parser.add_argument_group(title=_("Filtering of names & emails "
+ "(see also --name-callback "
+ "and --email-callback)"))
+ people.add_argument('--mailmap', dest='mailmap', metavar='FILENAME',
+ type=os.fsencode,
+ help=_("Use specified mailmap file (see git-shortlog(1) for "
+ "details on the format) when rewriting author, committer, "
+ "and tagger names and emails. If the specified file is "
+ "part of git history, historical versions of the file will "
+ "be ignored; only the current contents are consulted."))
+ people.add_argument('--use-mailmap', dest='mailmap',
+ action='store_const', const=b'.mailmap',
+ help=_("Same as: '--mailmap .mailmap' "))
+
+ parents = parser.add_argument_group(title=_("Parent rewriting"))
+ parents.add_argument('--replace-refs', default=None,
+ choices=['delete-no-add', 'delete-and-add',
+ 'update-no-add', 'update-or-add',
+ 'update-and-add', 'old-default'],
+ help=_("How to handle replace refs (see git-replace(1)). Replace "
+ "refs can be added during the history rewrite as a way to "
+ "allow users to pass old commit IDs (from before "
+ "git-filter-repo was run) to git commands and have git know "
+ "how to translate those old commit IDs to the new "
+ "(post-rewrite) commit IDs. Also, replace refs that existed "
+ "before the rewrite can either be deleted or updated. The "
+ "choices to pass to --replace-refs thus need to specify both "
+ "what to do with existing refs and what to do with commit "
+ "rewrites. Thus 'update-and-add' means to update existing "
+ "replace refs, and for any commit rewrite (even if already "
+ "pointed at by a replace ref) add a new refs/replace/ reference "
+ "to map from the old commit ID to the new commit ID. The "
+ "default is update-no-add, meaning update existing replace refs "
+ "but do not add any new ones. There is also a special "
+ "'old-default' option for picking the default used in versions "
+ "prior to git-filter-repo-2.45, namely 'update-and-add' upon "
+ "the first run of git-filter-repo in a repository and "
+ "'update-or-add' if running git-filter-repo again on a "
+ "repository."))
+ parents.add_argument('--prune-empty', default='auto',
+ choices=['always', 'auto', 'never'],
+ help=_("Whether to prune empty commits. 'auto' (the default) means "
+ "only prune commits which become empty (not commits which were "
+ "empty in the original repo, unless their parent was pruned). "
+ "When the parent of a commit is pruned, the first non-pruned "
+ "ancestor becomes the new parent."))
+ parents.add_argument('--prune-degenerate', default='auto',
+ choices=['always', 'auto', 'never'],
+ help=_("Since merge commits are needed for history topology, they "
+ "are typically exempt from pruning. However, they can become "
+ "degenerate with the pruning of other commits (having fewer "
+ "than two parents, having one commit serve as both parents, or "
+ "having one parent as the ancestor of the other.) If such "
+ "merge commits have no file changes, they can be pruned. The "
+ "default ('auto') is to only prune empty merge commits which "
+ "become degenerate (not which started as such)."))
+ parents.add_argument('--no-ff', action='store_true',
+ help=_("Even if the first parent is or becomes an ancestor of another "
+ "parent, do not prune it. This modifies how "
+ "--prune-degenerate behaves, and may be useful in projects who "
+ "always use merge --no-ff."))
+
+ callback = parser.add_argument_group(title=_("Generic callback code snippets"))
+ callback.add_argument('--filename-callback', metavar="FUNCTION_BODY_OR_FILE",
+ help=_("Python code body for processing filenames; see CALLBACKS "
+ "sections below."))
+ callback.add_argument('--file-info-callback', metavar="FUNCTION_BODY_OR_FILE",
+ help=_("Python code body for processing file and metadata; see "
+ "CALLBACKS sections below."))
+ callback.add_argument('--message-callback', metavar="FUNCTION_BODY_OR_FILE",
+ help=_("Python code body for processing messages (both commit "
+ "messages and tag messages); see CALLBACKS section below."))
+ callback.add_argument('--name-callback', metavar="FUNCTION_BODY_OR_FILE",
+ help=_("Python code body for processing names of people; see "
+ "CALLBACKS section below."))
+ callback.add_argument('--email-callback', metavar="FUNCTION_BODY_OR_FILE",
+ help=_("Python code body for processing emails addresses; see "
+ "CALLBACKS section below."))
+ callback.add_argument('--refname-callback', metavar="FUNCTION_BODY_OR_FILE",
+ help=_("Python code body for processing refnames; see CALLBACKS "
+ "section below."))
+
+ callback.add_argument('--blob-callback', metavar="FUNCTION_BODY_OR_FILE",
+ help=_("Python code body for processing blob objects; see "
+ "CALLBACKS section below."))
+ callback.add_argument('--commit-callback', metavar="FUNCTION_BODY_OR_FILE",
+ help=_("Python code body for processing commit objects; see "
+ "CALLBACKS section below."))
+ callback.add_argument('--tag-callback', metavar="FUNCTION_BODY_OR_FILE",
+ help=_("Python code body for processing tag objects. Note that "
+ "lightweight tags have no tag object and are thus not "
+ "handled by this callback. See CALLBACKS section below."))
+ callback.add_argument('--reset-callback', metavar="FUNCTION_BODY_OR_FILE",
+ help=_("Python code body for processing reset objects; see "
+ "CALLBACKS section below."))
+
+ sdr = parser.add_argument_group(title=_("Sensitive Data Removal Handling"))
+ sdr.add_argument('--sensitive-data-removal', '--sdr', action='store_true',
+ help=_("This rewrite is intended to remove sensitive data from a "
+ "repository. Gather extra information from the rewrite needed "
+ "to provide additional instructions on how to clean up other "
+ "copies."))
+ sdr.add_argument('--no-fetch', action='store_true',
+ help=_("By default, --sensitive-data-removal will trigger a "
+ "mirror-like fetch of all refs from origin, discarding local "
+ "changes, but ensuring that _all_ fetchable refs that hold on "
+ "to the sensitve data are rewritten. This flag removes that "
+ "fetch, risking that other refs continue holding on to the "
+ "sensitive data. This option is implied by --partial or any "
+ "flag that implies --partial."))
+
+ desc = _(
+ "Specifying alternate source or target locations implies --partial,\n"
+ "except that the normal default for --replace-refs is used. However,\n"
+ "unlike normal uses of --partial, this doesn't risk mixing old and new\n"
+ "history since the old and new histories are in different repositories.")
+ location = parser.add_argument_group(title=_("Location to filter from/to"),
+ description=desc)
+ location.add_argument('--source', type=os.fsencode,
+ help=_("Git repository to read from"))
+ location.add_argument('--target', type=os.fsencode,
+ help=_("Git repository to overwrite with filtered history"))
+
+ order = parser.add_argument_group(title=_("Ordering of commits"))
+ order.add_argument('--date-order', action='store_true',
+ help=_("Processes commits in commit timestamp order."))
+
+ misc = parser.add_argument_group(title=_("Miscellaneous options"))
+ misc.add_argument('--help', '-h', action='store_true',
+ help=_("Show this help message and exit."))
+ misc.add_argument('--version', action='store_true',
+ help=_("Display filter-repo's version and exit."))
+ misc.add_argument('--proceed', action='store_true',
+ help=_("Avoid triggering the no-arguments-specified check."))
+ misc.add_argument('--force', '-f', action='store_true',
+ help=_("Rewrite repository history even if the current repo does not "
+ "look like a fresh clone. History rewriting is irreversible "
+ "(and includes immediate pruning of reflogs and old objects), "
+ "so be cautious about using this flag."))
+ misc.add_argument('--partial', action='store_true',
+ help=_("Do a partial history rewrite, resulting in the mixture of "
+ "old and new history. This disables rewriting "
+ "refs/remotes/origin/* to refs/heads/*, disables removing "
+ "of the 'origin' remote, disables removing unexported refs, "
+ "disables expiring the reflog, and disables the automatic "
+ "post-filter gc. Also, this modifies --tag-rename and "
+ "--refname-callback options such that instead of replacing "
+ "old refs with new refnames, it will instead create new "
+ "refs and keep the old ones around. Use with caution."))
+ misc.add_argument('--no-gc', action='store_true',
+ help=_("Do not run 'git gc' after filtering."))
+ # WARNING: --refs presents a problem with become-degenerate pruning:
+ # * Excluding a commit also excludes its ancestors so when some other
+ # commit has an excluded ancestor as a parent we have no way of
+ # knowing what it is an ancestor of without doing a special
+ # full-graph walk.
+ misc.add_argument('--refs', nargs='+',
+ help=_("Limit history rewriting to the specified refs. Implies "
+ "--partial. In addition to the normal caveats of --partial "
+ "(mixing old and new history, no automatic remapping of "
+ "refs/remotes/origin/* to refs/heads/*, etc.), this also may "
+ "cause problems for pruning of degenerate empty merge "
+ "commits when negative revisions are specified."))
+
+ misc.add_argument('--dry-run', action='store_true',
+ help=_("Do not change the repository. Run `git fast-export` and "
+ "filter its output, and save both the original and the "
+ "filtered version for comparison. This also disables "
+ "rewriting commit messages due to not knowing new commit "
+ "IDs and disables filtering of some empty commits due to "
+ "inability to query the fast-import backend." ))
+ misc.add_argument('--debug', action='store_true',
+ help=_("Print additional information about operations being "
+ "performed and commands being run. When used together "
+ "with --dry-run, also show extra information about what "
+ "would be run."))
+ # WARNING: --state-branch has some problems:
+ # * It does not work well with manually inserted objects (user creating
+ # Blob() or Commit() or Tag() objects and calling
+ # RepoFilter.insert(obj) on them).
+ # * It does not work well with multiple source or multiple target repos
+ # * It doesn't work so well with pruning become-empty commits (though
+ # --refs doesn't work so well with it either)
+ # These are probably fixable, given some work (e.g. re-importing the
+ # graph at the beginning to get the AncestryGraph right, doing our own
+ # export of marks instead of using fast-export --export-marks, etc.), but
+ # for now just hide the option.
+ misc.add_argument('--state-branch',
+ #help=_("Enable incremental filtering by saving the mapping of old "
+ # "to new objects to the specified branch upon exit, and"
+ # "loading that mapping from that branch (if it exists) "
+ # "upon startup."))
+ help=argparse.SUPPRESS)
+ misc.add_argument('--stdin', action='store_true',
+ help=_("Instead of running `git fast-export` and filtering its "
+ "output, filter the fast-export stream from stdin. The "
+ "stdin must be in the expected input format (e.g. it needs "
+ "to include original-oid directives)."))
+ misc.add_argument('--quiet', action='store_true',
+ help=_("Pass --quiet to other git commands called"))
+ return parser
+
+ @staticmethod
+ def sanity_check_args(args):
+ if args.analyze and args.path_changes:
+ raise SystemExit(_("Error: --analyze is incompatible with --path* flags; "
+ "it's a read-only operation."))
+ if args.analyze and args.stdin:
+ raise SystemExit(_("Error: --analyze is incompatible with --stdin."))
+ # If no path_changes are found, initialize with empty list but mark as
+ # not inclusive so that all files match
+ if args.path_changes == None:
+ args.path_changes = []
+ args.inclusive = False
+ else:
+ # Similarly, if we have no filtering paths, then no path should be
+ # filtered out. Based on how newname() works, the easiest way to
+ # achieve that is setting args.inclusive to False.
+ if not any(x[0] == 'filter' for x in args.path_changes):
+ args.inclusive = False
+ # Also check for incompatible --use-base-name and --path-rename flags.
+ if args.use_base_name:
+ if any(x[0] == 'rename' for x in args.path_changes):
+ raise SystemExit(_("Error: --use-base-name and --path-rename are "
+ "incompatible."))
+ # Also throw some sanity checks on git version here;
+ # PERF: remove these checks once new enough git versions are common
+ p = subproc.Popen('git fast-export -h'.split(),
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ output = p.stdout.read()
+ if b'--anonymize-map' not in output: # pragma: no cover
+ global date_format_permissive
+ date_format_permissive = False
+ if not any(x in output for x in [b'--mark-tags',b'--[no-]mark-tags']): # pragma: no cover
+ global write_marks
+ write_marks = False
+ if args.state_branch:
+ # We need a version of git-fast-export with --mark-tags
+ raise SystemExit(_("Error: need git >= 2.24.0"))
+ if not any(x in output for x in [b'--reencode', b'--[no-]reencode']): # pragma: no cover
+ if args.preserve_commit_encoding:
+ # We need a version of git-fast-export with --reencode
+ raise SystemExit(_("Error: need git >= 2.23.0"))
+ else:
+ # Set args.preserve_commit_encoding to None which we'll check for later
+ # to avoid passing --reencode=yes to fast-export (that option was the
+ # default prior to git-2.23)
+ args.preserve_commit_encoding = None
+ # If we don't have fast-exoprt --reencode, we may also be missing
+ # diff-tree --combined-all-paths, which is even more important...
+ p = subproc.Popen('git diff-tree -h'.split(),
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ output = p.stdout.read()
+ if b'--combined-all-paths' not in output:
+ # We need a version of git-diff-tree with --combined-all-paths
+ raise SystemExit(_("Error: need git >= 2.22.0"))
+ if args.sensitive_data_removal:
+ p = subproc.Popen('git cat-file -h'.split(),
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ output = p.stdout.read()
+ if b"--batch-command" not in output: # pragma: no cover
+ raise SystemExit(_("Error: need git >= 2.36.0"))
+ # End of sanity checks on git version
+ if args.max_blob_size:
+ suffix = args.max_blob_size[-1]
+ if suffix not in '1234567890':
+ mult = {'K': 1024, 'M': 1024**2, 'G': 1024**3}
+ if suffix not in mult:
+ raise SystemExit(_("Error: could not parse --strip-blobs-bigger-than"
+ " argument %s")
+ % args.max_blob_size)
+ args.max_blob_size = int(args.max_blob_size[0:-1]) * mult[suffix]
+ else:
+ args.max_blob_size = int(args.max_blob_size)
+ if args.file_info_callback and (
+ args.stdin or args.blob_callback or args.filename_callback):
+ raise SystemExit(_("Error: --file-info-callback is incompatible with "
+ "--stdin, --blob-callback,\nand --filename-callback."))
+
+ @staticmethod
+ def get_replace_text(filename):
+ replace_literals = []
+ replace_regexes = []
+ with open(filename, 'br') as f:
+ for line in f:
+ line = line.rstrip(b'\r\n')
+
+ # Determine the replacement
+ replacement = FilteringOptions.default_replace_text
+ if b'==>' in line:
+ line, replacement = line.rsplit(b'==>', 1)
+
+ # See if we need to match via regex
+ regex = None
+ if line.startswith(b'regex:'):
+ regex = line[6:]
+ elif line.startswith(b'glob:'):
+ regex = glob_to_regex(line[5:])
+ if regex:
+ replace_regexes.append((re.compile(regex), replacement))
+ else:
+ # Otherwise, find the literal we need to replace
+ if line.startswith(b'literal:'):
+ line = line[8:]
+ if not line:
+ continue
+ replace_literals.append((line, replacement))
+ return {'literals': replace_literals, 'regexes': replace_regexes}
+
+ @staticmethod
+ def get_paths_from_file(filename):
+ new_path_changes = []
+ with open(filename, 'br') as f:
+ for line in f:
+ line = line.rstrip(b'\r\n')
+
+ # Skip blank lines
+ if not line:
+ continue
+ # Skip comment lines
+ if line.startswith(b'#'):
+ continue
+
+ # Determine the replacement
+ match_type, repl = 'literal', None
+ if b'==>' in line:
+ line, repl = line.rsplit(b'==>', 1)
+
+ # See if we need to match via regex
+ match_type = 'match' # a.k.a. 'literal'
+ if line.startswith(b'regex:'):
+ match_type = 'regex'
+ match = re.compile(line[6:])
+ elif line.startswith(b'glob:'):
+ match_type = 'glob'
+ match = line[5:]
+ if repl:
+ raise SystemExit(_("Error: In %s, 'glob:' and '==>' are incompatible (renaming globs makes no sense)" % decode(filename)))
+ else:
+ if line.startswith(b'literal:'):
+ match = line[8:]
+ else:
+ match = line
+ if repl is not None:
+ if match and repl and match.endswith(b'/') != repl.endswith(b'/'):
+ raise SystemExit(_("Error: When rename directories, if OLDNAME "
+ "and NEW_NAME are both non-empty and either "
+ "ends with a slash then both must."))
+
+ # Record the filter or rename
+ if repl is not None:
+ new_path_changes.append(['rename', match_type, (match, repl)])
+ else:
+ new_path_changes.append(['filter', match_type, match])
+ if match_type == 'glob' and not match.endswith(b'*'):
+ extension = b'*' if match.endswith(b'/') else b'/*'
+ new_path_changes.append(['filter', match_type, match+extension])
+ return new_path_changes
+
+ @staticmethod
+ def default_options():
+ return FilteringOptions.parse_args([], error_on_empty = False)
+
+ @staticmethod
+ def parse_args(input_args, error_on_empty = True):
+ parser = FilteringOptions.create_arg_parser()
+ if not input_args and error_on_empty:
+ parser.print_usage()
+ raise SystemExit(_("No arguments specified."))
+ args = parser.parse_args(input_args)
+ if args.help:
+ parser.print_help()
+ raise SystemExit()
+ if args.paths:
+ raise SystemExit("Error: Option `--paths` unrecognized; did you mean --path or --paths-from-file?")
+ if args.version:
+ GitUtils.print_my_version()
+ raise SystemExit()
+ FilteringOptions.sanity_check_args(args)
+ if args.mailmap:
+ args.mailmap = MailmapInfo(args.mailmap)
+ if args.replace_text:
+ args.replace_text = FilteringOptions.get_replace_text(args.replace_text)
+ if args.replace_message:
+ args.replace_message = FilteringOptions.get_replace_text(args.replace_message)
+ if args.strip_blobs_with_ids:
+ with open(args.strip_blobs_with_ids, 'br') as f:
+ args.strip_blobs_with_ids = set(f.read().split())
+ else:
+ args.strip_blobs_with_ids = set()
+ if (args.partial or args.refs) and not args.replace_refs:
+ args.replace_refs = 'update-no-add'
+ args.repack = not (args.partial or args.refs or args.no_gc)
+ if args.refs or args.source or args.target:
+ args.partial = True
+ if args.partial:
+ args.no_fetch = True
+ if not args.refs:
+ args.refs = ['--all']
+ return args
+
+class RepoAnalyze(object):
+
+ # First, several helper functions for analyze_commit()
+
+ @staticmethod
+ def equiv_class(stats, filename):
+ return stats['equivalence'].get(filename, (filename,))
+
+ @staticmethod
+ def setup_equivalence_for_rename(stats, oldname, newname):
+ # if A is renamed to B and B is renamed to C, then the user thinks of
+ # A, B, and C as all being different names for the same 'file'. We record
+ # this as an equivalence class:
+ # stats['equivalence'][name] = (A,B,C)
+ # for name being each of A, B, and C.
+ old_tuple = stats['equivalence'].get(oldname, ())
+ if newname in old_tuple:
+ return
+ elif old_tuple:
+ new_tuple = tuple(list(old_tuple)+[newname])
+ else:
+ new_tuple = (oldname, newname)
+ for f in new_tuple:
+ stats['equivalence'][f] = new_tuple
+
+ @staticmethod
+ def setup_or_update_rename_history(stats, commit, oldname, newname):
+ rename_commits = stats['rename_history'].get(oldname, set())
+ rename_commits.add(commit)
+ stats['rename_history'][oldname] = rename_commits
+
+ @staticmethod
+ def handle_renames(stats, commit, change_types, filenames):
+ for index, change_type in enumerate(change_types):
+ if change_type == ord(b'R'):
+ oldname, newname = filenames[index], filenames[-1]
+ RepoAnalyze.setup_equivalence_for_rename(stats, oldname, newname)
+ RepoAnalyze.setup_or_update_rename_history(stats, commit,
+ oldname, newname)
+
+ @staticmethod
+ def handle_file(stats, graph, commit, modes, shas, filenames):
+ mode, sha, filename = modes[-1], shas[-1], filenames[-1]
+
+ # Figure out kind of deletions to undo for this file, and update lists
+ # of all-names-by-sha and all-filenames
+ delmode = 'tree_deletions'
+ if mode != b'040000':
+ delmode = 'file_deletions'
+ stats['names'][sha].add(filename)
+ stats['allnames'].add(filename)
+
+ # If the file (or equivalence class of files) was recorded as deleted,
+ # clearly it isn't anymore
+ equiv = RepoAnalyze.equiv_class(stats, filename)
+ for f in equiv:
+ stats[delmode].pop(f, None)
+
+ # If we get a modify/add for a path that was renamed, we may need to break
+ # the equivalence class. However, if the modify/add was on a branch that
+ # doesn't have the rename in its history, we are still okay.
+ need_to_break_equivalence = False
+ if equiv[-1] != filename:
+ for rename_commit in stats['rename_history'][filename]:
+ if graph.is_ancestor(rename_commit, commit):
+ need_to_break_equivalence = True
+
+ if need_to_break_equivalence:
+ for f in equiv:
+ if f in stats['equivalence']:
+ del stats['equivalence'][f]
+
+ @staticmethod
+ def analyze_commit(stats, graph, commit, parents, date, file_changes):
+ graph.add_commit_and_parents(commit, parents)
+ for change in file_changes:
+ modes, shas, change_types, filenames = change
+ if len(parents) == 1 and change_types.startswith(b'R'):
+ change_types = b'R' # remove the rename score; we don't care
+ if modes[-1] == b'160000':
+ continue
+ elif modes[-1] == b'000000':
+ # Track when files/directories are deleted
+ for f in RepoAnalyze.equiv_class(stats, filenames[-1]):
+ if any(x == b'040000' for x in modes[0:-1]):
+ stats['tree_deletions'][f] = date
+ else:
+ stats['file_deletions'][f] = date
+ elif change_types.strip(b'AMT') == b'':
+ RepoAnalyze.handle_file(stats, graph, commit, modes, shas, filenames)
+ elif modes[-1] == b'040000' and change_types.strip(b'RAM') == b'':
+ RepoAnalyze.handle_file(stats, graph, commit, modes, shas, filenames)
+ elif change_types.strip(b'RAMT') == b'':
+ RepoAnalyze.handle_file(stats, graph, commit, modes, shas, filenames)
+ RepoAnalyze.handle_renames(stats, commit, change_types, filenames)
+ else:
+ raise SystemExit(_("Unhandled change type(s): %(change_type)s "
+ "(in commit %(commit)s)")
+ % ({'change_type': change_types, 'commit': commit})
+ ) # pragma: no cover
+
+ @staticmethod
+ def gather_data(args):
+ unpacked_size, packed_size = GitUtils.get_blob_sizes()
+ stats = {'names': collections.defaultdict(set),
+ 'allnames' : set(),
+ 'file_deletions': {},
+ 'tree_deletions': {},
+ 'equivalence': {},
+ 'rename_history': collections.defaultdict(set),
+ 'unpacked_size': unpacked_size,
+ 'packed_size': packed_size,
+ 'num_commits': 0}
+
+ # Setup the rev-list/diff-tree process
+ processed_commits_msg = _("Processed %d commits")
+ commit_parse_progress = ProgressWriter()
+ num_commits = 0
+ cmd = ('git rev-list --topo-order --reverse {}'.format(' '.join(args.refs)) +
+ ' | git diff-tree --stdin --always --root --format=%H%n%P%n%cd' +
+ ' --date=short -M -t -c --raw --combined-all-paths')
+ dtp = subproc.Popen(cmd, shell=True, bufsize=-1, stdout=subprocess.PIPE)
+ f = dtp.stdout
+ line = f.readline()
+ if not line:
+ raise SystemExit(_("Nothing to analyze; repository is empty."))
+ cont = bool(line)
+ graph = AncestryGraph()
+ while cont:
+ commit = line.rstrip()
+ parents = f.readline().split()
+ date = f.readline().rstrip()
+
+ # We expect a blank line next; if we get a non-blank line then
+ # this commit modified no files and we need to move on to the next.
+ # If there is no line, we've reached end-of-input.
+ line = f.readline()
+ if not line:
+ cont = False
+ line = line.rstrip()
+
+ # If we haven't reached end of input, and we got a blank line meaning
+ # a commit that has modified files, then get the file changes associated
+ # with this commit.
+ file_changes = []
+ if cont and not line:
+ cont = False
+ for line in f:
+ if not line.startswith(b':'):
+ cont = True
+ break
+ n = 1+max(1, len(parents))
+ assert line.startswith(b':'*(n-1))
+ relevant = line[n-1:-1]
+ splits = relevant.split(None, n)
+ modes = splits[0:n]
+ splits = splits[n].split(None, n)
+ shas = splits[0:n]
+ splits = splits[n].split(b'\t')
+ change_types = splits[0]
+ filenames = [PathQuoting.dequote(x) for x in splits[1:]]
+ file_changes.append([modes, shas, change_types, filenames])
+
+ # If someone is trying to analyze a subset of the history, make sure
+ # to avoid dying on commits with parents that we haven't seen before
+ if args.refs:
+ graph.record_external_commits([p for p in parents
+ if not p in graph.value])
+
+ # Analyze this commit and update progress
+ RepoAnalyze.analyze_commit(stats, graph, commit, parents, date,
+ file_changes)
+ num_commits += 1
+ commit_parse_progress.show(processed_commits_msg % num_commits)
+
+ # Show the final commits processed message and record the number of commits
+ commit_parse_progress.finish()
+ stats['num_commits'] = num_commits
+
+ # Close the output, ensure rev-list|diff-tree pipeline completed successfully
+ dtp.stdout.close()
+ if dtp.wait():
+ raise SystemExit(_("Error: rev-list|diff-tree pipeline failed; see above.")) # pragma: no cover
+
+ return stats
+
+ @staticmethod
+ def write_report(reportdir, stats):
+ def datestr(datetimestr):
+ return datetimestr if datetimestr else _('').encode()
+
+ def dirnames(path):
+ while True:
+ path = os.path.dirname(path)
+ yield path
+ if path == b'':
+ break
+
+ # Compute aggregate size information for paths, extensions, and dirs
+ total_size = {'packed': 0, 'unpacked': 0}
+ path_size = {'packed': collections.defaultdict(int),
+ 'unpacked': collections.defaultdict(int)}
+ ext_size = {'packed': collections.defaultdict(int),
+ 'unpacked': collections.defaultdict(int)}
+ dir_size = {'packed': collections.defaultdict(int),
+ 'unpacked': collections.defaultdict(int)}
+ for sha in stats['names']:
+ size = {'packed': stats['packed_size'][sha],
+ 'unpacked': stats['unpacked_size'][sha]}
+ for which in ('packed', 'unpacked'):
+ for name in stats['names'][sha]:
+ total_size[which] += size[which]
+ path_size[which][name] += size[which]
+ basename, ext = os.path.splitext(name)
+ ext_size[which][ext] += size[which]
+ for dirname in dirnames(name):
+ dir_size[which][dirname] += size[which]
+
+ # Determine if and when extensions and directories were deleted
+ ext_deleted_data = {}
+ for name in stats['allnames']:
+ when = stats['file_deletions'].get(name, None)
+
+ # Update the extension
+ basename, ext = os.path.splitext(name)
+ if when is None:
+ ext_deleted_data[ext] = None
+ elif ext in ext_deleted_data:
+ if ext_deleted_data[ext] is not None:
+ ext_deleted_data[ext] = max(ext_deleted_data[ext], when)
+ else:
+ ext_deleted_data[ext] = when
+
+ dir_deleted_data = {}
+ for name in dir_size['packed']:
+ dir_deleted_data[name] = stats['tree_deletions'].get(name, None)
+
+ with open(os.path.join(reportdir, b"README"), 'bw') as f:
+ # Give a basic overview of this file
+ f.write(b"== %s ==\n" % _("Overall Statistics").encode())
+ f.write((" %s: %d\n" % (_("Number of commits"),
+ stats['num_commits'])).encode())
+ f.write((" %s: %d\n" % (_("Number of filenames"),
+ len(path_size['packed']))).encode())
+ f.write((" %s: %d\n" % (_("Number of directories"),
+ len(dir_size['packed']))).encode())
+ f.write((" %s: %d\n" % (_("Number of file extensions"),
+ len(ext_size['packed']))).encode())
+ f.write(b"\n")
+ f.write((" %s: %d\n" % (_("Total unpacked size (bytes)"),
+ total_size['unpacked'])).encode())
+ f.write((" %s: %d\n" % (_("Total packed size (bytes)"),
+ total_size['packed'])).encode())
+ f.write(b"\n")
+
+ # Mention issues with the report
+ f.write(("== %s ==\n" % _("Caveats")).encode())
+ f.write(("=== %s ===\n" % _("Sizes")).encode())
+ f.write(textwrap.dedent(_("""
+ Packed size represents what size your repository would be if no
+ trees, commits, tags, or other metadata were included (though it may
+ fail to represent de-duplication; see below). It also represents the
+ current packing, which may be suboptimal if you haven't gc'ed for a
+ while.
+
+ Unpacked size represents what size your repository would be if no
+ trees, commits, tags, or other metadata were included AND if no
+ files were packed; i.e., without delta-ing or compression.
+
+ Both unpacked and packed sizes can be slightly misleading. Deleting
+ a blob from history not save as much space as the unpacked size,
+ because it is obviously normally stored in packed form. Also,
+ deleting a blob from history may not save as much space as its packed
+ size either, because another blob could be stored as a delta against
+ that blob, so when you remove one blob another blob's packed size may
+ grow.
+
+ Also, the sum of the packed sizes can add up to more than the
+ repository size; if the same contents appeared in the repository in
+ multiple places, git will automatically de-dupe and store only one
+ copy, while the way sizes are added in this analysis adds the size
+ for each file path that has those contents. Further, if a file is
+ ever reverted to a previous version's contents, the previous
+ version's size will be counted multiple times in this analysis, even
+ though git will only store it once.
+ """)[1:]).encode())
+ f.write(b"\n")
+ f.write(("=== %s ===\n" % _("Deletions")).encode())
+ f.write(textwrap.dedent(_("""
+ Whether a file is deleted is not a binary quality, since it can be
+ deleted on some branches but still exist in others. Also, it might
+ exist in an old tag, but have been deleted in versions newer than
+ that. More thorough tracking could be done, including looking at
+ merge commits where one side of history deleted and the other modified,
+ in order to give a more holistic picture of deletions. However, that
+ algorithm would not only be more complex to implement, it'd also be
+ quite difficult to present and interpret by users. Since --analyze
+ is just about getting a high-level rough picture of history, it instead
+ implements the simplistic rule that is good enough for 98% of cases:
+ A file is marked as deleted if the last commit in the fast-export
+ stream that mentions the file lists it as deleted.
+ This makes it dependent on topological ordering, but generally gives
+ the "right" answer.
+ """)[1:]).encode())
+ f.write(b"\n")
+ f.write(("=== %s ===\n" % _("Renames")).encode())
+ f.write(textwrap.dedent(_("""
+ Renames share the same non-binary nature that deletions do, plus
+ additional challenges:
+ * If the renamed file is renamed again, instead of just two names for
+ a path you can have three or more.
+ * Rename pairs of the form (oldname, newname) that we consider to be
+ different names of the "same file" might only be valid over certain
+ commit ranges. For example, if a new commit reintroduces a file
+ named oldname, then new versions of oldname aren't the "same file"
+ anymore. We could try to portray this to the user, but it's easier
+ for the user to just break the pairing and only report unbroken
+ rename pairings to the user.
+ * The ability for users to rename files differently in different
+ branches means that our chains of renames will not necessarily be
+ linear but may branch out.
+ """)[1:]).encode())
+ f.write(b"\n")
+
+ # Equivalence classes for names, so if folks only want to keep a
+ # certain set of paths, they know the old names they want to include
+ # too.
+ with open(os.path.join(reportdir, b"renames.txt"), 'bw') as f:
+ seen = set()
+ for pathname,equiv_group in sorted(stats['equivalence'].items(),
+ key=lambda x:(x[1], x[0])):
+ if equiv_group in seen:
+ continue
+ seen.add(equiv_group)
+ f.write(("{} ->\n ".format(decode(equiv_group[0])) +
+ "\n ".join(decode(x) for x in equiv_group[1:]) +
+ "\n").encode())
+
+ # List directories in reverse sorted order of unpacked size
+ with open(os.path.join(reportdir, b"directories-deleted-sizes.txt"), 'bw') as f:
+ msg = "=== %s ===\n" % _("Deleted directories by reverse size")
+ f.write(msg.encode())
+ msg = _("Format: unpacked size, packed size, date deleted, directory name\n")
+ f.write(msg.encode())
+ for dirname, size in sorted(dir_size['packed'].items(),
+ key=lambda x:(x[1],x[0]), reverse=True):
+ if (dir_deleted_data[dirname]):
+ f.write(b" %10d %10d %-10s %s\n" % (dir_size['unpacked'][dirname],
+ size,
+ datestr(dir_deleted_data[dirname]),
+ dirname or _('').encode()))
+
+ with open(os.path.join(reportdir, b"directories-all-sizes.txt"), 'bw') as f:
+ f.write(("=== %s ===\n" % _("All directories by reverse size")).encode())
+ msg = _("Format: unpacked size, packed size, date deleted, directory name\n")
+ f.write(msg.encode())
+ for dirname, size in sorted(dir_size['packed'].items(),
+ key=lambda x:(x[1],x[0]), reverse=True):
+ f.write(b" %10d %10d %-10s %s\n" % (dir_size['unpacked'][dirname],
+ size,
+ datestr(dir_deleted_data[dirname]),
+ dirname or _("").encode()))
+
+ # List extensions in reverse sorted order of unpacked size
+ with open(os.path.join(reportdir, b"extensions-deleted-sizes.txt"), 'bw') as f:
+ msg = "=== %s ===\n" % _("Deleted extensions by reverse size")
+ f.write(msg.encode())
+ msg = _("Format: unpacked size, packed size, date deleted, extension name\n")
+ f.write(msg.encode())
+ for extname, size in sorted(ext_size['packed'].items(),
+ key=lambda x:(x[1],x[0]), reverse=True):
+ if (ext_deleted_data[extname]):
+ f.write(b" %10d %10d %-10s %s\n" % (ext_size['unpacked'][extname],
+ size,
+ datestr(ext_deleted_data[extname]),
+ extname or _('').encode()))
+
+ with open(os.path.join(reportdir, b"extensions-all-sizes.txt"), 'bw') as f:
+ f.write(("=== %s ===\n" % _("All extensions by reverse size")).encode())
+ msg = _("Format: unpacked size, packed size, date deleted, extension name\n")
+ f.write(msg.encode())
+ for extname, size in sorted(ext_size['packed'].items(),
+ key=lambda x:(x[1],x[0]), reverse=True):
+ f.write(b" %10d %10d %-10s %s\n" % (ext_size['unpacked'][extname],
+ size,
+ datestr(ext_deleted_data[extname]),
+ extname or _('').encode()))
+
+ # List files in reverse sorted order of unpacked size
+ with open(os.path.join(reportdir, b"path-deleted-sizes.txt"), 'bw') as f:
+ msg = "=== %s ===\n" % _("Deleted paths by reverse accumulated size")
+ f.write(msg.encode())
+ msg = _("Format: unpacked size, packed size, date deleted, path name(s)\n")
+ f.write(msg.encode())
+ for pathname, size in sorted(path_size['packed'].items(),
+ key=lambda x:(x[1],x[0]), reverse=True):
+ when = stats['file_deletions'].get(pathname, None)
+ if when:
+ f.write(b" %10d %10d %-10s %s\n" % (path_size['unpacked'][pathname],
+ size,
+ datestr(when),
+ pathname))
+
+ with open(os.path.join(reportdir, b"path-all-sizes.txt"), 'bw') as f:
+ msg = "=== %s ===\n" % _("All paths by reverse accumulated size")
+ f.write(msg.encode())
+ msg = _("Format: unpacked size, packed size, date deleted, path name\n")
+ f.write(msg.encode())
+ for pathname, size in sorted(path_size['packed'].items(),
+ key=lambda x:(x[1],x[0]), reverse=True):
+ when = stats['file_deletions'].get(pathname, None)
+ f.write(b" %10d %10d %-10s %s\n" % (path_size['unpacked'][pathname],
+ size,
+ datestr(when),
+ pathname))
+
+ # List of filenames and sizes in descending order
+ with open(os.path.join(reportdir, b"blob-shas-and-paths.txt"), 'bw') as f:
+ f.write(("=== %s ===\n" % _("Files by sha and associated pathnames in reverse size")).encode())
+ f.write(_("Format: sha, unpacked size, packed size, filename(s) object stored as\n").encode())
+ for sha, size in sorted(stats['packed_size'].items(),
+ key=lambda x:(x[1],x[0]), reverse=True):
+ if sha not in stats['names']:
+ # Some objects in the repository might not be referenced, or not
+ # referenced by the branches/tags the user cares about; skip them.
+ continue
+ names_with_sha = stats['names'][sha]
+ if len(names_with_sha) == 1:
+ names_with_sha = names_with_sha.pop()
+ else:
+ names_with_sha = b'[' + b', '.join(sorted(names_with_sha)) + b']'
+ f.write(b" %s %10d %10d %s\n" % (sha,
+ stats['unpacked_size'][sha],
+ size,
+ names_with_sha))
+
+ @staticmethod
+ def run(args):
+ if args.report_dir:
+ reportdir = args.report_dir
+ else:
+ git_dir = GitUtils.determine_git_dir(b'.')
+
+ # Create the report directory as necessary
+ results_tmp_dir = os.path.join(git_dir, b'filter-repo')
+ if not os.path.isdir(results_tmp_dir):
+ os.mkdir(results_tmp_dir)
+ reportdir = os.path.join(results_tmp_dir, b"analysis")
+
+ if os.path.isdir(reportdir):
+ if args.force:
+ sys.stdout.write(_("Warning: Removing recursively: \"%s\"\n") % decode(reportdir))
+ shutil.rmtree(reportdir)
+ else:
+ sys.stdout.write(_("Error: dir already exists (use --force to delete): \"%s\"\n") % decode(reportdir))
+ sys.exit(1)
+
+ os.mkdir(reportdir)
+
+ # Gather the data we need
+ stats = RepoAnalyze.gather_data(args)
+
+ # Write the reports
+ sys.stdout.write(_("Writing reports to \"%s\"...") % decode(reportdir))
+ sys.stdout.flush()
+ RepoAnalyze.write_report(reportdir, stats)
+ sys.stdout.write(_("done.\n"))
+ sys.stdout.write(_("README: \"%s\"\n") % decode( os.path.join(reportdir, b"README") ))
+
+class FileInfoValueHelper:
+ def __init__(self, replace_text, insert_blob_func, source_working_dir):
+ self.data = {}
+ self._replace_text = replace_text
+ self._insert_blob_func = insert_blob_func
+ cmd = ['git', 'cat-file', '--batch-command']
+ self._cat_file_process = subproc.Popen(cmd,
+ stdin = subprocess.PIPE,
+ stdout = subprocess.PIPE,
+ cwd = source_working_dir)
+
+ def finalize(self):
+ self._cat_file_process.stdin.close()
+ self._cat_file_process.wait()
+
+ def get_contents_by_identifier(self, blobhash):
+ self._cat_file_process.stdin.write(b'contents '+blobhash+b'\n')
+ self._cat_file_process.stdin.flush()
+ line = self._cat_file_process.stdout.readline()
+ try:
+ (oid, oidtype, size) = line.split()
+ except ValueError:
+ assert(line == blobhash+b" missing\n")
+ return None
+ size = int(size) # Convert e.g. b'6283' to 6283
+ assert(oidtype == b'blob')
+ contents_plus_newline = self._cat_file_process.stdout.read(size+1)
+ return contents_plus_newline[:-1] # return all but the newline
+
+ def get_size_by_identifier(self, blobhash):
+ self._cat_file_process.stdin.write(b'info '+blobhash+b'\n')
+ self._cat_file_process.stdin.flush()
+ line = self._cat_file_process.stdout.readline()
+ (oid, oidtype, size) = line.split()
+ size = int(size) # Convert e.g. b'6283' to 6283
+ assert(oidtype == b'blob')
+ return size
+
+ def insert_file_with_contents(self, contents):
+ blob = Blob(contents)
+ self._insert_blob_func(blob)
+ return blob.id
+
+ def is_binary(self, contents):
+ return b"\0" in contents[0:8192]
+
+ def apply_replace_text(self, contents):
+ new_contents = contents
+ for literal, replacement in self._replace_text['literals']:
+ new_contents = new_contents.replace(literal, replacement)
+ for regex, replacement in self._replace_text['regexes']:
+ new_contents = regex.sub(replacement, new_contents)
+ return new_contents
+
+class LFSObjectTracker:
+ class LFSObjs:
+ def __init__(self):
+ self.id_to_object_map = {}
+ self.objects = set()
+
+ def __init__(self, file_info, check_sources, check_targets):
+ self.source_objects = LFSObjectTracker.LFSObjs()
+ self.target_objects = LFSObjectTracker.LFSObjs()
+ self.hash_to_object_map = {}
+ self.file_info = file_info
+ self.check_sources = check_sources
+ self.check_targets = check_targets
+ self.objects_orphaned = False
+
+ def _get_lfs_values(self, contents):
+ values = {}
+ if len(contents) > 1024:
+ return {}
+ for line in contents.splitlines():
+ try:
+ (key, value) = line.split(b' ', 1)
+ except ValueError:
+ return {}
+ if not values and key != b'version':
+ return values
+ values[key] = value
+ return values
+
+ def check_blob_data(self, contents, fast_export_id, source):
+ if source and not self.check_sources:
+ return
+ mymap = self.source_objects if source else self.target_objects
+ lfs_object_id = self._get_lfs_values(contents).get(b'oid')
+ if lfs_object_id:
+ mymap.id_to_object_map[fast_export_id] = lfs_object_id
+
+ def check_file_change_data(self, git_id, source):
+ if source and not self.check_sources:
+ return
+ mymap = self.source_objects if source else self.target_objects
+ if isinstance(git_id, int):
+ lfs_object_id = mymap.id_to_object_map.get(git_id)
+ if lfs_object_id:
+ mymap.objects.add(lfs_object_id)
+ else:
+ if git_id in self.hash_to_object_map:
+ mymap.objects.add(self.hash_to_object_map[git_id])
+ return
+ size = self.file_info.get_size_by_identifier(git_id)
+ if size >= 1024:
+ return
+ contents = self.file_info.get_contents_by_identifier(git_id)
+ lfs_object_id = self._get_lfs_values(contents).get(b'oid')
+ if lfs_object_id:
+ self.hash_to_object_map[git_id] = lfs_object_id
+ mymap.objects.add(lfs_object_id)
+
+ def check_output_object(self, obj):
+ if not self.check_targets:
+ return
+ if type(obj) == Blob:
+ self.check_blob_data(obj.data, obj.id, False)
+ elif type(obj) == Commit:
+ for change in obj.file_changes:
+ sys.stdout.flush()
+ if change.type != b'M' or change.mode == b'160000':
+ continue
+ self.check_file_change_data(change.blob_id, False)
+
+ def find_all_lfs_objects_in_repo(self, repo, source):
+ if not source:
+ self.file_info = FileInfoValueHelper(None, None, repo)
+ p = subproc.Popen(["git", "rev-list", "--objects", "--all"],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ cwd=repo)
+ for line in p.stdout.readlines():
+ try:
+ (git_oid, filename) = line.split()
+ except ValueError:
+ # Commit and tree objects only have oid
+ continue
+
+ mymap = self.source_objects if source else self.target_objects
+ size = self.file_info.get_size_by_identifier(git_oid)
+ if size >= 1024:
+ continue
+ contents = self.file_info.get_contents_by_identifier(git_oid)
+ lfs_object_id = self._get_lfs_values(contents).get(b'oid')
+ if lfs_object_id:
+ mymap.objects.add(lfs_object_id)
+ if not source:
+ self.file_info.finalize()
+
+class InputFileBackup:
+ def __init__(self, input_file, output_file):
+ self.input_file = input_file
+ self.output_file = output_file
+
+ def close(self):
+ self.input_file.close()
+ self.output_file.close()
+
+ def read(self, size):
+ output = self.input_file.read(size)
+ self.output_file.write(output)
+ return output
+
+ def readline(self):
+ line = self.input_file.readline()
+ self.output_file.write(line)
+ return line
+
+class DualFileWriter:
+ def __init__(self, file1, file2):
+ self.file1 = file1
+ self.file2 = file2
+
+ def write(self, *args):
+ self.file1.write(*args)
+ self.file2.write(*args)
+
+ def flush(self):
+ self.file1.flush()
+ self.file2.flush()
+
+ def close(self):
+ self.file1.close()
+ self.file2.close()
+
+class RepoFilter(object):
+ def __init__(self,
+ args,
+ filename_callback = None,
+ message_callback = None,
+ name_callback = None,
+ email_callback = None,
+ refname_callback = None,
+ blob_callback = None,
+ commit_callback = None,
+ tag_callback = None,
+ reset_callback = None,
+ done_callback = None,
+ file_info_callback = None):
+
+ self._args = args
+
+ # Repo we are exporting
+ self._repo_working_dir = None
+
+ # Store callbacks for acting on objects printed by FastExport
+ self._blob_callback = blob_callback
+ self._commit_callback = commit_callback
+ self._tag_callback = tag_callback
+ self._reset_callback = reset_callback
+ self._done_callback = done_callback
+
+ # Store callbacks for acting on slices of FastExport objects
+ self._filename_callback = filename_callback # filenames from commits
+ self._message_callback = message_callback # commit OR tag message
+ self._name_callback = name_callback # author, committer, tagger
+ self._email_callback = email_callback # author, committer, tagger
+ self._refname_callback = refname_callback # from commit/tag/reset
+ self._file_info_callback = file_info_callback # various file info
+ self._handle_arg_callbacks()
+
+ # Helpers for callbacks
+ self._file_info_value = None
+
+ # Defaults for input
+ self._input = None
+ self._fep = None # Fast Export Process
+ self._fe_orig = None # Path to where original fast-export output stored
+ self._fe_filt = None # Path to where filtered fast-export output stored
+ self._parser = None # FastExportParser object we are working with
+
+ # Defaults for output
+ self._output = None
+ self._fip = None # Fast Import Process
+ self._import_pipes = None
+ self._managed_output = True
+
+ # A tuple of (depth, list-of-ancestors). Commits and ancestors are
+ # identified by their id (their 'mark' in fast-export or fast-import
+ # speak). The depth of a commit is one more than the max depth of any
+ # of its ancestors.
+ self._graph = AncestryGraph()
+ # Another one, for ancestry of commits in the original repo
+ self._orig_graph = AncestryGraph()
+
+ # Names of files that were tweaked in any commit; such paths could lead
+ # to subsequent commits being empty
+ self._files_tweaked = set()
+
+ # A set of commit hash pairs (oldhash, newhash) which used to be merge
+ # commits but due to filtering were turned into non-merge commits.
+ # The commits probably have suboptimal commit messages (e.g. "Merge branch
+ # next into master").
+ self._commits_no_longer_merges = []
+
+ # A dict of original_ids to new_ids; filtering commits means getting
+ # new commit hash (sha1sums), and we record the mapping both for
+ # diagnostic purposes and so we can rewrite commit messages. Note that
+ # the new_id can be None rather than a commit hash if the original
+ # commit became empty and was pruned or was otherwise dropped.
+ self._commit_renames = {}
+
+ # A set of original_ids (i.e. original hashes) for which we have not yet
+ # gotten the new hashses; the value is always the corresponding fast-export
+ # id (i.e. commit.id)
+ self._pending_renames = collections.OrderedDict()
+
+ # A dict of commit_hash[0:7] -> set(commit_hashes with that prefix).
+ #
+ # It's common for commit messages to refer to commits by abbreviated
+ # commit hashes, as short as 7 characters. To facilitate translating
+ # such short hashes, we have a mapping of prefixes to full old hashes.
+ self._commit_short_old_hashes = collections.defaultdict(set)
+
+ # A set of commit hash references appearing in commit messages which
+ # mapped to a valid commit that was removed entirely in the filtering
+ # process. The commit message will continue to reference the
+ # now-missing commit hash, since there was nothing to map it to.
+ self._commits_referenced_but_removed = set()
+
+ # Other vars related to metadata tracking
+ self._already_ran = False
+ self._changed_refs = set()
+ self._lfs_object_tracker = None
+
+ # Progress handling (number of commits parsed, etc.)
+ self._progress_writer = ProgressWriter()
+ self._num_commits = 0
+
+ # Size of blobs in the repo
+ self._unpacked_size = {}
+
+ # Other vars
+ self._sanity_checks_handled = False
+ self._finalize_handled = False
+ self._orig_refs = None
+ self._config_settings = {}
+ self._newnames = {}
+ self._stash = None
+
+ # Cache a few message translations for performance reasons
+ self._parsed_message = _("Parsed %d commits")
+
+ # Compile some regexes and cache those
+ self._hash_re = re.compile(br'(\b[0-9a-f]{7,40}\b)')
+
+ def _handle_arg_callbacks(self):
+ def make_callback(args, bdy):
+ callback_globals = {g: globals()[g] for g in public_globals}
+ callback_locals = {}
+ if type(args) == str:
+ args = (args, '_do_not_use_this_var = None')
+ exec('def callback({}):\n'.format(', '.join(args))+
+ ' '+'\n '.join(bdy.splitlines()), callback_globals, callback_locals)
+ return callback_locals['callback']
+ def handle(which, args=None):
+ which_under = which.replace('-','_')
+ if not args:
+ args = which
+ callback_field = '_{}_callback'.format(which_under)
+ code_string = getattr(self._args, which_under+'_callback')
+ if code_string:
+ if os.path.exists(code_string):
+ with open(code_string, 'r', encoding='utf-8') as f:
+ code_string = f.read()
+ if getattr(self, callback_field):
+ raise SystemExit(_("Error: Cannot pass a %s_callback to RepoFilter "
+ "AND pass --%s-callback"
+ % (which_under, which)))
+ if 'return ' not in code_string and \
+ which not in ('blob', 'commit', 'tag', 'reset'):
+ raise SystemExit(_("Error: --%s-callback should have a return statement")
+ % which)
+ setattr(self, callback_field, make_callback(args, code_string))
+ handle('filename')
+ handle('message')
+ handle('name')
+ handle('email')
+ handle('refname')
+ handle('blob')
+ handle('commit')
+ handle('tag')
+ handle('reset')
+ handle('file-info', ('filename', 'mode', 'blob_id', 'value'))
+
+ def _run_sanity_checks(self):
+ self._sanity_checks_handled = True
+ if not self._managed_output:
+ if not self._args.replace_refs:
+ # If not _managed_output we don't want to make extra changes to the
+ # repo, so set default to no-op 'update-no-add'
+ self._args.replace_refs = 'update-no-add'
+ return
+
+ if self._args.debug:
+ print("[DEBUG] Passed arguments:\n{}".format(self._args))
+
+ # Determine basic repository information
+ target_working_dir = self._args.target or b'.'
+ self._orig_refs = GitUtils.get_refs(target_working_dir)
+ is_bare = GitUtils.is_repository_bare(target_working_dir)
+ self._config_settings = GitUtils.get_config_settings(target_working_dir)
+
+ # Determine if this is second or later run of filter-repo
+ tmp_dir = self.results_tmp_dir(create_if_missing=False)
+ ran_path = os.path.join(tmp_dir, b'already_ran')
+ self._already_ran = os.path.isfile(ran_path)
+ if self._already_ran:
+ current_time = time.time()
+ file_mod_time = os.path.getmtime(ran_path)
+ file_age = current_time - file_mod_time
+ if file_age > 86400: # file older than a day
+ msg = (f"The previous run is older than a day ({decode(ran_path)} already exists).\n"
+ f"See \"Already Ran\" section in the manual for more information.\n"
+ f"Treat this run as a continuation of filtering in the previous run (Y/N)? ")
+ response = input(msg)
+
+ if response.lower() != 'y':
+ os.remove(ran_path)
+ self._already_ran = False
+
+ # Interaction between --already-ran and --sensitive_data_removal
+ msg = textwrap.dedent(_("""\
+ Error: Cannot specify --sensitive-data-removal on a follow-up invocation
+ of git-filter-repo unless it was specified in previously runs."""))
+ if self._already_ran:
+ sdr_path = os.path.join(tmp_dir, b'sensitive_data_removal')
+ sdr_previously = os.path.isfile(sdr_path)
+ if not sdr_previously and self._args.sensitive_data_removal:
+ raise SystemExit(msg)
+ # Treat this as a --sensitive-data-removal run if a previous run was,
+ # even if it wasn't specified this time
+ self._args.sensitive_data_removal = sdr_previously
+
+ # Have to check sensitive_data_removal interactions here instead of
+ # sanity_check_args because of the above interaction with already_ran stuff
+ if self._args.sensitive_data_removal:
+ if self._args.stdin:
+ msg = _("Error: sensitive data removal is incompatible with --stdin")
+ raise SystemExit(msg)
+ if self._args.source or self._args.target:
+ msg = _("Error: sensitive data removal is incompatible with --source and --target")
+ raise SystemExit(msg)
+
+ # Default for --replace-refs
+ if not self._args.replace_refs:
+ self._args.replace_refs = 'delete-no-add'
+ if self._args.replace_refs == 'old-default':
+ self._args.replace_refs = ('update-or-add' if self._already_ran
+ else 'update-and-add')
+
+ # Do sanity checks from the correct directory
+ if not self._args.force and not self._already_ran:
+ cwd = os.getcwd()
+ os.chdir(target_working_dir)
+ RepoFilter.sanity_check(self._orig_refs, is_bare, self._config_settings)
+ os.chdir(cwd)
+
+ def _setup_lfs_orphaning_checks(self):
+ # Do a couple checks to see if we want to do lfs orphaning checks
+ if not self._args.sensitive_data_removal:
+ return
+ metadata_dir = self.results_tmp_dir()
+ lfs_objects_file = os.path.join(metadata_dir, b'original_lfs_objects')
+ if self._already_ran:
+ # Check if we did lfs filtering in the previous run
+ if not os.path.isfile(lfs_objects_file):
+ return
+
+ # Set up self._file_info_value so we can query git for stuff
+ source_working_dir = self._args.source or b'.'
+ self._file_info_value = FileInfoValueHelper(self._args.replace_text,
+ self.insert,
+ source_working_dir)
+
+ # One more check to see if we want to do lfs orphaning checks
+ if not self._already_ran:
+ # Check if lfs filtering is active in HEAD's .gitattributes file
+ a = self._file_info_value.get_contents_by_identifier(b"HEAD:.gitattributes")
+ if not a or not re.search(rb'\bfilter=lfs\b', a):
+ return
+
+ # Set up the object tracker
+ check_sources = not self._already_ran and not self._args.partial
+ check_targets = not self._args.partial
+ self._lfs_object_tracker = LFSObjectTracker(self._file_info_value,
+ check_sources,
+ check_targets)
+ self._parser._lfs_object_tracker = self._lfs_object_tracker # kinda gross
+
+ # Get initial objects
+ if self._already_ran:
+ with open(lfs_objects_file, 'br') as f:
+ for line in f:
+ self._lfs_object_tracker.source_objects.objects.add(line.strip())
+ elif self._args.partial:
+ source = True
+ self._lfs_object_tracker.find_all_lfs_objects_in_repo(source_working_dir,
+ source)
+
+ @staticmethod
+ def loose_objects_are_replace_refs(git_dir, refs, num_loose_objects):
+ replace_objects = set()
+ for refname, rev in refs.items():
+ if not refname.startswith(b'refs/replace/'):
+ continue
+ replace_objects.add(rev)
+
+ validobj_re = re.compile(rb'^[0-9a-f]{40}$')
+ object_dir=os.path.join(git_dir, b'objects')
+ for root, dirs, files in os.walk(object_dir):
+ for filename in files:
+ objname = os.path.basename(root)+filename
+ if objname not in replace_objects and validobj_re.match(objname):
+ return False
+
+ return True
+
+ @staticmethod
+ def sanity_check(refs, is_bare, config_settings):
+ def abort(reason):
+ dirname = config_settings.get(b'remote.origin.url', b'')
+ msg = ""
+ if dirname and os.path.isdir(dirname):
+ msg = _("Note: when cloning local repositories, you need to pass\n"
+ " --no-local to git clone to avoid this issue.\n")
+ raise SystemExit(
+ _("Aborting: Refusing to destructively overwrite repo history since\n"
+ "this does not look like a fresh clone.\n"
+ " (%s)\n%s"
+ "Please operate on a fresh clone instead. If you want to proceed\n"
+ "anyway, use --force.") % (reason, msg))
+
+ # Avoid letting people running with weird setups and overwriting GIT_DIR
+ # elsewhere
+ git_dir = GitUtils.determine_git_dir(b'.')
+ if is_bare and git_dir != b'.':
+ abort(_("GIT_DIR must be ."))
+ elif not is_bare and git_dir != b'.git':
+ abort(_("GIT_DIR must be .git"))
+
+ # Check for refname collisions
+ if config_settings.get(b'core.ignorecase', b'false') == b'true':
+ collisions = collections.defaultdict(list)
+ for ref in refs:
+ collisions[ref.lower()].append(ref)
+ msg = ""
+ for ref in collisions:
+ if len(collisions[ref]) >= 2:
+ msg += " " + decode(b", ".join(collisions[ref])) + "\n"
+ if msg:
+ raise SystemExit(
+ _("Aborting: Cannot rewrite history on a case insensitive\n"
+ "filesystem since you have refs that differ in case only:\n"
+ "%s") % msg)
+ if config_settings.get(b'core.precomposeunicode', b'false') == b'true':
+ import unicodedata # Mac users need to have python-3.8
+ collisions = collections.defaultdict(list)
+ for ref in refs:
+ strref = decode(ref)
+ collisions[unicodedata.normalize('NFC', strref)].append(strref)
+ msg = ""
+ for ref in collisions:
+ if len(collisions[ref]) >= 2:
+ msg += " " + ", ".join(collisions[ref]) + "\n"
+ if msg:
+ raise SystemExit(
+ _("Aborting: Cannot rewrite history on a character normalizing\n"
+ "filesystem since you have refs that differ in normalization:\n"
+ "%s") % msg)
+
+ # Make sure repo is fully packed, just like a fresh clone would be.
+ # Note that transfer.unpackLimit defaults to 100, meaning that a
+ # repository with no packs and less than 100 objects should be considered
+ # fully packed.
+ output = subproc.check_output('git count-objects -v'.split())
+ stats = dict(x.split(b': ') for x in output.splitlines())
+ num_packs = int(stats[b'packs'])
+ num_loose_objects = int(stats[b'count'])
+ if num_packs > 1 or \
+ num_loose_objects >= 100 or \
+ (num_packs == 1 and num_loose_objects > 0 and
+ not RepoFilter.loose_objects_are_replace_refs(git_dir, refs,
+ num_loose_objects)):
+ abort(_("expected freshly packed repo"))
+
+ # Make sure there is precisely one remote, named "origin"...or that this
+ # is a new bare repo with no packs and no remotes
+ output = subproc.check_output('git remote'.split()).strip()
+ if not (output == b"origin" or (num_packs == 0 and not output)):
+ abort(_("expected one remote, origin"))
+
+ # Make sure that all reflogs have precisely one entry
+ reflog_dir=os.path.join(git_dir, b'logs')
+ for root, dirs, files in os.walk(reflog_dir):
+ for filename in files:
+ pathname = os.path.join(root, filename)
+ with open(pathname, 'br') as f:
+ if len(f.read().splitlines()) > 1:
+ shortpath = pathname[len(reflog_dir)+1:]
+ abort(_("expected at most one entry in the reflog for %s") %
+ decode(shortpath))
+
+ # Make sure there are no stashed changes
+ if b'refs/stash' in refs:
+ abort(_("has stashed changes"))
+
+ # Do extra checks in non-bare repos
+ if not is_bare:
+ # Avoid uncommitted, unstaged, or untracked changes
+ if subproc.call('git diff --staged --quiet'.split()):
+ abort(_("you have uncommitted changes"))
+ if subproc.call('git diff --quiet'.split()):
+ abort(_("you have unstaged changes"))
+ untracked_output = subproc.check_output('git ls-files -o'.split())
+ if len(untracked_output) > 0:
+ uf = untracked_output.rstrip(b'\n').split(b'\n')
+ # Since running git-filter-repo can result in files being written to
+ # __pycache__ (depending on python version, env vars, etc.), let's
+ # ignore those as far as "clean clone" is concerned.
+ relevant_uf = [x for x in uf
+ if not x.startswith(b'__pycache__/git_filter_repo.')]
+ if len(relevant_uf) > 0:
+ abort(_("you have untracked changes"))
+
+ # Avoid unpushed changes
+ for refname, rev in refs.items():
+ if not refname.startswith(b'refs/heads/'):
+ continue
+ origin_ref = refname.replace(b'refs/heads/', b'refs/remotes/origin/')
+ if origin_ref not in refs:
+ abort(_('%s exists, but %s not found') % (decode(refname),
+ decode(origin_ref)))
+ if rev != refs[origin_ref]:
+ abort(_('%s does not match %s') % (decode(refname),
+ decode(origin_ref)))
+
+ # Make sure there is only one worktree
+ output = subproc.check_output('git worktree list'.split())
+ if len(output.splitlines()) > 1:
+ abort(_('you have multiple worktrees'))
+
+ def cleanup(self, repo, repack, reset,
+ run_quietly=False, show_debuginfo=False):
+ ''' cleanup repo; if repack then expire reflogs and do a gc --prune=now.
+ if reset then do a reset --hard. Optionally also curb output if
+ run_quietly is True, or go the opposite direction and show extra
+ output if show_debuginfo is True. '''
+ assert not (run_quietly and show_debuginfo)
+
+ if (repack and not run_quietly and not show_debuginfo):
+ print(_("Repacking your repo and cleaning out old unneeded objects"))
+ quiet_flags = '--quiet' if run_quietly else ''
+ cleanup_cmds = []
+ if repack:
+ cleanup_cmds = ['git reflog expire --expire=now --all'.split(),
+ 'git gc {} --prune=now'.format(quiet_flags).split()]
+ if reset:
+ cleanup_cmds.insert(0, 'git reset {} --hard'.format(quiet_flags).split())
+ location_info = ' (in {})'.format(decode(repo)) if repo != b'.' else ''
+ for cmd in cleanup_cmds:
+ if show_debuginfo:
+ print("[DEBUG] Running{}: {}".format(location_info, ' '.join(cmd)))
+ ret = subproc.call(cmd, cwd=repo)
+ if ret != 0:
+ raise SystemExit("fatal: running '%s' failed!" % ' '.join(cmd))
+ if cmd[0:3] == 'git reflog expire'.split():
+ self._write_stash()
+
+ def _get_rename(self, old_hash):
+ # If we already know the rename, just return it
+ new_hash = self._commit_renames.get(old_hash, None)
+ if new_hash:
+ return new_hash
+
+ # If it's not in the remaining pending renames, we don't know it
+ if old_hash is not None and old_hash not in self._pending_renames:
+ return None
+
+ # Read through the pending renames until we find it or we've read them all,
+ # and return whatever we might find
+ self._flush_renames(old_hash)
+ return self._commit_renames.get(old_hash, None)
+
+ def _flush_renames(self, old_hash=None, limit=0):
+ # Parse through self._pending_renames until we have read enough. We have
+ # read enough if:
+ # self._pending_renames is empty
+ # old_hash != None and we found a rename for old_hash
+ # limit > 0 and len(self._pending_renames) started less than 2*limit
+ # limit > 0 and len(self._pending_renames) < limit
+ if limit and len(self._pending_renames) < 2 * limit:
+ return
+ fi_input, fi_output = self._import_pipes
+ while self._pending_renames:
+ orig_hash, new_fast_export_id = self._pending_renames.popitem(last=False)
+ new_hash = fi_output.readline().rstrip()
+ self._commit_renames[orig_hash] = new_hash
+ self._graph.record_hash(new_fast_export_id, new_hash)
+ if old_hash == orig_hash:
+ return
+ if limit and len(self._pending_renames) < limit:
+ return
+
+ def _translate_commit_hash(self, matchobj_or_oldhash):
+ old_hash = matchobj_or_oldhash
+ if not isinstance(matchobj_or_oldhash, bytes):
+ old_hash = matchobj_or_oldhash.group(1)
+ orig_len = len(old_hash)
+ new_hash = self._get_rename(old_hash)
+ if new_hash is None:
+ if old_hash[0:7] not in self._commit_short_old_hashes:
+ self._commits_referenced_but_removed.add(old_hash)
+ return old_hash
+ possibilities = self._commit_short_old_hashes[old_hash[0:7]]
+ matches = [x for x in possibilities
+ if x[0:orig_len] == old_hash]
+ if len(matches) != 1:
+ self._commits_referenced_but_removed.add(old_hash)
+ return old_hash
+ old_hash = matches[0]
+ new_hash = self._get_rename(old_hash)
+
+ assert new_hash is not None
+ return new_hash[0:orig_len]
+
+ def _maybe_trim_extra_parents(self, orig_parents, parents):
+ '''Due to pruning of empty commits, some parents could be non-existent
+ (None) or otherwise redundant. Remove the non-existent parents, and
+ remove redundant parents ***SO LONG AS*** that doesn't transform a
+ merge commit into a non-merge commit.
+
+ Returns a tuple:
+ (parents, new_first_parent_if_would_become_non_merge)'''
+
+ always_prune = (self._args.prune_degenerate == 'always')
+
+ # Pruning of empty commits means multiple things:
+ # * An original parent of this commit may have been pruned causing the
+ # need to rewrite the reported parent to the nearest ancestor. We
+ # want to know when we're dealing with such a parent.
+ # * Further, there may be no "nearest ancestor" if the entire history
+ # of that parent was also pruned. (Detectable by the parent being
+ # 'None')
+ # Remove all parents rewritten to None, and keep track of which parents
+ # were rewritten to an ancestor.
+ tmp = zip(parents,
+ orig_parents,
+ [(x in _SKIPPED_COMMITS or always_prune) for x in orig_parents])
+ tmp2 = [x for x in tmp if x[0] is not None]
+ if not tmp2:
+ # All ancestors have been pruned; we have no parents.
+ return [], None
+ parents, orig_parents, is_rewritten = [list(x) for x in zip(*tmp2)]
+
+ # We can't have redundant parents if we don't have at least 2 parents
+ if len(parents) < 2:
+ return parents, None
+
+ # Don't remove redundant parents if user doesn't want us to
+ if self._args.prune_degenerate == 'never':
+ return parents, None
+
+ # Remove duplicate parents (if both sides of history have lots of commits
+ # which become empty due to pruning, the most recent ancestor on both
+ # sides may be the same commit), except only remove parents that have
+ # been rewritten due to previous empty pruning.
+ seen = set()
+ seen_add = seen.add
+ # Deleting duplicate rewritten parents means keeping parents if either
+ # they have not been seen or they are ones that have not been rewritten.
+ parents_copy = parents
+ uniq = [[p, orig_parents[i], is_rewritten[i]] for i, p in enumerate(parents)
+ if not (p in seen or seen_add(p)) or not is_rewritten[i]]
+ parents, orig_parents, is_rewritten = [list(x) for x in zip(*uniq)]
+ if len(parents) < 2:
+ return parents_copy, parents[0]
+
+ # Flatten unnecessary merges. (If one side of history is entirely
+ # empty commits that were pruned, we may end up attempting to
+ # merge a commit with its ancestor. Remove parents that are an
+ # ancestor of another parent.)
+ num_parents = len(parents)
+ to_remove = []
+ for cur in range(num_parents):
+ if not is_rewritten[cur]:
+ continue
+ for other in range(num_parents):
+ if cur == other:
+ continue
+ if not self._graph.is_ancestor(parents[cur], parents[other]):
+ continue
+ # parents[cur] is an ancestor of parents[other], so parents[cur]
+ # seems redundant. However, if it was intentionally redundant
+ # (e.g. a no-ff merge) in the original, then we want to keep it.
+ if not always_prune and \
+ self._orig_graph.is_ancestor(orig_parents[cur],
+ orig_parents[other]):
+ continue
+ # Some folks want their history to have all first parents be merge
+ # commits (except for any root commits), and always do a merge --no-ff.
+ # For such folks, don't remove the first parent even if it's an
+ # ancestor of other commits.
+ if self._args.no_ff and cur == 0:
+ continue
+ # Okay so the cur-th parent is an ancestor of the other-th parent,
+ # and it wasn't that way in the original repository; mark the
+ # cur-th parent as removable.
+ to_remove.append(cur)
+ break # cur removed, so skip rest of others -- i.e. check cur+=1
+ for x in reversed(to_remove):
+ parents.pop(x)
+ if len(parents) < 2:
+ return parents_copy, parents[0]
+
+ return parents, None
+
+ def _prunable(self, commit, new_1st_parent, had_file_changes, orig_parents):
+ parents = commit.parents
+
+ if self._args.prune_empty == 'never':
+ return False
+ always_prune = (self._args.prune_empty == 'always')
+
+ # For merge commits, unless there are prunable (redundant) parents, we
+ # do not want to prune
+ if len(parents) >= 2 and not new_1st_parent:
+ return False
+
+ if len(parents) < 2:
+ # Special logic for commits that started empty...
+ if not had_file_changes and not always_prune:
+ had_parents_pruned = (len(parents) < len(orig_parents) or
+ (len(orig_parents) == 1 and
+ orig_parents[0] in _SKIPPED_COMMITS))
+ # If the commit remains empty and had parents which were pruned,
+ # then prune this commit; otherwise, retain it
+ return (not commit.file_changes and had_parents_pruned)
+
+ # We can only get here if the commit didn't start empty, so if it's
+ # empty now, it obviously became empty
+ if not commit.file_changes:
+ return True
+
+ # If there are no parents of this commit and we didn't match the case
+ # above, then this commit cannot be pruned. Since we have no parent(s)
+ # to compare to, abort now to prevent future checks from failing.
+ if not parents:
+ return False
+
+ # Similarly, we cannot handle the hard cases if we don't have a pipe
+ # to communicate with fast-import
+ if not self._import_pipes:
+ return False
+
+ # If there have not been renames/remappings of IDs (due to insertion of
+ # new blobs), then we can sometimes know things aren't prunable with a
+ # simple check
+ if not _IDS.has_renames():
+ # non-merge commits can only be empty if blob/file-change editing caused
+ # all file changes in the commit to have the same file contents as
+ # the parent.
+ changed_files = set(change.filename for change in commit.file_changes)
+ if len(orig_parents) < 2 and changed_files - self._files_tweaked:
+ return False
+
+ # Finally, the hard case: due to either blob rewriting, or due to pruning
+ # of empty commits wiping out the first parent history back to the merge
+ # base, the list of file_changes we have may not actually differ from our
+ # (new) first parent's version of the files, i.e. this would actually be
+ # an empty commit. Check by comparing the contents of this commit to its
+ # (remaining) parent.
+ #
+ # NOTE on why this works, for the case of original first parent history
+ # having been pruned away due to being empty:
+ # The first parent history having been pruned away due to being
+ # empty implies the original first parent would have a tree (after
+ # filtering) that matched the merge base's tree. Since
+ # file_changes has the changes needed to go from what would have
+ # been the first parent to our new commit, and what would have been
+ # our first parent has a tree that matches the merge base, then if
+ # the new first parent has a tree matching the versions of files in
+ # file_changes, then this new commit is empty and thus prunable.
+ fi_input, fi_output = self._import_pipes
+ self._flush_renames() # Avoid fi_output having other stuff present
+ # Optimization note: we could have two loops over file_changes, the
+ # first doing all the self._output.write() calls, and the second doing
+ # the rest. But I'm worried about fast-import blocking on fi_output
+ # buffers filling up so I instead read from it as I go.
+ for change in commit.file_changes:
+ parent = new_1st_parent or commit.parents[0] # exists due to above checks
+ quoted_filename = PathQuoting.enquote(change.filename)
+ if isinstance(parent, int):
+ self._output.write(b"ls :%d %s\n" % (parent, quoted_filename))
+ else:
+ self._output.write(b"ls %s %s\n" % (parent, quoted_filename))
+ self._output.flush()
+ parent_version = fi_output.readline().split()
+ if change.type == b'D':
+ if parent_version != [b'missing', quoted_filename]:
+ return False
+ else:
+ blob_sha = change.blob_id
+ if isinstance(change.blob_id, int):
+ self._output.write(b"get-mark :%d\n" % change.blob_id)
+ self._output.flush()
+ blob_sha = fi_output.readline().rstrip()
+ if parent_version != [change.mode, b'blob', blob_sha, quoted_filename]:
+ return False
+
+ return True
+
+ def _record_remapping(self, commit, orig_parents):
+ new_id = None
+ # Record the mapping of old commit hash to new one
+ if commit.original_id and self._import_pipes:
+ fi_input, fi_output = self._import_pipes
+ self._output.write(b"get-mark :%d\n" % commit.id)
+ self._output.flush()
+ orig_id = commit.original_id
+ self._commit_short_old_hashes[orig_id[0:7]].add(orig_id)
+ # Note that we have queued up an id for later reading; flush a
+ # few of the older ones if we have too many queued up
+ self._pending_renames[orig_id] = commit.id
+ self._flush_renames(None, limit=40)
+ # Also, record if this was a merge commit that turned into a non-merge
+ # commit.
+ if len(orig_parents) >= 2 and len(commit.parents) < 2:
+ self._commits_no_longer_merges.append((commit.original_id, new_id))
+
+ def callback_metadata(self, extra_items = dict()):
+ return {'commit_rename_func': self._translate_commit_hash,
+ 'ancestry_graph': self._graph,
+ 'original_ancestry_graph': self._orig_graph,
+ **extra_items}
+
+ def _tweak_blob(self, blob):
+ if self._args.max_blob_size and len(blob.data) > self._args.max_blob_size:
+ blob.skip()
+
+ if blob.original_id in self._args.strip_blobs_with_ids:
+ blob.skip()
+
+ if ( self._args.replace_text
+ and not self._file_info_callback
+ # not (if blob contains zero byte in the first 8Kb, that is, if blob is binary data)
+ and not b"\0" in blob.data[0:8192]
+ ):
+ for literal, replacement in self._args.replace_text['literals']:
+ blob.data = blob.data.replace(literal, replacement)
+ for regex, replacement in self._args.replace_text['regexes']:
+ blob.data = regex.sub(replacement, blob.data)
+
+ if self._blob_callback:
+ self._blob_callback(blob, self.callback_metadata())
+
+ self._insert_into_stream(blob)
+
+ def _filter_files(self, commit):
+ def filename_matches(path_expression, pathname):
+ ''' Returns whether path_expression matches pathname or a leading
+ directory thereof, allowing path_expression to not have a trailing
+ slash even if it is meant to match a leading directory. '''
+ if path_expression == b'':
+ return True
+ n = len(path_expression)
+ if (pathname.startswith(path_expression) and
+ (path_expression[n-1:n] == b'/' or
+ len(pathname) == n or
+ pathname[n:n+1] == b'/')):
+ return True
+ return False
+
+ def newname(path_changes, pathname, use_base_name, filtering_is_inclusive):
+ ''' Applies filtering and rename changes from path_changes to pathname,
+ returning any of None (file isn't wanted), original filename (file
+ is wanted with original name), or new filename. '''
+ wanted = False
+ full_pathname = pathname
+ if use_base_name:
+ pathname = os.path.basename(pathname)
+ for (mod_type, match_type, path_exp) in path_changes:
+ if mod_type == 'filter' and not wanted:
+ assert match_type in ('match', 'glob', 'regex')
+ if match_type == 'match' and filename_matches(path_exp, pathname):
+ wanted = True
+ if match_type == 'glob' and fnmatch.fnmatch(pathname, path_exp):
+ wanted = True
+ if match_type == 'regex' and path_exp.search(pathname):
+ wanted = True
+ elif mod_type == 'rename':
+ match, repl = path_exp
+ assert match_type in ('match','regex') # glob was translated to regex
+ if match_type == 'match' and filename_matches(match, full_pathname):
+ full_pathname = full_pathname.replace(match, repl, 1)
+ pathname = full_pathname # rename incompatible with use_base_name
+ if match_type == 'regex':
+ full_pathname = match.sub(repl, full_pathname)
+ pathname = full_pathname # rename incompatible with use_base_name
+ return full_pathname if (wanted == filtering_is_inclusive) else None
+
+ args = self._args
+ new_file_changes = {} # Assumes no renames or copies, otherwise collisions
+ for change in commit.file_changes:
+ # NEEDSWORK: _If_ we ever want to pass `--full-tree` to fast-export and
+ # parse that output, we'll need to modify this block; `--full-tree`
+ # issues a deleteall directive which has no filename, and thus this
+ # block would normally strip it. Of course, FileChange() and
+ # _parse_optional_filechange() would need updates too.
+ if change.type == b'DELETEALL':
+ new_file_changes[b''] = change
+ continue
+ if change.filename in self._newnames:
+ change.filename = self._newnames[change.filename]
+ else:
+ original_filename = change.filename
+ change.filename = newname(args.path_changes, change.filename,
+ args.use_base_name, args.inclusive)
+ if self._filename_callback:
+ change.filename = self._filename_callback(change.filename)
+ self._newnames[original_filename] = change.filename
+ if not change.filename:
+ continue # Filtering criteria excluded this file; move on to next one
+ if change.filename in new_file_changes:
+ # Getting here means that path renaming is in effect, and caused one
+ # path to collide with another. That's usually bad, but can be okay
+ # under two circumstances:
+ # 1) Sometimes people have a file named OLDFILE in old revisions of
+ # history, and they rename to NEWFILE, and would like to rewrite
+ # history so that all revisions refer to it as NEWFILE. As such,
+ # we can allow a collision when (at least) one of the two paths
+ # is a deletion. Note that if OLDFILE and NEWFILE are unrelated
+ # this also allows the rewrite to continue, which makes sense
+ # since OLDFILE is no longer in the way.
+ # 2) If OLDFILE and NEWFILE are exactly equal, then writing them
+ # both to the same location poses no problem; we only need one
+ # file. (This could come up if someone copied a file in some
+ # commit, then later either deleted the file or kept it exactly
+ # in sync with the original with any changes, and then decides
+ # they want to rewrite history to only have one of the two files)
+ colliding_change = new_file_changes[change.filename]
+ if change.type == b'D':
+ # We can just throw this one away and keep the other
+ continue
+ elif change.type == b'M' and (
+ change.mode == colliding_change.mode and
+ change.blob_id == colliding_change.blob_id):
+ # The two are identical, so we can throw this one away and keep other
+ continue
+ elif new_file_changes[change.filename].type != b'D':
+ raise SystemExit(_("File renaming caused colliding pathnames!\n") +
+ _(" Commit: {}\n").format(commit.original_id) +
+ _(" Filename: {}").format(change.filename))
+ # Strip files that are too large
+ if self._args.max_blob_size and \
+ self._unpacked_size.get(change.blob_id, 0) > self._args.max_blob_size:
+ continue
+ if self._args.strip_blobs_with_ids and \
+ change.blob_id in self._args.strip_blobs_with_ids:
+ continue
+ # Otherwise, record the change
+ new_file_changes[change.filename] = change
+ commit.file_changes = [v for k,v in sorted(new_file_changes.items())]
+
+ def _tweak_commit(self, commit, aux_info):
+ if self._args.replace_message:
+ for literal, replacement in self._args.replace_message['literals']:
+ commit.message = commit.message.replace(literal, replacement)
+ for regex, replacement in self._args.replace_message['regexes']:
+ commit.message = regex.sub(replacement, commit.message)
+ if self._message_callback:
+ commit.message = self._message_callback(commit.message)
+
+ # Change the commit message according to callback
+ if not self._args.preserve_commit_hashes:
+ commit.message = self._hash_re.sub(self._translate_commit_hash,
+ commit.message)
+
+ # Change the author & committer according to mailmap rules
+ args = self._args
+ if args.mailmap:
+ commit.author_name, commit.author_email = \
+ args.mailmap.translate(commit.author_name, commit.author_email)
+ commit.committer_name, commit.committer_email = \
+ args.mailmap.translate(commit.committer_name, commit.committer_email)
+ # Change author & committer according to callbacks
+ if self._name_callback:
+ commit.author_name = self._name_callback(commit.author_name)
+ commit.committer_name = self._name_callback(commit.committer_name)
+ if self._email_callback:
+ commit.author_email = self._email_callback(commit.author_email)
+ commit.committer_email = self._email_callback(commit.committer_email)
+
+ # Sometimes the 'branch' given is a tag; if so, rename it as requested so
+ # we don't get any old tagnames
+ if self._args.tag_rename:
+ commit.branch = RepoFilter._do_tag_rename(args.tag_rename, commit.branch)
+ if self._refname_callback:
+ commit.branch = self._refname_callback(commit.branch)
+
+ # Filter or rename the list of file changes
+ orig_file_changes = set(commit.file_changes)
+ self._filter_files(commit)
+
+ # Record ancestry graph
+ parents, orig_parents = commit.parents, aux_info['orig_parents']
+ if self._args.state_branch:
+ external_parents = parents
+ else:
+ external_parents = [p for p in parents if not isinstance(p, int)]
+ # The use of 'reversed' is intentional here; there is a risk that we have
+ # duplicates in parents, and we want to map from parents to the first
+ # entry we find in orig_parents in such cases.
+ parent_reverse_dict = dict(zip(reversed(parents), reversed(orig_parents)))
+
+ self._graph.record_external_commits(external_parents)
+ self._orig_graph.record_external_commits(external_parents)
+ self._graph.add_commit_and_parents(commit.id, parents) # new githash unknown
+ self._orig_graph.add_commit_and_parents(commit.old_id, orig_parents,
+ commit.original_id)
+
+ # Prune parents (due to pruning of empty commits) if relevant, note that
+ # new_1st_parent is None unless this was a merge commit that is becoming
+ # a non-merge
+ prev_1st_parent = parents[0] if parents else None
+ parents, new_1st_parent = self._maybe_trim_extra_parents(orig_parents,
+ parents)
+ commit.parents = parents
+
+ # If parents were pruned, then we need our file changes to be relative
+ # to the new first parent
+ #
+ # Notes:
+ # * new_1st_parent and new_1st_parent != parents[0] uniquely happens for example when:
+ # working on merge, selecting subset of files and merge base still
+ # valid while first parent history doesn't touch any of those paths,
+ # but second parent history does. prev_1st_parent had already been
+ # rewritten to the non-None first ancestor and it remains valid.
+ # self._maybe_trim_extra_parents() avoids removing this first parent
+ # because it'd make the commit a non-merge. However, if there are
+ # no file_changes of note, we'll drop this commit and mark
+ # new_1st_parent as the new replacement. To correctly determine if
+ # there are no file_changes of note, we need to have the list of
+ # file_changes relative to new_1st_parent.
+ # (See t9390#3, "basic -> basic-ten using '--path ten'")
+ # * prev_1st_parent != parents[0] happens for example when:
+ # similar to above, but the merge base is no longer valid and was
+ # pruned away as well. Then parents started as e.g. [None, $num],
+ # and both prev_1st_parent and new_1st_parent are None, while parents
+ # after self._maybe_trim_extra_parents() becomes just [$num].
+ # (See t9390#67, "degenerate merge with non-matching filename".)
+ # Since $num was originally a second parent, we need to rewrite
+ # file changes to be relative to parents[0].
+ # * TODO: We should be getting the changes relative to the new first
+ # parent even if self._fep is None, BUT we can't. Our method of
+ # getting the changes right now is an external git diff invocation,
+ # which we can't do if we just have a fast export stream. We can't
+ # really work around it by querying the fast-import stream either,
+ # because the 'ls' directive only allows us to list info about
+ # specific paths, but we need to find out which paths exist in two
+ # commits and then query them. We could maybe force checkpointing in
+ # fast-import, then doing a diff from what'll be the new first parent
+ # back to prev_1st_parent (which may be None, i.e. empty tree), using
+ # the fact that in A->{B,C}->D, where D is merge of B & C, the diff
+ # from C->D == C->A + A->B + B->D, and in these cases A==B, so it
+ # simplifies to C->D == C->A + B->D, and C is our new 1st parent
+ # commit, A is prev_1st_commit, and B->D is commit.file_changes that
+ # we already have. However, checkpointing the fast-import process
+ # and figuring out how long to wait before we can run our diff just
+ # seems excessive. For now, just punt and assume the merge wasn't
+ # "evil" (i.e. that it's remerge-diff is empty, as is true for most
+ # merges). If the merge isn't evil, no further steps are necessary.
+ if parents and self._fep and (
+ prev_1st_parent != parents[0] or
+ new_1st_parent and new_1st_parent != parents[0]):
+ # Get the id from the original fast export stream corresponding to the
+ # new 1st parent. As noted above, that new 1st parent might be
+ # new_1st_parent, or if that is None, it'll be parents[0].
+ will_be_1st = new_1st_parent or parents[0]
+ old_id = parent_reverse_dict[will_be_1st]
+ # Now, translate that to a hash
+ will_be_1st_commit_hash = self._orig_graph.map_to_hash(old_id)
+ # Get the changes from what is going to be the new 1st parent to this
+ # merge commit. Note that since we are going from the new 1st parent
+ # to the merge commit, we can just replace the existing
+ # commit.file_changes rather than getting something we need to combine
+ # with the existing commit.file_changes. Also, we can just replace
+ # because prev_1st_parent is an ancestor of will_be_1st_commit_hash
+ # (or prev_1st_parent is None and first parent history is gone), so
+ # even if we retain prev_1st_parent and do not prune it, the changes
+ # will still work given the snapshot-based way fast-export/fast-import
+ # work.
+ commit.file_changes = GitUtils.get_file_changes(self._repo_working_dir,
+ will_be_1st_commit_hash,
+ commit.original_id)
+
+ # Save these and filter them
+ orig_file_changes = set(commit.file_changes)
+ self._filter_files(commit)
+
+ # Process the --file-info-callback
+ if self._file_info_callback:
+ if self._file_info_value is None:
+ source_working_dir = self._args.source or b'.'
+ self._file_info_value = FileInfoValueHelper(self._args.replace_text,
+ self.insert,
+ source_working_dir)
+ new_file_changes = []
+ for change in commit.file_changes:
+ if change.type != b'D':
+ assert(change.type == b'M')
+ (filename, mode, blob_id) = \
+ self._file_info_callback(change.filename,
+ change.mode,
+ change.blob_id,
+ self._file_info_value)
+ if mode is None:
+ # TODO: Should deletion of the file even be a feature? Might
+ # want to remove this branch of the if-elif-else.
+ assert(filename is not None)
+ assert(blob_id is not None)
+ new_change = FileChange(b'D', filename)
+ elif filename is None:
+ continue # Drop the FileChange from this commit
+ else:
+ new_change = FileChange(b'M', filename, blob_id, mode)
+ else:
+ new_change = change # use change as-is for deletions
+ new_file_changes.append(new_change)
+ commit.file_changes = new_file_changes
+
+ # Call the user-defined callback, if any
+ if self._commit_callback:
+ self._commit_callback(commit, self.callback_metadata(aux_info))
+
+ # Find out which files were modified by the callbacks. Such paths could
+ # lead to subsequent commits being empty (e.g. if removing a line containing
+ # a password from every version of a file that had the password, and some
+ # later commit did nothing more than remove that line)
+ final_file_changes = set(commit.file_changes)
+ if self._args.replace_text or self._blob_callback:
+ differences = orig_file_changes.union(final_file_changes)
+ else:
+ differences = orig_file_changes.symmetric_difference(final_file_changes)
+ self._files_tweaked.update(x.filename for x in differences)
+
+ # Now print the resulting commit, or if prunable skip it
+ if not commit.dumped:
+ if not self._prunable(commit, new_1st_parent,
+ aux_info['had_file_changes'], orig_parents):
+ self._insert_into_stream(commit)
+ self._record_remapping(commit, orig_parents)
+ else:
+ rewrite_to = new_1st_parent or commit.first_parent()
+ commit.skip(new_id = rewrite_to)
+ if self._args.state_branch:
+ alias = Alias(commit.old_id or commit.id, rewrite_to or deleted_hash)
+ self._insert_into_stream(alias)
+ if commit.branch.startswith(b'refs/') or commit.branch == b'HEAD':
+ # The special check above is because when direct revisions are passed
+ # along to fast-export (such as with stashes), there is a chance the
+ # revision is rewritten to nothing. In such cases, we don't want to
+ # point an invalid ref that just names a revision to some other point.
+ reset = Reset(commit.branch, rewrite_to or deleted_hash)
+ self._insert_into_stream(reset)
+ self._commit_renames[commit.original_id] = None
+
+ # Show progress
+ self._num_commits += 1
+ if not self._args.quiet:
+ self._progress_writer.show(self._parsed_message % self._num_commits)
+
+ @staticmethod
+ def _do_tag_rename(rename_pair, tagname):
+ old, new = rename_pair.split(b':', 1)
+ old, new = b'refs/tags/'+old, b'refs/tags/'+new
+ if tagname.startswith(old):
+ return tagname.replace(old, new, 1)
+ return tagname
+
+ def _tweak_tag(self, tag):
+ # Tweak the tag message according to callbacks
+ if self._args.replace_message:
+ for literal, replacement in self._args.replace_message['literals']:
+ tag.message = tag.message.replace(literal, replacement)
+ for regex, replacement in self._args.replace_message['regexes']:
+ tag.message = regex.sub(replacement, tag.message)
+ if self._message_callback:
+ tag.message = self._message_callback(tag.message)
+
+ # Tweak the tag name according to tag-name-related callbacks
+ tag_prefix = b'refs/tags/'
+ fullref = tag_prefix+tag.ref
+ if self._args.tag_rename:
+ fullref = RepoFilter._do_tag_rename(self._args.tag_rename, fullref)
+ if self._refname_callback:
+ fullref = self._refname_callback(fullref)
+ if not fullref.startswith(tag_prefix):
+ msg = "Error: fast-import requires tags to be in refs/tags/ namespace."
+ msg += "\n {} renamed to {}".format(tag_prefix+tag.ref, fullref)
+ raise SystemExit(msg)
+ tag.ref = fullref[len(tag_prefix):]
+
+ # Tweak the tagger according to callbacks
+ if self._args.mailmap:
+ tag.tagger_name, tag.tagger_email = \
+ self._args.mailmap.translate(tag.tagger_name, tag.tagger_email)
+ if self._name_callback:
+ tag.tagger_name = self._name_callback(tag.tagger_name)
+ if self._email_callback:
+ tag.tagger_email = self._email_callback(tag.tagger_email)
+
+ # Call general purpose tag callback
+ if self._tag_callback:
+ self._tag_callback(tag, self.callback_metadata())
+
+ def _tweak_reset(self, reset):
+ if self._args.tag_rename:
+ reset.ref = RepoFilter._do_tag_rename(self._args.tag_rename, reset.ref)
+ if self._refname_callback:
+ reset.ref = self._refname_callback(reset.ref)
+ if self._reset_callback:
+ self._reset_callback(reset, self.callback_metadata())
+
+ def results_tmp_dir(self, create_if_missing=True):
+ target_working_dir = self._args.target or b'.'
+ git_dir = GitUtils.determine_git_dir(target_working_dir)
+ d = os.path.join(git_dir, b'filter-repo')
+ if create_if_missing and not os.path.isdir(d):
+ os.mkdir(d)
+ return d
+
+ def _load_marks_file(self, marks_basename):
+ full_branch = 'refs/heads/{}'.format(self._args.state_branch)
+ marks_file = os.path.join(self.results_tmp_dir(), marks_basename)
+ working_dir = self._args.target or b'.'
+ cmd = ['git', '-C', working_dir, 'show-ref', full_branch]
+ contents = b''
+ if subproc.call(cmd, stdout=subprocess.DEVNULL) == 0:
+ cmd = ['git', '-C', working_dir, 'show',
+ '%s:%s' % (full_branch, decode(marks_basename))]
+ try:
+ contents = subproc.check_output(cmd)
+ except subprocess.CalledProcessError as e: # pragma: no cover
+ raise SystemExit(_("Failed loading %s from %s") %
+ (decode(marks_basename), full_branch))
+ if contents:
+ biggest_id = max(int(x.split()[0][1:]) for x in contents.splitlines())
+ _IDS._next_id = max(_IDS._next_id, biggest_id+1)
+ with open(marks_file, 'bw') as f:
+ f.write(contents)
+ return marks_file
+
+ def _save_marks_files(self):
+ basenames = [b'source-marks', b'target-marks']
+ working_dir = self._args.target or b'.'
+
+ # Check whether the branch exists
+ parent = []
+ full_branch = 'refs/heads/{}'.format(self._args.state_branch)
+ cmd = ['git', '-C', working_dir, 'show-ref', full_branch]
+ if subproc.call(cmd, stdout=subprocess.DEVNULL) == 0:
+ parent = ['-p', full_branch]
+
+ # Run 'git hash-object $MARKS_FILE' for each marks file, save result
+ blob_hashes = {}
+ for marks_basename in basenames:
+ marks_file = os.path.join(self.results_tmp_dir(), marks_basename)
+ if not os.path.isfile(marks_file): # pragma: no cover
+ raise SystemExit(_("Failed to find %s to save to %s")
+ % (marks_file, self._args.state_branch))
+ cmd = ['git', '-C', working_dir, 'hash-object', '-w', marks_file]
+ blob_hashes[marks_basename] = subproc.check_output(cmd).strip()
+
+ # Run 'git mktree' to create a tree out of it
+ p = subproc.Popen(['git', '-C', working_dir, 'mktree'],
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ for b in basenames:
+ p.stdin.write(b'100644 blob %s\t%s\n' % (blob_hashes[b], b))
+ p.stdin.close()
+ p.wait()
+ tree = p.stdout.read().strip()
+
+ # Create the new commit
+ cmd = (['git', '-C', working_dir, 'commit-tree', '-m', 'New mark files',
+ tree] + parent)
+ commit = subproc.check_output(cmd).strip()
+ subproc.call(['git', '-C', working_dir, 'update-ref', full_branch, commit])
+
+ def importer_only(self):
+ self._run_sanity_checks()
+ self._setup_output()
+
+ def set_output(self, outputRepoFilter):
+ assert outputRepoFilter._output
+
+ # set_output implies this RepoFilter is doing exporting, though may not
+ # be the only one.
+ self._setup_input(use_done_feature = False)
+
+ # Set our output management up to pipe to outputRepoFilter's locations
+ self._managed_output = False
+ self._output = outputRepoFilter._output
+ self._import_pipes = outputRepoFilter._import_pipes
+
+ # Handle sanity checks, though currently none needed for export-only cases
+ self._run_sanity_checks()
+
+ def _read_stash(self):
+ if self._stash:
+ return
+ if self._orig_refs and b'refs/stash' in self._orig_refs and \
+ self._args.refs == ['--all']:
+ repo_working_dir = self._args.source or b'.'
+ git_dir = GitUtils.determine_git_dir(repo_working_dir)
+ stash = os.path.join(git_dir, b'logs', b'refs', b'stash')
+ if os.path.exists(stash):
+ self._stash = []
+ with open(stash, 'br') as f:
+ for line in f:
+ (oldhash, newhash, rest) = line.split(None, 2)
+ self._stash.append((newhash, rest))
+ self._args.refs.extend([x[0] for x in self._stash])
+
+ def _write_stash(self):
+ last = deleted_hash
+ if self._stash:
+ target_working_dir = self._args.target or b'.'
+ git_dir = GitUtils.determine_git_dir(target_working_dir)
+ stash = os.path.join(git_dir, b'logs', b'refs', b'stash')
+ with open(stash, 'bw') as f:
+ for (hash, rest) in self._stash:
+ new_hash = self._get_rename(hash)
+ if new_hash is None:
+ continue
+ f.write(b' '.join([last, new_hash, rest]) + b'\n')
+ last = new_hash
+ print(_("Rewrote the stash."))
+
+ def _setup_input(self, use_done_feature):
+ if self._args.stdin:
+ self._input = sys.stdin.detach()
+ sys.stdin = None # Make sure no one tries to accidentally use it
+ self._fe_orig = None
+ else:
+ self._read_stash()
+ skip_blobs = (self._blob_callback is None and
+ (self._args.replace_text is None or
+ self._file_info_callback is not None) and
+ self._args.source == self._args.target)
+ extra_flags = []
+ if skip_blobs:
+ extra_flags.append('--no-data')
+ if self._args.max_blob_size:
+ self._unpacked_size, packed_size = GitUtils.get_blob_sizes()
+ if use_done_feature:
+ extra_flags.append('--use-done-feature')
+ if write_marks:
+ extra_flags.append(b'--mark-tags')
+ if self._args.state_branch:
+ assert(write_marks)
+ source_marks_file = self._load_marks_file(b'source-marks')
+ extra_flags.extend([b'--export-marks='+source_marks_file,
+ b'--import-marks='+source_marks_file])
+ if self._args.preserve_commit_encoding is not None: # pragma: no cover
+ reencode = 'no' if self._args.preserve_commit_encoding else 'yes'
+ extra_flags.append('--reencode='+reencode)
+ if self._args.date_order:
+ extra_flags.append('--date-order')
+ location = ['-C', self._args.source] if self._args.source else []
+ fep_cmd = ['git'] + location + ['fast-export', '--show-original-ids',
+ '--signed-tags=strip', '--tag-of-filtered-object=rewrite',
+ '--fake-missing-tagger', '--reference-excluded-parents'
+ ] + extra_flags + self._args.refs
+ self._fep = subproc.Popen(fep_cmd, bufsize=-1, stdout=subprocess.PIPE)
+ self._input = self._fep.stdout
+ if self._args.dry_run or self._args.debug:
+ self._fe_orig = os.path.join(self.results_tmp_dir(),
+ b'fast-export.original')
+ output = open(self._fe_orig, 'bw')
+ self._input = InputFileBackup(self._input, output)
+ if self._args.debug:
+ tmp = [decode(x) if isinstance(x, bytes) else x for x in fep_cmd]
+ print("[DEBUG] Running: {}".format(' '.join(tmp)))
+ print(" (saving a copy of the output at {})"
+ .format(decode(self._fe_orig)))
+
+ def _setup_output(self):
+ if not self._args.dry_run:
+ location = ['-C', self._args.target] if self._args.target else []
+ fip_cmd = ['git'] + location + ['-c', 'core.ignorecase=false',
+ 'fast-import', '--force', '--quiet']
+ if date_format_permissive:
+ fip_cmd.append('--date-format=raw-permissive')
+ if self._args.state_branch:
+ target_marks_file = self._load_marks_file(b'target-marks')
+ fip_cmd.extend([b'--export-marks='+target_marks_file,
+ b'--import-marks='+target_marks_file])
+ self._fip = subproc.Popen(fip_cmd, bufsize=-1,
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ self._import_pipes = (self._fip.stdin, self._fip.stdout)
+ if self._args.dry_run or self._args.debug:
+ self._fe_filt = os.path.join(self.results_tmp_dir(),
+ b'fast-export.filtered')
+ self._output = open(self._fe_filt, 'bw')
+ else:
+ self._output = self._fip.stdin
+ if self._args.debug and not self._args.dry_run:
+ self._output = DualFileWriter(self._fip.stdin, self._output)
+ tmp = [decode(x) if isinstance(x, bytes) else x for x in fip_cmd]
+ print("[DEBUG] Running: {}".format(' '.join(tmp)))
+ print(" (using the following file as input: {})"
+ .format(decode(self._fe_filt)))
+
+ def _migrate_origin_to_heads(self):
+ source_working_dir = self._args.source or b'.'
+ target_working_dir = self._args.target or b'.'
+ refs_to_migrate = set(x for x in self._orig_refs
+ if x.startswith(b'refs/remotes/origin/'))
+ refs_to_warn_about = set()
+ if refs_to_migrate:
+ if self._args.debug:
+ print("[DEBUG] Migrating refs/remotes/origin/* -> refs/heads/*")
+ p = subproc.Popen('git update-ref --no-deref --stdin'.split(),
+ stdin=subprocess.PIPE, cwd=source_working_dir)
+ for ref in refs_to_migrate:
+ if ref == b'refs/remotes/origin/HEAD':
+ p.stdin.write(b'delete %s %s\n' % (ref, self._orig_refs[ref]))
+ del self._orig_refs[ref]
+ continue
+ newref = ref.replace(b'refs/remotes/origin/', b'refs/heads/')
+ if newref not in self._orig_refs:
+ p.stdin.write(b'create %s %s\n' % (newref, self._orig_refs[ref]))
+ self._orig_refs[newref] = self._orig_refs[ref]
+ elif self._orig_refs[ref] != self._orig_refs[newref]:
+ refs_to_warn_about.add(newref)
+ p.stdin.write(b'delete %s %s\n' % (ref, self._orig_refs[ref]))
+ del self._orig_refs[ref]
+ p.stdin.close()
+ if p.wait(): # pragma: no cover
+ msg = _("git update-ref failed; see above")
+ raise SystemExit(msg)
+
+ if b'remote.origin.url' not in self._config_settings:
+ return
+
+ # For sensitive data removals, fetch ALL refs. Non-mirror clones normally
+ # only grab branches and tags, but other refs may hold on to the sensitive
+ # data as well.
+ if self._args.sensitive_data_removal and \
+ not self._args.no_fetch and \
+ not self._already_ran and \
+ self._config_settings.get(b'remote.origin.mirror', b'false') != b'true':
+
+ if refs_to_warn_about:
+ msg = ("Warning: You have refs modified from upstream:\n " +
+ "\n ".join([decode(x) for x in refs_to_warn_about]) +
+ "\n" +
+ " We want to forcibly fetch from upstream to ensure\n" +
+ " that all relevent refs are rewritten, but this will\n" +
+ " discard your local changes before starting the\n" +
+ " rewrite. Proceed with fetch (Y/N)?")
+ response = input(msg)
+
+ if response.lower() != 'y':
+ self._args.no_fetch = True
+ # Don't do the fetch, and don't remove the origin remote
+ return
+
+ cmd = 'git fetch -q --prune --update-head-ok --refmap "" origin +refs/*:refs/*'
+ m = _("NOTICE: Fetching all refs from origin to make sure we rewrite\n"
+ " all history that may reference the sensitive data, via\n"
+ " "+cmd)
+ print(m)
+ ret = subproc.call([arg if arg != '""' else '' for arg in cmd.split()],
+ cwd=source_working_dir)
+ if ret != 0: # pragma: no cover
+ m = _("Warning: Fetching all refs from origin failed")
+ print(m)
+ if self._args.sensitive_data_removal:
+ return
+
+ # Now remove the origin remote
+ url = self._config_settings[b'remote.origin.url'].decode(errors='replace')
+ m = _("NOTICE: Removing 'origin' remote; see 'Why is my origin removed?'\n"
+ " in the manual if you want to push back there.\n"
+ " (was %s)") % url
+ print(m)
+ subproc.call('git remote rm origin'.split(), cwd=target_working_dir)
+
+ def _final_commands(self):
+ self._finalize_handled = True
+ self._done_callback and self._done_callback()
+
+ if self._file_info_value:
+ self._file_info_value.finalize()
+ if not self._args.quiet:
+ self._progress_writer.finish()
+
+ def _ref_update(self, target_working_dir):
+ # Start the update-ref process
+ p = subproc.Popen('git update-ref --no-deref --stdin'.split(),
+ stdin=subprocess.PIPE,
+ cwd=target_working_dir)
+
+ # Remove replace_refs from _orig_refs
+ replace_refs = {k:v for k, v in self._orig_refs.items()
+ if k.startswith(b'refs/replace/')}
+ reverse_replace_refs = collections.defaultdict(list)
+ for k,v in replace_refs.items():
+ reverse_replace_refs[v].append(k)
+ all(map(self._orig_refs.pop, replace_refs))
+
+ # Remove unused refs
+ exported_refs, imported_refs = self.get_exported_and_imported_refs()
+ refs_to_nuke = exported_refs - imported_refs
+ # Because revisions can be passed to fast-export which handles them as
+ # though they were refs, we might have bad "refs" to nuke; strip them out.
+ refs_to_nuke = [x for x in refs_to_nuke
+ if x.startswith(b'refs/') or x == b'HEAD']
+ if self._args.partial:
+ refs_to_nuke = set()
+ if refs_to_nuke and self._args.debug:
+ print("[DEBUG] Deleting the following refs:\n "+
+ decode(b"\n ".join(sorted(refs_to_nuke))))
+ p.stdin.write(b''.join([b"delete %s\n" % x
+ for x in refs_to_nuke]))
+
+ # Delete or update and add replace_refs; note that fast-export automatically
+ # handles 'update-no-add', we only need to take action for the other four
+ # choices for replace_refs.
+ self._flush_renames()
+ actual_renames = {k:v for k,v in self._commit_renames.items() if k != v}
+ if self._args.replace_refs in ['delete-no-add', 'delete-and-add']:
+ # Delete old replace refs, if unwanted
+ replace_refs_to_nuke = set(replace_refs)
+ if self._args.replace_refs == 'delete-and-add':
+ # git-update-ref won't allow us to update a ref twice, so be careful
+ # to avoid deleting refs we'll later update
+ replace_refs_to_nuke = replace_refs_to_nuke.difference(
+ [b'refs/replace/'+x for x in actual_renames])
+ p.stdin.write(b''.join([b"delete %s\n" % x
+ for x in replace_refs_to_nuke]))
+ if self._args.replace_refs in ['delete-and-add', 'update-or-add',
+ 'update-and-add']:
+ # Add new replace refs
+ update_only = (self._args.replace_refs == 'update-or-add')
+ p.stdin.write(b''.join([b"update refs/replace/%s %s\n" % (old, new)
+ for old,new in actual_renames.items()
+ if new and not (update_only and
+ old in reverse_replace_refs)]))
+
+ # Complete the update-ref process
+ p.stdin.close()
+ if p.wait():
+ raise SystemExit(_("git update-ref failed; see above")) # pragma: no cover
+
+ def _remap_to(self, oldish_hash):
+ '''
+ Given an oldish_hash (from the beginning of the current run), return:
+ IF oldish_hash is NOT pruned:
+ the hash of the rewrite of oldish_hash
+ otherwise:
+ the hash of the rewrite of the first unpruned ancestor of oldish_hash
+ '''
+ old_id = self._orig_graph._hash_to_id[oldish_hash]
+ new_id = _IDS.translate(old_id)
+ new_hash = self._graph.git_hash[new_id] if new_id else deleted_hash
+ return new_hash
+
+ def _compute_metadata(self, metadata_dir, orig_refs):
+ #
+ # First, handle commit_renames
+ #
+ old_commit_renames = dict()
+ if not self._already_ran:
+ commit_renames = {old: new
+ for old, new in self._commit_renames.items()
+ }
+ else:
+ # Read commit-map into old_commit_renames
+ with open(os.path.join(metadata_dir, b'commit-map'), 'br') as f:
+ f.readline() # Skip the header line
+ for line in f:
+ (old,new) = line.split()
+ old_commit_renames[old] = new
+ # Use A->B mappings in old_commit_renames, and B->C mappings in
+ # self._commit_renames to yield A->C mappings in commit_renames
+ commit_renames = {old: self._commit_renames.get(newish, newish)
+ for old, newish in old_commit_renames.items()}
+ # If there are any B->C mappings in self._commit_renames for which
+ # there was no A->B mapping in old_commit_renames, then add the
+ # B->C mapping to commit_renames too.
+ seen = set(old_commit_renames.values())
+ commit_renames.update({old: new
+ for old, new in self._commit_renames.items()
+ if old not in seen})
+
+ #
+ # Second, handle ref_maps
+ #
+ exported_refs, imported_refs = self.get_exported_and_imported_refs()
+
+ old_commit_unrenames = dict()
+ if not self._already_ran:
+ old_ref_map = dict((refname, (old_hash, deleted_hash))
+ for refname, old_hash in orig_refs.items()
+ if refname in exported_refs)
+ else:
+ # old_commit_renames talk about how commits were renamed in the original
+ # run. Let's reverse it to find out how to get from the intermediate
+ # commit name, back to the original. Because everything in orig_refs
+ # right now refers to the intermediate commits after the first run(s),
+ # and we need to map them back to what they were before any changes.
+ old_commit_unrenames = dict((v,k) for (k,v) in old_commit_renames.items())
+
+ old_ref_map = {}
+ # Populate old_ref_map from the 'ref-map' file
+ with open(os.path.join(metadata_dir, b'ref-map'), 'br') as f:
+ f.readline() # Skip the header line
+ for line in f:
+ (old,intermediate,ref) = line.split()
+ old_ref_map[ref] = (old, intermediate)
+ # Append to old_ref_map items from orig_refs that were exported, but
+ # get the actual original commit name
+ for refname, old_hash in orig_refs.items():
+ if refname in old_ref_map:
+ continue
+ if refname not in exported_refs:
+ continue
+ # Compute older_hash
+ original_hash = old_commit_unrenames.get(old_hash, old_hash)
+ old_ref_map[refname] = (original_hash, deleted_hash)
+
+ new_refs = {}
+ new_refs_initialized = False
+ ref_maps = {}
+ self._orig_graph._ensure_reverse_maps_populated()
+ for refname, pair in old_ref_map.items():
+ old_hash, hash_ref_becomes_if_not_imported_in_this_run = pair
+ if refname not in imported_refs:
+ new_hash = hash_ref_becomes_if_not_imported_in_this_run
+ elif old_hash in commit_renames:
+ intermediate = old_commit_renames.get(old_hash,old_hash)
+ if intermediate in self._commit_renames:
+ new_hash = self._remap_to(intermediate)
+ else:
+ new_hash = intermediate
+ else: # Must be either an annotated tag, or a ref whose tip was pruned
+ if not new_refs_initialized:
+ target_working_dir = self._args.target or b'.'
+ new_refs = GitUtils.get_refs(target_working_dir)
+ new_refs_initialized = True
+ if refname in new_refs:
+ new_hash = new_refs[refname]
+ else:
+ new_hash = deleted_hash
+ ref_maps[refname] = (old_hash, new_hash)
+ if self._args.source or self._args.target:
+ if not new_refs_initialized:
+ target_working_dir = self._args.target or b'.'
+ new_refs = GitUtils.get_refs(target_working_dir)
+ new_refs_initialized = True
+ for ref, new_hash in new_refs.items():
+ if ref not in orig_refs and not ref.startswith(b'refs/replace/'):
+ old_hash = b'0'*len(new_hash)
+ ref_maps[ref] = (old_hash, new_hash)
+
+ #
+ # Third, handle first_changes
+ #
+
+ old_first_changes = dict()
+ if self._already_ran:
+ # Read first_changes into old_first_changes
+ with open(os.path.join(metadata_dir, b'first-changed-commits'), 'br') as f:
+ for line in f:
+ changed_commit, undeleted_self_or_ancestor = line.strip().split()
+ old_first_changes[changed_commit] = undeleted_self_or_ancestor
+ # We need to find the commits that were modified whose parents were not.
+ # To be able to find parents, we need the commit names as of the beginning
+ # of this run, and then when we are done, we need to map them back to the
+ # name of the commits from before any git-filter-repo runs.
+ #
+ # We are excluding here any commits deleted in previous git-filter-repo
+ # runs
+ undo_old_commit_renames = dict((v,k) for (k,v) in old_commit_renames.items()
+ if v != deleted_hash)
+ # Get a list of all commits that were changed, as of the beginning of
+ # this latest run.
+ changed_commits = {new
+ for (old,new) in old_commit_renames.items()
+ if old != new and new != deleted_hash} | \
+ {old
+ for (old,new) in self._commit_renames.items()
+ if old != new}
+ special_changed_commits = {old
+ for (old,new) in old_commit_renames.items()
+ if new == deleted_hash}
+ first_changes = dict()
+ for (old,new) in self._commit_renames.items():
+ if old == new:
+ # old wasn't modified, can't be first change if not even a change
+ continue
+ if old_commit_unrenames.get(old,old) != old:
+ # old was already modified in previous run; while it might represent
+ # something that is still a first change, we'll handle that as we
+ # loop over old_first_changes below
+ continue
+ if any(parent in changed_commits
+ for parent in self._orig_graph.get_parent_hashes(old)):
+ # a parent of old was modified, so old is not a first change
+ continue
+ # At this point, old IS a first change. We need to find out what new
+ # commit it maps to, or if it doesn't map to one, what new commit was
+ # its most recent ancestor that wasn't pruned.
+ if new is None:
+ new = self._remap_to(old)
+ first_changes[old] = (new if new is not None else deleted_hash)
+ for (old,undeleted_self_or_ancestor) in old_first_changes.items():
+ if undeleted_self_or_ancestor == deleted_hash:
+ # old represents a commit that was pruned and whose entire ancestry
+ # was pruned. So, old is still a first change
+ first_changes[old] = undeleted_self_or_ancestor
+ continue
+ intermediate = old_commit_renames.get(old, old)
+ usoa = undeleted_self_or_ancestor
+ new_ancestor = self._commit_renames.get(usoa, usoa)
+ if intermediate == deleted_hash:
+ # old was pruned in previous rewrite
+ if usoa != new_ancestor:
+ # old's ancestor got rewritten in this filtering run; we can drop
+ # this one from first_changes.
+ continue
+ # Getting here means old was a first change and old was pruned in a
+ # previous run, and its ancestors that survived were non rewritten in
+ # this run, so old remains a first change
+ first_changes[old] = new_ancestor # or usoa, since new_ancestor == usoa
+ continue
+ assert(usoa == intermediate) # old wasn't pruned => usoa == intermediate
+
+ # Check whether parents of intermediate were rewritten. Note that
+ # intermediate in self._commit_renames only means that intermediate was
+ # processed by the latest filtering (not necessarily that it changed),
+ # but we need to know that before we can check for parent hashes having
+ # changed.
+ if intermediate not in self._commit_renames:
+ # This commit was not processed by this run, so it remains a first
+ # change
+ first_changes[old] = usoa
+ continue
+ if any(parent in changed_commits
+ for parent in self._orig_graph.get_parent_hashes(intermediate)):
+ # An ancestor was modified by this run, so it is no longer a first
+ # change; continue to the next one.
+ continue
+ # This change is a first_change; find the new commit its usoa maps to
+ new = self._remap_to(intermediate)
+ assert(new is not None)
+ first_changes[old] = new
+
+ return commit_renames, ref_maps, first_changes
+
+ def _handle_lfs_metadata(self, metadata_dir):
+ if self._lfs_object_tracker is None:
+ print("NOTE: LFS object orphaning not checked (LFS not in use)")
+ return
+
+ if self._args.partial:
+ target_working_dir = self._args.target or b'.'
+ source = False
+ self._lfs_object_tracker.find_all_lfs_objects_in_repo(target_working_dir,
+ source)
+
+ with open(os.path.join(metadata_dir, b'original_lfs_objects'), 'bw') as f:
+ for obj in sorted(self._lfs_object_tracker.source_objects.objects):
+ f.write(obj+b"\n")
+
+ orphaned_lfs_path = os.path.join(metadata_dir, b'orphaned_lfs_objects')
+ msg = textwrap.dedent(_(f"""\
+ NOTE: There were LFS Objects Orphaned by this rewrite recorded in
+ {decode(orphaned_lfs_path)}."""))
+ with open(orphaned_lfs_path, 'bw') as f:
+ differences = self._lfs_object_tracker.source_objects.objects - \
+ self._lfs_object_tracker.target_objects.objects
+ for obj in sorted(differences):
+ f.write(obj+b"\n")
+ if differences:
+ self._lfs_object_tracker.objects_orphaned = True
+ print(msg)
+
+ def _record_metadata(self, metadata_dir, orig_refs):
+ self._flush_renames()
+ commit_renames, ref_maps, first_changes = \
+ self._compute_metadata(metadata_dir, orig_refs)
+
+ if self._args.sensitive_data_removal:
+ changed_commits = sum(k!=v for (k,v) in commit_renames.items())
+ print(f"You rewrote {changed_commits} (of {len(commit_renames)}) commits.")
+ print("") # Add a blank line before important rewrite information
+ print(f"NOTE: First Changed Commit(s) is/are:\n "
+ + decode(b"\n ".join(x for x in first_changes)))
+
+ with open(os.path.join(metadata_dir, b'sensitive_data_removal'), 'bw') as f:
+ pass # Write nothing; we only need the file created
+
+ self._handle_lfs_metadata(metadata_dir)
+ print("") # Add a blank line after important rewrite information
+
+ with open(os.path.join(metadata_dir, b'commit-map'), 'bw') as f:
+ f.write(("%-40s %s\n" % (_("old"), _("new"))).encode())
+ for (old,new) in sorted(commit_renames.items()):
+ msg = b'%s %s\n' % (old, new if new != None else deleted_hash)
+ f.write(msg)
+
+ with open(os.path.join(metadata_dir, b'ref-map'), 'bw') as f:
+ f.write(("%-40s %-40s %s\n" % (_("old"), _("new"), _("ref"))).encode())
+ for refname, hash_pair in sorted(ref_maps.items()):
+ (old_hash, new_hash) = hash_pair
+ f.write(b'%s %s %s\n' % (old_hash, new_hash, refname))
+ if old_hash != new_hash:
+ self._changed_refs.add(refname)
+
+ with open(os.path.join(metadata_dir, b'changed-refs'), 'bw') as f:
+ for refname in sorted(self._changed_refs):
+ f.write(b'%s\n' % refname)
+
+ with open(os.path.join(metadata_dir, b'first-changed-commits'), 'bw') as f:
+ for commit, undeleted_self_or_ancestor in sorted(first_changes.items()):
+ f.write(b'%s %s\n' % (commit, undeleted_self_or_ancestor))
+
+ with open(os.path.join(metadata_dir, b'suboptimal-issues'), 'bw') as f:
+ issues_found = False
+ if self._commits_no_longer_merges:
+ issues_found = True
+
+ f.write(textwrap.dedent(_('''
+ The following commits used to be merge commits but due to filtering
+ are now regular commits; they likely have suboptimal commit messages
+ (e.g. "Merge branch next into master"). Original commit hash on the
+ left, commit hash after filtering/rewriting on the right:
+ ''')[1:]).encode())
+ for oldhash, newhash in self._commits_no_longer_merges:
+ f.write(' {} {}\n'.format(oldhash, newhash).encode())
+ f.write(b'\n')
+
+ if self._commits_referenced_but_removed:
+ issues_found = True
+ f.write(textwrap.dedent(_('''
+ The following commits were filtered out, but referenced in another
+ commit message. The reference to the now-nonexistent commit hash
+ (or a substring thereof) was left as-is in any commit messages:
+ ''')[1:]).encode())
+ for bad_commit_reference in self._commits_referenced_but_removed:
+ f.write(' {}\n'.format(bad_commit_reference).encode())
+ f.write(b'\n')
+
+ if not issues_found:
+ f.write(_("No filtering problems encountered.\n").encode())
+
+ with open(os.path.join(metadata_dir, b'already_ran'), 'bw') as f:
+ f.write(_("This file exists to allow you to filter again without --force,\n"
+ "and to specify that metadata files should be updated instead\n"
+ "of rewritten").encode())
+
+ def finish(self):
+ ''' Alternative to run() when there is no input of our own to parse,
+ meaning that run only really needs to close the handle to fast-import
+ and let it finish, thus making a call to "run" feel like a misnomer. '''
+ assert not self._input
+ assert self._managed_output
+ self.run()
+
+ def insert(self, obj, direct_insertion = False):
+ if not direct_insertion:
+ if type(obj) == Blob:
+ self._tweak_blob(obj)
+ elif type(obj) == Commit:
+ aux_info = {'orig_parents': obj.parents,
+ 'had_file_changes': bool(obj.file_changes)}
+ self._tweak_commit(obj, aux_info)
+ elif type(obj) == Reset:
+ self._tweak_reset(obj)
+ elif type(obj) == Tag:
+ self._tweak_tag(obj)
+ self._insert_into_stream(obj)
+
+ def _insert_into_stream(self, obj):
+ if not obj.dumped:
+ if self._lfs_object_tracker:
+ self._lfs_object_tracker.check_output_object(obj)
+ if self._parser:
+ self._parser.insert(obj)
+ else:
+ obj.dump(self._output)
+
+ def get_exported_and_imported_refs(self):
+ return self._parser.get_exported_and_imported_refs()
+
+ def run(self):
+ start = time.time()
+ if not self._input and not self._output:
+ self._run_sanity_checks()
+ if not self._args.dry_run and not self._args.partial:
+ self._read_stash()
+ self._migrate_origin_to_heads()
+ self._setup_input(use_done_feature = True)
+ self._setup_output()
+ assert self._sanity_checks_handled
+
+ if self._input:
+ # Create and run the filter
+ self._repo_working_dir = self._args.source or b'.'
+ self._parser = FastExportParser(blob_callback = self._tweak_blob,
+ commit_callback = self._tweak_commit,
+ tag_callback = self._tweak_tag,
+ reset_callback = self._tweak_reset,
+ done_callback = self._final_commands)
+ self._setup_lfs_orphaning_checks()
+ self._parser.run(self._input, self._output)
+ if not self._finalize_handled:
+ self._final_commands()
+
+ # Make sure fast-export completed successfully
+ if not self._args.stdin and self._fep.wait():
+ raise SystemExit(_("Error: fast-export failed; see above.")) # pragma: no cover
+ self._input.close()
+
+ # If we're not the manager of self._output, we should avoid post-run cleanup
+ if not self._managed_output:
+ return
+
+ # Close the output and ensure fast-import successfully completes
+ self._output.close()
+ if not self._args.dry_run and self._fip.wait():
+ raise SystemExit(_("Error: fast-import failed; see above.")) # pragma: no cover
+
+ # With fast-export and fast-import complete, update state if requested
+ if self._args.state_branch:
+ self._save_marks_files()
+
+ # Notify user how long it took, before doing a gc and such
+ msg = "New history written in {:.2f} seconds..."
+ if self._args.repack:
+ msg = "New history written in {:.2f} seconds; now repacking/cleaning..."
+ print(msg.format(time.time()-start))
+
+ # Exit early, if requested
+ if self._args.dry_run:
+ print(_("NOTE: Not running fast-import or cleaning up; --dry-run passed."))
+ if self._fe_orig:
+ print(_(" Requested filtering can be seen by comparing:"))
+ print(" " + decode(self._fe_orig))
+ else:
+ print(_(" Requested filtering can be seen at:"))
+ print(" " + decode(self._fe_filt))
+ return
+
+ target_working_dir = self._args.target or b'.'
+ if self._input:
+ self._ref_update(target_working_dir)
+
+ # Write out data about run
+ self._record_metadata(self.results_tmp_dir(), self._orig_refs)
+
+ # Final cleanup:
+ # If we need a repack, then nuke the reflogs and repack.
+ # If we need a reset, do a reset --hard
+ reset = not GitUtils.is_repository_bare(target_working_dir)
+ self.cleanup(target_working_dir, self._args.repack, reset,
+ run_quietly=self._args.quiet,
+ show_debuginfo=self._args.debug)
+
+ # Let user know how long it took
+ print(_("Completely finished after {:.2f} seconds.")
+ .format(time.time()-start))
+
+ # Give post-rewrite instructions for cleaning up other copies for SDR
+ if self._args.sensitive_data_removal:
+ lfs_note = ""
+ if self._lfs_object_tracker and \
+ self._lfs_object_tracker.objects_orphaned == True:
+ lfs_note = _(" and LFS Objects Orphaned")
+ push_command = "git push --force --mirror origin"
+ if self._args.no_fetch:
+ if self._args.partial:
+ push_command = "git push --force origin " + \
+ " ".join(sorted([decode(x) for x in self._changed_refs]))
+ else:
+ push_command = "git push --all --tags origin"
+ print("")
+ print(sdr_next_steps % (push_command, lfs_note, lfs_note))
+
+def main():
+ setup_gettext()
+ args = FilteringOptions.parse_args(sys.argv[1:])
+ if args.analyze:
+ RepoAnalyze.run(args)
+ else:
+ filter = RepoFilter(args)
+ filter.run()
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/pre-commit b/contrib/pre-commit
new file mode 100644
index 00000000000..9836ae75070
--- /dev/null
+++ b/contrib/pre-commit
@@ -0,0 +1,38 @@
+#!/bin/sh
+FILES=`git diff --cached --name-only --diff-filter=ACMR HEAD | grep \\\\.php`
+PROJECT=`php -r "echo dirname(dirname(realpath('$0')));"`
+
+# Determine if a file list is passed
+if [ "$#" -eq 1 ]
+then
+ oIFS=$IFS
+ IFS='
+ '
+ SFILES="$1"
+ IFS=$oIFS
+fi
+SFILES=${SFILES:-$FILES}
+
+echo "Checking PHP Lint..."
+for FILE in $SFILES
+do
+ php -l -d display_errors=0 $PROJECT/$FILE
+ if [ $? != 0 ]
+ then
+ echo "Fix the error before commit."
+ exit 1
+ fi
+ FILES="$FILES $PROJECT/$FILE"
+done
+
+if [ "$SFILES" != "" ]
+then
+ echo "Running PHPCS"
+ ./vendor/bin/phpcs $SFILES
+ if [ $? != 0 ]
+ then
+ echo "PHPCS Errors found; commit aborted."
+ exit 1
+ fi
+fi
+exit $?
diff --git a/contrib/validate-deprecation-aliases.php b/contrib/validate-deprecation-aliases.php
new file mode 100644
index 00000000000..175c338d519
--- /dev/null
+++ b/contrib/validate-deprecation-aliases.php
@@ -0,0 +1,76 @@
+#!/usr/bin/php -q
+ $iterator */
+$iterator = new RecursiveIteratorIterator($di);
+
+$code = 0;
+foreach ($iterator as $file) {
+ if (pathinfo((string)$file, PATHINFO_EXTENSION) !== 'php') {
+ continue;
+ }
+ if (pathinfo((string)$file, PATHINFO_FILENAME) === 'functions') {
+ continue;
+ }
+ if (strpos($file->getRealPath(), '/TestSuite/')) {
+ continue;
+ }
+
+ $content = file_get_contents((string)$file);
+ if (!strpos($content, 'class_alias(')) {
+ continue;
+ }
+
+ preg_match('#class_alias\(\s*\'([^\']+)\',#', $content, $matches);
+ if (!$matches) {
+ var_dump($content);
+ var_dump($file->getPath());
+ exit(1);
+ }
+
+ echo $matches[1] . PHP_EOL;
+ $filePath = str_replace('\\', '/', $matches[1]);
+ $filePath = str_replace('Cake/', $path, $filePath);
+ $filePath .= '.php';
+ if (!file_exists($filePath)) {
+ throw new RuntimeException('Cannot find path for `' . $matches[1] . '`');
+ }
+
+ $newFileContent = file_get_contents($filePath);
+
+ if (!str_contains($newFileContent, 'class_exists(') && !str_contains($newFileContent, 'class_alias(')) {
+ $oldPath = str_replace($path, '', $file->getRealPath());
+ $newPath = str_replace($path, '', $filePath);
+ echo "\033[31m" . ' * Missing `class_exists()` or `class_alias()` on new file for `' . $oldPath . '` => `' . $newPath . '`' . "\033[0m" . PHP_EOL;
+ $code = 1;
+ } else {
+ echo ' * OK' . PHP_EOL;
+ }
+}
+
+exit($code);
diff --git a/contrib/validate-split-packages-phpstan.php b/contrib/validate-split-packages-phpstan.php
new file mode 100644
index 00000000000..1cf084cda52
--- /dev/null
+++ b/contrib/validate-split-packages-phpstan.php
@@ -0,0 +1,73 @@
+#!/usr/bin/php -q
+ $iterator */
+$iterator = new RegexIterator($iterator, '~/src/\w+/composer.json$~');
+
+$packages = [];
+$code = 0;
+foreach ($iterator as $file) {
+ $filePath = $file->getPath();
+ $package = substr($filePath, strrpos($filePath, '/') + 1);
+ $packages[$filePath . '/'] = $package;
+}
+ksort($packages);
+
+$phivePharsXml = simplexml_load_file(dirname(__FILE__, 2) . DS . '.phive' . DS . 'phars.xml');
+$phpstanVersion = null;
+foreach ($phivePharsXml->phar as $phar) {
+ if ($phar->attributes()->name == 'phpstan') {
+ $phpstanVersion = (string)$phar->attributes()->version;
+ break;
+ }
+}
+$composerCommand = 'composer require --dev phpstan/phpstan:' . $phpstanVersion;
+
+$issues = [];
+foreach ($packages as $path => $package) {
+ if (!file_exists($path . 'phpstan.neon.dist')) {
+ continue;
+ }
+
+ $exitCode = null;
+ exec(
+ 'cd ' . $path . ' && ' . $composerCommand . ' && vendor/bin/phpstan analyze ./',
+ $output,
+ $exitCode
+ );
+ if ($exitCode !== 0) {
+ $code = $exitCode;
+
+ $issues[] = $package . ': ' . PHP_EOL . implode(PHP_EOL, $output);
+ }
+ exec('cd ' . $path . ' && rm composer.lock && rm -rf vendor && git checkout composer.json');
+}
+
+echo implode(PHP_EOL . PHP_EOL, $issues);
+
+exit($code);
diff --git a/contrib/validate-split-packages.php b/contrib/validate-split-packages.php
new file mode 100644
index 00000000000..01dfa998945
--- /dev/null
+++ b/contrib/validate-split-packages.php
@@ -0,0 +1,103 @@
+#!/usr/bin/php -q
+ $iterator */
+$iterator = new RegexIterator($iterator, '~/src/\w+/composer.json$~');
+
+$packages = [];
+$code = 0;
+foreach ($iterator as $file) {
+ $filePath = $file->getPath();
+ $package = substr($filePath, strrpos($filePath, '/') + 1);
+ if ($package === 'ORM') {
+ $fullName = 'cakephp/orm';
+ } else {
+ $fullName = 'cakephp/' . Inflector::dasherize($package);
+ }
+ $packages[$fullName] = $package;
+}
+ksort($packages);
+
+$mainJsonContent = file_get_contents(dirname(__FILE__, 2) . DS . 'composer.json');
+$mainJson = json_decode($mainJsonContent, true);
+$mainReplace = $mainJson['replace'];
+$missing = [];
+foreach ($packages as $fullPackageName => $package) {
+ if (!empty($mainReplace[$fullPackageName])) {
+ unset($mainReplace[$fullPackageName]);
+
+ continue;
+ }
+
+ $missing[] = $package;
+}
+if ($mainReplace) {
+ echo "\033[31m" . ' * Missing "replace" statement in ROOT composer.json for package `' . $package . '`' . "\033[0m" . PHP_EOL;
+ $code = 1;
+}
+if ($missing) {
+ echo "\033[31m" . ' * Extra "replace" statement in ROOT composer.json for non-existent package(s) `' . implode(', ', $missing) . '`' . "\033[0m" . PHP_EOL;
+ $code = 1;
+}
+
+$mainRequire = $mainJson['require'];
+
+$issues = [];
+foreach ($packages as $package) {
+ $content = file_get_contents($path . $package . DS . 'composer.json');
+ $json = json_decode($content, true);
+ $require = $json['require'] ?? [];
+
+ foreach ($require as $packageName => $constraint) {
+ if (isset($packages[$packageName])) {
+ continue;
+ }
+
+ if (!isset($mainRequire[$packageName])) {
+ $issues[$package][] = 'Missing package requirement `' . $packageName . ': ' . $constraint . '` in ROOT composer.json';
+
+ continue;
+ }
+
+ if ($mainRequire[$packageName] !== $constraint) {
+ $issues[$package][] = 'Package requirement `' . $packageName . ': ' . $constraint . '` does not match the one in ROOT composer.json (`' . $mainRequire[$packageName] . '`)';
+ }
+ }
+}
+
+foreach ($issues as $packageName => $packageIssues) {
+ echo "\033[31m" . $packageName . ':' . "\033[0m" . PHP_EOL;
+ foreach ($packageIssues as $issue) {
+ echo "\033[31m" . ' - ' . $issue . "\033[0m" . PHP_EOL;
+ $code = 1;
+ }
+}
+
+exit($code);
diff --git a/index.php b/index.php
deleted file mode 100644
index 480a9c73206..00000000000
--- a/index.php
+++ /dev/null
@@ -1,40 +0,0 @@
- 'Apc',
- * 'prefix' => 'my_app_'
- * ));
- * }}}
- *
- * This would configure an APC cache engine to the 'shared' alias. You could then read and write
- * to that cache alias by using it for the `$config` parameter in the various Cache methods. In
- * general all Cache operations are supported by all cache engines. However, Cache::increment() and
- * Cache::decrement() are not supported by File caching.
- *
- * @package Cake.Cache
- */
-class Cache {
-
-/**
- * Cache configuration stack
- * Keeps the permanent/default settings for each cache engine.
- * These settings are used to reset the engines after temporary modification.
- *
- * @var array
- */
- protected static $_config = array();
-
-/**
- * Whether to reset the settings with the next call to Cache::set();
- *
- * @var array
- */
- protected static $_reset = false;
-
-/**
- * Engine instances keyed by configuration name.
- *
- * @var array
- */
- protected static $_engines = array();
-
-/**
- * Set the cache configuration to use. config() can
- * both create new configurations, return the settings for already configured
- * configurations.
- *
- * To create a new configuration, or to modify an existing configuration permanently:
- *
- * `Cache::config('my_config', array('engine' => 'File', 'path' => TMP));`
- *
- * If you need to modify a configuration temporarily, use Cache::set().
- * To get the settings for a configuration:
- *
- * `Cache::config('default');`
- *
- * There are 5 built-in caching engines:
- *
- * - `FileEngine` - Uses simple files to store content. Poor performance, but good for
- * storing large objects, or things that are not IO sensitive.
- * - `ApcEngine` - Uses the APC object cache, one of the fastest caching engines.
- * - `MemcacheEngine` - Uses the PECL::Memcache extension and Memcached for storage.
- * Fast reads/writes, and benefits from memcache being distributed.
- * - `XcacheEngine` - Uses the Xcache extension, an alternative to APC.
- * - `WincacheEngine` - Uses Windows Cache Extension for PHP. Supports wincache 1.1.0 and higher.
- *
- * The following keys are used in core cache engines:
- *
- * - `duration` Specify how long items in this cache configuration last.
- * - `prefix` Prefix appended to all entries. Good for when you need to share a keyspace
- * with either another cache config or another application.
- * - `probability` Probability of hitting a cache gc cleanup. Setting to 0 will disable
- * cache::gc from ever being called automatically.
- * - `servers' Used by memcache. Give the address of the memcached servers to use.
- * - `compress` Used by memcache. Enables memcache's compressed format.
- * - `serialize` Used by FileCache. Should cache objects be serialized first.
- * - `path` Used by FileCache. Path to where cachefiles should be saved.
- * - `lock` Used by FileCache. Should files be locked before writing to them?
- * - `user` Used by Xcache. Username for XCache
- * - `password` Used by Xcache. Password for XCache
- *
- * @see app/Config/core.php for configuration settings
- * @param string $name Name of the configuration
- * @param array $settings Optional associative array of settings passed to the engine
- * @return array(engine, settings) on success, false on failure
- * @throws CacheException
- */
- public static function config($name = null, $settings = array()) {
- if (is_array($name)) {
- $settings = $name;
- }
-
- $current = array();
- if (isset(self::$_config[$name])) {
- $current = self::$_config[$name];
- }
-
- if (!empty($settings)) {
- self::$_config[$name] = array_merge($current, $settings);
- }
-
- if (empty(self::$_config[$name]['engine'])) {
- return false;
- }
-
- $engine = self::$_config[$name]['engine'];
-
- if (!isset(self::$_engines[$name])) {
- self::_buildEngine($name);
- $settings = self::$_config[$name] = self::settings($name);
- } elseif ($settings = self::set(self::$_config[$name], null, $name)) {
- self::$_config[$name] = $settings;
- }
- return compact('engine', 'settings');
- }
-
-/**
- * Finds and builds the instance of the required engine class.
- *
- * @param string $name Name of the config array that needs an engine instance built
- * @return boolean
- * @throws CacheException
- */
- protected static function _buildEngine($name) {
- $config = self::$_config[$name];
-
- list($plugin, $class) = pluginSplit($config['engine'], true);
- $cacheClass = $class . 'Engine';
- App::uses($cacheClass, $plugin . 'Cache/Engine');
- if (!class_exists($cacheClass)) {
- return false;
- }
- $cacheClass = $class . 'Engine';
- if (!is_subclass_of($cacheClass, 'CacheEngine')) {
- throw new CacheException(__d('cake_dev', 'Cache engines must use CacheEngine as a base class.'));
- }
- self::$_engines[$name] = new $cacheClass();
- if (self::$_engines[$name]->init($config)) {
- if (self::$_engines[$name]->settings['probability'] && time() % self::$_engines[$name]->settings['probability'] === 0) {
- self::$_engines[$name]->gc();
- }
- return true;
- }
- return false;
- }
-
-/**
- * Returns an array containing the currently configured Cache settings.
- *
- * @return array Array of configured Cache config names.
- */
- public static function configured() {
- return array_keys(self::$_config);
- }
-
-/**
- * Drops a cache engine. Deletes the cache configuration information
- * If the deleted configuration is the last configuration using an certain engine,
- * the Engine instance is also unset.
- *
- * @param string $name A currently configured cache config you wish to remove.
- * @return boolean success of the removal, returns false when the config does not exist.
- */
- public static function drop($name) {
- if (!isset(self::$_config[$name])) {
- return false;
- }
- unset(self::$_config[$name], self::$_engines[$name]);
- return true;
- }
-
-/**
- * Temporarily change the settings on a cache config. The settings will persist for the next write
- * operation (write, decrement, increment, clear). Any reads that are done before the write, will
- * use the modified settings. If `$settings` is empty, the settings will be reset to the
- * original configuration.
- *
- * Can be called with 2 or 3 parameters. To set multiple values at once.
- *
- * `Cache::set(array('duration' => '+30 minutes'), 'my_config');`
- *
- * Or to set one value.
- *
- * `Cache::set('duration', '+30 minutes', 'my_config');`
- *
- * To reset a config back to the originally configured values.
- *
- * `Cache::set(null, 'my_config');`
- *
- * @param mixed $settings Optional string for simple name-value pair or array
- * @param string $value Optional for a simple name-value pair
- * @param string $config The configuration name you are changing. Defaults to 'default'
- * @return array Array of settings.
- */
- public static function set($settings = array(), $value = null, $config = 'default') {
- if (is_array($settings) && $value !== null) {
- $config = $value;
- }
- if (!isset(self::$_config[$config]) || !isset(self::$_engines[$config])) {
- return false;
- }
- if (!empty($settings)) {
- self::$_reset = true;
- }
-
- if (self::$_reset === true) {
- if (empty($settings)) {
- self::$_reset = false;
- $settings = self::$_config[$config];
- } else {
- if (is_string($settings) && $value !== null) {
- $settings = array($settings => $value);
- }
- $settings = array_merge(self::$_config[$config], $settings);
- if (isset($settings['duration']) && !is_numeric($settings['duration'])) {
- $settings['duration'] = strtotime($settings['duration']) - time();
- }
- }
- self::$_engines[$config]->settings = $settings;
- }
- return self::settings($config);
- }
-
-/**
- * Garbage collection
- *
- * Permanently remove all expired and deleted data
- *
- * @param string $config The config name you wish to have garbage collected. Defaults to 'default'
- * @return void
- */
- public static function gc($config = 'default') {
- self::$_engines[$config]->gc();
- }
-
-/**
- * Write data for key into cache. Will automatically use the currently
- * active cache configuration. To set the currently active configuration use
- * Cache::config()
- *
- * ### Usage:
- *
- * Writing to the active cache config:
- *
- * `Cache::write('cached_data', $data);`
- *
- * Writing to a specific cache config:
- *
- * `Cache::write('cached_data', $data, 'long_term');`
- *
- * @param string $key Identifier for the data
- * @param mixed $value Data to be cached - anything except a resource
- * @param string $config Optional string configuration name to write to. Defaults to 'default'
- * @return boolean True if the data was successfully cached, false on failure
- */
- public static function write($key, $value, $config = 'default') {
- $settings = self::settings($config);
-
- if (empty($settings)) {
- return false;
- }
- if (!self::isInitialized($config)) {
- return false;
- }
- $key = self::$_engines[$config]->key($key);
-
- if (!$key || is_resource($value)) {
- return false;
- }
-
- $success = self::$_engines[$config]->write($settings['prefix'] . $key, $value, $settings['duration']);
- self::set(null, $config);
- if ($success === false && $value !== '') {
- trigger_error(
- __d('cake_dev',
- "%s cache was unable to write '%s' to %s cache",
- $config,
- $key,
- self::$_engines[$config]->settings['engine']
- ),
- E_USER_WARNING
- );
- }
- return $success;
- }
-
-/**
- * Read a key from the cache. Will automatically use the currently
- * active cache configuration. To set the currently active configuration use
- * Cache::config()
- *
- * ### Usage:
- *
- * Reading from the active cache configuration.
- *
- * `Cache::read('my_data');`
- *
- * Reading from a specific cache configuration.
- *
- * `Cache::read('my_data', 'long_term');`
- *
- * @param string $key Identifier for the data
- * @param string $config optional name of the configuration to use. Defaults to 'default'
- * @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
- */
- public static function read($key, $config = 'default') {
- $settings = self::settings($config);
-
- if (empty($settings)) {
- return false;
- }
- if (!self::isInitialized($config)) {
- return false;
- }
- $key = self::$_engines[$config]->key($key);
- if (!$key) {
- return false;
- }
- return self::$_engines[$config]->read($settings['prefix'] . $key);
- }
-
-/**
- * Increment a number under the key and return incremented value.
- *
- * @param string $key Identifier for the data
- * @param integer $offset How much to add
- * @param string $config Optional string configuration name. Defaults to 'default'
- * @return mixed new value, or false if the data doesn't exist, is not integer,
- * or if there was an error fetching it.
- */
- public static function increment($key, $offset = 1, $config = 'default') {
- $settings = self::settings($config);
-
- if (empty($settings)) {
- return false;
- }
- if (!self::isInitialized($config)) {
- return false;
- }
- $key = self::$_engines[$config]->key($key);
-
- if (!$key || !is_integer($offset) || $offset < 0) {
- return false;
- }
- $success = self::$_engines[$config]->increment($settings['prefix'] . $key, $offset);
- self::set(null, $config);
- return $success;
- }
-
-/**
- * Decrement a number under the key and return decremented value.
- *
- * @param string $key Identifier for the data
- * @param integer $offset How much to subtract
- * @param string $config Optional string configuration name. Defaults to 'default'
- * @return mixed new value, or false if the data doesn't exist, is not integer,
- * or if there was an error fetching it
- */
- public static function decrement($key, $offset = 1, $config = 'default') {
- $settings = self::settings($config);
-
- if (empty($settings)) {
- return false;
- }
- if (!self::isInitialized($config)) {
- return false;
- }
- $key = self::$_engines[$config]->key($key);
-
- if (!$key || !is_integer($offset) || $offset < 0) {
- return false;
- }
- $success = self::$_engines[$config]->decrement($settings['prefix'] . $key, $offset);
- self::set(null, $config);
- return $success;
- }
-
-/**
- * Delete a key from the cache.
- *
- * ### Usage:
- *
- * Deleting from the active cache configuration.
- *
- * `Cache::delete('my_data');`
- *
- * Deleting from a specific cache configuration.
- *
- * `Cache::delete('my_data', 'long_term');`
- *
- * @param string $key Identifier for the data
- * @param string $config name of the configuration to use. Defaults to 'default'
- * @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
- */
- public static function delete($key, $config = 'default') {
- $settings = self::settings($config);
-
- if (empty($settings)) {
- return false;
- }
- if (!self::isInitialized($config)) {
- return false;
- }
- $key = self::$_engines[$config]->key($key);
- if (!$key) {
- return false;
- }
-
- $success = self::$_engines[$config]->delete($settings['prefix'] . $key);
- self::set(null, $config);
- return $success;
- }
-
-/**
- * Delete all keys from the cache.
- *
- * @param boolean $check if true will check expiration, otherwise delete all
- * @param string $config name of the configuration to use. Defaults to 'default'
- * @return boolean True if the cache was successfully cleared, false otherwise
- */
- public static function clear($check = false, $config = 'default') {
- if (!self::isInitialized($config)) {
- return false;
- }
- $success = self::$_engines[$config]->clear($check);
- self::set(null, $config);
- return $success;
- }
-
-/**
- * Check if Cache has initialized a working config for the given name.
- *
- * @param string $config name of the configuration to use. Defaults to 'default'
- * @return boolean Whether or not the config name has been initialized.
- */
- public static function isInitialized($config = 'default') {
- if (Configure::read('Cache.disable')) {
- return false;
- }
- return isset(self::$_engines[$config]);
- }
-
-/**
- * Return the settings for the named cache engine.
- *
- * @param string $name Name of the configuration to get settings for. Defaults to 'default'
- * @return array list of settings for this engine
- * @see Cache::config()
- */
- public static function settings($name = 'default') {
- if (!empty(self::$_engines[$name])) {
- return self::$_engines[$name]->settings();
- }
- return array();
- }
-
-}
-
diff --git a/lib/Cake/Cache/CacheEngine.php b/lib/Cake/Cache/CacheEngine.php
deleted file mode 100644
index f71b8a15902..00000000000
--- a/lib/Cake/Cache/CacheEngine.php
+++ /dev/null
@@ -1,134 +0,0 @@
-settings = array_merge(
- array('prefix' => 'cake_', 'duration' => 3600, 'probability' => 100),
- $this->settings,
- $settings
- );
- if (!is_numeric($this->settings['duration'])) {
- $this->settings['duration'] = strtotime($this->settings['duration']) - time();
- }
- return true;
- }
-
-/**
- * Garbage collection
- *
- * Permanently remove all expired and deleted data
- * @return void
- */
- public function gc() {
- }
-
-/**
- * Write value for a key into cache
- *
- * @param string $key Identifier for the data
- * @param mixed $value Data to be cached
- * @param mixed $duration How long to cache for.
- * @return boolean True if the data was successfully cached, false on failure
- */
- abstract public function write($key, $value, $duration);
-
-/**
- * Read a key from the cache
- *
- * @param string $key Identifier for the data
- * @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
- */
- abstract public function read($key);
-
-/**
- * Increment a number under the key and return incremented value
- *
- * @param string $key Identifier for the data
- * @param integer $offset How much to add
- * @return New incremented value, false otherwise
- */
- abstract public function increment($key, $offset = 1);
-
-/**
- * Decrement a number under the key and return decremented value
- *
- * @param string $key Identifier for the data
- * @param integer $offset How much to subtract
- * @return New incremented value, false otherwise
- */
- abstract public function decrement($key, $offset = 1);
-
-/**
- * Delete a key from the cache
- *
- * @param string $key Identifier for the data
- * @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
- */
- abstract public function delete($key);
-
-/**
- * Delete all keys from the cache
- *
- * @param boolean $check if true will check expiration, otherwise delete all
- * @return boolean True if the cache was successfully cleared, false otherwise
- */
- abstract public function clear($check);
-
-/**
- * Cache Engine settings
- *
- * @return array settings
- */
- public function settings() {
- return $this->settings;
- }
-
-/**
- * Generates a safe key for use with cache engine storage engines.
- *
- * @param string $key the key passed over
- * @return mixed string $key or false
- */
- public function key($key) {
- if (empty($key)) {
- return false;
- }
- $key = Inflector::underscore(str_replace(array(DS, '/', '.'), '_', strval($key)));
- return $key;
- }
-
-}
diff --git a/lib/Cake/Cache/Engine/ApcEngine.php b/lib/Cake/Cache/Engine/ApcEngine.php
deleted file mode 100644
index a453ecd1fe5..00000000000
--- a/lib/Cake/Cache/Engine/ApcEngine.php
+++ /dev/null
@@ -1,130 +0,0 @@
- 'Apc', 'prefix' => Inflector::slug(APP_DIR) . '_'), $settings));
- return function_exists('apc_dec');
- }
-
-/**
- * Write data for key into cache
- *
- * @param string $key Identifier for the data
- * @param mixed $value Data to be cached
- * @param integer $duration How long to cache the data, in seconds
- * @return boolean True if the data was successfully cached, false on failure
- */
- public function write($key, $value, $duration) {
- if ($duration == 0) {
- $expires = 0;
- } else {
- $expires = time() + $duration;
- }
- apc_store($key . '_expires', $expires, $duration);
- return apc_store($key, $value, $duration);
- }
-
-/**
- * Read a key from the cache
- *
- * @param string $key Identifier for the data
- * @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
- */
- public function read($key) {
- $time = time();
- $cachetime = intval(apc_fetch($key . '_expires'));
- if ($cachetime !== 0 && ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime)) {
- return false;
- }
- return apc_fetch($key);
- }
-
-/**
- * Increments the value of an integer cached key
- *
- * @param string $key Identifier for the data
- * @param integer $offset How much to increment
- * @return New incremented value, false otherwise
- */
- public function increment($key, $offset = 1) {
- return apc_inc($key, $offset);
- }
-
-/**
- * Decrements the value of an integer cached key
- *
- * @param string $key Identifier for the data
- * @param integer $offset How much to subtract
- * @return New decremented value, false otherwise
- */
- public function decrement($key, $offset = 1) {
- return apc_dec($key, $offset);
- }
-
-/**
- * Delete a key from the cache
- *
- * @param string $key Identifier for the data
- * @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
- */
- public function delete($key) {
- return apc_delete($key);
- }
-
-/**
- * Delete all keys from the cache. This will clear every cache config using APC.
- *
- * @param boolean $check If true, nothing will be cleared, as entries are removed
- * from APC as they expired. This flag is really only used by FileEngine.
- * @return boolean True Returns true.
- */
- public function clear($check) {
- if ($check) {
- return true;
- }
- $info = apc_cache_info('user');
- $cacheKeys = $info['cache_list'];
- unset($info);
- foreach ($cacheKeys as $key) {
- if (strpos($key['info'], $this->settings['prefix']) === 0) {
- apc_delete($key['info']);
- }
- }
- return true;
- }
-
-}
diff --git a/lib/Cake/Cache/Engine/FileEngine.php b/lib/Cake/Cache/Engine/FileEngine.php
deleted file mode 100644
index 9213a5f2a37..00000000000
--- a/lib/Cake/Cache/Engine/FileEngine.php
+++ /dev/null
@@ -1,326 +0,0 @@
- CACHE
- * - prefix = string prefix for filename, default => cake_
- * - lock = enable file locking on write, default => false
- * - serialize = serialize the data, default => true
- *
- * @var array
- * @see CacheEngine::__defaults
- */
- public $settings = array();
-
-/**
- * True unless FileEngine::__active(); fails
- *
- * @var boolean
- */
- protected $_init = true;
-
-/**
- * Initialize the Cache Engine
- *
- * Called automatically by the cache frontend
- * To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
- *
- * @param array $settings array of setting for the engine
- * @return boolean True if the engine has been successfully initialized, false if not
- */
- public function init($settings = array()) {
- parent::init(array_merge(
- array(
- 'engine' => 'File', 'path' => CACHE, 'prefix' => 'cake_', 'lock' => true,
- 'serialize' => true, 'isWindows' => false, 'mask' => 0664
- ),
- $settings
- ));
-
- if (DS === '\\') {
- $this->settings['isWindows'] = true;
- }
- if (substr($this->settings['path'], -1) !== DS) {
- $this->settings['path'] .= DS;
- }
- return $this->_active();
- }
-
-/**
- * Garbage collection. Permanently remove all expired and deleted data
- *
- * @return boolean True if garbage collection was successful, false on failure
- */
- public function gc() {
- return $this->clear(true);
- }
-
-/**
- * Write data for key into cache
- *
- * @param string $key Identifier for the data
- * @param mixed $data Data to be cached
- * @param mixed $duration How long to cache the data, in seconds
- * @return boolean True if the data was successfully cached, false on failure
- */
- public function write($key, $data, $duration) {
- if ($data === '' || !$this->_init) {
- return false;
- }
-
- if ($this->_setKey($key, true) === false) {
- return false;
- }
-
- $lineBreak = "\n";
-
- if ($this->settings['isWindows']) {
- $lineBreak = "\r\n";
- }
-
- if (!empty($this->settings['serialize'])) {
- if ($this->settings['isWindows']) {
- $data = str_replace('\\', '\\\\\\\\', serialize($data));
- } else {
- $data = serialize($data);
- }
- }
-
- $expires = time() + $duration;
- $contents = $expires . $lineBreak . $data . $lineBreak;
-
- if ($this->settings['lock']) {
- $this->_File->flock(LOCK_EX);
- }
-
- $this->_File->rewind();
- $success = $this->_File->ftruncate(0) && $this->_File->fwrite($contents) && $this->_File->fflush();
-
- if ($this->settings['lock']) {
- $this->_File->flock(LOCK_UN);
- }
-
- return $success;
- }
-
-/**
- * Read a key from the cache
- *
- * @param string $key Identifier for the data
- * @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
- */
- public function read($key) {
- if (!$this->_init || $this->_setKey($key) === false) {
- return false;
- }
-
- if ($this->settings['lock']) {
- $this->_File->flock(LOCK_SH);
- }
-
- $this->_File->rewind();
- $time = time();
- $cachetime = intval($this->_File->current());
-
- if ($cachetime !== false && ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime)) {
- if ($this->settings['lock']) {
- $this->_File->flock(LOCK_UN);
- }
- return false;
- }
-
- $data = '';
- $this->_File->next();
- while ($this->_File->valid()) {
- $data .= $this->_File->current();
- $this->_File->next();
- }
-
- if ($this->settings['lock']) {
- $this->_File->flock(LOCK_UN);
- }
-
- $data = trim($data);
-
- if ($data !== '' && !empty($this->settings['serialize'])) {
- if ($this->settings['isWindows']) {
- $data = str_replace('\\\\\\\\', '\\', $data);
- }
- $data = unserialize((string)$data);
- }
- return $data;
- }
-
-/**
- * Delete a key from the cache
- *
- * @param string $key Identifier for the data
- * @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
- */
- public function delete($key) {
- if ($this->_setKey($key) === false || !$this->_init) {
- return false;
- }
- $path = $this->_File->getRealPath();
- $this->_File = null;
- return unlink($path);
- }
-
-/**
- * Delete all values from the cache
- *
- * @param boolean $check Optional - only delete expired cache items
- * @return boolean True if the cache was successfully cleared, false otherwise
- */
- public function clear($check) {
- if (!$this->_init) {
- return false;
- }
- $dir = dir($this->settings['path']);
- if ($check) {
- $now = time();
- $threshold = $now - $this->settings['duration'];
- }
- $prefixLength = strlen($this->settings['prefix']);
- while (($entry = $dir->read()) !== false) {
- if (substr($entry, 0, $prefixLength) !== $this->settings['prefix']) {
- continue;
- }
- if ($this->_setKey($entry) === false) {
- continue;
- }
- if ($check) {
- $mtime = $this->_File->getMTime();
-
- if ($mtime > $threshold) {
- continue;
- }
-
- $expires = (int)$this->_File->current();
-
- if ($expires > $now) {
- continue;
- }
- }
- $path = $this->_File->getRealPath();
- $this->_File = null;
- if (file_exists($path)) {
- unlink($path);
- }
- }
- $dir->close();
- return true;
- }
-
-/**
- * Not implemented
- *
- * @param string $key
- * @param integer $offset
- * @return void
- * @throws CacheException
- */
- public function decrement($key, $offset = 1) {
- throw new CacheException(__d('cake_dev', 'Files cannot be atomically decremented.'));
- }
-
-/**
- * Not implemented
- *
- * @param string $key
- * @param integer $offset
- * @return void
- * @throws CacheException
- */
- public function increment($key, $offset = 1) {
- throw new CacheException(__d('cake_dev', 'Files cannot be atomically incremented.'));
- }
-
-/**
- * Sets the current cache key this class is managing, and creates a writable SplFileObject
- * for the cache file the key is referring to.
- *
- * @param string $key The key
- * @param boolean $createKey Whether the key should be created if it doesn't exists, or not
- * @return boolean true if the cache key could be set, false otherwise
- */
- protected function _setKey($key, $createKey = false) {
- $path = new SplFileInfo($this->settings['path'] . $key);
-
- if (!$createKey && !$path->isFile()) {
- return false;
- }
- if (empty($this->_File) || $this->_File->getBaseName() !== $key) {
- $exists = file_exists($path->getPathname());
- try {
- $this->_File = $path->openFile('c+');
- } catch (Exception $e) {
- trigger_error($e->getMessage(), E_USER_WARNING);
- return false;
- }
- unset($path);
-
- if (!$exists && !chmod($this->_File->getPathname(), (int)$this->settings['mask'])) {
- trigger_error(__d(
- 'cake_dev', 'Could not apply permission mask "%s" on cache file "%s"',
- array($this->_File->getPathname(), $this->settings['mask'])), E_USER_WARNING);
- }
- }
- return true;
- }
-
-/**
- * Determine is cache directory is writable
- *
- * @return boolean
- */
- protected function _active() {
- $dir = new SplFileInfo($this->settings['path']);
- if ($this->_init && !($dir->isDir() && $dir->isWritable())) {
- $this->_init = false;
- trigger_error(__d('cake_dev', '%s is not writable', $this->settings['path']), E_USER_WARNING);
- return false;
- }
- return true;
- }
-
-}
diff --git a/lib/Cake/Cache/Engine/MemcacheEngine.php b/lib/Cake/Cache/Engine/MemcacheEngine.php
deleted file mode 100644
index e68035c3f05..00000000000
--- a/lib/Cake/Cache/Engine/MemcacheEngine.php
+++ /dev/null
@@ -1,238 +0,0 @@
- 127.0.0.1. If an
- * array MemcacheEngine will use them as a pool.
- * - compress = boolean, default => false
- *
- * @var array
- */
- public $settings = array();
-
-/**
- * Initialize the Cache Engine
- *
- * Called automatically by the cache frontend
- * To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
- *
- * @param array $settings array of setting for the engine
- * @return boolean True if the engine has been successfully initialized, false if not
- */
- public function init($settings = array()) {
- if (!class_exists('Memcache')) {
- return false;
- }
- parent::init(array_merge(array(
- 'engine' => 'Memcache',
- 'prefix' => Inflector::slug(APP_DIR) . '_',
- 'servers' => array('127.0.0.1'),
- 'compress' => false,
- 'persistent' => true
- ), $settings)
- );
-
- if ($this->settings['compress']) {
- $this->settings['compress'] = MEMCACHE_COMPRESSED;
- }
- if (!is_array($this->settings['servers'])) {
- $this->settings['servers'] = array($this->settings['servers']);
- }
- if (!isset($this->_Memcache)) {
- $return = false;
- $this->_Memcache = new Memcache();
- foreach ($this->settings['servers'] as $server) {
- list($host, $port) = $this->_parseServerString($server);
- if ($this->_Memcache->addServer($host, $port, $this->settings['persistent'])) {
- $return = true;
- }
- }
- return $return;
- }
- return true;
- }
-
-/**
- * Parses the server address into the host/port. Handles both IPv6 and IPv4
- * addresses and Unix sockets
- *
- * @param string $server The server address string.
- * @return array Array containing host, port
- */
- protected function _parseServerString($server) {
- if ($server[0] == 'u') {
- return array($server, 0);
- }
- if (substr($server, 0, 1) == '[') {
- $position = strpos($server, ']:');
- if ($position !== false) {
- $position++;
- }
- } else {
- $position = strpos($server, ':');
- }
- $port = 11211;
- $host = $server;
- if ($position !== false) {
- $host = substr($server, 0, $position);
- $port = substr($server, $position + 1);
- }
- return array($host, $port);
- }
-
-/**
- * Write data for key into cache. When using memcache as your cache engine
- * remember that the Memcache pecl extension does not support cache expiry times greater
- * than 30 days in the future. Any duration greater than 30 days will be treated as never expiring.
- *
- * @param string $key Identifier for the data
- * @param mixed $value Data to be cached
- * @param integer $duration How long to cache the data, in seconds
- * @return boolean True if the data was successfully cached, false on failure
- * @see http://php.net/manual/en/memcache.set.php
- */
- public function write($key, $value, $duration) {
- if ($duration > 30 * DAY) {
- $duration = 0;
- }
- return $this->_Memcache->set($key, $value, $this->settings['compress'], $duration);
- }
-
-/**
- * Read a key from the cache
- *
- * @param string $key Identifier for the data
- * @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
- */
- public function read($key) {
- return $this->_Memcache->get($key);
- }
-
-/**
- * Increments the value of an integer cached key
- *
- * @param string $key Identifier for the data
- * @param integer $offset How much to increment
- * @return New incremented value, false otherwise
- * @throws CacheException when you try to increment with compress = true
- */
- public function increment($key, $offset = 1) {
- if ($this->settings['compress']) {
- throw new CacheException(
- __d('cake_dev', 'Method increment() not implemented for compressed cache in %s', __CLASS__)
- );
- }
- return $this->_Memcache->increment($key, $offset);
- }
-
-/**
- * Decrements the value of an integer cached key
- *
- * @param string $key Identifier for the data
- * @param integer $offset How much to subtract
- * @return New decremented value, false otherwise
- * @throws CacheException when you try to decrement with compress = true
- */
- public function decrement($key, $offset = 1) {
- if ($this->settings['compress']) {
- throw new CacheException(
- __d('cake_dev', 'Method decrement() not implemented for compressed cache in %s', __CLASS__)
- );
- }
- return $this->_Memcache->decrement($key, $offset);
- }
-
-/**
- * Delete a key from the cache
- *
- * @param string $key Identifier for the data
- * @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
- */
- public function delete($key) {
- return $this->_Memcache->delete($key);
- }
-
-/**
- * Delete all keys from the cache
- *
- * @param boolean $check
- * @return boolean True if the cache was successfully cleared, false otherwise
- */
- public function clear($check) {
- if ($check) {
- return true;
- }
- foreach ($this->_Memcache->getExtendedStats('slabs') as $slabs) {
- foreach (array_keys($slabs) as $slabId) {
- if (!is_numeric($slabId)) {
- continue;
- }
-
- foreach ($this->_Memcache->getExtendedStats('cachedump', $slabId) as $stats) {
- if (!is_array($stats)) {
- continue;
- }
- foreach (array_keys($stats) as $key) {
- if (strpos($key, $this->settings['prefix']) === 0) {
- $this->_Memcache->delete($key);
- }
- }
- }
- }
- }
- return true;
- }
-
-/**
- * Connects to a server in connection pool
- *
- * @param string $host host ip address or name
- * @param integer $port Server port
- * @return boolean True if memcache server was connected
- */
- public function connect($host, $port = 11211) {
- if ($this->_Memcache->getServerStatus($host, $port) === 0) {
- if ($this->_Memcache->connect($host, $port)) {
- return true;
- }
- return false;
- }
- return true;
- }
-
-}
diff --git a/lib/Cake/Cache/Engine/WincacheEngine.php b/lib/Cake/Cache/Engine/WincacheEngine.php
deleted file mode 100644
index f6dc6de240c..00000000000
--- a/lib/Cake/Cache/Engine/WincacheEngine.php
+++ /dev/null
@@ -1,137 +0,0 @@
- 'Wincache',
- 'prefix' => Inflector::slug(APP_DIR) . '_'),
- $settings));
- return function_exists('wincache_ucache_info');
- }
-
-/**
- * Write data for key into cache
- *
- * @param string $key Identifier for the data
- * @param mixed $value Data to be cached
- * @param integer $duration How long to cache the data, in seconds
- * @return boolean True if the data was successfully cached, false on failure
- */
- public function write($key, $value, $duration) {
- $expires = time() + $duration;
-
- $data = array(
- $key . '_expires' => $expires,
- $key => $value
- );
- $result = wincache_ucache_set($data, null, $duration);
- return empty($result);
- }
-
-/**
- * Read a key from the cache
- *
- * @param string $key Identifier for the data
- * @return mixed The cached data, or false if the data doesn't exist, has expired, or if
- * there was an error fetching it
- */
- public function read($key) {
- $time = time();
- $cachetime = intval(wincache_ucache_get($key . '_expires'));
- if ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime) {
- return false;
- }
- return wincache_ucache_get($key);
- }
-
-/**
- * Increments the value of an integer cached key
- *
- * @param string $key Identifier for the data
- * @param integer $offset How much to increment
- * @return New incremented value, false otherwise
- */
- public function increment($key, $offset = 1) {
- return wincache_ucache_inc($key, $offset);
- }
-
-/**
- * Decrements the value of an integer cached key
- *
- * @param string $key Identifier for the data
- * @param integer $offset How much to subtract
- * @return New decremented value, false otherwise
- */
- public function decrement($key, $offset = 1) {
- return wincache_ucache_dec($key, $offset);
- }
-
-/**
- * Delete a key from the cache
- *
- * @param string $key Identifier for the data
- * @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
- */
- public function delete($key) {
- return wincache_ucache_delete($key);
- }
-
-/**
- * Delete all keys from the cache. This will clear every
- * item in the cache matching the cache config prefix.
- *
- * @param boolean $check If true, nothing will be cleared, as entries will
- * naturally expire in wincache..
- * @return boolean True Returns true.
- */
- public function clear($check) {
- if ($check) {
- return true;
- }
- $info = wincache_ucache_info();
- $cacheKeys = $info['ucache_entries'];
- unset($info);
- foreach ($cacheKeys as $key) {
- if (strpos($key['key_name'], $this->settings['prefix']) === 0) {
- wincache_ucache_delete($key['key_name']);
- }
- }
- return true;
- }
-
-}
diff --git a/lib/Cake/Cache/Engine/XcacheEngine.php b/lib/Cake/Cache/Engine/XcacheEngine.php
deleted file mode 100644
index d41cfdb6db1..00000000000
--- a/lib/Cake/Cache/Engine/XcacheEngine.php
+++ /dev/null
@@ -1,177 +0,0 @@
- 'Xcache',
- 'prefix' => Inflector::slug(APP_DIR) . '_',
- 'PHP_AUTH_USER' => 'user',
- 'PHP_AUTH_PW' => 'password'
- ), $settings)
- );
- return function_exists('xcache_info');
- }
-
-/**
- * Write data for key into cache
- *
- * @param string $key Identifier for the data
- * @param mixed $value Data to be cached
- * @param integer $duration How long to cache the data, in seconds
- * @return boolean True if the data was successfully cached, false on failure
- */
- public function write($key, $value, $duration) {
- $expires = time() + $duration;
- xcache_set($key . '_expires', $expires, $duration);
- return xcache_set($key, $value, $duration);
- }
-
-/**
- * Read a key from the cache
- *
- * @param string $key Identifier for the data
- * @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
- */
- public function read($key) {
- if (xcache_isset($key)) {
- $time = time();
- $cachetime = intval(xcache_get($key . '_expires'));
- if ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime) {
- return false;
- }
- return xcache_get($key);
- }
- return false;
- }
-
-/**
- * Increments the value of an integer cached key
- * If the cache key is not an integer it will be treated as 0
- *
- * @param string $key Identifier for the data
- * @param integer $offset How much to increment
- * @return New incremented value, false otherwise
- */
- public function increment($key, $offset = 1) {
- return xcache_inc($key, $offset);
- }
-
-/**
- * Decrements the value of an integer cached key.
- * If the cache key is not an integer it will be treated as 0
- *
- * @param string $key Identifier for the data
- * @param integer $offset How much to subtract
- * @return New decremented value, false otherwise
- */
- public function decrement($key, $offset = 1) {
- return xcache_dec($key, $offset);
- }
-
-/**
- * Delete a key from the cache
- *
- * @param string $key Identifier for the data
- * @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
- */
- public function delete($key) {
- return xcache_unset($key);
- }
-
-/**
- * Delete all keys from the cache
- *
- * @param boolean $check
- * @return boolean True if the cache was successfully cleared, false otherwise
- */
- public function clear($check) {
- $this->_auth();
- $max = xcache_count(XC_TYPE_VAR);
- for ($i = 0; $i < $max; $i++) {
- xcache_clear_cache(XC_TYPE_VAR, $i);
- }
- $this->_auth(true);
- return true;
- }
-
-/**
- * Populates and reverses $_SERVER authentication values
- * Makes necessary changes (and reverting them back) in $_SERVER
- *
- * This has to be done because xcache_clear_cache() needs to pass Basic Http Auth
- * (see xcache.admin configuration settings)
- *
- * @param boolean $reverse Revert changes
- * @return void
- */
- protected function _auth($reverse = false) {
- static $backup = array();
- $keys = array('PHP_AUTH_USER' => 'user', 'PHP_AUTH_PW' => 'password');
- foreach ($keys as $key => $setting) {
- if ($reverse) {
- if (isset($backup[$key])) {
- $_SERVER[$key] = $backup[$key];
- unset($backup[$key]);
- } else {
- unset($_SERVER[$key]);
- }
- } else {
- $value = env($key);
- if (!empty($value)) {
- $backup[$key] = $value;
- }
- if (!empty($this->settings[$setting])) {
- $_SERVER[$key] = $this->settings[$setting];
- } elseif (!empty($this->settings[$key])) {
- $_SERVER[$key] = $this->settings[$key];
- } else {
- $_SERVER[$key] = $value;
- }
- }
- }
- }
-
-}
diff --git a/lib/Cake/Config/config.php b/lib/Cake/Config/config.php
deleted file mode 100644
index f8528e8ef14..00000000000
--- a/lib/Cake/Config/config.php
+++ /dev/null
@@ -1,21 +0,0 @@
- $value) {
- $plugins[$key] = Inflector::underscore($value);
- }
- $pluginPattern = implode('|', $plugins);
- $match = array('plugin' => $pluginPattern);
- $shortParams = array('routeClass' => 'PluginShortRoute', 'plugin' => $pluginPattern);
-
- foreach ($prefixes as $prefix) {
- $params = array('prefix' => $prefix, $prefix => true);
- $indexParams = $params + array('action' => 'index');
- Router::connect("/{$prefix}/:plugin", $indexParams, $shortParams);
- Router::connect("/{$prefix}/:plugin/:controller", $indexParams, $match);
- Router::connect("/{$prefix}/:plugin/:controller/:action/*", $params, $match);
- }
- Router::connect('/:plugin', array('action' => 'index'), $shortParams);
- Router::connect('/:plugin/:controller', array('action' => 'index'), $match);
- Router::connect('/:plugin/:controller/:action/*', array(), $match);
-}
-
-foreach ($prefixes as $prefix) {
- $params = array('prefix' => $prefix, $prefix => true);
- $indexParams = $params + array('action' => 'index');
- Router::connect("/{$prefix}/:controller", $indexParams);
- Router::connect("/{$prefix}/:controller/:action/*", $params);
-}
-Router::connect('/:controller', array('action' => 'index'));
-Router::connect('/:controller/:action/*');
-
-$namedConfig = Router::namedConfig();
-if ($namedConfig['rules'] === false) {
- Router::connectNamed(true);
-}
-
-unset($namedConfig, $params, $indexParams, $prefix, $prefixes, $shortParams, $match,
- $pluginPattern, $plugins, $key, $value);
diff --git a/lib/Cake/Config/unicode/casefolding/0080_00ff.php b/lib/Cake/Config/unicode/casefolding/0080_00ff.php
deleted file mode 100644
index 542f47d2b37..00000000000
--- a/lib/Cake/Config/unicode/casefolding/0080_00ff.php
+++ /dev/null
@@ -1,73 +0,0 @@
- 181, 'status' => 'C', 'lower' => array(956));
-$config['0080_00ff'][] = array('upper' => 924, 'status' => 'C', 'lower' => array(181));
-$config['0080_00ff'][] = array('upper' => 192, 'status' => 'C', 'lower' => array(224)); /* LATIN CAPITAL LETTER A WITH GRAVE */
-$config['0080_00ff'][] = array('upper' => 193, 'status' => 'C', 'lower' => array(225)); /* LATIN CAPITAL LETTER A WITH ACUTE */
-$config['0080_00ff'][] = array('upper' => 194, 'status' => 'C', 'lower' => array(226)); /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
-$config['0080_00ff'][] = array('upper' => 195, 'status' => 'C', 'lower' => array(227)); /* LATIN CAPITAL LETTER A WITH TILDE */
-$config['0080_00ff'][] = array('upper' => 196, 'status' => 'C', 'lower' => array(228)); /* LATIN CAPITAL LETTER A WITH DIAERESIS */
-$config['0080_00ff'][] = array('upper' => 197, 'status' => 'C', 'lower' => array(229)); /* LATIN CAPITAL LETTER A WITH RING ABOVE */
-$config['0080_00ff'][] = array('upper' => 198, 'status' => 'C', 'lower' => array(230)); /* LATIN CAPITAL LETTER AE */
-$config['0080_00ff'][] = array('upper' => 199, 'status' => 'C', 'lower' => array(231)); /* LATIN CAPITAL LETTER C WITH CEDILLA */
-$config['0080_00ff'][] = array('upper' => 200, 'status' => 'C', 'lower' => array(232)); /* LATIN CAPITAL LETTER E WITH GRAVE */
-$config['0080_00ff'][] = array('upper' => 201, 'status' => 'C', 'lower' => array(233)); /* LATIN CAPITAL LETTER E WITH ACUTE */
-$config['0080_00ff'][] = array('upper' => 202, 'status' => 'C', 'lower' => array(234)); /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
-$config['0080_00ff'][] = array('upper' => 203, 'status' => 'C', 'lower' => array(235)); /* LATIN CAPITAL LETTER E WITH DIAERESIS */
-$config['0080_00ff'][] = array('upper' => 204, 'status' => 'C', 'lower' => array(236)); /* LATIN CAPITAL LETTER I WITH GRAVE */
-$config['0080_00ff'][] = array('upper' => 205, 'status' => 'C', 'lower' => array(237)); /* LATIN CAPITAL LETTER I WITH ACUTE */
-$config['0080_00ff'][] = array('upper' => 206, 'status' => 'C', 'lower' => array(238)); /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
-$config['0080_00ff'][] = array('upper' => 207, 'status' => 'C', 'lower' => array(239)); /* LATIN CAPITAL LETTER I WITH DIAERESIS */
-$config['0080_00ff'][] = array('upper' => 208, 'status' => 'C', 'lower' => array(240)); /* LATIN CAPITAL LETTER ETH */
-$config['0080_00ff'][] = array('upper' => 209, 'status' => 'C', 'lower' => array(241)); /* LATIN CAPITAL LETTER N WITH TILDE */
-$config['0080_00ff'][] = array('upper' => 210, 'status' => 'C', 'lower' => array(242)); /* LATIN CAPITAL LETTER O WITH GRAVE */
-$config['0080_00ff'][] = array('upper' => 211, 'status' => 'C', 'lower' => array(243)); /* LATIN CAPITAL LETTER O WITH ACUTE */
-$config['0080_00ff'][] = array('upper' => 212, 'status' => 'C', 'lower' => array(244)); /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
-$config['0080_00ff'][] = array('upper' => 213, 'status' => 'C', 'lower' => array(245)); /* LATIN CAPITAL LETTER O WITH TILDE */
-$config['0080_00ff'][] = array('upper' => 214, 'status' => 'C', 'lower' => array(246)); /* LATIN CAPITAL LETTER O WITH DIAERESIS */
-$config['0080_00ff'][] = array('upper' => 216, 'status' => 'C', 'lower' => array(248)); /* LATIN CAPITAL LETTER O WITH STROKE */
-$config['0080_00ff'][] = array('upper' => 217, 'status' => 'C', 'lower' => array(249)); /* LATIN CAPITAL LETTER U WITH GRAVE */
-$config['0080_00ff'][] = array('upper' => 218, 'status' => 'C', 'lower' => array(250)); /* LATIN CAPITAL LETTER U WITH ACUTE */
-$config['0080_00ff'][] = array('upper' => 219, 'status' => 'C', 'lower' => array(251)); /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
-$config['0080_00ff'][] = array('upper' => 220, 'status' => 'C', 'lower' => array(252)); /* LATIN CAPITAL LETTER U WITH DIAERESIS */
-$config['0080_00ff'][] = array('upper' => 221, 'status' => 'C', 'lower' => array(253)); /* LATIN CAPITAL LETTER Y WITH ACUTE */
-$config['0080_00ff'][] = array('upper' => 222, 'status' => 'C', 'lower' => array(254)); /* LATIN CAPITAL LETTER THORN */
-$config['0080_00ff'][] = array('upper' => 223, 'status' => 'F', 'lower' => array(115, 115)); /* LATIN SMALL LETTER SHARP S */
diff --git a/lib/Cake/Config/unicode/casefolding/0100_017f.php b/lib/Cake/Config/unicode/casefolding/0100_017f.php
deleted file mode 100644
index e8c3ff6c427..00000000000
--- a/lib/Cake/Config/unicode/casefolding/0100_017f.php
+++ /dev/null
@@ -1,106 +0,0 @@
- 256, 'status' => 'C', 'lower' => array(257)); /* LATIN CAPITAL LETTER A WITH MACRON */
-$config['0100_017f'][] = array('upper' => 258, 'status' => 'C', 'lower' => array(259)); /* LATIN CAPITAL LETTER A WITH BREVE */
-$config['0100_017f'][] = array('upper' => 260, 'status' => 'C', 'lower' => array(261)); /* LATIN CAPITAL LETTER A WITH OGONEK */
-$config['0100_017f'][] = array('upper' => 262, 'status' => 'C', 'lower' => array(263)); /* LATIN CAPITAL LETTER C WITH ACUTE */
-$config['0100_017f'][] = array('upper' => 264, 'status' => 'C', 'lower' => array(265)); /* LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
-$config['0100_017f'][] = array('upper' => 266, 'status' => 'C', 'lower' => array(267)); /* LATIN CAPITAL LETTER C WITH DOT ABOVE */
-$config['0100_017f'][] = array('upper' => 268, 'status' => 'C', 'lower' => array(269)); /* LATIN CAPITAL LETTER C WITH CARON */
-$config['0100_017f'][] = array('upper' => 270, 'status' => 'C', 'lower' => array(271)); /* LATIN CAPITAL LETTER D WITH CARON */
-$config['0100_017f'][] = array('upper' => 272, 'status' => 'C', 'lower' => array(273)); /* LATIN CAPITAL LETTER D WITH STROKE */
-$config['0100_017f'][] = array('upper' => 274, 'status' => 'C', 'lower' => array(275)); /* LATIN CAPITAL LETTER E WITH MACRON */
-$config['0100_017f'][] = array('upper' => 276, 'status' => 'C', 'lower' => array(277)); /* LATIN CAPITAL LETTER E WITH BREVE */
-$config['0100_017f'][] = array('upper' => 278, 'status' => 'C', 'lower' => array(279)); /* LATIN CAPITAL LETTER E WITH DOT ABOVE */
-$config['0100_017f'][] = array('upper' => 280, 'status' => 'C', 'lower' => array(281)); /* LATIN CAPITAL LETTER E WITH OGONEK */
-$config['0100_017f'][] = array('upper' => 282, 'status' => 'C', 'lower' => array(283)); /* LATIN CAPITAL LETTER E WITH CARON */
-$config['0100_017f'][] = array('upper' => 284, 'status' => 'C', 'lower' => array(285)); /* LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
-$config['0100_017f'][] = array('upper' => 286, 'status' => 'C', 'lower' => array(287)); /* LATIN CAPITAL LETTER G WITH BREVE */
-$config['0100_017f'][] = array('upper' => 288, 'status' => 'C', 'lower' => array(289)); /* LATIN CAPITAL LETTER G WITH DOT ABOVE */
-$config['0100_017f'][] = array('upper' => 290, 'status' => 'C', 'lower' => array(291)); /* LATIN CAPITAL LETTER G WITH CEDILLA */
-$config['0100_017f'][] = array('upper' => 292, 'status' => 'C', 'lower' => array(293)); /* LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
-$config['0100_017f'][] = array('upper' => 294, 'status' => 'C', 'lower' => array(295)); /* LATIN CAPITAL LETTER H WITH STROKE */
-$config['0100_017f'][] = array('upper' => 296, 'status' => 'C', 'lower' => array(297)); /* LATIN CAPITAL LETTER I WITH TILDE */
-$config['0100_017f'][] = array('upper' => 298, 'status' => 'C', 'lower' => array(299)); /* LATIN CAPITAL LETTER I WITH MACRON */
-$config['0100_017f'][] = array('upper' => 300, 'status' => 'C', 'lower' => array(301)); /* LATIN CAPITAL LETTER I WITH BREVE */
-$config['0100_017f'][] = array('upper' => 302, 'status' => 'C', 'lower' => array(303)); /* LATIN CAPITAL LETTER I WITH OGONEK */
-$config['0100_017f'][] = array('upper' => 304, 'status' => 'F', 'lower' => array(105, 775)); /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
-$config['0100_017f'][] = array('upper' => 304, 'status' => 'T', 'lower' => array(105)); /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
-$config['0100_017f'][] = array('upper' => 306, 'status' => 'C', 'lower' => array(307)); /* LATIN CAPITAL LIGATURE IJ */
-$config['0100_017f'][] = array('upper' => 308, 'status' => 'C', 'lower' => array(309)); /* LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
-$config['0100_017f'][] = array('upper' => 310, 'status' => 'C', 'lower' => array(311)); /* LATIN CAPITAL LETTER K WITH CEDILLA */
-$config['0100_017f'][] = array('upper' => 313, 'status' => 'C', 'lower' => array(314)); /* LATIN CAPITAL LETTER L WITH ACUTE */
-$config['0100_017f'][] = array('upper' => 315, 'status' => 'C', 'lower' => array(316)); /* LATIN CAPITAL LETTER L WITH CEDILLA */
-$config['0100_017f'][] = array('upper' => 317, 'status' => 'C', 'lower' => array(318)); /* LATIN CAPITAL LETTER L WITH CARON */
-$config['0100_017f'][] = array('upper' => 319, 'status' => 'C', 'lower' => array(320)); /* LATIN CAPITAL LETTER L WITH MIDDLE DOT */
-$config['0100_017f'][] = array('upper' => 321, 'status' => 'C', 'lower' => array(322)); /* LATIN CAPITAL LETTER L WITH STROKE */
-$config['0100_017f'][] = array('upper' => 323, 'status' => 'C', 'lower' => array(324)); /* LATIN CAPITAL LETTER N WITH ACUTE */
-$config['0100_017f'][] = array('upper' => 325, 'status' => 'C', 'lower' => array(326)); /* LATIN CAPITAL LETTER N WITH CEDILLA */
-$config['0100_017f'][] = array('upper' => 327, 'status' => 'C', 'lower' => array(328)); /* LATIN CAPITAL LETTER N WITH CARON */
-$config['0100_017f'][] = array('upper' => 329, 'status' => 'F', 'lower' => array(700, 110)); /* LATIN SMALL LETTER N PRECEDED BY APOSTROPHE */
-$config['0100_017f'][] = array('upper' => 330, 'status' => 'C', 'lower' => array(331)); /* LATIN CAPITAL LETTER ENG */
-$config['0100_017f'][] = array('upper' => 332, 'status' => 'C', 'lower' => array(333)); /* LATIN CAPITAL LETTER O WITH MACRON */
-$config['0100_017f'][] = array('upper' => 334, 'status' => 'C', 'lower' => array(335)); /* LATIN CAPITAL LETTER O WITH BREVE */
-$config['0100_017f'][] = array('upper' => 336, 'status' => 'C', 'lower' => array(337)); /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
-$config['0100_017f'][] = array('upper' => 338, 'status' => 'C', 'lower' => array(339)); /* LATIN CAPITAL LIGATURE OE */
-$config['0100_017f'][] = array('upper' => 340, 'status' => 'C', 'lower' => array(341)); /* LATIN CAPITAL LETTER R WITH ACUTE */
-$config['0100_017f'][] = array('upper' => 342, 'status' => 'C', 'lower' => array(343)); /* LATIN CAPITAL LETTER R WITH CEDILLA */
-$config['0100_017f'][] = array('upper' => 344, 'status' => 'C', 'lower' => array(345)); /* LATIN CAPITAL LETTER R WITH CARON */
-$config['0100_017f'][] = array('upper' => 346, 'status' => 'C', 'lower' => array(347)); /* LATIN CAPITAL LETTER S WITH ACUTE */
-$config['0100_017f'][] = array('upper' => 348, 'status' => 'C', 'lower' => array(349)); /* LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
-$config['0100_017f'][] = array('upper' => 350, 'status' => 'C', 'lower' => array(351)); /* LATIN CAPITAL LETTER S WITH CEDILLA */
-$config['0100_017f'][] = array('upper' => 352, 'status' => 'C', 'lower' => array(353)); /* LATIN CAPITAL LETTER S WITH CARON */
-$config['0100_017f'][] = array('upper' => 354, 'status' => 'C', 'lower' => array(355)); /* LATIN CAPITAL LETTER T WITH CEDILLA */
-$config['0100_017f'][] = array('upper' => 356, 'status' => 'C', 'lower' => array(357)); /* LATIN CAPITAL LETTER T WITH CARON */
-$config['0100_017f'][] = array('upper' => 358, 'status' => 'C', 'lower' => array(359)); /* LATIN CAPITAL LETTER T WITH STROKE */
-$config['0100_017f'][] = array('upper' => 360, 'status' => 'C', 'lower' => array(361)); /* LATIN CAPITAL LETTER U WITH TILDE */
-$config['0100_017f'][] = array('upper' => 362, 'status' => 'C', 'lower' => array(363)); /* LATIN CAPITAL LETTER U WITH MACRON */
-$config['0100_017f'][] = array('upper' => 364, 'status' => 'C', 'lower' => array(365)); /* LATIN CAPITAL LETTER U WITH BREVE */
-$config['0100_017f'][] = array('upper' => 366, 'status' => 'C', 'lower' => array(367)); /* LATIN CAPITAL LETTER U WITH RING ABOVE */
-$config['0100_017f'][] = array('upper' => 368, 'status' => 'C', 'lower' => array(369)); /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
-$config['0100_017f'][] = array('upper' => 370, 'status' => 'C', 'lower' => array(371)); /* LATIN CAPITAL LETTER U WITH OGONEK */
-$config['0100_017f'][] = array('upper' => 372, 'status' => 'C', 'lower' => array(373)); /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX */
-$config['0100_017f'][] = array('upper' => 374, 'status' => 'C', 'lower' => array(375)); /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */
-$config['0100_017f'][] = array('upper' => 376, 'status' => 'C', 'lower' => array(255)); /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
-$config['0100_017f'][] = array('upper' => 377, 'status' => 'C', 'lower' => array(378)); /* LATIN CAPITAL LETTER Z WITH ACUTE */
-$config['0100_017f'][] = array('upper' => 379, 'status' => 'C', 'lower' => array(380)); /* LATIN CAPITAL LETTER Z WITH DOT ABOVE */
-$config['0100_017f'][] = array('upper' => 381, 'status' => 'C', 'lower' => array(382)); /* LATIN CAPITAL LETTER Z WITH CARON */
-$config['0100_017f'][] = array('upper' => 383, 'status' => 'C', 'lower' => array(115)); /* LATIN SMALL LETTER LONG S */
diff --git a/lib/Cake/Config/unicode/casefolding/0180_024F.php b/lib/Cake/Config/unicode/casefolding/0180_024F.php
deleted file mode 100644
index e8baaa32c2f..00000000000
--- a/lib/Cake/Config/unicode/casefolding/0180_024F.php
+++ /dev/null
@@ -1,148 +0,0 @@
- 385, 'status' => 'C', 'lower' => array(595)); /* LATIN CAPITAL LETTER B WITH HOOK */
-$config['0180_024F'][] = array('upper' => 386, 'status' => 'C', 'lower' => array(387)); /* LATIN CAPITAL LETTER B WITH TOPBAR */
-$config['0180_024F'][] = array('upper' => 388, 'status' => 'C', 'lower' => array(389)); /* LATIN CAPITAL LETTER TONE SIX */
-$config['0180_024F'][] = array('upper' => 390, 'status' => 'C', 'lower' => array(596)); /* LATIN CAPITAL LETTER OPEN O */
-$config['0180_024F'][] = array('upper' => 391, 'status' => 'C', 'lower' => array(392)); /* LATIN CAPITAL LETTER C WITH HOOK */
-$config['0180_024F'][] = array('upper' => 393, 'status' => 'C', 'lower' => array(598)); /* LATIN CAPITAL LETTER AFRICAN D */
-$config['0180_024F'][] = array('upper' => 394, 'status' => 'C', 'lower' => array(599)); /* LATIN CAPITAL LETTER D WITH HOOK */
-$config['0180_024F'][] = array('upper' => 395, 'status' => 'C', 'lower' => array(396)); /* LATIN CAPITAL LETTER D WITH TOPBAR */
-$config['0180_024F'][] = array('upper' => 398, 'status' => 'C', 'lower' => array(477)); /* LATIN CAPITAL LETTER REVERSED E */
-$config['0180_024F'][] = array('upper' => 399, 'status' => 'C', 'lower' => array(601)); /* LATIN CAPITAL LETTER SCHWA */
-$config['0180_024F'][] = array('upper' => 400, 'status' => 'C', 'lower' => array(603)); /* LATIN CAPITAL LETTER OPEN E */
-$config['0180_024F'][] = array('upper' => 401, 'status' => 'C', 'lower' => array(402)); /* LATIN CAPITAL LETTER F WITH HOOK */
-$config['0180_024F'][] = array('upper' => 403, 'status' => 'C', 'lower' => array(608)); /* LATIN CAPITAL LETTER G WITH HOOK */
-$config['0180_024F'][] = array('upper' => 404, 'status' => 'C', 'lower' => array(611)); /* LATIN CAPITAL LETTER GAMMA */
-$config['0180_024F'][] = array('upper' => 406, 'status' => 'C', 'lower' => array(617)); /* LATIN CAPITAL LETTER IOTA */
-$config['0180_024F'][] = array('upper' => 407, 'status' => 'C', 'lower' => array(616)); /* LATIN CAPITAL LETTER I WITH STROKE */
-$config['0180_024F'][] = array('upper' => 408, 'status' => 'C', 'lower' => array(409)); /* LATIN CAPITAL LETTER K WITH HOOK */
-$config['0180_024F'][] = array('upper' => 412, 'status' => 'C', 'lower' => array(623)); /* LATIN CAPITAL LETTER TURNED M */
-$config['0180_024F'][] = array('upper' => 413, 'status' => 'C', 'lower' => array(626)); /* LATIN CAPITAL LETTER N WITH LEFT HOOK */
-$config['0180_024F'][] = array('upper' => 415, 'status' => 'C', 'lower' => array(629)); /* LATIN CAPITAL LETTER O WITH MIDDLE TILDE */
-$config['0180_024F'][] = array('upper' => 416, 'status' => 'C', 'lower' => array(417)); /* LATIN CAPITAL LETTER O WITH HORN */
-$config['0180_024F'][] = array('upper' => 418, 'status' => 'C', 'lower' => array(419)); /* LATIN CAPITAL LETTER OI */
-$config['0180_024F'][] = array('upper' => 420, 'status' => 'C', 'lower' => array(421)); /* LATIN CAPITAL LETTER P WITH HOOK */
-$config['0180_024F'][] = array('upper' => 422, 'status' => 'C', 'lower' => array(640)); /* LATIN LETTER YR */
-$config['0180_024F'][] = array('upper' => 423, 'status' => 'C', 'lower' => array(424)); /* LATIN CAPITAL LETTER TONE TWO */
-$config['0180_024F'][] = array('upper' => 425, 'status' => 'C', 'lower' => array(643)); /* LATIN CAPITAL LETTER ESH */
-$config['0180_024F'][] = array('upper' => 428, 'status' => 'C', 'lower' => array(429)); /* LATIN CAPITAL LETTER T WITH HOOK */
-$config['0180_024F'][] = array('upper' => 430, 'status' => 'C', 'lower' => array(648)); /* LATIN CAPITAL LETTER T WITH RETROFLEX HOOK */
-$config['0180_024F'][] = array('upper' => 431, 'status' => 'C', 'lower' => array(432)); /* LATIN CAPITAL LETTER U WITH HORN */
-$config['0180_024F'][] = array('upper' => 433, 'status' => 'C', 'lower' => array(650)); /* LATIN CAPITAL LETTER UPSILON */
-$config['0180_024F'][] = array('upper' => 434, 'status' => 'C', 'lower' => array(651)); /* LATIN CAPITAL LETTER V WITH HOOK */
-$config['0180_024F'][] = array('upper' => 435, 'status' => 'C', 'lower' => array(436)); /* LATIN CAPITAL LETTER Y WITH HOOK */
-$config['0180_024F'][] = array('upper' => 437, 'status' => 'C', 'lower' => array(438)); /* LATIN CAPITAL LETTER Z WITH STROKE */
-$config['0180_024F'][] = array('upper' => 439, 'status' => 'C', 'lower' => array(658)); /* LATIN CAPITAL LETTER EZH */
-$config['0180_024F'][] = array('upper' => 440, 'status' => 'C', 'lower' => array(441)); /* LATIN CAPITAL LETTER EZH REVERSED */
-$config['0180_024F'][] = array('upper' => 444, 'status' => 'C', 'lower' => array(445)); /* LATIN CAPITAL LETTER TONE FIVE */
-$config['0180_024F'][] = array('upper' => 452, 'status' => 'C', 'lower' => array(454)); /* LATIN CAPITAL LETTER DZ WITH CARON */
-$config['0180_024F'][] = array('upper' => 453, 'status' => 'C', 'lower' => array(454)); /* LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON */
-$config['0180_024F'][] = array('upper' => 455, 'status' => 'C', 'lower' => array(457)); /* LATIN CAPITAL LETTER LJ */
-$config['0180_024F'][] = array('upper' => 456, 'status' => 'C', 'lower' => array(457)); /* LATIN CAPITAL LETTER L WITH SMALL LETTER J */
-$config['0180_024F'][] = array('upper' => 458, 'status' => 'C', 'lower' => array(460)); /* LATIN CAPITAL LETTER NJ */
-$config['0180_024F'][] = array('upper' => 459, 'status' => 'C', 'lower' => array(460)); /* LATIN CAPITAL LETTER N WITH SMALL LETTER J */
-$config['0180_024F'][] = array('upper' => 461, 'status' => 'C', 'lower' => array(462)); /* LATIN CAPITAL LETTER A WITH CARON */
-$config['0180_024F'][] = array('upper' => 463, 'status' => 'C', 'lower' => array(464)); /* LATIN CAPITAL LETTER I WITH CARON */
-$config['0180_024F'][] = array('upper' => 465, 'status' => 'C', 'lower' => array(466)); /* LATIN CAPITAL LETTER O WITH CARON */
-$config['0180_024F'][] = array('upper' => 467, 'status' => 'C', 'lower' => array(468)); /* LATIN CAPITAL LETTER U WITH CARON */
-$config['0180_024F'][] = array('upper' => 469, 'status' => 'C', 'lower' => array(470)); /* LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON */
-$config['0180_024F'][] = array('upper' => 471, 'status' => 'C', 'lower' => array(472)); /* LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE */
-$config['0180_024F'][] = array('upper' => 473, 'status' => 'C', 'lower' => array(474)); /* LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON */
-$config['0180_024F'][] = array('upper' => 475, 'status' => 'C', 'lower' => array(476)); /* LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE */
-$config['0180_024F'][] = array('upper' => 478, 'status' => 'C', 'lower' => array(479)); /* LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON */
-$config['0180_024F'][] = array('upper' => 480, 'status' => 'C', 'lower' => array(481)); /* LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON */
-$config['0180_024F'][] = array('upper' => 482, 'status' => 'C', 'lower' => array(483)); /* LATIN CAPITAL LETTER AE WITH MACRON */
-$config['0180_024F'][] = array('upper' => 484, 'status' => 'C', 'lower' => array(485)); /* LATIN CAPITAL LETTER G WITH STROKE */
-$config['0180_024F'][] = array('upper' => 486, 'status' => 'C', 'lower' => array(487)); /* LATIN CAPITAL LETTER G WITH CARON */
-$config['0180_024F'][] = array('upper' => 488, 'status' => 'C', 'lower' => array(489)); /* LATIN CAPITAL LETTER K WITH CARON */
-$config['0180_024F'][] = array('upper' => 490, 'status' => 'C', 'lower' => array(491)); /* LATIN CAPITAL LETTER O WITH OGONEK */
-$config['0180_024F'][] = array('upper' => 492, 'status' => 'C', 'lower' => array(493)); /* LATIN CAPITAL LETTER O WITH OGONEK AND MACRON */
-$config['0180_024F'][] = array('upper' => 494, 'status' => 'C', 'lower' => array(495)); /* LATIN CAPITAL LETTER EZH WITH CARON */
-$config['0180_024F'][] = array('upper' => 496, 'status' => 'F', 'lower' => array(106, 780)); /* LATIN SMALL LETTER J WITH CARON */
-$config['0180_024F'][] = array('upper' => 497, 'status' => 'C', 'lower' => array(499)); /* LATIN CAPITAL LETTER DZ */
-$config['0180_024F'][] = array('upper' => 498, 'status' => 'C', 'lower' => array(499)); /* LATIN CAPITAL LETTER D WITH SMALL LETTER Z */
-$config['0180_024F'][] = array('upper' => 500, 'status' => 'C', 'lower' => array(501)); /* LATIN CAPITAL LETTER G WITH ACUTE */
-$config['0180_024F'][] = array('upper' => 502, 'status' => 'C', 'lower' => array(405)); /* LATIN CAPITAL LETTER HWAIR */
-$config['0180_024F'][] = array('upper' => 503, 'status' => 'C', 'lower' => array(447)); /* LATIN CAPITAL LETTER WYNN */
-$config['0180_024F'][] = array('upper' => 504, 'status' => 'C', 'lower' => array(505)); /* LATIN CAPITAL LETTER N WITH GRAVE */
-$config['0180_024F'][] = array('upper' => 506, 'status' => 'C', 'lower' => array(507)); /* LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE */
-$config['0180_024F'][] = array('upper' => 508, 'status' => 'C', 'lower' => array(509)); /* LATIN CAPITAL LETTER AE WITH ACUTE */
-$config['0180_024F'][] = array('upper' => 510, 'status' => 'C', 'lower' => array(511)); /* LATIN CAPITAL LETTER O WITH STROKE AND ACUTE */
-$config['0180_024F'][] = array('upper' => 512, 'status' => 'C', 'lower' => array(513)); /* LATIN CAPITAL LETTER A WITH DOUBLE GRAVE */
-$config['0180_024F'][] = array('upper' => 514, 'status' => 'C', 'lower' => array(515)); /* LATIN CAPITAL LETTER A WITH INVERTED BREVE */
-$config['0180_024F'][] = array('upper' => 516, 'status' => 'C', 'lower' => array(517)); /* LATIN CAPITAL LETTER E WITH DOUBLE GRAVE */
-$config['0180_024F'][] = array('upper' => 518, 'status' => 'C', 'lower' => array(519)); /* LATIN CAPITAL LETTER E WITH INVERTED BREVE */
-$config['0180_024F'][] = array('upper' => 520, 'status' => 'C', 'lower' => array(521)); /* LATIN CAPITAL LETTER I WITH DOUBLE GRAVE */
-$config['0180_024F'][] = array('upper' => 522, 'status' => 'C', 'lower' => array(523)); /* LATIN CAPITAL LETTER I WITH INVERTED BREVE */
-$config['0180_024F'][] = array('upper' => 524, 'status' => 'C', 'lower' => array(525)); /* LATIN CAPITAL LETTER O WITH DOUBLE GRAVE */
-$config['0180_024F'][] = array('upper' => 526, 'status' => 'C', 'lower' => array(527)); /* LATIN CAPITAL LETTER O WITH INVERTED BREVE */
-$config['0180_024F'][] = array('upper' => 528, 'status' => 'C', 'lower' => array(529)); /* LATIN CAPITAL LETTER R WITH DOUBLE GRAVE */
-$config['0180_024F'][] = array('upper' => 530, 'status' => 'C', 'lower' => array(531)); /* LATIN CAPITAL LETTER R WITH INVERTED BREVE */
-$config['0180_024F'][] = array('upper' => 532, 'status' => 'C', 'lower' => array(533)); /* LATIN CAPITAL LETTER U WITH DOUBLE GRAVE */
-$config['0180_024F'][] = array('upper' => 534, 'status' => 'C', 'lower' => array(535)); /* LATIN CAPITAL LETTER U WITH INVERTED BREVE */
-$config['0180_024F'][] = array('upper' => 536, 'status' => 'C', 'lower' => array(537)); /* LATIN CAPITAL LETTER S WITH COMMA BELOW */
-$config['0180_024F'][] = array('upper' => 538, 'status' => 'C', 'lower' => array(539)); /* LATIN CAPITAL LETTER T WITH COMMA BELOW */
-$config['0180_024F'][] = array('upper' => 540, 'status' => 'C', 'lower' => array(541)); /* LATIN CAPITAL LETTER YOGH */
-$config['0180_024F'][] = array('upper' => 542, 'status' => 'C', 'lower' => array(543)); /* LATIN CAPITAL LETTER H WITH CARON */
-$config['0180_024F'][] = array('upper' => 544, 'status' => 'C', 'lower' => array(414)); /* LATIN CAPITAL LETTER N WITH LONG RIGHT LEG */
-$config['0180_024F'][] = array('upper' => 546, 'status' => 'C', 'lower' => array(547)); /* LATIN CAPITAL LETTER OU */
-$config['0180_024F'][] = array('upper' => 548, 'status' => 'C', 'lower' => array(549)); /* LATIN CAPITAL LETTER Z WITH HOOK */
-$config['0180_024F'][] = array('upper' => 550, 'status' => 'C', 'lower' => array(551)); /* LATIN CAPITAL LETTER A WITH DOT ABOVE */
-$config['0180_024F'][] = array('upper' => 552, 'status' => 'C', 'lower' => array(553)); /* LATIN CAPITAL LETTER E WITH CEDILLA */
-$config['0180_024F'][] = array('upper' => 554, 'status' => 'C', 'lower' => array(555)); /* LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON */
-$config['0180_024F'][] = array('upper' => 556, 'status' => 'C', 'lower' => array(557)); /* LATIN CAPITAL LETTER O WITH TILDE AND MACRON */
-$config['0180_024F'][] = array('upper' => 558, 'status' => 'C', 'lower' => array(559)); /* LATIN CAPITAL LETTER O WITH DOT ABOVE */
-$config['0180_024F'][] = array('upper' => 560, 'status' => 'C', 'lower' => array(561)); /* LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON */
-$config['0180_024F'][] = array('upper' => 562, 'status' => 'C', 'lower' => array(563)); /* LATIN CAPITAL LETTER Y WITH MACRON */
-$config['0180_024F'][] = array('upper' => 570, 'status' => 'C', 'lower' => array(11365)); /* LATIN CAPITAL LETTER A WITH STROKE */
-$config['0180_024F'][] = array('upper' => 571, 'status' => 'C', 'lower' => array(572)); /* LATIN CAPITAL LETTER C WITH STROKE */
-$config['0180_024F'][] = array('upper' => 573, 'status' => 'C', 'lower' => array(410)); /* LATIN CAPITAL LETTER L WITH BAR */
-$config['0180_024F'][] = array('upper' => 574, 'status' => 'C', 'lower' => array(11366)); /* LATIN CAPITAL LETTER T WITH DIAGONAL STROKE */
-$config['0180_024F'][] = array('upper' => 577, 'status' => 'C', 'lower' => array(578)); /* LATIN CAPITAL LETTER GLOTTAL STOP */
-$config['0180_024F'][] = array('upper' => 579, 'status' => 'C', 'lower' => array(384)); /* LATIN CAPITAL LETTER B WITH STROKE */
-$config['0180_024F'][] = array('upper' => 580, 'status' => 'C', 'lower' => array(649)); /* LATIN CAPITAL LETTER U BAR */
-$config['0180_024F'][] = array('upper' => 581, 'status' => 'C', 'lower' => array(652)); /* LATIN CAPITAL LETTER TURNED V */
-$config['0180_024F'][] = array('upper' => 582, 'status' => 'C', 'lower' => array(583)); /* LATIN CAPITAL LETTER E WITH STROKE */
-$config['0180_024F'][] = array('upper' => 584, 'status' => 'C', 'lower' => array(585)); /* LATIN CAPITAL LETTER J WITH STROKE */
-$config['0180_024F'][] = array('upper' => 586, 'status' => 'C', 'lower' => array(587)); /* LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL */
-$config['0180_024F'][] = array('upper' => 588, 'status' => 'C', 'lower' => array(589)); /* LATIN CAPITAL LETTER R WITH STROKE */
-$config['0180_024F'][] = array('upper' => 590, 'status' => 'C', 'lower' => array(591)); /* LATIN CAPITAL LETTER Y WITH STROKE */
diff --git a/lib/Cake/Config/unicode/casefolding/0250_02af.php b/lib/Cake/Config/unicode/casefolding/0250_02af.php
deleted file mode 100644
index 6ffa59d1b8c..00000000000
--- a/lib/Cake/Config/unicode/casefolding/0250_02af.php
+++ /dev/null
@@ -1,41 +0,0 @@
- 422, 'status' => 'C', 'lower' => array(640));
diff --git a/lib/Cake/Config/unicode/casefolding/0370_03ff.php b/lib/Cake/Config/unicode/casefolding/0370_03ff.php
deleted file mode 100644
index bb7ecde79c8..00000000000
--- a/lib/Cake/Config/unicode/casefolding/0370_03ff.php
+++ /dev/null
@@ -1,102 +0,0 @@
- 902, 'status' => 'C', 'lower' => array(940)); /* GREEK CAPITAL LETTER ALPHA WITH TONOS */
-$config['0370_03ff'][] = array('upper' => 904, 'status' => 'C', 'lower' => array(941)); /* GREEK CAPITAL LETTER EPSILON WITH TONOS */
-$config['0370_03ff'][] = array('upper' => 905, 'status' => 'C', 'lower' => array(942)); /* GREEK CAPITAL LETTER ETA WITH TONOS */
-$config['0370_03ff'][] = array('upper' => 906, 'status' => 'C', 'lower' => array(943)); /* GREEK CAPITAL LETTER IOTA WITH TONOS */
-$config['0370_03ff'][] = array('upper' => 908, 'status' => 'C', 'lower' => array(972)); /* GREEK CAPITAL LETTER OMICRON WITH TONOS */
-$config['0370_03ff'][] = array('upper' => 910, 'status' => 'C', 'lower' => array(973)); /* GREEK CAPITAL LETTER UPSILON WITH TONOS */
-$config['0370_03ff'][] = array('upper' => 911, 'status' => 'C', 'lower' => array(974)); /* GREEK CAPITAL LETTER OMEGA WITH TONOS */
-//$config['0370_03ff'][] = array('upper' => 912, 'status' => 'F', 'lower' => array(953, 776, 769)); /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
-$config['0370_03ff'][] = array('upper' => 913, 'status' => 'C', 'lower' => array(945)); /* GREEK CAPITAL LETTER ALPHA */
-$config['0370_03ff'][] = array('upper' => 914, 'status' => 'C', 'lower' => array(946)); /* GREEK CAPITAL LETTER BETA */
-$config['0370_03ff'][] = array('upper' => 915, 'status' => 'C', 'lower' => array(947)); /* GREEK CAPITAL LETTER GAMMA */
-$config['0370_03ff'][] = array('upper' => 916, 'status' => 'C', 'lower' => array(948)); /* GREEK CAPITAL LETTER DELTA */
-$config['0370_03ff'][] = array('upper' => 917, 'status' => 'C', 'lower' => array(949)); /* GREEK CAPITAL LETTER EPSILON */
-$config['0370_03ff'][] = array('upper' => 918, 'status' => 'C', 'lower' => array(950)); /* GREEK CAPITAL LETTER ZETA */
-$config['0370_03ff'][] = array('upper' => 919, 'status' => 'C', 'lower' => array(951)); /* GREEK CAPITAL LETTER ETA */
-$config['0370_03ff'][] = array('upper' => 920, 'status' => 'C', 'lower' => array(952)); /* GREEK CAPITAL LETTER THETA */
-$config['0370_03ff'][] = array('upper' => 921, 'status' => 'C', 'lower' => array(953)); /* GREEK CAPITAL LETTER IOTA */
-$config['0370_03ff'][] = array('upper' => 922, 'status' => 'C', 'lower' => array(954)); /* GREEK CAPITAL LETTER KAPPA */
-$config['0370_03ff'][] = array('upper' => 923, 'status' => 'C', 'lower' => array(955)); /* GREEK CAPITAL LETTER LAMDA */
-$config['0370_03ff'][] = array('upper' => 924, 'status' => 'C', 'lower' => array(956)); /* GREEK CAPITAL LETTER MU */
-$config['0370_03ff'][] = array('upper' => 925, 'status' => 'C', 'lower' => array(957)); /* GREEK CAPITAL LETTER NU */
-$config['0370_03ff'][] = array('upper' => 926, 'status' => 'C', 'lower' => array(958)); /* GREEK CAPITAL LETTER XI */
-$config['0370_03ff'][] = array('upper' => 927, 'status' => 'C', 'lower' => array(959)); /* GREEK CAPITAL LETTER OMICRON */
-$config['0370_03ff'][] = array('upper' => 928, 'status' => 'C', 'lower' => array(960)); /* GREEK CAPITAL LETTER PI */
-$config['0370_03ff'][] = array('upper' => 929, 'status' => 'C', 'lower' => array(961)); /* GREEK CAPITAL LETTER RHO */
-$config['0370_03ff'][] = array('upper' => 931, 'status' => 'C', 'lower' => array(963)); /* GREEK CAPITAL LETTER SIGMA */
-$config['0370_03ff'][] = array('upper' => 932, 'status' => 'C', 'lower' => array(964)); /* GREEK CAPITAL LETTER TAU */
-$config['0370_03ff'][] = array('upper' => 933, 'status' => 'C', 'lower' => array(965)); /* GREEK CAPITAL LETTER UPSILON */
-$config['0370_03ff'][] = array('upper' => 934, 'status' => 'C', 'lower' => array(966)); /* GREEK CAPITAL LETTER PHI */
-$config['0370_03ff'][] = array('upper' => 935, 'status' => 'C', 'lower' => array(967)); /* GREEK CAPITAL LETTER CHI */
-$config['0370_03ff'][] = array('upper' => 936, 'status' => 'C', 'lower' => array(968)); /* GREEK CAPITAL LETTER PSI */
-$config['0370_03ff'][] = array('upper' => 937, 'status' => 'C', 'lower' => array(969)); /* GREEK CAPITAL LETTER OMEGA */
-$config['0370_03ff'][] = array('upper' => 938, 'status' => 'C', 'lower' => array(970)); /* GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
-$config['0370_03ff'][] = array('upper' => 939, 'status' => 'C', 'lower' => array(971)); /* GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
-$config['0370_03ff'][] = array('upper' => 944, 'status' => 'F', 'lower' => array(965, 776, 769)); /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
-$config['0370_03ff'][] = array('upper' => 962, 'status' => 'C', 'lower' => array(963)); /* GREEK SMALL LETTER FINAL SIGMA */
-$config['0370_03ff'][] = array('upper' => 976, 'status' => 'C', 'lower' => array(946)); /* GREEK BETA SYMBOL */
-$config['0370_03ff'][] = array('upper' => 977, 'status' => 'C', 'lower' => array(952)); /* GREEK THETA SYMBOL */
-$config['0370_03ff'][] = array('upper' => 981, 'status' => 'C', 'lower' => array(966)); /* GREEK PHI SYMBOL */
-$config['0370_03ff'][] = array('upper' => 982, 'status' => 'C', 'lower' => array(960)); /* GREEK PI SYMBOL */
-$config['0370_03ff'][] = array('upper' => 984, 'status' => 'C', 'lower' => array(985)); /* GREEK LETTER ARCHAIC KOPPA */
-$config['0370_03ff'][] = array('upper' => 986, 'status' => 'C', 'lower' => array(987)); /* GREEK LETTER STIGMA */
-$config['0370_03ff'][] = array('upper' => 988, 'status' => 'C', 'lower' => array(989)); /* GREEK LETTER DIGAMMA */
-$config['0370_03ff'][] = array('upper' => 990, 'status' => 'C', 'lower' => array(991)); /* GREEK LETTER KOPPA */
-$config['0370_03ff'][] = array('upper' => 992, 'status' => 'C', 'lower' => array(993)); /* GREEK LETTER SAMPI */
-$config['0370_03ff'][] = array('upper' => 994, 'status' => 'C', 'lower' => array(995)); /* COPTIC CAPITAL LETTER SHEI */
-$config['0370_03ff'][] = array('upper' => 996, 'status' => 'C', 'lower' => array(997)); /* COPTIC CAPITAL LETTER FEI */
-$config['0370_03ff'][] = array('upper' => 998, 'status' => 'C', 'lower' => array(999)); /* COPTIC CAPITAL LETTER KHEI */
-$config['0370_03ff'][] = array('upper' => 1000, 'status' => 'C', 'lower' => array(1001)); /* COPTIC CAPITAL LETTER HORI */
-$config['0370_03ff'][] = array('upper' => 1002, 'status' => 'C', 'lower' => array(1003)); /* COPTIC CAPITAL LETTER GANGIA */
-$config['0370_03ff'][] = array('upper' => 1004, 'status' => 'C', 'lower' => array(1005)); /* COPTIC CAPITAL LETTER SHIMA */
-$config['0370_03ff'][] = array('upper' => 1006, 'status' => 'C', 'lower' => array(1007)); /* COPTIC CAPITAL LETTER DEI */
-$config['0370_03ff'][] = array('upper' => 1008, 'status' => 'C', 'lower' => array(954)); /* GREEK KAPPA SYMBOL */
-$config['0370_03ff'][] = array('upper' => 1009, 'status' => 'C', 'lower' => array(961)); /* GREEK RHO SYMBOL */
-$config['0370_03ff'][] = array('upper' => 1012, 'status' => 'C', 'lower' => array(952)); /* GREEK CAPITAL THETA SYMBOL */
-$config['0370_03ff'][] = array('upper' => 1013, 'status' => 'C', 'lower' => array(949)); /* GREEK LUNATE EPSILON SYMBOL */
-$config['0370_03ff'][] = array('upper' => 1015, 'status' => 'C', 'lower' => array(1016)); /* GREEK CAPITAL LETTER SHO */
-$config['0370_03ff'][] = array('upper' => 1017, 'status' => 'C', 'lower' => array(1010)); /* GREEK CAPITAL LUNATE SIGMA SYMBOL */
-$config['0370_03ff'][] = array('upper' => 1018, 'status' => 'C', 'lower' => array(1019)); /* GREEK CAPITAL LETTER SAN */
-$config['0370_03ff'][] = array('upper' => 1021, 'status' => 'C', 'lower' => array(891)); /* GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL */
-$config['0370_03ff'][] = array('upper' => 1022, 'status' => 'C', 'lower' => array(892)); /* GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL */
-$config['0370_03ff'][] = array('upper' => 1023, 'status' => 'C', 'lower' => array(893)); /* GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL */
diff --git a/lib/Cake/Config/unicode/casefolding/0400_04ff.php b/lib/Cake/Config/unicode/casefolding/0400_04ff.php
deleted file mode 100644
index 7a3f93a5cd6..00000000000
--- a/lib/Cake/Config/unicode/casefolding/0400_04ff.php
+++ /dev/null
@@ -1,164 +0,0 @@
- 1024, 'status' => 'C', 'lower' => array(1104)); /* CYRILLIC CAPITAL LETTER IE WITH GRAVE */
-$config['0400_04ff'][] = array('upper' => 1025, 'status' => 'C', 'lower' => array(1105)); /* CYRILLIC CAPITAL LETTER IO */
-$config['0400_04ff'][] = array('upper' => 1026, 'status' => 'C', 'lower' => array(1106)); /* CYRILLIC CAPITAL LETTER DJE */
-$config['0400_04ff'][] = array('upper' => 1027, 'status' => 'C', 'lower' => array(1107)); /* CYRILLIC CAPITAL LETTER GJE */
-$config['0400_04ff'][] = array('upper' => 1028, 'status' => 'C', 'lower' => array(1108)); /* CYRILLIC CAPITAL LETTER UKRAINIAN IE */
-$config['0400_04ff'][] = array('upper' => 1029, 'status' => 'C', 'lower' => array(1109)); /* CYRILLIC CAPITAL LETTER DZE */
-$config['0400_04ff'][] = array('upper' => 1030, 'status' => 'C', 'lower' => array(1110)); /* CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
-$config['0400_04ff'][] = array('upper' => 1031, 'status' => 'C', 'lower' => array(1111)); /* CYRILLIC CAPITAL LETTER YI */
-$config['0400_04ff'][] = array('upper' => 1032, 'status' => 'C', 'lower' => array(1112)); /* CYRILLIC CAPITAL LETTER JE */
-$config['0400_04ff'][] = array('upper' => 1033, 'status' => 'C', 'lower' => array(1113)); /* CYRILLIC CAPITAL LETTER LJE */
-$config['0400_04ff'][] = array('upper' => 1034, 'status' => 'C', 'lower' => array(1114)); /* CYRILLIC CAPITAL LETTER NJE */
-$config['0400_04ff'][] = array('upper' => 1035, 'status' => 'C', 'lower' => array(1115)); /* CYRILLIC CAPITAL LETTER TSHE */
-$config['0400_04ff'][] = array('upper' => 1036, 'status' => 'C', 'lower' => array(1116)); /* CYRILLIC CAPITAL LETTER KJE */
-$config['0400_04ff'][] = array('upper' => 1037, 'status' => 'C', 'lower' => array(1117)); /* CYRILLIC CAPITAL LETTER I WITH GRAVE */
-$config['0400_04ff'][] = array('upper' => 1038, 'status' => 'C', 'lower' => array(1118)); /* CYRILLIC CAPITAL LETTER SHORT U */
-$config['0400_04ff'][] = array('upper' => 1039, 'status' => 'C', 'lower' => array(1119)); /* CYRILLIC CAPITAL LETTER DZHE */
-$config['0400_04ff'][] = array('upper' => 1040, 'status' => 'C', 'lower' => array(1072)); /* CYRILLIC CAPITAL LETTER A */
-$config['0400_04ff'][] = array('upper' => 1041, 'status' => 'C', 'lower' => array(1073)); /* CYRILLIC CAPITAL LETTER BE */
-$config['0400_04ff'][] = array('upper' => 1042, 'status' => 'C', 'lower' => array(1074)); /* CYRILLIC CAPITAL LETTER VE */
-$config['0400_04ff'][] = array('upper' => 1043, 'status' => 'C', 'lower' => array(1075)); /* CYRILLIC CAPITAL LETTER GHE */
-$config['0400_04ff'][] = array('upper' => 1044, 'status' => 'C', 'lower' => array(1076)); /* CYRILLIC CAPITAL LETTER DE */
-$config['0400_04ff'][] = array('upper' => 1045, 'status' => 'C', 'lower' => array(1077)); /* CYRILLIC CAPITAL LETTER IE */
-$config['0400_04ff'][] = array('upper' => 1046, 'status' => 'C', 'lower' => array(1078)); /* CYRILLIC CAPITAL LETTER ZHE */
-$config['0400_04ff'][] = array('upper' => 1047, 'status' => 'C', 'lower' => array(1079)); /* CYRILLIC CAPITAL LETTER ZE */
-$config['0400_04ff'][] = array('upper' => 1048, 'status' => 'C', 'lower' => array(1080)); /* CYRILLIC CAPITAL LETTER I */
-$config['0400_04ff'][] = array('upper' => 1049, 'status' => 'C', 'lower' => array(1081)); /* CYRILLIC CAPITAL LETTER SHORT I */
-$config['0400_04ff'][] = array('upper' => 1050, 'status' => 'C', 'lower' => array(1082)); /* CYRILLIC CAPITAL LETTER KA */
-$config['0400_04ff'][] = array('upper' => 1051, 'status' => 'C', 'lower' => array(1083)); /* CYRILLIC CAPITAL LETTER EL */
-$config['0400_04ff'][] = array('upper' => 1052, 'status' => 'C', 'lower' => array(1084)); /* CYRILLIC CAPITAL LETTER EM */
-$config['0400_04ff'][] = array('upper' => 1053, 'status' => 'C', 'lower' => array(1085)); /* CYRILLIC CAPITAL LETTER EN */
-$config['0400_04ff'][] = array('upper' => 1054, 'status' => 'C', 'lower' => array(1086)); /* CYRILLIC CAPITAL LETTER O */
-$config['0400_04ff'][] = array('upper' => 1055, 'status' => 'C', 'lower' => array(1087)); /* CYRILLIC CAPITAL LETTER PE */
-$config['0400_04ff'][] = array('upper' => 1056, 'status' => 'C', 'lower' => array(1088)); /* CYRILLIC CAPITAL LETTER ER */
-$config['0400_04ff'][] = array('upper' => 1057, 'status' => 'C', 'lower' => array(1089)); /* CYRILLIC CAPITAL LETTER ES */
-$config['0400_04ff'][] = array('upper' => 1058, 'status' => 'C', 'lower' => array(1090)); /* CYRILLIC CAPITAL LETTER TE */
-$config['0400_04ff'][] = array('upper' => 1059, 'status' => 'C', 'lower' => array(1091)); /* CYRILLIC CAPITAL LETTER U */
-$config['0400_04ff'][] = array('upper' => 1060, 'status' => 'C', 'lower' => array(1092)); /* CYRILLIC CAPITAL LETTER EF */
-$config['0400_04ff'][] = array('upper' => 1061, 'status' => 'C', 'lower' => array(1093)); /* CYRILLIC CAPITAL LETTER HA */
-$config['0400_04ff'][] = array('upper' => 1062, 'status' => 'C', 'lower' => array(1094)); /* CYRILLIC CAPITAL LETTER TSE */
-$config['0400_04ff'][] = array('upper' => 1063, 'status' => 'C', 'lower' => array(1095)); /* CYRILLIC CAPITAL LETTER CHE */
-$config['0400_04ff'][] = array('upper' => 1064, 'status' => 'C', 'lower' => array(1096)); /* CYRILLIC CAPITAL LETTER SHA */
-$config['0400_04ff'][] = array('upper' => 1065, 'status' => 'C', 'lower' => array(1097)); /* CYRILLIC CAPITAL LETTER SHCHA */
-$config['0400_04ff'][] = array('upper' => 1066, 'status' => 'C', 'lower' => array(1098)); /* CYRILLIC CAPITAL LETTER HARD SIGN */
-$config['0400_04ff'][] = array('upper' => 1067, 'status' => 'C', 'lower' => array(1099)); /* CYRILLIC CAPITAL LETTER YERU */
-$config['0400_04ff'][] = array('upper' => 1068, 'status' => 'C', 'lower' => array(1100)); /* CYRILLIC CAPITAL LETTER SOFT SIGN */
-$config['0400_04ff'][] = array('upper' => 1069, 'status' => 'C', 'lower' => array(1101)); /* CYRILLIC CAPITAL LETTER E */
-$config['0400_04ff'][] = array('upper' => 1070, 'status' => 'C', 'lower' => array(1102)); /* CYRILLIC CAPITAL LETTER YU */
-$config['0400_04ff'][] = array('upper' => 1071, 'status' => 'C', 'lower' => array(1103)); /* CYRILLIC CAPITAL LETTER YA */
-$config['0400_04ff'][] = array('upper' => 1120, 'status' => 'C', 'lower' => array(1121)); /* CYRILLIC CAPITAL LETTER OMEGA */
-$config['0400_04ff'][] = array('upper' => 1122, 'status' => 'C', 'lower' => array(1123)); /* CYRILLIC CAPITAL LETTER YAT */
-$config['0400_04ff'][] = array('upper' => 1124, 'status' => 'C', 'lower' => array(1125)); /* CYRILLIC CAPITAL LETTER IOTIFIED E */
-$config['0400_04ff'][] = array('upper' => 1126, 'status' => 'C', 'lower' => array(1127)); /* CYRILLIC CAPITAL LETTER LITTLE YUS */
-$config['0400_04ff'][] = array('upper' => 1128, 'status' => 'C', 'lower' => array(1129)); /* CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS */
-$config['0400_04ff'][] = array('upper' => 1130, 'status' => 'C', 'lower' => array(1131)); /* CYRILLIC CAPITAL LETTER BIG YUS */
-$config['0400_04ff'][] = array('upper' => 1132, 'status' => 'C', 'lower' => array(1133)); /* CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS */
-$config['0400_04ff'][] = array('upper' => 1134, 'status' => 'C', 'lower' => array(1135)); /* CYRILLIC CAPITAL LETTER KSI */
-$config['0400_04ff'][] = array('upper' => 1136, 'status' => 'C', 'lower' => array(1137)); /* CYRILLIC CAPITAL LETTER PSI */
-$config['0400_04ff'][] = array('upper' => 1138, 'status' => 'C', 'lower' => array(1139)); /* CYRILLIC CAPITAL LETTER FITA */
-$config['0400_04ff'][] = array('upper' => 1140, 'status' => 'C', 'lower' => array(1141)); /* CYRILLIC CAPITAL LETTER IZHITSA */
-$config['0400_04ff'][] = array('upper' => 1142, 'status' => 'C', 'lower' => array(1143)); /* CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT */
-$config['0400_04ff'][] = array('upper' => 1144, 'status' => 'C', 'lower' => array(1145)); /* CYRILLIC CAPITAL LETTER UK */
-$config['0400_04ff'][] = array('upper' => 1146, 'status' => 'C', 'lower' => array(1147)); /* CYRILLIC CAPITAL LETTER ROUND OMEGA */
-$config['0400_04ff'][] = array('upper' => 1148, 'status' => 'C', 'lower' => array(1149)); /* CYRILLIC CAPITAL LETTER OMEGA WITH TITLO */
-$config['0400_04ff'][] = array('upper' => 1150, 'status' => 'C', 'lower' => array(1151)); /* CYRILLIC CAPITAL LETTER OT */
-$config['0400_04ff'][] = array('upper' => 1152, 'status' => 'C', 'lower' => array(1153)); /* CYRILLIC CAPITAL LETTER KOPPA */
-$config['0400_04ff'][] = array('upper' => 1162, 'status' => 'C', 'lower' => array(1163)); /* CYRILLIC CAPITAL LETTER SHORT I WITH TAIL */
-$config['0400_04ff'][] = array('upper' => 1164, 'status' => 'C', 'lower' => array(1165)); /* CYRILLIC CAPITAL LETTER SEMISOFT SIGN */
-$config['0400_04ff'][] = array('upper' => 1166, 'status' => 'C', 'lower' => array(1167)); /* CYRILLIC CAPITAL LETTER ER WITH TICK */
-$config['0400_04ff'][] = array('upper' => 1168, 'status' => 'C', 'lower' => array(1169)); /* CYRILLIC CAPITAL LETTER GHE WITH UPTURN */
-$config['0400_04ff'][] = array('upper' => 1170, 'status' => 'C', 'lower' => array(1171)); /* CYRILLIC CAPITAL LETTER GHE WITH STROKE */
-$config['0400_04ff'][] = array('upper' => 1172, 'status' => 'C', 'lower' => array(1173)); /* CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK */
-$config['0400_04ff'][] = array('upper' => 1174, 'status' => 'C', 'lower' => array(1175)); /* CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER */
-$config['0400_04ff'][] = array('upper' => 1176, 'status' => 'C', 'lower' => array(1177)); /* CYRILLIC CAPITAL LETTER ZE WITH DESCENDER */
-$config['0400_04ff'][] = array('upper' => 1178, 'status' => 'C', 'lower' => array(1179)); /* CYRILLIC CAPITAL LETTER KA WITH DESCENDER */
-$config['0400_04ff'][] = array('upper' => 1180, 'status' => 'C', 'lower' => array(1181)); /* CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE */
-$config['0400_04ff'][] = array('upper' => 1182, 'status' => 'C', 'lower' => array(1183)); /* CYRILLIC CAPITAL LETTER KA WITH STROKE */
-$config['0400_04ff'][] = array('upper' => 1184, 'status' => 'C', 'lower' => array(1185)); /* CYRILLIC CAPITAL LETTER BASHKIR KA */
-$config['0400_04ff'][] = array('upper' => 1186, 'status' => 'C', 'lower' => array(1187)); /* CYRILLIC CAPITAL LETTER EN WITH DESCENDER */
-$config['0400_04ff'][] = array('upper' => 1188, 'status' => 'C', 'lower' => array(1189)); /* CYRILLIC CAPITAL LIGATURE EN GHE */
-$config['0400_04ff'][] = array('upper' => 1190, 'status' => 'C', 'lower' => array(1191)); /* CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK */
-$config['0400_04ff'][] = array('upper' => 1192, 'status' => 'C', 'lower' => array(1193)); /* CYRILLIC CAPITAL LETTER ABKHASIAN HA */
-$config['0400_04ff'][] = array('upper' => 1194, 'status' => 'C', 'lower' => array(1195)); /* CYRILLIC CAPITAL LETTER ES WITH DESCENDER */
-$config['0400_04ff'][] = array('upper' => 1196, 'status' => 'C', 'lower' => array(1197)); /* CYRILLIC CAPITAL LETTER TE WITH DESCENDER */
-$config['0400_04ff'][] = array('upper' => 1198, 'status' => 'C', 'lower' => array(1199)); /* CYRILLIC CAPITAL LETTER STRAIGHT U */
-$config['0400_04ff'][] = array('upper' => 1200, 'status' => 'C', 'lower' => array(1201)); /* CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE */
-$config['0400_04ff'][] = array('upper' => 1202, 'status' => 'C', 'lower' => array(1203)); /* CYRILLIC CAPITAL LETTER HA WITH DESCENDER */
-$config['0400_04ff'][] = array('upper' => 1204, 'status' => 'C', 'lower' => array(1205)); /* CYRILLIC CAPITAL LIGATURE TE TSE */
-$config['0400_04ff'][] = array('upper' => 1206, 'status' => 'C', 'lower' => array(1207)); /* CYRILLIC CAPITAL LETTER CHE WITH DESCENDER */
-$config['0400_04ff'][] = array('upper' => 1208, 'status' => 'C', 'lower' => array(1209)); /* CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE */
-$config['0400_04ff'][] = array('upper' => 1210, 'status' => 'C', 'lower' => array(1211)); /* CYRILLIC CAPITAL LETTER SHHA */
-$config['0400_04ff'][] = array('upper' => 1212, 'status' => 'C', 'lower' => array(1213)); /* CYRILLIC CAPITAL LETTER ABKHASIAN CHE */
-$config['0400_04ff'][] = array('upper' => 1214, 'status' => 'C', 'lower' => array(1215)); /* CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER */
-$config['0400_04ff'][] = array('upper' => 1216, 'status' => 'C', 'lower' => array(1231)); /* CYRILLIC LETTER PALOCHKA */
-$config['0400_04ff'][] = array('upper' => 1217, 'status' => 'C', 'lower' => array(1218)); /* CYRILLIC CAPITAL LETTER ZHE WITH BREVE */
-$config['0400_04ff'][] = array('upper' => 1219, 'status' => 'C', 'lower' => array(1220)); /* CYRILLIC CAPITAL LETTER KA WITH HOOK */
-$config['0400_04ff'][] = array('upper' => 1221, 'status' => 'C', 'lower' => array(1222)); /* CYRILLIC CAPITAL LETTER EL WITH TAIL */
-$config['0400_04ff'][] = array('upper' => 1223, 'status' => 'C', 'lower' => array(1224)); /* CYRILLIC CAPITAL LETTER EN WITH HOOK */
-$config['0400_04ff'][] = array('upper' => 1225, 'status' => 'C', 'lower' => array(1226)); /* CYRILLIC CAPITAL LETTER EN WITH TAIL */
-$config['0400_04ff'][] = array('upper' => 1227, 'status' => 'C', 'lower' => array(1228)); /* CYRILLIC CAPITAL LETTER KHAKASSIAN CHE */
-$config['0400_04ff'][] = array('upper' => 1229, 'status' => 'C', 'lower' => array(1230)); /* CYRILLIC CAPITAL LETTER EM WITH TAIL */
-$config['0400_04ff'][] = array('upper' => 1232, 'status' => 'C', 'lower' => array(1233)); /* CYRILLIC CAPITAL LETTER A WITH BREVE */
-$config['0400_04ff'][] = array('upper' => 1234, 'status' => 'C', 'lower' => array(1235)); /* CYRILLIC CAPITAL LETTER A WITH DIAERESIS */
-$config['0400_04ff'][] = array('upper' => 1236, 'status' => 'C', 'lower' => array(1237)); /* CYRILLIC CAPITAL LIGATURE A IE */
-$config['0400_04ff'][] = array('upper' => 1238, 'status' => 'C', 'lower' => array(1239)); /* CYRILLIC CAPITAL LETTER IE WITH BREVE */
-$config['0400_04ff'][] = array('upper' => 1240, 'status' => 'C', 'lower' => array(1241)); /* CYRILLIC CAPITAL LETTER SCHWA */
-$config['0400_04ff'][] = array('upper' => 1242, 'status' => 'C', 'lower' => array(1243)); /* CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS */
-$config['0400_04ff'][] = array('upper' => 1244, 'status' => 'C', 'lower' => array(1245)); /* CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS */
-$config['0400_04ff'][] = array('upper' => 1246, 'status' => 'C', 'lower' => array(1247)); /* CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS */
-$config['0400_04ff'][] = array('upper' => 1248, 'status' => 'C', 'lower' => array(1249)); /* CYRILLIC CAPITAL LETTER ABKHASIAN DZE */
-$config['0400_04ff'][] = array('upper' => 1250, 'status' => 'C', 'lower' => array(1251)); /* CYRILLIC CAPITAL LETTER I WITH MACRON */
-$config['0400_04ff'][] = array('upper' => 1252, 'status' => 'C', 'lower' => array(1253)); /* CYRILLIC CAPITAL LETTER I WITH DIAERESIS */
-$config['0400_04ff'][] = array('upper' => 1254, 'status' => 'C', 'lower' => array(1255)); /* CYRILLIC CAPITAL LETTER O WITH DIAERESIS */
-$config['0400_04ff'][] = array('upper' => 1256, 'status' => 'C', 'lower' => array(1257)); /* CYRILLIC CAPITAL LETTER BARRED O */
-$config['0400_04ff'][] = array('upper' => 1258, 'status' => 'C', 'lower' => array(1259)); /* CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS */
-$config['0400_04ff'][] = array('upper' => 1260, 'status' => 'C', 'lower' => array(1261)); /* CYRILLIC CAPITAL LETTER E WITH DIAERESIS */
-$config['0400_04ff'][] = array('upper' => 1262, 'status' => 'C', 'lower' => array(1263)); /* CYRILLIC CAPITAL LETTER U WITH MACRON */
-$config['0400_04ff'][] = array('upper' => 1264, 'status' => 'C', 'lower' => array(1265)); /* CYRILLIC CAPITAL LETTER U WITH DIAERESIS */
-$config['0400_04ff'][] = array('upper' => 1266, 'status' => 'C', 'lower' => array(1267)); /* CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE */
-$config['0400_04ff'][] = array('upper' => 1268, 'status' => 'C', 'lower' => array(1269)); /* CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS */
-$config['0400_04ff'][] = array('upper' => 1270, 'status' => 'C', 'lower' => array(1271)); /* CYRILLIC CAPITAL LETTER GHE WITH DESCENDER */
-$config['0400_04ff'][] = array('upper' => 1272, 'status' => 'C', 'lower' => array(1273)); /* CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS */
-$config['0400_04ff'][] = array('upper' => 1274, 'status' => 'C', 'lower' => array(1275)); /* CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK */
-$config['0400_04ff'][] = array('upper' => 1276, 'status' => 'C', 'lower' => array(1277)); /* CYRILLIC CAPITAL LETTER HA WITH HOOK */
-$config['0400_04ff'][] = array('upper' => 1278, 'status' => 'C', 'lower' => array(1279)); /* CYRILLIC CAPITAL LETTER HA WITH STROKE */
diff --git a/lib/Cake/Config/unicode/casefolding/0500_052f.php b/lib/Cake/Config/unicode/casefolding/0500_052f.php
deleted file mode 100644
index 73b81fa8134..00000000000
--- a/lib/Cake/Config/unicode/casefolding/0500_052f.php
+++ /dev/null
@@ -1,50 +0,0 @@
- 1280, 'status' => 'C', 'lower' => array(1281)); /* CYRILLIC CAPITAL LETTER KOMI DE */
-$config['0500_052f'][] = array('upper' => 1282, 'status' => 'C', 'lower' => array(1283)); /* CYRILLIC CAPITAL LETTER KOMI DJE */
-$config['0500_052f'][] = array('upper' => 1284, 'status' => 'C', 'lower' => array(1285)); /* CYRILLIC CAPITAL LETTER KOMI ZJE */
-$config['0500_052f'][] = array('upper' => 1286, 'status' => 'C', 'lower' => array(1287)); /* CYRILLIC CAPITAL LETTER KOMI DZJE */
-$config['0500_052f'][] = array('upper' => 1288, 'status' => 'C', 'lower' => array(1289)); /* CYRILLIC CAPITAL LETTER KOMI LJE */
-$config['0500_052f'][] = array('upper' => 1290, 'status' => 'C', 'lower' => array(1291)); /* CYRILLIC CAPITAL LETTER KOMI NJE */
-$config['0500_052f'][] = array('upper' => 1292, 'status' => 'C', 'lower' => array(1293)); /* CYRILLIC CAPITAL LETTER KOMI SJE */
-$config['0500_052f'][] = array('upper' => 1294, 'status' => 'C', 'lower' => array(1295)); /* CYRILLIC CAPITAL LETTER KOMI TJE */
-$config['0500_052f'][] = array('upper' => 1296, 'status' => 'C', 'lower' => array(1297)); /* CYRILLIC CAPITAL LETTER ZE */
-$config['0500_052f'][] = array('upper' => 1298, 'status' => 'C', 'lower' => array(1299)); /* CYRILLIC CAPITAL LETTER El with hook */
diff --git a/lib/Cake/Config/unicode/casefolding/0530_058f.php b/lib/Cake/Config/unicode/casefolding/0530_058f.php
deleted file mode 100644
index 4ffb553e90a..00000000000
--- a/lib/Cake/Config/unicode/casefolding/0530_058f.php
+++ /dev/null
@@ -1,78 +0,0 @@
- 1329, 'status' => 'C', 'lower' => array(1377)); /* ARMENIAN CAPITAL LETTER AYB */
-$config['0530_058f'][] = array('upper' => 1330, 'status' => 'C', 'lower' => array(1378)); /* ARMENIAN CAPITAL LETTER BEN */
-$config['0530_058f'][] = array('upper' => 1331, 'status' => 'C', 'lower' => array(1379)); /* ARMENIAN CAPITAL LETTER GIM */
-$config['0530_058f'][] = array('upper' => 1332, 'status' => 'C', 'lower' => array(1380)); /* ARMENIAN CAPITAL LETTER DA */
-$config['0530_058f'][] = array('upper' => 1333, 'status' => 'C', 'lower' => array(1381)); /* ARMENIAN CAPITAL LETTER ECH */
-$config['0530_058f'][] = array('upper' => 1334, 'status' => 'C', 'lower' => array(1382)); /* ARMENIAN CAPITAL LETTER ZA */
-$config['0530_058f'][] = array('upper' => 1335, 'status' => 'C', 'lower' => array(1383)); /* ARMENIAN CAPITAL LETTER EH */
-$config['0530_058f'][] = array('upper' => 1336, 'status' => 'C', 'lower' => array(1384)); /* ARMENIAN CAPITAL LETTER ET */
-$config['0530_058f'][] = array('upper' => 1337, 'status' => 'C', 'lower' => array(1385)); /* ARMENIAN CAPITAL LETTER TO */
-$config['0530_058f'][] = array('upper' => 1338, 'status' => 'C', 'lower' => array(1386)); /* ARMENIAN CAPITAL LETTER ZHE */
-$config['0530_058f'][] = array('upper' => 1339, 'status' => 'C', 'lower' => array(1387)); /* ARMENIAN CAPITAL LETTER INI */
-$config['0530_058f'][] = array('upper' => 1340, 'status' => 'C', 'lower' => array(1388)); /* ARMENIAN CAPITAL LETTER LIWN */
-$config['0530_058f'][] = array('upper' => 1341, 'status' => 'C', 'lower' => array(1389)); /* ARMENIAN CAPITAL LETTER XEH */
-$config['0530_058f'][] = array('upper' => 1342, 'status' => 'C', 'lower' => array(1390)); /* ARMENIAN CAPITAL LETTER CA */
-$config['0530_058f'][] = array('upper' => 1343, 'status' => 'C', 'lower' => array(1391)); /* ARMENIAN CAPITAL LETTER KEN */
-$config['0530_058f'][] = array('upper' => 1344, 'status' => 'C', 'lower' => array(1392)); /* ARMENIAN CAPITAL LETTER HO */
-$config['0530_058f'][] = array('upper' => 1345, 'status' => 'C', 'lower' => array(1393)); /* ARMENIAN CAPITAL LETTER JA */
-$config['0530_058f'][] = array('upper' => 1346, 'status' => 'C', 'lower' => array(1394)); /* ARMENIAN CAPITAL LETTER GHAD */
-$config['0530_058f'][] = array('upper' => 1347, 'status' => 'C', 'lower' => array(1395)); /* ARMENIAN CAPITAL LETTER CHEH */
-$config['0530_058f'][] = array('upper' => 1348, 'status' => 'C', 'lower' => array(1396)); /* ARMENIAN CAPITAL LETTER MEN */
-$config['0530_058f'][] = array('upper' => 1349, 'status' => 'C', 'lower' => array(1397)); /* ARMENIAN CAPITAL LETTER YI */
-$config['0530_058f'][] = array('upper' => 1350, 'status' => 'C', 'lower' => array(1398)); /* ARMENIAN CAPITAL LETTER NOW */
-$config['0530_058f'][] = array('upper' => 1351, 'status' => 'C', 'lower' => array(1399)); /* ARMENIAN CAPITAL LETTER SHA */
-$config['0530_058f'][] = array('upper' => 1352, 'status' => 'C', 'lower' => array(1400)); /* ARMENIAN CAPITAL LETTER VO */
-$config['0530_058f'][] = array('upper' => 1353, 'status' => 'C', 'lower' => array(1401)); /* ARMENIAN CAPITAL LETTER CHA */
-$config['0530_058f'][] = array('upper' => 1354, 'status' => 'C', 'lower' => array(1402)); /* ARMENIAN CAPITAL LETTER PEH */
-$config['0530_058f'][] = array('upper' => 1355, 'status' => 'C', 'lower' => array(1403)); /* ARMENIAN CAPITAL LETTER JHEH */
-$config['0530_058f'][] = array('upper' => 1356, 'status' => 'C', 'lower' => array(1404)); /* ARMENIAN CAPITAL LETTER RA */
-$config['0530_058f'][] = array('upper' => 1357, 'status' => 'C', 'lower' => array(1405)); /* ARMENIAN CAPITAL LETTER SEH */
-$config['0530_058f'][] = array('upper' => 1358, 'status' => 'C', 'lower' => array(1406)); /* ARMENIAN CAPITAL LETTER VEW */
-$config['0530_058f'][] = array('upper' => 1359, 'status' => 'C', 'lower' => array(1407)); /* ARMENIAN CAPITAL LETTER TIWN */
-$config['0530_058f'][] = array('upper' => 1360, 'status' => 'C', 'lower' => array(1408)); /* ARMENIAN CAPITAL LETTER REH */
-$config['0530_058f'][] = array('upper' => 1361, 'status' => 'C', 'lower' => array(1409)); /* ARMENIAN CAPITAL LETTER CO */
-$config['0530_058f'][] = array('upper' => 1362, 'status' => 'C', 'lower' => array(1410)); /* ARMENIAN CAPITAL LETTER YIWN */
-$config['0530_058f'][] = array('upper' => 1363, 'status' => 'C', 'lower' => array(1411)); /* ARMENIAN CAPITAL LETTER PIWR */
-$config['0530_058f'][] = array('upper' => 1364, 'status' => 'C', 'lower' => array(1412)); /* ARMENIAN CAPITAL LETTER KEH */
-$config['0530_058f'][] = array('upper' => 1365, 'status' => 'C', 'lower' => array(1413)); /* ARMENIAN CAPITAL LETTER OH */
-$config['0530_058f'][] = array('upper' => 1366, 'status' => 'C', 'lower' => array(1414)); /* ARMENIAN CAPITAL LETTER FEH */
diff --git a/lib/Cake/Config/unicode/casefolding/1e00_1eff.php b/lib/Cake/Config/unicode/casefolding/1e00_1eff.php
deleted file mode 100644
index 5b534a3c410..00000000000
--- a/lib/Cake/Config/unicode/casefolding/1e00_1eff.php
+++ /dev/null
@@ -1,168 +0,0 @@
- 7680, 'status' => 'C', 'lower' => array(7681)); /* LATIN CAPITAL LETTER A WITH RING BELOW */
-$config['1e00_1eff'][] = array('upper' => 7682, 'status' => 'C', 'lower' => array(7683)); /* LATIN CAPITAL LETTER B WITH DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7684, 'status' => 'C', 'lower' => array(7685)); /* LATIN CAPITAL LETTER B WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7686, 'status' => 'C', 'lower' => array(7687)); /* LATIN CAPITAL LETTER B WITH LINE BELOW */
-$config['1e00_1eff'][] = array('upper' => 7688, 'status' => 'C', 'lower' => array(7689)); /* LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7690, 'status' => 'C', 'lower' => array(7691)); /* LATIN CAPITAL LETTER D WITH DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7692, 'status' => 'C', 'lower' => array(7693)); /* LATIN CAPITAL LETTER D WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7694, 'status' => 'C', 'lower' => array(7695)); /* LATIN CAPITAL LETTER D WITH LINE BELOW */
-$config['1e00_1eff'][] = array('upper' => 7696, 'status' => 'C', 'lower' => array(7697)); /* LATIN CAPITAL LETTER D WITH CEDILLA */
-$config['1e00_1eff'][] = array('upper' => 7698, 'status' => 'C', 'lower' => array(7699)); /* LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW */
-$config['1e00_1eff'][] = array('upper' => 7700, 'status' => 'C', 'lower' => array(7701)); /* LATIN CAPITAL LETTER E WITH MACRON AND GRAVE */
-$config['1e00_1eff'][] = array('upper' => 7702, 'status' => 'C', 'lower' => array(7703)); /* LATIN CAPITAL LETTER E WITH MACRON AND ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7704, 'status' => 'C', 'lower' => array(7705)); /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW */
-$config['1e00_1eff'][] = array('upper' => 7706, 'status' => 'C', 'lower' => array(7707)); /* LATIN CAPITAL LETTER E WITH TILDE BELOW */
-$config['1e00_1eff'][] = array('upper' => 7708, 'status' => 'C', 'lower' => array(7709)); /* LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE */
-$config['1e00_1eff'][] = array('upper' => 7710, 'status' => 'C', 'lower' => array(7711)); /* LATIN CAPITAL LETTER F WITH DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7712, 'status' => 'C', 'lower' => array(7713)); /* LATIN CAPITAL LETTER G WITH MACRON */
-$config['1e00_1eff'][] = array('upper' => 7714, 'status' => 'C', 'lower' => array(7715)); /* LATIN CAPITAL LETTER H WITH DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7716, 'status' => 'C', 'lower' => array(7717)); /* LATIN CAPITAL LETTER H WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7718, 'status' => 'C', 'lower' => array(7719)); /* LATIN CAPITAL LETTER H WITH DIAERESIS */
-$config['1e00_1eff'][] = array('upper' => 7720, 'status' => 'C', 'lower' => array(7721)); /* LATIN CAPITAL LETTER H WITH CEDILLA */
-$config['1e00_1eff'][] = array('upper' => 7722, 'status' => 'C', 'lower' => array(7723)); /* LATIN CAPITAL LETTER H WITH BREVE BELOW */
-$config['1e00_1eff'][] = array('upper' => 7724, 'status' => 'C', 'lower' => array(7725)); /* LATIN CAPITAL LETTER I WITH TILDE BELOW */
-$config['1e00_1eff'][] = array('upper' => 7726, 'status' => 'C', 'lower' => array(7727)); /* LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7728, 'status' => 'C', 'lower' => array(7729)); /* LATIN CAPITAL LETTER K WITH ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7730, 'status' => 'C', 'lower' => array(7731)); /* LATIN CAPITAL LETTER K WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7732, 'status' => 'C', 'lower' => array(7733)); /* LATIN CAPITAL LETTER K WITH LINE BELOW */
-$config['1e00_1eff'][] = array('upper' => 7734, 'status' => 'C', 'lower' => array(7735)); /* LATIN CAPITAL LETTER L WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7736, 'status' => 'C', 'lower' => array(7737)); /* LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON */
-$config['1e00_1eff'][] = array('upper' => 7738, 'status' => 'C', 'lower' => array(7739)); /* LATIN CAPITAL LETTER L WITH LINE BELOW */
-$config['1e00_1eff'][] = array('upper' => 7740, 'status' => 'C', 'lower' => array(7741)); /* LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW */
-$config['1e00_1eff'][] = array('upper' => 7742, 'status' => 'C', 'lower' => array(7743)); /* LATIN CAPITAL LETTER M WITH ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7744, 'status' => 'C', 'lower' => array(7745)); /* LATIN CAPITAL LETTER M WITH DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7746, 'status' => 'C', 'lower' => array(7747)); /* LATIN CAPITAL LETTER M WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7748, 'status' => 'C', 'lower' => array(7749)); /* LATIN CAPITAL LETTER N WITH DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7750, 'status' => 'C', 'lower' => array(7751)); /* LATIN CAPITAL LETTER N WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7752, 'status' => 'C', 'lower' => array(7753)); /* LATIN CAPITAL LETTER N WITH LINE BELOW */
-$config['1e00_1eff'][] = array('upper' => 7754, 'status' => 'C', 'lower' => array(7755)); /* LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW */
-$config['1e00_1eff'][] = array('upper' => 7756, 'status' => 'C', 'lower' => array(7757)); /* LATIN CAPITAL LETTER O WITH TILDE AND ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7758, 'status' => 'C', 'lower' => array(7759)); /* LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS */
-$config['1e00_1eff'][] = array('upper' => 7760, 'status' => 'C', 'lower' => array(7761)); /* LATIN CAPITAL LETTER O WITH MACRON AND GRAVE */
-$config['1e00_1eff'][] = array('upper' => 7762, 'status' => 'C', 'lower' => array(7763)); /* LATIN CAPITAL LETTER O WITH MACRON AND ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7764, 'status' => 'C', 'lower' => array(7765)); /* LATIN CAPITAL LETTER P WITH ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7766, 'status' => 'C', 'lower' => array(7767)); /* LATIN CAPITAL LETTER P WITH DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7768, 'status' => 'C', 'lower' => array(7769)); /* LATIN CAPITAL LETTER R WITH DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7770, 'status' => 'C', 'lower' => array(7771)); /* LATIN CAPITAL LETTER R WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7772, 'status' => 'C', 'lower' => array(7773)); /* LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON */
-$config['1e00_1eff'][] = array('upper' => 7774, 'status' => 'C', 'lower' => array(7775)); /* LATIN CAPITAL LETTER R WITH LINE BELOW */
-$config['1e00_1eff'][] = array('upper' => 7776, 'status' => 'C', 'lower' => array(7777)); /* LATIN CAPITAL LETTER S WITH DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7778, 'status' => 'C', 'lower' => array(7779)); /* LATIN CAPITAL LETTER S WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7780, 'status' => 'C', 'lower' => array(7781)); /* LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7782, 'status' => 'C', 'lower' => array(7783)); /* LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7784, 'status' => 'C', 'lower' => array(7785)); /* LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7786, 'status' => 'C', 'lower' => array(7787)); /* LATIN CAPITAL LETTER T WITH DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7788, 'status' => 'C', 'lower' => array(7789)); /* LATIN CAPITAL LETTER T WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7790, 'status' => 'C', 'lower' => array(7791)); /* LATIN CAPITAL LETTER T WITH LINE BELOW */
-$config['1e00_1eff'][] = array('upper' => 7792, 'status' => 'C', 'lower' => array(7793)); /* LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW */
-$config['1e00_1eff'][] = array('upper' => 7794, 'status' => 'C', 'lower' => array(7795)); /* LATIN CAPITAL LETTER U WITH DIAERESIS BELOW */
-$config['1e00_1eff'][] = array('upper' => 7796, 'status' => 'C', 'lower' => array(7797)); /* LATIN CAPITAL LETTER U WITH TILDE BELOW */
-$config['1e00_1eff'][] = array('upper' => 7798, 'status' => 'C', 'lower' => array(7799)); /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW */
-$config['1e00_1eff'][] = array('upper' => 7800, 'status' => 'C', 'lower' => array(7801)); /* LATIN CAPITAL LETTER U WITH TILDE AND ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7802, 'status' => 'C', 'lower' => array(7803)); /* LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS */
-$config['1e00_1eff'][] = array('upper' => 7804, 'status' => 'C', 'lower' => array(7805)); /* LATIN CAPITAL LETTER V WITH TILDE */
-$config['1e00_1eff'][] = array('upper' => 7806, 'status' => 'C', 'lower' => array(7807)); /* LATIN CAPITAL LETTER V WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7808, 'status' => 'C', 'lower' => array(7809)); /* LATIN CAPITAL LETTER W WITH GRAVE */
-$config['1e00_1eff'][] = array('upper' => 7810, 'status' => 'C', 'lower' => array(7811)); /* LATIN CAPITAL LETTER W WITH ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7812, 'status' => 'C', 'lower' => array(7813)); /* LATIN CAPITAL LETTER W WITH DIAERESIS */
-$config['1e00_1eff'][] = array('upper' => 7814, 'status' => 'C', 'lower' => array(7815)); /* LATIN CAPITAL LETTER W WITH DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7816, 'status' => 'C', 'lower' => array(7817)); /* LATIN CAPITAL LETTER W WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7818, 'status' => 'C', 'lower' => array(7819)); /* LATIN CAPITAL LETTER X WITH DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7820, 'status' => 'C', 'lower' => array(7821)); /* LATIN CAPITAL LETTER X WITH DIAERESIS */
-$config['1e00_1eff'][] = array('upper' => 7822, 'status' => 'C', 'lower' => array(7823)); /* LATIN CAPITAL LETTER Y WITH DOT ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7824, 'status' => 'C', 'lower' => array(7825)); /* LATIN CAPITAL LETTER Z WITH CIRCUMFLEX */
-$config['1e00_1eff'][] = array('upper' => 7826, 'status' => 'C', 'lower' => array(7827)); /* LATIN CAPITAL LETTER Z WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7828, 'status' => 'C', 'lower' => array(7829)); /* LATIN CAPITAL LETTER Z WITH LINE BELOW */
-
-//$config['1e00_1eff'][] = array('upper' => 7830, 'status' => 'F', 'lower' => array(104, 817)); /* LATIN SMALL LETTER H WITH LINE BELOW */
-//$config['1e00_1eff'][] = array('upper' => 7831, 'status' => 'F', 'lower' => array(116, 776)); /* LATIN SMALL LETTER T WITH DIAERESIS */
-//$config['1e00_1eff'][] = array('upper' => 7832, 'status' => 'F', 'lower' => array(119, 778)); /* LATIN SMALL LETTER W WITH RING ABOVE */
-//$config['1e00_1eff'][] = array('upper' => 7833, 'status' => 'F', 'lower' => array(121, 778)); /* LATIN SMALL LETTER Y WITH RING ABOVE */
-//$config['1e00_1eff'][] = array('upper' => 7834, 'status' => 'F', 'lower' => array(97, 702)); /* LATIN SMALL LETTER A WITH RIGHT HALF RING */
-//$config['1e00_1eff'][] = array('upper' => 7835, 'status' => 'C', 'lower' => array(7777)); /* LATIN SMALL LETTER LONG S WITH DOT ABOVE */
-
-$config['1e00_1eff'][] = array('upper' => 7840, 'status' => 'C', 'lower' => array(7841)); /* LATIN CAPITAL LETTER A WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7842, 'status' => 'C', 'lower' => array(7843)); /* LATIN CAPITAL LETTER A WITH HOOK ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7844, 'status' => 'C', 'lower' => array(7845)); /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7846, 'status' => 'C', 'lower' => array(7847)); /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE */
-$config['1e00_1eff'][] = array('upper' => 7848, 'status' => 'C', 'lower' => array(7849)); /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7850, 'status' => 'C', 'lower' => array(7851)); /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE */
-$config['1e00_1eff'][] = array('upper' => 7852, 'status' => 'C', 'lower' => array(7853)); /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7854, 'status' => 'C', 'lower' => array(7855)); /* LATIN CAPITAL LETTER A WITH BREVE AND ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7856, 'status' => 'C', 'lower' => array(7857)); /* LATIN CAPITAL LETTER A WITH BREVE AND GRAVE */
-$config['1e00_1eff'][] = array('upper' => 7858, 'status' => 'C', 'lower' => array(7859)); /* LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7860, 'status' => 'C', 'lower' => array(7861)); /* LATIN CAPITAL LETTER A WITH BREVE AND TILDE */
-$config['1e00_1eff'][] = array('upper' => 7862, 'status' => 'C', 'lower' => array(7863)); /* LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7864, 'status' => 'C', 'lower' => array(7865)); /* LATIN CAPITAL LETTER E WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7866, 'status' => 'C', 'lower' => array(7867)); /* LATIN CAPITAL LETTER E WITH HOOK ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7868, 'status' => 'C', 'lower' => array(7869)); /* LATIN CAPITAL LETTER E WITH TILDE */
-$config['1e00_1eff'][] = array('upper' => 7870, 'status' => 'C', 'lower' => array(7871)); /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7872, 'status' => 'C', 'lower' => array(7873)); /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE */
-$config['1e00_1eff'][] = array('upper' => 7874, 'status' => 'C', 'lower' => array(7875)); /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7876, 'status' => 'C', 'lower' => array(7877)); /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE */
-$config['1e00_1eff'][] = array('upper' => 7878, 'status' => 'C', 'lower' => array(7879)); /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7880, 'status' => 'C', 'lower' => array(7881)); /* LATIN CAPITAL LETTER I WITH HOOK ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7882, 'status' => 'C', 'lower' => array(7883)); /* LATIN CAPITAL LETTER I WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7884, 'status' => 'C', 'lower' => array(7885)); /* LATIN CAPITAL LETTER O WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7886, 'status' => 'C', 'lower' => array(7887)); /* LATIN CAPITAL LETTER O WITH HOOK ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7888, 'status' => 'C', 'lower' => array(7889)); /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7890, 'status' => 'C', 'lower' => array(7891)); /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE */
-$config['1e00_1eff'][] = array('upper' => 7892, 'status' => 'C', 'lower' => array(7893)); /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7894, 'status' => 'C', 'lower' => array(7895)); /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE */
-$config['1e00_1eff'][] = array('upper' => 7896, 'status' => 'C', 'lower' => array(7897)); /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7898, 'status' => 'C', 'lower' => array(7899)); /* LATIN CAPITAL LETTER O WITH HORN AND ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7900, 'status' => 'C', 'lower' => array(7901)); /* LATIN CAPITAL LETTER O WITH HORN AND GRAVE */
-$config['1e00_1eff'][] = array('upper' => 7902, 'status' => 'C', 'lower' => array(7903)); /* LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7904, 'status' => 'C', 'lower' => array(7905)); /* LATIN CAPITAL LETTER O WITH HORN AND TILDE */
-$config['1e00_1eff'][] = array('upper' => 7906, 'status' => 'C', 'lower' => array(7907)); /* LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7908, 'status' => 'C', 'lower' => array(7909)); /* LATIN CAPITAL LETTER U WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7910, 'status' => 'C', 'lower' => array(7911)); /* LATIN CAPITAL LETTER U WITH HOOK ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7912, 'status' => 'C', 'lower' => array(7913)); /* LATIN CAPITAL LETTER U WITH HORN AND ACUTE */
-$config['1e00_1eff'][] = array('upper' => 7914, 'status' => 'C', 'lower' => array(7915)); /* LATIN CAPITAL LETTER U WITH HORN AND GRAVE */
-$config['1e00_1eff'][] = array('upper' => 7916, 'status' => 'C', 'lower' => array(7917)); /* LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7918, 'status' => 'C', 'lower' => array(7919)); /* LATIN CAPITAL LETTER U WITH HORN AND TILDE */
-$config['1e00_1eff'][] = array('upper' => 7920, 'status' => 'C', 'lower' => array(7921)); /* LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7922, 'status' => 'C', 'lower' => array(7923)); /* LATIN CAPITAL LETTER Y WITH GRAVE */
-$config['1e00_1eff'][] = array('upper' => 7924, 'status' => 'C', 'lower' => array(7925)); /* LATIN CAPITAL LETTER Y WITH DOT BELOW */
-$config['1e00_1eff'][] = array('upper' => 7926, 'status' => 'C', 'lower' => array(7927)); /* LATIN CAPITAL LETTER Y WITH HOOK ABOVE */
-$config['1e00_1eff'][] = array('upper' => 7928, 'status' => 'C', 'lower' => array(7929)); /* LATIN CAPITAL LETTER Y WITH TILDE */
diff --git a/lib/Cake/Config/unicode/casefolding/1f00_1fff.php b/lib/Cake/Config/unicode/casefolding/1f00_1fff.php
deleted file mode 100644
index be09aa5a157..00000000000
--- a/lib/Cake/Config/unicode/casefolding/1f00_1fff.php
+++ /dev/null
@@ -1,216 +0,0 @@
- 7944, 'status' => 'C', 'lower' => array(7936, 953)); /* GREEK CAPITAL LETTER ALPHA WITH PSILI */
-$config['1f00_1fff'][] = array('upper' => 7945, 'status' => 'C', 'lower' => array(7937)); /* GREEK CAPITAL LETTER ALPHA WITH DASIA */
-$config['1f00_1fff'][] = array('upper' => 7946, 'status' => 'C', 'lower' => array(7938)); /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 7947, 'status' => 'C', 'lower' => array(7939)); /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 7948, 'status' => 'C', 'lower' => array(7940)); /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 7949, 'status' => 'C', 'lower' => array(7941)); /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 7950, 'status' => 'C', 'lower' => array(7942)); /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 7951, 'status' => 'C', 'lower' => array(7943)); /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 7960, 'status' => 'C', 'lower' => array(7952)); /* GREEK CAPITAL LETTER EPSILON WITH PSILI */
-$config['1f00_1fff'][] = array('upper' => 7961, 'status' => 'C', 'lower' => array(7953)); /* GREEK CAPITAL LETTER EPSILON WITH DASIA */
-$config['1f00_1fff'][] = array('upper' => 7962, 'status' => 'C', 'lower' => array(7954)); /* GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 7963, 'status' => 'C', 'lower' => array(7955)); /* GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 7964, 'status' => 'C', 'lower' => array(7956)); /* GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 7965, 'status' => 'C', 'lower' => array(7957)); /* GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 7976, 'status' => 'C', 'lower' => array(7968)); /* GREEK CAPITAL LETTER ETA WITH PSILI */
-$config['1f00_1fff'][] = array('upper' => 7977, 'status' => 'C', 'lower' => array(7969)); /* GREEK CAPITAL LETTER ETA WITH DASIA */
-$config['1f00_1fff'][] = array('upper' => 7978, 'status' => 'C', 'lower' => array(7970)); /* GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 7979, 'status' => 'C', 'lower' => array(7971)); /* GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 7980, 'status' => 'C', 'lower' => array(7972)); /* GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 7981, 'status' => 'C', 'lower' => array(7973)); /* GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 7982, 'status' => 'C', 'lower' => array(7974)); /* GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 7983, 'status' => 'C', 'lower' => array(7975)); /* GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 7992, 'status' => 'C', 'lower' => array(7984)); /* GREEK CAPITAL LETTER IOTA WITH PSILI */
-$config['1f00_1fff'][] = array('upper' => 7993, 'status' => 'C', 'lower' => array(7985)); /* GREEK CAPITAL LETTER IOTA WITH DASIA */
-$config['1f00_1fff'][] = array('upper' => 7994, 'status' => 'C', 'lower' => array(7986)); /* GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 7995, 'status' => 'C', 'lower' => array(7987)); /* GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 7996, 'status' => 'C', 'lower' => array(7988)); /* GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 7997, 'status' => 'C', 'lower' => array(7989)); /* GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 7998, 'status' => 'C', 'lower' => array(7990)); /* GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 7999, 'status' => 'C', 'lower' => array(7991)); /* GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 8008, 'status' => 'C', 'lower' => array(8000)); /* GREEK CAPITAL LETTER OMICRON WITH PSILI */
-$config['1f00_1fff'][] = array('upper' => 8009, 'status' => 'C', 'lower' => array(8001)); /* GREEK CAPITAL LETTER OMICRON WITH DASIA */
-$config['1f00_1fff'][] = array('upper' => 8010, 'status' => 'C', 'lower' => array(8002)); /* GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 8011, 'status' => 'C', 'lower' => array(8003)); /* GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 8012, 'status' => 'C', 'lower' => array(8004)); /* GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 8013, 'status' => 'C', 'lower' => array(8005)); /* GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 8016, 'status' => 'F', 'lower' => array(965, 787)); /* GREEK SMALL LETTER UPSILON WITH PSILI */
-$config['1f00_1fff'][] = array('upper' => 8018, 'status' => 'F', 'lower' => array(965, 787, 768)); /* GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 8020, 'status' => 'F', 'lower' => array(965, 787, 769)); /* GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 8022, 'status' => 'F', 'lower' => array(965, 787, 834)); /* GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 8025, 'status' => 'C', 'lower' => array(8017)); /* GREEK CAPITAL LETTER UPSILON WITH DASIA */
-$config['1f00_1fff'][] = array('upper' => 8027, 'status' => 'C', 'lower' => array(8019)); /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 8029, 'status' => 'C', 'lower' => array(8021)); /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 8031, 'status' => 'C', 'lower' => array(8023)); /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 8040, 'status' => 'C', 'lower' => array(8032)); /* GREEK CAPITAL LETTER OMEGA WITH PSILI */
-$config['1f00_1fff'][] = array('upper' => 8041, 'status' => 'C', 'lower' => array(8033)); /* GREEK CAPITAL LETTER OMEGA WITH DASIA */
-$config['1f00_1fff'][] = array('upper' => 8042, 'status' => 'C', 'lower' => array(8034)); /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 8043, 'status' => 'C', 'lower' => array(8035)); /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 8044, 'status' => 'C', 'lower' => array(8036)); /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 8045, 'status' => 'C', 'lower' => array(8037)); /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 8046, 'status' => 'C', 'lower' => array(8038)); /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 8047, 'status' => 'C', 'lower' => array(8039)); /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 8064, 'status' => 'F', 'lower' => array(7936, 953)); /* GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8065, 'status' => 'F', 'lower' => array(7937, 953)); /* GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8066, 'status' => 'F', 'lower' => array(7938, 953)); /* GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8067, 'status' => 'F', 'lower' => array(7939, 953)); /* GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8068, 'status' => 'F', 'lower' => array(7940, 953)); /* GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8069, 'status' => 'F', 'lower' => array(7941, 953)); /* GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8070, 'status' => 'F', 'lower' => array(7942, 953)); /* GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8071, 'status' => 'F', 'lower' => array(7943, 953)); /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8072, 'status' => 'F', 'lower' => array(7936, 953)); /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8072, 'status' => 'S', 'lower' => array(8064)); /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8073, 'status' => 'F', 'lower' => array(7937, 953)); /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8073, 'status' => 'S', 'lower' => array(8065)); /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8074, 'status' => 'F', 'lower' => array(7938, 953)); /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8074, 'status' => 'S', 'lower' => array(8066)); /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8075, 'status' => 'F', 'lower' => array(7939, 953)); /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8075, 'status' => 'S', 'lower' => array(8067)); /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8076, 'status' => 'F', 'lower' => array(7940, 953)); /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8076, 'status' => 'S', 'lower' => array(8068)); /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8077, 'status' => 'F', 'lower' => array(7941, 953)); /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8077, 'status' => 'S', 'lower' => array(8069)); /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8078, 'status' => 'F', 'lower' => array(7942, 953)); /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8078, 'status' => 'S', 'lower' => array(8070)); /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8079, 'status' => 'F', 'lower' => array(7943, 953)); /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8079, 'status' => 'S', 'lower' => array(8071)); /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8080, 'status' => 'F', 'lower' => array(7968, 953)); /* GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8081, 'status' => 'F', 'lower' => array(7969, 953)); /* GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8082, 'status' => 'F', 'lower' => array(7970, 953)); /* GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8083, 'status' => 'F', 'lower' => array(7971, 953)); /* GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8084, 'status' => 'F', 'lower' => array(7972, 953)); /* GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8085, 'status' => 'F', 'lower' => array(7973, 953)); /* GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8086, 'status' => 'F', 'lower' => array(7974, 953)); /* GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8087, 'status' => 'F', 'lower' => array(7975, 953)); /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8088, 'status' => 'F', 'lower' => array(7968, 953)); /* GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8088, 'status' => 'S', 'lower' => array(8080)); /* GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8089, 'status' => 'F', 'lower' => array(7969, 953)); /* GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8089, 'status' => 'S', 'lower' => array(8081)); /* GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8090, 'status' => 'F', 'lower' => array(7970, 953)); /* GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8090, 'status' => 'S', 'lower' => array(8082)); /* GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8091, 'status' => 'F', 'lower' => array(7971, 953)); /* GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8091, 'status' => 'S', 'lower' => array(8083)); /* GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8092, 'status' => 'F', 'lower' => array(7972, 953)); /* GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8092, 'status' => 'S', 'lower' => array(8084)); /* GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8093, 'status' => 'F', 'lower' => array(7973, 953)); /* GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8093, 'status' => 'S', 'lower' => array(8085)); /* GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8094, 'status' => 'F', 'lower' => array(7974, 953)); /* GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8094, 'status' => 'S', 'lower' => array(8086)); /* GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8095, 'status' => 'F', 'lower' => array(7975, 953)); /* GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8095, 'status' => 'S', 'lower' => array(8087)); /* GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8096, 'status' => 'F', 'lower' => array(8032, 953)); /* GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8097, 'status' => 'F', 'lower' => array(8033, 953)); /* GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8098, 'status' => 'F', 'lower' => array(8034, 953)); /* GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8099, 'status' => 'F', 'lower' => array(8035, 953)); /* GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8100, 'status' => 'F', 'lower' => array(8036, 953)); /* GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8101, 'status' => 'F', 'lower' => array(8037, 953)); /* GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8102, 'status' => 'F', 'lower' => array(8038, 953)); /* GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8103, 'status' => 'F', 'lower' => array(8039, 953)); /* GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8104, 'status' => 'F', 'lower' => array(8032, 953)); /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8104, 'status' => 'S', 'lower' => array(8096)); /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8105, 'status' => 'F', 'lower' => array(8033, 953)); /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8105, 'status' => 'S', 'lower' => array(8097)); /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8106, 'status' => 'F', 'lower' => array(8034, 953)); /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8106, 'status' => 'S', 'lower' => array(8098)); /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8107, 'status' => 'F', 'lower' => array(8035, 953)); /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8107, 'status' => 'S', 'lower' => array(8099)); /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8108, 'status' => 'F', 'lower' => array(8036, 953)); /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8108, 'status' => 'S', 'lower' => array(8100)); /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8109, 'status' => 'F', 'lower' => array(8037, 953)); /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8109, 'status' => 'S', 'lower' => array(8101)); /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8110, 'status' => 'F', 'lower' => array(8038, 953)); /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8110, 'status' => 'S', 'lower' => array(8102)); /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8111, 'status' => 'F', 'lower' => array(8039, 953)); /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8111, 'status' => 'S', 'lower' => array(8103)); /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8114, 'status' => 'F', 'lower' => array(8048, 953)); /* GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8115, 'status' => 'F', 'lower' => array(945, 953)); /* GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8116, 'status' => 'F', 'lower' => array(940, 953)); /* GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8118, 'status' => 'F', 'lower' => array(945, 834)); /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 8119, 'status' => 'F', 'lower' => array(945, 834, 953)); /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8120, 'status' => 'C', 'lower' => array(8112)); /* GREEK CAPITAL LETTER ALPHA WITH VRACHY */
-$config['1f00_1fff'][] = array('upper' => 8121, 'status' => 'C', 'lower' => array(8113)); /* GREEK CAPITAL LETTER ALPHA WITH MACRON */
-$config['1f00_1fff'][] = array('upper' => 8122, 'status' => 'C', 'lower' => array(8048)); /* GREEK CAPITAL LETTER ALPHA WITH VARIA */
-$config['1f00_1fff'][] = array('upper' => 8123, 'status' => 'C', 'lower' => array(8049)); /* GREEK CAPITAL LETTER ALPHA WITH OXIA */
-$config['1f00_1fff'][] = array('upper' => 8124, 'status' => 'F', 'lower' => array(945, 953)); /* GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8124, 'status' => 'S', 'lower' => array(8115)); /* GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8126, 'status' => 'C', 'lower' => array(953)); /* GREEK PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8130, 'status' => 'F', 'lower' => array(8052, 953)); /* GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8131, 'status' => 'F', 'lower' => array(951, 953)); /* GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8132, 'status' => 'F', 'lower' => array(942, 953)); /* GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8134, 'status' => 'F', 'lower' => array(951, 834)); /* GREEK SMALL LETTER ETA WITH PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 8135, 'status' => 'F', 'lower' => array(951, 834, 953)); /* GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8136, 'status' => 'C', 'lower' => array(8050)); /* GREEK CAPITAL LETTER EPSILON WITH VARIA */
-$config['1f00_1fff'][] = array('upper' => 8137, 'status' => 'C', 'lower' => array(8051)); /* GREEK CAPITAL LETTER EPSILON WITH OXIA */
-$config['1f00_1fff'][] = array('upper' => 8138, 'status' => 'C', 'lower' => array(8052)); /* GREEK CAPITAL LETTER ETA WITH VARIA */
-$config['1f00_1fff'][] = array('upper' => 8139, 'status' => 'C', 'lower' => array(8053)); /* GREEK CAPITAL LETTER ETA WITH OXIA */
-$config['1f00_1fff'][] = array('upper' => 8140, 'status' => 'F', 'lower' => array(951, 953)); /* GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8140, 'status' => 'S', 'lower' => array(8131)); /* GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8146, 'status' => 'F', 'lower' => array(953, 776, 768)); /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 8147, 'status' => 'F', 'lower' => array(953, 776, 769)); /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 8150, 'status' => 'F', 'lower' => array(953, 834)); /* GREEK SMALL LETTER IOTA WITH PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 8151, 'status' => 'F', 'lower' => array(953, 776, 834)); /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 8152, 'status' => 'C', 'lower' => array(8144)); /* GREEK CAPITAL LETTER IOTA WITH VRACHY */
-$config['1f00_1fff'][] = array('upper' => 8153, 'status' => 'C', 'lower' => array(8145)); /* GREEK CAPITAL LETTER IOTA WITH MACRON */
-$config['1f00_1fff'][] = array('upper' => 8154, 'status' => 'C', 'lower' => array(8054)); /* GREEK CAPITAL LETTER IOTA WITH VARIA */
-$config['1f00_1fff'][] = array('upper' => 8155, 'status' => 'C', 'lower' => array(8055)); /* GREEK CAPITAL LETTER IOTA WITH OXIA */
-$config['1f00_1fff'][] = array('upper' => 8162, 'status' => 'F', 'lower' => array(965, 776, 768)); /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA */
-$config['1f00_1fff'][] = array('upper' => 8163, 'status' => 'F', 'lower' => array(965, 776, 769)); /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA */
-$config['1f00_1fff'][] = array('upper' => 8164, 'status' => 'F', 'lower' => array(961, 787)); /* GREEK SMALL LETTER RHO WITH PSILI */
-$config['1f00_1fff'][] = array('upper' => 8166, 'status' => 'F', 'lower' => array(965, 834)); /* GREEK SMALL LETTER UPSILON WITH PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 8167, 'status' => 'F', 'lower' => array(965, 776, 834)); /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 8168, 'status' => 'C', 'lower' => array(8160)); /* GREEK CAPITAL LETTER UPSILON WITH VRACHY */
-$config['1f00_1fff'][] = array('upper' => 8169, 'status' => 'C', 'lower' => array(8161)); /* GREEK CAPITAL LETTER UPSILON WITH MACRON */
-$config['1f00_1fff'][] = array('upper' => 8170, 'status' => 'C', 'lower' => array(8058)); /* GREEK CAPITAL LETTER UPSILON WITH VARIA */
-$config['1f00_1fff'][] = array('upper' => 8171, 'status' => 'C', 'lower' => array(8059)); /* GREEK CAPITAL LETTER UPSILON WITH OXIA */
-$config['1f00_1fff'][] = array('upper' => 8172, 'status' => 'C', 'lower' => array(8165)); /* GREEK CAPITAL LETTER RHO WITH DASIA */
-$config['1f00_1fff'][] = array('upper' => 8178, 'status' => 'F', 'lower' => array(8060, 953)); /* GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8179, 'status' => 'F', 'lower' => array(969, 953)); /* GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8180, 'status' => 'F', 'lower' => array(974, 953)); /* GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8182, 'status' => 'F', 'lower' => array(969, 834)); /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI */
-$config['1f00_1fff'][] = array('upper' => 8183, 'status' => 'F', 'lower' => array(969, 834, 953)); /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8184, 'status' => 'C', 'lower' => array(8056)); /* GREEK CAPITAL LETTER OMICRON WITH VARIA */
-$config['1f00_1fff'][] = array('upper' => 8185, 'status' => 'C', 'lower' => array(8057)); /* GREEK CAPITAL LETTER OMICRON WITH OXIA */
-$config['1f00_1fff'][] = array('upper' => 8186, 'status' => 'C', 'lower' => array(8060)); /* GREEK CAPITAL LETTER OMEGA WITH VARIA */
-$config['1f00_1fff'][] = array('upper' => 8187, 'status' => 'C', 'lower' => array(8061)); /* GREEK CAPITAL LETTER OMEGA WITH OXIA */
-$config['1f00_1fff'][] = array('upper' => 8188, 'status' => 'F', 'lower' => array(969, 953)); /* GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI */
-$config['1f00_1fff'][] = array('upper' => 8188, 'status' => 'S', 'lower' => array(8179)); /* GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI */
diff --git a/lib/Cake/Config/unicode/casefolding/2100_214f.php b/lib/Cake/Config/unicode/casefolding/2100_214f.php
deleted file mode 100644
index 77705ede8fb..00000000000
--- a/lib/Cake/Config/unicode/casefolding/2100_214f.php
+++ /dev/null
@@ -1,44 +0,0 @@
- 8486, 'status' => 'C', 'lower' => array(969)); /* OHM SIGN */
-$config['2100_214f'][] = array('upper' => 8490, 'status' => 'C', 'lower' => array(107)); /* KELVIN SIGN */
-$config['2100_214f'][] = array('upper' => 8491, 'status' => 'C', 'lower' => array(229)); /* ANGSTROM SIGN */
-$config['2100_214f'][] = array('upper' => 8498, 'status' => 'C', 'lower' => array(8526)); /* TURNED CAPITAL F */
diff --git a/lib/Cake/Config/unicode/casefolding/2150_218f.php b/lib/Cake/Config/unicode/casefolding/2150_218f.php
deleted file mode 100644
index 8821fbdea8b..00000000000
--- a/lib/Cake/Config/unicode/casefolding/2150_218f.php
+++ /dev/null
@@ -1,57 +0,0 @@
- 8544, 'status' => 'C', 'lower' => array(8560)); /* ROMAN NUMERAL ONE */
-$config['2150_218f'][] = array('upper' => 8545, 'status' => 'C', 'lower' => array(8561)); /* ROMAN NUMERAL TWO */
-$config['2150_218f'][] = array('upper' => 8546, 'status' => 'C', 'lower' => array(8562)); /* ROMAN NUMERAL THREE */
-$config['2150_218f'][] = array('upper' => 8547, 'status' => 'C', 'lower' => array(8563)); /* ROMAN NUMERAL FOUR */
-$config['2150_218f'][] = array('upper' => 8548, 'status' => 'C', 'lower' => array(8564)); /* ROMAN NUMERAL FIVE */
-$config['2150_218f'][] = array('upper' => 8549, 'status' => 'C', 'lower' => array(8565)); /* ROMAN NUMERAL SIX */
-$config['2150_218f'][] = array('upper' => 8550, 'status' => 'C', 'lower' => array(8566)); /* ROMAN NUMERAL SEVEN */
-$config['2150_218f'][] = array('upper' => 8551, 'status' => 'C', 'lower' => array(8567)); /* ROMAN NUMERAL EIGHT */
-$config['2150_218f'][] = array('upper' => 8552, 'status' => 'C', 'lower' => array(8568)); /* ROMAN NUMERAL NINE */
-$config['2150_218f'][] = array('upper' => 8553, 'status' => 'C', 'lower' => array(8569)); /* ROMAN NUMERAL TEN */
-$config['2150_218f'][] = array('upper' => 8554, 'status' => 'C', 'lower' => array(8570)); /* ROMAN NUMERAL ELEVEN */
-$config['2150_218f'][] = array('upper' => 8555, 'status' => 'C', 'lower' => array(8571)); /* ROMAN NUMERAL TWELVE */
-$config['2150_218f'][] = array('upper' => 8556, 'status' => 'C', 'lower' => array(8572)); /* ROMAN NUMERAL FIFTY */
-$config['2150_218f'][] = array('upper' => 8557, 'status' => 'C', 'lower' => array(8573)); /* ROMAN NUMERAL ONE HUNDRED */
-$config['2150_218f'][] = array('upper' => 8558, 'status' => 'C', 'lower' => array(8574)); /* ROMAN NUMERAL FIVE HUNDRED */
-$config['2150_218f'][] = array('upper' => 8559, 'status' => 'C', 'lower' => array(8575)); /* ROMAN NUMERAL ONE THOUSAND */
-$config['2150_218f'][] = array('upper' => 8579, 'status' => 'C', 'lower' => array(8580)); /* ROMAN NUMERAL REVERSED ONE HUNDRED */
diff --git a/lib/Cake/Config/unicode/casefolding/2460_24ff.php b/lib/Cake/Config/unicode/casefolding/2460_24ff.php
deleted file mode 100644
index 08b26159444..00000000000
--- a/lib/Cake/Config/unicode/casefolding/2460_24ff.php
+++ /dev/null
@@ -1,66 +0,0 @@
- 9398, 'status' => 'C', 'lower' => array(9424)); /* CIRCLED LATIN CAPITAL LETTER A */
-$config['2460_24ff'][] = array('upper' => 9399, 'status' => 'C', 'lower' => array(9425)); /* CIRCLED LATIN CAPITAL LETTER B */
-$config['2460_24ff'][] = array('upper' => 9400, 'status' => 'C', 'lower' => array(9426)); /* CIRCLED LATIN CAPITAL LETTER C */
-$config['2460_24ff'][] = array('upper' => 9401, 'status' => 'C', 'lower' => array(9427)); /* CIRCLED LATIN CAPITAL LETTER D */
-$config['2460_24ff'][] = array('upper' => 9402, 'status' => 'C', 'lower' => array(9428)); /* CIRCLED LATIN CAPITAL LETTER E */
-$config['2460_24ff'][] = array('upper' => 9403, 'status' => 'C', 'lower' => array(9429)); /* CIRCLED LATIN CAPITAL LETTER F */
-$config['2460_24ff'][] = array('upper' => 9404, 'status' => 'C', 'lower' => array(9430)); /* CIRCLED LATIN CAPITAL LETTER G */
-$config['2460_24ff'][] = array('upper' => 9405, 'status' => 'C', 'lower' => array(9431)); /* CIRCLED LATIN CAPITAL LETTER H */
-$config['2460_24ff'][] = array('upper' => 9406, 'status' => 'C', 'lower' => array(9432)); /* CIRCLED LATIN CAPITAL LETTER I */
-$config['2460_24ff'][] = array('upper' => 9407, 'status' => 'C', 'lower' => array(9433)); /* CIRCLED LATIN CAPITAL LETTER J */
-$config['2460_24ff'][] = array('upper' => 9408, 'status' => 'C', 'lower' => array(9434)); /* CIRCLED LATIN CAPITAL LETTER K */
-$config['2460_24ff'][] = array('upper' => 9409, 'status' => 'C', 'lower' => array(9435)); /* CIRCLED LATIN CAPITAL LETTER L */
-$config['2460_24ff'][] = array('upper' => 9410, 'status' => 'C', 'lower' => array(9436)); /* CIRCLED LATIN CAPITAL LETTER M */
-$config['2460_24ff'][] = array('upper' => 9411, 'status' => 'C', 'lower' => array(9437)); /* CIRCLED LATIN CAPITAL LETTER N */
-$config['2460_24ff'][] = array('upper' => 9412, 'status' => 'C', 'lower' => array(9438)); /* CIRCLED LATIN CAPITAL LETTER O */
-$config['2460_24ff'][] = array('upper' => 9413, 'status' => 'C', 'lower' => array(9439)); /* CIRCLED LATIN CAPITAL LETTER P */
-$config['2460_24ff'][] = array('upper' => 9414, 'status' => 'C', 'lower' => array(9440)); /* CIRCLED LATIN CAPITAL LETTER Q */
-$config['2460_24ff'][] = array('upper' => 9415, 'status' => 'C', 'lower' => array(9441)); /* CIRCLED LATIN CAPITAL LETTER R */
-$config['2460_24ff'][] = array('upper' => 9416, 'status' => 'C', 'lower' => array(9442)); /* CIRCLED LATIN CAPITAL LETTER S */
-$config['2460_24ff'][] = array('upper' => 9417, 'status' => 'C', 'lower' => array(9443)); /* CIRCLED LATIN CAPITAL LETTER T */
-$config['2460_24ff'][] = array('upper' => 9418, 'status' => 'C', 'lower' => array(9444)); /* CIRCLED LATIN CAPITAL LETTER U */
-$config['2460_24ff'][] = array('upper' => 9419, 'status' => 'C', 'lower' => array(9445)); /* CIRCLED LATIN CAPITAL LETTER V */
-$config['2460_24ff'][] = array('upper' => 9420, 'status' => 'C', 'lower' => array(9446)); /* CIRCLED LATIN CAPITAL LETTER W */
-$config['2460_24ff'][] = array('upper' => 9421, 'status' => 'C', 'lower' => array(9447)); /* CIRCLED LATIN CAPITAL LETTER X */
-$config['2460_24ff'][] = array('upper' => 9422, 'status' => 'C', 'lower' => array(9448)); /* CIRCLED LATIN CAPITAL LETTER Y */
-$config['2460_24ff'][] = array('upper' => 9423, 'status' => 'C', 'lower' => array(9449)); /* CIRCLED LATIN CAPITAL LETTER Z */
diff --git a/lib/Cake/Config/unicode/casefolding/2c00_2c5f.php b/lib/Cake/Config/unicode/casefolding/2c00_2c5f.php
deleted file mode 100644
index 185f39011ab..00000000000
--- a/lib/Cake/Config/unicode/casefolding/2c00_2c5f.php
+++ /dev/null
@@ -1,87 +0,0 @@
- 11264, 'status' => 'C', 'lower' => array(11312)); /* GLAGOLITIC CAPITAL LETTER AZU */
-$config['2c00_2c5f'][] = array('upper' => 11265, 'status' => 'C', 'lower' => array(11313)); /* GLAGOLITIC CAPITAL LETTER BUKY */
-$config['2c00_2c5f'][] = array('upper' => 11266, 'status' => 'C', 'lower' => array(11314)); /* GLAGOLITIC CAPITAL LETTER VEDE */
-$config['2c00_2c5f'][] = array('upper' => 11267, 'status' => 'C', 'lower' => array(11315)); /* GLAGOLITIC CAPITAL LETTER GLAGOLI */
-$config['2c00_2c5f'][] = array('upper' => 11268, 'status' => 'C', 'lower' => array(11316)); /* GLAGOLITIC CAPITAL LETTER DOBRO */
-$config['2c00_2c5f'][] = array('upper' => 11269, 'status' => 'C', 'lower' => array(11317)); /* GLAGOLITIC CAPITAL LETTER YESTU */
-$config['2c00_2c5f'][] = array('upper' => 11270, 'status' => 'C', 'lower' => array(11318)); /* GLAGOLITIC CAPITAL LETTER ZHIVETE */
-$config['2c00_2c5f'][] = array('upper' => 11271, 'status' => 'C', 'lower' => array(11319)); /* GLAGOLITIC CAPITAL LETTER DZELO */
-$config['2c00_2c5f'][] = array('upper' => 11272, 'status' => 'C', 'lower' => array(11320)); /* GLAGOLITIC CAPITAL LETTER ZEMLJA */
-$config['2c00_2c5f'][] = array('upper' => 11273, 'status' => 'C', 'lower' => array(11321)); /* GLAGOLITIC CAPITAL LETTER IZHE */
-$config['2c00_2c5f'][] = array('upper' => 11274, 'status' => 'C', 'lower' => array(11322)); /* GLAGOLITIC CAPITAL LETTER INITIAL IZHE */
-$config['2c00_2c5f'][] = array('upper' => 11275, 'status' => 'C', 'lower' => array(11323)); /* GLAGOLITIC CAPITAL LETTER I */
-$config['2c00_2c5f'][] = array('upper' => 11276, 'status' => 'C', 'lower' => array(11324)); /* GLAGOLITIC CAPITAL LETTER DJERVI */
-$config['2c00_2c5f'][] = array('upper' => 11277, 'status' => 'C', 'lower' => array(11325)); /* GLAGOLITIC CAPITAL LETTER KAKO */
-$config['2c00_2c5f'][] = array('upper' => 11278, 'status' => 'C', 'lower' => array(11326)); /* GLAGOLITIC CAPITAL LETTER LJUDIJE */
-$config['2c00_2c5f'][] = array('upper' => 11279, 'status' => 'C', 'lower' => array(11327)); /* GLAGOLITIC CAPITAL LETTER MYSLITE */
-$config['2c00_2c5f'][] = array('upper' => 11280, 'status' => 'C', 'lower' => array(11328)); /* GLAGOLITIC CAPITAL LETTER NASHI */
-$config['2c00_2c5f'][] = array('upper' => 11281, 'status' => 'C', 'lower' => array(11329)); /* GLAGOLITIC CAPITAL LETTER ONU */
-$config['2c00_2c5f'][] = array('upper' => 11282, 'status' => 'C', 'lower' => array(11330)); /* GLAGOLITIC CAPITAL LETTER POKOJI */
-$config['2c00_2c5f'][] = array('upper' => 11283, 'status' => 'C', 'lower' => array(11331)); /* GLAGOLITIC CAPITAL LETTER RITSI */
-$config['2c00_2c5f'][] = array('upper' => 11284, 'status' => 'C', 'lower' => array(11332)); /* GLAGOLITIC CAPITAL LETTER SLOVO */
-$config['2c00_2c5f'][] = array('upper' => 11285, 'status' => 'C', 'lower' => array(11333)); /* GLAGOLITIC CAPITAL LETTER TVRIDO */
-$config['2c00_2c5f'][] = array('upper' => 11286, 'status' => 'C', 'lower' => array(11334)); /* GLAGOLITIC CAPITAL LETTER UKU */
-$config['2c00_2c5f'][] = array('upper' => 11287, 'status' => 'C', 'lower' => array(11335)); /* GLAGOLITIC CAPITAL LETTER FRITU */
-$config['2c00_2c5f'][] = array('upper' => 11288, 'status' => 'C', 'lower' => array(11336)); /* GLAGOLITIC CAPITAL LETTER HERU */
-$config['2c00_2c5f'][] = array('upper' => 11289, 'status' => 'C', 'lower' => array(11337)); /* GLAGOLITIC CAPITAL LETTER OTU */
-$config['2c00_2c5f'][] = array('upper' => 11290, 'status' => 'C', 'lower' => array(11338)); /* GLAGOLITIC CAPITAL LETTER PE */
-$config['2c00_2c5f'][] = array('upper' => 11291, 'status' => 'C', 'lower' => array(11339)); /* GLAGOLITIC CAPITAL LETTER SHTA */
-$config['2c00_2c5f'][] = array('upper' => 11292, 'status' => 'C', 'lower' => array(11340)); /* GLAGOLITIC CAPITAL LETTER TSI */
-$config['2c00_2c5f'][] = array('upper' => 11293, 'status' => 'C', 'lower' => array(11341)); /* GLAGOLITIC CAPITAL LETTER CHRIVI */
-$config['2c00_2c5f'][] = array('upper' => 11294, 'status' => 'C', 'lower' => array(11342)); /* GLAGOLITIC CAPITAL LETTER SHA */
-$config['2c00_2c5f'][] = array('upper' => 11295, 'status' => 'C', 'lower' => array(11343)); /* GLAGOLITIC CAPITAL LETTER YERU */
-$config['2c00_2c5f'][] = array('upper' => 11296, 'status' => 'C', 'lower' => array(11344)); /* GLAGOLITIC CAPITAL LETTER YERI */
-$config['2c00_2c5f'][] = array('upper' => 11297, 'status' => 'C', 'lower' => array(11345)); /* GLAGOLITIC CAPITAL LETTER YATI */
-$config['2c00_2c5f'][] = array('upper' => 11298, 'status' => 'C', 'lower' => array(11346)); /* GLAGOLITIC CAPITAL LETTER SPIDERY HA */
-$config['2c00_2c5f'][] = array('upper' => 11299, 'status' => 'C', 'lower' => array(11347)); /* GLAGOLITIC CAPITAL LETTER YU */
-$config['2c00_2c5f'][] = array('upper' => 11300, 'status' => 'C', 'lower' => array(11348)); /* GLAGOLITIC CAPITAL LETTER SMALL YUS */
-$config['2c00_2c5f'][] = array('upper' => 11301, 'status' => 'C', 'lower' => array(11349)); /* GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL */
-$config['2c00_2c5f'][] = array('upper' => 11302, 'status' => 'C', 'lower' => array(11350)); /* GLAGOLITIC CAPITAL LETTER YO */
-$config['2c00_2c5f'][] = array('upper' => 11303, 'status' => 'C', 'lower' => array(11351)); /* GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS */
-$config['2c00_2c5f'][] = array('upper' => 11304, 'status' => 'C', 'lower' => array(11352)); /* GLAGOLITIC CAPITAL LETTER BIG YUS */
-$config['2c00_2c5f'][] = array('upper' => 11305, 'status' => 'C', 'lower' => array(11353)); /* GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS */
-$config['2c00_2c5f'][] = array('upper' => 11306, 'status' => 'C', 'lower' => array(11354)); /* GLAGOLITIC CAPITAL LETTER FITA */
-$config['2c00_2c5f'][] = array('upper' => 11307, 'status' => 'C', 'lower' => array(11355)); /* GLAGOLITIC CAPITAL LETTER IZHITSA */
-$config['2c00_2c5f'][] = array('upper' => 11308, 'status' => 'C', 'lower' => array(11356)); /* GLAGOLITIC CAPITAL LETTER SHTAPIC */
-$config['2c00_2c5f'][] = array('upper' => 11309, 'status' => 'C', 'lower' => array(11357)); /* GLAGOLITIC CAPITAL LETTER TROKUTASTI A */
-$config['2c00_2c5f'][] = array('upper' => 11310, 'status' => 'C', 'lower' => array(11358)); /* GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE */
diff --git a/lib/Cake/Config/unicode/casefolding/2c60_2c7f.php b/lib/Cake/Config/unicode/casefolding/2c60_2c7f.php
deleted file mode 100644
index f0f1e906673..00000000000
--- a/lib/Cake/Config/unicode/casefolding/2c60_2c7f.php
+++ /dev/null
@@ -1,48 +0,0 @@
- 11360, 'status' => 'C', 'lower' => array(11361)); /* LATIN CAPITAL LETTER L WITH DOUBLE BAR */
-$config['2c60_2c7f'][] = array('upper' => 11362, 'status' => 'C', 'lower' => array(619)); /* LATIN CAPITAL LETTER L WITH MIDDLE TILDE */
-$config['2c60_2c7f'][] = array('upper' => 11363, 'status' => 'C', 'lower' => array(7549)); /* LATIN CAPITAL LETTER P WITH STROKE */
-$config['2c60_2c7f'][] = array('upper' => 11364, 'status' => 'C', 'lower' => array(637)); /* LATIN CAPITAL LETTER R WITH TAIL */
-$config['2c60_2c7f'][] = array('upper' => 11367, 'status' => 'C', 'lower' => array(11368)); /* LATIN CAPITAL LETTER H WITH DESCENDER */
-$config['2c60_2c7f'][] = array('upper' => 11369, 'status' => 'C', 'lower' => array(11370)); /* LATIN CAPITAL LETTER K WITH DESCENDER */
-$config['2c60_2c7f'][] = array('upper' => 11371, 'status' => 'C', 'lower' => array(11372)); /* LATIN CAPITAL LETTER Z WITH DESCENDER */
-$config['2c60_2c7f'][] = array('upper' => 11381, 'status' => 'C', 'lower' => array(11382)); /* LATIN CAPITAL LETTER HALF H */
diff --git a/lib/Cake/Config/unicode/casefolding/2c80_2cff.php b/lib/Cake/Config/unicode/casefolding/2c80_2cff.php
deleted file mode 100644
index c073a534f2f..00000000000
--- a/lib/Cake/Config/unicode/casefolding/2c80_2cff.php
+++ /dev/null
@@ -1,90 +0,0 @@
- 11392, 'status' => 'C', 'lower' => array(11393)); /* COPTIC CAPITAL LETTER ALFA */
-$config['2c80_2cff'][] = array('upper' => 11394, 'status' => 'C', 'lower' => array(11395)); /* COPTIC CAPITAL LETTER VIDA */
-$config['2c80_2cff'][] = array('upper' => 11396, 'status' => 'C', 'lower' => array(11397)); /* COPTIC CAPITAL LETTER GAMMA */
-$config['2c80_2cff'][] = array('upper' => 11398, 'status' => 'C', 'lower' => array(11399)); /* COPTIC CAPITAL LETTER DALDA */
-$config['2c80_2cff'][] = array('upper' => 11400, 'status' => 'C', 'lower' => array(11401)); /* COPTIC CAPITAL LETTER EIE */
-$config['2c80_2cff'][] = array('upper' => 11402, 'status' => 'C', 'lower' => array(11403)); /* COPTIC CAPITAL LETTER SOU */
-$config['2c80_2cff'][] = array('upper' => 11404, 'status' => 'C', 'lower' => array(11405)); /* COPTIC CAPITAL LETTER ZATA */
-$config['2c80_2cff'][] = array('upper' => 11406, 'status' => 'C', 'lower' => array(11407)); /* COPTIC CAPITAL LETTER HATE */
-$config['2c80_2cff'][] = array('upper' => 11408, 'status' => 'C', 'lower' => array(11409)); /* COPTIC CAPITAL LETTER THETHE */
-$config['2c80_2cff'][] = array('upper' => 11410, 'status' => 'C', 'lower' => array(11411)); /* COPTIC CAPITAL LETTER IAUDA */
-$config['2c80_2cff'][] = array('upper' => 11412, 'status' => 'C', 'lower' => array(11413)); /* COPTIC CAPITAL LETTER KAPA */
-$config['2c80_2cff'][] = array('upper' => 11414, 'status' => 'C', 'lower' => array(11415)); /* COPTIC CAPITAL LETTER LAULA */
-$config['2c80_2cff'][] = array('upper' => 11416, 'status' => 'C', 'lower' => array(11417)); /* COPTIC CAPITAL LETTER MI */
-$config['2c80_2cff'][] = array('upper' => 11418, 'status' => 'C', 'lower' => array(11419)); /* COPTIC CAPITAL LETTER NI */
-$config['2c80_2cff'][] = array('upper' => 11420, 'status' => 'C', 'lower' => array(11421)); /* COPTIC CAPITAL LETTER KSI */
-$config['2c80_2cff'][] = array('upper' => 11422, 'status' => 'C', 'lower' => array(11423)); /* COPTIC CAPITAL LETTER O */
-$config['2c80_2cff'][] = array('upper' => 11424, 'status' => 'C', 'lower' => array(11425)); /* COPTIC CAPITAL LETTER PI */
-$config['2c80_2cff'][] = array('upper' => 11426, 'status' => 'C', 'lower' => array(11427)); /* COPTIC CAPITAL LETTER RO */
-$config['2c80_2cff'][] = array('upper' => 11428, 'status' => 'C', 'lower' => array(11429)); /* COPTIC CAPITAL LETTER SIMA */
-$config['2c80_2cff'][] = array('upper' => 11430, 'status' => 'C', 'lower' => array(11431)); /* COPTIC CAPITAL LETTER TAU */
-$config['2c80_2cff'][] = array('upper' => 11432, 'status' => 'C', 'lower' => array(11433)); /* COPTIC CAPITAL LETTER UA */
-$config['2c80_2cff'][] = array('upper' => 11434, 'status' => 'C', 'lower' => array(11435)); /* COPTIC CAPITAL LETTER FI */
-$config['2c80_2cff'][] = array('upper' => 11436, 'status' => 'C', 'lower' => array(11437)); /* COPTIC CAPITAL LETTER KHI */
-$config['2c80_2cff'][] = array('upper' => 11438, 'status' => 'C', 'lower' => array(11439)); /* COPTIC CAPITAL LETTER PSI */
-$config['2c80_2cff'][] = array('upper' => 11440, 'status' => 'C', 'lower' => array(11441)); /* COPTIC CAPITAL LETTER OOU */
-$config['2c80_2cff'][] = array('upper' => 11442, 'status' => 'C', 'lower' => array(11443)); /* COPTIC CAPITAL LETTER DIALECT-P ALEF */
-$config['2c80_2cff'][] = array('upper' => 11444, 'status' => 'C', 'lower' => array(11445)); /* COPTIC CAPITAL LETTER OLD COPTIC AIN */
-$config['2c80_2cff'][] = array('upper' => 11446, 'status' => 'C', 'lower' => array(11447)); /* COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE */
-$config['2c80_2cff'][] = array('upper' => 11448, 'status' => 'C', 'lower' => array(11449)); /* COPTIC CAPITAL LETTER DIALECT-P KAPA */
-$config['2c80_2cff'][] = array('upper' => 11450, 'status' => 'C', 'lower' => array(11451)); /* COPTIC CAPITAL LETTER DIALECT-P NI */
-$config['2c80_2cff'][] = array('upper' => 11452, 'status' => 'C', 'lower' => array(11453)); /* COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI */
-$config['2c80_2cff'][] = array('upper' => 11454, 'status' => 'C', 'lower' => array(11455)); /* COPTIC CAPITAL LETTER OLD COPTIC OOU */
-$config['2c80_2cff'][] = array('upper' => 11456, 'status' => 'C', 'lower' => array(11457)); /* COPTIC CAPITAL LETTER SAMPI */
-$config['2c80_2cff'][] = array('upper' => 11458, 'status' => 'C', 'lower' => array(11459)); /* COPTIC CAPITAL LETTER CROSSED SHEI */
-$config['2c80_2cff'][] = array('upper' => 11460, 'status' => 'C', 'lower' => array(11461)); /* COPTIC CAPITAL LETTER OLD COPTIC SHEI */
-$config['2c80_2cff'][] = array('upper' => 11462, 'status' => 'C', 'lower' => array(11463)); /* COPTIC CAPITAL LETTER OLD COPTIC ESH */
-$config['2c80_2cff'][] = array('upper' => 11464, 'status' => 'C', 'lower' => array(11465)); /* COPTIC CAPITAL LETTER AKHMIMIC KHEI */
-$config['2c80_2cff'][] = array('upper' => 11466, 'status' => 'C', 'lower' => array(11467)); /* COPTIC CAPITAL LETTER DIALECT-P HORI */
-$config['2c80_2cff'][] = array('upper' => 11468, 'status' => 'C', 'lower' => array(11469)); /* COPTIC CAPITAL LETTER OLD COPTIC HORI */
-$config['2c80_2cff'][] = array('upper' => 11470, 'status' => 'C', 'lower' => array(11471)); /* COPTIC CAPITAL LETTER OLD COPTIC HA */
-$config['2c80_2cff'][] = array('upper' => 11472, 'status' => 'C', 'lower' => array(11473)); /* COPTIC CAPITAL LETTER L-SHAPED HA */
-$config['2c80_2cff'][] = array('upper' => 11474, 'status' => 'C', 'lower' => array(11475)); /* COPTIC CAPITAL LETTER OLD COPTIC HEI */
-$config['2c80_2cff'][] = array('upper' => 11476, 'status' => 'C', 'lower' => array(11477)); /* COPTIC CAPITAL LETTER OLD COPTIC HAT */
-$config['2c80_2cff'][] = array('upper' => 11478, 'status' => 'C', 'lower' => array(11479)); /* COPTIC CAPITAL LETTER OLD COPTIC GANGIA */
-$config['2c80_2cff'][] = array('upper' => 11480, 'status' => 'C', 'lower' => array(11481)); /* COPTIC CAPITAL LETTER OLD COPTIC DJA */
-$config['2c80_2cff'][] = array('upper' => 11482, 'status' => 'C', 'lower' => array(11483)); /* COPTIC CAPITAL LETTER OLD COPTIC SHIMA */
-$config['2c80_2cff'][] = array('upper' => 11484, 'status' => 'C', 'lower' => array(11485)); /* COPTIC CAPITAL LETTER OLD NUBIAN SHIMA */
-$config['2c80_2cff'][] = array('upper' => 11486, 'status' => 'C', 'lower' => array(11487)); /* COPTIC CAPITAL LETTER OLD NUBIAN NGI */
-$config['2c80_2cff'][] = array('upper' => 11488, 'status' => 'C', 'lower' => array(11489)); /* COPTIC CAPITAL LETTER OLD NUBIAN NYI */
-$config['2c80_2cff'][] = array('upper' => 11490, 'status' => 'C', 'lower' => array(11491)); /* COPTIC CAPITAL LETTER OLD NUBIAN WAU */
diff --git a/lib/Cake/Config/unicode/casefolding/ff00_ffef.php b/lib/Cake/Config/unicode/casefolding/ff00_ffef.php
deleted file mode 100644
index 22d7a2d4686..00000000000
--- a/lib/Cake/Config/unicode/casefolding/ff00_ffef.php
+++ /dev/null
@@ -1,66 +0,0 @@
- 65313, 'status' => 'C', 'lower' => array(65345)); /* FULLWIDTH LATIN CAPITAL LETTER A */
-$config['ff00_ffef'][] = array('upper' => 65314, 'status' => 'C', 'lower' => array(65346)); /* FULLWIDTH LATIN CAPITAL LETTER B */
-$config['ff00_ffef'][] = array('upper' => 65315, 'status' => 'C', 'lower' => array(65347)); /* FULLWIDTH LATIN CAPITAL LETTER C */
-$config['ff00_ffef'][] = array('upper' => 65316, 'status' => 'C', 'lower' => array(65348)); /* FULLWIDTH LATIN CAPITAL LETTER D */
-$config['ff00_ffef'][] = array('upper' => 65317, 'status' => 'C', 'lower' => array(65349)); /* FULLWIDTH LATIN CAPITAL LETTER E */
-$config['ff00_ffef'][] = array('upper' => 65318, 'status' => 'C', 'lower' => array(65350)); /* FULLWIDTH LATIN CAPITAL LETTER F */
-$config['ff00_ffef'][] = array('upper' => 65319, 'status' => 'C', 'lower' => array(65351)); /* FULLWIDTH LATIN CAPITAL LETTER G */
-$config['ff00_ffef'][] = array('upper' => 65320, 'status' => 'C', 'lower' => array(65352)); /* FULLWIDTH LATIN CAPITAL LETTER H */
-$config['ff00_ffef'][] = array('upper' => 65321, 'status' => 'C', 'lower' => array(65353)); /* FULLWIDTH LATIN CAPITAL LETTER I */
-$config['ff00_ffef'][] = array('upper' => 65322, 'status' => 'C', 'lower' => array(65354)); /* FULLWIDTH LATIN CAPITAL LETTER J */
-$config['ff00_ffef'][] = array('upper' => 65323, 'status' => 'C', 'lower' => array(65355)); /* FULLWIDTH LATIN CAPITAL LETTER K */
-$config['ff00_ffef'][] = array('upper' => 65324, 'status' => 'C', 'lower' => array(65356)); /* FULLWIDTH LATIN CAPITAL LETTER L */
-$config['ff00_ffef'][] = array('upper' => 65325, 'status' => 'C', 'lower' => array(65357)); /* FULLWIDTH LATIN CAPITAL LETTER M */
-$config['ff00_ffef'][] = array('upper' => 65326, 'status' => 'C', 'lower' => array(65358)); /* FULLWIDTH LATIN CAPITAL LETTER N */
-$config['ff00_ffef'][] = array('upper' => 65327, 'status' => 'C', 'lower' => array(65359)); /* FULLWIDTH LATIN CAPITAL LETTER O */
-$config['ff00_ffef'][] = array('upper' => 65328, 'status' => 'C', 'lower' => array(65360)); /* FULLWIDTH LATIN CAPITAL LETTER P */
-$config['ff00_ffef'][] = array('upper' => 65329, 'status' => 'C', 'lower' => array(65361)); /* FULLWIDTH LATIN CAPITAL LETTER Q */
-$config['ff00_ffef'][] = array('upper' => 65330, 'status' => 'C', 'lower' => array(65362)); /* FULLWIDTH LATIN CAPITAL LETTER R */
-$config['ff00_ffef'][] = array('upper' => 65331, 'status' => 'C', 'lower' => array(65363)); /* FULLWIDTH LATIN CAPITAL LETTER S */
-$config['ff00_ffef'][] = array('upper' => 65332, 'status' => 'C', 'lower' => array(65364)); /* FULLWIDTH LATIN CAPITAL LETTER T */
-$config['ff00_ffef'][] = array('upper' => 65333, 'status' => 'C', 'lower' => array(65365)); /* FULLWIDTH LATIN CAPITAL LETTER U */
-$config['ff00_ffef'][] = array('upper' => 65334, 'status' => 'C', 'lower' => array(65366)); /* FULLWIDTH LATIN CAPITAL LETTER V */
-$config['ff00_ffef'][] = array('upper' => 65335, 'status' => 'C', 'lower' => array(65367)); /* FULLWIDTH LATIN CAPITAL LETTER W */
-$config['ff00_ffef'][] = array('upper' => 65336, 'status' => 'C', 'lower' => array(65368)); /* FULLWIDTH LATIN CAPITAL LETTER X */
-$config['ff00_ffef'][] = array('upper' => 65337, 'status' => 'C', 'lower' => array(65369)); /* FULLWIDTH LATIN CAPITAL LETTER Y */
-$config['ff00_ffef'][] = array('upper' => 65338, 'status' => 'C', 'lower' => array(65370)); /* FULLWIDTH LATIN CAPITAL LETTER Z */
diff --git a/lib/Cake/Configure/ConfigReaderInterface.php b/lib/Cake/Configure/ConfigReaderInterface.php
deleted file mode 100644
index f1373550519..00000000000
--- a/lib/Cake/Configure/ConfigReaderInterface.php
+++ /dev/null
@@ -1,33 +0,0 @@
- array('password' => 'secret'))`
- *
- * You can nest properties as deeply as needed using `.`'s. In addition to using `.` you
- * can use standard ini section notation to create nested structures:
- *
- * {{{
- * [section]
- * key = value
- * }}}
- *
- * Once loaded into Configure, the above would be accessed using:
- *
- * `Configure::read('section.key');
- *
- * You can combine `.` separated values with sections to create more deeply
- * nested structures.
- *
- * IniReader also manipulates how the special ini values of
- * 'yes', 'no', 'on', 'off', 'null' are handled. These values will be
- * converted to their boolean equivalents.
- *
- * @package Cake.Configure
- * @see http://php.net/parse_ini_file
- */
-class IniReader implements ConfigReaderInterface {
-
-/**
- * The path to read ini files from.
- *
- * @var array
- */
- protected $_path;
-
-/**
- * The section to read, if null all sections will be read.
- *
- * @var string
- */
- protected $_section;
-
-/**
- * Build and construct a new ini file parser. The parser can be used to read
- * ini files that are on the filesystem.
- *
- * @param string $path Path to load ini config files from.
- * @param string $section Only get one section, leave null to parse and fetch
- * all sections in the ini file.
- */
- public function __construct($path, $section = null) {
- $this->_path = $path;
- $this->_section = $section;
- }
-
-/**
- * Read an ini file and return the results as an array.
- *
- * @param string $file Name of the file to read. The chosen file
- * must be on the reader's path.
- * @return array
- * @throws ConfigureException
- */
- public function read($file) {
- $filename = $this->_path . $file;
- if (!file_exists($filename)) {
- $filename .= '.ini';
- if (!file_exists($filename)) {
- throw new ConfigureException(__d('cake_dev', 'Could not load configuration files: %s or %s', substr($filename, 0, -4), $filename));
- }
- }
- $contents = parse_ini_file($filename, true);
- if (!empty($this->_section) && isset($contents[$this->_section])) {
- $values = $this->_parseNestedValues($contents[$this->_section]);
- } else {
- $values = array();
- foreach ($contents as $section => $attribs) {
- if (is_array($attribs)) {
- $values[$section] = $this->_parseNestedValues($attribs);
- } else {
- $parse = $this->_parseNestedValues(array($attribs));
- $values[$section] = array_shift($parse);
- }
- }
- }
- return $values;
- }
-
-/**
- * parses nested values out of keys.
- *
- * @param array $values Values to be exploded.
- * @return array Array of values exploded
- */
- protected function _parseNestedValues($values) {
- foreach ($values as $key => $value) {
- if ($value === '1') {
- $value = true;
- }
- if ($value === '') {
- $value = false;
- }
- if (strpos($key, '.') !== false) {
- $values = Set::insert($values, $key, $value);
- } else {
- $values[$key] = $value;
- }
- }
- return $values;
- }
-
-}
diff --git a/lib/Cake/Configure/PhpReader.php b/lib/Cake/Configure/PhpReader.php
deleted file mode 100644
index 2043351b88b..00000000000
--- a/lib/Cake/Configure/PhpReader.php
+++ /dev/null
@@ -1,91 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/2.0/en/development/configuration.html#loading-configuration-files CakePHP(tm) Configuration
- * @package Cake.Configure
- * @since CakePHP(tm) v 2.0
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-/**
- * PHP Reader allows Configure to load configuration values from
- * files containing simple PHP arrays.
- *
- * Files compatible with PhpReader should define a `$config` variable, that
- * contains all of the configuration data contained in the file.
- *
- * @package Cake.Configure
- */
-class PhpReader implements ConfigReaderInterface {
-
-/**
- * The path this reader finds files on.
- *
- * @var string
- */
- protected $_path = null;
-
-/**
- * Constructor for PHP Config file reading.
- *
- * @param string $path The path to read config files from. Defaults to APP . 'Config' . DS
- */
- public function __construct($path = null) {
- if (!$path) {
- $path = APP . 'Config' . DS;
- }
- $this->_path = $path;
- }
-
-/**
- * Read a config file and return its contents.
- *
- * Files with `.` in the name will be treated as values in plugins. Instead of reading from
- * the initialized path, plugin keys will be located using App::pluginPath().
- *
- * @param string $key The identifier to read from. If the key has a . it will be treated
- * as a plugin prefix.
- * @return array Parsed configuration values.
- * @throws ConfigureException when files don't exist or they don't contain `$config`.
- * Or when files contain '..' as this could lead to abusive reads.
- */
- public function read($key) {
- if (strpos($key, '..') !== false) {
- throw new ConfigureException(__d('cake_dev', 'Cannot load configuration files with ../ in them.'));
- }
- if (substr($key, -4) === '.php') {
- $key = substr($key, 0, -4);
- }
- list($plugin, $key) = pluginSplit($key);
-
- if ($plugin) {
- $file = App::pluginPath($plugin) . 'Config' . DS . $key;
- } else {
- $file = $this->_path . $key;
- }
- $file .= '.php';
- if (!is_file($file)) {
- if (!is_file(substr($file, 0, -4))) {
- throw new ConfigureException(__d('cake_dev', 'Could not load configuration files: %s or %s', $file, substr($file, 0, -4)));
- }
- }
- include $file;
- if (!isset($config)) {
- throw new ConfigureException(
- sprintf(__d('cake_dev', 'No variable $config found in %s.php'), $file)
- );
- }
- return $config;
- }
-
-}
diff --git a/lib/Cake/Console/Command/AclShell.php b/lib/Cake/Console/Command/AclShell.php
deleted file mode 100644
index a935f6b2a1c..00000000000
--- a/lib/Cake/Console/Command/AclShell.php
+++ /dev/null
@@ -1,608 +0,0 @@
-params['connection'])) {
- $this->connection = $this->params['connection'];
- }
-
- if (!in_array(Configure::read('Acl.classname'), array('DbAcl', 'DB_ACL'))) {
- $out = "--------------------------------------------------\n";
- $out .= __d('cake_console', 'Error: Your current Cake configuration is set to an ACL implementation other than DB.') . "\n";
- $out .= __d('cake_console', 'Please change your core config to reflect your decision to use DbAcl before attempting to use this script') . "\n";
- $out .= "--------------------------------------------------\n";
- $out .= __d('cake_console', 'Current ACL Classname: %s', Configure::read('Acl.classname')) . "\n";
- $out .= "--------------------------------------------------\n";
- $this->err($out);
- $this->_stop();
- }
-
- if ($this->command) {
- if (!config('database')) {
- $this->out(__d('cake_console', 'Your database configuration was not found. Take a moment to create one.'), true);
- $this->args = null;
- return $this->DbConfig->execute();
- }
- require_once (APP . 'Config' . DS . 'database.php');
-
- if (!in_array($this->command, array('initdb'))) {
- $collection = new ComponentCollection();
- $this->Acl = new AclComponent($collection);
- $controller = new Controller();
- $this->Acl->startup($controller);
- }
- }
- }
-
-/**
- * Override main() for help message hook
- *
- * @return void
- */
- public function main() {
- $this->out($this->OptionParser->help());
- }
-
-/**
- * Creates an ARO/ACO node
- *
- * @return void
- */
- public function create() {
- extract($this->_dataVars());
-
- $class = ucfirst($this->args[0]);
- $parent = $this->parseIdentifier($this->args[1]);
-
- if (!empty($parent) && $parent != '/' && $parent != 'root') {
- $parent = $this->_getNodeId($class, $parent);
- } else {
- $parent = null;
- }
-
- $data = $this->parseIdentifier($this->args[2]);
- if (is_string($data) && $data != '/') {
- $data = array('alias' => $data);
- } elseif (is_string($data)) {
- $this->error(__d('cake_console', '/ can not be used as an alias!') . __d('cake_console', " / is the root, please supply a sub alias"));
- }
-
- $data['parent_id'] = $parent;
- $this->Acl->{$class}->create();
- if ($this->Acl->{$class}->save($data)) {
- $this->out(__d('cake_console', "New %s '%s' created.", $class, $this->args[2]), 2);
- } else {
- $this->err(__d('cake_console', "There was a problem creating a new %s '%s'.", $class, $this->args[2]));
- }
- }
-
-/**
- * Delete an ARO/ACO node.
- *
- * @return void
- */
- public function delete() {
- extract($this->_dataVars());
-
- $identifier = $this->parseIdentifier($this->args[1]);
- $nodeId = $this->_getNodeId($class, $identifier);
-
- if (!$this->Acl->{$class}->delete($nodeId)) {
- $this->error(__d('cake_console', 'Node Not Deleted') . __d('cake_console', 'There was an error deleting the %s. Check that the node exists.', $class) . "\n");
- }
- $this->out(__d('cake_console', '%s deleted. ', $class), 2);
- }
-
-/**
- * Set parent for an ARO/ACO node.
- *
- * @return void
- */
- public function setParent() {
- extract($this->_dataVars());
- $target = $this->parseIdentifier($this->args[1]);
- $parent = $this->parseIdentifier($this->args[2]);
-
- $data = array(
- $class => array(
- 'id' => $this->_getNodeId($class, $target),
- 'parent_id' => $this->_getNodeId($class, $parent)
- )
- );
- $this->Acl->{$class}->create();
- if (!$this->Acl->{$class}->save($data)) {
- $this->out(__d('cake_console', 'Error in setting new parent. Please make sure the parent node exists, and is not a descendant of the node specified.'), true);
- } else {
- $this->out(__d('cake_console', 'Node parent set to %s', $this->args[2]) . "\n", true);
- }
- }
-
-/**
- * Get path to specified ARO/ACO node.
- *
- * @return void
- */
- public function getPath() {
- extract($this->_dataVars());
- $identifier = $this->parseIdentifier($this->args[1]);
-
- $id = $this->_getNodeId($class, $identifier);
- $nodes = $this->Acl->{$class}->getPath($id);
-
- if (empty($nodes)) {
- $this->error(
- __d('cake_console', "Supplied Node '%s' not found", $this->args[1]),
- __d('cake_console', 'No tree returned.')
- );
- }
- $this->out(__d('cake_console', 'Path:'));
- $this->hr();
- for ($i = 0, $len = count($nodes); $i < $len; $i++) {
- $this->_outputNode($class, $nodes[$i], $i);
- }
- }
-
-/**
- * Outputs a single node, Either using the alias or Model.key
- *
- * @param string $class Class name that is being used.
- * @param array $node Array of node information.
- * @param integer $indent indent level.
- * @return void
- */
- protected function _outputNode($class, $node, $indent) {
- $indent = str_repeat(' ', $indent);
- $data = $node[$class];
- if ($data['alias']) {
- $this->out($indent . "[" . $data['id'] . "] " . $data['alias']);
- } else {
- $this->out($indent . "[" . $data['id'] . "] " . $data['model'] . '.' . $data['foreign_key']);
- }
- }
-
-/**
- * Check permission for a given ARO to a given ACO.
- *
- * @return void
- */
- public function check() {
- extract($this->_getParams());
-
- if ($this->Acl->check($aro, $aco, $action)) {
- $this->out(__d('cake_console', '%s is allowed .', $aroName), true);
- } else {
- $this->out(__d('cake_console', '%s is not allowed .', $aroName), true);
- }
- }
-
-/**
- * Grant permission for a given ARO to a given ACO.
- *
- * @return void
- */
- public function grant() {
- extract($this->_getParams());
-
- if ($this->Acl->allow($aro, $aco, $action)) {
- $this->out(__d('cake_console', 'Permission granted .'), true);
- } else {
- $this->out(__d('cake_console', 'Permission was not granted .'), true);
- }
- }
-
-/**
- * Deny access for an ARO to an ACO.
- *
- * @return void
- */
- public function deny() {
- extract($this->_getParams());
-
- if ($this->Acl->deny($aro, $aco, $action)) {
- $this->out(__d('cake_console', 'Permission denied.'), true);
- } else {
- $this->out(__d('cake_console', 'Permission was not denied.'), true);
- }
- }
-
-/**
- * Set an ARO to inherit permission to an ACO.
- *
- * @return void
- */
- public function inherit() {
- extract($this->_getParams());
-
- if ($this->Acl->inherit($aro, $aco, $action)) {
- $this->out(__d('cake_console', 'Permission inherited.'), true);
- } else {
- $this->out(__d('cake_console', 'Permission was not inherited.'), true);
- }
- }
-
-/**
- * Show a specific ARO/ACO node.
- *
- * @return void
- */
- public function view() {
- extract($this->_dataVars());
-
- if (isset($this->args[1])) {
- $identity = $this->parseIdentifier($this->args[1]);
-
- $topNode = $this->Acl->{$class}->find('first', array(
- 'conditions' => array($class . '.id' => $this->_getNodeId($class, $identity))
- ));
-
- $nodes = $this->Acl->{$class}->find('all', array(
- 'conditions' => array(
- $class . '.lft >=' => $topNode[$class]['lft'],
- $class . '.lft <=' => $topNode[$class]['rght']
- ),
- 'order' => $class . '.lft ASC'
- ));
- } else {
- $nodes = $this->Acl->{$class}->find('all', array('order' => $class . '.lft ASC'));
- }
-
- if (empty($nodes)) {
- if (isset($this->args[1])) {
- $this->error(__d('cake_console', '%s not found', $this->args[1]), __d('cake_console', 'No tree returned.'));
- } elseif (isset($this->args[0])) {
- $this->error(__d('cake_console', '%s not found', $this->args[0]), __d('cake_console', 'No tree returned.'));
- }
- }
- $this->out($class . ' tree:');
- $this->hr();
-
- $stack = array();
- $last = null;
-
- foreach ($nodes as $n) {
- $stack[] = $n;
- if (!empty($last)) {
- $end = end($stack);
- if ($end[$class]['rght'] > $last) {
- foreach ($stack as $k => $v) {
- $end = end($stack);
- if ($v[$class]['rght'] < $end[$class]['rght']) {
- unset($stack[$k]);
- }
- }
- }
- }
- $last = $n[$class]['rght'];
- $count = count($stack);
-
- $this->_outputNode($class, $n, $count);
- }
- $this->hr();
- }
-
-/**
- * Initialize ACL database.
- *
- * @return mixed
- */
- public function initdb() {
- return $this->dispatchShell('schema create DbAcl');
- }
-
-/**
- * Get the option parser.
- *
- * @return void
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
-
- $type = array(
- 'choices' => array('aro', 'aco'),
- 'required' => true,
- 'help' => __d('cake_console', 'Type of node to create.')
- );
-
- $parser->description(
- __d('cake_console', 'A console tool for managing the DbAcl')
- )->addSubcommand('create', array(
- 'help' => __d('cake_console', 'Create a new ACL node'),
- 'parser' => array(
- 'description' => __d('cake_console', 'Creates a new ACL object under the parent'),
- 'arguments' => array(
- 'type' => $type,
- 'parent' => array(
- 'help' => __d('cake_console', 'The node selector for the parent.'),
- 'required' => true
- ),
- 'alias' => array(
- 'help' => __d('cake_console', 'The alias to use for the newly created node.'),
- 'required' => true
- )
- )
- )
- ))->addSubcommand('delete', array(
- 'help' => __d('cake_console', 'Deletes the ACL object with the given reference'),
- 'parser' => array(
- 'description' => __d('cake_console', 'Delete an ACL node.'),
- 'arguments' => array(
- 'type' => $type,
- 'node' => array(
- 'help' => __d('cake_console', 'The node identifier to delete.'),
- 'required' => true,
- )
- )
- )
- ))->addSubcommand('setparent', array(
- 'help' => __d('cake_console', 'Moves the ACL node under a new parent.'),
- 'parser' => array(
- 'description' => __d('cake_console', 'Moves the ACL object specified by beneath '),
- 'arguments' => array(
- 'type' => $type,
- 'node' => array(
- 'help' => __d('cake_console', 'The node to move'),
- 'required' => true,
- ),
- 'parent' => array(
- 'help' => __d('cake_console', 'The new parent for .'),
- 'required' => true
- )
- )
- )
- ))->addSubcommand('getpath', array(
- 'help' => __d('cake_console', 'Print out the path to an ACL node.'),
- 'parser' => array(
- 'description' => array(
- __d('cake_console', "Returns the path to the ACL object specified by ."),
- __d('cake_console', "This command is useful in determining the inheritance of permissions for a certain object in the tree.")
- ),
- 'arguments' => array(
- 'type' => $type,
- 'node' => array(
- 'help' => __d('cake_console', 'The node to get the path of'),
- 'required' => true,
- )
- )
- )
- ))->addSubcommand('check', array(
- 'help' => __d('cake_console', 'Check the permissions between an ACO and ARO.'),
- 'parser' => array(
- 'description' => array(
- __d('cake_console', 'Use this command to check ACL permissions.')
- ),
- 'arguments' => array(
- 'aro' => array('help' => __d('cake_console', 'ARO to check.'), 'required' => true),
- 'aco' => array('help' => __d('cake_console', 'ACO to check.'), 'required' => true),
- 'action' => array('help' => __d('cake_console', 'Action to check'), 'default' => 'all')
- )
- )
- ))->addSubcommand('grant', array(
- 'help' => __d('cake_console', 'Grant an ARO permissions to an ACO.'),
- 'parser' => array(
- 'description' => array(
- __d('cake_console', 'Use this command to grant ACL permissions. Once executed, the ARO specified (and its children, if any) will have ALLOW access to the specified ACO action (and the ACO\'s children, if any).')
- ),
- 'arguments' => array(
- 'aro' => array('help' => __d('cake_console', 'ARO to grant permission to.'), 'required' => true),
- 'aco' => array('help' => __d('cake_console', 'ACO to grant access to.'), 'required' => true),
- 'action' => array('help' => __d('cake_console', 'Action to grant'), 'default' => 'all')
- )
- )
- ))->addSubcommand('deny', array(
- 'help' => __d('cake_console', 'Deny an ARO permissions to an ACO.'),
- 'parser' => array(
- 'description' => array(
- __d('cake_console', 'Use this command to deny ACL permissions. Once executed, the ARO specified (and its children, if any) will have DENY access to the specified ACO action (and the ACO\'s children, if any).')
- ),
- 'arguments' => array(
- 'aro' => array('help' => __d('cake_console', 'ARO to deny.'), 'required' => true),
- 'aco' => array('help' => __d('cake_console', 'ACO to deny.'), 'required' => true),
- 'action' => array('help' => __d('cake_console', 'Action to deny'), 'default' => 'all')
- )
- )
- ))->addSubcommand('inherit', array(
- 'help' => __d('cake_console', 'Inherit an ARO\'s parent permissions.'),
- 'parser' => array(
- 'description' => array(
- __d('cake_console', "Use this command to force a child ARO object to inherit its permissions settings from its parent.")
- ),
- 'arguments' => array(
- 'aro' => array('help' => __d('cake_console', 'ARO to have permissions inherit.'), 'required' => true),
- 'aco' => array('help' => __d('cake_console', 'ACO to inherit permissions on.'), 'required' => true),
- 'action' => array('help' => __d('cake_console', 'Action to inherit'), 'default' => 'all')
- )
- )
- ))->addSubcommand('view', array(
- 'help' => __d('cake_console', 'View a tree or a single node\'s subtree.'),
- 'parser' => array(
- 'description' => array(
- __d('cake_console', "The view command will return the ARO or ACO tree."),
- __d('cake_console', "The optional node parameter allows you to return"),
- __d('cake_console', "only a portion of the requested tree.")
- ),
- 'arguments' => array(
- 'type' => $type,
- 'node' => array('help' => __d('cake_console', 'The optional node to view the subtree of.'))
- )
- )
- ))->addSubcommand('initdb', array(
- 'help' => __d('cake_console', 'Initialize the DbAcl tables. Uses this command : cake schema create DbAcl')
- ))->epilog(
- array(
- 'Node and parent arguments can be in one of the following formats:',
- '',
- ' - . - The node will be bound to a specific record of the given model.',
- '',
- ' - - The node will be given a string alias (or path, in the case of )',
- " i.e. 'John'. When used with , this takes the form of an alias path,",
- " i.e. //.",
- '',
- "To add a node at the root level, enter 'root' or '/' as the parameter."
- )
- );
- return $parser;
- }
-
-/**
- * Checks that given node exists
- *
- * @return boolean Success
- */
- public function nodeExists() {
- if (!isset($this->args[0]) || !isset($this->args[1])) {
- return false;
- }
- $dataVars = $this->_dataVars($this->args[0]);
- extract($dataVars);
- $key = is_numeric($this->args[1]) ? $dataVars['secondary_id'] : 'alias';
- $conditions = array($class . '.' . $key => $this->args[1]);
- $possibility = $this->Acl->{$class}->find('all', compact('conditions'));
- if (empty($possibility)) {
- $this->error(__d('cake_console', '%s not found', $this->args[1]), __d('cake_console', 'No tree returned.'));
- }
- return $possibility;
- }
-
-/**
- * Parse an identifier into Model.foreignKey or an alias.
- * Takes an identifier determines its type and returns the result as used by other methods.
- *
- * @param string $identifier Identifier to parse
- * @return mixed a string for aliases, and an array for model.foreignKey
- */
- public function parseIdentifier($identifier) {
- if (preg_match('/^([\w]+)\.(.*)$/', $identifier, $matches)) {
- return array(
- 'model' => $matches[1],
- 'foreign_key' => $matches[2],
- );
- }
- return $identifier;
- }
-
-/**
- * Get the node for a given identifier. $identifier can either be a string alias
- * or an array of properties to use in AcoNode::node()
- *
- * @param string $class Class type you want (Aro/Aco)
- * @param mixed $identifier A mixed identifier for finding the node.
- * @return integer Integer of NodeId. Will trigger an error if nothing is found.
- */
- protected function _getNodeId($class, $identifier) {
- $node = $this->Acl->{$class}->node($identifier);
- if (empty($node)) {
- if (is_array($identifier)) {
- $identifier = var_export($identifier, true);
- }
- $this->error(__d('cake_console', 'Could not find node using reference "%s"', $identifier));
- }
- return Set::extract($node, "0.{$class}.id");
- }
-
-/**
- * get params for standard Acl methods
- *
- * @return array aro, aco, action
- */
- protected function _getParams() {
- $aro = is_numeric($this->args[0]) ? intval($this->args[0]) : $this->args[0];
- $aco = is_numeric($this->args[1]) ? intval($this->args[1]) : $this->args[1];
- $aroName = $aro;
- $acoName = $aco;
-
- if (is_string($aro)) {
- $aro = $this->parseIdentifier($aro);
- }
- if (is_string($aco)) {
- $aco = $this->parseIdentifier($aco);
- }
- $action = '*';
- if (isset($this->args[2]) && !in_array($this->args[2], array('', 'all'))) {
- $action = $this->args[2];
- }
- return compact('aro', 'aco', 'action', 'aroName', 'acoName');
- }
-
-/**
- * Build data parameters based on node type
- *
- * @param string $type Node type (ARO/ACO)
- * @return array Variables
- */
- protected function _dataVars($type = null) {
- if ($type == null) {
- $type = $this->args[0];
- }
- $vars = array();
- $class = ucwords($type);
- $vars['secondary_id'] = (strtolower($class) == 'aro') ? 'foreign_key' : 'object_id';
- $vars['data_name'] = $type;
- $vars['table_name'] = $type . 's';
- $vars['class'] = $class;
- return $vars;
- }
-
-}
diff --git a/lib/Cake/Console/Command/ApiShell.php b/lib/Cake/Console/Command/ApiShell.php
deleted file mode 100644
index 8ba50e7fbbf..00000000000
--- a/lib/Cake/Console/Command/ApiShell.php
+++ /dev/null
@@ -1,238 +0,0 @@
-paths = array_merge($this->paths, array(
- 'behavior' => CAKE . 'Model' . DS . 'Behavior' . DS,
- 'cache' => CAKE . 'Cache' . DS,
- 'controller' => CAKE . 'Controller' . DS,
- 'component' => CAKE . 'Controller' . DS . 'Component' . DS,
- 'helper' => CAKE . 'View' . DS . 'Helper' . DS,
- 'model' => CAKE . 'Model' . DS,
- 'view' => CAKE . 'View' . DS,
- 'core' => CAKE
- ));
- }
-
-/**
- * Override main() to handle action
- *
- * @return void
- */
- public function main() {
- if (empty($this->args)) {
- return $this->out($this->OptionParser->help());
- }
-
- $type = strtolower($this->args[0]);
-
- if (isset($this->paths[$type])) {
- $path = $this->paths[$type];
- } else {
- $path = $this->paths['core'];
- }
-
- if (count($this->args) == 1) {
- $file = $type;
- $class = Inflector::camelize($type);
- } elseif (count($this->args) > 1) {
- $file = Inflector::underscore($this->args[1]);
- $class = Inflector::camelize($this->args[1]);
- }
- $objects = App::objects('class', $path);
- if (in_array($class, $objects)) {
- if (in_array($type, array('behavior', 'component', 'helper')) && $type !== $file) {
- if (!preg_match('/' . Inflector::camelize($type) . '$/', $class)) {
- $class .= Inflector::camelize($type);
- }
- }
-
- } else {
- $this->error(__d('cake_console', '%s not found', $class));
- }
-
- $parsed = $this->_parseClass($path . $class . '.php', $class);
-
- if (!empty($parsed)) {
- if (isset($this->params['method'])) {
- if (!isset($parsed[$this->params['method']])) {
- $this->err(__d('cake_console', '%s::%s() could not be found', $class, $this->params['method']));
- $this->_stop();
- }
- $method = $parsed[$this->params['method']];
- $this->out($class . '::' . $method['method'] . $method['parameters']);
- $this->hr();
- $this->out($method['comment'], true);
- } else {
- $this->out(ucwords($class));
- $this->hr();
- $i = 0;
- foreach ($parsed as $method) {
- $list[] = ++$i . ". " . $method['method'] . $method['parameters'];
- }
- $this->out($list);
-
- $methods = array_keys($parsed);
- while ($number = strtolower($this->in(__d('cake_console', 'Select a number to see the more information about a specific method. q to quit. l to list.'), null, 'q'))) {
- if ($number === 'q') {
- $this->out(__d('cake_console', 'Done'));
- return $this->_stop();
- }
-
- if ($number === 'l') {
- $this->out($list);
- }
-
- if (isset($methods[--$number])) {
- $method = $parsed[$methods[$number]];
- $this->hr();
- $this->out($class . '::' . $method['method'] . $method['parameters']);
- $this->hr();
- $this->out($method['comment'], true);
- }
- }
- }
- }
- }
-
-/**
- * Get and configure the optionparser.
- *
- * @return ConsoleOptionParser
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- $parser->addArgument('type', array(
- 'help' => __d('cake_console', 'Either a full path or type of class (model, behavior, controller, component, view, helper)')
- ))->addArgument('className', array(
- 'help' => __d('cake_console', 'A CakePHP core class name (e.g: Component, HtmlHelper).')
- ))->addOption('method', array(
- 'short' => 'm',
- 'help' => __d('cake_console', 'The specific method you want help on.')
- ))->description(__d('cake_console', 'Lookup doc block comments for classes in CakePHP.'));
- return $parser;
- }
-
-/**
- * Show help for this shell.
- *
- * @return void
- */
- public function help() {
- $head = "Usage: cake api [] [-m ]\n";
- $head .= "-----------------------------------------------\n";
- $head .= "Parameters:\n\n";
-
- $commands = array(
- 'path' => "\t\n" .
- "\t\tEither a full path or type of class (model, behavior, controller, component, view, helper).\n" .
- "\t\tAvailable values:\n\n" .
- "\t\tbehavior\tLook for class in CakePHP behavior path\n" .
- "\t\tcache\tLook for class in CakePHP cache path\n" .
- "\t\tcontroller\tLook for class in CakePHP controller path\n" .
- "\t\tcomponent\tLook for class in CakePHP component path\n" .
- "\t\thelper\tLook for class in CakePHP helper path\n" .
- "\t\tmodel\tLook for class in CakePHP model path\n" .
- "\t\tview\tLook for class in CakePHP view path\n",
- 'className' => "\t\n" .
- "\t\tA CakePHP core class name (e.g: Component, HtmlHelper).\n"
- );
-
- $this->out($head);
- if (!isset($this->args[1])) {
- foreach ($commands as $cmd) {
- $this->out("{$cmd}\n\n");
- }
- } elseif (isset($commands[strtolower($this->args[1])])) {
- $this->out($commands[strtolower($this->args[1])] . "\n\n");
- } else {
- $this->out(__d('cake_console', 'Command %s not found', $this->args[1]));
- }
- }
-
-/**
- * Parse a given class (located on given file) and get public methods and their
- * signatures.
- *
- * @param string $path File path
- * @param string $class Class name
- * @return array Methods and signatures indexed by method name
- */
- protected function _parseClass($path, $class) {
- $parsed = array();
-
- if (!class_exists($class)) {
- if (!include_once $path) {
- $this->err(__d('cake_console', '%s could not be found', $path));
- }
- }
-
- $reflection = new ReflectionClass($class);
-
- foreach ($reflection->getMethods() as $method) {
- if (!$method->isPublic() || strpos($method->getName(), '_') === 0) {
- continue;
- }
- if ($method->getDeclaringClass()->getName() != $class) {
- continue;
- }
- $args = array();
- foreach ($method->getParameters() as $param) {
- $paramString = '$' . $param->getName();
- if ($param->isDefaultValueAvailable()) {
- $paramString .= ' = ' . str_replace("\n", '', var_export($param->getDefaultValue(), true));
- }
- $args[] = $paramString;
- }
- $parsed[$method->getName()] = array(
- 'comment' => str_replace(array('/*', '*/', '*'), '', $method->getDocComment()),
- 'method' => $method->getName(),
- 'parameters' => '(' . implode(', ', $args) . ')'
- );
- }
- ksort($parsed);
- return $parsed;
- }
-
-}
diff --git a/lib/Cake/Console/Command/AppShell.php b/lib/Cake/Console/Command/AppShell.php
deleted file mode 100644
index 5cc915f6bfe..00000000000
--- a/lib/Cake/Console/Command/AppShell.php
+++ /dev/null
@@ -1,31 +0,0 @@
-connection to the active task if a connection param is set.
- *
- * @return void
- */
- public function startup() {
- parent::startup();
- Configure::write('debug', 2);
- Configure::write('Cache.disable', 1);
-
- $task = Inflector::classify($this->command);
- if (isset($this->{$task}) && !in_array($task, array('Project', 'DbConfig'))) {
- if (isset($this->params['connection'])) {
- $this->{$task}->connection = $this->params['connection'];
- }
- }
- }
-
-/**
- * Override main() to handle action
- *
- * @return mixed
- */
- public function main() {
- if (!is_dir($this->DbConfig->path)) {
- $path = $this->Project->execute();
- if (!empty($path)) {
- $this->DbConfig->path = $path . 'Config' . DS;
- } else {
- return false;
- }
- }
-
- if (!config('database')) {
- $this->out(__d('cake_console', 'Your database configuration was not found. Take a moment to create one.'));
- $this->args = null;
- return $this->DbConfig->execute();
- }
- $this->out(__d('cake_console', 'Interactive Bake Shell'));
- $this->hr();
- $this->out(__d('cake_console', '[D]atabase Configuration'));
- $this->out(__d('cake_console', '[M]odel'));
- $this->out(__d('cake_console', '[V]iew'));
- $this->out(__d('cake_console', '[C]ontroller'));
- $this->out(__d('cake_console', '[P]roject'));
- $this->out(__d('cake_console', '[F]ixture'));
- $this->out(__d('cake_console', '[T]est case'));
- $this->out(__d('cake_console', '[Q]uit'));
-
- $classToBake = strtoupper($this->in(__d('cake_console', 'What would you like to Bake?'), array('D', 'M', 'V', 'C', 'P', 'F', 'T', 'Q')));
- switch ($classToBake) {
- case 'D':
- $this->DbConfig->execute();
- break;
- case 'M':
- $this->Model->execute();
- break;
- case 'V':
- $this->View->execute();
- break;
- case 'C':
- $this->Controller->execute();
- break;
- case 'P':
- $this->Project->execute();
- break;
- case 'F':
- $this->Fixture->execute();
- break;
- case 'T':
- $this->Test->execute();
- break;
- case 'Q':
- exit(0);
- break;
- default:
- $this->out(__d('cake_console', 'You have made an invalid selection. Please choose a type of class to Bake by entering D, M, V, F, T, or C.'));
- }
- $this->hr();
- $this->main();
- }
-
-/**
- * Quickly bake the MVC
- *
- * @return void
- */
- public function all() {
- $this->out('Bake All');
- $this->hr();
-
- if (!isset($this->params['connection']) && empty($this->connection)) {
- $this->connection = $this->DbConfig->getConfig();
- }
-
- if (empty($this->args)) {
- $this->Model->interactive = true;
- $name = $this->Model->getName($this->connection);
- }
-
- foreach (array('Model', 'Controller', 'View') as $task) {
- $this->{$task}->connection = $this->connection;
- $this->{$task}->interactive = false;
- }
-
- if (!empty($this->args[0])) {
- $name = $this->args[0];
- }
-
- $modelExists = false;
- $model = $this->_modelName($name);
-
- App::uses('AppModel', 'Model');
- App::uses($model, 'Model');
- if (class_exists($model)) {
- $object = new $model();
- $modelExists = true;
- } else {
- $object = new Model(array('name' => $name, 'ds' => $this->connection));
- }
-
- $modelBaked = $this->Model->bake($object, false);
-
- if ($modelBaked && $modelExists === false) {
- if ($this->_checkUnitTest()) {
- $this->Model->bakeFixture($model);
- $this->Model->bakeTest($model);
- }
- $modelExists = true;
- }
-
- if ($modelExists === true) {
- $controller = $this->_controllerName($name);
- if ($this->Controller->bake($controller, $this->Controller->bakeActions($controller))) {
- if ($this->_checkUnitTest()) {
- $this->Controller->bakeTest($controller);
- }
- }
- App::uses($controller . 'Controller', 'Controller');
- if (class_exists($controller . 'Controller')) {
- $this->View->args = array($name);
- $this->View->execute();
- }
- $this->out('', 1, Shell::QUIET);
- $this->out(__d('cake_console', 'Bake All complete '), 1, Shell::QUIET);
- array_shift($this->args);
- } else {
- $this->error(__d('cake_console', 'Bake All could not continue without a valid model'));
- }
- return $this->_stop();
- }
-
-/**
- * get the option parser.
- *
- * @return void
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- return $parser->description(__d('cake_console',
- 'The Bake script generates controllers, views and models for your application.' .
- ' If run with no command line arguments, Bake guides the user through the class creation process.' .
- ' You can customize the generation process by telling Bake where different parts of your application are using command line arguments.'
- ))->addSubcommand('all', array(
- 'help' => __d('cake_console', 'Bake a complete MVC. optional of a Model'),
- ))->addSubcommand('project', array(
- 'help' => __d('cake_console', 'Bake a new app folder in the path supplied or in current directory if no path is specified'),
- 'parser' => $this->Project->getOptionParser()
- ))->addSubcommand('plugin', array(
- 'help' => __d('cake_console', 'Bake a new plugin folder in the path supplied or in current directory if no path is specified.'),
- 'parser' => $this->Plugin->getOptionParser()
- ))->addSubcommand('db_config', array(
- 'help' => __d('cake_console', 'Bake a database.php file in config directory.'),
- 'parser' => $this->DbConfig->getOptionParser()
- ))->addSubcommand('model', array(
- 'help' => __d('cake_console', 'Bake a model.'),
- 'parser' => $this->Model->getOptionParser()
- ))->addSubcommand('view', array(
- 'help' => __d('cake_console', 'Bake views for controllers.'),
- 'parser' => $this->View->getOptionParser()
- ))->addSubcommand('controller', array(
- 'help' => __d('cake_console', 'Bake a controller.'),
- 'parser' => $this->Controller->getOptionParser()
- ))->addSubcommand('fixture', array(
- 'help' => __d('cake_console', 'Bake a fixture.'),
- 'parser' => $this->Fixture->getOptionParser()
- ))->addSubcommand('test', array(
- 'help' => __d('cake_console', 'Bake a unit test.'),
- 'parser' => $this->Test->getOptionParser()
- ))->addOption('connection', array(
- 'help' => __d('cake_console', 'Database connection to use in conjunction with `bake all`.'),
- 'short' => 'c',
- 'default' => 'default'
- ));
- }
-
-}
diff --git a/lib/Cake/Console/Command/CommandListShell.php b/lib/Cake/Console/Command/CommandListShell.php
deleted file mode 100644
index 9b5db93fd42..00000000000
--- a/lib/Cake/Console/Command/CommandListShell.php
+++ /dev/null
@@ -1,234 +0,0 @@
-params['xml'])) {
- parent::startup();
- }
- }
-
-/**
- * Main function Prints out the list of shells.
- *
- * @return void
- */
- public function main() {
- if (empty($this->params['xml'])) {
- $this->out(__d('cake_console', "Current Paths: "), 2);
- $this->out(" -app: " . APP_DIR);
- $this->out(" -working: " . rtrim(APP, DS));
- $this->out(" -root: " . rtrim(ROOT, DS));
- $this->out(" -core: " . rtrim(CORE_PATH, DS));
- $this->out("");
- $this->out(__d('cake_console', "Changing Paths: "), 2);
- $this->out(__d('cake_console', "Your working path should be the same as your application path to change your path use the '-app' param."));
- $this->out(__d('cake_console', "Example: -app relative/path/to/myapp or -app /absolute/path/to/myapp"), 2);
-
- $this->out(__d('cake_console', "Available Shells: "), 2);
- }
-
- $shellList = $this->_getShellList();
-
- if ($shellList) {
- ksort($shellList);
- if (empty($this->params['xml'])) {
- if (!empty($this->params['sort'])) {
- $this->_asSorted($shellList);
- } else {
- $this->_asText($shellList);
- }
- } else {
- $this->_asXml($shellList);
- }
- }
- }
-
-/**
- * Gets the shell command listing.
- *
- * @return array
- */
- protected function _getShellList() {
- $shellList = array();
- $skipFiles = array('AppShell');
-
- $corePath = App::core('Console/Command');
- $shells = App::objects('file', $corePath[0]);
- $shells = array_diff($shells, $skipFiles);
- $shellList = $this->_appendShells('CORE', $shells, $shellList);
-
- $appShells = App::objects('Console/Command', null, false);
- $appShells = array_diff($appShells, $shells, $skipFiles);
- $shellList = $this->_appendShells('app', $appShells, $shellList);
-
- $plugins = CakePlugin::loaded();
- foreach ($plugins as $plugin) {
- $pluginShells = App::objects($plugin . '.Console/Command');
- $shellList = $this->_appendShells($plugin, $pluginShells, $shellList);
- }
-
- return $shellList;
- }
-
-/**
- * Scan the provided paths for shells, and append them into $shellList
- *
- * @param string $type
- * @param array $shells
- * @param array $shellList
- * @return array
- */
- protected function _appendShells($type, $shells, $shellList) {
- foreach ($shells as $shell) {
- $shell = Inflector::underscore(str_replace('Shell', '', $shell));
- $shellList[$shell][$type] = $type;
- }
- return $shellList;
- }
-
-/**
- * Output text.
- *
- * @param array $shellList
- * @return void
- */
- protected function _asText($shellList) {
- if (DS === '/') {
- $width = exec('tput cols') - 2;
- }
- if (empty($width)) {
- $width = 80;
- }
- $columns = max(1, floor($width / 30));
- $rows = ceil(count($shellList) / $columns);
-
- foreach ($shellList as $shell => $types) {
- sort($types);
- $shellList[$shell] = str_pad($shell . ' [' . implode ($types, ', ') . ']', $width / $columns);
- }
- $out = array_chunk($shellList, $rows);
- for ($i = 0; $i < $rows; $i++) {
- $row = '';
- for ($j = 0; $j < $columns; $j++) {
- if (!isset($out[$j][$i])) {
- continue;
- }
- $row .= $out[$j][$i];
- }
- $this->out(" " . $row);
- }
- $this->out();
- $this->out(__d('cake_console', "To run an app or core command, type cake shell_name [args] "));
- $this->out(__d('cake_console', "To run a plugin command, type cake Plugin.shell_name [args] "));
- $this->out(__d('cake_console', "To get help on a specific command, type cake shell_name --help "), 2);
- }
-
-/**
- * Generates the shell list sorted by where the shells are found.
- *
- * @param array $shellList
- * @return void
- */
- protected function _asSorted($shellList) {
- $grouped = array();
- foreach ($shellList as $shell => $types) {
- foreach ($types as $type) {
- $type = Inflector::camelize($type);
- if (empty($grouped[$type])) {
- $grouped[$type] = array();
- }
- $grouped[$type][] = $shell;
- }
- }
- if (!empty($grouped['App'])) {
- sort($grouped['App'], SORT_STRING);
- $this->out('[ App ]');
- $this->out(' ' . implode(', ', $grouped['App']), 2);
- unset($grouped['App']);
- }
- foreach ($grouped as $section => $shells) {
- if ($section == 'CORE') {
- continue;
- }
- sort($shells, SORT_STRING);
- $this->out('[ ' . $section . ' ]');
- $this->out(' ' . implode(', ', $shells), 2);
- }
- if (!empty($grouped['CORE'])) {
- sort($grouped['CORE'], SORT_STRING);
- $this->out('[ Core ]');
- $this->out(' ' . implode(', ', $grouped['CORE']), 2);
- }
- $this->out();
- }
-
-/**
- * Output as XML
- *
- * @param array $shellList
- * @return void
- */
- protected function _asXml($shellList) {
- $plugins = CakePlugin::loaded();
- $shells = new SimpleXmlElement(' ');
- foreach ($shellList as $name => $location) {
- $source = current($location);
- $callable = $name;
- if (in_array($source, $plugins)) {
- $callable = Inflector::camelize($source) . '.' . $name;
- }
- $shell = $shells->addChild('shell');
- $shell->addAttribute('name', $name);
- $shell->addAttribute('call_as', $callable);
- $shell->addAttribute('provider', $source);
- $shell->addAttribute('help', $callable . ' -h');
- }
- $this->stdout->outputAs(ConsoleOutput::RAW);
- $this->out($shells->saveXml());
- }
-
-/**
- * get the option parser
- *
- * @return void
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- return $parser->description(__d('cake_console', 'Get the list of available shells for this CakePHP application.'))
- ->addOption('xml', array(
- 'help' => __d('cake_console', 'Get the listing as XML.'),
- 'boolean' => true
- ))->addOption('sort', array(
- 'help' => __d('cake_console', 'Sorts the commands by where they are located.'),
- 'boolean' => true
- ));
- }
-
-}
diff --git a/lib/Cake/Console/Command/ConsoleShell.php b/lib/Cake/Console/Command/ConsoleShell.php
deleted file mode 100644
index 2471440c3dd..00000000000
--- a/lib/Cake/Console/Command/ConsoleShell.php
+++ /dev/null
@@ -1,359 +0,0 @@
-Dispatcher = new Dispatcher();
- $this->models = App::objects('Model');
-
- foreach ($this->models as $model) {
- $class = $model;
- $this->models[$model] = $class;
- App::uses($class, 'Model');
- $this->{$class} = new $class();
- }
- $this->out(__d('cake_console', 'Model classes:'));
- $this->hr();
-
- foreach ($this->models as $model) {
- $this->out(" - {$model}");
- }
- $this->_loadRoutes();
- }
-
-/**
- * Prints the help message
- *
- * @return void
- */
- public function help() {
- $out = 'Console help:';
- $out .= '-------------';
- $out .= 'The interactive console is a tool for testing parts of your app before you';
- $out .= 'write code.';
- $out .= "\n";
- $out .= 'Model testing:';
- $out .= 'To test model results, use the name of your model without a leading $';
- $out .= 'e.g. Foo->find("all")';
- $out .= "\n";
- $out .= 'To dynamically set associations, you can do the following:';
- $out .= "\tModelA bind ModelB";
- $out .= "where the supported associations are hasOne, hasMany, belongsTo, hasAndBelongsToMany";
- $out .= "\n";
- $out .= 'To dynamically remove associations, you can do the following:';
- $out .= "\t ModelA unbind ModelB";
- $out .= "where the supported associations are the same as above";
- $out .= "\n";
- $out .= "To save a new field in a model, you can do the following:";
- $out .= "\tModelA->save(array('foo' => 'bar', 'baz' => 0))";
- $out .= "where you are passing a hash of data to be saved in the format";
- $out .= "of field => value pairs";
- $out .= "\n";
- $out .= "To get column information for a model, use the following:";
- $out .= "\tModelA columns";
- $out .= "which returns a list of columns and their type";
- $out .= "\n";
- $out .= "\n";
- $out .= 'Route testing:';
- $out .= "\n";
- $out .= 'To test URLs against your app\'s route configuration, type:';
- $out .= "\n";
- $out .= "\tRoute ";
- $out .= "\n";
- $out .= "where url is the path to your your action plus any query parameters,";
- $out .= "minus the application's base path. For example:";
- $out .= "\n";
- $out .= "\tRoute /posts/view/1";
- $out .= "\n";
- $out .= "will return something like the following:";
- $out .= "\n";
- $out .= "\tarray(";
- $out .= "\t [...]";
- $out .= "\t 'controller' => 'posts',";
- $out .= "\t 'action' => 'view',";
- $out .= "\t [...]";
- $out .= "\t)";
- $out .= "\n";
- $out .= 'Alternatively, you can use simple array syntax to test reverse';
- $out .= 'To reload your routes config (Config/routes.php), do the following:';
- $out .= "\n";
- $out .= "\tRoutes reload";
- $out .= "\n";
- $out .= 'To show all connected routes, do the following:';
- $out .= "\tRoutes show";
- $this->out($out);
- }
-
-/**
- * Override main() to handle action
- *
- * @param string $command
- * @return void
- */
- public function main($command = null) {
- while (true) {
- if (empty($command)) {
- $command = trim($this->in(''));
- }
-
- switch ($command) {
- case 'help':
- $this->help();
- break;
- case 'quit':
- case 'exit':
- return true;
- break;
- case 'models':
- $this->out(__d('cake_console', 'Model classes:'));
- $this->hr();
- foreach ($this->models as $model) {
- $this->out(" - {$model}");
- }
- break;
- case (preg_match("/^(\w+) bind (\w+) (\w+)/", $command, $tmp) == true):
- foreach ($tmp as $data) {
- $data = strip_tags($data);
- $data = str_replace($this->badCommandChars, "", $data);
- }
-
- $modelA = $tmp[1];
- $association = $tmp[2];
- $modelB = $tmp[3];
-
- if ($this->_isValidModel($modelA) && $this->_isValidModel($modelB) && in_array($association, $this->associations)) {
- $this->{$modelA}->bindModel(array($association => array($modelB => array('className' => $modelB))), false);
- $this->out(__d('cake_console', "Created %s association between %s and %s",
- $association, $modelA, $modelB));
- } else {
- $this->out(__d('cake_console', "Please verify you are using valid models and association types"));
- }
- break;
- case (preg_match("/^(\w+) unbind (\w+) (\w+)/", $command, $tmp) == true):
- foreach ($tmp as $data) {
- $data = strip_tags($data);
- $data = str_replace($this->badCommandChars, "", $data);
- }
-
- $modelA = $tmp[1];
- $association = $tmp[2];
- $modelB = $tmp[3];
-
- // Verify that there is actually an association to unbind
- $currentAssociations = $this->{$modelA}->getAssociated();
- $validCurrentAssociation = false;
-
- foreach ($currentAssociations as $model => $currentAssociation) {
- if ($model == $modelB && $association == $currentAssociation) {
- $validCurrentAssociation = true;
- }
- }
-
- if ($this->_isValidModel($modelA) && $this->_isValidModel($modelB) && in_array($association, $this->associations) && $validCurrentAssociation) {
- $this->{$modelA}->unbindModel(array($association => array($modelB)));
- $this->out(__d('cake_console', "Removed %s association between %s and %s",
- $association, $modelA, $modelB));
- } else {
- $this->out(__d('cake_console', "Please verify you are using valid models, valid current association, and valid association types"));
- }
- break;
- case (strpos($command, "->find") > 0):
- // Remove any bad info
- $command = strip_tags($command);
- $command = str_replace($this->badCommandChars, "", $command);
-
- // Do we have a valid model?
- list($modelToCheck, $tmp) = explode('->', $command);
-
- if ($this->_isValidModel($modelToCheck)) {
- $findCommand = "\$data = \$this->$command;";
- @eval($findCommand);
-
- if (is_array($data)) {
- foreach ($data as $idx => $results) {
- if (is_numeric($idx)) { // findAll() output
- foreach ($results as $modelName => $result) {
- $this->out("$modelName");
-
- foreach ($result as $field => $value) {
- if (is_array($value)) {
- foreach ($value as $field2 => $value2) {
- $this->out("\t$field2: $value2");
- }
-
- $this->out();
- } else {
- $this->out("\t$field: $value");
- }
- }
- }
- } else { // find() output
- $this->out($idx);
-
- foreach ($results as $field => $value) {
- if (is_array($value)) {
- foreach ($value as $field2 => $value2) {
- $this->out("\t$field2: $value2");
- }
-
- $this->out();
- } else {
- $this->out("\t$field: $value");
- }
- }
- }
- }
- } else {
- $this->out();
- $this->out(__d('cake_console', "No result set found"));
- }
- } else {
- $this->out(__d('cake_console', "%s is not a valid model", $modelToCheck));
- }
-
- break;
- case (strpos($command, '->save') > 0):
- // Validate the model we're trying to save here
- $command = strip_tags($command);
- $command = str_replace($this->badCommandChars, "", $command);
- list($modelToSave, $tmp) = explode("->", $command);
-
- if ($this->_isValidModel($modelToSave)) {
- // Extract the array of data we are trying to build
- list($foo, $data) = explode("->save", $command);
- $data = preg_replace('/^\(*(array)?\(*(.+?)\)*$/i', '\\2', $data);
- $saveCommand = "\$this->{$modelToSave}->save(array('{$modelToSave}' => array({$data})));";
- @eval($saveCommand);
- $this->out(__d('cake_console', 'Saved record for %s', $modelToSave));
- }
- break;
- case (preg_match("/^(\w+) columns/", $command, $tmp) == true):
- $modelToCheck = strip_tags(str_replace($this->badCommandChars, "", $tmp[1]));
-
- if ($this->_isValidModel($modelToCheck)) {
- // Get the column info for this model
- $fieldsCommand = "\$data = \$this->{$modelToCheck}->getColumnTypes();";
- @eval($fieldsCommand);
-
- if (is_array($data)) {
- foreach ($data as $field => $type) {
- $this->out("\t{$field}: {$type}");
- }
- }
- } else {
- $this->out(__d('cake_console', "Please verify that you selected a valid model"));
- }
- break;
- case (preg_match("/^routes\s+reload/i", $command, $tmp) == true):
- $router = Router::getInstance();
- if (!$this->_loadRoutes()) {
- $this->out(__d('cake_console', "There was an error loading the routes config. Please check that the file exists and is free of parse errors."));
- break;
- }
- $this->out(__d('cake_console', "Routes configuration reloaded, %d routes connected", count($router->routes)));
- break;
- case (preg_match("/^routes\s+show/i", $command, $tmp) == true):
- $router = Router::getInstance();
- $this->out(implode("\n", Set::extract($router->routes, '{n}.0')));
- break;
- case (preg_match("/^route\s+(\(.*\))$/i", $command, $tmp) == true):
- if ($url = eval('return array' . $tmp[1] . ';')) {
- $this->out(Router::url($url));
- }
- break;
- case (preg_match("/^route\s+(.*)/i", $command, $tmp) == true):
- $this->out(var_export(Router::parse($tmp[1]), true));
- break;
- default:
- $this->out(__d('cake_console', "Invalid command"));
- $this->out();
- break;
- }
- $command = '';
- }
- }
-
-/**
- * Tells if the specified model is included in the list of available models
- *
- * @param string $modelToCheck
- * @return boolean true if is an available model, false otherwise
- */
- protected function _isValidModel($modelToCheck) {
- return in_array($modelToCheck, $this->models);
- }
-
-/**
- * Reloads the routes configuration from app/Config/routes.php, and compiles
- * all routes found
- *
- * @return boolean True if config reload was a success, otherwise false
- */
- protected function _loadRoutes() {
- Router::reload();
- extract(Router::getNamedExpressions());
-
- if (!@include APP . 'Config' . DS . 'routes.php') {
- return false;
- }
- CakePlugin::routes();
-
- Router::parse('/');
-
- foreach (array_keys(Router::getNamedExpressions()) as $var) {
- unset(${$var});
- }
-
- foreach (Router::$routes as $route) {
- $route->compile();
- }
- return true;
- }
-
-}
diff --git a/lib/Cake/Console/Command/I18nShell.php b/lib/Cake/Console/Command/I18nShell.php
deleted file mode 100644
index 73e67a26025..00000000000
--- a/lib/Cake/Console/Command/I18nShell.php
+++ /dev/null
@@ -1,121 +0,0 @@
-_welcome();
- if (isset($this->params['datasource'])) {
- $this->dataSource = $this->params['datasource'];
- }
-
- if ($this->command && !in_array($this->command, array('help'))) {
- if (!config('database')) {
- $this->out(__d('cake_console', 'Your database configuration was not found. Take a moment to create one.'), true);
- return $this->DbConfig->execute();
- }
- }
- }
-
-/**
- * Override main() for help message hook
- *
- * @return void
- */
- public function main() {
- $this->out(__d('cake_console', 'I18n Shell '));
- $this->hr();
- $this->out(__d('cake_console', '[E]xtract POT file from sources'));
- $this->out(__d('cake_console', '[I]nitialize i18n database table'));
- $this->out(__d('cake_console', '[H]elp'));
- $this->out(__d('cake_console', '[Q]uit'));
-
- $choice = strtolower($this->in(__d('cake_console', 'What would you like to do?'), array('E', 'I', 'H', 'Q')));
- switch ($choice) {
- case 'e':
- $this->Extract->execute();
- break;
- case 'i':
- $this->initdb();
- break;
- case 'h':
- $this->out($this->OptionParser->help());
- break;
- case 'q':
- exit(0);
- break;
- default:
- $this->out(__d('cake_console', 'You have made an invalid selection. Please choose a command to execute by entering E, I, H, or Q.'));
- }
- $this->hr();
- $this->main();
- }
-
-/**
- * Initialize I18N database.
- *
- * @return void
- */
- public function initdb() {
- $this->dispatchShell('schema create i18n');
- }
-
-/**
- * Get and configure the Option parser
- *
- * @return ConsoleOptionParser
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- return $parser->description(
- __d('cake_console', 'I18n Shell initializes i18n database table for your application and generates .pot files(s) with translations.')
- )->addSubcommand('initdb', array(
- 'help' => __d('cake_console', 'Initialize the i18n table.')
- ))->addSubcommand('extract', array(
- 'help' => __d('cake_console', 'Extract the po translations from your application'),
- 'parser' => $this->Extract->getOptionParser()
- ));
- }
-
-}
diff --git a/lib/Cake/Console/Command/SchemaShell.php b/lib/Cake/Console/Command/SchemaShell.php
deleted file mode 100644
index eb332150096..00000000000
--- a/lib/Cake/Console/Command/SchemaShell.php
+++ /dev/null
@@ -1,533 +0,0 @@
-_welcome();
- $this->out('Cake Schema Shell');
- $this->hr();
-
- $name = $path = $connection = $plugin = null;
- if (!empty($this->params['name'])) {
- $name = $this->params['name'];
- } elseif (!empty($this->args[0]) && $this->args[0] !== 'snapshot') {
- $name = $this->params['name'] = $this->args[0];
- }
-
- if (strpos($name, '.')) {
- list($this->params['plugin'], $splitName) = pluginSplit($name);
- $name = $this->params['name'] = $splitName;
- }
-
- if ($name) {
- $this->params['file'] = Inflector::underscore($name);
- }
-
- if (empty($this->params['file'])) {
- $this->params['file'] = 'schema.php';
- }
- if (strpos($this->params['file'], '.php') === false) {
- $this->params['file'] .= '.php';
- }
- $file = $this->params['file'];
-
- if (!empty($this->params['path'])) {
- $path = $this->params['path'];
- }
-
- if (!empty($this->params['connection'])) {
- $connection = $this->params['connection'];
- }
- if (!empty($this->params['plugin'])) {
- $plugin = $this->params['plugin'];
- if (empty($name)) {
- $name = $plugin;
- }
- }
- $this->Schema = new CakeSchema(compact('name', 'path', 'file', 'connection', 'plugin'));
- }
-
-/**
- * Read and output contents of schema object
- * path to read as second arg
- *
- * @return void
- */
- public function view() {
- $File = new File($this->Schema->path . DS . $this->params['file']);
- if ($File->exists()) {
- $this->out($File->read());
- $this->_stop();
- } else {
- $file = $this->Schema->path . DS . $this->params['file'];
- $this->err(__d('cake_console', 'Schema file (%s) could not be found.', $file));
- $this->_stop();
- }
- }
-
-/**
- * Read database and Write schema object
- * accepts a connection as first arg or path to save as second arg
- *
- * @return void
- */
- public function generate() {
- $this->out(__d('cake_console', 'Generating Schema...'));
- $options = array();
- if ($this->params['force']) {
- $options = array('models' => false);
- }
-
- $snapshot = false;
- if (isset($this->args[0]) && $this->args[0] === 'snapshot') {
- $snapshot = true;
- }
-
- if (!$snapshot && file_exists($this->Schema->path . DS . $this->params['file'])) {
- $snapshot = true;
- $prompt = __d('cake_console', "Schema file exists.\n [O]verwrite\n [S]napshot\n [Q]uit\nWould you like to do?");
- $result = strtolower($this->in($prompt, array('o', 's', 'q'), 's'));
- if ($result === 'q') {
- return $this->_stop();
- }
- if ($result === 'o') {
- $snapshot = false;
- }
- }
-
- $cacheDisable = Configure::read('Cache.disable');
- Configure::write('Cache.disable', true);
-
- $content = $this->Schema->read($options);
- $content['file'] = $this->params['file'];
-
- Configure::write('Cache.disable', $cacheDisable);
-
- if ($snapshot === true) {
- $fileName = rtrim($this->params['file'], '.php');
- $Folder = new Folder($this->Schema->path);
- $result = $Folder->read();
-
- $numToUse = false;
- if (isset($this->params['snapshot'])) {
- $numToUse = $this->params['snapshot'];
- }
-
- $count = 0;
- if (!empty($result[1])) {
- foreach ($result[1] as $file) {
- if (preg_match('/' . preg_quote($fileName) . '(?:[_\d]*)?\.php$/', $file)) {
- $count++;
- }
- }
- }
-
- if ($numToUse !== false) {
- if ($numToUse > $count) {
- $count = $numToUse;
- }
- }
-
- $content['file'] = $fileName . '_' . $count . '.php';
- }
-
- if ($this->Schema->write($content)) {
- $this->out(__d('cake_console', 'Schema file: %s generated', $content['file']));
- $this->_stop();
- } else {
- $this->err(__d('cake_console', 'Schema file: %s generated'));
- $this->_stop();
- }
- }
-
-/**
- * Dump Schema object to sql file
- * Use the `write` param to enable and control SQL file output location.
- * Simply using -write will write the sql file to the same dir as the schema file.
- * If -write contains a full path name the file will be saved there. If -write only
- * contains no DS, that will be used as the file name, in the same dir as the schema file.
- *
- * @return string
- */
- public function dump() {
- $write = false;
- $Schema = $this->Schema->load();
- if (!$Schema) {
- $this->err(__d('cake_console', 'Schema could not be loaded'));
- $this->_stop();
- }
- if (!empty($this->params['write'])) {
- if ($this->params['write'] == 1) {
- $write = Inflector::underscore($this->Schema->name);
- } else {
- $write = $this->params['write'];
- }
- }
- $db = ConnectionManager::getDataSource($this->Schema->connection);
- $contents = "\n\n" . $db->dropSchema($Schema) . "\n\n" . $db->createSchema($Schema);
-
- if ($write) {
- if (strpos($write, '.sql') === false) {
- $write .= '.sql';
- }
- if (strpos($write, DS) !== false) {
- $File = new File($write, true);
- } else {
- $File = new File($this->Schema->path . DS . $write, true);
- }
-
- if ($File->write($contents)) {
- $this->out(__d('cake_console', 'SQL dump file created in %s', $File->pwd()));
- $this->_stop();
- } else {
- $this->err(__d('cake_console', 'SQL dump could not be created'));
- $this->_stop();
- }
- }
- $this->out($contents);
- return $contents;
- }
-
-/**
- * Run database create commands. Alias for run create.
- *
- * @return void
- */
- public function create() {
- list($Schema, $table) = $this->_loadSchema();
- $this->_create($Schema, $table);
- }
-
-/**
- * Run database create commands. Alias for run create.
- *
- * @return void
- */
- public function update() {
- list($Schema, $table) = $this->_loadSchema();
- $this->_update($Schema, $table);
- }
-
-/**
- * Prepares the Schema objects for database operations.
- *
- * @return void
- */
- protected function _loadSchema() {
- $name = $plugin = null;
- if (!empty($this->params['name'])) {
- $name = $this->params['name'];
- }
- if (!empty($this->params['plugin'])) {
- $plugin = $this->params['plugin'];
- }
-
- if (!empty($this->params['dry'])) {
- $this->_dry = true;
- $this->out(__d('cake_console', 'Performing a dry run.'));
- }
-
- $options = array('name' => $name, 'plugin' => $plugin);
- if (!empty($this->params['snapshot'])) {
- $fileName = rtrim($this->Schema->file, '.php');
- $options['file'] = $fileName . '_' . $this->params['snapshot'] . '.php';
- }
-
- $Schema = $this->Schema->load($options);
-
- if (!$Schema) {
- $this->err(__d('cake_console', '%s could not be loaded', $this->Schema->path . DS . $this->Schema->file));
- $this->_stop();
- }
- $table = null;
- if (isset($this->args[1])) {
- $table = $this->args[1];
- }
- return array(&$Schema, $table);
- }
-
-/**
- * Create database from Schema object
- * Should be called via the run method
- *
- * @param CakeSchema $Schema
- * @param string $table
- * @return void
- */
- protected function _create($Schema, $table = null) {
- $db = ConnectionManager::getDataSource($this->Schema->connection);
-
- $drop = $create = array();
-
- if (!$table) {
- foreach ($Schema->tables as $table => $fields) {
- $drop[$table] = $db->dropSchema($Schema, $table);
- $create[$table] = $db->createSchema($Schema, $table);
- }
- } elseif (isset($Schema->tables[$table])) {
- $drop[$table] = $db->dropSchema($Schema, $table);
- $create[$table] = $db->createSchema($Schema, $table);
- }
- if (empty($drop) || empty($create)) {
- $this->out(__d('cake_console', 'Schema is up to date.'));
- $this->_stop();
- }
-
- $this->out("\n" . __d('cake_console', 'The following table(s) will be dropped.'));
- $this->out(array_keys($drop));
-
- if ('y' == $this->in(__d('cake_console', 'Are you sure you want to drop the table(s)?'), array('y', 'n'), 'n')) {
- $this->out(__d('cake_console', 'Dropping table(s).'));
- $this->_run($drop, 'drop', $Schema);
- }
-
- $this->out("\n" . __d('cake_console', 'The following table(s) will be created.'));
- $this->out(array_keys($create));
-
- if ('y' == $this->in(__d('cake_console', 'Are you sure you want to create the table(s)?'), array('y', 'n'), 'y')) {
- $this->out(__d('cake_console', 'Creating table(s).'));
- $this->_run($create, 'create', $Schema);
- }
- $this->out(__d('cake_console', 'End create.'));
- }
-
-/**
- * Update database with Schema object
- * Should be called via the run method
- *
- * @param CakeSchema $Schema
- * @param string $table
- * @return void
- */
- protected function _update(&$Schema, $table = null) {
- $db = ConnectionManager::getDataSource($this->Schema->connection);
-
- $this->out(__d('cake_console', 'Comparing Database to Schema...'));
- $options = array();
- if (isset($this->params['force'])) {
- $options['models'] = false;
- }
- $Old = $this->Schema->read($options);
- $compare = $this->Schema->compare($Old, $Schema);
-
- $contents = array();
-
- if (empty($table)) {
- foreach ($compare as $table => $changes) {
- $contents[$table] = $db->alterSchema(array($table => $changes), $table);
- }
- } elseif (isset($compare[$table])) {
- $contents[$table] = $db->alterSchema(array($table => $compare[$table]), $table);
- }
-
- if (empty($contents)) {
- $this->out(__d('cake_console', 'Schema is up to date.'));
- $this->_stop();
- }
-
- $this->out("\n" . __d('cake_console', 'The following statements will run.'));
- $this->out(array_map('trim', $contents));
- if ('y' == $this->in(__d('cake_console', 'Are you sure you want to alter the tables?'), array('y', 'n'), 'n')) {
- $this->out();
- $this->out(__d('cake_console', 'Updating Database...'));
- $this->_run($contents, 'update', $Schema);
- }
-
- $this->out(__d('cake_console', 'End update.'));
- }
-
-/**
- * Runs sql from _create() or _update()
- *
- * @param array $contents
- * @param string $event
- * @param CakeSchema $Schema
- * @return void
- */
- protected function _run($contents, $event, &$Schema) {
- if (empty($contents)) {
- $this->err(__d('cake_console', 'Sql could not be run'));
- return;
- }
- Configure::write('debug', 2);
- $db = ConnectionManager::getDataSource($this->Schema->connection);
-
- foreach ($contents as $table => $sql) {
- if (empty($sql)) {
- $this->out(__d('cake_console', '%s is up to date.', $table));
- } else {
- if ($this->_dry === true) {
- $this->out(__d('cake_console', 'Dry run for %s :', $table));
- $this->out($sql);
- } else {
- if (!$Schema->before(array($event => $table))) {
- return false;
- }
- $error = null;
- try {
- $db->execute($sql);
- } catch (PDOException $e) {
- $error = $table . ': ' . $e->getMessage();
- }
-
- $Schema->after(array($event => $table, 'errors' => $error));
-
- if (!empty($error)) {
- $this->err($error);
- } else {
- $this->out(__d('cake_console', '%s updated.', $table));
- }
- }
- }
- }
- }
-
-/**
- * get the option parser
- *
- * @return void
- */
- public function getOptionParser() {
- $plugin = array(
- 'short' => 'p',
- 'help' => __d('cake_console', 'The plugin to use.'),
- );
- $connection = array(
- 'short' => 'c',
- 'help' => __d('cake_console', 'Set the db config to use.'),
- 'default' => 'default'
- );
- $path = array(
- 'help' => __d('cake_console', 'Path to read and write schema.php'),
- 'default' => APP . 'Config' . DS . 'Schema'
- );
- $file = array(
- 'help' => __d('cake_console', 'File name to read and write.'),
- 'default' => 'schema.php'
- );
- $name = array(
- 'help' => __d('cake_console', 'Classname to use. If its Plugin.class, both name and plugin options will be set.')
- );
- $snapshot = array(
- 'short' => 's',
- 'help' => __d('cake_console', 'Snapshot number to use/make.')
- );
- $dry = array(
- 'help' => __d('cake_console', 'Perform a dry run on create and update commands. Queries will be output instead of run.'),
- 'boolean' => true
- );
- $force = array(
- 'short' => 'f',
- 'help' => __d('cake_console', 'Force "generate" to create a new schema'),
- 'boolean' => true
- );
- $write = array(
- 'help' => __d('cake_console', 'Write the dumped SQL to a file.')
- );
-
- $parser = parent::getOptionParser();
- $parser->description(
- __d('cake_console', 'The Schema Shell generates a schema object from the database and updates the database from the schema.')
- )->addSubcommand('view', array(
- 'help' => __d('cake_console', 'Read and output the contents of a schema file'),
- 'parser' => array(
- 'options' => compact('plugin', 'path', 'file', 'name', 'connection'),
- 'arguments' => compact('name')
- )
- ))->addSubcommand('generate', array(
- 'help' => __d('cake_console', 'Reads from --connection and writes to --path. Generate snapshots with -s'),
- 'parser' => array(
- 'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'snapshot', 'force'),
- 'arguments' => array(
- 'snapshot' => array('help' => __d('cake_console', 'Generate a snapshot.'))
- )
- )
- ))->addSubcommand('dump', array(
- 'help' => __d('cake_console', 'Dump database SQL based on a schema file to stdout.'),
- 'parser' => array(
- 'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'write'),
- 'arguments' => compact('name')
- )
- ))->addSubcommand('create', array(
- 'help' => __d('cake_console', 'Drop and create tables based on the schema file.'),
- 'parser' => array(
- 'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'dry', 'snapshot'),
- 'args' => array(
- 'name' => array(
- 'help' => __d('cake_console', 'Name of schema to use.')
- ),
- 'table' => array(
- 'help' => __d('cake_console', 'Only create the specified table.')
- )
- )
- )
- ))->addSubcommand('update', array(
- 'help' => __d('cake_console', 'Alter the tables based on the schema file.'),
- 'parser' => array(
- 'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'dry', 'snapshot', 'force'),
- 'args' => array(
- 'name' => array(
- 'help' => __d('cake_console', 'Name of schema to use.')
- ),
- 'table' => array(
- 'help' => __d('cake_console', 'Only create the specified table.')
- )
- )
- )
- ));
- return $parser;
- }
-
-}
diff --git a/lib/Cake/Console/Command/Task/BakeTask.php b/lib/Cake/Console/Command/Task/BakeTask.php
deleted file mode 100644
index e32e2539e38..00000000000
--- a/lib/Cake/Console/Command/Task/BakeTask.php
+++ /dev/null
@@ -1,93 +0,0 @@
-path;
- if (isset($this->plugin)) {
- $path = $this->_pluginPath($this->plugin) . $this->name . DS;
- }
- return $path;
- }
-
-/**
- * Base execute method parses some parameters and sets some properties on the bake tasks.
- * call when overriding execute()
- *
- * @return void
- */
- public function execute() {
- foreach ($this->args as $i => $arg) {
- if (strpos($arg, '.')) {
- list($this->params['plugin'], $this->args[$i]) = pluginSplit($arg);
- break;
- }
- }
- if (isset($this->params['plugin'])) {
- $this->plugin = $this->params['plugin'];
- }
- }
-
-}
diff --git a/lib/Cake/Console/Command/Task/ControllerTask.php b/lib/Cake/Console/Command/Task/ControllerTask.php
deleted file mode 100644
index ca68389adfa..00000000000
--- a/lib/Cake/Console/Command/Task/ControllerTask.php
+++ /dev/null
@@ -1,470 +0,0 @@
-path = current(App::path('Controller'));
- }
-
-/**
- * Execution method always used for tasks
- *
- * @return void
- */
- public function execute() {
- parent::execute();
- if (empty($this->args)) {
- return $this->_interactive();
- }
-
- if (isset($this->args[0])) {
- if (!isset($this->connection)) {
- $this->connection = 'default';
- }
- if (strtolower($this->args[0]) == 'all') {
- return $this->all();
- }
-
- $controller = $this->_controllerName($this->args[0]);
- $actions = '';
-
- if (!empty($this->params['public'])) {
- $this->out(__d('cake_console', 'Baking basic crud methods for ') . $controller);
- $actions .= $this->bakeActions($controller);
- }
- if (!empty($this->params['admin'])) {
- $admin = $this->Project->getPrefix();
- if ($admin) {
- $this->out(__d('cake_console', 'Adding %s methods', $admin));
- $actions .= "\n" . $this->bakeActions($controller, $admin);
- }
- }
- if (empty($actions)) {
- $actions = 'scaffold';
- }
-
- if ($this->bake($controller, $actions)) {
- if ($this->_checkUnitTest()) {
- $this->bakeTest($controller);
- }
- }
- }
- }
-
-/**
- * Bake All the controllers at once. Will only bake controllers for models that exist.
- *
- * @return void
- */
- public function all() {
- $this->interactive = false;
- $this->listAll($this->connection, false);
- ClassRegistry::config('Model', array('ds' => $this->connection));
- $unitTestExists = $this->_checkUnitTest();
- foreach ($this->__tables as $table) {
- $model = $this->_modelName($table);
- $controller = $this->_controllerName($model);
- App::uses($model, 'Model');
- if (class_exists($model)) {
- $actions = $this->bakeActions($controller);
- if ($this->bake($controller, $actions) && $unitTestExists) {
- $this->bakeTest($controller);
- }
- }
- }
- }
-
-/**
- * Interactive
- *
- * @return void
- */
- protected function _interactive() {
- $this->interactive = true;
- $this->hr();
- $this->out(__d('cake_console', "Bake Controller\nPath: %s", $this->getPath()));
- $this->hr();
-
- if (empty($this->connection)) {
- $this->connection = $this->DbConfig->getConfig();
- }
-
- $controllerName = $this->getName();
- $this->hr();
- $this->out(__d('cake_console', 'Baking %sController', $controllerName));
- $this->hr();
-
- $helpers = $components = array();
- $actions = '';
- $wannaUseSession = 'y';
- $wannaBakeAdminCrud = 'n';
- $useDynamicScaffold = 'n';
- $wannaBakeCrud = 'y';
-
- $question[] = __d('cake_console', "Would you like to build your controller interactively?");
- if (file_exists($this->path . $controllerName . 'Controller.php')) {
- $question[] = __d('cake_console', "Warning: Choosing no will overwrite the %sController.", $controllerName);
- }
- $doItInteractive = $this->in(implode("\n", $question), array('y', 'n'), 'y');
-
- if (strtolower($doItInteractive) == 'y') {
- $this->interactive = true;
- $useDynamicScaffold = $this->in(
- __d('cake_console', "Would you like to use dynamic scaffolding?"), array('y', 'n'), 'n'
- );
-
- if (strtolower($useDynamicScaffold) == 'y') {
- $wannaBakeCrud = 'n';
- $actions = 'scaffold';
- } else {
- list($wannaBakeCrud, $wannaBakeAdminCrud) = $this->_askAboutMethods();
-
- $helpers = $this->doHelpers();
- $components = $this->doComponents();
-
- $wannaUseSession = $this->in(
- __d('cake_console', "Would you like to use Session flash messages?"), array('y','n'), 'y'
- );
- }
- } else {
- list($wannaBakeCrud, $wannaBakeAdminCrud) = $this->_askAboutMethods();
- }
-
- if (strtolower($wannaBakeCrud) == 'y') {
- $actions = $this->bakeActions($controllerName, null, strtolower($wannaUseSession) == 'y');
- }
- if (strtolower($wannaBakeAdminCrud) == 'y') {
- $admin = $this->Project->getPrefix();
- $actions .= $this->bakeActions($controllerName, $admin, strtolower($wannaUseSession) == 'y');
- }
-
- $baked = false;
- if ($this->interactive === true) {
- $this->confirmController($controllerName, $useDynamicScaffold, $helpers, $components);
- $looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y','n'), 'y');
-
- if (strtolower($looksGood) == 'y') {
- $baked = $this->bake($controllerName, $actions, $helpers, $components);
- if ($baked && $this->_checkUnitTest()) {
- $this->bakeTest($controllerName);
- }
- }
- } else {
- $baked = $this->bake($controllerName, $actions, $helpers, $components);
- if ($baked && $this->_checkUnitTest()) {
- $this->bakeTest($controllerName);
- }
- }
- return $baked;
- }
-
-/**
- * Confirm a to be baked controller with the user
- *
- * @param string $controllerName
- * @param string $useDynamicScaffold
- * @param array $helpers
- * @param array $components
- * @return void
- */
- public function confirmController($controllerName, $useDynamicScaffold, $helpers, $components) {
- $this->out();
- $this->hr();
- $this->out(__d('cake_console', 'The following controller will be created:'));
- $this->hr();
- $this->out(__d('cake_console', "Controller Name:\n\t%s", $controllerName));
-
- if (strtolower($useDynamicScaffold) == 'y') {
- $this->out("public \$scaffold;");
- }
-
- $properties = array(
- 'helpers' => __d('cake_console', 'Helpers:'),
- 'components' => __d('cake_console', 'Components:'),
- );
-
- foreach ($properties as $var => $title) {
- if (count($$var)) {
- $output = '';
- $length = count($$var);
- foreach ($$var as $i => $propElement) {
- if ($i != $length - 1) {
- $output .= ucfirst($propElement) . ', ';
- } else {
- $output .= ucfirst($propElement);
- }
- }
- $this->out($title . "\n\t" . $output);
- }
- }
- $this->hr();
- }
-
-/**
- * Interact with the user and ask about which methods (admin or regular they want to bake)
- *
- * @return array Array containing (bakeRegular, bakeAdmin) answers
- */
- protected function _askAboutMethods() {
- $wannaBakeCrud = $this->in(
- __d('cake_console', "Would you like to create some basic class methods \n(index(), add(), view(), edit())?"),
- array('y','n'), 'n'
- );
- $wannaBakeAdminCrud = $this->in(
- __d('cake_console', "Would you like to create the basic class methods for admin routing?"),
- array('y','n'), 'n'
- );
- return array($wannaBakeCrud, $wannaBakeAdminCrud);
- }
-
-/**
- * Bake scaffold actions
- *
- * @param string $controllerName Controller name
- * @param string $admin Admin route to use
- * @param boolean $wannaUseSession Set to true to use sessions, false otherwise
- * @return string Baked actions
- */
- public function bakeActions($controllerName, $admin = null, $wannaUseSession = true) {
- $currentModelName = $modelImport = $this->_modelName($controllerName);
- $plugin = $this->plugin;
- if ($plugin) {
- $plugin .= '.';
- }
- App::uses($modelImport, $plugin . 'Model');
- if (!class_exists($modelImport)) {
- $this->err(__d('cake_console', 'You must have a model for this class to build basic methods. Please try again.'));
- $this->_stop();
- }
-
- $modelObj = ClassRegistry::init($currentModelName);
- $controllerPath = $this->_controllerPath($controllerName);
- $pluralName = $this->_pluralName($currentModelName);
- $singularName = Inflector::variable($currentModelName);
- $singularHumanName = $this->_singularHumanName($controllerName);
- $pluralHumanName = $this->_pluralName($controllerName);
- $displayField = $modelObj->displayField;
- $primaryKey = $modelObj->primaryKey;
-
- $this->Template->set(compact(
- 'plugin', 'admin', 'controllerPath', 'pluralName', 'singularName',
- 'singularHumanName', 'pluralHumanName', 'modelObj', 'wannaUseSession', 'currentModelName',
- 'displayField', 'primaryKey'
- ));
- $actions = $this->Template->generate('actions', 'controller_actions');
- return $actions;
- }
-
-/**
- * Assembles and writes a Controller file
- *
- * @param string $controllerName Controller name already pluralized and correctly cased.
- * @param string $actions Actions to add, or set the whole controller to use $scaffold (set $actions to 'scaffold')
- * @param array $helpers Helpers to use in controller
- * @param array $components Components to use in controller
- * @return string Baked controller
- */
- public function bake($controllerName, $actions = '', $helpers = null, $components = null) {
- $this->out("\n" . __d('cake_console', 'Baking controller class for %s...', $controllerName), 1, Shell::QUIET);
-
- $isScaffold = ($actions === 'scaffold') ? true : false;
-
- $this->Template->set(array(
- 'plugin' => $this->plugin,
- 'pluginPath' => empty($this->plugin) ? '' : $this->plugin . '.'
- ));
- $this->Template->set(compact('controllerName', 'actions', 'helpers', 'components', 'isScaffold'));
- $contents = $this->Template->generate('classes', 'controller');
-
- $path = $this->getPath();
- $filename = $path . $controllerName . 'Controller.php';
- if ($this->createFile($filename, $contents)) {
- return $contents;
- }
- return false;
- }
-
-/**
- * Assembles and writes a unit test file
- *
- * @param string $className Controller class name
- * @return string Baked test
- */
- public function bakeTest($className) {
- $this->Test->plugin = $this->plugin;
- $this->Test->connection = $this->connection;
- $this->Test->interactive = $this->interactive;
- return $this->Test->bake('Controller', $className);
- }
-
-/**
- * Interact with the user and get a list of additional helpers
- *
- * @return array Helpers that the user wants to use.
- */
- public function doHelpers() {
- return $this->_doPropertyChoices(
- __d('cake_console', "Would you like this controller to use other helpers\nbesides HtmlHelper and FormHelper?"),
- __d('cake_console', "Please provide a comma separated list of the other\nhelper names you'd like to use.\nExample: 'Ajax, Javascript, Time'")
- );
- }
-
-/**
- * Interact with the user and get a list of additional components
- *
- * @return array Components the user wants to use.
- */
- public function doComponents() {
- return $this->_doPropertyChoices(
- __d('cake_console', "Would you like this controller to use any components?"),
- __d('cake_console', "Please provide a comma separated list of the component names you'd like to use.\nExample: 'Acl, Security, RequestHandler'")
- );
- }
-
-/**
- * Common code for property choice handling.
- *
- * @param string $prompt A yes/no question to precede the list
- * @param string $example A question for a comma separated list, with examples.
- * @return array Array of values for property.
- */
- protected function _doPropertyChoices($prompt, $example) {
- $proceed = $this->in($prompt, array('y','n'), 'n');
- $property = array();
- if (strtolower($proceed) == 'y') {
- $propertyList = $this->in($example);
- $propertyListTrimmed = str_replace(' ', '', $propertyList);
- $property = explode(',', $propertyListTrimmed);
- }
- return array_filter($property);
- }
-
-/**
- * Outputs and gets the list of possible controllers from database
- *
- * @param string $useDbConfig Database configuration name
- * @return array Set of controllers
- */
- public function listAll($useDbConfig = null) {
- if (is_null($useDbConfig)) {
- $useDbConfig = $this->connection;
- }
- $this->__tables = $this->Model->getAllTables($useDbConfig);
-
- if ($this->interactive == true) {
- $this->out(__d('cake_console', 'Possible Controllers based on your current database:'));
- $this->_controllerNames = array();
- $count = count($this->__tables);
- for ($i = 0; $i < $count; $i++) {
- $this->_controllerNames[] = $this->_controllerName($this->_modelName($this->__tables[$i]));
- $this->out($i + 1 . ". " . $this->_controllerNames[$i]);
- }
- return $this->_controllerNames;
- }
- return $this->__tables;
- }
-
-/**
- * Forces the user to specify the controller he wants to bake, and returns the selected controller name.
- *
- * @param string $useDbConfig Connection name to get a controller name for.
- * @return string Controller name
- */
- public function getName($useDbConfig = null) {
- $controllers = $this->listAll($useDbConfig);
- $enteredController = '';
-
- while ($enteredController == '') {
- $enteredController = $this->in(__d('cake_console', "Enter a number from the list above,\ntype in the name of another controller, or 'q' to exit"), null, 'q');
- if ($enteredController === 'q') {
- $this->out(__d('cake_console', 'Exit'));
- return $this->_stop();
- }
-
- if ($enteredController == '' || intval($enteredController) > count($controllers)) {
- $this->err(__d('cake_console', "The Controller name you supplied was empty,\nor the number you selected was not an option. Please try again."));
- $enteredController = '';
- }
- }
-
- if (intval($enteredController) > 0 && intval($enteredController) <= count($controllers) ) {
- $controllerName = $controllers[intval($enteredController) - 1];
- } else {
- $controllerName = Inflector::camelize($enteredController);
- }
- return $controllerName;
- }
-
-/**
- * get the option parser.
- *
- * @return void
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- return $parser->description(
- __d('cake_console', 'Bake a controller for a model. Using options you can bake public, admin or both.')
- )->addArgument('name', array(
- 'help' => __d('cake_console', 'Name of the controller to bake. Can use Plugin.name to bake controllers into plugins.')
- ))->addOption('public', array(
- 'help' => __d('cake_console', 'Bake a controller with basic crud actions (index, view, add, edit, delete).'),
- 'boolean' => true
- ))->addOption('admin', array(
- 'help' => __d('cake_console', 'Bake a controller with crud actions for one of the Routing.prefixes.'),
- 'boolean' => true
- ))->addOption('plugin', array(
- 'short' => 'p',
- 'help' => __d('cake_console', 'Plugin to bake the controller into.')
- ))->addOption('connection', array(
- 'short' => 'c',
- 'help' => __d('cake_console', 'The connection the controller\'s model is on.')
- ))->addSubcommand('all', array(
- 'help' => __d('cake_console', 'Bake all controllers with CRUD methods.')
- ))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.'));
- }
-
-}
diff --git a/lib/Cake/Console/Command/Task/DbConfigTask.php b/lib/Cake/Console/Command/Task/DbConfigTask.php
deleted file mode 100644
index 0bf28ff9659..00000000000
--- a/lib/Cake/Console/Command/Task/DbConfigTask.php
+++ /dev/null
@@ -1,384 +0,0 @@
- 'default',
- 'datasource' => 'Database/Mysql',
- 'persistent' => 'false',
- 'host' => 'localhost',
- 'login' => 'root',
- 'password' => 'password',
- 'database' => 'project_name',
- 'schema' => null,
- 'prefix' => null,
- 'encoding' => null,
- 'port' => null
- );
-
-/**
- * String name of the database config class name.
- * Used for testing.
- *
- * @var string
- */
- public $databaseClassName = 'DATABASE_CONFIG';
-
-/**
- * initialization callback
- *
- * @return void
- */
- public function initialize() {
- $this->path = APP . 'Config' . DS;
- }
-
-/**
- * Execution method always used for tasks
- *
- * @return void
- */
- public function execute() {
- if (empty($this->args)) {
- $this->_interactive();
- $this->_stop();
- }
- }
-
-/**
- * Interactive interface
- *
- * @return void
- */
- protected function _interactive() {
- $this->hr();
- $this->out(__d('cake_console', 'Database Configuration:'));
- $this->hr();
- $done = false;
- $dbConfigs = array();
-
- while ($done == false) {
- $name = '';
-
- while ($name == '') {
- $name = $this->in(__d('cake_console', "Name:"), null, 'default');
- if (preg_match('/[^a-z0-9_]/i', $name)) {
- $name = '';
- $this->out(__d('cake_console', 'The name may only contain unaccented latin characters, numbers or underscores'));
- } elseif (preg_match('/^[^a-z_]/i', $name)) {
- $name = '';
- $this->out(__d('cake_console', 'The name must start with an unaccented latin character or an underscore'));
- }
- }
-
- $datasource = $this->in(__d('cake_console', 'Datasource:'), array('Mysql', 'Postgres', 'Sqlite', 'Sqlserver'), 'Mysql');
-
- $persistent = $this->in(__d('cake_console', 'Persistent Connection?'), array('y', 'n'), 'n');
- if (strtolower($persistent) == 'n') {
- $persistent = 'false';
- } else {
- $persistent = 'true';
- }
-
- $host = '';
- while ($host == '') {
- $host = $this->in(__d('cake_console', 'Database Host:'), null, 'localhost');
- }
-
- $port = '';
- while ($port == '') {
- $port = $this->in(__d('cake_console', 'Port?'), null, 'n');
- }
-
- if (strtolower($port) == 'n') {
- $port = null;
- }
-
- $login = '';
- while ($login == '') {
- $login = $this->in(__d('cake_console', 'User:'), null, 'root');
- }
- $password = '';
- $blankPassword = false;
-
- while ($password == '' && $blankPassword == false) {
- $password = $this->in(__d('cake_console', 'Password:'));
-
- if ($password == '') {
- $blank = $this->in(__d('cake_console', 'The password you supplied was empty. Use an empty password?'), array('y', 'n'), 'n');
- if ($blank == 'y') {
- $blankPassword = true;
- }
- }
- }
-
- $database = '';
- while ($database == '') {
- $database = $this->in(__d('cake_console', 'Database Name:'), null, 'cake');
- }
-
- $prefix = '';
- while ($prefix == '') {
- $prefix = $this->in(__d('cake_console', 'Table Prefix?'), null, 'n');
- }
- if (strtolower($prefix) == 'n') {
- $prefix = null;
- }
-
- $encoding = '';
- while ($encoding == '') {
- $encoding = $this->in(__d('cake_console', 'Table encoding?'), null, 'n');
- }
- if (strtolower($encoding) == 'n') {
- $encoding = null;
- }
-
- $schema = '';
- if ($datasource == 'postgres') {
- while ($schema == '') {
- $schema = $this->in(__d('cake_console', 'Table schema?'), null, 'n');
- }
- }
- if (strtolower($schema) == 'n') {
- $schema = null;
- }
-
- $config = compact('name', 'datasource', 'persistent', 'host', 'login', 'password', 'database', 'prefix', 'encoding', 'port', 'schema');
-
- while ($this->_verify($config) == false) {
- $this->_interactive();
- }
-
- $dbConfigs[] = $config;
- $doneYet = $this->in(__d('cake_console', 'Do you wish to add another database configuration?'), null, 'n');
-
- if (strtolower($doneYet == 'n')) {
- $done = true;
- }
- }
-
- $this->bake($dbConfigs);
- config('database');
- return true;
- }
-
-/**
- * Output verification message and bake if it looks good
- *
- * @param array $config
- * @return boolean True if user says it looks good, false otherwise
- */
- protected function _verify($config) {
- $config = array_merge($this->_defaultConfig, $config);
- extract($config);
- $this->out();
- $this->hr();
- $this->out(__d('cake_console', 'The following database configuration will be created:'));
- $this->hr();
- $this->out(__d('cake_console', "Name: %s", $name));
- $this->out(__d('cake_console', "Datasource: %s", $datasource));
- $this->out(__d('cake_console', "Persistent: %s", $persistent));
- $this->out(__d('cake_console', "Host: %s", $host));
-
- if ($port) {
- $this->out(__d('cake_console', "Port: %s", $port));
- }
-
- $this->out(__d('cake_console', "User: %s", $login));
- $this->out(__d('cake_console', "Pass: %s", str_repeat('*', strlen($password))));
- $this->out(__d('cake_console', "Database: %s", $database));
-
- if ($prefix) {
- $this->out(__d('cake_console', "Table prefix: %s", $prefix));
- }
-
- if ($schema) {
- $this->out(__d('cake_console', "Schema: %s", $schema));
- }
-
- if ($encoding) {
- $this->out(__d('cake_console', "Encoding: %s", $encoding));
- }
-
- $this->hr();
- $looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n'), 'y');
-
- if (strtolower($looksGood) == 'y') {
- return $config;
- }
- return false;
- }
-
-/**
- * Assembles and writes database.php
- *
- * @param array $configs Configuration settings to use
- * @return boolean Success
- */
- public function bake($configs) {
- if (!is_dir($this->path)) {
- $this->err(__d('cake_console', '%s not found', $this->path));
- return false;
- }
-
- $filename = $this->path . 'database.php';
- $oldConfigs = array();
-
- if (file_exists($filename)) {
- config('database');
- $db = new $this->databaseClassName;
- $temp = get_class_vars(get_class($db));
-
- foreach ($temp as $configName => $info) {
- $info = array_merge($this->_defaultConfig, $info);
-
- if (!isset($info['schema'])) {
- $info['schema'] = null;
- }
- if (!isset($info['encoding'])) {
- $info['encoding'] = null;
- }
- if (!isset($info['port'])) {
- $info['port'] = null;
- }
-
- if ($info['persistent'] === false) {
- $info['persistent'] = 'false';
- } else {
- $info['persistent'] = ($info['persistent'] == true) ? 'true' : 'false';
- }
-
- $oldConfigs[] = array(
- 'name' => $configName,
- 'datasource' => $info['datasource'],
- 'persistent' => $info['persistent'],
- 'host' => $info['host'],
- 'port' => $info['port'],
- 'login' => $info['login'],
- 'password' => $info['password'],
- 'database' => $info['database'],
- 'prefix' => $info['prefix'],
- 'schema' => $info['schema'],
- 'encoding' => $info['encoding']
- );
- }
- }
-
- foreach ($oldConfigs as $key => $oldConfig) {
- foreach ($configs as $key1 => $config) {
- if ($oldConfig['name'] == $config['name']) {
- unset($oldConfigs[$key]);
- }
- }
- }
-
- $configs = array_merge($oldConfigs, $configs);
- $out = "_defaultConfig, $config);
- extract($config);
-
- $out .= "\tpublic \${$name} = array(\n";
- $out .= "\t\t'datasource' => 'Database/{$datasource}',\n";
- $out .= "\t\t'persistent' => {$persistent},\n";
- $out .= "\t\t'host' => '{$host}',\n";
-
- if ($port) {
- $out .= "\t\t'port' => {$port},\n";
- }
-
- $out .= "\t\t'login' => '{$login}',\n";
- $out .= "\t\t'password' => '{$password}',\n";
- $out .= "\t\t'database' => '{$database}',\n";
-
- if ($schema) {
- $out .= "\t\t'schema' => '{$schema}',\n";
- }
-
- if ($prefix) {
- $out .= "\t\t'prefix' => '{$prefix}',\n";
- }
-
- if ($encoding) {
- $out .= "\t\t'encoding' => '{$encoding}'\n";
- }
-
- $out .= "\t);\n";
- }
-
- $out .= "}\n";
- $filename = $this->path . 'database.php';
- return $this->createFile($filename, $out);
- }
-
-/**
- * Get a user specified Connection name
- *
- * @return void
- */
- public function getConfig() {
- App::uses('ConnectionManager', 'Model');
- $configs = ConnectionManager::enumConnectionObjects();
-
- $useDbConfig = key($configs);
- if (!is_array($configs) || empty($configs)) {
- return $this->execute();
- }
- $connections = array_keys($configs);
-
- if (count($connections) > 1) {
- $useDbConfig = $this->in(__d('cake_console', 'Use Database Config') . ':', $connections, $useDbConfig);
- }
- return $useDbConfig;
- }
-
-/**
- * get the option parser
- *
- * @return ConsoleOptionParser
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- return $parser->description(
- __d('cake_console', 'Bake new database configuration settings.')
- );
- }
-
-}
diff --git a/lib/Cake/Console/Command/Task/ExtractTask.php b/lib/Cake/Console/Command/Task/ExtractTask.php
deleted file mode 100644
index 64aad3b032f..00000000000
--- a/lib/Cake/Console/Command/Task/ExtractTask.php
+++ /dev/null
@@ -1,700 +0,0 @@
-params['exclude'])) {
- $this->_exclude = explode(',', $this->params['exclude']);
- }
- if (isset($this->params['files']) && !is_array($this->params['files'])) {
- $this->_files = explode(',', $this->params['files']);
- }
- if (isset($this->params['paths'])) {
- $this->_paths = explode(',', $this->params['paths']);
- } elseif (isset($this->params['plugin'])) {
- $plugin = Inflector::camelize($this->params['plugin']);
- if (!CakePlugin::loaded($plugin)) {
- CakePlugin::load($plugin);
- }
- $this->_paths = array(CakePlugin::path($plugin));
- $this->params['plugin'] = $plugin;
- } else {
- $defaultPath = APP;
- $message = __d('cake_console', "What is the path you would like to extract?\n[Q]uit [D]one");
- while (true) {
- $response = $this->in($message, null, $defaultPath);
- if (strtoupper($response) === 'Q') {
- $this->out(__d('cake_console', 'Extract Aborted'));
- $this->_stop();
- } elseif (strtoupper($response) === 'D') {
- $this->out();
- break;
- } elseif (is_dir($response)) {
- $this->_paths[] = $response;
- $defaultPath = 'D';
- } else {
- $this->err(__d('cake_console', 'The directory path you supplied was not found. Please try again.'));
- }
- $this->out();
- }
- }
-
- if (!empty($this->params['exclude-plugins']) && $this->_isExtractingApp()) {
- $this->_exclude = array_merge($this->_exclude, App::path('plugins'));
- }
-
- if (!empty($this->params['ignore-model-validation']) || (!$this->_isExtractingApp() && empty($plugin))) {
- $this->_extractValidation = false;
- }
- if (!empty($this->params['validation-domain'])) {
- $this->_validationDomain = $this->params['validation-domain'];
- }
-
- if (isset($this->params['output'])) {
- $this->_output = $this->params['output'];
- } elseif (isset($this->params['plugin'])) {
- $this->_output = $this->_paths[0] . DS . 'Locale';
- } else {
- $message = __d('cake_console', "What is the path you would like to output?\n[Q]uit", $this->_paths[0] . DS . 'Locale');
- while (true) {
- $response = $this->in($message, null, rtrim($this->_paths[0], DS) . DS . 'Locale');
- if (strtoupper($response) === 'Q') {
- $this->out(__d('cake_console', 'Extract Aborted'));
- $this->_stop();
- } elseif (is_dir($response)) {
- $this->_output = $response . DS;
- break;
- } else {
- $this->err(__d('cake_console', 'The directory path you supplied was not found. Please try again.'));
- }
- $this->out();
- }
- }
-
- if (isset($this->params['merge'])) {
- $this->_merge = !(strtolower($this->params['merge']) === 'no');
- } else {
- $this->out();
- $response = $this->in(__d('cake_console', 'Would you like to merge all domains strings into the default.pot file?'), array('y', 'n'), 'n');
- $this->_merge = strtolower($response) === 'y';
- }
-
- if (empty($this->_files)) {
- $this->_searchFiles();
- }
- $this->_output = rtrim($this->_output, DS) . DS;
- $this->_extract();
- }
-
-/**
- * Add a translation to the internal translations property
- *
- * Takes care of duplicate translations
- *
- * @param string $domain
- * @param string $msgid
- * @param array $details
- */
- protected function _addTranslation($domain, $msgid, $details = array()) {
- if (empty($this->_translations[$domain][$msgid])) {
- $this->_translations[$domain][$msgid] = array(
- 'msgid_plural' => false
- );
- }
-
- if (isset($details['msgid_plural'])) {
- $this->_translations[$domain][$msgid]['msgid_plural'] = $details['msgid_plural'];
- }
-
- if (isset($details['file'])) {
- $line = 0;
- if (isset($details['line'])) {
- $line = $details['line'];
- }
- $this->_translations[$domain][$msgid]['references'][$details['file']][] = $line;
- }
- }
-
-/**
- * Extract text
- *
- * @return void
- */
- protected function _extract() {
- $this->out();
- $this->out();
- $this->out(__d('cake_console', 'Extracting...'));
- $this->hr();
- $this->out(__d('cake_console', 'Paths:'));
- foreach ($this->_paths as $path) {
- $this->out(' ' . $path);
- }
- $this->out(__d('cake_console', 'Output Directory: ') . $this->_output);
- $this->hr();
- $this->_extractTokens();
- $this->_extractValidationMessages();
- $this->_buildFiles();
- $this->_writeFiles();
- $this->_paths = $this->_files = $this->_storage = array();
- $this->_translations = $this->_tokens = array();
- $this->_extractValidation = true;
- $this->out();
- $this->out(__d('cake_console', 'Done.'));
- }
-
-/**
- * Get & configure the option parser
- *
- * @return void
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- return $parser->description(__d('cake_console', 'CakePHP Language String Extraction:'))
- ->addOption('app', array('help' => __d('cake_console', 'Directory where your application is located.')))
- ->addOption('paths', array('help' => __d('cake_console', 'Comma separated list of paths.')))
- ->addOption('merge', array(
- 'help' => __d('cake_console', 'Merge all domain strings into the default.po file.'),
- 'choices' => array('yes', 'no')
- ))
- ->addOption('output', array('help' => __d('cake_console', 'Full path to output directory.')))
- ->addOption('files', array('help' => __d('cake_console', 'Comma separated list of files.')))
- ->addOption('exclude-plugins', array(
- 'boolean' => true,
- 'default' => true,
- 'help' => __d('cake_console', 'Ignores all files in plugins if this command is run inside from the same app directory.')
- ))
- ->addOption('plugin', array(
- 'help' => __d('cake_console', 'Extracts tokens only from the plugin specified and puts the result in the plugin\'s Locale directory.')
- ))
- ->addOption('ignore-model-validation', array(
- 'boolean' => true,
- 'default' => false,
- 'help' => __d('cake_console', 'Ignores validation messages in the $validate property.' .
- ' If this flag is not set and the command is run from the same app directory,' .
- ' all messages in model validation rules will be extracted as tokens.')
- ))
- ->addOption('validation-domain', array(
- 'help' => __d('cake_console', 'If set to a value, the localization domain to be used for model validation messages.')
- ))
- ->addOption('exclude', array(
- 'help' => __d('cake_console', 'Comma separated list of directories to exclude.' .
- ' Any path containing a path segment with the provided values will be skipped. E.g. test,vendors')
- ));
- }
-
-/**
- * Extract tokens out of all files to be processed
- *
- * @return void
- */
- protected function _extractTokens() {
- foreach ($this->_files as $file) {
- $this->_file = $file;
- $this->out(__d('cake_console', 'Processing %s...', $file));
-
- $code = file_get_contents($file);
- $allTokens = token_get_all($code);
-
- $this->_tokens = array();
- foreach ($allTokens as $token) {
- if (!is_array($token) || ($token[0] != T_WHITESPACE && $token[0] != T_INLINE_HTML)) {
- $this->_tokens[] = $token;
- }
- }
- unset($allTokens);
- $this->_parse('__', array('singular'));
- $this->_parse('__n', array('singular', 'plural'));
- $this->_parse('__d', array('domain', 'singular'));
- $this->_parse('__c', array('singular'));
- $this->_parse('__dc', array('domain', 'singular'));
- $this->_parse('__dn', array('domain', 'singular', 'plural'));
- $this->_parse('__dcn', array('domain', 'singular', 'plural'));
- }
- }
-
-/**
- * Parse tokens
- *
- * @param string $functionName Function name that indicates translatable string (e.g: '__')
- * @param array $map Array containing what variables it will find (e.g: domain, singular, plural)
- * @return void
- */
- protected function _parse($functionName, $map) {
- $count = 0;
- $tokenCount = count($this->_tokens);
-
- while (($tokenCount - $count) > 1) {
- $countToken = $this->_tokens[$count];
- $firstParenthesis = $this->_tokens[$count + 1];
- if (!is_array($countToken)) {
- $count++;
- continue;
- }
-
- list($type, $string, $line) = $countToken;
- if (($type == T_STRING) && ($string == $functionName) && ($firstParenthesis == '(')) {
- $position = $count;
- $depth = 0;
-
- while ($depth == 0) {
- if ($this->_tokens[$position] == '(') {
- $depth++;
- } elseif ($this->_tokens[$position] == ')') {
- $depth--;
- }
- $position++;
- }
-
- $mapCount = count($map);
- $strings = $this->_getStrings($position, $mapCount);
-
- if ($mapCount == count($strings)) {
- extract(array_combine($map, $strings));
- $domain = isset($domain) ? $domain : 'default';
- $details = array(
- 'file' => $this->_file,
- 'line' => $line,
- );
- if (isset($plural)) {
- $details['msgid_plural'] = $plural;
- }
- $this->_addTranslation($domain, $singular, $details);
- } else {
- $this->_markerError($this->_file, $line, $functionName, $count);
- }
- }
- $count++;
- }
- }
-
-/**
- * Looks for models in the application and extracts the validation messages
- * to be added to the translation map
- *
- * @return void
- */
- protected function _extractValidationMessages() {
- if (!$this->_extractValidation) {
- return;
- }
-
- App::uses('AppModel', 'Model');
- $plugin = null;
- if (!empty($this->params['plugin'])) {
- App::uses($this->params['plugin'] . 'AppModel', $this->params['plugin'] . '.Model');
- $plugin = $this->params['plugin'] . '.';
- }
- $models = App::objects($plugin . 'Model', null, false);
-
- foreach ($models as $model) {
- App::uses($model, $plugin . 'Model');
- $reflection = new ReflectionClass($model);
- if (!$reflection->isSubClassOf('Model')) {
- continue;
- }
- $properties = $reflection->getDefaultProperties();
- $validate = $properties['validate'];
- if (empty($validate)) {
- continue;
- }
-
- $file = $reflection->getFileName();
- $domain = $this->_validationDomain;
- if (!empty($properties['validationDomain'])) {
- $domain = $properties['validationDomain'];
- }
- foreach ($validate as $field => $rules) {
- $this->_processValidationRules($field, $rules, $file, $domain);
- }
- }
- }
-
-/**
- * Process a validation rule for a field and looks for a message to be added
- * to the translation map
- *
- * @param string $field the name of the field that is being processed
- * @param array $rules the set of validation rules for the field
- * @param string $file the file name where this validation rule was found
- * @param string $domain default domain to bind the validations to
- * @return void
- */
- protected function _processValidationRules($field, $rules, $file, $domain) {
- if (!is_array($rules)) {
- return;
- }
-
- $dims = Set::countDim($rules);
- if ($dims == 1 || ($dims == 2 && isset($rules['message']))) {
- $rules = array($rules);
- }
-
- foreach ($rules as $rule => $validateProp) {
- $msgid = null;
- if (isset($validateProp['message'])) {
- if (is_array($validateProp['message'])) {
- $msgid = $validateProp['message'][0];
- } else {
- $msgid = $validateProp['message'];
- }
- } elseif (is_string($rule)) {
- $msgid = $rule;
- }
- if ($msgid) {
- $details = array(
- 'file' => $file,
- 'line' => 'validation for field ' . $field
- );
- $this->_addTranslation($domain, $msgid, $details);
- }
- }
- }
-
-/**
- * Build the translate template file contents out of obtained strings
- *
- * @return void
- */
- protected function _buildFiles() {
- foreach ($this->_translations as $domain => $translations) {
- foreach ($translations as $msgid => $details) {
- $plural = $details['msgid_plural'];
- $files = $details['references'];
- $occurrences = array();
- foreach ($files as $file => $lines) {
- $lines = array_unique($lines);
- $occurrences[] = $file . ':' . implode(';', $lines);
- }
- $occurrences = implode("\n#: ", $occurrences);
- $header = '#: ' . str_replace($this->_paths, '', $occurrences) . "\n";
-
- if ($plural === false) {
- $sentence = "msgid \"{$msgid}\"\n";
- $sentence .= "msgstr \"\"\n\n";
- } else {
- $sentence = "msgid \"{$msgid}\"\n";
- $sentence .= "msgid_plural \"{$plural}\"\n";
- $sentence .= "msgstr[0] \"\"\n";
- $sentence .= "msgstr[1] \"\"\n\n";
- }
-
- $this->_store($domain, $header, $sentence);
- if ($domain != 'default' && $this->_merge) {
- $this->_store('default', $header, $sentence);
- }
- }
- }
- }
-
-/**
- * Prepare a file to be stored
- *
- * @param string $domain
- * @param string $header
- * @param string $sentence
- * @return void
- */
- protected function _store($domain, $header, $sentence) {
- if (!isset($this->_storage[$domain])) {
- $this->_storage[$domain] = array();
- }
- if (!isset($this->_storage[$domain][$sentence])) {
- $this->_storage[$domain][$sentence] = $header;
- } else {
- $this->_storage[$domain][$sentence] .= $header;
- }
- }
-
-/**
- * Write the files that need to be stored
- *
- * @return void
- */
- protected function _writeFiles() {
- $overwriteAll = false;
- foreach ($this->_storage as $domain => $sentences) {
- $output = $this->_writeHeader();
- foreach ($sentences as $sentence => $header) {
- $output .= $header . $sentence;
- }
-
- $filename = $domain . '.pot';
- $File = new File($this->_output . $filename);
- $response = '';
- while ($overwriteAll === false && $File->exists() && strtoupper($response) !== 'Y') {
- $this->out();
- $response = $this->in(
- __d('cake_console', 'Error: %s already exists in this location. Overwrite? [Y]es, [N]o, [A]ll', $filename),
- array('y', 'n', 'a'),
- 'y'
- );
- if (strtoupper($response) === 'N') {
- $response = '';
- while ($response == '') {
- $response = $this->in(__d('cake_console', "What would you like to name this file?"), null, 'new_' . $filename);
- $File = new File($this->_output . $response);
- $filename = $response;
- }
- } elseif (strtoupper($response) === 'A') {
- $overwriteAll = true;
- }
- }
- $File->write($output);
- $File->close();
- }
- }
-
-/**
- * Build the translation template header
- *
- * @return string Translation template header
- */
- protected function _writeHeader() {
- $output = "# LANGUAGE translation of CakePHP Application\n";
- $output .= "# Copyright YEAR NAME \n";
- $output .= "#\n";
- $output .= "#, fuzzy\n";
- $output .= "msgid \"\"\n";
- $output .= "msgstr \"\"\n";
- $output .= "\"Project-Id-Version: PROJECT VERSION\\n\"\n";
- $output .= "\"POT-Creation-Date: " . date("Y-m-d H:iO") . "\\n\"\n";
- $output .= "\"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\\n\"\n";
- $output .= "\"Last-Translator: NAME \\n\"\n";
- $output .= "\"Language-Team: LANGUAGE \\n\"\n";
- $output .= "\"MIME-Version: 1.0\\n\"\n";
- $output .= "\"Content-Type: text/plain; charset=utf-8\\n\"\n";
- $output .= "\"Content-Transfer-Encoding: 8bit\\n\"\n";
- $output .= "\"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n\"\n\n";
- return $output;
- }
-
-/**
- * Get the strings from the position forward
- *
- * @param integer $position Actual position on tokens array
- * @param integer $target Number of strings to extract
- * @return array Strings extracted
- */
- protected function _getStrings(&$position, $target) {
- $strings = array();
- $count = count($strings);
- while ($count < $target && ($this->_tokens[$position] == ',' || $this->_tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING)) {
- $count = count($strings);
- if ($this->_tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING && $this->_tokens[$position + 1] == '.') {
- $string = '';
- while ($this->_tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING || $this->_tokens[$position] == '.') {
- if ($this->_tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING) {
- $string .= $this->_formatString($this->_tokens[$position][1]);
- }
- $position++;
- }
- $strings[] = $string;
- } elseif ($this->_tokens[$position][0] == T_CONSTANT_ENCAPSED_STRING) {
- $strings[] = $this->_formatString($this->_tokens[$position][1]);
- }
- $position++;
- }
- return $strings;
- }
-
-/**
- * Format a string to be added as a translatable string
- *
- * @param string $string String to format
- * @return string Formatted string
- */
- protected function _formatString($string) {
- $quote = substr($string, 0, 1);
- $string = substr($string, 1, -1);
- if ($quote == '"') {
- $string = stripcslashes($string);
- } else {
- $string = strtr($string, array("\\'" => "'", "\\\\" => "\\"));
- }
- $string = str_replace("\r\n", "\n", $string);
- return addcslashes($string, "\0..\37\\\"");
- }
-
-/**
- * Indicate an invalid marker on a processed file
- *
- * @param string $file File where invalid marker resides
- * @param integer $line Line number
- * @param string $marker Marker found
- * @param integer $count Count
- * @return void
- */
- protected function _markerError($file, $line, $marker, $count) {
- $this->out(__d('cake_console', "Invalid marker content in %s:%s\n* %s(", $file, $line, $marker), true);
- $count += 2;
- $tokenCount = count($this->_tokens);
- $parenthesis = 1;
-
- while ((($tokenCount - $count) > 0) && $parenthesis) {
- if (is_array($this->_tokens[$count])) {
- $this->out($this->_tokens[$count][1], false);
- } else {
- $this->out($this->_tokens[$count], false);
- if ($this->_tokens[$count] == '(') {
- $parenthesis++;
- }
-
- if ($this->_tokens[$count] == ')') {
- $parenthesis--;
- }
- }
- $count++;
- }
- $this->out("\n", true);
- }
-
-/**
- * Search files that may contain translatable strings
- *
- * @return void
- */
- protected function _searchFiles() {
- $pattern = false;
- if (!empty($this->_exclude)) {
- $exclude = array();
- foreach ($this->_exclude as $e) {
- if (DS !== '\\' && $e[0] !== DS) {
- $e = DS . $e;
- }
- $exclude[] = preg_quote($e, '/');
- }
- $pattern = '/' . implode('|', $exclude) . '/';
- }
- foreach ($this->_paths as $path) {
- $Folder = new Folder($path);
- $files = $Folder->findRecursive('.*\.(php|ctp|thtml|inc|tpl)', true);
- if (!empty($pattern)) {
- foreach ($files as $i => $file) {
- if (preg_match($pattern, $file)) {
- unset($files[$i]);
- }
- }
- $files = array_values($files);
- }
- $this->_files = array_merge($this->_files, $files);
- }
- }
-
-/**
- * Returns whether this execution is meant to extract string only from directories in folder represented by the
- * APP constant, i.e. this task is extracting strings from same application.
- *
- * @return boolean
- */
- protected function _isExtractingApp() {
- return $this->_paths === array(APP);
- }
-
-}
diff --git a/lib/Cake/Console/Command/Task/FixtureTask.php b/lib/Cake/Console/Command/Task/FixtureTask.php
deleted file mode 100644
index c4bf93d6251..00000000000
--- a/lib/Cake/Console/Command/Task/FixtureTask.php
+++ /dev/null
@@ -1,418 +0,0 @@
-path = APP . 'Test' . DS . 'Fixture' . DS;
- }
-
-/**
- * get the option parser.
- *
- * @return void
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- return $parser->description(
- __d('cake_console', 'Generate fixtures for use with the test suite. You can use `bake fixture all` to bake all fixtures.')
- )->addArgument('name', array(
- 'help' => __d('cake_console', 'Name of the fixture to bake. Can use Plugin.name to bake plugin fixtures.')
- ))->addOption('count', array(
- 'help' => __d('cake_console', 'When using generated data, the number of records to include in the fixture(s).'),
- 'short' => 'n',
- 'default' => 10
- ))->addOption('connection', array(
- 'help' => __d('cake_console', 'Which database configuration to use for baking.'),
- 'short' => 'c',
- 'default' => 'default'
- ))->addOption('plugin', array(
- 'help' => __d('cake_console', 'CamelCased name of the plugin to bake fixtures for.'),
- 'short' => 'p',
- ))->addOption('records', array(
- 'help' => __d('cake_console', 'Used with --count and /all commands to pull [n] records from the live tables, where [n] is either --count or the default of 10'),
- 'short' => 'r',
- 'boolean' => true
- ))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.'));
- }
-
-/**
- * Execution method always used for tasks
- * Handles dispatching to interactive, named, or all processes.
- *
- * @return void
- */
- public function execute() {
- parent::execute();
- if (empty($this->args)) {
- $this->_interactive();
- }
-
- if (isset($this->args[0])) {
- $this->interactive = false;
- if (!isset($this->connection)) {
- $this->connection = 'default';
- }
- if (strtolower($this->args[0]) == 'all') {
- return $this->all();
- }
- $model = $this->_modelName($this->args[0]);
- $this->bake($model);
- }
- }
-
-/**
- * Bake All the Fixtures at once. Will only bake fixtures for models that exist.
- *
- * @return void
- */
- public function all() {
- $this->interactive = false;
- $this->Model->interactive = false;
- $tables = $this->Model->listAll($this->connection, false);
- foreach ($tables as $table) {
- $model = $this->_modelName($table);
- $this->bake($model);
- }
- }
-
-/**
- * Interactive baking function
- *
- * @return void
- */
- protected function _interactive() {
- $this->DbConfig->interactive = $this->Model->interactive = $this->interactive = true;
- $this->hr();
- $this->out(__d('cake_console', "Bake Fixture\nPath: %s", $this->getPath()));
- $this->hr();
-
- if (!isset($this->connection)) {
- $this->connection = $this->DbConfig->getConfig();
- }
- $modelName = $this->Model->getName($this->connection);
- $useTable = $this->Model->getTable($modelName, $this->connection);
- $importOptions = $this->importOptions($modelName);
- $this->bake($modelName, $useTable, $importOptions);
- }
-
-/**
- * Interacts with the User to setup an array of import options. For a fixture.
- *
- * @param string $modelName Name of model you are dealing with.
- * @return array Array of import options.
- */
- public function importOptions($modelName) {
- $options = array();
- $doSchema = $this->in(__d('cake_console', 'Would you like to import schema for this fixture?'), array('y', 'n'), 'n');
- if ($doSchema == 'y') {
- $options['schema'] = $modelName;
- }
- $doRecords = $this->in(__d('cake_console', 'Would you like to use record importing for this fixture?'), array('y', 'n'), 'n');
- if ($doRecords == 'y') {
- $options['records'] = true;
- }
- if ($doRecords == 'n') {
- $prompt = __d('cake_console', "Would you like to build this fixture with data from %s's table?", $modelName);
- $fromTable = $this->in($prompt, array('y', 'n'), 'n');
- if (strtolower($fromTable) == 'y') {
- $options['fromTable'] = true;
- }
- }
- return $options;
- }
-
-/**
- * Assembles and writes a Fixture file
- *
- * @param string $model Name of model to bake.
- * @param string $useTable Name of table to use.
- * @param array $importOptions Options for public $import
- * @return string Baked fixture content
- */
- public function bake($model, $useTable = false, $importOptions = array()) {
- App::uses('CakeSchema', 'Model');
- $table = $schema = $records = $import = $modelImport = null;
- $importBits = array();
-
- if (!$useTable) {
- $useTable = Inflector::tableize($model);
- } elseif ($useTable != Inflector::tableize($model)) {
- $table = $useTable;
- }
-
- if (!empty($importOptions)) {
- if (isset($importOptions['schema'])) {
- $modelImport = true;
- $importBits[] = "'model' => '{$importOptions['schema']}'";
- }
- if (isset($importOptions['records'])) {
- $importBits[] = "'records' => true";
- }
- if ($this->connection != 'default') {
- $importBits[] .= "'connection' => '{$this->connection}'";
- }
- if (!empty($importBits)) {
- $import = sprintf("array(%s)", implode(', ', $importBits));
- }
- }
-
- $this->_Schema = new CakeSchema();
- $data = $this->_Schema->read(array('models' => false, 'connection' => $this->connection));
- if (!isset($data['tables'][$useTable])) {
- $this->err('Could not find your selected table ' . $useTable);
- return false;
- }
-
- $tableInfo = $data['tables'][$useTable];
- if (is_null($modelImport)) {
- $schema = $this->_generateSchema($tableInfo);
- }
-
- if (empty($importOptions['records']) && !isset($importOptions['fromTable'])) {
- $recordCount = 1;
- if (isset($this->params['count'])) {
- $recordCount = $this->params['count'];
- }
- $records = $this->_makeRecordString($this->_generateRecords($tableInfo, $recordCount));
- }
- if (!empty($this->params['records']) || isset($importOptions['fromTable'])) {
- $records = $this->_makeRecordString($this->_getRecordsFromTable($model, $useTable));
- }
- $out = $this->generateFixtureFile($model, compact('records', 'table', 'schema', 'import', 'fields'));
- return $out;
- }
-
-/**
- * Generate the fixture file, and write to disk
- *
- * @param string $model name of the model being generated
- * @param string $otherVars Contents of the fixture file.
- * @return string Content saved into fixture file.
- */
- public function generateFixtureFile($model, $otherVars) {
- $defaults = array('table' => null, 'schema' => null, 'records' => null, 'import' => null, 'fields' => null);
- $vars = array_merge($defaults, $otherVars);
-
- $path = $this->getPath();
- $filename = Inflector::camelize($model) . 'Fixture.php';
-
- $this->Template->set('model', $model);
- $this->Template->set($vars);
- $content = $this->Template->generate('classes', 'fixture');
-
- $this->out("\n" . __d('cake_console', 'Baking test fixture for %s...', $model), 1, Shell::QUIET);
- $this->createFile($path . $filename, $content);
- return $content;
- }
-
-/**
- * Get the path to the fixtures.
- *
- * @return string Path for the fixtures
- */
- public function getPath() {
- $path = $this->path;
- if (isset($this->plugin)) {
- $path = $this->_pluginPath($this->plugin) . 'Test' . DS . 'Fixture' . DS;
- }
- return $path;
- }
-
-/**
- * Generates a string representation of a schema.
- *
- * @param array $tableInfo Table schema array
- * @return string fields definitions
- */
- protected function _generateSchema($tableInfo) {
- $schema = $this->_Schema->generateTable('f', $tableInfo);
- return substr($schema, 13, -2);
- }
-
-/**
- * Generate String representation of Records
- *
- * @param array $tableInfo Table schema array
- * @param integer $recordCount
- * @return array Array of records to use in the fixture.
- */
- protected function _generateRecords($tableInfo, $recordCount = 1) {
- $records = array();
- for ($i = 0; $i < $recordCount; $i++) {
- $record = array();
- foreach ($tableInfo as $field => $fieldInfo) {
- if (empty($fieldInfo['type'])) {
- continue;
- }
- switch ($fieldInfo['type']) {
- case 'integer':
- case 'float':
- $insert = $i + 1;
- break;
- case 'string':
- case 'binary':
- $isPrimaryUuid = (
- isset($fieldInfo['key']) && strtolower($fieldInfo['key']) == 'primary' &&
- isset($fieldInfo['length']) && $fieldInfo['length'] == 36
- );
- if ($isPrimaryUuid) {
- $insert = String::uuid();
- } else {
- $insert = "Lorem ipsum dolor sit amet";
- if (!empty($fieldInfo['length'])) {
- $insert = substr($insert, 0, (int)$fieldInfo['length'] - 2);
- }
- }
- break;
- case 'timestamp':
- $insert = time();
- break;
- case 'datetime':
- $insert = date('Y-m-d H:i:s');
- break;
- case 'date':
- $insert = date('Y-m-d');
- break;
- case 'time':
- $insert = date('H:i:s');
- break;
- case 'boolean':
- $insert = 1;
- break;
- case 'text':
- $insert = "Lorem ipsum dolor sit amet, aliquet feugiat.";
- $insert .= " Convallis morbi fringilla gravida,";
- $insert .= " phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin";
- $insert .= " venenatis cum nullam, vivamus ut a sed, mollitia lectus. Nulla";
- $insert .= " vestibulum massa neque ut et, id hendrerit sit,";
- $insert .= " feugiat in taciti enim proin nibh, tempor dignissim, rhoncus";
- $insert .= " duis vestibulum nunc mattis convallis.";
- break;
- }
- $record[$field] = $insert;
- }
- $records[] = $record;
- }
- return $records;
- }
-
-/**
- * Convert a $records array into a a string.
- *
- * @param array $records Array of records to be converted to string
- * @return string A string value of the $records array.
- */
- protected function _makeRecordString($records) {
- $out = "array(\n";
- foreach ($records as $record) {
- $values = array();
- foreach ($record as $field => $value) {
- $val = var_export($value, true);
- $values[] = "\t\t\t'$field' => $val";
- }
- $out .= "\t\tarray(\n";
- $out .= implode(",\n", $values);
- $out .= "\n\t\t),\n";
- }
- $out .= "\t)";
- return $out;
- }
-
-/**
- * Interact with the user to get a custom SQL condition and use that to extract data
- * to build a fixture.
- *
- * @param string $modelName name of the model to take records from.
- * @param string $useTable Name of table to use.
- * @return array Array of records.
- */
- protected function _getRecordsFromTable($modelName, $useTable = null) {
- if ($this->interactive) {
- $condition = null;
- $prompt = __d('cake_console', "Please provide a SQL fragment to use as conditions\nExample: WHERE 1=1");
- while (!$condition) {
- $condition = $this->in($prompt, null, 'WHERE 1=1');
- }
- $prompt = __d('cake_console', "How many records do you want to import?");
- $recordCount = $this->in($prompt, null, 10);
- } else {
- $condition = 'WHERE 1=1';
- $recordCount = (isset($this->params['count']) ? $this->params['count'] : 10);
- }
- $modelObject = new Model(array('name' => $modelName, 'table' => $useTable, 'ds' => $this->connection));
- $records = $modelObject->find('all', array(
- 'conditions' => $condition,
- 'recursive' => -1,
- 'limit' => $recordCount
- ));
- $db = $modelObject->getDatasource();
- $schema = $modelObject->schema(true);
- $out = array();
- foreach ($records as $record) {
- $row = array();
- foreach ($record[$modelObject->alias] as $field => $value) {
- if ($schema[$field]['type'] === 'boolean') {
- $value = (int)(bool)$value;
- }
- $row[$field] = $value;
- }
- $out[] = $row;
- }
- return $out;
- }
-
-}
diff --git a/lib/Cake/Console/Command/Task/ModelTask.php b/lib/Cake/Console/Command/Task/ModelTask.php
deleted file mode 100644
index 424674950ed..00000000000
--- a/lib/Cake/Console/Command/Task/ModelTask.php
+++ /dev/null
@@ -1,988 +0,0 @@
-path = current(App::path('Model'));
- }
-
-/**
- * Execution method always used for tasks
- *
- * @return void
- */
- public function execute() {
- parent::execute();
-
- if (empty($this->args)) {
- $this->_interactive();
- }
-
- if (!empty($this->args[0])) {
- $this->interactive = false;
- if (!isset($this->connection)) {
- $this->connection = 'default';
- }
- if (strtolower($this->args[0]) == 'all') {
- return $this->all();
- }
- $model = $this->_modelName($this->args[0]);
- $this->listAll($this->connection);
- $useTable = $this->getTable($model);
- $object = $this->_getModelObject($model, $useTable);
- if ($this->bake($object, false)) {
- if ($this->_checkUnitTest()) {
- $this->bakeFixture($model, $useTable);
- $this->bakeTest($model);
- }
- }
- }
- }
-
-/**
- * Bake all models at once.
- *
- * @return void
- */
- public function all() {
- $this->listAll($this->connection, false);
- $unitTestExists = $this->_checkUnitTest();
- foreach ($this->_tables as $table) {
- if (in_array($table, $this->skipTables)) {
- continue;
- }
- $modelClass = Inflector::classify($table);
- $this->out(__d('cake_console', 'Baking %s', $modelClass));
- $object = $this->_getModelObject($modelClass, $table);
- if ($this->bake($object, false) && $unitTestExists) {
- $this->bakeFixture($modelClass, $table);
- $this->bakeTest($modelClass);
- }
- }
- }
-
-/**
- * Get a model object for a class name.
- *
- * @param string $className Name of class you want model to be.
- * @param string $table Table name
- * @return Model Model instance
- */
- protected function _getModelObject($className, $table = null) {
- if (!$table) {
- $table = Inflector::tableize($className);
- }
- $object = new Model(array('name' => $className, 'table' => $table, 'ds' => $this->connection));
- $fields = $object->schema(true);
- foreach ($fields as $name => $field) {
- if (isset($field['key']) && $field['key'] == 'primary') {
- $object->primaryKey = $name;
- break;
- }
- }
- return $object;
- }
-
-/**
- * Generate a key value list of options and a prompt.
- *
- * @param array $options Array of options to use for the selections. indexes must start at 0
- * @param string $prompt Prompt to use for options list.
- * @param integer $default The default option for the given prompt.
- * @return integer result of user choice.
- */
- public function inOptions($options, $prompt = null, $default = null) {
- $valid = false;
- $max = count($options);
- while (!$valid) {
- foreach ($options as $i => $option) {
- $this->out($i + 1 . '. ' . $option);
- }
- if (empty($prompt)) {
- $prompt = __d('cake_console', 'Make a selection from the choices above');
- }
- $choice = $this->in($prompt, null, $default);
- if (intval($choice) > 0 && intval($choice) <= $max) {
- $valid = true;
- }
- }
- return $choice - 1;
- }
-
-/**
- * Handles interactive baking
- *
- * @return boolean
- */
- protected function _interactive() {
- $this->hr();
- $this->out(__d('cake_console', "Bake Model\nPath: %s", $this->getPath()));
- $this->hr();
- $this->interactive = true;
-
- $primaryKey = 'id';
- $validate = $associations = array();
-
- if (empty($this->connection)) {
- $this->connection = $this->DbConfig->getConfig();
- }
- $currentModelName = $this->getName();
- $useTable = $this->getTable($currentModelName);
- $db = ConnectionManager::getDataSource($this->connection);
- $fullTableName = $db->fullTableName($useTable);
- if (!in_array($useTable, $this->_tables)) {
- $prompt = __d('cake_console', "The table %s doesn't exist or could not be automatically detected\ncontinue anyway?", $useTable);
- $continue = $this->in($prompt, array('y', 'n'));
- if (strtolower($continue) == 'n') {
- return false;
- }
- }
-
- $tempModel = new Model(array('name' => $currentModelName, 'table' => $useTable, 'ds' => $this->connection));
-
- $knownToExist = false;
- try {
- $fields = $tempModel->schema(true);
- $knownToExist = true;
- } catch (Exception $e) {
- $fields = array($tempModel->primaryKey);
- }
- if (!array_key_exists('id', $fields)) {
- $primaryKey = $this->findPrimaryKey($fields);
- }
-
- if ($knownToExist) {
- $displayField = $tempModel->hasField(array('name', 'title'));
- if (!$displayField) {
- $displayField = $this->findDisplayField($tempModel->schema());
- }
-
- $prompt = __d('cake_console', "Would you like to supply validation criteria \nfor the fields in your model?");
- $wannaDoValidation = $this->in($prompt, array('y','n'), 'y');
- if (array_search($useTable, $this->_tables) !== false && strtolower($wannaDoValidation) == 'y') {
- $validate = $this->doValidation($tempModel);
- }
-
- $prompt = __d('cake_console', "Would you like to define model associations\n(hasMany, hasOne, belongsTo, etc.)?");
- $wannaDoAssoc = $this->in($prompt, array('y','n'), 'y');
- if (strtolower($wannaDoAssoc) == 'y') {
- $associations = $this->doAssociations($tempModel);
- }
- }
-
- $this->out();
- $this->hr();
- $this->out(__d('cake_console', 'The following Model will be created:'));
- $this->hr();
- $this->out(__d('cake_console', "Name: %s", $currentModelName));
-
- if ($this->connection !== 'default') {
- $this->out(__d('cake_console', "DB Config: %s", $this->connection));
- }
- if ($fullTableName !== Inflector::tableize($currentModelName)) {
- $this->out(__d('cake_console', 'DB Table: %s', $fullTableName));
- }
- if ($primaryKey != 'id') {
- $this->out(__d('cake_console', 'Primary Key: %s', $primaryKey));
- }
- if (!empty($validate)) {
- $this->out(__d('cake_console', 'Validation: %s', print_r($validate, true)));
- }
- if (!empty($associations)) {
- $this->out(__d('cake_console', 'Associations:'));
- $assocKeys = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
- foreach ($assocKeys as $assocKey) {
- $this->_printAssociation($currentModelName, $assocKey, $associations);
- }
- }
-
- $this->hr();
- $looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n'), 'y');
-
- if (strtolower($looksGood) == 'y') {
- $vars = compact('associations', 'validate', 'primaryKey', 'useTable', 'displayField');
- $vars['useDbConfig'] = $this->connection;
- if ($this->bake($currentModelName, $vars)) {
- if ($this->_checkUnitTest()) {
- $this->bakeFixture($currentModelName, $useTable);
- $this->bakeTest($currentModelName, $useTable, $associations);
- }
- }
- } else {
- return false;
- }
- }
-
-/**
- * Print out all the associations of a particular type
- *
- * @param string $modelName Name of the model relations belong to.
- * @param string $type Name of association you want to see. i.e. 'belongsTo'
- * @param string $associations Collection of associations.
- * @return void
- */
- protected function _printAssociation($modelName, $type, $associations) {
- if (!empty($associations[$type])) {
- for ($i = 0, $len = count($associations[$type]); $i < $len; $i++) {
- $out = "\t" . $modelName . ' ' . $type . ' ' . $associations[$type][$i]['alias'];
- $this->out($out);
- }
- }
- }
-
-/**
- * Finds a primary Key in a list of fields.
- *
- * @param array $fields Array of fields that might have a primary key.
- * @return string Name of field that is a primary key.
- */
- public function findPrimaryKey($fields) {
- $name = 'id';
- foreach ($fields as $name => $field) {
- if (isset($field['key']) && $field['key'] == 'primary') {
- break;
- }
- }
- return $this->in(__d('cake_console', 'What is the primaryKey?'), null, $name);
- }
-
-/**
- * interact with the user to find the displayField value for a model.
- *
- * @param array $fields Array of fields to look for and choose as a displayField
- * @return mixed Name of field to use for displayField or false if the user declines to choose
- */
- public function findDisplayField($fields) {
- $fieldNames = array_keys($fields);
- $prompt = __d('cake_console', "A displayField could not be automatically detected\nwould you like to choose one?");
- $continue = $this->in($prompt, array('y', 'n'));
- if (strtolower($continue) == 'n') {
- return false;
- }
- $prompt = __d('cake_console', 'Choose a field from the options above:');
- $choice = $this->inOptions($fieldNames, $prompt);
- return $fieldNames[$choice];
- }
-
-/**
- * Handles Generation and user interaction for creating validation.
- *
- * @param Model $model Model to have validations generated for.
- * @return array $validate Array of user selected validations.
- */
- public function doValidation($model) {
- if (!is_object($model)) {
- return false;
- }
- $fields = $model->schema();
-
- if (empty($fields)) {
- return false;
- }
- $validate = array();
- $this->initValidations();
- foreach ($fields as $fieldName => $field) {
- $validation = $this->fieldValidation($fieldName, $field, $model->primaryKey);
- if (!empty($validation)) {
- $validate[$fieldName] = $validation;
- }
- }
- return $validate;
- }
-
-/**
- * Populate the _validations array
- *
- * @return void
- */
- public function initValidations() {
- $options = $choices = array();
- if (class_exists('Validation')) {
- $options = get_class_methods('Validation');
- }
- sort($options);
- $default = 1;
- foreach ($options as $key => $option) {
- if ($option{0} != '_') {
- $choices[$default] = strtolower($option);
- $default++;
- }
- }
- $choices[$default] = 'none'; // Needed since index starts at 1
- $this->_validations = $choices;
- return $choices;
- }
-
-/**
- * Does individual field validation handling.
- *
- * @param string $fieldName Name of field to be validated.
- * @param array $metaData metadata for field
- * @param string $primaryKey
- * @return array Array of validation for the field.
- */
- public function fieldValidation($fieldName, $metaData, $primaryKey = 'id') {
- $defaultChoice = count($this->_validations);
- $validate = $alreadyChosen = array();
-
- $anotherValidator = 'y';
- while ($anotherValidator == 'y') {
- if ($this->interactive) {
- $this->out();
- $this->out(__d('cake_console', 'Field: %s', $fieldName));
- $this->out(__d('cake_console', 'Type: %s', $metaData['type']));
- $this->hr();
- $this->out(__d('cake_console', 'Please select one of the following validation options:'));
- $this->hr();
- }
-
- $prompt = '';
- for ($i = 1; $i < $defaultChoice; $i++) {
- $prompt .= $i . ' - ' . $this->_validations[$i] . "\n";
- }
- $prompt .= __d('cake_console', "%s - Do not do any validation on this field.\n", $defaultChoice);
- $prompt .= __d('cake_console', "... or enter in a valid regex validation string.\n");
-
- $methods = array_flip($this->_validations);
- $guess = $defaultChoice;
- if ($metaData['null'] != 1 && !in_array($fieldName, array($primaryKey, 'created', 'modified', 'updated'))) {
- if ($fieldName == 'email') {
- $guess = $methods['email'];
- } elseif ($metaData['type'] == 'string' && $metaData['length'] == 36) {
- $guess = $methods['uuid'];
- } elseif ($metaData['type'] == 'string') {
- $guess = $methods['notempty'];
- } elseif ($metaData['type'] == 'text') {
- $guess = $methods['notempty'];
- } elseif ($metaData['type'] == 'integer') {
- $guess = $methods['numeric'];
- } elseif ($metaData['type'] == 'boolean') {
- $guess = $methods['boolean'];
- } elseif ($metaData['type'] == 'date') {
- $guess = $methods['date'];
- } elseif ($metaData['type'] == 'time') {
- $guess = $methods['time'];
- } elseif ($metaData['type'] == 'inet') {
- $guess = $methods['ip'];
- }
- }
-
- if ($this->interactive === true) {
- $choice = $this->in($prompt, null, $guess);
- if (in_array($choice, $alreadyChosen)) {
- $this->out(__d('cake_console', "You have already chosen that validation rule,\nplease choose again"));
- continue;
- }
- if (!isset($this->_validations[$choice]) && is_numeric($choice)) {
- $this->out(__d('cake_console', 'Please make a valid selection.'));
- continue;
- }
- $alreadyChosen[] = $choice;
- } else {
- $choice = $guess;
- }
-
- if (isset($this->_validations[$choice])) {
- $validatorName = $this->_validations[$choice];
- } else {
- $validatorName = Inflector::slug($choice);
- }
-
- if ($choice != $defaultChoice) {
- if (is_numeric($choice) && isset($this->_validations[$choice])) {
- $validate[$validatorName] = $this->_validations[$choice];
- } else {
- $validate[$validatorName] = $choice;
- }
- }
- if ($this->interactive == true && $choice != $defaultChoice) {
- $anotherValidator = $this->in(__d('cake_console', 'Would you like to add another validation rule?'), array('y', 'n'), 'n');
- } else {
- $anotherValidator = 'n';
- }
- }
- return $validate;
- }
-
-/**
- * Handles associations
- *
- * @param Model $model
- * @return array $associations
- */
- public function doAssociations($model) {
- if (!is_object($model)) {
- return false;
- }
- if ($this->interactive === true) {
- $this->out(__d('cake_console', 'One moment while the associations are detected.'));
- }
-
- $fields = $model->schema(true);
- if (empty($fields)) {
- return array();
- }
-
- if (empty($this->_tables)) {
- $this->_tables = (array)$this->getAllTables();
- }
-
- $associations = array(
- 'belongsTo' => array(),
- 'hasMany' => array(),
- 'hasOne' => array(),
- 'hasAndBelongsToMany' => array()
- );
-
- $associations = $this->findBelongsTo($model, $associations);
- $associations = $this->findHasOneAndMany($model, $associations);
- $associations = $this->findHasAndBelongsToMany($model, $associations);
-
- if ($this->interactive !== true) {
- unset($associations['hasOne']);
- }
-
- if ($this->interactive === true) {
- $this->hr();
- if (empty($associations)) {
- $this->out(__d('cake_console', 'None found.'));
- } else {
- $this->out(__d('cake_console', 'Please confirm the following associations:'));
- $this->hr();
- $associations = $this->confirmAssociations($model, $associations);
- }
- $associations = $this->doMoreAssociations($model, $associations);
- }
- return $associations;
- }
-
-/**
- * Find belongsTo relations and add them to the associations list.
- *
- * @param Model $model Model instance of model being generated.
- * @param array $associations Array of in progress associations
- * @return array $associations with belongsTo added in.
- */
- public function findBelongsTo(Model $model, $associations) {
- $fields = $model->schema(true);
- foreach ($fields as $fieldName => $field) {
- $offset = strpos($fieldName, '_id');
- if ($fieldName != $model->primaryKey && $fieldName != 'parent_id' && $offset !== false) {
- $tmpModelName = $this->_modelNameFromKey($fieldName);
- $associations['belongsTo'][] = array(
- 'alias' => $tmpModelName,
- 'className' => $tmpModelName,
- 'foreignKey' => $fieldName,
- );
- } elseif ($fieldName == 'parent_id') {
- $associations['belongsTo'][] = array(
- 'alias' => 'Parent' . $model->name,
- 'className' => $model->name,
- 'foreignKey' => $fieldName,
- );
- }
- }
- return $associations;
- }
-
-/**
- * Find the hasOne and HasMany relations and add them to associations list
- *
- * @param Model $model Model instance being generated
- * @param array $associations Array of in progress associations
- * @return array $associations with hasOne and hasMany added in.
- */
- public function findHasOneAndMany(Model $model, $associations) {
- $foreignKey = $this->_modelKey($model->name);
- foreach ($this->_tables as $otherTable) {
- $tempOtherModel = $this->_getModelObject($this->_modelName($otherTable), $otherTable);
- $modelFieldsTemp = $tempOtherModel->schema(true);
-
- $pattern = '/_' . preg_quote($model->table, '/') . '|' . preg_quote($model->table, '/') . '_/';
- $possibleJoinTable = preg_match($pattern, $otherTable);
- if ($possibleJoinTable == true) {
- continue;
- }
- foreach ($modelFieldsTemp as $fieldName => $field) {
- $assoc = false;
- if ($fieldName != $model->primaryKey && $fieldName == $foreignKey) {
- $assoc = array(
- 'alias' => $tempOtherModel->name,
- 'className' => $tempOtherModel->name,
- 'foreignKey' => $fieldName
- );
- } elseif ($otherTable == $model->table && $fieldName == 'parent_id') {
- $assoc = array(
- 'alias' => 'Child' . $model->name,
- 'className' => $model->name,
- 'foreignKey' => $fieldName
- );
- }
- if ($assoc) {
- $associations['hasOne'][] = $assoc;
- $associations['hasMany'][] = $assoc;
- }
-
- }
- }
- return $associations;
- }
-
-/**
- * Find the hasAndBelongsToMany relations and add them to associations list
- *
- * @param Model $model Model instance being generated
- * @param array $associations Array of in-progress associations
- * @return array $associations with hasAndBelongsToMany added in.
- */
- public function findHasAndBelongsToMany(Model $model, $associations) {
- $foreignKey = $this->_modelKey($model->name);
- foreach ($this->_tables as $otherTable) {
- $tempOtherModel = $this->_getModelObject($this->_modelName($otherTable), $otherTable);
- $modelFieldsTemp = $tempOtherModel->schema(true);
-
- $offset = strpos($otherTable, $model->table . '_');
- $otherOffset = strpos($otherTable, '_' . $model->table);
-
- if ($offset !== false) {
- $offset = strlen($model->table . '_');
- $habtmName = $this->_modelName(substr($otherTable, $offset));
- $associations['hasAndBelongsToMany'][] = array(
- 'alias' => $habtmName,
- 'className' => $habtmName,
- 'foreignKey' => $foreignKey,
- 'associationForeignKey' => $this->_modelKey($habtmName),
- 'joinTable' => $otherTable
- );
- } elseif ($otherOffset !== false) {
- $habtmName = $this->_modelName(substr($otherTable, 0, $otherOffset));
- $associations['hasAndBelongsToMany'][] = array(
- 'alias' => $habtmName,
- 'className' => $habtmName,
- 'foreignKey' => $foreignKey,
- 'associationForeignKey' => $this->_modelKey($habtmName),
- 'joinTable' => $otherTable
- );
- }
- }
- return $associations;
- }
-
-/**
- * Interact with the user and confirm associations.
- *
- * @param array $model Temporary Model instance.
- * @param array $associations Array of associations to be confirmed.
- * @return array Array of confirmed associations
- */
- public function confirmAssociations(Model $model, $associations) {
- foreach ($associations as $type => $settings) {
- if (!empty($associations[$type])) {
- foreach ($associations[$type] as $i => $assoc) {
- $prompt = "{$model->name} {$type} {$assoc['alias']}?";
- $response = $this->in($prompt, array('y', 'n'), 'y');
-
- if ('n' == strtolower($response)) {
- unset($associations[$type][$i]);
- } elseif ($type == 'hasMany') {
- unset($associations['hasOne'][$i]);
- }
- }
- $associations[$type] = array_merge($associations[$type]);
- }
- }
- return $associations;
- }
-
-/**
- * Interact with the user and generate additional non-conventional associations
- *
- * @param Model $model Temporary model instance
- * @param array $associations Array of associations.
- * @return array Array of associations.
- */
- public function doMoreAssociations(Model $model, $associations) {
- $prompt = __d('cake_console', 'Would you like to define some additional model associations?');
- $wannaDoMoreAssoc = $this->in($prompt, array('y', 'n'), 'n');
- $possibleKeys = $this->_generatePossibleKeys();
- while (strtolower($wannaDoMoreAssoc) == 'y') {
- $assocs = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
- $this->out(__d('cake_console', 'What is the association type?'));
- $assocType = intval($this->inOptions($assocs, __d('cake_console', 'Enter a number')));
-
- $this->out(__d('cake_console', "For the following options be very careful to match your setup exactly.\n" .
- "Any spelling mistakes will cause errors."));
- $this->hr();
-
- $alias = $this->in(__d('cake_console', 'What is the alias for this association?'));
- $className = $this->in(__d('cake_console', 'What className will %s use?', $alias), null, $alias );
-
- if ($assocType == 0) {
- if (!empty($possibleKeys[$model->table])) {
- $showKeys = $possibleKeys[$model->table];
- } else {
- $showKeys = null;
- }
- $suggestedForeignKey = $this->_modelKey($alias);
- } else {
- $otherTable = Inflector::tableize($className);
- if (in_array($otherTable, $this->_tables)) {
- if ($assocType < 3) {
- if (!empty($possibleKeys[$otherTable])) {
- $showKeys = $possibleKeys[$otherTable];
- } else {
- $showKeys = null;
- }
- } else {
- $showKeys = null;
- }
- } else {
- $otherTable = $this->in(__d('cake_console', 'What is the table for this model?'));
- $showKeys = $possibleKeys[$otherTable];
- }
- $suggestedForeignKey = $this->_modelKey($model->name);
- }
- if (!empty($showKeys)) {
- $this->out(__d('cake_console', 'A helpful List of possible keys'));
- $foreignKey = $this->inOptions($showKeys, __d('cake_console', 'What is the foreignKey?'));
- $foreignKey = $showKeys[intval($foreignKey)];
- }
- if (!isset($foreignKey)) {
- $foreignKey = $this->in(__d('cake_console', 'What is the foreignKey? Specify your own.'), null, $suggestedForeignKey);
- }
- if ($assocType == 3) {
- $associationForeignKey = $this->in(__d('cake_console', 'What is the associationForeignKey?'), null, $this->_modelKey($model->name));
- $joinTable = $this->in(__d('cake_console', 'What is the joinTable?'));
- }
- $associations[$assocs[$assocType]] = array_values((array)$associations[$assocs[$assocType]]);
- $count = count($associations[$assocs[$assocType]]);
- $i = ($count > 0) ? $count : 0;
- $associations[$assocs[$assocType]][$i]['alias'] = $alias;
- $associations[$assocs[$assocType]][$i]['className'] = $className;
- $associations[$assocs[$assocType]][$i]['foreignKey'] = $foreignKey;
- if ($assocType == 3) {
- $associations[$assocs[$assocType]][$i]['associationForeignKey'] = $associationForeignKey;
- $associations[$assocs[$assocType]][$i]['joinTable'] = $joinTable;
- }
- $wannaDoMoreAssoc = $this->in(__d('cake_console', 'Define another association?'), array('y', 'n'), 'y');
- }
- return $associations;
- }
-
-/**
- * Finds all possible keys to use on custom associations.
- *
- * @return array array of tables and possible keys
- */
- protected function _generatePossibleKeys() {
- $possible = array();
- foreach ($this->_tables as $otherTable) {
- $tempOtherModel = new Model(array('table' => $otherTable, 'ds' => $this->connection));
- $modelFieldsTemp = $tempOtherModel->schema(true);
- foreach ($modelFieldsTemp as $fieldName => $field) {
- if ($field['type'] == 'integer' || $field['type'] == 'string') {
- $possible[$otherTable][] = $fieldName;
- }
- }
- }
- return $possible;
- }
-
-/**
- * Assembles and writes a Model file.
- *
- * @param mixed $name Model name or object
- * @param mixed $data if array and $name is not an object assume bake data, otherwise boolean.
- * @return string
- */
- public function bake($name, $data = array()) {
- if (is_object($name)) {
- if ($data == false) {
- $data = array();
- $data['associations'] = $this->doAssociations($name);
- $data['validate'] = $this->doValidation($name);
- }
- $data['primaryKey'] = $name->primaryKey;
- $data['useTable'] = $name->table;
- $data['useDbConfig'] = $name->useDbConfig;
- $data['name'] = $name = $name->name;
- } else {
- $data['name'] = $name;
- }
- $defaults = array(
- 'associations' => array(),
- 'validate' => array(),
- 'primaryKey' => 'id',
- 'useTable' => null,
- 'useDbConfig' => 'default',
- 'displayField' => null
- );
- $data = array_merge($defaults, $data);
-
- $pluginPath = '';
- if ($this->plugin) {
- $pluginPath = $this->plugin . '.';
- }
-
- $this->Template->set($data);
- $this->Template->set(array(
- 'plugin' => $this->plugin,
- 'pluginPath' => $pluginPath
- ));
- $out = $this->Template->generate('classes', 'model');
-
- $path = $this->getPath();
- $filename = $path . $name . '.php';
- $this->out("\n" . __d('cake_console', 'Baking model class for %s...', $name), 1, Shell::QUIET);
- $this->createFile($filename, $out);
- ClassRegistry::flush();
- return $out;
- }
-
-/**
- * Assembles and writes a unit test file
- *
- * @param string $className Model class name
- * @return string
- */
- public function bakeTest($className) {
- $this->Test->interactive = $this->interactive;
- $this->Test->plugin = $this->plugin;
- $this->Test->connection = $this->connection;
- return $this->Test->bake('Model', $className);
- }
-
-/**
- * outputs the a list of possible models or controllers from database
- *
- * @param string $useDbConfig Database configuration name
- * @return array
- */
- public function listAll($useDbConfig = null) {
- $this->_tables = (array)$this->getAllTables($useDbConfig);
-
- $this->_modelNames = array();
- $count = count($this->_tables);
- for ($i = 0; $i < $count; $i++) {
- $this->_modelNames[] = $this->_modelName($this->_tables[$i]);
- }
- if ($this->interactive === true) {
- $this->out(__d('cake_console', 'Possible Models based on your current database:'));
- for ($i = 0; $i < $count; $i++) {
- $this->out($i + 1 . ". " . $this->_modelNames[$i]);
- }
- }
- return $this->_tables;
- }
-
-/**
- * Interact with the user to determine the table name of a particular model
- *
- * @param string $modelName Name of the model you want a table for.
- * @param string $useDbConfig Name of the database config you want to get tables from.
- * @return string Table name
- */
- public function getTable($modelName, $useDbConfig = null) {
- $useTable = Inflector::tableize($modelName);
- if (in_array($modelName, $this->_modelNames)) {
- $modelNames = array_flip($this->_modelNames);
- $useTable = $this->_tables[$modelNames[$modelName]];
- }
-
- if ($this->interactive === true) {
- if (!isset($useDbConfig)) {
- $useDbConfig = $this->connection;
- }
- $db = ConnectionManager::getDataSource($useDbConfig);
- $fullTableName = $db->fullTableName($useTable, false);
- $tableIsGood = false;
- if (array_search($useTable, $this->_tables) === false) {
- $this->out();
- $this->out(__d('cake_console', "Given your model named '%s',\nCake would expect a database table named '%s'", $modelName, $fullTableName));
- $tableIsGood = $this->in(__d('cake_console', 'Do you want to use this table?'), array('y', 'n'), 'y');
- }
- if (strtolower($tableIsGood) == 'n') {
- $useTable = $this->in(__d('cake_console', 'What is the name of the table?'));
- }
- }
- return $useTable;
- }
-
-/**
- * Get an Array of all the tables in the supplied connection
- * will halt the script if no tables are found.
- *
- * @param string $useDbConfig Connection name to scan.
- * @return array Array of tables in the database.
- */
- public function getAllTables($useDbConfig = null) {
- if (!isset($useDbConfig)) {
- $useDbConfig = $this->connection;
- }
-
- $tables = array();
- $db = ConnectionManager::getDataSource($useDbConfig);
- $db->cacheSources = false;
- $usePrefix = empty($db->config['prefix']) ? '' : $db->config['prefix'];
- if ($usePrefix) {
- foreach ($db->listSources() as $table) {
- if (!strncmp($table, $usePrefix, strlen($usePrefix))) {
- $tables[] = substr($table, strlen($usePrefix));
- }
- }
- } else {
- $tables = $db->listSources();
- }
- if (empty($tables)) {
- $this->err(__d('cake_console', 'Your database does not have any tables.'));
- $this->_stop();
- }
- return $tables;
- }
-
-/**
- * Forces the user to specify the model he wants to bake, and returns the selected model name.
- *
- * @param string $useDbConfig Database config name
- * @return string the model name
- */
- public function getName($useDbConfig = null) {
- $this->listAll($useDbConfig);
-
- $enteredModel = '';
-
- while ($enteredModel == '') {
- $enteredModel = $this->in(__d('cake_console', "Enter a number from the list above,\n" .
- "type in the name of another model, or 'q' to exit"), null, 'q');
-
- if ($enteredModel === 'q') {
- $this->out(__d('cake_console', 'Exit'));
- $this->_stop();
- }
-
- if ($enteredModel == '' || intval($enteredModel) > count($this->_modelNames)) {
- $this->err(__d('cake_console', "The model name you supplied was empty,\n" .
- "or the number you selected was not an option. Please try again."));
- $enteredModel = '';
- }
- }
- if (intval($enteredModel) > 0 && intval($enteredModel) <= count($this->_modelNames)) {
- $currentModelName = $this->_modelNames[intval($enteredModel) - 1];
- } else {
- $currentModelName = $enteredModel;
- }
- return $currentModelName;
- }
-
-/**
- * get the option parser.
- *
- * @return void
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- return $parser->description(
- __d('cake_console', 'Bake models.')
- )->addArgument('name', array(
- 'help' => __d('cake_console', 'Name of the model to bake. Can use Plugin.name to bake plugin models.')
- ))->addSubcommand('all', array(
- 'help' => __d('cake_console', 'Bake all model files with associations and validation.')
- ))->addOption('plugin', array(
- 'short' => 'p',
- 'help' => __d('cake_console', 'Plugin to bake the model into.')
- ))->addOption('connection', array(
- 'short' => 'c',
- 'help' => __d('cake_console', 'The connection the model table is on.')
- ))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.'));
- }
-
-/**
- * Interact with FixtureTask to automatically bake fixtures when baking models.
- *
- * @param string $className Name of class to bake fixture for
- * @param string $useTable Optional table name for fixture to use.
- * @return void
- * @see FixtureTask::bake
- */
- public function bakeFixture($className, $useTable = null) {
- $this->Fixture->interactive = $this->interactive;
- $this->Fixture->connection = $this->connection;
- $this->Fixture->plugin = $this->plugin;
- $this->Fixture->bake($className, $useTable);
- }
-
-}
diff --git a/lib/Cake/Console/Command/Task/PluginTask.php b/lib/Cake/Console/Command/Task/PluginTask.php
deleted file mode 100644
index a10e072ce0d..00000000000
--- a/lib/Cake/Console/Command/Task/PluginTask.php
+++ /dev/null
@@ -1,196 +0,0 @@
-path = current(App::path('plugins'));
- }
-
-/**
- * Execution method always used for tasks
- *
- * @return void
- */
- public function execute() {
- if (isset($this->args[0])) {
- $plugin = Inflector::camelize($this->args[0]);
- $pluginPath = $this->_pluginPath($plugin);
- if (is_dir($pluginPath)) {
- $this->out(__d('cake_console', 'Plugin: %s', $plugin));
- $this->out(__d('cake_console', 'Path: %s', $pluginPath));
- } else {
- $this->_interactive($plugin);
- }
- } else {
- return $this->_interactive();
- }
- }
-
-/**
- * Interactive interface
- *
- * @param string $plugin
- * @return void
- */
- protected function _interactive($plugin = null) {
- while ($plugin === null) {
- $plugin = $this->in(__d('cake_console', 'Enter the name of the plugin in CamelCase format'));
- }
-
- if (!$this->bake($plugin)) {
- $this->error(__d('cake_console', "An error occurred trying to bake: %s in %s", $plugin, $this->path . $plugin));
- }
- }
-
-/**
- * Bake the plugin, create directories and files
- *
- * @param string $plugin Name of the plugin in CamelCased format
- * @return boolean
- */
- public function bake($plugin) {
- $pathOptions = App::path('plugins');
- if (count($pathOptions) > 1) {
- $this->findPath($pathOptions);
- }
- $this->hr();
- $this->out(__d('cake_console', "Plugin Name: %s", $plugin));
- $this->out(__d('cake_console', "Plugin Directory: %s", $this->path . $plugin));
- $this->hr();
-
- $looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n', 'q'), 'y');
-
- if (strtolower($looksGood) == 'y') {
- $Folder = new Folder($this->path . $plugin);
- $directories = array(
- 'Config' . DS . 'Schema',
- 'Model' . DS . 'Behavior',
- 'Model' . DS . 'Datasource',
- 'Console' . DS . 'Command' . DS . 'Task',
- 'Controller' . DS . 'Component',
- 'Lib',
- 'View' . DS . 'Helper',
- 'Test' . DS . 'Case' . DS . 'Controller' . DS . 'Component',
- 'Test' . DS . 'Case' . DS . 'View' . DS . 'Helper',
- 'Test' . DS . 'Case' . DS . 'Model' . DS . 'Behavior',
- 'Test' . DS . 'Fixture',
- 'Vendor',
- 'webroot'
- );
-
- foreach ($directories as $directory) {
- $dirPath = $this->path . $plugin . DS . $directory;
- $Folder->create($dirPath);
- $File = new File($dirPath . DS . 'empty', true);
- }
-
- foreach ($Folder->messages() as $message) {
- $this->out($message, 1, Shell::VERBOSE);
- }
-
- $errors = $Folder->errors();
- if (!empty($errors)) {
- return false;
- }
-
- $controllerFileName = $plugin . 'AppController.php';
-
- $out = "createFile($this->path . $plugin . DS . 'Controller' . DS . $controllerFileName, $out);
-
- $modelFileName = $plugin . 'AppModel.php';
-
- $out = "createFile($this->path . $plugin . DS . 'Model' . DS . $modelFileName, $out);
-
- $this->hr();
- $this->out(__d('cake_console', 'Created: %s in %s', $plugin, $this->path . $plugin), 2);
- }
-
- return true;
- }
-
-/**
- * find and change $this->path to the user selection
- *
- * @param array $pathOptions
- * @return string plugin path
- */
- public function findPath($pathOptions) {
- $valid = false;
- foreach ($pathOptions as $i => $path) {
- if (!is_dir($path)) {
- array_splice($pathOptions, $i, 1);
- }
- }
- $max = count($pathOptions);
- while (!$valid) {
- foreach ($pathOptions as $i => $option) {
- $this->out($i + 1 . '. ' . $option);
- }
- $prompt = __d('cake_console', 'Choose a plugin path from the paths above.');
- $choice = $this->in($prompt);
- if (intval($choice) > 0 && intval($choice) <= $max) {
- $valid = true;
- }
- }
- $this->path = $pathOptions[$choice - 1];
- }
-
-/**
- * get the option parser for the plugin task
- *
- * @return void
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- return $parser->description(__d('cake_console',
- 'Create the directory structure, AppModel and AppController classes for a new plugin. ' .
- 'Can create plugins in any of your bootstrapped plugin paths.'
- ))->addArgument('name', array(
- 'help' => __d('cake_console', 'CamelCased name of the plugin to create.')
- ));
- }
-
-}
diff --git a/lib/Cake/Console/Command/Task/ProjectTask.php b/lib/Cake/Console/Command/Task/ProjectTask.php
deleted file mode 100644
index 92135906a1d..00000000000
--- a/lib/Cake/Console/Command/Task/ProjectTask.php
+++ /dev/null
@@ -1,434 +0,0 @@
-args[0])) {
- $project = $this->args[0];
- }
-
- while (!$project) {
- $prompt = __d('cake_console', "What is the path to the project you want to bake?");
- $project = $this->in($prompt, null, APP . 'myapp');
- }
-
- if ($project && !Folder::isAbsolute($project) && isset($_SERVER['PWD'])) {
- $project = $_SERVER['PWD'] . DS . $project;
- }
-
- $response = false;
- while ($response == false && is_dir($project) === true && file_exists($project . 'Config' . 'core.php')) {
- $prompt = __d('cake_console', 'A project already exists in this location: %s Overwrite?', $project);
- $response = $this->in($prompt, array('y', 'n'), 'n');
- if (strtolower($response) === 'n') {
- $response = $project = false;
- }
- }
-
- $success = true;
- if ($this->bake($project)) {
- $path = Folder::slashTerm($project);
- if ($this->createHome($path)) {
- $this->out(__d('cake_console', ' * Welcome page created'));
- } else {
- $this->err(__d('cake_console', 'The Welcome page was NOT created'));
- $success = false;
- }
-
- if ($this->securitySalt($path) === true) {
- $this->out(__d('cake_console', ' * Random hash key created for \'Security.salt\''));
- } else {
- $this->err(__d('cake_console', 'Unable to generate random hash for \'Security.salt\', you should change it in %s', APP . 'Config' . DS . 'core.php'));
- $success = false;
- }
-
- if ($this->securityCipherSeed($path) === true) {
- $this->out(__d('cake_console', ' * Random seed created for \'Security.cipherSeed\''));
- } else {
- $this->err(__d('cake_console', 'Unable to generate random seed for \'Security.cipherSeed\', you should change it in %s', APP . 'Config' . DS . 'core.php'));
- $success = false;
- }
-
- if ($this->consolePath($path) === true) {
- $this->out(__d('cake_console', ' * app/Console/cake.php path set.'));
- } else {
- $this->err(__d('cake_console', 'Unable to set console path for app/Console.'));
- $success = false;
- }
-
- $hardCode = false;
- if ($this->cakeOnIncludePath()) {
- $this->out(__d('cake_console', 'CakePHP is on your `include_path`. CAKE_CORE_INCLUDE_PATH will be set, but commented out. '));
- } else {
- $this->out(__d('cake_console', 'CakePHP is not on your `include_path`, CAKE_CORE_INCLUDE_PATH will be hard coded. '));
- $this->out(__d('cake_console', 'You can fix this by adding CakePHP to your `include_path`.'));
- $hardCode = true;
- }
- $success = $this->corePath($path, $hardCode) === true;
- if ($success) {
- $this->out(__d('cake_console', ' * CAKE_CORE_INCLUDE_PATH set to %s in webroot/index.php', CAKE_CORE_INCLUDE_PATH));
- $this->out(__d('cake_console', ' * CAKE_CORE_INCLUDE_PATH set to %s in webroot/test.php', CAKE_CORE_INCLUDE_PATH));
- } else {
- $this->err(__d('cake_console', 'Unable to set CAKE_CORE_INCLUDE_PATH, you should change it in %s', $path . 'webroot' . DS . 'index.php'));
- $success = false;
- }
- if ($success && $hardCode) {
- $this->out(__d('cake_console', ' * Remember to check these values after moving to production server '));
- }
-
- $Folder = new Folder($path);
- if (!$Folder->chmod($path . 'tmp', 0777)) {
- $this->err(__d('cake_console', 'Could not set permissions on %s', $path . DS . 'tmp'));
- $this->out(__d('cake_console', 'chmod -R 0777 %s', $path . DS . 'tmp'));
- $success = false;
- }
- if ($success) {
- $this->out(__d('cake_console', 'Project baked successfully! '));
- } else {
- $this->out(__d('cake_console', 'Project baked but with some issues. .'));
- }
- return $path;
- }
- }
-
-/**
- * Checks PHP's include_path for CakePHP.
- *
- * @return boolean Indicates whether or not CakePHP exists on include_path
- */
- public function cakeOnIncludePath() {
- $paths = explode(PATH_SEPARATOR, ini_get('include_path'));
- foreach ($paths as $path) {
- if (file_exists($path . DS . 'Cake' . DS . 'bootstrap.php')) {
- return true;
- }
- }
- return false;
- }
-
-/**
- * Looks for a skeleton template of a Cake application,
- * and if not found asks the user for a path. When there is a path
- * this method will make a deep copy of the skeleton to the project directory.
- *
- * @param string $path Project path
- * @param string $skel Path to copy from
- * @param string $skip array of directories to skip when copying
- * @return mixed
- */
- public function bake($path, $skel = null, $skip = array('empty')) {
- if (!$skel && !empty($this->params['skel'])) {
- $skel = $this->params['skel'];
- }
- while (!$skel) {
- $skel = $this->in(
- __d('cake_console', "What is the path to the directory layout you wish to copy?"),
- null,
- CAKE . 'Console' . DS . 'Templates' . DS . 'skel'
- );
- if (!$skel) {
- $this->err(__d('cake_console', 'The directory path you supplied was empty. Please try again.'));
- } else {
- while (is_dir($skel) === false) {
- $skel = $this->in(
- __d('cake_console', 'Directory path does not exist please choose another:'),
- null,
- CAKE . 'Console' . DS . 'Templates' . DS . 'skel'
- );
- }
- }
- }
-
- $app = basename($path);
-
- $this->out(__d('cake_console', 'Skel Directory : ') . $skel);
- $this->out(__d('cake_console', 'Will be copied to : ') . $path);
- $this->hr();
-
- $looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n', 'q'), 'y');
-
- switch (strtolower($looksGood)) {
- case 'y':
- $Folder = new Folder($skel);
- if (!empty($this->params['empty'])) {
- $skip = array();
- }
-
- if ($Folder->copy(array('to' => $path, 'skip' => $skip))) {
- $this->hr();
- $this->out(__d('cake_console', 'Created: %s in %s', $app, $path));
- $this->hr();
- } else {
- $this->err(__d('cake_console', "Could not create '%s' properly.", $app));
- return false;
- }
-
- foreach ($Folder->messages() as $message) {
- $this->out(String::wrap(' * ' . $message), 1, Shell::VERBOSE);
- }
-
- return true;
- case 'n':
- unset($this->args[0]);
- $this->execute();
- return false;
- case 'q':
- $this->out(__d('cake_console', 'Bake Aborted. '));
- return false;
- }
- }
-
-/**
- * Writes a file with a default home page to the project.
- *
- * @param string $dir Path to project
- * @return boolean Success
- */
- public function createHome($dir) {
- $app = basename($dir);
- $path = $dir . 'View' . DS . 'Pages' . DS;
- $source = CAKE . 'Console' . DS . 'Templates' . DS . 'default' . DS . 'views' . DS . 'home.ctp';
- include $source;
- return $this->createFile($path . 'home.ctp', $output);
- }
-
-/**
- * Generates the correct path to the CakePHP libs that are generating the project
- * and points app/console/cake.php to the right place
- *
- * @param string $path Project path.
- * @return boolean success
- */
- public function consolePath($path) {
- $File = new File($path . 'Console' . DS . 'cake.php');
- $contents = $File->read();
- if (preg_match('/(__CAKE_PATH__)/', $contents, $match)) {
- $root = strpos(CAKE_CORE_INCLUDE_PATH, '/') === 0 ? " \$ds . '" : "'";
- $replacement = $root . str_replace(DS, "' . \$ds . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "'";
- $result = str_replace($match[0], $replacement, $contents);
- if ($File->write($result)) {
- return true;
- }
- return false;
- }
- return false;
- }
-
-/**
- * Generates and writes 'Security.salt'
- *
- * @param string $path Project path
- * @return boolean Success
- */
- public function securitySalt($path) {
- $File = new File($path . 'Config' . DS . 'core.php');
- $contents = $File->read();
- if (preg_match('/([\s]*Configure::write\(\'Security.salt\',[\s\'A-z0-9]*\);)/', $contents, $match)) {
- $string = Security::generateAuthKey();
- $result = str_replace($match[0], "\t" . 'Configure::write(\'Security.salt\', \'' . $string . '\');', $contents);
- if ($File->write($result)) {
- return true;
- }
- return false;
- }
- return false;
- }
-
-/**
- * Generates and writes 'Security.cipherSeed'
- *
- * @param string $path Project path
- * @return boolean Success
- */
- public function securityCipherSeed($path) {
- $File = new File($path . 'Config' . DS . 'core.php');
- $contents = $File->read();
- if (preg_match('/([\s]*Configure::write\(\'Security.cipherSeed\',[\s\'A-z0-9]*\);)/', $contents, $match)) {
- App::uses('Security', 'Utility');
- $string = substr(bin2hex(Security::generateAuthKey()), 0, 30);
- $result = str_replace($match[0], "\t" . 'Configure::write(\'Security.cipherSeed\', \'' . $string . '\');', $contents);
- if ($File->write($result)) {
- return true;
- }
- return false;
- }
- return false;
- }
-
-/**
- * Generates and writes CAKE_CORE_INCLUDE_PATH
- *
- * @param string $path Project path
- * @param boolean $hardCode Wether or not define calls should be hardcoded.
- * @return boolean Success
- */
- public function corePath($path, $hardCode = true) {
- if (dirname($path) !== CAKE_CORE_INCLUDE_PATH) {
- $filename = $path . 'webroot' . DS . 'index.php';
- if (!$this->_replaceCorePath($filename, $hardCode)) {
- return false;
- }
- $filename = $path . 'webroot' . DS . 'test.php';
- if (!$this->_replaceCorePath($filename, $hardCode)) {
- return false;
- }
- return true;
- }
- }
-
-/**
- * Replaces the __CAKE_PATH__ placeholder in the template files.
- *
- * @param string $filename The filename to operate on.
- * @param boolean $hardCode Whether or not the define should be uncommented.
- * @return boolean Success
- */
- protected function _replaceCorePath($filename, $hardCode) {
- $contents = file_get_contents($filename);
-
- $root = strpos(CAKE_CORE_INCLUDE_PATH, '/') === 0 ? " DS . '" : "'";
- $corePath = $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "'";
-
- $result = str_replace('__CAKE_PATH__', $corePath, $contents, $count);
- if ($hardCode) {
- $result = str_replace('//define(\'CAKE_CORE', 'define(\'CAKE_CORE', $result);
- }
- if (!file_put_contents($filename, $result)) {
- return false;
- }
- if ($count == 0) {
- return false;
- }
- return true;
- }
-
-/**
- * Enables Configure::read('Routing.prefixes') in /app/Config/core.php
- *
- * @param string $name Name to use as admin routing
- * @return boolean Success
- */
- public function cakeAdmin($name) {
- $path = (empty($this->configPath)) ? APP . 'Config' . DS : $this->configPath;
- $File = new File($path . 'core.php');
- $contents = $File->read();
- if (preg_match('%(\s*[/]*Configure::write\(\'Routing.prefixes\',[\s\'a-z,\)\(]*\);)%', $contents, $match)) {
- $result = str_replace($match[0], "\n" . 'Configure::write(\'Routing.prefixes\', array(\'' . $name . '\'));', $contents);
- if ($File->write($result)) {
- Configure::write('Routing.prefixes', array($name));
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
-
-/**
- * Checks for Configure::read('Routing.prefixes') and forces user to input it if not enabled
- *
- * @return string Admin route to use
- */
- public function getPrefix() {
- $admin = '';
- $prefixes = Configure::read('Routing.prefixes');
- if (!empty($prefixes)) {
- if (count($prefixes) == 1) {
- return $prefixes[0] . '_';
- }
- if ($this->interactive) {
- $this->out();
- $this->out(__d('cake_console', 'You have more than one routing prefix configured'));
- }
- $options = array();
- foreach ($prefixes as $i => $prefix) {
- $options[] = $i + 1;
- if ($this->interactive) {
- $this->out($i + 1 . '. ' . $prefix);
- }
- }
- $selection = $this->in(__d('cake_console', 'Please choose a prefix to bake with.'), $options, 1);
- return $prefixes[$selection - 1] . '_';
- }
- if ($this->interactive) {
- $this->hr();
- $this->out(__d('cake_console', 'You need to enable Configure::write(\'Routing.prefixes\',array(\'admin\')) in /app/Config/core.php to use prefix routing.'));
- $this->out(__d('cake_console', 'What would you like the prefix route to be?'));
- $this->out(__d('cake_console', 'Example: www.example.com/admin/controller'));
- while ($admin == '') {
- $admin = $this->in(__d('cake_console', 'Enter a routing prefix:'), null, 'admin');
- }
- if ($this->cakeAdmin($admin) !== true) {
- $this->out(__d('cake_console', 'Unable to write to /app/Config/core.php.'));
- $this->out(__d('cake_console', 'You need to enable Configure::write(\'Routing.prefixes\',array(\'admin\')) in /app/Config/core.php to use prefix routing.'));
- $this->_stop();
- }
- return $admin . '_';
- }
- return '';
- }
-
-/**
- * get the option parser.
- *
- * @return ConsoleOptionParser
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- return $parser->description(
- __d('cake_console', 'Generate a new CakePHP project skeleton.')
- )->addArgument('name', array(
- 'help' => __d('cake_console', 'Application directory to make, if it starts with "/" the path is absolute.')
- ))->addOption('empty', array(
- 'boolean' => true,
- 'help' => __d('cake_console', 'Create empty files in each of the directories. Good if you are using git')
- ))->addOption('skel', array(
- 'default' => current(App::core('Console')) . 'Templates' . DS . 'skel',
- 'help' => __d('cake_console', 'The directory layout to use for the new application skeleton. Defaults to cake/Console/Templates/skel of CakePHP used to create the project.')
- ));
- }
-
-}
diff --git a/lib/Cake/Console/Command/Task/TemplateTask.php b/lib/Cake/Console/Command/Task/TemplateTask.php
deleted file mode 100644
index d9a0e3f4378..00000000000
--- a/lib/Cake/Console/Command/Task/TemplateTask.php
+++ /dev/null
@@ -1,218 +0,0 @@
- $path
- *
- * @var array
- */
- public $templatePaths = array();
-
-/**
- * Initialize callback. Setup paths for the template task.
- *
- * @return void
- */
- public function initialize() {
- $this->templatePaths = $this->_findThemes();
- }
-
-/**
- * Find the paths to all the installed shell themes in the app.
- *
- * Bake themes are directories not named `skel` inside a `Console/Templates` path.
- *
- * @return array Array of bake themes that are installed.
- */
- protected function _findThemes() {
- $paths = array();
- $core = current(App::core('Console'));
- $separator = DS === '/' ? '/' : '\\\\';
- $core = preg_replace('#shells' . $separator . '$#', '', $core);
-
- $Folder = new Folder($core . 'Templates' . DS . 'default');
-
- $contents = $Folder->read();
- $themeFolders = $contents[0];
-
- $plugins = App::objects('plugin');
- $paths[] = $core;
- foreach ($plugins as $plugin) {
- $paths[] = $this->_pluginPath($plugin) . 'Console' . DS;
- }
-
- $paths = array_merge($paths, App::path('Console'));
-
- // TEMPORARY TODO remove when all paths are DS terminated
- foreach ($paths as $i => $path) {
- $paths[$i] = rtrim($path, DS) . DS;
- }
-
- $themes = array();
- foreach ($paths as $path) {
- $Folder = new Folder($path . 'Templates', false);
- $contents = $Folder->read();
- $subDirs = $contents[0];
- foreach ($subDirs as $dir) {
- if (empty($dir) || preg_match('@^skel$|_skel$@', $dir)) {
- continue;
- }
- $Folder = new Folder($path . 'Templates' . DS . $dir);
- $contents = $Folder->read();
- $subDirs = $contents[0];
- if (array_intersect($contents[0], $themeFolders)) {
- $templateDir = $path . 'Templates' . DS . $dir . DS;
- $themes[$dir] = $templateDir;
- }
- }
- }
- return $themes;
- }
-
-/**
- * Set variable values to the template scope
- *
- * @param string|array $one A string or an array of data.
- * @param mixed $two Value in case $one is a string (which then works as the key).
- * Unused if $one is an associative array, otherwise serves as the values to $one's keys.
- * @return void
- */
- public function set($one, $two = null) {
- if (is_array($one)) {
- if (is_array($two)) {
- $data = array_combine($one, $two);
- } else {
- $data = $one;
- }
- } else {
- $data = array($one => $two);
- }
-
- if ($data == null) {
- return false;
- }
- $this->templateVars = $data + $this->templateVars;
- }
-
-/**
- * Runs the template
- *
- * @param string $directory directory / type of thing you want
- * @param string $filename template name
- * @param array $vars Additional vars to set to template scope.
- * @return string contents of generated code template
- */
- public function generate($directory, $filename, $vars = null) {
- if ($vars !== null) {
- $this->set($vars);
- }
- if (empty($this->templatePaths)) {
- $this->initialize();
- }
- $themePath = $this->getThemePath();
- $templateFile = $this->_findTemplate($themePath, $directory, $filename);
- if ($templateFile) {
- extract($this->templateVars);
- ob_start();
- ob_implicit_flush(0);
- include $templateFile;
- $content = ob_get_clean();
- return $content;
- }
- return '';
- }
-
-/**
- * Find the theme name for the current operation.
- * If there is only one theme in $templatePaths it will be used.
- * If there is a -theme param in the cli args, it will be used.
- * If there is more than one installed theme user interaction will happen
- *
- * @return string returns the path to the selected theme.
- */
- public function getThemePath() {
- if (count($this->templatePaths) == 1) {
- $paths = array_values($this->templatePaths);
- return $paths[0];
- }
- if (!empty($this->params['theme']) && isset($this->templatePaths[$this->params['theme']])) {
- return $this->templatePaths[$this->params['theme']];
- }
-
- $this->hr();
- $this->out(__d('cake_console', 'You have more than one set of templates installed.'));
- $this->out(__d('cake_console', 'Please choose the template set you wish to use:'));
- $this->hr();
-
- $i = 1;
- $indexedPaths = array();
- foreach ($this->templatePaths as $key => $path) {
- $this->out($i . '. ' . $key);
- $indexedPaths[$i] = $path;
- $i++;
- }
- $index = $this->in(__d('cake_console', 'Which bake theme would you like to use?'), range(1, $i - 1), 1);
- $themeNames = array_keys($this->templatePaths);
- $this->params['theme'] = $themeNames[$index - 1];
- return $indexedPaths[$index];
- }
-
-/**
- * Find a template inside a directory inside a path.
- * Will scan all other theme dirs if the template is not found in the first directory.
- *
- * @param string $path The initial path to look for the file on. If it is not found fallbacks will be used.
- * @param string $directory Subdirectory to look for ie. 'views', 'objects'
- * @param string $filename lower_case_underscored filename you want.
- * @return string filename will exit program if template is not found.
- */
- protected function _findTemplate($path, $directory, $filename) {
- $themeFile = $path . $directory . DS . $filename . '.ctp';
- if (file_exists($themeFile)) {
- return $themeFile;
- }
- foreach ($this->templatePaths as $path) {
- $templatePath = $path . $directory . DS . $filename . '.ctp';
- if (file_exists($templatePath)) {
- return $templatePath;
- }
- }
- $this->err(__d('cake_console', 'Could not find template for %s', $filename));
- return false;
- }
-
-}
diff --git a/lib/Cake/Console/Command/Task/TestTask.php b/lib/Cake/Console/Command/Task/TestTask.php
deleted file mode 100644
index e90239e0107..00000000000
--- a/lib/Cake/Console/Command/Task/TestTask.php
+++ /dev/null
@@ -1,535 +0,0 @@
- 'Model',
- 'Controller' => 'Controller',
- 'Component' => 'Controller/Component',
- 'Behavior' => 'Model/Behavior',
- 'Helper' => 'View/Helper'
- );
-
-/**
- * Internal list of fixtures that have been added so far.
- *
- * @var array
- */
- protected $_fixtures = array();
-
-/**
- * Execution method always used for tasks
- *
- * @return void
- */
- public function execute() {
- parent::execute();
- if (empty($this->args)) {
- $this->_interactive();
- }
-
- if (count($this->args) == 1) {
- $this->_interactive($this->args[0]);
- }
-
- if (count($this->args) > 1) {
- $type = Inflector::underscore($this->args[0]);
- if ($this->bake($type, $this->args[1])) {
- $this->out('Done ');
- }
- }
- }
-
-/**
- * Handles interactive baking
- *
- * @param string $type
- * @return string|boolean
- */
- protected function _interactive($type = null) {
- $this->interactive = true;
- $this->hr();
- $this->out(__d('cake_console', 'Bake Tests'));
- $this->out(__d('cake_console', 'Path: %s', $this->getPath()));
- $this->hr();
-
- if ($type) {
- $type = Inflector::camelize($type);
- if (!isset($this->classTypes[$type])) {
- $this->error(__d('cake_console', 'Incorrect type provided. Please choose one of %s', implode(', ', array_keys($this->classTypes))));
- }
- } else {
- $type = $this->getObjectType();
- }
- $className = $this->getClassName($type);
- return $this->bake($type, $className);
- }
-
-/**
- * Completes final steps for generating data to create test case.
- *
- * @param string $type Type of object to bake test case for ie. Model, Controller
- * @param string $className the 'cake name' for the class ie. Posts for the PostsController
- * @return string|boolean
- */
- public function bake($type, $className) {
- $plugin = null;
- if ($this->plugin) {
- $plugin = $this->plugin . '.';
- }
-
- $realType = $this->mapType($type, $plugin);
- $fullClassName = $this->getRealClassName($type, $className);
-
- if ($this->typeCanDetectFixtures($type) && $this->isLoadableClass($realType, $fullClassName)) {
- $this->out(__d('cake_console', 'Bake is detecting possible fixtures...'));
- $testSubject = $this->buildTestSubject($type, $className);
- $this->generateFixtureList($testSubject);
- } elseif ($this->interactive) {
- $this->getUserFixtures();
- }
- App::uses($fullClassName, $realType);
-
- $methods = array();
- if (class_exists($fullClassName)) {
- $methods = $this->getTestableMethods($fullClassName);
- }
- $mock = $this->hasMockClass($type, $fullClassName);
- list($preConstruct, $construction, $postConstruct) = $this->generateConstructor($type, $fullClassName);
- $uses = $this->generateUses($type, $realType, $fullClassName);
-
- $this->out("\n" . __d('cake_console', 'Baking test case for %s %s ...', $className, $type), 1, Shell::QUIET);
-
- $this->Template->set('fixtures', $this->_fixtures);
- $this->Template->set('plugin', $plugin);
- $this->Template->set(compact(
- 'className', 'methods', 'type', 'fullClassName', 'mock',
- 'realType', 'preConstruct', 'postConstruct', 'construction',
- 'uses'
- ));
- $out = $this->Template->generate('classes', 'test');
-
- $filename = $this->testCaseFileName($type, $className);
- $made = $this->createFile($filename, $out);
- if ($made) {
- return $out;
- }
- return false;
- }
-
-/**
- * Interact with the user and get their chosen type. Can exit the script.
- *
- * @return string Users chosen type.
- */
- public function getObjectType() {
- $this->hr();
- $this->out(__d('cake_console', 'Select an object type:'));
- $this->hr();
-
- $keys = array();
- $i = 0;
- foreach ($this->classTypes as $option => $package) {
- $this->out(++$i . '. ' . $option);
- $keys[] = $i;
- }
- $keys[] = 'q';
- $selection = $this->in(__d('cake_console', 'Enter the type of object to bake a test for or (q)uit'), $keys, 'q');
- if ($selection == 'q') {
- return $this->_stop();
- }
- $types = array_keys($this->classTypes);
- return $types[$selection - 1];
- }
-
-/**
- * Get the user chosen Class name for the chosen type
- *
- * @param string $objectType Type of object to list classes for i.e. Model, Controller.
- * @return string Class name the user chose.
- */
- public function getClassName($objectType) {
- $type = ucfirst(strtolower($objectType));
- $typeLength = strlen($type);
- $type = $this->classTypes[$type];
- if ($this->plugin) {
- $plugin = $this->plugin . '.';
- $options = App::objects($plugin . $type);
- } else {
- $options = App::objects($type);
- }
- $this->out(__d('cake_console', 'Choose a %s class', $objectType));
- $keys = array();
- foreach ($options as $key => $option) {
- $this->out(++$key . '. ' . $option);
- $keys[] = $key;
- }
- while (empty($selection)) {
- $selection = $this->in(__d('cake_console', 'Choose an existing class, or enter the name of a class that does not exist'));
- if (is_numeric($selection) && isset($options[$selection - 1])) {
- $selection = $options[$selection - 1];
- }
- if ($type !== 'Model') {
- $selection = substr($selection, 0, $typeLength * - 1);
- }
- }
- return $selection;
- }
-
-/**
- * Checks whether the chosen type can find its own fixtures.
- * Currently only model, and controller are supported
- *
- * @param string $type The Type of object you are generating tests for eg. controller
- * @return boolean
- */
- public function typeCanDetectFixtures($type) {
- $type = strtolower($type);
- return in_array($type, array('controller', 'model'));
- }
-
-/**
- * Check if a class with the given package is loaded or can be loaded.
- *
- * @param string $package The package of object you are generating tests for eg. controller
- * @param string $class the Classname of the class the test is being generated for.
- * @return boolean
- */
- public function isLoadableClass($package, $class) {
- App::uses($class, $package);
- return class_exists($class);
- }
-
-/**
- * Construct an instance of the class to be tested.
- * So that fixtures can be detected
- *
- * @param string $type The Type of object you are generating tests for eg. controller
- * @param string $class the Classname of the class the test is being generated for.
- * @return object And instance of the class that is going to be tested.
- */
- public function &buildTestSubject($type, $class) {
- ClassRegistry::flush();
- App::import($type, $class);
- $class = $this->getRealClassName($type, $class);
- if (strtolower($type) == 'model') {
- $instance = ClassRegistry::init($class);
- } else {
- $instance = new $class();
- }
- return $instance;
- }
-
-/**
- * Gets the real class name from the cake short form. If the class name is already
- * suffixed with the type, the type will not be duplicated.
- *
- * @param string $type The Type of object you are generating tests for eg. controller
- * @param string $class the Classname of the class the test is being generated for.
- * @return string Real classname
- */
- public function getRealClassName($type, $class) {
- if (strtolower($type) == 'model' || empty($this->classTypes[$type])) {
- return $class;
- }
-
- $position = strpos($class, $type);
-
- if ($position !== false && strlen($class) - $position == strlen($type)) {
- return $class;
- }
- return $class . $type;
- }
-
-/**
- * Map the types that TestTask uses to concrete types that App::uses can use.
- *
- * @param string $type The type of thing having a test generated.
- * @param string $plugin The plugin name.
- * @return string
- * @throws CakeException When invalid object types are requested.
- */
- public function mapType($type, $plugin) {
- $type = ucfirst($type);
- if (empty($this->classTypes[$type])) {
- throw new CakeException(__d('cake_dev', 'Invalid object type.'));
- }
- $real = $this->classTypes[$type];
- if ($plugin) {
- $real = trim($plugin, '.') . '.' . $real;
- }
- return $real;
- }
-
-/**
- * Get methods declared in the class given.
- * No parent methods will be returned
- *
- * @param string $className Name of class to look at.
- * @return array Array of method names.
- */
- public function getTestableMethods($className) {
- $classMethods = get_class_methods($className);
- $parentMethods = get_class_methods(get_parent_class($className));
- $thisMethods = array_diff($classMethods, $parentMethods);
- $out = array();
- foreach ($thisMethods as $method) {
- if (substr($method, 0, 1) != '_' && $method != strtolower($className)) {
- $out[] = $method;
- }
- }
- return $out;
- }
-
-/**
- * Generate the list of fixtures that will be required to run this test based on
- * loaded models.
- *
- * @param object $subject The object you want to generate fixtures for.
- * @return array Array of fixtures to be included in the test.
- */
- public function generateFixtureList($subject) {
- $this->_fixtures = array();
- if (is_a($subject, 'Model')) {
- $this->_processModel($subject);
- } elseif (is_a($subject, 'Controller')) {
- $this->_processController($subject);
- }
- return array_values($this->_fixtures);
- }
-
-/**
- * Process a model recursively and pull out all the
- * model names converting them to fixture names.
- *
- * @param Model $subject A Model class to scan for associations and pull fixtures off of.
- * @return void
- */
- protected function _processModel($subject) {
- $this->_addFixture($subject->name);
- $associated = $subject->getAssociated();
- foreach ($associated as $alias => $type) {
- $className = $subject->{$alias}->name;
- if (!isset($this->_fixtures[$className])) {
- $this->_processModel($subject->{$alias});
- }
- if ($type == 'hasAndBelongsToMany') {
- if (!empty($subject->hasAndBelongsToMany[$alias]['with'])) {
- list($plugin, $joinModel) = pluginSplit($subject->hasAndBelongsToMany[$alias]['with']);
- } else {
- $joinModel = Inflector::classify($subject->hasAndBelongsToMany[$alias]['joinTable']);
- }
- if (!isset($this->_fixtures[$joinModel])) {
- $this->_processModel($subject->{$joinModel});
- }
- }
- }
- }
-
-/**
- * Process all the models attached to a controller
- * and generate a fixture list.
- *
- * @param Controller $subject A controller to pull model names off of.
- * @return void
- */
- protected function _processController($subject) {
- $subject->constructClasses();
- $models = array(Inflector::classify($subject->name));
- if (!empty($subject->uses)) {
- $models = $subject->uses;
- }
- foreach ($models as $model) {
- $this->_processModel($subject->{$model});
- }
- }
-
-/**
- * Add classname to the fixture list.
- * Sets the app. or plugin.plugin_name. prefix.
- *
- * @param string $name Name of the Model class that a fixture might be required for.
- * @return void
- */
- protected function _addFixture($name) {
- $parent = get_parent_class($name);
- $prefix = 'app.';
- if (strtolower($parent) != 'appmodel' && strtolower(substr($parent, - 8)) == 'appmodel') {
- $pluginName = substr($parent, 0, strlen($parent) - 8);
- $prefix = 'plugin.' . Inflector::underscore($pluginName) . '.';
- }
- $fixture = $prefix . Inflector::underscore($name);
- $this->_fixtures[$name] = $fixture;
- }
-
-/**
- * Interact with the user to get additional fixtures they want to use.
- *
- * @return array Array of fixtures the user wants to add.
- */
- public function getUserFixtures() {
- $proceed = $this->in(__d('cake_console', 'Bake could not detect fixtures, would you like to add some?'), array('y', 'n'), 'n');
- $fixtures = array();
- if (strtolower($proceed) == 'y') {
- $fixtureList = $this->in(__d('cake_console', "Please provide a comma separated list of the fixtures names you'd like to use.\nExample: 'app.comment, app.post, plugin.forums.post'"));
- $fixtureListTrimmed = str_replace(' ', '', $fixtureList);
- $fixtures = explode(',', $fixtureListTrimmed);
- }
- $this->_fixtures = array_merge($this->_fixtures, $fixtures);
- return $fixtures;
- }
-
-/**
- * Is a mock class required for this type of test?
- * Controllers require a mock class.
- *
- * @param string $type The type of object tests are being generated for eg. controller.
- * @return boolean
- */
- public function hasMockClass($type) {
- $type = strtolower($type);
- return $type == 'controller';
- }
-
-/**
- * Generate a constructor code snippet for the type and classname
- *
- * @param string $type The Type of object you are generating tests for eg. controller
- * @param string $fullClassName The Classname of the class the test is being generated for.
- * @return array Constructor snippets for the thing you are building.
- */
- public function generateConstructor($type, $fullClassName) {
- $type = strtolower($type);
- $pre = $post = '';
- if ($type == 'model') {
- $construct = "ClassRegistry::init('$fullClassName');\n";
- }
- if ($type == 'behavior') {
- $construct = "new $fullClassName();\n";
- }
- if ($type == 'controller') {
- $className = substr($fullClassName, 0, strlen($fullClassName) - 10);
- $construct = "new Test$fullClassName();\n";
- $post = "\$this->{$className}->constructClasses();\n";
- }
- if ($type == 'helper') {
- $pre = "\$View = new View();\n";
- $construct = "new {$fullClassName}(\$View);\n";
- }
- if ($type == 'component') {
- $pre = "\$Collection = new ComponentCollection();\n";
- $construct = "new {$fullClassName}(\$Collection);\n";
- }
- return array($pre, $construct, $post);
- }
-
-/**
- * Generate the uses() calls for a type & classname
- *
- * @param string $type The Type of object you are generating tests for eg. controller
- * @param string $realType The package name for the class.
- * @param string $className The Classname of the class the test is being generated for.
- * @return array An array containing used classes
- */
- public function generateUses($type, $realType, $className) {
- $uses = array();
- if ($type == 'component') {
- $uses[] = array('ComponentCollection', 'Controller');
- $uses[] = array('Component', 'Controller');
- }
- if ($type == 'helper') {
- $uses[] = array('View', 'View');
- $uses[] = array('Helper', 'View');
- }
- $uses[] = array($className, $realType);
- return $uses;
- }
-
-/**
- * Make the filename for the test case. resolve the suffixes for controllers
- * and get the plugin path if needed.
- *
- * @param string $type The Type of object you are generating tests for eg. controller
- * @param string $className the Classname of the class the test is being generated for.
- * @return string filename the test should be created on.
- */
- public function testCaseFileName($type, $className) {
- $path = $this->getPath() . 'Case' . DS;
- $type = Inflector::camelize($type);
- if (isset($this->classTypes[$type])) {
- $path .= $this->classTypes[$type] . DS;
- }
- $className = $this->getRealClassName($type, $className);
- return str_replace('/', DS, $path) . Inflector::camelize($className) . 'Test.php';
- }
-
-/**
- * get the option parser.
- *
- * @return void
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- return $parser->description(__d('cake_console', 'Bake test case skeletons for classes.'))
- ->addArgument('type', array(
- 'help' => __d('cake_console', 'Type of class to bake, can be any of the following: controller, model, helper, component or behavior.'),
- 'choices' => array(
- 'Controller', 'controller',
- 'Model', 'model',
- 'Helper', 'helper',
- 'Component', 'component',
- 'Behavior', 'behavior'
- )
- ))->addArgument('name', array(
- 'help' => __d('cake_console', 'An existing class to bake tests for.')
- ))->addOption('plugin', array(
- 'short' => 'p',
- 'help' => __d('cake_console', 'CamelCased name of the plugin to bake tests for.')
- ))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.'));
- }
-
-}
diff --git a/lib/Cake/Console/Command/Task/ViewTask.php b/lib/Cake/Console/Command/Task/ViewTask.php
deleted file mode 100644
index 8baf4263e24..00000000000
--- a/lib/Cake/Console/Command/Task/ViewTask.php
+++ /dev/null
@@ -1,468 +0,0 @@
-path = current(App::path('View'));
- }
-
-/**
- * Execution method always used for tasks
- *
- * @return mixed
- */
- public function execute() {
- parent::execute();
- if (empty($this->args)) {
- $this->_interactive();
- }
- if (empty($this->args[0])) {
- return;
- }
- if (!isset($this->connection)) {
- $this->connection = 'default';
- }
- $action = null;
- $this->controllerName = $this->_controllerName($this->args[0]);
-
- $this->Project->interactive = false;
- if (strtolower($this->args[0]) == 'all') {
- return $this->all();
- }
-
- if (isset($this->args[1])) {
- $this->template = $this->args[1];
- }
- if (isset($this->args[2])) {
- $action = $this->args[2];
- }
- if (!$action) {
- $action = $this->template;
- }
- if ($action) {
- return $this->bake($action, true);
- }
-
- $vars = $this->_loadController();
- $methods = $this->_methodsToBake();
-
- foreach ($methods as $method) {
- $content = $this->getContent($method, $vars);
- if ($content) {
- $this->bake($method, $content);
- }
- }
- }
-
-/**
- * Get a list of actions that can / should have views baked for them.
- *
- * @return array Array of action names that should be baked
- */
- protected function _methodsToBake() {
- $methods = array_diff(
- array_map('strtolower', get_class_methods($this->controllerName . 'Controller')),
- array_map('strtolower', get_class_methods('AppController'))
- );
- $scaffoldActions = false;
- if (empty($methods)) {
- $scaffoldActions = true;
- $methods = $this->scaffoldActions;
- }
- $adminRoute = $this->Project->getPrefix();
- foreach ($methods as $i => $method) {
- if ($adminRoute && !empty($this->params['admin'])) {
- if ($scaffoldActions) {
- $methods[$i] = $adminRoute . $method;
- continue;
- } elseif (strpos($method, $adminRoute) === false) {
- unset($methods[$i]);
- }
- }
- if ($method[0] === '_' || $method == strtolower($this->controllerName . 'Controller')) {
- unset($methods[$i]);
- }
- }
- return $methods;
- }
-
-/**
- * Bake All views for All controllers.
- *
- * @return void
- */
- public function all() {
- $this->Controller->interactive = false;
- $tables = $this->Controller->listAll($this->connection, false);
-
- $actions = null;
- if (isset($this->args[1])) {
- $actions = array($this->args[1]);
- }
- $this->interactive = false;
- foreach ($tables as $table) {
- $model = $this->_modelName($table);
- $this->controllerName = $this->_controllerName($model);
- App::uses($model, 'Model');
- if (class_exists($model)) {
- $vars = $this->_loadController();
- if (!$actions) {
- $actions = $this->_methodsToBake();
- }
- $this->bakeActions($actions, $vars);
- $actions = null;
- }
- }
- }
-
-/**
- * Handles interactive baking
- *
- * @return void
- */
- protected function _interactive() {
- $this->hr();
- $this->out(sprintf("Bake View\nPath: %s", $this->getPath()));
- $this->hr();
-
- $this->DbConfig->interactive = $this->Controller->interactive = $this->interactive = true;
-
- if (empty($this->connection)) {
- $this->connection = $this->DbConfig->getConfig();
- }
-
- $this->Controller->connection = $this->connection;
- $this->controllerName = $this->Controller->getName();
-
- $prompt = __d('cake_console', "Would you like bake to build your views interactively?\nWarning: Choosing no will overwrite %s views if it exist.", $this->controllerName);
- $interactive = $this->in($prompt, array('y', 'n'), 'n');
-
- if (strtolower($interactive) == 'n') {
- $this->interactive = false;
- }
-
- $prompt = __d('cake_console', "Would you like to create some CRUD views\n(index, add, view, edit) for this controller?\nNOTE: Before doing so, you'll need to create your controller\nand model classes (including associated models).");
- $wannaDoScaffold = $this->in($prompt, array('y', 'n'), 'y');
-
- $wannaDoAdmin = $this->in(__d('cake_console', "Would you like to create the views for admin routing?"), array('y', 'n'), 'n');
-
- if (strtolower($wannaDoScaffold) == 'y' || strtolower($wannaDoAdmin) == 'y') {
- $vars = $this->_loadController();
- if (strtolower($wannaDoScaffold) == 'y') {
- $actions = $this->scaffoldActions;
- $this->bakeActions($actions, $vars);
- }
- if (strtolower($wannaDoAdmin) == 'y') {
- $admin = $this->Project->getPrefix();
- $regularActions = $this->scaffoldActions;
- $adminActions = array();
- foreach ($regularActions as $action) {
- $adminActions[] = $admin . $action;
- }
- $this->bakeActions($adminActions, $vars);
- }
- $this->hr();
- $this->out();
- $this->out(__d('cake_console', "View Scaffolding Complete.\n"));
- } else {
- $this->customAction();
- }
- }
-
-/**
- * Loads Controller and sets variables for the template
- * Available template variables
- * 'modelClass', 'primaryKey', 'displayField', 'singularVar', 'pluralVar',
- * 'singularHumanName', 'pluralHumanName', 'fields', 'foreignKeys',
- * 'belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany'
- *
- * @return array Returns an variables to be made available to a view template
- */
- protected function _loadController() {
- if (!$this->controllerName) {
- $this->err(__d('cake_console', 'Controller not found'));
- }
-
- $plugin = null;
- if ($this->plugin) {
- $plugin = $this->plugin . '.';
- }
-
- $controllerClassName = $this->controllerName . 'Controller';
- App::uses($controllerClassName, $plugin . 'Controller');
- if (!class_exists($controllerClassName)) {
- $file = $controllerClassName . '.php';
- $this->err(__d('cake_console', "The file '%s' could not be found.\nIn order to bake a view, you'll need to first create the controller.", $file));
- $this->_stop();
- }
- $controllerObj = new $controllerClassName();
- $controllerObj->plugin = $this->plugin;
- $controllerObj->constructClasses();
- $modelClass = $controllerObj->modelClass;
- $modelObj = $controllerObj->{$controllerObj->modelClass};
-
- if ($modelObj) {
- $primaryKey = $modelObj->primaryKey;
- $displayField = $modelObj->displayField;
- $singularVar = Inflector::variable($modelClass);
- $singularHumanName = $this->_singularHumanName($this->controllerName);
- $schema = $modelObj->schema(true);
- $fields = array_keys($schema);
- $associations = $this->_associations($modelObj);
- } else {
- $primaryKey = $displayField = null;
- $singularVar = Inflector::variable(Inflector::singularize($this->controllerName));
- $singularHumanName = $this->_singularHumanName($this->controllerName);
- $fields = $schema = $associations = array();
- }
- $pluralVar = Inflector::variable($this->controllerName);
- $pluralHumanName = $this->_pluralHumanName($this->controllerName);
-
- return compact('modelClass', 'schema', 'primaryKey', 'displayField', 'singularVar', 'pluralVar',
- 'singularHumanName', 'pluralHumanName', 'fields', 'associations');
- }
-
-/**
- * Bake a view file for each of the supplied actions
- *
- * @param array $actions Array of actions to make files for.
- * @param array $vars
- * @return void
- */
- public function bakeActions($actions, $vars) {
- foreach ($actions as $action) {
- $content = $this->getContent($action, $vars);
- $this->bake($action, $content);
- }
- }
-
-/**
- * handle creation of baking a custom action view file
- *
- * @return void
- */
- public function customAction() {
- $action = '';
- while ($action == '') {
- $action = $this->in(__d('cake_console', 'Action Name? (use lowercase_underscored function name)'));
- if ($action == '') {
- $this->out(__d('cake_console', 'The action name you supplied was empty. Please try again.'));
- }
- }
- $this->out();
- $this->hr();
- $this->out(__d('cake_console', 'The following view will be created:'));
- $this->hr();
- $this->out(__d('cake_console', 'Controller Name: %s', $this->controllerName));
- $this->out(__d('cake_console', 'Action Name: %s', $action));
- $this->out(__d('cake_console', 'Path: %s', $this->getPath() . $this->controllerName . DS . Inflector::underscore($action) . ".ctp"));
- $this->hr();
- $looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n'), 'y');
- if (strtolower($looksGood) == 'y') {
- $this->bake($action, ' ');
- $this->_stop();
- } else {
- $this->out(__d('cake_console', 'Bake Aborted.'));
- }
- }
-
-/**
- * Assembles and writes bakes the view file.
- *
- * @param string $action Action to bake
- * @param string $content Content to write
- * @return boolean Success
- */
- public function bake($action, $content = '') {
- if ($content === true) {
- $content = $this->getContent($action);
- }
- if (empty($content)) {
- return false;
- }
- $this->out("\n" . __d('cake_console', 'Baking `%s` view file...', $action), 1, Shell::QUIET);
- $path = $this->getPath();
- $filename = $path . $this->controllerName . DS . Inflector::underscore($action) . '.ctp';
- return $this->createFile($filename, $content);
- }
-
-/**
- * Builds content from template and variables
- *
- * @param string $action name to generate content to
- * @param array $vars passed for use in templates
- * @return string content from template
- */
- public function getContent($action, $vars = null) {
- if (!$vars) {
- $vars = $this->_loadController();
- }
-
- $this->Template->set('action', $action);
- $this->Template->set('plugin', $this->plugin);
- $this->Template->set($vars);
- $template = $this->getTemplate($action);
- if ($template) {
- return $this->Template->generate('views', $template);
- }
- return false;
- }
-
-/**
- * Gets the template name based on the action name
- *
- * @param string $action name
- * @return string template name
- */
- public function getTemplate($action) {
- if ($action != $this->template && in_array($action, $this->noTemplateActions)) {
- return false;
- }
- if (!empty($this->template) && $action != $this->template) {
- return $this->template;
- }
- $themePath = $this->Template->getThemePath();
- if (file_exists($themePath . 'views' . DS . $action . '.ctp')) {
- return $action;
- }
- $template = $action;
- $prefixes = Configure::read('Routing.prefixes');
- foreach ((array)$prefixes as $prefix) {
- if (strpos($template, $prefix) !== false) {
- $template = str_replace($prefix . '_', '', $template);
- }
- }
- if (in_array($template, array('add', 'edit'))) {
- $template = 'form';
- } elseif (preg_match('@(_add|_edit)$@', $template)) {
- $template = str_replace(array('_add', '_edit'), '_form', $template);
- }
- return $template;
- }
-
-/**
- * get the option parser for this task
- *
- * @return ConsoleOptionParser
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- return $parser->description(
- __d('cake_console', 'Bake views for a controller, using built-in or custom templates.')
- )->addArgument('controller', array(
- 'help' => __d('cake_console', 'Name of the controller views to bake. Can be Plugin.name as a shortcut for plugin baking.')
- ))->addArgument('action', array(
- 'help' => __d('cake_console', "Will bake a single action's file. core templates are (index, add, edit, view)")
- ))->addArgument('alias', array(
- 'help' => __d('cake_console', 'Will bake the template in but create the filename after .')
- ))->addOption('plugin', array(
- 'short' => 'p',
- 'help' => __d('cake_console', 'Plugin to bake the view into.')
- ))->addOption('admin', array(
- 'help' => __d('cake_console', 'Set to only bake views for a prefix in Routing.prefixes'),
- 'boolean' => true
- ))->addOption('connection', array(
- 'short' => 'c',
- 'help' => __d('cake_console', 'The connection the connected model is on.')
- ))->addSubcommand('all', array(
- 'help' => __d('cake_console', 'Bake all CRUD action views for all controllers. Requires models and controllers to exist.')
- ))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.'));
- }
-
-/**
- * Returns associations for controllers models.
- *
- * @param Model $model
- * @return array $associations
- */
- protected function _associations(Model $model) {
- $keys = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
- $associations = array();
-
- foreach ($keys as $key => $type) {
- foreach ($model->{$type} as $assocKey => $assocData) {
- list($plugin, $modelClass) = pluginSplit($assocData['className']);
- $associations[$type][$assocKey]['primaryKey'] = $model->{$assocKey}->primaryKey;
- $associations[$type][$assocKey]['displayField'] = $model->{$assocKey}->displayField;
- $associations[$type][$assocKey]['foreignKey'] = $assocData['foreignKey'];
- $associations[$type][$assocKey]['controller'] = Inflector::pluralize(Inflector::underscore($modelClass));
- $associations[$type][$assocKey]['fields'] = array_keys($model->{$assocKey}->schema(true));
- }
- }
- return $associations;
- }
-
-}
diff --git a/lib/Cake/Console/Command/TestShell.php b/lib/Cake/Console/Command/TestShell.php
deleted file mode 100644
index a3b410ba09c..00000000000
--- a/lib/Cake/Console/Command/TestShell.php
+++ /dev/null
@@ -1,434 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @since CakePHP(tm) v 1.2.0.4433
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('Shell', 'Console');
-App::uses('CakeTestSuiteDispatcher', 'TestSuite');
-App::uses('CakeTestSuiteCommand', 'TestSuite');
-App::uses('CakeTestLoader', 'TestSuite');
-
-/**
- * Provides a CakePHP wrapper around PHPUnit.
- * Adds in CakePHP's fixtures and gives access to plugin, app and core test cases
- *
- * @package Cake.Console.Command
- */
-class TestShell extends Shell {
-
-/**
- * Dispatcher object for the run.
- *
- * @var CakeTestDispatcher
- */
- protected $_dispatcher = null;
-
-/**
- * get the option parser for the test suite.
- *
- * @return void
- */
- public function getOptionParser() {
- $parser = new ConsoleOptionParser($this->name);
- $parser->description(array(
- __d('cake_console', 'The CakePHP Testsuite allows you to run test cases from the command line'),
- ))->addArgument('category', array(
- 'help' => __d('cake_console', 'The category for the test, or test file, to test.'),
- 'required' => false,
- ))->addArgument('file', array(
- 'help' => __d('cake_console', 'The path to the file, or test file, to test.'),
- 'required' => false,
- ))->addOption('log-junit', array(
- 'help' => __d('cake_console', ' Log test execution in JUnit XML format to file.'),
- 'default' => false
- ))->addOption('log-json', array(
- 'help' => __d('cake_console', ' Log test execution in TAP format to file.'),
- 'default' => false
- ))->addOption('log-tap', array(
- 'help' => __d('cake_console', ' Log test execution in TAP format to file.'),
- 'default' => false
- ))->addOption('log-dbus', array(
- 'help' => __d('cake_console', 'Log test execution to DBUS.'),
- 'default' => false
- ))->addOption('coverage-html', array(
- 'help' => __d('cake_console', ' Generate code coverage report in HTML format.'),
- 'default' => false
- ))->addOption('coverage-clover', array(
- 'help' => __d('cake_console', ' Write code coverage data in Clover XML format.'),
- 'default' => false
- ))->addOption('testdox-html', array(
- 'help' => __d('cake_console', ' Write agile documentation in HTML format to file.'),
- 'default' => false
- ))->addOption('testdox-text', array(
- 'help' => __d('cake_console', ' Write agile documentation in Text format to file.'),
- 'default' => false
- ))->addOption('filter', array(
- 'help' => __d('cake_console', ' Filter which tests to run.'),
- 'default' => false
- ))->addOption('group', array(
- 'help' => __d('cake_console', ' Only runs tests from the specified group(s).'),
- 'default' => false
- ))->addOption('exclude-group', array(
- 'help' => __d('cake_console', ' Exclude tests from the specified group(s).'),
- 'default' => false
- ))->addOption('list-groups', array(
- 'help' => __d('cake_console', 'List available test groups.'),
- 'boolean' => true
- ))->addOption('loader', array(
- 'help' => __d('cake_console', 'TestSuiteLoader implementation to use.'),
- 'default' => false
- ))->addOption('repeat', array(
- 'help' => __d('cake_console', ' Runs the test(s) repeatedly.'),
- 'default' => false
- ))->addOption('tap', array(
- 'help' => __d('cake_console', 'Report test execution progress in TAP format.'),
- 'boolean' => true
- ))->addOption('testdox', array(
- 'help' => __d('cake_console', 'Report test execution progress in TestDox format.'),
- 'default' => false,
- 'boolean' => true
- ))->addOption('no-colors', array(
- 'help' => __d('cake_console', 'Do not use colors in output.'),
- 'boolean' => true
- ))->addOption('stderr', array(
- 'help' => __d('cake_console', 'Write to STDERR instead of STDOUT.'),
- 'boolean' => true
- ))->addOption('stop-on-error', array(
- 'help' => __d('cake_console', 'Stop execution upon first error or failure.'),
- 'boolean' => true
- ))->addOption('stop-on-failure', array(
- 'help' => __d('cake_console', 'Stop execution upon first failure.'),
- 'boolean' => true
- ))->addOption('stop-on-skipped ', array(
- 'help' => __d('cake_console', 'Stop execution upon first skipped test.'),
- 'boolean' => true
- ))->addOption('stop-on-incomplete', array(
- 'help' => __d('cake_console', 'Stop execution upon first incomplete test.'),
- 'boolean' => true
- ))->addOption('strict', array(
- 'help' => __d('cake_console', 'Mark a test as incomplete if no assertions are made.'),
- 'boolean' => true
- ))->addOption('wait', array(
- 'help' => __d('cake_console', 'Waits for a keystroke after each test.'),
- 'boolean' => true
- ))->addOption('process-isolation', array(
- 'help' => __d('cake_console', 'Run each test in a separate PHP process.'),
- 'boolean' => true
- ))->addOption('no-globals-backup', array(
- 'help' => __d('cake_console', 'Do not backup and restore $GLOBALS for each test.'),
- 'boolean' => true
- ))->addOption('static-backup ', array(
- 'help' => __d('cake_console', 'Backup and restore static attributes for each test.'),
- 'boolean' => true
- ))->addOption('syntax-check', array(
- 'help' => __d('cake_console', 'Try to check source files for syntax errors.'),
- 'boolean' => true
- ))->addOption('bootstrap', array(
- 'help' => __d('cake_console', ' A "bootstrap" PHP file that is run before the tests.'),
- 'default' => false
- ))->addOption('configuration', array(
- 'help' => __d('cake_console', ' Read configuration from XML file.'),
- 'default' => false
- ))->addOption('no-configuration', array(
- 'help' => __d('cake_console', 'Ignore default configuration file (phpunit.xml).'),
- 'boolean' => true
- ))->addOption('include-path', array(
- 'help' => __d('cake_console', ' Prepend PHP include_path with given path(s).'),
- 'default' => false
- ))->addOption('directive', array(
- 'help' => __d('cake_console', 'key[=value] Sets a php.ini value.'),
- 'default' => false
- ))->addOption('fixture', array(
- 'help' => __d('cake_console', 'Choose a custom fixture manager.'),
- ))->addOption('debug', array(
- 'help' => __d('cake_console', 'More verbose output.'),
- ));
-
- return $parser;
- }
-
-/**
- * Initialization method installs PHPUnit and loads all plugins
- *
- * @return void
- * @throws Exception
- */
- public function initialize() {
- $this->_dispatcher = new CakeTestSuiteDispatcher();
- $sucess = $this->_dispatcher->loadTestFramework();
- if (!$sucess) {
- throw new Exception(__d('cake_dev', 'Please install PHPUnit framework (http://www.phpunit.de) '));
- }
- }
-
-/**
- * Parse the CLI options into an array CakeTestDispatcher can use.
- *
- * @return array Array of params for CakeTestDispatcher
- */
- protected function _parseArgs() {
- if (empty($this->args)) {
- return;
- }
- $params = array(
- 'core' => false,
- 'app' => false,
- 'plugin' => null,
- 'output' => 'text',
- );
-
- if (strpos($this->args[0], '.php')) {
- $category = $this->_mapFileToCategory($this->args[0]);
- $params['case'] = $this->_mapFileToCase($this->args[0], $category);
- } else {
- $category = $this->args[0];
- if (isset($this->args[1])) {
- $params['case'] = $this->args[1];
- }
- }
-
- if ($category === 'core') {
- $params['core'] = true;
- } elseif ($category === 'app') {
- $params['app'] = true;
- } else {
- $params['plugin'] = $category;
- }
-
- return $params;
- }
-
-/**
- * Converts the options passed to the shell as options for the PHPUnit cli runner
- *
- * @return array Array of params for CakeTestDispatcher
- */
- protected function _runnerOptions() {
- $options = array();
- $params = $this->params;
- unset($params['help']);
-
- if (!empty($params['no-colors'])) {
- unset($params['no-colors'], $params['colors']);
- } else {
- $params['colors'] = true;
- }
-
- foreach ($params as $param => $value) {
- if ($value === false) {
- continue;
- }
- $options[] = '--' . $param;
- if (is_string($value)) {
- $options[] = $value;
- }
- }
- return $options;
- }
-
-/**
- * Main entry point to this shell
- *
- * @return void
- */
- public function main() {
- $this->out(__d('cake_console', 'CakePHP Test Shell'));
- $this->hr();
-
- $args = $this->_parseArgs();
-
- if (empty($args['case'])) {
- return $this->available();
- }
-
- $this->_run($args, $this->_runnerOptions());
- }
-
-/**
- * Runs the test case from $runnerArgs
- *
- * @param array $runnerArgs list of arguments as obtained from _parseArgs()
- * @param array $options list of options as constructed by _runnerOptions()
- * @return void
- */
- protected function _run($runnerArgs, $options = array()) {
- restore_error_handler();
- restore_error_handler();
-
- $testCli = new CakeTestSuiteCommand('CakeTestLoader', $runnerArgs);
- $testCli->run($options);
- }
-
-/**
- * Shows a list of available test cases and gives the option to run one of them
- *
- * @return void
- */
- public function available() {
- $params = $this->_parseArgs();
- $testCases = CakeTestLoader::generateTestList($params);
- $app = $params['app'];
- $plugin = $params['plugin'];
-
- $title = "Core Test Cases:";
- $category = 'core';
- if ($app) {
- $title = "App Test Cases:";
- $category = 'app';
- } elseif ($plugin) {
- $title = Inflector::humanize($plugin) . " Test Cases:";
- $category = $plugin;
- }
-
- if (empty($testCases)) {
- $this->out(__d('cake_console', "No test cases available \n\n"));
- return $this->out($this->OptionParser->help());
- }
-
- $this->out($title);
- $i = 1;
- $cases = array();
- foreach ($testCases as $testCaseFile => $testCase) {
- $case = str_replace('Test.php', '', $testCase);
- $this->out("[$i] $case");
- $cases[$i] = $case;
- $i++;
- }
-
- while ($choice = $this->in(__d('cake_console', 'What test case would you like to run?'), null, 'q')) {
- if (is_numeric($choice) && isset($cases[$choice])) {
- $this->args[0] = $category;
- $this->args[1] = $cases[$choice];
- $this->_run($this->_parseArgs(), $this->_runnerOptions());
- break;
- }
-
- if (is_string($choice) && in_array($choice, $cases)) {
- $this->args[0] = $category;
- $this->args[1] = $choice;
- $this->_run($this->_parseArgs(), $this->_runnerOptions());
- break;
- }
-
- if ($choice == 'q') {
- break;
- }
- }
- }
-
-/**
- * Find the test case for the passed file. The file could itself be a test.
- *
- * @param mixed $file
- * @param mixed $category
- * @param mixed $throwOnMissingFile
- * @access protected
- * @return array(type, case)
- * @throws Exception
- */
- protected function _mapFileToCase($file, $category, $throwOnMissingFile = true) {
- if (!$category || (substr($file, -4) !== '.php')) {
- return false;
- }
-
- $_file = realpath($file);
- if ($_file) {
- $file = $_file;
- }
-
- $testFile = $testCase = null;
-
- if (preg_match('@Test[\\\/]@', $file)) {
-
- if (substr($file, -8) === 'Test.php') {
-
- $testCase = substr($file, 0, -8);
- $testCase = str_replace(DS, '/', $testCase);
-
- if ($testCase = preg_replace('@.*Test\/Case\/@', '', $testCase)) {
-
- if ($category === 'core') {
- $testCase = str_replace('lib/Cake', '', $testCase);
- }
-
- return $testCase;
- }
-
- throw new Exception(__d('cake_dev', 'Test case %s cannot be run via this shell', $testFile));
- }
- }
-
- $file = substr($file, 0, -4);
- if ($category === 'core') {
-
- $testCase = str_replace(DS, '/', $file);
- $testCase = preg_replace('@.*lib/Cake/@', '', $file);
- $testCase[0] = strtoupper($testCase[0]);
- $testFile = CAKE . 'Test/Case/' . $testCase . 'Test.php';
-
- if (!file_exists($testFile) && $throwOnMissingFile) {
- throw new Exception(__d('cake_dev', 'Test case %s not found', $testFile));
- }
-
- return $testCase;
- }
-
- if ($category === 'app') {
- $testFile = str_replace(APP, APP . 'Test/Case/', $file) . 'Test.php';
- } else {
- $testFile = preg_replace(
- "@((?:plugins|Plugin)[\\/]{$category}[\\/])(.*)$@",
- '\1Test/Case/\2Test.php',
- $file
- );
- }
-
- if (!file_exists($testFile) && $throwOnMissingFile) {
- throw new Exception(__d('cake_dev', 'Test case %s not found', $testFile));
- }
-
- $testCase = substr($testFile, 0, -8);
- $testCase = str_replace(DS, '/', $testCase);
- $testCase = preg_replace('@.*Test/Case/@', '', $testCase);
-
- return $testCase;
- }
-
-/**
- * For the given file, what category of test is it? returns app, core or the name of the plugin
- *
- * @param mixed $file
- * @access protected
- * @return string
- */
- protected function _mapFileToCategory($file) {
- $_file = realpath($file);
- if ($_file) {
- $file = $_file;
- }
-
- $file = str_replace(DS, '/', $file);
- if (strpos($file, 'lib/Cake/') !== false) {
- return 'core';
- } elseif (preg_match('@(?:plugins|Plugin)/([^/]*)@', $file, $match)) {
- return $match[1];
- }
- return 'app';
- }
-
-}
diff --git a/lib/Cake/Console/Command/TestsuiteShell.php b/lib/Cake/Console/Command/TestsuiteShell.php
deleted file mode 100644
index 71decbeff27..00000000000
--- a/lib/Cake/Console/Command/TestsuiteShell.php
+++ /dev/null
@@ -1,101 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @since CakePHP(tm) v 1.2.0.4433
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('TestShell', 'Console/Command');
-App::uses('AppShell', 'Console/Command');
-App::uses('CakeTestSuiteDispatcher', 'TestSuite');
-App::uses('CakeTestSuiteCommand', 'TestSuite');
-App::uses('CakeTestLoader', 'TestSuite');
-
-/**
- * Provides a CakePHP wrapper around PHPUnit.
- * Adds in CakePHP's fixtures and gives access to plugin, app and core test cases
- *
- * @package Cake.Console.Command
- */
-class TestsuiteShell extends TestShell {
-
-/**
- * get the option parser for the test suite.
- *
- * @return void
- */
- public function getOptionParser() {
- $parser = parent::getOptionParser();
- $parser->description(array(
- __d('cake_console', 'The CakePHP Testsuite allows you to run test cases from the command line'),
- __d('cake_console', 'This shell is for backwards-compatibility only '),
- __d('cake_console', 'use the test shell instead')
- ));
-
- return $parser;
- }
-
-/**
- * Parse the CLI options into an array CakeTestDispatcher can use.
- *
- * @return array Array of params for CakeTestDispatcher
- */
- protected function _parseArgs() {
- if (empty($this->args)) {
- return;
- }
- $params = array(
- 'core' => false,
- 'app' => false,
- 'plugin' => null,
- 'output' => 'text',
- );
-
- $category = $this->args[0];
-
- if ($category == 'core') {
- $params['core'] = true;
- } elseif ($category == 'app') {
- $params['app'] = true;
- } elseif ($category != 'core') {
- $params['plugin'] = $category;
- }
-
- if (isset($this->args[1])) {
- $params['case'] = $this->args[1];
- }
- return $params;
- }
-
-/**
- * Main entry point to this shell
- *
- * @return void
- */
- public function main() {
- $this->out(__d('cake_console', 'CakePHP Test Shell'));
- $this->hr();
-
- $args = $this->_parseArgs();
-
- if (empty($args['case'])) {
- return $this->available();
- }
-
- $this->_run($args, $this->_runnerOptions());
- }
-
-}
diff --git a/lib/Cake/Console/Command/UpgradeShell.php b/lib/Cake/Console/Command/UpgradeShell.php
deleted file mode 100644
index a7e8e10a040..00000000000
--- a/lib/Cake/Console/Command/UpgradeShell.php
+++ /dev/null
@@ -1,858 +0,0 @@
- 'Controller',
- 'Component' => 'Controller/Component',
- 'Model' => 'Model',
- 'Behavior' => 'Model/Behavior',
- 'Datasource' => 'Model/Datasource',
- 'Dbo' => 'Model/Datasource/Database',
- 'View' => 'View',
- 'Helper' => 'View/Helper',
- 'Shell' => 'Console/Command',
- 'Task' => 'Console/Command/Task',
- 'Case' => 'Test/Case',
- 'Fixture' => 'Test/Fixture',
- 'Error' => 'Lib/Error',
- );
-
-/**
- * Shell startup, prints info message about dry run.
- *
- * @return void
- */
- public function startup() {
- parent::startup();
- if ($this->params['dry-run']) {
- $this->out(__d('cake_console', 'Dry-run mode enabled! '), 1, Shell::QUIET);
- }
- if ($this->params['git'] && !is_dir('.git')) {
- $this->out(__d('cake_console', 'No git repository detected! '), 1, Shell::QUIET);
- }
- }
-
-/**
- * Run all upgrade steps one at a time
- *
- * @return void
- */
- public function all() {
- foreach ($this->OptionParser->subcommands() as $command) {
- $name = $command->name();
- if ($name === 'all') {
- continue;
- }
- $this->out(__d('cake_console', 'Running %s', $name));
- $this->$name();
- }
- }
-
-/**
- * Update tests.
- *
- * - Update tests class names to FooTest rather than FooTestCase.
- *
- * @return void
- */
- public function tests() {
- $this->_paths = array(APP . 'tests' . DS);
- if (!empty($this->params['plugin'])) {
- $this->_paths = array(App::pluginPath($this->params['plugin']) . 'tests' . DS);
- }
- $patterns = array(
- array(
- '*TestCase extends CakeTestCase to *Test extends CakeTestCase',
- '/([a-zA-Z]*Test)Case extends CakeTestCase/',
- '\1 extends CakeTestCase'
- ),
- );
-
- $this->_filesRegexpUpdate($patterns);
- }
-
-/**
- * Move files and folders to their new homes
- *
- * Moves folders containing files which cannot necessarily be auto-detected (libs and templates)
- * and then looks for all php files except vendors, and moves them to where Cake 2.0 expects
- * to find them.
- *
- * @return void
- */
- public function locations() {
- $cwd = getcwd();
-
- if (!empty($this->params['plugin'])) {
- chdir(App::pluginPath($this->params['plugin']));
- }
-
- if (is_dir('plugins')) {
- $Folder = new Folder('plugins');
- list($plugins) = $Folder->read();
- foreach ($plugins as $plugin) {
- chdir($cwd . DS . 'plugins' . DS . $plugin);
- $this->locations();
- }
- $this->_files = array();
- chdir($cwd);
- }
- $moves = array(
- 'config' => 'Config',
- 'Config' . DS . 'schema' => 'Config' . DS . 'Schema',
- 'libs' => 'Lib',
- 'tests' => 'Test',
- 'views' => 'View',
- 'models' => 'Model',
- 'Model' . DS . 'behaviors' => 'Model' . DS . 'Behavior',
- 'Model' . DS . 'datasources' => 'Model' . DS . 'Datasource',
- 'Test' . DS . 'cases' => 'Test' . DS . 'Case',
- 'Test' . DS . 'fixtures' => 'Test' . DS . 'Fixture',
- 'vendors' . DS . 'shells' . DS . 'templates' => 'Console' . DS . 'Templates',
- );
- foreach ($moves as $old => $new) {
- if (is_dir($old)) {
- $this->out(__d('cake_console', 'Moving %s to %s', $old, $new));
- if (!$this->params['dry-run']) {
- if ($this->params['git']) {
- exec('git mv -f ' . escapeshellarg($old) . ' ' . escapeshellarg($old . '__'));
- exec('git mv -f ' . escapeshellarg($old . '__') . ' ' . escapeshellarg($new));
- } else {
- $Folder = new Folder($old);
- $Folder->move($new);
- }
- }
- }
- }
-
- $this->_moveViewFiles();
- $this->_moveAppClasses();
-
- $sourceDirs = array(
- '.' => array('recursive' => false),
- 'Console',
- 'controllers',
- 'Controller',
- 'Lib' => array('checkFolder' => false),
- 'models',
- 'Model',
- 'tests',
- 'Test' => array('regex' => '@class (\S*Test) extends CakeTestCase@'),
- 'views',
- 'View',
- 'vendors/shells',
- );
-
- $defaultOptions = array(
- 'recursive' => true,
- 'checkFolder' => true,
- 'regex' => '@class (\S*) .*(\s|\v)*{@i'
- );
- foreach ($sourceDirs as $dir => $options) {
- if (is_numeric($dir)) {
- $dir = $options;
- $options = array();
- }
- $options = array_merge($defaultOptions, $options);
- $this->_movePhpFiles($dir, $options);
- }
- }
-
-/**
- * Update helpers.
- *
- * - Converts helpers usage to new format.
- *
- * @return void
- */
- public function helpers() {
- $this->_paths = array_diff(App::path('views'), App::core('views'));
-
- if (!empty($this->params['plugin'])) {
- $this->_paths = array(App::pluginPath($this->params['plugin']) . 'views' . DS);
- }
-
- $patterns = array();
- App::build(array(
- 'View/Helper' => App::core('View/Helper'),
- ), App::APPEND);
- $helpers = App::objects('helper');
- $plugins = App::objects('plugin');
- $pluginHelpers = array();
- foreach ($plugins as $plugin) {
- CakePlugin::load($plugin);
- $pluginHelpers = array_merge(
- $pluginHelpers,
- App::objects('helper', App::pluginPath($plugin) . DS . 'views' . DS . 'helpers' . DS, false)
- );
- }
- $helpers = array_merge($pluginHelpers, $helpers);
- foreach ($helpers as $helper) {
- $helper = preg_replace('/Helper$/', '', $helper);
- $oldHelper = strtolower(substr($helper, 0, 1)) . substr($helper, 1);
- $patterns[] = array(
- "\${$oldHelper} to \$this->{$helper}",
- "/\\\${$oldHelper}->/",
- "\\\$this->{$helper}->"
- );
- }
-
- $this->_filesRegexpUpdate($patterns);
- }
-
-/**
- * Update i18n.
- *
- * - Removes extra true param.
- * - Add the echo to __*() calls that didn't need them before.
- *
- * @return void
- */
- public function i18n() {
- $this->_paths = array(
- APP
- );
- if (!empty($this->params['plugin'])) {
- $this->_paths = array(App::pluginPath($this->params['plugin']));
- }
-
- $patterns = array(
- array(
- '_filesRegexpUpdate($patterns);
- }
-
-/**
- * Upgrade the removed basics functions.
- *
- * - a(*) -> array(*)
- * - e(*) -> echo *
- * - ife(*, *, *) -> !empty(*) ? * : *
- * - a(*) -> array(*)
- * - r(*, *, *) -> str_replace(*, *, *)
- * - up(*) -> strtoupper(*)
- * - low(*, *, *) -> strtolower(*)
- * - getMicrotime() -> microtime(true)
- *
- * @return void
- */
- public function basics() {
- $this->_paths = array(
- APP
- );
- if (!empty($this->params['plugin'])) {
- $this->_paths = array(App::pluginPath($this->params['plugin']));
- }
- $patterns = array(
- array(
- 'a(*) -> array(*)',
- '/\ba\((.*)\)/',
- 'array(\1)'
- ),
- array(
- 'e(*) -> echo *',
- '/\be\((.*)\)/',
- 'echo \1'
- ),
- array(
- 'ife(*, *, *) -> !empty(*) ? * : *',
- '/ife\((.*), (.*), (.*)\)/',
- '!empty(\1) ? \2 : \3'
- ),
- array(
- 'r(*, *, *) -> str_replace(*, *, *)',
- '/\br\(/',
- 'str_replace('
- ),
- array(
- 'up(*) -> strtoupper(*)',
- '/\bup\(/',
- 'strtoupper('
- ),
- array(
- 'low(*) -> strtolower(*)',
- '/\blow\(/',
- 'strtolower('
- ),
- array(
- 'getMicrotime() -> microtime(true)',
- '/getMicrotime\(\)/',
- 'microtime(true)'
- ),
- );
- $this->_filesRegexpUpdate($patterns);
- }
-
-/**
- * Update the properties moved to CakeRequest.
- *
- * @return void
- */
- public function request() {
- $views = array_diff(App::path('views'), App::core('views'));
- $controllers = array_diff(App::path('controllers'), App::core('controllers'), array(APP));
- $components = array_diff(App::path('components'), App::core('components'));
-
- $this->_paths = array_merge($views, $controllers, $components);
-
- if (!empty($this->params['plugin'])) {
- $pluginPath = App::pluginPath($this->params['plugin']);
- $this->_paths = array(
- $pluginPath . 'controllers' . DS,
- $pluginPath . 'controllers' . DS . 'components' . DS,
- $pluginPath . 'views' . DS,
- );
- }
- $patterns = array(
- array(
- '$this->data -> $this->request->data',
- '/(\$this->data\b(?!\())/',
- '$this->request->data'
- ),
- array(
- '$this->params -> $this->request->params',
- '/(\$this->params\b(?!\())/',
- '$this->request->params'
- ),
- array(
- '$this->webroot -> $this->request->webroot',
- '/(\$this->webroot\b(?!\())/',
- '$this->request->webroot'
- ),
- array(
- '$this->base -> $this->request->base',
- '/(\$this->base\b(?!\())/',
- '$this->request->base'
- ),
- array(
- '$this->here -> $this->request->here',
- '/(\$this->here\b(?!\())/',
- '$this->request->here'
- ),
- array(
- '$this->action -> $this->request->action',
- '/(\$this->action\b(?!\())/',
- '$this->request->action'
- ),
- );
- $this->_filesRegexpUpdate($patterns);
- }
-
-/**
- * Update Configure::read() calls with no params.
- *
- * @return void
- */
- public function configure() {
- $this->_paths = array(
- APP
- );
- if (!empty($this->params['plugin'])) {
- $this->_paths = array(App::pluginPath($this->params['plugin']));
- }
- $patterns = array(
- array(
- "Configure::read() -> Configure::read('debug')",
- '/Configure::read\(\)/',
- 'Configure::read(\'debug\')'
- ),
- );
- $this->_filesRegexpUpdate($patterns);
- }
-
-/**
- * constants
- *
- * @return void
- */
- public function constants() {
- $this->_paths = array(
- APP
- );
- if (!empty($this->params['plugin'])) {
- $this->_paths = array(App::pluginPath($this->params['plugin']));
- }
- $patterns = array(
- array(
- "LIBS -> CAKE",
- '/\bLIBS\b/',
- 'CAKE'
- ),
- array(
- "CONFIGS -> APP . 'Config' . DS",
- '/\bCONFIGS\b/',
- 'APP . \'Config\' . DS'
- ),
- array(
- "CONTROLLERS -> APP . 'Controller' . DS",
- '/\bCONTROLLERS\b/',
- 'APP . \'Controller\' . DS'
- ),
- array(
- "COMPONENTS -> APP . 'Controller' . DS . 'Component' . DS",
- '/\bCOMPONENTS\b/',
- 'APP . \'Controller\' . DS . \'Component\''
- ),
- array(
- "MODELS -> APP . 'Model' . DS",
- '/\bMODELS\b/',
- 'APP . \'Model\' . DS'
- ),
- array(
- "BEHAVIORS -> APP . 'Model' . DS . 'Behavior' . DS",
- '/\bBEHAVIORS\b/',
- 'APP . \'Model\' . DS . \'Behavior\' . DS'
- ),
- array(
- "VIEWS -> APP . 'View' . DS",
- '/\bVIEWS\b/',
- 'APP . \'View\' . DS'
- ),
- array(
- "HELPERS -> APP . 'View' . DS . 'Helper' . DS",
- '/\bHELPERS\b/',
- 'APP . \'View\' . DS . \'Helper\' . DS'
- ),
- array(
- "LAYOUTS -> APP . 'View' . DS . 'Layouts' . DS",
- '/\bLAYOUTS\b/',
- 'APP . \'View\' . DS . \'Layouts\' . DS'
- ),
- array(
- "ELEMENTS -> APP . 'View' . DS . 'Elements' . DS",
- '/\bELEMENTS\b/',
- 'APP . \'View\' . DS . \'Elements\' . DS'
- ),
- array(
- "CONSOLE_LIBS -> CAKE . 'Console' . DS",
- '/\bCONSOLE_LIBS\b/',
- 'CAKE . \'Console\' . DS'
- ),
- array(
- "CAKE_TESTS_LIB -> CAKE . 'TestSuite' . DS",
- '/\bCAKE_TESTS_LIB\b/',
- 'CAKE . \'TestSuite\' . DS'
- ),
- array(
- "CAKE_TESTS -> CAKE . 'Test' . DS",
- '/\bCAKE_TESTS\b/',
- 'CAKE . \'Test\' . DS'
- )
- );
- $this->_filesRegexpUpdate($patterns);
- }
-
-/**
- * Update components.
- *
- * - Make components that extend Object to extend Component.
- *
- * @return void
- */
- public function components() {
- $this->_paths = App::Path('Controller/Component');
- if (!empty($this->params['plugin'])) {
- $this->_paths = App::Path('Controller/Component', $this->params['plugin']);
- }
- $patterns = array(
- array(
- '*Component extends Object to *Component extends Component',
- '/([a-zA-Z]*Component extends) Object/',
- '\1 Component'
- ),
- );
-
- $this->_filesRegexpUpdate($patterns);
- }
-
-/**
- * Replace cakeError with built-in exceptions.
- * NOTE: this ignores calls where you've passed your own secondary parameters to cakeError().
- * @return void
- */
- public function exceptions() {
- $controllers = array_diff(App::path('controllers'), App::core('controllers'), array(APP));
- $components = array_diff(App::path('components'), App::core('components'));
-
- $this->_paths = array_merge($controllers, $components);
-
- if (!empty($this->params['plugin'])) {
- $pluginPath = App::pluginPath($this->params['plugin']);
- $this->_paths = array(
- $pluginPath . 'controllers' . DS,
- $pluginPath . 'controllers' . DS . 'components' . DS,
- );
- }
- $patterns = array(
- array(
- '$this->cakeError("error400") -> throw new BadRequestException()',
- '/(\$this->cakeError\(["\']error400["\']\));/',
- 'throw new BadRequestException();'
- ),
- array(
- '$this->cakeError("error404") -> throw new NotFoundException()',
- '/(\$this->cakeError\(["\']error404["\']\));/',
- 'throw new NotFoundException();'
- ),
- array(
- '$this->cakeError("error500") -> throw new InternalErrorException()',
- '/(\$this->cakeError\(["\']error500["\']\));/',
- 'throw new InternalErrorException();'
- ),
- );
- $this->_filesRegexpUpdate($patterns);
- }
-
-/**
- * Move application views files to where they now should be
- *
- * Find all view files in the folder and determine where cake expects the file to be
- *
- * @return void
- */
- protected function _moveViewFiles() {
- if (!is_dir('View')) {
- return;
- }
-
- $dirs = scandir('View');
- foreach ($dirs as $old) {
- if (!is_dir('View' . DS . $old) || $old === '.' || $old === '..') {
- continue;
- }
-
- $new = 'View' . DS . Inflector::camelize($old);
- $old = 'View' . DS . $old;
- if ($new == $old) {
- continue;
- }
-
- $this->out(__d('cake_console', 'Moving %s to %s', $old, $new));
- if (!$this->params['dry-run']) {
- if ($this->params['git']) {
- exec('git mv -f ' . escapeshellarg($old) . ' ' . escapeshellarg($old . '__'));
- exec('git mv -f ' . escapeshellarg($old . '__') . ' ' . escapeshellarg($new));
- } else {
- $Folder = new Folder($old);
- $Folder->move($new);
- }
- }
- }
- }
-
-/**
- * Move the AppController, and AppModel classes.
- *
- * @return void
- */
- protected function _moveAppClasses() {
- $files = array(
- APP . 'app_controller.php' => APP . 'Controller' . DS . 'AppController.php',
- APP . 'controllers' . DS . 'app_controller.php' => APP . 'Controller' . DS . 'AppController.php',
- APP . 'app_model.php' => APP . 'Model' . DS . 'AppModel.php',
- APP . 'models' . DS . 'app_model.php' => APP . 'Model' . DS . 'AppModel.php',
- );
- foreach ($files as $old => $new) {
- if (file_exists($old)) {
- $this->out(__d('cake_console', 'Moving %s to %s', $old, $new));
-
- if ($this->params['dry-run']) {
- continue;
- }
- if ($this->params['git']) {
- exec('git mv -f ' . escapeshellarg($old) . ' ' . escapeshellarg($old . '__'));
- exec('git mv -f ' . escapeshellarg($old . '__') . ' ' . escapeshellarg($new));
- } else {
- rename($old, $new);
- }
- }
- }
- }
-
-/**
- * Move application php files to where they now should be
- *
- * Find all php files in the folder (honoring recursive) and determine where cake expects the file to be
- * If the file is not exactly where cake expects it - move it.
- *
- * @param mixed $path
- * @param mixed $options array(recursive, checkFolder)
- * @return void
- */
- protected function _movePhpFiles($path, $options) {
- if (!is_dir($path)) {
- return;
- }
-
- $paths = $this->_paths;
-
- $this->_paths = array($path);
- $this->_files = array();
- if ($options['recursive']) {
- $this->_findFiles('php');
- } else {
- $this->_files = scandir($path);
- foreach ($this->_files as $i => $file) {
- if (strlen($file) < 5 || substr($file, -4) !== '.php') {
- unset($this->_files[$i]);
- }
- }
- }
-
- $cwd = getcwd();
- foreach ($this->_files as &$file) {
- $file = $cwd . DS . $file;
-
- $contents = file_get_contents($file);
- preg_match($options['regex'], $contents, $match);
- if (!$match) {
- continue;
- }
-
- $class = $match[1];
-
- if (substr($class, 0, 3) === 'Dbo') {
- $type = 'Dbo';
- } else {
- preg_match('@([A-Z][^A-Z]*)$@', $class, $match);
- if ($match) {
- $type = $match[1];
- } else {
- $type = 'unknown';
- }
- }
-
- preg_match('@^.*[\\\/]plugins[\\\/](.*?)[\\\/]@', $file, $match);
- $base = $cwd . DS;
- $plugin = false;
- if ($match) {
- $base = $match[0];
- $plugin = $match[1];
- }
-
- if ($options['checkFolder'] && !empty($this->_map[$type])) {
- $folder = str_replace('/', DS, $this->_map[$type]);
- $new = $base . $folder . DS . $class . '.php';
- } else {
- $new = dirname($file) . DS . $class . '.php';
- }
-
- if ($file === $new) {
- continue;
- }
-
- $dir = dirname($new);
- if (!is_dir($dir)) {
- new Folder($dir, true);
- }
-
- $this->out(__d('cake_console', 'Moving %s to %s', $file, $new), 1, Shell::VERBOSE);
- if (!$this->params['dry-run']) {
- if ($this->params['git']) {
- exec('git mv -f ' . escapeshellarg($file) . ' ' . escapeshellarg($file . '__'));
- exec('git mv -f ' . escapeshellarg($file . '__') . ' ' . escapeshellarg($new));
- } else {
- rename($file, $new);
- }
- }
- }
-
- $this->_paths = $paths;
- }
-
-/**
- * Updates files based on regular expressions.
- *
- * @param array $patterns Array of search and replacement patterns.
- * @return void
- */
- protected function _filesRegexpUpdate($patterns) {
- $this->_findFiles($this->params['ext']);
- foreach ($this->_files as $file) {
- $this->out(__d('cake_console', 'Updating %s...', $file), 1, Shell::VERBOSE);
- $this->_updateFile($file, $patterns);
- }
- }
-
-/**
- * Searches the paths and finds files based on extension.
- *
- * @param string $extensions
- * @return void
- */
- protected function _findFiles($extensions = '') {
- $this->_files = array();
- foreach ($this->_paths as $path) {
- if (!is_dir($path)) {
- continue;
- }
- $Iterator = new RegexIterator(
- new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)),
- '/^.+\.(' . $extensions . ')$/i',
- RegexIterator::MATCH
- );
- foreach ($Iterator as $file) {
- if ($file->isFile()) {
- $this->_files[] = $file->getPathname();
- }
- }
- }
- }
-
-/**
- * Update a single file.
- *
- * @param string $file The file to update
- * @param array $patterns The replacement patterns to run.
- * @return void
- */
- protected function _updateFile($file, $patterns) {
- $contents = file_get_contents($file);
-
- foreach ($patterns as $pattern) {
- $this->out(__d('cake_console', ' * Updating %s', $pattern[0]), 1, Shell::VERBOSE);
- $contents = preg_replace($pattern[1], $pattern[2], $contents);
- }
-
- $this->out(__d('cake_console', 'Done updating %s', $file), 1);
- if (!$this->params['dry-run']) {
- file_put_contents($file, $contents);
- }
- }
-
-/**
- * get the option parser
- *
- * @return ConsoleOptionParser
- */
- public function getOptionParser() {
- $subcommandParser = array(
- 'options' => array(
- 'plugin' => array(
- 'short' => 'p',
- 'help' => __d('cake_console', 'The plugin to update. Only the specified plugin will be updated.')
- ),
- 'ext' => array(
- 'short' => 'e',
- 'help' => __d('cake_console', 'The extension(s) to search. A pipe delimited list, or a preg_match compatible subpattern'),
- 'default' => 'php|ctp|thtml|inc|tpl'
- ),
- 'git' => array(
- 'short' => 'g',
- 'help' => __d('cake_console', 'Use git command for moving files around.'),
- 'boolean' => true
- ),
- 'dry-run' => array(
- 'short' => 'd',
- 'help' => __d('cake_console', 'Dry run the update, no files will actually be modified.'),
- 'boolean' => true
- )
- )
- );
-
- return parent::getOptionParser()
- ->description(__d('cake_console', "A shell to help automate upgrading from CakePHP 1.3 to 2.0. \n" .
- "Be sure to have a backup of your application before running these commands."))
- ->addSubcommand('all', array(
- 'help' => __d('cake_console', 'Run all upgrade commands.'),
- 'parser' => $subcommandParser
- ))
- ->addSubcommand('tests', array(
- 'help' => __d('cake_console', 'Update tests class names to FooTest rather than FooTestCase.'),
- 'parser' => $subcommandParser
- ))
- ->addSubcommand('locations', array(
- 'help' => __d('cake_console', 'Move files and folders to their new homes.'),
- 'parser' => $subcommandParser
- ))
- ->addSubcommand('i18n', array(
- 'help' => __d('cake_console', 'Update the i18n translation method calls.'),
- 'parser' => $subcommandParser
- ))
- ->addSubcommand('helpers', array(
- 'help' => __d('cake_console', 'Update calls to helpers.'),
- 'parser' => $subcommandParser
- ))
- ->addSubcommand('basics', array(
- 'help' => __d('cake_console', 'Update removed basics functions to PHP native functions.'),
- 'parser' => $subcommandParser
- ))
- ->addSubcommand('request', array(
- 'help' => __d('cake_console', 'Update removed request access, and replace with $this->request.'),
- 'parser' => $subcommandParser
- ))
- ->addSubcommand('configure', array(
- 'help' => __d('cake_console', "Update Configure::read() to Configure::read('debug')"),
- 'parser' => $subcommandParser
- ))
- ->addSubcommand('constants', array(
- 'help' => __d('cake_console', "Replace Obsolete constants"),
- 'parser' => $subcommandParser
- ))
- ->addSubcommand('components', array(
- 'help' => __d('cake_console', 'Update components to extend Component class.'),
- 'parser' => $subcommandParser
- ))
- ->addSubcommand('exceptions', array(
- 'help' => __d('cake_console', 'Replace use of cakeError with exceptions.'),
- 'parser' => $subcommandParser
- ));
- }
-
-}
diff --git a/lib/Cake/Console/ConsoleErrorHandler.php b/lib/Cake/Console/ConsoleErrorHandler.php
deleted file mode 100644
index 043c621256d..00000000000
--- a/lib/Cake/Console/ConsoleErrorHandler.php
+++ /dev/null
@@ -1,98 +0,0 @@
-write(__d('cake_console', "Error: %s\n%s",
- $exception->getMessage(),
- $exception->getTraceAsString()
- ));
- $this->_stop($exception->getCode() ? $exception->getCode() : 1);
- }
-
-/**
- * Handle errors in the console environment. Writes errors to stderr,
- * and logs messages if Configure::read('debug') is 0.
- *
- * @param integer $code Error code
- * @param string $description Description of the error.
- * @param string $file The file the error occurred in.
- * @param integer $line The line the error occurred on.
- * @param array $context The backtrace of the error.
- * @return void
- */
- public function handleError($code, $description, $file = null, $line = null, $context = null) {
- if (error_reporting() === 0) {
- return;
- }
- $stderr = self::getStderr();
- list($name, $log) = ErrorHandler::mapErrorCode($code);
- $message = __d('cake_console', '%s in [%s, line %s]', $description, $file, $line);
- $stderr->write(__d('cake_console', "%s Error: %s\n", $name, $message));
-
- if (Configure::read('debug') == 0) {
- CakeLog::write($log, $message);
- }
- }
-
-/**
- * Wrapper for exit(), used for testing.
- *
- * @param $code int The exit code.
- */
- protected function _stop($code = 0) {
- exit($code);
- }
-
-}
diff --git a/lib/Cake/Console/ConsoleInput.php b/lib/Cake/Console/ConsoleInput.php
deleted file mode 100644
index eb4928b3807..00000000000
--- a/lib/Cake/Console/ConsoleInput.php
+++ /dev/null
@@ -1,51 +0,0 @@
-_input = fopen($handle, 'r');
- }
-
-/**
- * Read a value from the stream
- *
- * @return mixed The value of the stream
- */
- public function read() {
- return fgets($this->_input);
- }
-
-}
diff --git a/lib/Cake/Console/ConsoleInputArgument.php b/lib/Cake/Console/ConsoleInputArgument.php
deleted file mode 100644
index ef40e0a942f..00000000000
--- a/lib/Cake/Console/ConsoleInputArgument.php
+++ /dev/null
@@ -1,170 +0,0 @@
- $value) {
- $this->{'_' . $key} = $value;
- }
- } else {
- $this->_name = $name;
- $this->_help = $help;
- $this->_required = $required;
- $this->_choices = $choices;
- }
- }
-
-/**
- * Get the value of the name attribute.
- *
- * @return string Value of this->_name.
- */
- public function name() {
- return $this->_name;
- }
-
-/**
- * Generate the help for this argument.
- *
- * @param integer $width The width to make the name of the option.
- * @return string
- */
- public function help($width = 0) {
- $name = $this->_name;
- if (strlen($name) < $width) {
- $name = str_pad($name, $width, ' ');
- }
- $optional = '';
- if (!$this->isRequired()) {
- $optional = __d('cake_console', ' (optional) ');
- }
- if (!empty($this->_choices)) {
- $optional .= __d('cake_console', ' (choices: %s) ', implode('|', $this->_choices));
- }
- return sprintf('%s%s%s', $name, $this->_help, $optional);
- }
-
-/**
- * Get the usage value for this argument
- *
- * @return string
- */
- public function usage() {
- $name = $this->_name;
- if (!empty($this->_choices)) {
- $name = implode('|', $this->_choices);
- }
- $name = '<' . $name . '>';
- if (!$this->isRequired()) {
- $name = '[' . $name . ']';
- }
- return $name;
- }
-
-/**
- * Check if this argument is a required argument
- *
- * @return boolean
- */
- public function isRequired() {
- return (bool)$this->_required;
- }
-
-/**
- * Check that $value is a valid choice for this argument.
- *
- * @param string $value
- * @return boolean
- * @throws ConsoleException
- */
- public function validChoice($value) {
- if (empty($this->_choices)) {
- return true;
- }
- if (!in_array($value, $this->_choices)) {
- throw new ConsoleException(
- __d('cake_console', '"%s" is not a valid value for %s. Please use one of "%s"',
- $value, $this->_name, implode(', ', $this->_choices)
- ));
- }
- return true;
- }
-
-/**
- * Append this arguments XML representation to the passed in SimpleXml object.
- *
- * @param SimpleXmlElement $parent The parent element.
- * @return SimpleXmlElement The parent with this argument appended.
- */
- public function xml(SimpleXmlElement $parent) {
- $option = $parent->addChild('argument');
- $option->addAttribute('name', $this->_name);
- $option->addAttribute('help', $this->_help);
- $option->addAttribute('required', $this->isRequired());
- $choices = $option->addChild('choices');
- foreach ($this->_choices as $valid) {
- $choices->addChild('choice', $valid);
- }
- return $parent;
- }
-
-}
diff --git a/lib/Cake/Console/ConsoleInputOption.php b/lib/Cake/Console/ConsoleInputOption.php
deleted file mode 100644
index 889166be7d6..00000000000
--- a/lib/Cake/Console/ConsoleInputOption.php
+++ /dev/null
@@ -1,221 +0,0 @@
- $value) {
- $this->{'_' . $key} = $value;
- }
- } else {
- $this->_name = $name;
- $this->_short = $short;
- $this->_help = $help;
- $this->_boolean = $boolean;
- $this->_default = $default;
- $this->_choices = $choices;
- }
- if (strlen($this->_short) > 1) {
- throw new ConsoleException(
- __d('cake_console', 'Short options must be one letter.')
- );
- }
- }
-
-/**
- * Get the value of the name attribute.
- *
- * @return string Value of this->_name.
- */
- public function name() {
- return $this->_name;
- }
-
-/**
- * Get the value of the short attribute.
- *
- * @return string Value of this->_short.
- */
- public function short() {
- return $this->_short;
- }
-
-/**
- * Generate the help for this this option.
- *
- * @param integer $width The width to make the name of the option.
- * @return string
- */
- public function help($width = 0) {
- $default = $short = '';
- if (!empty($this->_default) && $this->_default !== true) {
- $default = __d('cake_console', ' (default: %s) ', $this->_default);
- }
- if (!empty($this->_choices)) {
- $default .= __d('cake_console', ' (choices: %s) ', implode('|', $this->_choices));
- }
- if (!empty($this->_short)) {
- $short = ', -' . $this->_short;
- }
- $name = sprintf('--%s%s', $this->_name, $short);
- if (strlen($name) < $width) {
- $name = str_pad($name, $width, ' ');
- }
- return sprintf('%s%s%s', $name, $this->_help, $default);
- }
-
-/**
- * Get the usage value for this option
- *
- * @return string
- */
- public function usage() {
- $name = empty($this->_short) ? '--' . $this->_name : '-' . $this->_short;
- $default = '';
- if (!empty($this->_default) && $this->_default !== true) {
- $default = ' ' . $this->_default;
- }
- if (!empty($this->_choices)) {
- $default = ' ' . implode('|', $this->_choices);
- }
- return sprintf('[%s%s]', $name, $default);
- }
-
-/**
- * Get the default value for this option
- *
- * @return mixed
- */
- public function defaultValue() {
- return $this->_default;
- }
-
-/**
- * Check if this option is a boolean option
- *
- * @return boolean
- */
- public function isBoolean() {
- return (bool)$this->_boolean;
- }
-
-/**
- * Check that a value is a valid choice for this option.
- *
- * @param string $value
- * @return boolean
- * @throws ConsoleException
- */
- public function validChoice($value) {
- if (empty($this->_choices)) {
- return true;
- }
- if (!in_array($value, $this->_choices)) {
- throw new ConsoleException(
- __d('cake_console', '"%s" is not a valid value for --%s. Please use one of "%s"',
- $value, $this->_name, implode(', ', $this->_choices)
- ));
- }
- return true;
- }
-
-/**
- * Append the option's xml into the parent.
- *
- * @param SimpleXmlElement $parent The parent element.
- * @return SimpleXmlElement The parent with this option appended.
- */
- public function xml(SimpleXmlElement $parent) {
- $option = $parent->addChild('option');
- $option->addAttribute('name', '--' . $this->_name);
- $short = '';
- if (strlen($this->_short)) {
- $short = $this->_short;
- }
- $option->addAttribute('short', '-' . $short);
- $option->addAttribute('boolean', $this->_boolean);
- $option->addChild('default', $this->_default);
- $choices = $option->addChild('choices');
- foreach ($this->_choices as $valid) {
- $choices->addChild('choice', $valid);
- }
- return $parent;
- }
-
-}
diff --git a/lib/Cake/Console/ConsoleInputSubcommand.php b/lib/Cake/Console/ConsoleInputSubcommand.php
deleted file mode 100644
index b9520644f52..00000000000
--- a/lib/Cake/Console/ConsoleInputSubcommand.php
+++ /dev/null
@@ -1,121 +0,0 @@
- $value) {
- $this->{'_' . $key} = $value;
- }
- } else {
- $this->_name = $name;
- $this->_help = $help;
- $this->_parser = $parser;
- }
- if (is_array($this->_parser)) {
- $this->_parser['command'] = $this->_name;
- $this->_parser = ConsoleOptionParser::buildFromArray($this->_parser);
- }
- }
-
-/**
- * Get the value of the name attribute.
- *
- * @return string Value of this->_name.
- */
- public function name() {
- return $this->_name;
- }
-
-/**
- * Generate the help for this this subcommand.
- *
- * @param integer $width The width to make the name of the subcommand.
- * @return string
- */
- public function help($width = 0) {
- $name = $this->_name;
- if (strlen($name) < $width) {
- $name = str_pad($name, $width, ' ');
- }
- return $name . $this->_help;
- }
-
-/**
- * Get the usage value for this option
- *
- * @return mixed Either false or a ConsoleOptionParser
- */
- public function parser() {
- if ($this->_parser instanceof ConsoleOptionParser) {
- return $this->_parser;
- }
- return false;
- }
-
-/**
- * Append this subcommand to the Parent element
- *
- * @param SimpleXmlElement $parent The parent element.
- * @return SimpleXmlElement The parent with this subcommand appended.
- */
- public function xml(SimpleXmlElement $parent) {
- $command = $parent->addChild('command');
- $command->addAttribute('name', $this->_name);
- $command->addAttribute('help', $this->_help);
- return $parent;
- }
-
-}
diff --git a/lib/Cake/Console/ConsoleOptionParser.php b/lib/Cake/Console/ConsoleOptionParser.php
deleted file mode 100644
index 703023c7d4f..00000000000
--- a/lib/Cake/Console/ConsoleOptionParser.php
+++ /dev/null
@@ -1,651 +0,0 @@
-addOption()`
- * you can define new options. The name of the option is used as its long form, and you
- * can supply an additional short form, with the `short` option. Short options should
- * only be one letter long. Using more than one letter for a short option will raise an exception.
- *
- * Calling options can be done using syntax similar to most *nix command line tools. Long options
- * cane either include an `=` or leave it out.
- *
- * `cake myshell command --connection default --name=something`
- *
- * Short options can be defined signally or in groups.
- *
- * `cake myshell command -cn`
- *
- * Short options can be combined into groups as seen above. Each letter in a group
- * will be treated as a separate option. The previous example is equivalent to:
- *
- * `cake myshell command -c -n`
- *
- * Short options can also accept values:
- *
- * `cake myshell command -c default`
- *
- * ### Positional arguments
- *
- * If no positional arguments are defined, all of them will be parsed. If you define positional
- * arguments any arguments greater than those defined will cause exceptions. Additionally you can
- * declare arguments as optional, by setting the required param to false.
- *
- * `$parser->addArgument('model', array('required' => false));`
- *
- * ### Providing Help text
- *
- * By providing help text for your positional arguments and named arguments, the ConsoleOptionParser
- * can generate a help display for you. You can view the help for shells by using the `--help` or `-h` switch.
- *
- * @package Cake.Console
- */
-class ConsoleOptionParser {
-
-/**
- * Description text - displays before options when help is generated
- *
- * @see ConsoleOptionParser::description()
- * @var string
- */
- protected $_description = null;
-
-/**
- * Epilog text - displays after options when help is generated
- *
- * @see ConsoleOptionParser::epilog()
- * @var string
- */
- protected $_epilog = null;
-
-/**
- * Option definitions.
- *
- * @see ConsoleOptionParser::addOption()
- * @var array
- */
- protected $_options = array();
-
-/**
- * Map of short -> long options, generated when using addOption()
- *
- * @var string
- */
- protected $_shortOptions = array();
-
-/**
- * Positional argument definitions.
- *
- * @see ConsoleOptionParser::addArgument()
- * @var array
- */
- protected $_args = array();
-
-/**
- * Subcommands for this Shell.
- *
- * @see ConsoleOptionParser::addSubcommand()
- * @var array
- */
- protected $_subcommands = array();
-
-/**
- * Command name.
- *
- * @var string
- */
- protected $_command = '';
-
-/**
- * Construct an OptionParser so you can define its behavior
- *
- * @param string $command The command name this parser is for. The command name is used for generating help.
- * @param boolean $defaultOptions Whether you want the verbose and quiet options set. Setting
- * this to false will prevent the addition of `--verbose` & `--quiet` options.
- */
- public function __construct($command = null, $defaultOptions = true) {
- $this->command($command);
-
- $this->addOption('help', array(
- 'short' => 'h',
- 'help' => __d('cake_console', 'Display this help.'),
- 'boolean' => true
- ));
-
- if ($defaultOptions) {
- $this->addOption('verbose', array(
- 'short' => 'v',
- 'help' => __d('cake_console', 'Enable verbose output.'),
- 'boolean' => true
- ))->addOption('quiet', array(
- 'short' => 'q',
- 'help' => __d('cake_console', 'Enable quiet output.'),
- 'boolean' => true
- ));
- }
- }
-
-/**
- * Static factory method for creating new OptionParsers so you can chain methods off of them.
- *
- * @param string $command The command name this parser is for. The command name is used for generating help.
- * @param boolean $defaultOptions Whether you want the verbose and quiet options set.
- * @return ConsoleOptionParser
- */
- public static function create($command, $defaultOptions = true) {
- return new ConsoleOptionParser($command, $defaultOptions);
- }
-
-/**
- * Build a parser from an array. Uses an array like
- *
- * {{{
- * $spec = array(
- * 'description' => 'text',
- * 'epilog' => 'text',
- * 'arguments' => array(
- * // list of arguments compatible with addArguments.
- * ),
- * 'options' => array(
- * // list of options compatible with addOptions
- * ),
- * 'subcommands' => array(
- * // list of subcommands to add.
- * )
- * );
- * }}}
- *
- * @param array $spec The spec to build the OptionParser with.
- * @return ConsoleOptionParser
- */
- public static function buildFromArray($spec) {
- $parser = new ConsoleOptionParser($spec['command']);
- if (!empty($spec['arguments'])) {
- $parser->addArguments($spec['arguments']);
- }
- if (!empty($spec['options'])) {
- $parser->addOptions($spec['options']);
- }
- if (!empty($spec['subcommands'])) {
- $parser->addSubcommands($spec['subcommands']);
- }
- if (!empty($spec['description'])) {
- $parser->description($spec['description']);
- }
- if (!empty($spec['epilog'])) {
- $parser->epilog($spec['epilog']);
- }
- return $parser;
- }
-
-/**
- * Get or set the command name for shell/task.
- *
- * @param string $text The text to set, or null if you want to read
- * @return mixed If reading, the value of the command. If setting $this will be returned
- */
- public function command($text = null) {
- if ($text !== null) {
- $this->_command = Inflector::underscore($text);
- return $this;
- }
- return $this->_command;
- }
-
-/**
- * Get or set the description text for shell/task.
- *
- * @param mixed $text The text to set, or null if you want to read. If an array the
- * text will be imploded with "\n"
- * @return mixed If reading, the value of the description. If setting $this will be returned
- */
- public function description($text = null) {
- if ($text !== null) {
- if (is_array($text)) {
- $text = implode("\n", $text);
- }
- $this->_description = $text;
- return $this;
- }
- return $this->_description;
- }
-
-/**
- * Get or set an epilog to the parser. The epilog is added to the end of
- * the options and arguments listing when help is generated.
- *
- * @param mixed $text Text when setting or null when reading. If an array the text will be imploded with "\n"
- * @return mixed If reading, the value of the epilog. If setting $this will be returned.
- */
- public function epilog($text = null) {
- if ($text !== null) {
- if (is_array($text)) {
- $text = implode("\n", $text);
- }
- $this->_epilog = $text;
- return $this;
- }
- return $this->_epilog;
- }
-
-/**
- * Add an option to the option parser. Options allow you to define optional or required
- * parameters for your console application. Options are defined by the parameters they use.
- *
- * ### Options
- *
- * - `short` - The single letter variant for this option, leave undefined for none.
- * - `help` - Help text for this option. Used when generating help for the option.
- * - `default` - The default value for this option. Defaults are added into the parsed params when the
- * attached option is not provided or has no value. Using default and boolean together will not work.
- * are added into the parsed parameters when the option is undefined. Defaults to null.
- * - `boolean` - The option uses no value, its just a boolean switch. Defaults to false.
- * If an option is defined as boolean, it will always be added to the parsed params. If no present
- * it will be false, if present it will be true.
- * - `choices` A list of valid choices for this option. If left empty all values are valid..
- * An exception will be raised when parse() encounters an invalid value.
- *
- * @param mixed $name The long name you want to the value to be parsed out as when options are parsed.
- * Will also accept an instance of ConsoleInputOption
- * @param array $options An array of parameters that define the behavior of the option
- * @return ConsoleOptionParser $this.
- */
- public function addOption($name, $options = array()) {
- if (is_object($name) && $name instanceof ConsoleInputOption) {
- $option = $name;
- $name = $option->name();
- } else {
- $defaults = array(
- 'name' => $name,
- 'short' => null,
- 'help' => '',
- 'default' => null,
- 'boolean' => false,
- 'choices' => array()
- );
- $options = array_merge($defaults, $options);
- $option = new ConsoleInputOption($options);
- }
- $this->_options[$name] = $option;
- if ($option->short() !== null) {
- $this->_shortOptions[$option->short()] = $name;
- }
- return $this;
- }
-
-/**
- * Add a positional argument to the option parser.
- *
- * ### Params
- *
- * - `help` The help text to display for this argument.
- * - `required` Whether this parameter is required.
- * - `index` The index for the arg, if left undefined the argument will be put
- * onto the end of the arguments. If you define the same index twice the first
- * option will be overwritten.
- * - `choices` A list of valid choices for this argument. If left empty all values are valid..
- * An exception will be raised when parse() encounters an invalid value.
- *
- * @param mixed $name The name of the argument. Will also accept an instance of ConsoleInputArgument
- * @param array $params Parameters for the argument, see above.
- * @return ConsoleOptionParser $this.
- */
- public function addArgument($name, $params = array()) {
- if (is_object($name) && $name instanceof ConsoleInputArgument) {
- $arg = $name;
- $index = count($this->_args);
- } else {
- $defaults = array(
- 'name' => $name,
- 'help' => '',
- 'index' => count($this->_args),
- 'required' => false,
- 'choices' => array()
- );
- $options = array_merge($defaults, $params);
- $index = $options['index'];
- unset($options['index']);
- $arg = new ConsoleInputArgument($options);
- }
- $this->_args[$index] = $arg;
- return $this;
- }
-
-/**
- * Add multiple arguments at once. Take an array of argument definitions.
- * The keys are used as the argument names, and the values as params for the argument.
- *
- * @param array $args Array of arguments to add.
- * @see ConsoleOptionParser::addArgument()
- * @return ConsoleOptionParser $this
- */
- public function addArguments(array $args) {
- foreach ($args as $name => $params) {
- $this->addArgument($name, $params);
- }
- return $this;
- }
-
-/**
- * Add multiple options at once. Takes an array of option definitions.
- * The keys are used as option names, and the values as params for the option.
- *
- * @param array $options Array of options to add.
- * @see ConsoleOptionParser::addOption()
- * @return ConsoleOptionParser $this
- */
- public function addOptions(array $options) {
- foreach ($options as $name => $params) {
- $this->addOption($name, $params);
- }
- return $this;
- }
-
-/**
- * Append a subcommand to the subcommand list.
- * Subcommands are usually methods on your Shell, but can also be used to document Tasks.
- *
- * ### Options
- *
- * - `help` - Help text for the subcommand.
- * - `parser` - A ConsoleOptionParser for the subcommand. This allows you to create method
- * specific option parsers. When help is generated for a subcommand, if a parser is present
- * it will be used.
- *
- * @param mixed $name Name of the subcommand. Will also accept an instance of ConsoleInputSubcommand
- * @param array $options Array of params, see above.
- * @return ConsoleOptionParser $this.
- */
- public function addSubcommand($name, $options = array()) {
- if (is_object($name) && $name instanceof ConsoleInputSubcommand) {
- $command = $name;
- $name = $command->name();
- } else {
- $defaults = array(
- 'name' => $name,
- 'help' => '',
- 'parser' => null
- );
- $options = array_merge($defaults, $options);
- $command = new ConsoleInputSubcommand($options);
- }
- $this->_subcommands[$name] = $command;
- return $this;
- }
-
-/**
- * Add multiple subcommands at once.
- *
- * @param array $commands Array of subcommands.
- * @return ConsoleOptionParser $this
- */
- public function addSubcommands(array $commands) {
- foreach ($commands as $name => $params) {
- $this->addSubcommand($name, $params);
- }
- return $this;
- }
-
-/**
- * Gets the arguments defined in the parser.
- *
- * @return array Array of argument descriptions
- */
- public function arguments() {
- return $this->_args;
- }
-
-/**
- * Get the defined options in the parser.
- *
- * @return array
- */
- public function options() {
- return $this->_options;
- }
-
-/**
- * Get the array of defined subcommands
- *
- * @return array
- */
- public function subcommands() {
- return $this->_subcommands;
- }
-
-/**
- * Parse the argv array into a set of params and args. If $command is not null
- * and $command is equal to a subcommand that has a parser, that parser will be used
- * to parse the $argv
- *
- * @param array $argv Array of args (argv) to parse.
- * @param string $command The subcommand to use. If this parameter is a subcommand, that has a parser,
- * That parser will be used to parse $argv instead.
- * @return Array array($params, $args)
- * @throws ConsoleException When an invalid parameter is encountered.
- */
- public function parse($argv, $command = null) {
- if (isset($this->_subcommands[$command]) && $this->_subcommands[$command]->parser()) {
- return $this->_subcommands[$command]->parser()->parse($argv);
- }
- $params = $args = array();
- $this->_tokens = $argv;
- while (($token = array_shift($this->_tokens)) !== null) {
- if (substr($token, 0, 2) == '--') {
- $params = $this->_parseLongOption($token, $params);
- } elseif (substr($token, 0, 1) == '-') {
- $params = $this->_parseShortOption($token, $params);
- } else {
- $args = $this->_parseArg($token, $args);
- }
- }
- foreach ($this->_args as $i => $arg) {
- if ($arg->isRequired() && !isset($args[$i]) && empty($params['help'])) {
- throw new ConsoleException(
- __d('cake_console', 'Missing required arguments. %s is required.', $arg->name())
- );
- }
- }
- foreach ($this->_options as $option) {
- $name = $option->name();
- $isBoolean = $option->isBoolean();
- $default = $option->defaultValue();
-
- if ($default !== null && !isset($params[$name]) && !$isBoolean) {
- $params[$name] = $default;
- }
- if ($isBoolean && !isset($params[$name])) {
- $params[$name] = false;
- }
- }
- return array($params, $args);
- }
-
-/**
- * Gets formatted help for this parser object.
- * Generates help text based on the description, options, arguments, subcommands and epilog
- * in the parser.
- *
- * @param string $subcommand If present and a valid subcommand that has a linked parser.
- * That subcommands help will be shown instead.
- * @param string $format Define the output format, can be text or xml
- * @param integer $width The width to format user content to. Defaults to 72
- * @return string Generated help.
- */
- public function help($subcommand = null, $format = 'text', $width = 72) {
- if (
- isset($this->_subcommands[$subcommand]) &&
- $this->_subcommands[$subcommand]->parser() instanceof self
- ) {
- $subparser = $this->_subcommands[$subcommand]->parser();
- $subparser->command($this->command() . ' ' . $subparser->command());
- return $subparser->help(null, $format, $width);
- }
- $formatter = new HelpFormatter($this);
- if ($format == 'text' || $format === true) {
- return $formatter->text($width);
- } elseif ($format == 'xml') {
- return $formatter->xml();
- }
- }
-
-/**
- * Parse the value for a long option out of $this->_tokens. Will handle
- * options with an `=` in them.
- *
- * @param string $option The option to parse.
- * @param array $params The params to append the parsed value into
- * @return array Params with $option added in.
- */
- protected function _parseLongOption($option, $params) {
- $name = substr($option, 2);
- if (strpos($name, '=') !== false) {
- list($name, $value) = explode('=', $name, 2);
- array_unshift($this->_tokens, $value);
- }
- return $this->_parseOption($name, $params);
- }
-
-/**
- * Parse the value for a short option out of $this->_tokens
- * If the $option is a combination of multiple shortcuts like -otf
- * they will be shifted onto the token stack and parsed individually.
- *
- * @param string $option The option to parse.
- * @param array $params The params to append the parsed value into
- * @return array Params with $option added in.
- * @throws ConsoleException When unknown short options are encountered.
- */
- protected function _parseShortOption($option, $params) {
- $key = substr($option, 1);
- if (strlen($key) > 1) {
- $flags = str_split($key);
- $key = $flags[0];
- for ($i = 1, $len = count($flags); $i < $len; $i++) {
- array_unshift($this->_tokens, '-' . $flags[$i]);
- }
- }
- if (!isset($this->_shortOptions[$key])) {
- throw new ConsoleException(__d('cake_console', 'Unknown short option `%s`', $key));
- }
- $name = $this->_shortOptions[$key];
- return $this->_parseOption($name, $params);
- }
-
-/**
- * Parse an option by its name index.
- *
- * @param string $name The name to parse.
- * @param array $params The params to append the parsed value into
- * @return array Params with $option added in.
- * @throws ConsoleException
- */
- protected function _parseOption($name, $params) {
- if (!isset($this->_options[$name])) {
- throw new ConsoleException(__d('cake_console', 'Unknown option `%s`', $name));
- }
- $option = $this->_options[$name];
- $isBoolean = $option->isBoolean();
- $nextValue = $this->_nextToken();
- if (!$isBoolean && !empty($nextValue) && !$this->_optionExists($nextValue)) {
- array_shift($this->_tokens);
- $value = $nextValue;
- } elseif ($isBoolean) {
- $value = true;
- } else {
- $value = $option->defaultValue();
- }
- if ($option->validChoice($value)) {
- $params[$name] = $value;
- return $params;
- }
- }
-
-/**
- * Check to see if $name has an option (short/long) defined for it.
- *
- * @param string $name The name of the option.
- * @return boolean
- */
- protected function _optionExists($name) {
- if (substr($name, 0, 2) === '--') {
- return isset($this->_options[substr($name, 2)]);
- }
- if ($name{0} === '-' && $name{1} !== '-') {
- return isset($this->_shortOptions[$name{1}]);
- }
- return false;
- }
-
-/**
- * Parse an argument, and ensure that the argument doesn't exceed the number of arguments
- * and that the argument is a valid choice.
- *
- * @param string $argument The argument to append
- * @param array $args The array of parsed args to append to.
- * @return array Args
- * @throws ConsoleException
- */
- protected function _parseArg($argument, $args) {
- if (empty($this->_args)) {
- array_push($args, $argument);
- return $args;
- }
- $next = count($args);
- if (!isset($this->_args[$next])) {
- throw new ConsoleException(__d('cake_console', 'Too many arguments.'));
- }
-
- if ($this->_args[$next]->validChoice($argument)) {
- array_push($args, $argument);
- return $args;
- }
- }
-
-/**
- * Find the next token in the argv set.
- *
- * @return string next token or ''
- */
- protected function _nextToken() {
- return isset($this->_tokens[0]) ? $this->_tokens[0] : '';
- }
-
-}
diff --git a/lib/Cake/Console/ConsoleOutput.php b/lib/Cake/Console/ConsoleOutput.php
deleted file mode 100644
index 9b0bd3a963c..00000000000
--- a/lib/Cake/Console/ConsoleOutput.php
+++ /dev/null
@@ -1,288 +0,0 @@
-out('Overwrite: foo.php was overwritten.');`
- *
- * This would create orange 'Overwrite:' text, while the rest of the text would remain the normal color.
- * See ConsoleOutput::styles() to learn more about defining your own styles. Nested styles are not supported
- * at this time.
- *
- * @package Cake.Console
- */
-class ConsoleOutput {
-/**
- * Raw output constant - no modification of output text.
- */
- const RAW = 0;
-
-/**
- * Plain output - tags will be stripped.
- */
- const PLAIN = 1;
-
-/**
- * Color output - Convert known tags in to ANSI color escape codes.
- */
- const COLOR = 2;
-
-/**
- * Constant for a newline.
- */
- const LF = PHP_EOL;
-
-/**
- * File handle for output.
- *
- * @var resource
- */
- protected $_output;
-
-/**
- * The current output type. Manipulated with ConsoleOutput::outputAs();
- *
- * @var integer.
- */
- protected $_outputAs = self::COLOR;
-
-/**
- * text colors used in colored output.
- *
- * @var array
- */
- protected static $_foregroundColors = array(
- 'black' => 30,
- 'red' => 31,
- 'green' => 32,
- 'yellow' => 33,
- 'blue' => 34,
- 'magenta' => 35,
- 'cyan' => 36,
- 'white' => 37
- );
-
-/**
- * background colors used in colored output.
- *
- * @var array
- */
- protected static $_backgroundColors = array(
- 'black' => 40,
- 'red' => 41,
- 'green' => 42,
- 'yellow' => 43,
- 'blue' => 44,
- 'magenta' => 45,
- 'cyan' => 46,
- 'white' => 47
- );
-
-/**
- * formatting options for colored output
- *
- * @var string
- */
- protected static $_options = array(
- 'bold' => 1,
- 'underline' => 4,
- 'blink' => 5,
- 'reverse' => 7,
- );
-
-/**
- * Styles that are available as tags in console output.
- * You can modify these styles with ConsoleOutput::styles()
- *
- * @var array
- */
- protected static $_styles = array(
- 'error' => array('text' => 'red', 'underline' => true),
- 'warning' => array('text' => 'yellow'),
- 'info' => array('text' => 'cyan'),
- 'success' => array('text' => 'green'),
- 'comment' => array('text' => 'blue'),
- 'question' => array('text' => "magenta"),
- );
-
-/**
- * Construct the output object.
- *
- * Checks for a pretty console environment. Ansicon allows pretty consoles
- * on windows, and is supported.
- *
- * @param string $stream The identifier of the stream to write output to.
- */
- public function __construct($stream = 'php://stdout') {
- $this->_output = fopen($stream, 'w');
-
- if (DS == '\\' && !(bool)env('ANSICON')) {
- $this->_outputAs = self::PLAIN;
- }
- }
-
-/**
- * Outputs a single or multiple messages to stdout. If no parameters
- * are passed, outputs just a newline.
- *
- * @param mixed $message A string or a an array of strings to output
- * @param integer $newlines Number of newlines to append
- * @return integer Returns the number of bytes returned from writing to stdout.
- */
- public function write($message, $newlines = 1) {
- if (is_array($message)) {
- $message = implode(self::LF, $message);
- }
- return $this->_write($this->styleText($message . str_repeat(self::LF, $newlines)));
- }
-
-/**
- * Apply styling to text.
- *
- * @param string $text Text with styling tags.
- * @return string String with color codes added.
- */
- public function styleText($text) {
- if ($this->_outputAs == self::RAW) {
- return $text;
- }
- if ($this->_outputAs == self::PLAIN) {
- $tags = implode('|', array_keys(self::$_styles));
- return preg_replace('#?(?:' . $tags . ')>#', '', $text);
- }
- return preg_replace_callback(
- '/<(?[a-z0-9-_]+)>(?.*?)<\/(\1)>/ims', array($this, '_replaceTags'), $text
- );
- }
-
-/**
- * Replace tags with color codes.
- *
- * @param array $matches.
- * @return string
- */
- protected function _replaceTags($matches) {
- $style = $this->styles($matches['tag']);
- if (empty($style)) {
- return '<' . $matches['tag'] . '>' . $matches['text'] . '' . $matches['tag'] . '>';
- }
-
- $styleInfo = array();
- if (!empty($style['text']) && isset(self::$_foregroundColors[$style['text']])) {
- $styleInfo[] = self::$_foregroundColors[$style['text']];
- }
- if (!empty($style['background']) && isset(self::$_backgroundColors[$style['background']])) {
- $styleInfo[] = self::$_backgroundColors[$style['background']];
- }
- unset($style['text'], $style['background']);
- foreach ($style as $option => $value) {
- if ($value) {
- $styleInfo[] = self::$_options[$option];
- }
- }
- return "\033[" . implode($styleInfo, ';') . 'm' . $matches['text'] . "\033[0m";
- }
-
-/**
- * Writes a message to the output stream.
- *
- * @param string $message Message to write.
- * @return boolean success
- */
- protected function _write($message) {
- return fwrite($this->_output, $message);
- }
-
-/**
- * Get the current styles offered, or append new ones in.
- *
- * ### Get a style definition
- *
- * `$this->output->styles('error');`
- *
- * ### Get all the style definitions
- *
- * `$this->output->styles();`
- *
- * ### Create or modify an existing style
- *
- * `$this->output->styles('annoy', array('text' => 'purple', 'background' => 'yellow', 'blink' => true));`
- *
- * ### Remove a style
- *
- * `$this->output->styles('annoy', false);`
- *
- * @param string $style The style to get or create.
- * @param mixed $definition The array definition of the style to change or create a style
- * or false to remove a style.
- * @return mixed If you are getting styles, the style or null will be returned. If you are creating/modifying
- * styles true will be returned.
- */
- public function styles($style = null, $definition = null) {
- if ($style === null && $definition === null) {
- return self::$_styles;
- }
- if (is_string($style) && $definition === null) {
- return isset(self::$_styles[$style]) ? self::$_styles[$style] : null;
- }
- if ($definition === false) {
- unset(self::$_styles[$style]);
- return true;
- }
- self::$_styles[$style] = $definition;
- return true;
- }
-
-/**
- * Get/Set the output type to use. The output type how formatting tags are treated.
- *
- * @param integer $type The output type to use. Should be one of the class constants.
- * @return mixed Either null or the value if getting.
- */
- public function outputAs($type = null) {
- if ($type === null) {
- return $this->_outputAs;
- }
- $this->_outputAs = $type;
- }
-
-/**
- * clean up and close handles
- *
- */
- public function __destruct() {
- fclose($this->_output);
- }
-
-}
diff --git a/lib/Cake/Console/HelpFormatter.php b/lib/Cake/Console/HelpFormatter.php
deleted file mode 100644
index 2b495b9e170..00000000000
--- a/lib/Cake/Console/HelpFormatter.php
+++ /dev/null
@@ -1,201 +0,0 @@
-help($command, 'xml'); is usually
- * how you would access help. Or via the `--help=xml` option on the command line.
- *
- * Xml output is useful for integration with other tools like IDE's or other build tools.
- *
- * @package Cake.Console
- * @since CakePHP(tm) v 2.0
- */
-class HelpFormatter {
-
-/**
- * The maximum number of arguments shown when generating usage.
- *
- * @var integer
- */
- protected $_maxArgs = 6;
-
-/**
- * The maximum number of options shown when generating usage.
- *
- * @var integer
- */
- protected $_maxOptions = 6;
-
-/**
- * Build the help formatter for a an OptionParser
- *
- * @param ConsoleOptionParser $parser The option parser help is being generated for.
- */
- public function __construct(ConsoleOptionParser $parser) {
- $this->_parser = $parser;
- }
-
-/**
- * Get the help as formatted text suitable for output on the command line.
- *
- * @param integer $width The width of the help output.
- * @return string
- */
- public function text($width = 72) {
- $parser = $this->_parser;
- $out = array();
- $description = $parser->description();
- if (!empty($description)) {
- $out[] = String::wrap($description, $width);
- $out[] = '';
- }
- $out[] = __d('cake_console', 'Usage: ');
- $out[] = $this->_generateUsage();
- $out[] = '';
- $subcommands = $parser->subcommands();
- if (!empty($subcommands)) {
- $out[] = __d('cake_console', 'Subcommands: ');
- $out[] = '';
- $max = $this->_getMaxLength($subcommands) + 2;
- foreach ($subcommands as $command) {
- $out[] = String::wrap($command->help($max), array(
- 'width' => $width,
- 'indent' => str_repeat(' ', $max),
- 'indentAt' => 1
- ));
- }
- $out[] = '';
- $out[] = __d('cake_console', 'To see help on a subcommand use `cake %s [subcommand] --help` ', $parser->command());
- $out[] = '';
- }
-
- $options = $parser->options();
- if (!empty($options)) {
- $max = $this->_getMaxLength($options) + 8;
- $out[] = __d('cake_console', 'Options: ');
- $out[] = '';
- foreach ($options as $option) {
- $out[] = String::wrap($option->help($max), array(
- 'width' => $width,
- 'indent' => str_repeat(' ', $max),
- 'indentAt' => 1
- ));
- }
- $out[] = '';
- }
-
- $arguments = $parser->arguments();
- if (!empty($arguments)) {
- $max = $this->_getMaxLength($arguments) + 2;
- $out[] = __d('cake_console', 'Arguments: ');
- $out[] = '';
- foreach ($arguments as $argument) {
- $out[] = String::wrap($argument->help($max), array(
- 'width' => $width,
- 'indent' => str_repeat(' ', $max),
- 'indentAt' => 1
- ));
- }
- $out[] = '';
- }
- $epilog = $parser->epilog();
- if (!empty($epilog)) {
- $out[] = String::wrap($epilog, $width);
- $out[] = '';
- }
- return implode("\n", $out);
- }
-
-/**
- * Generate the usage for a shell based on its arguments and options.
- * Usage strings favor short options over the long ones. and optional args will
- * be indicated with []
- *
- * @return string
- */
- protected function _generateUsage() {
- $usage = array('cake ' . $this->_parser->command());
- $subcommands = $this->_parser->subcommands();
- if (!empty($subcommands)) {
- $usage[] = '[subcommand]';
- }
- $options = array();
- foreach ($this->_parser->options() as $option) {
- $options[] = $option->usage();
- }
- if (count($options) > $this->_maxOptions) {
- $options = array('[options]');
- }
- $usage = array_merge($usage, $options);
- $args = array();
- foreach ($this->_parser->arguments() as $argument) {
- $args[] = $argument->usage();
- }
- if (count($args) > $this->_maxArgs) {
- $args = array('[arguments]');
- }
- $usage = array_merge($usage, $args);
- return implode(' ', $usage);
- }
-
-/**
- * Iterate over a collection and find the longest named thing.
- *
- * @param array $collection
- * @return integer
- */
- protected function _getMaxLength($collection) {
- $max = 0;
- foreach ($collection as $item) {
- $max = (strlen($item->name()) > $max) ? strlen($item->name()) : $max;
- }
- return $max;
- }
-
-/**
- * Get the help as an xml string.
- *
- * @param boolean $string Return the SimpleXml object or a string. Defaults to true.
- * @return mixed. See $string
- */
- public function xml($string = true) {
- $parser = $this->_parser;
- $xml = new SimpleXmlElement(' ');
- $xml->addChild('command', $parser->command());
- $xml->addChild('description', $parser->description());
-
- $xml->addChild('epilog', $parser->epilog());
- $subcommands = $xml->addChild('subcommands');
- foreach ($parser->subcommands() as $command) {
- $command->xml($subcommands);
- }
- $options = $xml->addChild('options');
- foreach ($parser->options() as $option) {
- $option->xml($options);
- }
- $arguments = $xml->addChild('arguments');
- foreach ($parser->arguments() as $argument) {
- $argument->xml($arguments);
- }
- return $string ? $xml->asXml() : $xml;
- }
-
-}
diff --git a/lib/Cake/Console/Shell.php b/lib/Cake/Console/Shell.php
deleted file mode 100644
index 788bb8b397c..00000000000
--- a/lib/Cake/Console/Shell.php
+++ /dev/null
@@ -1,816 +0,0 @@
-name == null) {
- $this->name = Inflector::camelize(str_replace(array('Shell', 'Task'), '', get_class($this)));
- }
- $this->Tasks = new TaskCollection($this);
-
- $this->stdout = $stdout;
- $this->stderr = $stderr;
- $this->stdin = $stdin;
- if ($this->stdout == null) {
- $this->stdout = new ConsoleOutput('php://stdout');
- }
- if ($this->stderr == null) {
- $this->stderr = new ConsoleOutput('php://stderr');
- }
- if ($this->stdin == null) {
- $this->stdin = new ConsoleInput('php://stdin');
- }
-
- $parent = get_parent_class($this);
- if ($this->tasks !== null && $this->tasks !== false) {
- $this->_mergeVars(array('tasks'), $parent, true);
- }
- if ($this->uses !== null && $this->uses !== false) {
- $this->_mergeVars(array('uses'), $parent, false);
- }
- }
-
-/**
- * Initializes the Shell
- * acts as constructor for subclasses
- * allows configuration of tasks prior to shell execution
- *
- * @return void
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::initialize
- */
- public function initialize() {
- $this->_loadModels();
- }
-
-/**
- * Starts up the Shell and displays the welcome message.
- * Allows for checking and configuring prior to command or main execution
- *
- * Override this method if you want to remove the welcome information,
- * or otherwise modify the pre-command flow.
- *
- * @return void
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::startup
- */
- public function startup() {
- $this->_welcome();
- }
-
-/**
- * Displays a header for the shell
- *
- * @return void
- */
- protected function _welcome() {
- $this->out();
- $this->out(__d('cake_console', 'Welcome to CakePHP %s Console ', 'v' . Configure::version()));
- $this->hr();
- $this->out(__d('cake_console', 'App : %s', APP_DIR));
- $this->out(__d('cake_console', 'Path: %s', APP));
- $this->hr();
- }
-
-/**
- * If $uses = true
- * Loads AppModel file and constructs AppModel class
- * makes $this->AppModel available to subclasses
- * If public $uses is an array of models will load those models
- *
- * @return boolean
- */
- protected function _loadModels() {
- if ($this->uses === null || $this->uses === false) {
- return;
- }
- App::uses('ClassRegistry', 'Utility');
-
- if ($this->uses !== true && !empty($this->uses)) {
- $uses = is_array($this->uses) ? $this->uses : array($this->uses);
-
- $modelClassName = $uses[0];
- if (strpos($uses[0], '.') !== false) {
- list($plugin, $modelClassName) = explode('.', $uses[0]);
- }
- $this->modelClass = $modelClassName;
-
- foreach ($uses as $modelClass) {
- list($plugin, $modelClass) = pluginSplit($modelClass, true);
- $this->{$modelClass} = ClassRegistry::init($plugin . $modelClass);
- }
- return true;
- }
- return false;
- }
-
-/**
- * Loads tasks defined in public $tasks
- *
- * @return boolean
- */
- public function loadTasks() {
- if ($this->tasks === true || empty($this->tasks) || empty($this->Tasks)) {
- return true;
- }
- $this->_taskMap = TaskCollection::normalizeObjectArray((array)$this->tasks);
- foreach ($this->_taskMap as $task => $properties) {
- $this->taskNames[] = $task;
- }
- return true;
- }
-
-/**
- * Check to see if this shell has a task with the provided name.
- *
- * @param string $task The task name to check.
- * @return boolean Success
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hasTask
- */
- public function hasTask($task) {
- return isset($this->_taskMap[Inflector::camelize($task)]);
- }
-
-/**
- * Check to see if this shell has a callable method by the given name.
- *
- * @param string $name The method name to check.
- * @return boolean
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hasMethod
- */
- public function hasMethod($name) {
- try {
- $method = new ReflectionMethod($this, $name);
- if (!$method->isPublic() || substr($name, 0, 1) === '_') {
- return false;
- }
- if ($method->getDeclaringClass()->name == 'Shell') {
- return false;
- }
- return true;
- } catch (ReflectionException $e) {
- return false;
- }
- }
-
-/**
- * Dispatch a command to another Shell. Similar to Object::requestAction()
- * but intended for running shells from other shells.
- *
- * ### Usage:
- *
- * With a string command:
- *
- * `return $this->dispatchShell('schema create DbAcl');`
- *
- * Avoid using this form if you have string arguments, with spaces in them.
- * The dispatched will be invoked incorrectly. Only use this form for simple
- * command dispatching.
- *
- * With an array command:
- *
- * `return $this->dispatchShell('schema', 'create', 'i18n', '--dry');`
- *
- * @return mixed The return of the other shell.
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::dispatchShell
- */
- public function dispatchShell() {
- $args = func_get_args();
- if (is_string($args[0]) && count($args) == 1) {
- $args = explode(' ', $args[0]);
- }
-
- $Dispatcher = new ShellDispatcher($args, false);
- return $Dispatcher->dispatch();
- }
-
-/**
- * Runs the Shell with the provided argv.
- *
- * Delegates calls to Tasks and resolves methods inside the class. Commands are looked
- * up with the following order:
- *
- * - Method on the shell.
- * - Matching task name.
- * - `main()` method.
- *
- * If a shell implements a `main()` method, all missing method calls will be sent to
- * `main()` with the original method name in the argv.
- *
- * @param string $command The command name to run on this shell. If this argument is empty,
- * and the shell has a `main()` method, that will be called instead.
- * @param array $argv Array of arguments to run the shell with. This array should be missing the shell name.
- * @return void
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::runCommand
- */
- public function runCommand($command, $argv) {
- $isTask = $this->hasTask($command);
- $isMethod = $this->hasMethod($command);
- $isMain = $this->hasMethod('main');
-
- if ($isTask || $isMethod && $command !== 'execute') {
- array_shift($argv);
- }
-
- try {
- $this->OptionParser = $this->getOptionParser();
- list($this->params, $this->args) = $this->OptionParser->parse($argv, $command);
- } catch (ConsoleException $e) {
- $this->out($this->OptionParser->help($command));
- return false;
- }
-
- $this->command = $command;
- if (!empty($this->params['help'])) {
- return $this->_displayHelp($command);
- }
-
- if (($isTask || $isMethod || $isMain) && $command !== 'execute') {
- $this->startup();
- }
-
- if ($isTask) {
- $command = Inflector::camelize($command);
- return $this->{$command}->runCommand('execute', $argv);
- }
- if ($isMethod) {
- return $this->{$command}();
- }
- if ($isMain) {
- return $this->main();
- }
- $this->out($this->OptionParser->help($command));
- return false;
- }
-
-/**
- * Display the help in the correct format
- *
- * @param string $command
- * @return void
- */
- protected function _displayHelp($command) {
- $format = 'text';
- if (!empty($this->args[0]) && $this->args[0] == 'xml') {
- $format = 'xml';
- $this->stdout->outputAs(ConsoleOutput::RAW);
- } else {
- $this->_welcome();
- }
- return $this->out($this->OptionParser->help($command, $format));
- }
-
-/**
- * Gets the option parser instance and configures it.
- * By overriding this method you can configure the ConsoleOptionParser before returning it.
- *
- * @return ConsoleOptionParser
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::getOptionParser
- */
- public function getOptionParser() {
- $name = ($this->plugin ? $this->plugin . '.' : '') . $this->name;
- $parser = new ConsoleOptionParser($name);
- return $parser;
- }
-
-/**
- * Overload get for lazy building of tasks
- *
- * @param string $name
- * @return Shell Object of Task
- */
- public function __get($name) {
- if (empty($this->{$name}) && in_array($name, $this->taskNames)) {
- $properties = $this->_taskMap[$name];
- $this->{$name} = $this->Tasks->load($properties['class'], $properties['settings']);
- $this->{$name}->args =& $this->args;
- $this->{$name}->params =& $this->params;
- $this->{$name}->initialize();
- $this->{$name}->loadTasks();
- }
- return $this->{$name};
- }
-
-/**
- * Prompts the user for input, and returns it.
- *
- * @param string $prompt Prompt text.
- * @param mixed $options Array or string of options.
- * @param string $default Default input value.
- * @return mixed Either the default value, or the user-provided input.
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::in
- */
- public function in($prompt, $options = null, $default = null) {
- if (!$this->interactive) {
- return $default;
- }
- $originalOptions = $options;
- $in = $this->_getInput($prompt, $originalOptions, $default);
-
- if ($options && is_string($options)) {
- if (strpos($options, ',')) {
- $options = explode(',', $options);
- } elseif (strpos($options, '/')) {
- $options = explode('/', $options);
- } else {
- $options = array($options);
- }
- }
- if (is_array($options)) {
- $options = array_merge(
- array_map('strtolower', $options),
- array_map('strtoupper', $options),
- $options
- );
- while ($in === '' || !in_array($in, $options)) {
- $in = $this->_getInput($prompt, $originalOptions, $default);
- }
- }
- return $in;
- }
-
-/**
- * Prompts the user for input, and returns it.
- *
- * @param string $prompt Prompt text.
- * @param mixed $options Array or string of options.
- * @param string $default Default input value.
- * @return Either the default value, or the user-provided input.
- */
- protected function _getInput($prompt, $options, $default) {
- if (!is_array($options)) {
- $printOptions = '';
- } else {
- $printOptions = '(' . implode('/', $options) . ')';
- }
-
- if ($default === null) {
- $this->stdout->write('' . $prompt . ' ' . " $printOptions \n" . '> ', 0);
- } else {
- $this->stdout->write('' . $prompt . ' ' . " $printOptions \n" . "[$default] > ", 0);
- }
- $result = $this->stdin->read();
-
- if ($result === false) {
- $this->_stop(1);
- }
- $result = trim($result);
-
- if ($default !== null && ($result === '' || $result === null)) {
- return $default;
- }
- return $result;
- }
-
-/**
- * Wrap a block of text.
- * Allows you to set the width, and indenting on a block of text.
- *
- * ### Options
- *
- * - `width` The width to wrap to. Defaults to 72
- * - `wordWrap` Only wrap on words breaks (spaces) Defaults to true.
- * - `indent` Indent the text with the string provided. Defaults to null.
- *
- * @param string $text Text the text to format.
- * @param mixed $options Array of options to use, or an integer to wrap the text to.
- * @return string Wrapped / indented text
- * @see String::wrap()
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::wrapText
- */
- public function wrapText($text, $options = array()) {
- return String::wrap($text, $options);
- }
-
-/**
- * Outputs a single or multiple messages to stdout. If no parameters
- * are passed outputs just a newline.
- *
- * ### Output levels
- *
- * There are 3 built-in output level. Shell::QUIET, Shell::NORMAL, Shell::VERBOSE.
- * The verbose and quiet output levels, map to the `verbose` and `quiet` output switches
- * present in most shells. Using Shell::QUIET for a message means it will always display.
- * While using Shell::VERBOSE means it will only display when verbose output is toggled.
- *
- * @param mixed $message A string or a an array of strings to output
- * @param integer $newlines Number of newlines to append
- * @param integer $level The message's output level, see above.
- * @return integer|boolean Returns the number of bytes returned from writing to stdout.
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::out
- */
- public function out($message = null, $newlines = 1, $level = Shell::NORMAL) {
- $currentLevel = Shell::NORMAL;
- if (!empty($this->params['verbose'])) {
- $currentLevel = Shell::VERBOSE;
- }
- if (!empty($this->params['quiet'])) {
- $currentLevel = Shell::QUIET;
- }
- if ($level <= $currentLevel) {
- return $this->stdout->write($message, $newlines);
- }
- return true;
- }
-
-/**
- * Outputs a single or multiple error messages to stderr. If no parameters
- * are passed outputs just a newline.
- *
- * @param mixed $message A string or a an array of strings to output
- * @param integer $newlines Number of newlines to append
- * @return void
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::err
- */
- public function err($message = null, $newlines = 1) {
- $this->stderr->write($message, $newlines);
- }
-
-/**
- * Returns a single or multiple linefeeds sequences.
- *
- * @param integer $multiplier Number of times the linefeed sequence should be repeated
- * @return string
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::nl
- */
- public function nl($multiplier = 1) {
- return str_repeat(ConsoleOutput::LF, $multiplier);
- }
-
-/**
- * Outputs a series of minus characters to the standard output, acts as a visual separator.
- *
- * @param integer $newlines Number of newlines to pre- and append
- * @param integer $width Width of the line, defaults to 63
- * @return void
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hr
- */
- public function hr($newlines = 0, $width = 63) {
- $this->out(null, $newlines);
- $this->out(str_repeat('-', $width));
- $this->out(null, $newlines);
- }
-
-/**
- * Displays a formatted error message
- * and exits the application with status code 1
- *
- * @param string $title Title of the error
- * @param string $message An optional error message
- * @return void
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::error
- */
- public function error($title, $message = null) {
- $this->err(__d('cake_console', 'Error: %s', $title));
-
- if (!empty($message)) {
- $this->err($message);
- }
- $this->_stop(1);
- }
-
-/**
- * Clear the console
- *
- * @return void
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::clear
- */
- public function clear() {
- if (empty($this->params['noclear'])) {
- if (DS === '/') {
- passthru('clear');
- } else {
- passthru('cls');
- }
- }
- }
-
-/**
- * Creates a file at given path
- *
- * @param string $path Where to put the file.
- * @param string $contents Content to put in the file.
- * @return boolean Success
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::createFile
- */
- public function createFile($path, $contents) {
- $path = str_replace(DS . DS, DS, $path);
-
- $this->out();
-
- if (is_file($path) && $this->interactive === true) {
- $this->out(__d('cake_console', 'File `%s` exists ', $path));
- $key = $this->in(__d('cake_console', 'Do you want to overwrite?'), array('y', 'n', 'q'), 'n');
-
- if (strtolower($key) == 'q') {
- $this->out(__d('cake_console', 'Quitting .'), 2);
- $this->_stop();
- } elseif (strtolower($key) != 'y') {
- $this->out(__d('cake_console', 'Skip `%s`', $path), 2);
- return false;
- }
- } else {
- $this->out(__d('cake_console', 'Creating file %s', $path));
- }
-
- $File = new File($path, true);
- if ($File->exists() && $File->writable()) {
- $data = $File->prepare($contents);
- $File->write($data);
- $this->out(__d('cake_console', 'Wrote `%s`', $path));
- return true;
- } else {
- $this->err(__d('cake_console', 'Could not write to `%s` .', $path), 2);
- return false;
- }
- }
-
-/**
- * Action to create a Unit Test
- *
- * @return boolean Success
- */
- protected function _checkUnitTest() {
- if (App::import('Vendor', 'phpunit', array('file' => 'PHPUnit' . DS . 'Autoload.php'))) {
- return true;
- }
- if (@include 'PHPUnit' . DS . 'Autoload.php') {
- return true;
- }
- $prompt = __d('cake_console', 'PHPUnit is not installed. Do you want to bake unit test files anyway?');
- $unitTest = $this->in($prompt, array('y', 'n'), 'y');
- $result = strtolower($unitTest) == 'y' || strtolower($unitTest) == 'yes';
-
- if ($result) {
- $this->out();
- $this->out(__d('cake_console', 'You can download PHPUnit from %s', 'http://phpunit.de'));
- }
- return $result;
- }
-
-/**
- * Makes absolute file path easier to read
- *
- * @param string $file Absolute file path
- * @return string short path
- * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::shortPath
- */
- public function shortPath($file) {
- $shortPath = str_replace(ROOT, null, $file);
- $shortPath = str_replace('..' . DS, '', $shortPath);
- return str_replace(DS . DS, DS, $shortPath);
- }
-
-/**
- * Creates the proper controller path for the specified controller class name
- *
- * @param string $name Controller class name
- * @return string Path to controller
- */
- protected function _controllerPath($name) {
- return Inflector::underscore($name);
- }
-
-/**
- * Creates the proper controller plural name for the specified controller class name
- *
- * @param string $name Controller class name
- * @return string Controller plural name
- */
- protected function _controllerName($name) {
- return Inflector::pluralize(Inflector::camelize($name));
- }
-
-/**
- * Creates the proper model camelized name (singularized) for the specified name
- *
- * @param string $name Name
- * @return string Camelized and singularized model name
- */
- protected function _modelName($name) {
- return Inflector::camelize(Inflector::singularize($name));
- }
-
-/**
- * Creates the proper underscored model key for associations
- *
- * @param string $name Model class name
- * @return string Singular model key
- */
- protected function _modelKey($name) {
- return Inflector::underscore($name) . '_id';
- }
-
-/**
- * Creates the proper model name from a foreign key
- *
- * @param string $key Foreign key
- * @return string Model name
- */
- protected function _modelNameFromKey($key) {
- return Inflector::camelize(str_replace('_id', '', $key));
- }
-
-/**
- * creates the singular name for use in views.
- *
- * @param string $name
- * @return string $name
- */
- protected function _singularName($name) {
- return Inflector::variable(Inflector::singularize($name));
- }
-
-/**
- * Creates the plural name for views
- *
- * @param string $name Name to use
- * @return string Plural name for views
- */
- protected function _pluralName($name) {
- return Inflector::variable(Inflector::pluralize($name));
- }
-
-/**
- * Creates the singular human name used in views
- *
- * @param string $name Controller name
- * @return string Singular human name
- */
- protected function _singularHumanName($name) {
- return Inflector::humanize(Inflector::underscore(Inflector::singularize($name)));
- }
-
-/**
- * Creates the plural human name used in views
- *
- * @param string $name Controller name
- * @return string Plural human name
- */
- protected function _pluralHumanName($name) {
- return Inflector::humanize(Inflector::underscore($name));
- }
-
-/**
- * Find the correct path for a plugin. Scans $pluginPaths for the plugin you want.
- *
- * @param string $pluginName Name of the plugin you want ie. DebugKit
- * @return string $path path to the correct plugin.
- */
- protected function _pluginPath($pluginName) {
- if (CakePlugin::loaded($pluginName)) {
- return CakePlugin::path($pluginName);
- }
- return current(App::path('plugins')) . $pluginName . DS;
- }
-
-}
diff --git a/lib/Cake/Console/ShellDispatcher.php b/lib/Cake/Console/ShellDispatcher.php
deleted file mode 100644
index 5f2f5a6aa5d..00000000000
--- a/lib/Cake/Console/ShellDispatcher.php
+++ /dev/null
@@ -1,332 +0,0 @@
-_initConstants();
- }
- $this->parseParams($args);
- if ($bootstrap) {
- $this->_initEnvironment();
- }
- }
-
-/**
- * Run the dispatcher
- *
- * @param array $argv The argv from PHP
- * @return void
- */
- public static function run($argv) {
- $dispatcher = new ShellDispatcher($argv);
- $dispatcher->_stop($dispatcher->dispatch() === false ? 1 : 0);
- }
-
-/**
- * Defines core configuration.
- *
- * @return void
- */
- protected function _initConstants() {
- if (function_exists('ini_set')) {
- ini_set('html_errors', false);
- ini_set('implicit_flush', true);
- ini_set('max_execution_time', 0);
- }
-
- if (!defined('CAKE_CORE_INCLUDE_PATH')) {
- define('DS', DIRECTORY_SEPARATOR);
- define('CAKE_CORE_INCLUDE_PATH', dirname(dirname(dirname(__FILE__))));
- define('CAKEPHP_SHELL', true);
- if (!defined('CORE_PATH')) {
- define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);
- }
- }
- }
-
-/**
- * Defines current working environment.
- *
- * @return void
- * @throws CakeException
- */
- protected function _initEnvironment() {
- if (!$this->_bootstrap()) {
- $message = "Unable to load CakePHP core.\nMake sure " . DS . 'lib' . DS . 'Cake exists in ' . CAKE_CORE_INCLUDE_PATH;
- throw new CakeException($message);
- }
-
- if (!isset($this->args[0]) || !isset($this->params['working'])) {
- $message = "This file has been loaded incorrectly and cannot continue.\n" .
- "Please make sure that " . DS . 'lib' . DS . 'Cake' . DS . "Console is in your system path,\n" .
- "and check the cookbook for the correct usage of this command.\n" .
- "(http://book.cakephp.org/)";
- throw new CakeException($message);
- }
-
- $this->shiftArgs();
- }
-
-/**
- * Initializes the environment and loads the Cake core.
- *
- * @return boolean Success.
- */
- protected function _bootstrap() {
- define('ROOT', $this->params['root']);
- define('APP_DIR', $this->params['app']);
- define('APP', $this->params['working'] . DS);
- define('WWW_ROOT', APP . $this->params['webroot'] . DS);
- if (!is_dir(ROOT . DS . APP_DIR . DS . 'tmp')) {
- define('TMP', CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'tmp' . DS);
- }
- $boot = file_exists(ROOT . DS . APP_DIR . DS . 'Config' . DS . 'bootstrap.php');
- require CORE_PATH . 'Cake' . DS . 'bootstrap.php';
-
- if (!file_exists(APP . 'Config' . DS . 'core.php')) {
- include_once CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'Config' . DS . 'core.php';
- App::build();
- }
- require_once CAKE . 'Console' . DS . 'ConsoleErrorHandler.php';
- $ErrorHandler = new ConsoleErrorHandler();
- set_exception_handler(array($ErrorHandler, 'handleException'));
- set_error_handler(array($ErrorHandler, 'handleError'), Configure::read('Error.level'));
-
- if (!defined('FULL_BASE_URL')) {
- define('FULL_BASE_URL', 'http://localhost');
- }
-
- return true;
- }
-
-/**
- * Dispatches a CLI request
- *
- * @return boolean
- * @throws MissingShellMethodException
- */
- public function dispatch() {
- $shell = $this->shiftArgs();
-
- if (!$shell) {
- $this->help();
- return false;
- }
- if (in_array($shell, array('help', '--help', '-h'))) {
- $this->help();
- return true;
- }
-
- $Shell = $this->_getShell($shell);
-
- $command = null;
- if (isset($this->args[0])) {
- $command = $this->args[0];
- }
-
- if ($Shell instanceof Shell) {
- $Shell->initialize();
- $Shell->loadTasks();
- return $Shell->runCommand($command, $this->args);
- }
- $methods = array_diff(get_class_methods($Shell), get_class_methods('Shell'));
- $added = in_array($command, $methods);
- $private = $command[0] == '_' && method_exists($Shell, $command);
-
- if (!$private) {
- if ($added) {
- $this->shiftArgs();
- $Shell->startup();
- return $Shell->{$command}();
- }
- if (method_exists($Shell, 'main')) {
- $Shell->startup();
- return $Shell->main();
- }
- }
- throw new MissingShellMethodException(array('shell' => $shell, 'method' => $arg));
- }
-
-/**
- * Get shell to use, either plugin shell or application shell
- *
- * All paths in the loaded shell paths are searched.
- *
- * @param string $shell Optionally the name of a plugin
- * @return mixed An object
- * @throws MissingShellException when errors are encountered.
- */
- protected function _getShell($shell) {
- list($plugin, $shell) = pluginSplit($shell, true);
-
- $plugin = Inflector::camelize($plugin);
- $class = Inflector::camelize($shell) . 'Shell';
-
- App::uses('Shell', 'Console');
- App::uses('AppShell', 'Console/Command');
- App::uses($class, $plugin . 'Console/Command');
-
- if (!class_exists($class)) {
- throw new MissingShellException(array(
- 'class' => $class
- ));
- }
- $Shell = new $class();
- $Shell->plugin = trim($plugin, '.');
- return $Shell;
- }
-
-/**
- * Parses command line options and extracts the directory paths from $params
- *
- * @param array $args Parameters to parse
- * @return void
- */
- public function parseParams($args) {
- $this->_parsePaths($args);
-
- $defaults = array(
- 'app' => 'app',
- 'root' => dirname(dirname(dirname(dirname(__FILE__)))),
- 'working' => null,
- 'webroot' => 'webroot'
- );
- $params = array_merge($defaults, array_intersect_key($this->params, $defaults));
- $isWin = false;
- foreach ($defaults as $default => $value) {
- if (strpos($params[$default], '\\') !== false) {
- $isWin = true;
- break;
- }
- }
- $params = str_replace('\\', '/', $params);
-
- if (isset($params['working'])) {
- $params['working'] = trim($params['working']);
- }
- if (!empty($params['working']) && (!isset($this->args[0]) || isset($this->args[0]) && $this->args[0]{0} !== '.')) {
- if (empty($this->params['app']) && $params['working'] != $params['root']) {
- $params['root'] = dirname($params['working']);
- $params['app'] = basename($params['working']);
- } else {
- $params['root'] = $params['working'];
- }
- }
-
- if ($params['app'][0] == '/' || preg_match('/([a-z])(:)/i', $params['app'], $matches)) {
- $params['root'] = dirname($params['app']);
- } elseif (strpos($params['app'], '/')) {
- $params['root'] .= '/' . dirname($params['app']);
- }
-
- $params['app'] = basename($params['app']);
- $params['working'] = rtrim($params['root'], '/');
- if (!$isWin || !preg_match('/^[A-Z]:$/i', $params['app'])) {
- $params['working'] .= '/' . $params['app'];
- }
-
- if (!empty($matches[0]) || !empty($isWin)) {
- $params = str_replace('/', '\\', $params);
- }
-
- $this->params = array_merge($this->params, $params);
- }
-
-/**
- * Parses out the paths from from the argv
- *
- * @param array $args
- * @return void
- */
- protected function _parsePaths($args) {
- $parsed = array();
- $keys = array('-working', '--working', '-app', '--app', '-root', '--root');
- foreach ($keys as $key) {
- while (($index = array_search($key, $args)) !== false) {
- $keyname = str_replace('-', '', $key);
- $valueIndex = $index + 1;
- $parsed[$keyname] = $args[$valueIndex];
- array_splice($args, $index, 2);
- }
- }
- $this->args = $args;
- $this->params = $parsed;
- }
-
-/**
- * Removes first argument and shifts other arguments up
- *
- * @return mixed Null if there are no arguments otherwise the shifted argument
- */
- public function shiftArgs() {
- return array_shift($this->args);
- }
-
-/**
- * Shows console help. Performs an internal dispatch to the CommandList Shell
- *
- * @return void
- */
- public function help() {
- $this->args = array_merge(array('command_list'), $this->args);
- $this->dispatch();
- }
-
-/**
- * Stop execution of the current script
- *
- * @param integer|string $status see http://php.net/exit for values
- * @return void
- */
- protected function _stop($status = 0) {
- exit($status);
- }
-
-}
diff --git a/lib/Cake/Console/TaskCollection.php b/lib/Cake/Console/TaskCollection.php
deleted file mode 100644
index 35f21eecf68..00000000000
--- a/lib/Cake/Console/TaskCollection.php
+++ /dev/null
@@ -1,82 +0,0 @@
-_Shell = $Shell;
- }
-
-/**
- * Loads/constructs a task. Will return the instance in the collection
- * if it already exists.
- *
- * @param string $task Task name to load
- * @param array $settings Settings for the task.
- * @return Task A task object, Either the existing loaded task or a new one.
- * @throws MissingTaskException when the task could not be found
- */
- public function load($task, $settings = array()) {
- list($plugin, $name) = pluginSplit($task, true);
-
- if (isset($this->_loaded[$name])) {
- return $this->_loaded[$name];
- }
- $taskClass = $name . 'Task';
- App::uses($taskClass, $plugin . 'Console/Command/Task');
- if (!class_exists($taskClass)) {
- if (!class_exists($taskClass)) {
- throw new MissingTaskException(array(
- 'class' => $taskClass
- ));
- }
- }
-
- $this->_loaded[$name] = new $taskClass(
- $this->_Shell->stdout, $this->_Shell->stderr, $this->_Shell->stdin
- );
- return $this->_loaded[$name];
- }
-
-}
diff --git a/lib/Cake/Console/Templates/default/actions/controller_actions.ctp b/lib/Cake/Console/Templates/default/actions/controller_actions.ctp
deleted file mode 100644
index c0921c2c4ac..00000000000
--- a/lib/Cake/Console/Templates/default/actions/controller_actions.ctp
+++ /dev/null
@@ -1,157 +0,0 @@
-
-
-/**
- * index method
- *
- * @return void
- */
- public function index() {
- $this->->recursive = 0;
- $this->set('', $this->paginate());
- }
-
-/**
- * view method
- *
- * @param string $id
- * @return void
- */
- public function view($id = null) {
- $this->->id = $id;
- if (!$this->->exists()) {
- throw new NotFoundException(__('Invalid '));
- }
- $this->set('', $this->->read(null, $id));
- }
-
-
-/**
- * add method
- *
- * @return void
- */
- public function add() {
- if ($this->request->is('post')) {
- $this->->create();
- if ($this->->save($this->request->data)) {
-
- $this->Session->setFlash(__('The has been saved'));
- $this->redirect(array('action' => 'index'));
-
- $this->flash(__(' saved.'), array('action' => 'index'));
-
- } else {
-
- $this->Session->setFlash(__('The could not be saved. Please, try again.'));
-
- }
- }
-{$assoc} as $associationName => $relation):
- if (!empty($associationName)):
- $otherModelName = $this->_modelName($associationName);
- $otherPluralName = $this->_pluralName($associationName);
- echo "\t\t\${$otherPluralName} = \$this->{$currentModelName}->{$otherModelName}->find('list');\n";
- $compact[] = "'{$otherPluralName}'";
- endif;
- endforeach;
- endforeach;
- if (!empty($compact)):
- echo "\t\t\$this->set(compact(".join(', ', $compact)."));\n";
- endif;
-?>
- }
-
-
-/**
- * edit method
- *
- * @param string $id
- * @return void
- */
- public function edit($id = null) {
- $this->->id = $id;
- if (!$this->->exists()) {
- throw new NotFoundException(__('Invalid '));
- }
- if ($this->request->is('post') || $this->request->is('put')) {
- if ($this->->save($this->request->data)) {
-
- $this->Session->setFlash(__('The has been saved'));
- $this->redirect(array('action' => 'index'));
-
- $this->flash(__('The has been saved.'), array('action' => 'index'));
-
- } else {
-
- $this->Session->setFlash(__('The could not be saved. Please, try again.'));
-
- }
- } else {
- $this->request->data = $this->->read(null, $id);
- }
-{$assoc} as $associationName => $relation):
- if (!empty($associationName)):
- $otherModelName = $this->_modelName($associationName);
- $otherPluralName = $this->_pluralName($associationName);
- echo "\t\t\${$otherPluralName} = \$this->{$currentModelName}->{$otherModelName}->find('list');\n";
- $compact[] = "'{$otherPluralName}'";
- endif;
- endforeach;
- endforeach;
- if (!empty($compact)):
- echo "\t\t\$this->set(compact(".join(', ', $compact)."));\n";
- endif;
- ?>
- }
-
-/**
- * delete method
- *
- * @param string $id
- * @return void
- */
- public function delete($id = null) {
- if (!$this->request->is('post')) {
- throw new MethodNotAllowedException();
- }
- $this->->id = $id;
- if (!$this->->exists()) {
- throw new NotFoundException(__('Invalid '));
- }
- if ($this->->delete()) {
-
- $this->Session->setFlash(__(' deleted'));
- $this->redirect(array('action' => 'index'));
-
- $this->flash(__(' deleted'), array('action' => 'index'));
-
- }
-
- $this->Session->setFlash(__(' was not deleted'));
-
- $this->flash(__(' was not deleted'), array('action' => 'index'));
-
- $this->redirect(array('action' => 'index'));
- }
\ No newline at end of file
diff --git a/lib/Cake/Console/Templates/default/classes/controller.ctp b/lib/Cake/Console/Templates/default/classes/controller.ctp
deleted file mode 100644
index 741e06b0079..00000000000
--- a/lib/Cake/Console/Templates/default/classes/controller.ctp
+++ /dev/null
@@ -1,81 +0,0 @@
-
-/**
- * Controller
- *
-
- */
-class Controller extends AppController {
-
-
-/**
- * Scaffold
- *
- * @var mixed
- */
- public $scaffold;
-
-
-
-}
diff --git a/lib/Cake/Console/Templates/default/classes/fixture.ctp b/lib/Cake/Console/Templates/default/classes/fixture.ctp
deleted file mode 100644
index 48f6c78345a..00000000000
--- a/lib/Cake/Console/Templates/default/classes/fixture.ctp
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-/**
- * Fixture
- *
- */
-class Fixture extends CakeTestFixture {
-
-/**
- * Table name
- *
- * @var string
- */
- public $table = '';
-
-
-/**
- * Import
- *
- * @var array
- */
- public $import = ;
-
-
-
-/**
- * Fields
- *
- * @var array
- */
- public $fields = ;
-
-
-
-/**
- * Records
- *
- * @var array
- */
- public $records = ;
-
-}
diff --git a/lib/Cake/Console/Templates/default/classes/model.ctp b/lib/Cake/Console/Templates/default/classes/model.ctp
deleted file mode 100644
index 3634b802ff5..00000000000
--- a/lib/Cake/Console/Templates/default/classes/model.ctp
+++ /dev/null
@@ -1,175 +0,0 @@
-
-/**
- * Model
- *
-
- */
-class extends AppModel {
-
-/**
- * Use database config
- *
- * @var string
- */
- public $useDbConfig = '';
-
-
-/**
- * Primary key field
- *
- * @var string
- */
- public $primaryKey = '';
-
-/**
- * Display field
- *
- * @var string
- */
- public $displayField = '';
- $validations):
- echo "\t\t'$field' => array(\n";
- foreach ($validations as $key => $validator):
- echo "\t\t\t'$key' => array(\n";
- echo "\t\t\t\t'rule' => array('$validator'),\n";
- echo "\t\t\t\t//'message' => 'Your custom message here',\n";
- echo "\t\t\t\t//'allowEmpty' => false,\n";
- echo "\t\t\t\t//'required' => false,\n";
- echo "\t\t\t\t//'last' => false, // Stop validation after this rule\n";
- echo "\t\t\t\t//'on' => 'create', // Limit validation to 'create' or 'update' operations\n";
- echo "\t\t\t),\n";
- endforeach;
- echo "\t\t),\n";
- endforeach;
- echo "\t);\n";
-endif;
-
-foreach ($associations as $assoc):
- if (!empty($assoc)):
-?>
-
- //The Associations below have been created with all possible keys, those that are not needed can be removed
- $relation):
- $out = "\n\t\t'{$relation['alias']}' => array(\n";
- $out .= "\t\t\t'className' => '{$relation['className']}',\n";
- $out .= "\t\t\t'foreignKey' => '{$relation['foreignKey']}',\n";
- $out .= "\t\t\t'conditions' => '',\n";
- $out .= "\t\t\t'fields' => '',\n";
- $out .= "\t\t\t'order' => ''\n";
- $out .= "\t\t)";
- if ($i + 1 < $typeCount) {
- $out .= ",";
- }
- echo $out;
- endforeach;
- echo "\n\t);\n";
- endif;
-endforeach;
-
-if (!empty($associations['hasMany'])):
- $belongsToCount = count($associations['hasMany']);
- echo "\n/**\n * hasMany associations\n *\n * @var array\n */";
- echo "\n\tpublic \$hasMany = array(";
- foreach ($associations['hasMany'] as $i => $relation):
- $out = "\n\t\t'{$relation['alias']}' => array(\n";
- $out .= "\t\t\t'className' => '{$relation['className']}',\n";
- $out .= "\t\t\t'foreignKey' => '{$relation['foreignKey']}',\n";
- $out .= "\t\t\t'dependent' => false,\n";
- $out .= "\t\t\t'conditions' => '',\n";
- $out .= "\t\t\t'fields' => '',\n";
- $out .= "\t\t\t'order' => '',\n";
- $out .= "\t\t\t'limit' => '',\n";
- $out .= "\t\t\t'offset' => '',\n";
- $out .= "\t\t\t'exclusive' => '',\n";
- $out .= "\t\t\t'finderQuery' => '',\n";
- $out .= "\t\t\t'counterQuery' => ''\n";
- $out .= "\t\t)";
- if ($i + 1 < $belongsToCount) {
- $out .= ",";
- }
- echo $out;
- endforeach;
- echo "\n\t);\n\n";
-endif;
-
-if (!empty($associations['hasAndBelongsToMany'])):
- $habtmCount = count($associations['hasAndBelongsToMany']);
- echo "\n/**\n * hasAndBelongsToMany associations\n *\n * @var array\n */";
- echo "\n\tpublic \$hasAndBelongsToMany = array(";
- foreach ($associations['hasAndBelongsToMany'] as $i => $relation):
- $out = "\n\t\t'{$relation['alias']}' => array(\n";
- $out .= "\t\t\t'className' => '{$relation['className']}',\n";
- $out .= "\t\t\t'joinTable' => '{$relation['joinTable']}',\n";
- $out .= "\t\t\t'foreignKey' => '{$relation['foreignKey']}',\n";
- $out .= "\t\t\t'associationForeignKey' => '{$relation['associationForeignKey']}',\n";
- $out .= "\t\t\t'unique' => 'keepExisting',\n";
- $out .= "\t\t\t'conditions' => '',\n";
- $out .= "\t\t\t'fields' => '',\n";
- $out .= "\t\t\t'order' => '',\n";
- $out .= "\t\t\t'limit' => '',\n";
- $out .= "\t\t\t'offset' => '',\n";
- $out .= "\t\t\t'finderQuery' => '',\n";
- $out .= "\t\t\t'deleteQuery' => '',\n";
- $out .= "\t\t\t'insertQuery' => ''\n";
- $out .= "\t\t)";
- if ($i + 1 < $habtmCount) {
- $out .= ",";
- }
- echo $out;
- endforeach;
- echo "\n\t);\n\n";
-endif;
-?>
-}
diff --git a/lib/Cake/Console/Templates/default/classes/test.ctp b/lib/Cake/Console/Templates/default/classes/test.ctp
deleted file mode 100644
index ecf8ea8a5d1..00000000000
--- a/lib/Cake/Console/Templates/default/classes/test.ctp
+++ /dev/null
@@ -1,100 +0,0 @@
-
-
-App::uses('', '');
-
-
-
-/**
- * Test
- *
- */
-class Test extends {
-/**
- * Auto render
- *
- * @var boolean
- */
- public $autoRender = false;
-
-/**
- * Redirect action
- *
- * @param mixed $url
- * @param mixed $status
- * @param boolean $exit
- * @return void
- */
- public function redirect($url, $status = null, $exit = true) {
- $this->redirectUrl = $url;
- }
-}
-
-
-/**
- * Test Case
- *
- */
-class TestCase extends CakeTestCase {
-
-/**
- * Fixtures
- *
- * @var array
- */
- public $fixtures = array('');
-
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
-
- $this->
-
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- unset($this->);
-
- parent::tearDown();
- }
-
-
-/**
- * test method
- *
- * @return void
- */
- public function test() {
-
- }
-
-}
diff --git a/lib/Cake/Console/Templates/default/views/form.ctp b/lib/Cake/Console/Templates/default/views/form.ctp
deleted file mode 100644
index aaf3c23d7cf..00000000000
--- a/lib/Cake/Console/Templates/default/views/form.ctp
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-Form->create('{$modelClass}');?>\n";?>
-
- ", Inflector::humanize($action), $singularHumanName); ?>
-Form->input('{$field}');\n";
- }
- }
- if (!empty($associations['hasAndBelongsToMany'])) {
- foreach ($associations['hasAndBelongsToMany'] as $assocName => $assocData) {
- echo "\t\techo \$this->Form->input('{$assocName}');\n";
- }
- }
- echo "\t?>\n";
-?>
-
-Form->end(__('Submit'));?>\n";
-?>
-
-
-
"; ?>
-
-
-
- Form->postLink(__('Delete'), array('action' => 'delete', \$this->Form->value('{$modelClass}.{$primaryKey}')), null, __('Are you sure you want to delete # %s?', \$this->Form->value('{$modelClass}.{$primaryKey}'))); ?>";?>
-
- Html->link(__('List " . $pluralHumanName . "'), array('action' => 'index'));?>";?>
- $data) {
- foreach ($data as $alias => $details) {
- if ($details['controller'] != $this->name && !in_array($details['controller'], $done)) {
- echo "\t\tHtml->link(__('List " . Inflector::humanize($details['controller']) . "'), array('controller' => '{$details['controller']}', 'action' => 'index')); ?> \n";
- echo "\t\tHtml->link(__('New " . Inflector::humanize(Inflector::underscore($alias)) . "'), array('controller' => '{$details['controller']}', 'action' => 'add')); ?> \n";
- $done[] = $details['controller'];
- }
- }
- }
-?>
-
-
diff --git a/lib/Cake/Console/Templates/default/views/home.ctp b/lib/Cake/Console/Templates/default/views/home.ctp
deleted file mode 100644
index 424051981fc..00000000000
--- a/lib/Cake/Console/Templates/default/views/home.ctp
+++ /dev/null
@@ -1,113 +0,0 @@
-
- For updates and important announcements, visit http://cakefest.org
-\n";
-$output .= "Sweet, \"" . Inflector::humanize($app) . "\" got Baked by CakePHP! \n";
-$output .="
- 0):
- Debugger::checkSecurityKeys();
-endif;
-?>
-
-=')):
- echo '';
- echo __d('cake_dev', 'Your version of PHP is 5.2.8 or higher.');
- echo ' ';
- else:
- echo '';
- echo __d('cake_dev', 'Your version of PHP is too low. You need PHP 5.2.8 or higher to use CakePHP.');
- echo ' ';
- endif;
-?>
-
-
-';
- echo __d('cake_dev', 'Your tmp directory is writable.');
- echo '';
- else:
- echo '';
- echo __d('cake_dev', 'Your tmp directory is NOT writable.');
- echo ' ';
- endif;
-?>
-
-
-';
- echo __d('cake_dev', 'The %s is being used for core caching. To change the config edit APP/Config/core.php ', ''. \$settings['engine'] . 'Engine ');
- echo '';
- else:
- echo '';
- echo __d('cake_dev', 'Your cache is NOT working. Please check the settings in APP/Config/core.php');
- echo ' ';
- endif;
-?>
-
-
-';
- echo __d('cake_dev', 'Your database configuration file is present.');
- \$filePresent = true;
- echo '';
- else:
- echo '';
- echo __d('cake_dev', 'Your database configuration file is NOT present.');
- echo ' ';
- echo __d('cake_dev', 'Rename APP/Config/database.php.default to APP/Config/database.php');
- echo ' ';
- endif;
-?>
-
-
-
- isConnected()):
- echo '';
- echo __d('cake_dev', 'Cake is able to connect to the database.');
- echo ' ';
- else:
- echo '';
- echo __d('cake_dev', 'Cake is NOT able to connect to the database.');
- echo ' ';
- endif;
- ?>
-
-
-';
- __d('cake_dev', 'PCRE has not been compiled with Unicode support.');
- echo ' ';
- __d('cake_dev', 'Recompile PCRE with Unicode support by adding --enable-unicode-properties when configuring');
- echo ' ';
- }
-?>\n";
-$output .= " \n";
-$output .= "\n";
-$output .= "', APP . 'View' . DS . 'Layouts' . DS . 'default.ctp. ', APP . 'webroot' . DS . 'css');\n";
-$output .= "?>\n";
-$output .= "
\n";
-?>
diff --git a/lib/Cake/Console/Templates/default/views/index.ctp b/lib/Cake/Console/Templates/default/views/index.ctp
deleted file mode 100644
index ded100e8e67..00000000000
--- a/lib/Cake/Console/Templates/default/views/index.ctp
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
-
";?>
-
-
-
- Paginator->sort('{$field}');?>";?>
-
- ";?>
-
- \n";
- echo "\t\n";
- foreach ($fields as $field) {
- $isKey = false;
- if (!empty($associations['belongsTo'])) {
- foreach ($associations['belongsTo'] as $alias => $details) {
- if ($field === $details['foreignKey']) {
- $isKey = true;
- echo "\t\t\n\t\t\tHtml->link(\${$singularVar}['{$alias}']['{$details['displayField']}'], array('controller' => '{$details['controller']}', 'action' => 'view', \${$singularVar}['{$alias}']['{$details['primaryKey']}'])); ?>\n\t\t \n";
- break;
- }
- }
- }
- if ($isKey !== true) {
- echo "\t\t \n";
- }
- }
-
- echo "\t\t\n";
- echo "\t\t\tHtml->link(__('View'), array('action' => 'view', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n";
- echo "\t\t\tHtml->link(__('Edit'), array('action' => 'edit', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n";
- echo "\t\t\tForm->postLink(__('Delete'), array('action' => 'delete', \${$singularVar}['{$modelClass}']['{$primaryKey}']), null, __('Are you sure you want to delete # %s?', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?>\n";
- echo "\t\t \n";
- echo "\t \n";
-
- echo "\n";
- ?>
-
-
- Paginator->counter(array(
- 'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
- ));
- ?>";?>
-
-
-
- Paginator->prev('< ' . __('previous'), array(), null, array('class' => 'prev disabled'));\n";
- echo "\t\techo \$this->Paginator->numbers(array('separator' => ''));\n";
- echo "\t\techo \$this->Paginator->next(__('next') . ' >', array(), null, array('class' => 'next disabled'));\n";
- echo "\t?>\n";
- ?>
-
-
-
-
"; ?>
-
- Html->link(__('New " . $singularHumanName . "'), array('action' => 'add')); ?>";?>
- $data) {
- foreach ($data as $alias => $details) {
- if ($details['controller'] != $this->name && !in_array($details['controller'], $done)) {
- echo "\t\tHtml->link(__('List " . Inflector::humanize($details['controller']) . "'), array('controller' => '{$details['controller']}', 'action' => 'index')); ?> \n";
- echo "\t\tHtml->link(__('New " . Inflector::humanize(Inflector::underscore($alias)) . "'), array('controller' => '{$details['controller']}', 'action' => 'add')); ?> \n";
- $done[] = $details['controller'];
- }
- }
- }
-?>
-
-
diff --git a/lib/Cake/Console/Templates/default/views/view.ctp b/lib/Cake/Console/Templates/default/views/view.ctp
deleted file mode 100644
index 5daf35f2d13..00000000000
--- a/lib/Cake/Console/Templates/default/views/view.ctp
+++ /dev/null
@@ -1,139 +0,0 @@
-
-
-
";?>
-
- $details) {
- if ($field === $details['foreignKey']) {
- $isKey = true;
- echo "\t\t \n";
- echo "\t\t\n\t\t\tHtml->link(\${$singularVar}['{$alias}']['{$details['displayField']}'], array('controller' => '{$details['controller']}', 'action' => 'view', \${$singularVar}['{$alias}']['{$details['primaryKey']}'])); ?>\n\t\t\t \n\t\t \n";
- break;
- }
- }
- }
- if ($isKey !== true) {
- echo "\t\t \n";
- echo "\t\t\n\t\t\t\n\t\t\t \n\t\t \n";
- }
-}
-?>
-
-
-
-
"; ?>
-
-Html->link(__('Edit " . $singularHumanName ."'), array('action' => 'edit', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?> \n";
- echo "\t\tForm->postLink(__('Delete " . $singularHumanName . "'), array('action' => 'delete', \${$singularVar}['{$modelClass}']['{$primaryKey}']), null, __('Are you sure you want to delete # %s?', \${$singularVar}['{$modelClass}']['{$primaryKey}'])); ?> \n";
- echo "\t\tHtml->link(__('List " . $pluralHumanName . "'), array('action' => 'index')); ?> \n";
- echo "\t\tHtml->link(__('New " . $singularHumanName . "'), array('action' => 'add')); ?> \n";
-
- $done = array();
- foreach ($associations as $type => $data) {
- foreach ($data as $alias => $details) {
- if ($details['controller'] != $this->name && !in_array($details['controller'], $done)) {
- echo "\t\tHtml->link(__('List " . Inflector::humanize($details['controller']) . "'), array('controller' => '{$details['controller']}', 'action' => 'index')); ?> \n";
- echo "\t\tHtml->link(__('New " . Inflector::humanize(Inflector::underscore($alias)) . "'), array('controller' => '{$details['controller']}', 'action' => 'add')); ?> \n";
- $done[] = $details['controller'];
- }
- }
- }
-?>
-
-
- $details): ?>
-
- $details):
- $otherSingularVar = Inflector::variable($alias);
- $otherPluralHumanName = Inflector::humanize($details['controller']);
- ?>
-
-
diff --git a/lib/Cake/Console/Templates/skel/.htaccess b/lib/Cake/Console/Templates/skel/.htaccess
deleted file mode 100644
index fc3aac4b296..00000000000
--- a/lib/Cake/Console/Templates/skel/.htaccess
+++ /dev/null
@@ -1,5 +0,0 @@
-
- RewriteEngine on
- RewriteRule ^$ webroot/ [L]
- RewriteRule (.*) webroot/$1 [L]
-
\ No newline at end of file
diff --git a/lib/Cake/Console/Templates/skel/Config/Schema/db_acl.php b/lib/Cake/Console/Templates/skel/Config/Schema/db_acl.php
deleted file mode 100644
index de359628265..00000000000
--- a/lib/Cake/Console/Templates/skel/Config/Schema/db_acl.php
+++ /dev/null
@@ -1,74 +0,0 @@
- array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 10, 'key' => 'primary'),
- 'parent_id' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
- 'model' => array('type' => 'string', 'null' => true),
- 'foreign_key' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
- 'alias' => array('type' => 'string', 'null' => true),
- 'lft' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
- 'rght' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
- );
-
- public $aros = array(
- 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 10, 'key' => 'primary'),
- 'parent_id' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
- 'model' => array('type' => 'string', 'null' => true),
- 'foreign_key' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
- 'alias' => array('type' => 'string', 'null' => true),
- 'lft' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
- 'rght' => array('type' => 'integer', 'null' => true, 'default' => null, 'length' => 10),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
- );
-
- public $aros_acos = array(
- 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 10, 'key' => 'primary'),
- 'aro_id' => array('type' => 'integer', 'null' => false, 'length' => 10, 'key' => 'index'),
- 'aco_id' => array('type' => 'integer', 'null' => false, 'length' => 10),
- '_create' => array('type' => 'string', 'null' => false, 'default' => '0', 'length' => 2),
- '_read' => array('type' => 'string', 'null' => false, 'default' => '0', 'length' => 2),
- '_update' => array('type' => 'string', 'null' => false, 'default' => '0', 'length' => 2),
- '_delete' => array('type' => 'string', 'null' => false, 'default' => '0', 'length' => 2),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'ARO_ACO_KEY' => array('column' => array('aro_id', 'aco_id'), 'unique' => 1))
- );
-
-}
diff --git a/lib/Cake/Console/Templates/skel/Config/Schema/db_acl.sql b/lib/Cake/Console/Templates/skel/Config/Schema/db_acl.sql
deleted file mode 100644
index f50f3921e8c..00000000000
--- a/lib/Cake/Console/Templates/skel/Config/Schema/db_acl.sql
+++ /dev/null
@@ -1,40 +0,0 @@
-# $Id$
-#
-# Copyright 2005-2012, Cake Software Foundation, Inc.
-#
-# Licensed under The MIT License
-# Redistributions of files must retain the above copyright notice.
-# MIT License (http://www.opensource.org/licenses/mit-license.php)
-
-CREATE TABLE acos (
- id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
- parent_id INTEGER(10) DEFAULT NULL,
- model VARCHAR(255) DEFAULT '',
- foreign_key INTEGER(10) UNSIGNED DEFAULT NULL,
- alias VARCHAR(255) DEFAULT '',
- lft INTEGER(10) DEFAULT NULL,
- rght INTEGER(10) DEFAULT NULL,
- PRIMARY KEY (id)
-);
-
-CREATE TABLE aros_acos (
- id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
- aro_id INTEGER(10) UNSIGNED NOT NULL,
- aco_id INTEGER(10) UNSIGNED NOT NULL,
- _create CHAR(2) NOT NULL DEFAULT 0,
- _read CHAR(2) NOT NULL DEFAULT 0,
- _update CHAR(2) NOT NULL DEFAULT 0,
- _delete CHAR(2) NOT NULL DEFAULT 0,
- PRIMARY KEY(id)
-);
-
-CREATE TABLE aros (
- id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
- parent_id INTEGER(10) DEFAULT NULL,
- model VARCHAR(255) DEFAULT '',
- foreign_key INTEGER(10) UNSIGNED DEFAULT NULL,
- alias VARCHAR(255) DEFAULT '',
- lft INTEGER(10) DEFAULT NULL,
- rght INTEGER(10) DEFAULT NULL,
- PRIMARY KEY (id)
-);
\ No newline at end of file
diff --git a/lib/Cake/Console/Templates/skel/Config/Schema/i18n.php b/lib/Cake/Console/Templates/skel/Config/Schema/i18n.php
deleted file mode 100644
index 1a29ffd986a..00000000000
--- a/lib/Cake/Console/Templates/skel/Config/Schema/i18n.php
+++ /dev/null
@@ -1,51 +0,0 @@
- array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 10, 'key' => 'primary'),
- 'locale' => array('type' => 'string', 'null' => false, 'length' => 6, 'key' => 'index'),
- 'model' => array('type' => 'string', 'null' => false, 'key' => 'index'),
- 'foreign_key' => array('type' => 'integer', 'null' => false, 'length' => 10, 'key' => 'index'),
- 'field' => array('type' => 'string', 'null' => false, 'key' => 'index'),
- 'content' => array('type' => 'text', 'null' => true, 'default' => null),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'locale' => array('column' => 'locale', 'unique' => 0), 'model' => array('column' => 'model', 'unique' => 0), 'row_id' => array('column' => 'foreign_key', 'unique' => 0), 'field' => array('column' => 'field', 'unique' => 0))
- );
-
-}
diff --git a/lib/Cake/Console/Templates/skel/Config/Schema/i18n.sql b/lib/Cake/Console/Templates/skel/Config/Schema/i18n.sql
deleted file mode 100644
index 239e146230a..00000000000
--- a/lib/Cake/Console/Templates/skel/Config/Schema/i18n.sql
+++ /dev/null
@@ -1,26 +0,0 @@
-# $Id$
-#
-# Copyright 2005-2012, Cake Software Foundation, Inc.
-#
-# Licensed under The MIT License
-# Redistributions of files must retain the above copyright notice.
-# MIT License (http://www.opensource.org/licenses/mit-license.php)
-
-CREATE TABLE i18n (
- id int(10) NOT NULL auto_increment,
- locale varchar(6) NOT NULL,
- model varchar(255) NOT NULL,
- foreign_key int(10) NOT NULL,
- field varchar(255) NOT NULL,
- content mediumtext,
- PRIMARY KEY (id),
-# UNIQUE INDEX I18N_LOCALE_FIELD(locale, model, foreign_key, field),
-# INDEX I18N_LOCALE_ROW(locale, model, foreign_key),
-# INDEX I18N_LOCALE_MODEL(locale, model),
-# INDEX I18N_FIELD(model, foreign_key, field),
-# INDEX I18N_ROW(model, foreign_key),
- INDEX locale (locale),
- INDEX model (model),
- INDEX row_id (foreign_key),
- INDEX field (field)
-);
\ No newline at end of file
diff --git a/lib/Cake/Console/Templates/skel/Config/Schema/sessions.php b/lib/Cake/Console/Templates/skel/Config/Schema/sessions.php
deleted file mode 100644
index d83e09662e5..00000000000
--- a/lib/Cake/Console/Templates/skel/Config/Schema/sessions.php
+++ /dev/null
@@ -1,48 +0,0 @@
- array('type' => 'string', 'null' => false, 'key' => 'primary'),
- 'data' => array('type' => 'text', 'null' => true, 'default' => null),
- 'expires' => array('type' => 'integer', 'null' => true, 'default' => null),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
- );
-
-}
diff --git a/lib/Cake/Console/Templates/skel/Config/Schema/sessions.sql b/lib/Cake/Console/Templates/skel/Config/Schema/sessions.sql
deleted file mode 100644
index b8951b6f5d4..00000000000
--- a/lib/Cake/Console/Templates/skel/Config/Schema/sessions.sql
+++ /dev/null
@@ -1,16 +0,0 @@
-# $Id$
-#
-# Copyright 2005-2012, Cake Software Foundation, Inc.
-# 1785 E. Sahara Avenue, Suite 490-204
-# Las Vegas, Nevada 89104
-#
-# Licensed under The MIT License
-# Redistributions of files must retain the above copyright notice.
-# MIT License (http://www.opensource.org/licenses/mit-license.php)
-
-CREATE TABLE cake_sessions (
- id varchar(255) NOT NULL default '',
- data text,
- expires int(11) default NULL,
- PRIMARY KEY (id)
-);
\ No newline at end of file
diff --git a/lib/Cake/Console/Templates/skel/Config/acl.ini.php b/lib/Cake/Console/Templates/skel/Config/acl.ini.php
deleted file mode 100644
index 11ce65b5723..00000000000
--- a/lib/Cake/Console/Templates/skel/Config/acl.ini.php
+++ /dev/null
@@ -1,68 +0,0 @@
-;
-;/**
-; * ACL Configuration
-; *
-; *
-; * PHP 5
-; *
-; * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
-; * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
-; *
-; * Licensed under The MIT License
-; * Redistributions of files must retain the above copyright notice.
-; *
-; * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
-; * @link http://cakephp.org CakePHP(tm) Project
-; * @package app.Config
-; * @since CakePHP(tm) v 0.10.0.1076
-; * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
-; */
-
-; acl.ini.php - Cake ACL Configuration
-; ---------------------------------------------------------------------
-; Use this file to specify user permissions.
-; aco = access control object (something in your application)
-; aro = access request object (something requesting access)
-;
-; User records are added as follows:
-;
-; [uid]
-; groups = group1, group2, group3
-; allow = aco1, aco2, aco3
-; deny = aco4, aco5, aco6
-;
-; Group records are added in a similar manner:
-;
-; [gid]
-; allow = aco1, aco2, aco3
-; deny = aco4, aco5, aco6
-;
-; The allow, deny, and groups sections are all optional.
-; NOTE: groups names *cannot* ever be the same as usernames!
-;
-; ACL permissions are checked in the following order:
-; 1. Check for user denies (and DENY if specified)
-; 2. Check for user allows (and ALLOW if specified)
-; 3. Gather user's groups
-; 4. Check group denies (and DENY if specified)
-; 5. Check group allows (and ALLOW if specified)
-; 6. If no aro, aco, or group information is found, DENY
-;
-; ---------------------------------------------------------------------
-
-;-------------------------------------
-;Users
-;-------------------------------------
-
-[username-goes-here]
-groups = group1, group2
-deny = aco1, aco2
-allow = aco3, aco4
-
-;-------------------------------------
-;Groups
-;-------------------------------------
-
-[groupname-goes-here]
-deny = aco5, aco6
-allow = aco7, aco8
diff --git a/lib/Cake/Console/Templates/skel/Config/bootstrap.php b/lib/Cake/Console/Templates/skel/Config/bootstrap.php
deleted file mode 100644
index 78ac2896e0a..00000000000
--- a/lib/Cake/Console/Templates/skel/Config/bootstrap.php
+++ /dev/null
@@ -1,65 +0,0 @@
- 'File'));
-
-/**
- * The settings below can be used to set additional paths to models, views and controllers.
- *
- * App::build(array(
- * 'Plugin' => array('/full/path/to/plugins/', '/next/full/path/to/plugins/'),
- * 'Model' => array('/full/path/to/models/', '/next/full/path/to/models/'),
- * 'View' => array('/full/path/to/views/', '/next/full/path/to/views/'),
- * 'Controller' => array('/full/path/to/controllers/', '/next/full/path/to/controllers/'),
- * 'Model/Datasource' => array('/full/path/to/datasources/', '/next/full/path/to/datasources/'),
- * 'Model/Behavior' => array('/full/path/to/behaviors/', '/next/full/path/to/behaviors/'),
- * 'Controller/Component' => array('/full/path/to/components/', '/next/full/path/to/components/'),
- * 'View/Helper' => array('/full/path/to/helpers/', '/next/full/path/to/helpers/'),
- * 'Vendor' => array('/full/path/to/vendors/', '/next/full/path/to/vendors/'),
- * 'Console/Command' => array('/full/path/to/shells/', '/next/full/path/to/shells/'),
- * 'Locale' => array('/full/path/to/locale/', '/next/full/path/to/locale/')
- * ));
- *
- */
-
-/**
- * Custom Inflector rules, can be set to correctly pluralize or singularize table, model, controller names or whatever other
- * string is passed to the inflection functions
- *
- * Inflector::rules('singular', array('rules' => array(), 'irregular' => array(), 'uninflected' => array()));
- * Inflector::rules('plural', array('rules' => array(), 'irregular' => array(), 'uninflected' => array()));
- *
- */
-
-/**
- * Plugins need to be loaded manually, you can either load them one by one or all of them in a single call
- * Uncomment one of the lines below, as you need. make sure you read the documentation on CakePlugin to use more
- * advanced ways of loading plugins
- *
- * CakePlugin::loadAll(); // Loads all plugins at once
- * CakePlugin::load('DebugKit'); //Loads a single plugin named DebugKit
- *
- */
diff --git a/lib/Cake/Console/Templates/skel/Config/core.php b/lib/Cake/Console/Templates/skel/Config/core.php
deleted file mode 100644
index 20c354bc96b..00000000000
--- a/lib/Cake/Console/Templates/skel/Config/core.php
+++ /dev/null
@@ -1,336 +0,0 @@
- 0
- * and log errors with CakeLog when debug = 0.
- *
- * Options:
- *
- * - `handler` - callback - The callback to handle errors. You can set this to any callback type,
- * including anonymous functions.
- * - `level` - int - The level of errors you are interested in capturing.
- * - `trace` - boolean - Include stack traces for errors in log files.
- *
- * @see ErrorHandler for more information on error handling and configuration.
- */
- Configure::write('Error', array(
- 'handler' => 'ErrorHandler::handleError',
- 'level' => E_ALL & ~E_DEPRECATED,
- 'trace' => true
- ));
-
-/**
- * Configure the Exception handler used for uncaught exceptions. By default,
- * ErrorHandler::handleException() is used. It will display a HTML page for the exception, and
- * while debug > 0, framework errors like Missing Controller will be displayed. When debug = 0,
- * framework errors will be coerced into generic HTTP errors.
- *
- * Options:
- *
- * - `handler` - callback - The callback to handle exceptions. You can set this to any callback type,
- * including anonymous functions.
- * - `renderer` - string - The class responsible for rendering uncaught exceptions. If you choose a custom class you
- * should place the file for that class in app/Lib/Error. This class needs to implement a render method.
- * - `log` - boolean - Should Exceptions be logged?
- *
- * @see ErrorHandler for more information on exception handling and configuration.
- */
- Configure::write('Exception', array(
- 'handler' => 'ErrorHandler::handleException',
- 'renderer' => 'ExceptionRenderer',
- 'log' => true
- ));
-
-/**
- * Application wide charset encoding
- */
- Configure::write('App.encoding', 'UTF-8');
-
-/**
- * To configure CakePHP *not* to use mod_rewrite and to
- * use CakePHP pretty URLs, remove these .htaccess
- * files:
- *
- * /.htaccess
- * /app/.htaccess
- * /app/webroot/.htaccess
- *
- * And uncomment the App.baseUrl below:
- */
- //Configure::write('App.baseUrl', env('SCRIPT_NAME'));
-
-/**
- * Uncomment the define below to use CakePHP prefix routes.
- *
- * The value of the define determines the names of the routes
- * and their associated controller actions:
- *
- * Set to an array of prefixes you want to use in your application. Use for
- * admin or other prefixed routes.
- *
- * Routing.prefixes = array('admin', 'manager');
- *
- * Enables:
- * `admin_index()` and `/admin/controller/index`
- * `manager_index()` and `/manager/controller/index`
- *
- */
- //Configure::write('Routing.prefixes', array('admin'));
-
-/**
- * Turn off all caching application-wide.
- *
- */
- //Configure::write('Cache.disable', true);
-
-/**
- * Enable cache checking.
- *
- * If set to true, for view caching you must still use the controller
- * public $cacheAction inside your controllers to define caching settings.
- * You can either set it controller-wide by setting public $cacheAction = true,
- * or in each action using $this->cacheAction = true.
- *
- */
- //Configure::write('Cache.check', true);
-
-/**
- * Defines the default error type when using the log() function. Used for
- * differentiating error logging and debugging. Currently PHP supports LOG_DEBUG.
- */
- define('LOG_ERROR', 2);
-
-/**
- * Session configuration.
- *
- * Contains an array of settings to use for session configuration. The defaults key is
- * used to define a default preset to use for sessions, any settings declared here will override
- * the settings of the default config.
- *
- * ## Options
- *
- * - `Session.cookie` - The name of the cookie to use. Defaults to 'CAKEPHP'
- * - `Session.timeout` - The number of minutes you want sessions to live for. This timeout is handled by CakePHP
- * - `Session.cookieTimeout` - The number of minutes you want session cookies to live for.
- * - `Session.checkAgent` - Do you want the user agent to be checked when starting sessions? You might want to set the
- * value to false, when dealing with older versions of IE, Chrome Frame or certain web-browsing devices and AJAX
- * - `Session.defaults` - The default configuration set to use as a basis for your session.
- * There are four builtins: php, cake, cache, database.
- * - `Session.handler` - Can be used to enable a custom session handler. Expects an array of of callables,
- * that can be used with `session_save_handler`. Using this option will automatically add `session.save_handler`
- * to the ini array.
- * - `Session.autoRegenerate` - Enabling this setting, turns on automatic renewal of sessions, and
- * sessionids that change frequently. See CakeSession::$requestCountdown.
- * - `Session.ini` - An associative array of additional ini values to set.
- *
- * The built in defaults are:
- *
- * - 'php' - Uses settings defined in your php.ini.
- * - 'cake' - Saves session files in CakePHP's /tmp directory.
- * - 'database' - Uses CakePHP's database sessions.
- * - 'cache' - Use the Cache class to save sessions.
- *
- * To define a custom session handler, save it at /app/Model/Datasource/Session/.php.
- * Make sure the class implements `CakeSessionHandlerInterface` and set Session.handler to
- *
- * To use database sessions, run the app/Config/Schema/sessions.php schema using
- * the cake shell command: cake schema create Sessions
- *
- */
- Configure::write('Session', array(
- 'defaults' => 'php'
- ));
-
-/**
- * The level of CakePHP security.
- */
- Configure::write('Security.level', 'medium');
-
-/**
- * A random string used in security hashing methods.
- */
- Configure::write('Security.salt', 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi');
-
-/**
- * A random numeric string (digits only) used to encrypt/decrypt strings.
- */
- Configure::write('Security.cipherSeed', '76859309657453542496749683645');
-
-/**
- * Apply timestamps with the last modified time to static assets (js, css, images).
- * Will append a querystring parameter containing the time the file was modified. This is
- * useful for invalidating browser caches.
- *
- * Set to `true` to apply timestamps when debug > 0. Set to 'force' to always enable
- * timestamping regardless of debug value.
- */
- //Configure::write('Asset.timestamp', true);
-
-/**
- * Compress CSS output by removing comments, whitespace, repeating tags, etc.
- * This requires a/var/cache directory to be writable by the web server for caching.
- * and /vendors/csspp/csspp.php
- *
- * To use, prefix the CSS link URL with '/ccss/' instead of '/css/' or use HtmlHelper::css().
- */
- //Configure::write('Asset.filter.css', 'css.php');
-
-/**
- * Plug in your own custom JavaScript compressor by dropping a script in your webroot to handle the
- * output, and setting the config below to the name of the script.
- *
- * To use, prefix your JavaScript link URLs with '/cjs/' instead of '/js/' or use JavaScriptHelper::link().
- */
- //Configure::write('Asset.filter.js', 'custom_javascript_output_filter.php');
-
-/**
- * The classname and database used in CakePHP's
- * access control lists.
- */
- Configure::write('Acl.classname', 'DbAcl');
- Configure::write('Acl.database', 'default');
-
-/**
- * Uncomment this line and correct your server timezone to fix
- * any date & time related errors.
- */
- //date_default_timezone_set('UTC');
-
-/**
- *
- * Cache Engine Configuration
- * Default settings provided below
- *
- * File storage engine.
- *
- * Cache::config('default', array(
- * 'engine' => 'File', //[required]
- * 'duration' => 3600, //[optional]
- * 'probability' => 100, //[optional]
- * 'path' => CACHE, //[optional] use system tmp directory - remember to use absolute path
- * 'prefix' => 'cake_', //[optional] prefix every cache file with this string
- * 'lock' => false, //[optional] use file locking
- * 'serialize' => true, [optional]
- * ));
- *
- * APC (http://pecl.php.net/package/APC)
- *
- * Cache::config('default', array(
- * 'engine' => 'Apc', //[required]
- * 'duration' => 3600, //[optional]
- * 'probability' => 100, //[optional]
- * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
- * ));
- *
- * Xcache (http://xcache.lighttpd.net/)
- *
- * Cache::config('default', array(
- * 'engine' => 'Xcache', //[required]
- * 'duration' => 3600, //[optional]
- * 'probability' => 100, //[optional]
- * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
- * 'user' => 'user', //user from xcache.admin.user settings
- * 'password' => 'password', //plaintext password (xcache.admin.pass)
- * ));
- *
- * Memcache (http://www.danga.com/memcached/)
- *
- * Cache::config('default', array(
- * 'engine' => 'Memcache', //[required]
- * 'duration' => 3600, //[optional]
- * 'probability' => 100, //[optional]
- * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
- * 'servers' => array(
- * '127.0.0.1:11211' // localhost, default port 11211
- * ), //[optional]
- * 'persistent' => true, // [optional] set this to false for non-persistent connections
- * 'compress' => false, // [optional] compress data in Memcache (slower, but uses less memory)
- * ));
- *
- * Wincache (http://php.net/wincache)
- *
- * Cache::config('default', array(
- * 'engine' => 'Wincache', //[required]
- * 'duration' => 3600, //[optional]
- * 'probability' => 100, //[optional]
- * 'prefix' => Inflector::slug(APP_DIR) . '_', //[optional] prefix every cache file with this string
- * ));
- */
-
-/**
- * Pick the caching engine to use. If APC is enabled use it.
- * If running via cli - apc is disabled by default. ensure it's available and enabled in this case
- *
- */
-$engine = 'File';
-if (extension_loaded('apc') && function_exists('apc_dec') && (php_sapi_name() !== 'cli' || ini_get('apc.enable_cli'))) {
- $engine = 'Apc';
-}
-
-// In development mode, caches should expire quickly.
-$duration = '+999 days';
-if (Configure::read('debug') >= 1) {
- $duration = '+10 seconds';
-}
-
-// Prefix each application on the same server with a different string, to avoid Memcache and APC conflicts.
-$prefix = 'myapp_';
-
-/**
- * Configure the cache used for general framework caching. Path information,
- * object listings, and translation cache files are stored with this configuration.
- */
-Cache::config('_cake_core_', array(
- 'engine' => $engine,
- 'prefix' => $prefix . 'cake_core_',
- 'path' => CACHE . 'persistent' . DS,
- 'serialize' => ($engine === 'File'),
- 'duration' => $duration
-));
-
-/**
- * Configure the cache for model and datasource caches. This cache configuration
- * is used to store schema descriptions, and table listings in connections.
- */
-Cache::config('_cake_model_', array(
- 'engine' => $engine,
- 'prefix' => $prefix . 'cake_model_',
- 'path' => CACHE . 'models' . DS,
- 'serialize' => ($engine === 'File'),
- 'duration' => $duration
-));
diff --git a/lib/Cake/Console/Templates/skel/Config/database.php.default b/lib/Cake/Console/Templates/skel/Config/database.php.default
deleted file mode 100644
index 245c28222da..00000000000
--- a/lib/Cake/Console/Templates/skel/Config/database.php.default
+++ /dev/null
@@ -1,84 +0,0 @@
- The name of a supported datasource; valid options are as follows:
- * Database/Mysql - MySQL 4 & 5,
- * Database/Sqlite - SQLite (PHP5 only),
- * Database/Postgres - PostgreSQL 7 and higher,
- * Database/Sqlserver - Microsoft SQL Server 2005 and higher
- *
- * You can add custom database datasources (or override existing datasources) by adding the
- * appropriate file to app/Model/Datasource/Database. Datasources should be named 'MyDatasource.php',
- *
- *
- * persistent => true / false
- * Determines whether or not the database should use a persistent connection
- *
- * host =>
- * the host you connect to the database. To add a socket or port number, use 'port' => #
- *
- * prefix =>
- * Uses the given prefix for all the tables in this database. This setting can be overridden
- * on a per-table basis with the Model::$tablePrefix property.
- *
- * schema =>
- * For Postgres/Sqlserver specifies which schema you would like to use the tables in. Postgres defaults to 'public'. For Sqlserver, it defaults to empty and use
- * the connected user's default schema (typically 'dbo').
- *
- * encoding =>
- * For MySQL, Postgres specifies the character encoding to use when connecting to the
- * database. Uses database default not specified.
- *
- * unix_socket =>
- * For MySQL to connect via socket specify the `unix_socket` parameter instead of `host` and `port`
- */
-class DATABASE_CONFIG {
-
- public $default = array(
- 'datasource' => 'Database/Mysql',
- 'persistent' => false,
- 'host' => 'localhost',
- 'login' => 'user',
- 'password' => 'password',
- 'database' => 'database_name',
- 'prefix' => '',
- //'encoding' => 'utf8',
- );
-
- public $test = array(
- 'datasource' => 'Database/Mysql',
- 'persistent' => false,
- 'host' => 'localhost',
- 'login' => 'user',
- 'password' => 'password',
- 'database' => 'test_database_name',
- 'prefix' => '',
- //'encoding' => 'utf8',
- );
-}
diff --git a/lib/Cake/Console/Templates/skel/Config/email.php.default b/lib/Cake/Console/Templates/skel/Config/email.php.default
deleted file mode 100644
index c423f782f29..00000000000
--- a/lib/Cake/Console/Templates/skel/Config/email.php.default
+++ /dev/null
@@ -1,97 +0,0 @@
- The name of a supported transport; valid options are as follows:
- * Mail - Send using PHP mail function
- * Smtp - Send using SMTP
- * Debug - Do not send the email, just return the result
- *
- * You can add custom transports (or override existing transports) by adding the
- * appropriate file to app/Network/Email. Transports should be named 'YourTransport.php',
- * where 'Your' is the name of the transport.
- *
- * from =>
- * The origin email. See CakeEmail::from() about the valid values
- *
- */
-class EmailConfig {
-
- public $default = array(
- 'transport' => 'Mail',
- 'from' => 'you@localhost',
- //'charset' => 'utf-8',
- //'headerCharset' => 'utf-8',
- );
-
- public $smtp = array(
- 'transport' => 'Smtp',
- 'from' => array('site@localhost' => 'My Site'),
- 'host' => 'localhost',
- 'port' => 25,
- 'timeout' => 30,
- 'username' => 'user',
- 'password' => 'secret',
- 'client' => null,
- 'log' => false
- //'charset' => 'utf-8',
- //'headerCharset' => 'utf-8',
- );
-
- public $fast = array(
- 'from' => 'you@localhost',
- 'sender' => null,
- 'to' => null,
- 'cc' => null,
- 'bcc' => null,
- 'replyTo' => null,
- 'readReceipt' => null,
- 'returnPath' => null,
- 'messageId' => true,
- 'subject' => null,
- 'message' => null,
- 'headers' => null,
- 'viewRender' => null,
- 'template' => false,
- 'layout' => false,
- 'viewVars' => null,
- 'attachments' => null,
- 'emailFormat' => null,
- 'transport' => 'Smtp',
- 'host' => 'localhost',
- 'port' => 25,
- 'timeout' => 30,
- 'username' => 'user',
- 'password' => 'secret',
- 'client' => null,
- 'log' => true,
- //'charset' => 'utf-8',
- //'headerCharset' => 'utf-8',
- );
-
-}
diff --git a/lib/Cake/Console/Templates/skel/Config/routes.php b/lib/Cake/Console/Templates/skel/Config/routes.php
deleted file mode 100644
index 82cd2dbe9e4..00000000000
--- a/lib/Cake/Console/Templates/skel/Config/routes.php
+++ /dev/null
@@ -1,44 +0,0 @@
- 'pages', 'action' => 'display', 'home'));
-/**
- * ...and connect the rest of 'Pages' controller's urls.
- */
- Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
-
-/**
- * Load all plugin routes. See the CakePlugin documentation on
- * how to customize the loading of plugin routes.
- */
- CakePlugin::routes();
-
-/**
- * Load the CakePHP default routes. Remove this if you do not want to use
- * the built-in default routes.
- */
- require CAKE . 'Config' . DS . 'routes.php';
diff --git a/lib/Cake/Console/Templates/skel/Console/Command/AppShell.php b/lib/Cake/Console/Templates/skel/Console/Command/AppShell.php
deleted file mode 100644
index 5cc915f6bfe..00000000000
--- a/lib/Cake/Console/Templates/skel/Console/Command/AppShell.php
+++ /dev/null
@@ -1,31 +0,0 @@
-redirect('/');
- }
- $page = $subpage = $title = null;
-
- if (!empty($path[0])) {
- $page = $path[0];
- }
- if (!empty($path[1])) {
- $subpage = $path[1];
- }
- if (!empty($path[$count - 1])) {
- $title = Inflector::humanize($path[$count - 1]);
- }
- $this->set(compact('page', 'subpage'));
- $this->set('title_for_layout', $title);
- $this->render(implode('/', $path));
- }
-
-}
diff --git a/lib/Cake/Console/Templates/skel/Lib/empty b/lib/Cake/Console/Templates/skel/Lib/empty
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/lib/Cake/Console/Templates/skel/Locale/eng/LC_MESSAGES/empty b/lib/Cake/Console/Templates/skel/Locale/eng/LC_MESSAGES/empty
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/lib/Cake/Console/Templates/skel/Model/AppModel.php b/lib/Cake/Console/Templates/skel/Model/AppModel.php
deleted file mode 100644
index 94e5e5f39d1..00000000000
--- a/lib/Cake/Console/Templates/skel/Model/AppModel.php
+++ /dev/null
@@ -1,34 +0,0 @@
-
- ' . $line . '';
-endforeach;
-?>
\ No newline at end of file
diff --git a/lib/Cake/Console/Templates/skel/View/Emails/text/default.ctp b/lib/Cake/Console/Templates/skel/View/Emails/text/default.ctp
deleted file mode 100644
index 8b5e8c8da8c..00000000000
--- a/lib/Cake/Console/Templates/skel/View/Emails/text/default.ctp
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
\ No newline at end of file
diff --git a/lib/Cake/Console/Templates/skel/View/Errors/error400.ctp b/lib/Cake/Console/Templates/skel/View/Errors/error400.ctp
deleted file mode 100644
index 6d508604c7c..00000000000
--- a/lib/Cake/Console/Templates/skel/View/Errors/error400.ctp
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
- :
- '{$url}'"
- ); ?>
-
- 0 ):
- echo $this->element('exception_stack_trace');
-endif;
-?>
diff --git a/lib/Cake/Console/Templates/skel/View/Errors/error500.ctp b/lib/Cake/Console/Templates/skel/View/Errors/error500.ctp
deleted file mode 100644
index 4e1f36ece56..00000000000
--- a/lib/Cake/Console/Templates/skel/View/Errors/error500.ctp
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
- :
-
-
- 0 ):
- echo $this->element('exception_stack_trace');
-endif;
-?>
diff --git a/lib/Cake/Console/Templates/skel/View/Helper/AppHelper.php b/lib/Cake/Console/Templates/skel/View/Helper/AppHelper.php
deleted file mode 100644
index caceda86062..00000000000
--- a/lib/Cake/Console/Templates/skel/View/Helper/AppHelper.php
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
- This email was sent using the CakePHP Framework
-
-
\ No newline at end of file
diff --git a/lib/Cake/Console/Templates/skel/View/Layouts/Emails/text/default.ctp b/lib/Cake/Console/Templates/skel/View/Layouts/Emails/text/default.ctp
deleted file mode 100644
index ba3086ad930..00000000000
--- a/lib/Cake/Console/Templates/skel/View/Layouts/Emails/text/default.ctp
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-This email was sent using the CakePHP Framework, http://cakephp.org.
diff --git a/lib/Cake/Console/Templates/skel/View/Layouts/ajax.ctp b/lib/Cake/Console/Templates/skel/View/Layouts/ajax.ctp
deleted file mode 100644
index 9475d5f7d62..00000000000
--- a/lib/Cake/Console/Templates/skel/View/Layouts/ajax.ctp
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
\ No newline at end of file
diff --git a/lib/Cake/Console/Templates/skel/View/Layouts/default.ctp b/lib/Cake/Console/Templates/skel/View/Layouts/default.ctp
deleted file mode 100644
index 4aab010a999..00000000000
--- a/lib/Cake/Console/Templates/skel/View/Layouts/default.ctp
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
- Html->charset(); ?>
-
-
-
-
- Html->meta('icon');
-
- echo $this->Html->css('cake.generic');
-
- echo $this->fetch('meta');
- echo $this->fetch('css');
- echo $this->fetch('script');
- ?>
-
-
-
-
-
-
- Session->flash(); ?>
-
- fetch('content'); ?>
-
-
-
- element('sql_dump'); ?>
-
-
diff --git a/lib/Cake/Console/Templates/skel/View/Layouts/flash.ctp b/lib/Cake/Console/Templates/skel/View/Layouts/flash.ctp
deleted file mode 100644
index 35f5a942ff8..00000000000
--- a/lib/Cake/Console/Templates/skel/View/Layouts/flash.ctp
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-Html->charset(); ?>
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/lib/Cake/Console/Templates/skel/View/Layouts/js/default.ctp b/lib/Cake/Console/Templates/skel/View/Layouts/js/default.ctp
deleted file mode 100644
index d94dc903a57..00000000000
--- a/lib/Cake/Console/Templates/skel/View/Layouts/js/default.ctp
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/lib/Cake/Console/Templates/skel/View/Layouts/rss/default.ctp b/lib/Cake/Console/Templates/skel/View/Layouts/rss/default.ctp
deleted file mode 100644
index 94067f2bfbc..00000000000
--- a/lib/Cake/Console/Templates/skel/View/Layouts/rss/default.ctp
+++ /dev/null
@@ -1,17 +0,0 @@
-header();
-
-if (!isset($channel)) {
- $channel = array();
-}
-if (!isset($channel['title'])) {
- $channel['title'] = $title_for_layout;
-}
-
-echo $rss->document(
- $rss->channel(
- array(), $channel, $content_for_layout
- )
-);
-
-?>
\ No newline at end of file
diff --git a/lib/Cake/Console/Templates/skel/View/Layouts/xml/default.ctp b/lib/Cake/Console/Templates/skel/View/Layouts/xml/default.ctp
deleted file mode 100644
index 27f20316b37..00000000000
--- a/lib/Cake/Console/Templates/skel/View/Layouts/xml/default.ctp
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/lib/Cake/Console/Templates/skel/View/Pages/home.ctp b/lib/Cake/Console/Templates/skel/View/Pages/home.ctp
deleted file mode 100644
index 6661e9a6240..00000000000
--- a/lib/Cake/Console/Templates/skel/View/Pages/home.ctp
+++ /dev/null
@@ -1,188 +0,0 @@
-
-
-
-
- 0):
- Debugger::checkSecurityKeys();
-endif;
-?>
-
-
- 1) Help me configure it
- 2) I don't / can't use URL rewriting
-
-
-=')):
- echo '';
- echo __d('cake_dev', 'Your version of PHP is 5.2.8 or higher.');
- echo ' ';
- else:
- echo '';
- echo __d('cake_dev', 'Your version of PHP is too low. You need PHP 5.2.8 or higher to use CakePHP.');
- echo ' ';
- endif;
-?>
-
-
- ';
- echo __d('cake_dev', 'Your tmp directory is writable.');
- echo '';
- else:
- echo '';
- echo __d('cake_dev', 'Your tmp directory is NOT writable.');
- echo ' ';
- endif;
- ?>
-
-
- ';
- echo __d('cake_dev', 'The %s is being used for core caching. To change the config edit APP/Config/core.php ', ''. $settings['engine'] . 'Engine ');
- echo '';
- else:
- echo '';
- echo __d('cake_dev', 'Your cache is NOT working. Please check the settings in APP/Config/core.php');
- echo ' ';
- endif;
- ?>
-
-
- ';
- echo __d('cake_dev', 'Your database configuration file is present.');
- $filePresent = true;
- echo '';
- else:
- echo '';
- echo __d('cake_dev', 'Your database configuration file is NOT present.');
- echo ' ';
- echo __d('cake_dev', 'Rename APP/Config/database.php.default to APP/Config/database.php');
- echo ' ';
- endif;
- ?>
-
-
-
- isConnected()):
- echo '';
- echo __d('cake_dev', 'Cake is able to connect to the database.');
- echo ' ';
- else:
- echo '';
- echo __d('cake_dev', 'Cake is NOT able to connect to the database.');
- echo ' ';
- echo $connectionError->getMessage();
- echo ' ';
- endif;
- ?>
-
-
-';
- echo __d('cake_dev', 'PCRE has not been compiled with Unicode support.');
- echo ' ';
- echo __d('cake_dev', 'Recompile PCRE with Unicode support by adding --enable-unicode-properties when configuring');
- echo ' ';
- }
-?>
-
-
-
-To change its layout, create: APP/View/Layouts/default.ctp.
-You can also add some CSS styles for your pages at: APP/webroot/css.');
-?>
-
-
-
-
- Html->link(
- sprintf('%s %s', __d('cake_dev', 'New'), __d('cake_dev', 'CakePHP 2.0 Docs')),
- 'http://book.cakephp.org/2.0/en/',
- array('target' => '_blank', 'escape' => false)
- );
- ?>
-
-
- Html->link(
- __d('cake_dev', 'The 15 min Blog Tutorial'),
- 'http://book.cakephp.org/2.0/en/tutorials-and-examples/blog/blog.html',
- array('target' => '_blank', 'escape' => false)
- );
- ?>
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/Cake/Console/Templates/skel/View/Scaffolds/empty b/lib/Cake/Console/Templates/skel/View/Scaffolds/empty
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/lib/Cake/Console/Templates/skel/index.php b/lib/Cake/Console/Templates/skel/index.php
deleted file mode 100644
index 29f2c572852..00000000000
--- a/lib/Cake/Console/Templates/skel/index.php
+++ /dev/null
@@ -1,17 +0,0 @@
-
- RewriteEngine On
- RewriteCond %{REQUEST_FILENAME} !-d
- RewriteCond %{REQUEST_FILENAME} !-f
- RewriteRule ^(.*)$ index.php [QSA,L]
-
diff --git a/lib/Cake/Console/Templates/skel/webroot/css/cake.generic.css b/lib/Cake/Console/Templates/skel/webroot/css/cake.generic.css
deleted file mode 100644
index 2244ad2f868..00000000000
--- a/lib/Cake/Console/Templates/skel/webroot/css/cake.generic.css
+++ /dev/null
@@ -1,739 +0,0 @@
-@charset "utf-8";
-/**
- *
- * Generic CSS for CakePHP
- *
- * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://cakephp.org CakePHP(tm) Project
- * @package app.webroot.css
- * @since CakePHP(tm)
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-* {
- margin:0;
- padding:0;
-}
-
-/** General Style Info **/
-body {
- background: #003d4c;
- color: #fff;
- font-family:'lucida grande',verdana,helvetica,arial,sans-serif;
- font-size:90%;
- margin: 0;
-}
-a {
- color: #003d4c;
- text-decoration: underline;
- font-weight: bold;
-}
-a:hover {
- color: #367889;
- text-decoration:none;
-}
-a img {
- border:none;
-}
-h1, h2, h3, h4 {
- font-weight: normal;
- margin-bottom:0.5em;
-}
-h1 {
- background:#fff;
- color: #003d4c;
- font-size: 100%;
-}
-h2 {
- background:#fff;
- color: #e32;
- font-family:'Gill Sans','lucida grande', helvetica, arial, sans-serif;
- font-size: 190%;
-}
-h3 {
- color: #2c6877;
- font-family:'Gill Sans','lucida grande', helvetica, arial, sans-serif;
- font-size: 165%;
-}
-h4 {
- color: #993;
- font-weight: normal;
-}
-ul, li {
- margin: 0 12px;
-}
-p {
- margin: 0 0 1em 0;
-}
-
-/** Layout **/
-#container {
- text-align: left;
-}
-
-#header{
- padding: 10px 20px;
-}
-#header h1 {
- line-height:20px;
- background: #003d4c url('../img/cake.icon.png') no-repeat left;
- color: #fff;
- padding: 0px 30px;
-}
-#header h1 a {
- color: #fff;
- background: #003d4c;
- font-weight: normal;
- text-decoration: none;
-}
-#header h1 a:hover {
- color: #fff;
- background: #003d4c;
- text-decoration: underline;
-}
-#content{
- background: #fff;
- clear: both;
- color: #333;
- padding: 10px 20px 40px 20px;
- overflow: auto;
-}
-#footer {
- clear: both;
- padding: 6px 10px;
- text-align: right;
-}
-
-/** containers **/
-div.form,
-div.index,
-div.view {
- float:right;
- width:76%;
- border-left:1px solid #666;
- padding:10px 2%;
-}
-div.actions {
- float:left;
- width:16%;
- padding:10px 1.5%;
-}
-div.actions h3 {
- padding-top:0;
- color:#777;
-}
-
-
-/** Tables **/
-table {
- border-right:0;
- clear: both;
- color: #333;
- margin-bottom: 10px;
- width: 100%;
-}
-th {
- border:0;
- border-bottom:2px solid #555;
- text-align: left;
- padding:4px;
-}
-th a {
- display: block;
- padding: 2px 4px;
- text-decoration: none;
-}
-th a.asc:after {
- content: ' ⇣';
-}
-th a.desc:after {
- content: ' ⇡';
-}
-table tr td {
- padding: 6px;
- text-align: left;
- vertical-align: top;
- border-bottom:1px solid #ddd;
-}
-table tr:nth-child(even) {
- background: #f9f9f9;
-}
-td.actions {
- text-align: center;
- white-space: nowrap;
-}
-table td.actions a {
- margin: 0px 6px;
- padding:2px 5px;
-}
-
-/* SQL log */
-.cake-sql-log {
- background: #fff;
-}
-.cake-sql-log td {
- padding: 4px 8px;
- text-align: left;
- font-family: Monaco, Consolas, "Courier New", monospaced;
-}
-.cake-sql-log caption {
- color:#fff;
-}
-
-/** Paging **/
-.paging {
- background:#fff;
- color: #ccc;
- margin-top: 1em;
- clear:both;
-}
-.paging .current,
-.paging .disabled,
-.paging a {
- text-decoration: none;
- padding: 5px 8px;
- display: inline-block
-}
-.paging > span {
- display: inline-block;
- border: 1px solid #ccc;
- border-left: 0;
-}
-.paging > span:hover {
- background: #efefef;
-}
-.paging .prev {
- border-left: 1px solid #ccc;
- -moz-border-radius: 4px 0 0 4px;
- -webkit-border-radius: 4px 0 0 4px;
- border-radius: 4px 0 0 4px;
-}
-.paging .next {
- -moz-border-radius: 0 4px 4px 0;
- -webkit-border-radius: 0 4px 4px 0;
- border-radius: 0 4px 4px 0;
-}
-.paging .disabled {
- color: #ddd;
-}
-.paging .disabled:hover {
- background: transparent;
-}
-.paging .current {
- background: #efefef;
- color: #c73e14;
-}
-
-/** Scaffold View **/
-dl {
- line-height: 2em;
- margin: 0em 0em;
- width: 60%;
-}
-dl dd:nth-child(4n+2),
-dl dt:nth-child(4n+1) {
- background: #f4f4f4;
-}
-
-dt {
- font-weight: bold;
- padding-left: 4px;
- vertical-align: top;
- width: 10em;
-}
-dd {
- margin-left: 10em;
- margin-top: -2em;
- vertical-align: top;
-}
-
-/** Forms **/
-form {
- clear: both;
- margin-right: 20px;
- padding: 0;
- width: 95%;
-}
-fieldset {
- border: none;
- margin-bottom: 1em;
- padding: 16px 10px;
-}
-fieldset legend {
- color: #e32;
- font-size: 160%;
- font-weight: bold;
-}
-fieldset fieldset {
- margin-top: 0;
- padding: 10px 0 0;
-}
-fieldset fieldset legend {
- font-size: 120%;
- font-weight: normal;
-}
-fieldset fieldset div {
- clear: left;
- margin: 0 20px;
-}
-form div {
- clear: both;
- margin-bottom: 1em;
- padding: .5em;
- vertical-align: text-top;
-}
-form .input {
- color: #444;
-}
-form .required {
- font-weight: bold;
-}
-form .required label:after {
- color: #e32;
- content: '*';
- display:inline;
-}
-form div.submit {
- border: 0;
- clear: both;
- margin-top: 10px;
-}
-label {
- display: block;
- font-size: 110%;
- margin-bottom:3px;
-}
-input, textarea {
- clear: both;
- font-size: 140%;
- font-family: "frutiger linotype", "lucida grande", "verdana", sans-serif;
- padding: 1%;
- width:98%;
-}
-select {
- clear: both;
- font-size: 120%;
- vertical-align: text-bottom;
-}
-select[multiple=multiple] {
- width: 100%;
-}
-option {
- font-size: 120%;
- padding: 0 3px;
-}
-input[type=checkbox] {
- clear: left;
- float: left;
- margin: 0px 6px 7px 2px;
- width: auto;
-}
-div.checkbox label {
- display: inline;
-}
-input[type=radio] {
- float:left;
- width:auto;
- margin: 6px 0;
- padding: 0;
- line-height: 26px;
-}
-.radio label {
- margin: 0 0 6px 20px;
- line-height: 26px;
-}
-input[type=submit] {
- display: inline;
- font-size: 110%;
- width: auto;
-}
-form .submit input[type=submit] {
- background:#62af56;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#76BF6B), to(#3B8230));
- background-image: -webkit-linear-gradient(top, #76BF6B, #3B8230);
- background-image: -moz-linear-gradient(top, #76BF6B, #3B8230);
- border-color: #2d6324;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px;
- padding: 8px 10px;
-}
-form .submit input[type=submit]:hover {
- background: #5BA150;
-}
-/* Form errors */
-form .error {
- background: #FFDACC;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- border-radius: 4px;
- font-weight: normal;
-}
-form .error-message {
- -moz-border-radius: none;
- -webkit-border-radius: none;
- border-radius: none;
- border: none;
- background: none;
- margin: 0;
- padding-left: 4px;
- padding-right: 0;
-}
-form .error,
-form .error-message {
- color: #9E2424;
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- -ms-box-shadow: none;
- -o-box-shadow: none;
- box-shadow: none;
- text-shadow: none;
-}
-
-/** Notices and Errors **/
-.message {
- clear: both;
- color: #fff;
- font-size: 140%;
- font-weight: bold;
- margin: 0 0 1em 0;
- padding: 5px;
-}
-
-.success,
-.message,
-.cake-error,
-.cake-debug,
-.notice,
-p.error,
-.error-message {
- background: #ffcc00;
- background-repeat: repeat-x;
- background-image: -moz-linear-gradient(top, #ffcc00, #E6B800);
- background-image: -ms-linear-gradient(top, #ffcc00, #E6B800);
- background-image: -webkit-gradient(linear, left top, left bottom, from(#ffcc00), to(#E6B800));
- background-image: -webkit-linear-gradient(top, #ffcc00, #E6B800);
- background-image: -o-linear-gradient(top, #ffcc00, #E6B800);
- background-image: linear-gradient(top, #ffcc00, #E6B800);
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
- border: 1px solid rgba(0, 0, 0, 0.2);
- margin-bottom: 18px;
- padding: 7px 14px;
- color: #404040;
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
-}
-.success,
-.message,
-.cake-error,
-p.error,
-.error-message {
- clear: both;
- color: #fff;
- background: #c43c35;
- border: 1px solid rgba(0, 0, 0, 0.5);
- background-repeat: repeat-x;
- background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
- background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
- background-image: -webkit-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));
- background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
- background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
- background-image: linear-gradient(top, #ee5f5b, #c43c35);
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
-}
-.success {
- clear: both;
- color: #fff;
- border: 1px solid rgba(0, 0, 0, 0.5);
- background: #3B8230;
- background-repeat: repeat-x;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#76BF6B), to(#3B8230));
- background-image: -webkit-linear-gradient(top, #76BF6B, #3B8230);
- background-image: -moz-linear-gradient(top, #76BF6B, #3B8230);
- background-image: -ms-linear-gradient(top, #76BF6B, #3B8230);
- background-image: -o-linear-gradient(top, #76BF6B, #3B8230);
- background-image: linear-gradient(top, #76BF6B, #3B8230);
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
-}
-p.error {
- font-family: Monaco, Consolas, Courier, monospace;
- font-size: 120%;
- padding: 0.8em;
- margin: 1em 0;
-}
-p.error em {
- font-weight: normal;
- line-height: 140%;
-}
-.notice {
- color: #000;
- display: block;
- font-size: 120%;
- padding: 0.8em;
- margin: 1em 0;
-}
-.success {
- color: #fff;
-}
-
-/** Actions **/
-.actions ul {
- margin: 0;
- padding: 0;
-}
-.actions li {
- margin:0 0 0.5em 0;
- list-style-type: none;
- white-space: nowrap;
- padding: 0;
-}
-.actions ul li a {
- font-weight: normal;
- display: block;
- clear: both;
-}
-
-/* Buttons and button links */
-input[type=submit],
-.actions ul li a,
-.actions a {
- font-weight:normal;
- padding: 4px 8px;
- background: #dcdcdc;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#fefefe), to(#dcdcdc));
- background-image: -webkit-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: -moz-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: -ms-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: -o-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: linear-gradient(top, #fefefe, #dcdcdc);
- color:#333;
- border:1px solid #bbb;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- text-decoration: none;
- text-shadow: #fff 0px 1px 0px;
- min-width: 0;
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0px 1px 1px rgba(0, 0, 0, 0.2);
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0px 1px 1px rgba(0, 0, 0, 0.2);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0px 1px 1px rgba(0, 0, 0, 0.2);
- -webkit-user-select: none;
- user-select: none;
-}
-.actions ul li a:hover,
-.actions a:hover {
- background: #ededed;
- border-color: #acacac;
- text-decoration: none;
-}
-input[type=submit]:active,
-.actions ul li a:active,
-.actions a:active {
- background: #eee;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#dfdfdf), to(#eee));
- background-image: -webkit-linear-gradient(top, #dfdfdf, #eee);
- background-image: -moz-linear-gradient(top, #dfdfdf, #eee);
- background-image: -ms-linear-gradient(top, #dfdfdf, #eee);
- background-image: -o-linear-gradient(top, #dfdfdf, #eee);
- background-image: linear-gradient(top, #dfdfdf, #eee);
- text-shadow: #eee 0px 1px 0px;
- -moz-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3);
- -webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3);
- box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3);
- border-color: #aaa;
- text-decoration: none;
-}
-
-/** Related **/
-.related {
- clear: both;
- display: block;
-}
-
-/** Debugging **/
-pre {
- color: #000;
- background: #f0f0f0;
- padding: 15px;
- -moz-box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
- -webkit-box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
- box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
-}
-.cake-debug-output {
- padding: 0;
- position: relative;
-}
-.cake-debug-output > span {
- position: absolute;
- top: 5px;
- right: 5px;
- background: rgba(255, 255, 255, 0.3);
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- border-radius: 4px;
- padding: 5px 6px;
- color: #000;
- display: block;
- float: left;
- -moz-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.25), 0 1px 0 rgba(255, 255, 255, 0.5);
- -webkit-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.25), 0 1px 0 rgba(255, 255, 255, 0.5);
- box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.25), 0 1px 0 rgba(255, 255, 255, 0.5);
- text-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
-}
-.cake-debug,
-.cake-error {
- font-size: 16px;
- line-height: 20px;
- clear: both;
-}
-.cake-error > a {
- text-shadow: none;
-}
-.cake-error {
- white-space: normal;
-}
-.cake-stack-trace {
- background: rgba(255, 255, 255, 0.7);
- color: #333;
- margin: 10px 0 5px 0;
- padding: 10px 10px 0 10px;
- font-size: 120%;
- line-height: 140%;
- overflow: auto;
- position: relative;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- border-radius: 4px;
-}
-.cake-stack-trace a {
- text-shadow: none;
- background: rgba(255, 255, 255, 0.7);
- padding: 5px;
- -moz-border-radius: 10px;
- -webkit-border-radius: 10px;
- border-radius: 10px;
- margin: 0px 4px 10px 2px;
- font-family: sans-serif;
- font-size: 14px;
- line-height: 14px;
- display: inline-block;
- text-decoration: none;
- -moz-box-shadow: inset 0px 1px 0 rgba(0, 0, 0, 0.3);
- -webkit-box-shadow: inset 0px 1px 0 rgba(0, 0, 0, 0.3);
- box-shadow: inset 0px 1px 0 rgba(0, 0, 0, 0.3);
-}
-.cake-code-dump pre {
- position: relative;
- overflow: auto;
-}
-.cake-context {
- margin-bottom: 10px;
-}
-.cake-stack-trace pre {
- color: #000;
- background-color: #F0F0F0;
- margin: 0px 0 10px 0;
- padding: 1em;
- overflow: auto;
- text-shadow: none;
-}
-.cake-stack-trace li {
- padding: 10px 5px 0px;
- margin: 0 0 4px 0;
- font-family: monospace;
- border: 1px solid #bbb;
- -moz-border-radius: 4px;
- -wekbkit-border-radius: 4px;
- border-radius: 4px;
- background: #dcdcdc;
- background-image: -webkit-gradient(linear, left top, left bottom, from(#fefefe), to(#dcdcdc));
- background-image: -webkit-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: -moz-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: -ms-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: -o-linear-gradient(top, #fefefe, #dcdcdc);
- background-image: linear-gradient(top, #fefefe, #dcdcdc);
-}
-/* excerpt */
-.cake-code-dump pre,
-.cake-code-dump pre code {
- clear: both;
- font-size: 12px;
- line-height: 15px;
- margin: 4px 2px;
- padding: 4px;
- overflow: auto;
-}
-.cake-code-dump .code-highlight {
- display: block;
- background-color: rgba(255, 255, 0, 0.5);
-}
-.code-coverage-results div.code-line {
- padding-left:5px;
- display:block;
- margin-left:10px;
-}
-.code-coverage-results div.uncovered span.content {
- background:#ecc;
-}
-.code-coverage-results div.covered span.content {
- background:#cec;
-}
-.code-coverage-results div.ignored span.content {
- color:#aaa;
-}
-.code-coverage-results span.line-num {
- color:#666;
- display:block;
- float:left;
- width:20px;
- text-align:right;
- margin-right:5px;
-}
-.code-coverage-results span.line-num strong {
- color:#666;
-}
-.code-coverage-results div.start {
- border:1px solid #aaa;
- border-width:1px 1px 0px 1px;
- margin-top:30px;
- padding-top:5px;
-}
-.code-coverage-results div.end {
- border:1px solid #aaa;
- border-width:0px 1px 1px 1px;
- margin-bottom:30px;
- padding-bottom:5px;
-}
-.code-coverage-results div.realstart {
- margin-top:0px;
-}
-.code-coverage-results p.note {
- color:#bbb;
- padding:5px;
- margin:5px 0 10px;
- font-size:10px;
-}
-.code-coverage-results span.result-bad {
- color: #a00;
-}
-.code-coverage-results span.result-ok {
- color: #fa0;
-}
-.code-coverage-results span.result-good {
- color: #0a0;
-}
-
-/** Elements **/
-#url-rewriting-warning {
- display:none;
-}
diff --git a/lib/Cake/Console/Templates/skel/webroot/favicon.ico b/lib/Cake/Console/Templates/skel/webroot/favicon.ico
deleted file mode 100644
index b36e81f2f35..00000000000
Binary files a/lib/Cake/Console/Templates/skel/webroot/favicon.ico and /dev/null differ
diff --git a/lib/Cake/Console/Templates/skel/webroot/files/empty b/lib/Cake/Console/Templates/skel/webroot/files/empty
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/lib/Cake/Console/Templates/skel/webroot/img/cake.icon.png b/lib/Cake/Console/Templates/skel/webroot/img/cake.icon.png
deleted file mode 100644
index 394fa42d513..00000000000
Binary files a/lib/Cake/Console/Templates/skel/webroot/img/cake.icon.png and /dev/null differ
diff --git a/lib/Cake/Console/Templates/skel/webroot/img/test-error-icon.png b/lib/Cake/Console/Templates/skel/webroot/img/test-error-icon.png
deleted file mode 100644
index 07bb1241143..00000000000
Binary files a/lib/Cake/Console/Templates/skel/webroot/img/test-error-icon.png and /dev/null differ
diff --git a/lib/Cake/Console/Templates/skel/webroot/img/test-fail-icon.png b/lib/Cake/Console/Templates/skel/webroot/img/test-fail-icon.png
deleted file mode 100644
index f9d2f147ec4..00000000000
Binary files a/lib/Cake/Console/Templates/skel/webroot/img/test-fail-icon.png and /dev/null differ
diff --git a/lib/Cake/Console/Templates/skel/webroot/img/test-pass-icon.png b/lib/Cake/Console/Templates/skel/webroot/img/test-pass-icon.png
deleted file mode 100644
index 99c5eb05ad2..00000000000
Binary files a/lib/Cake/Console/Templates/skel/webroot/img/test-pass-icon.png and /dev/null differ
diff --git a/lib/Cake/Console/Templates/skel/webroot/img/test-skip-icon.png b/lib/Cake/Console/Templates/skel/webroot/img/test-skip-icon.png
deleted file mode 100644
index 749771c9895..00000000000
Binary files a/lib/Cake/Console/Templates/skel/webroot/img/test-skip-icon.png and /dev/null differ
diff --git a/lib/Cake/Console/Templates/skel/webroot/index.php b/lib/Cake/Console/Templates/skel/webroot/index.php
deleted file mode 100644
index 17b461c0c1b..00000000000
--- a/lib/Cake/Console/Templates/skel/webroot/index.php
+++ /dev/null
@@ -1,101 +0,0 @@
-dispatch(
- new CakeRequest(),
- new CakeResponse(array('charset' => Configure::read('App.encoding')))
-);
diff --git a/lib/Cake/Console/Templates/skel/webroot/js/empty b/lib/Cake/Console/Templates/skel/webroot/js/empty
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/lib/Cake/Console/Templates/skel/webroot/test.php b/lib/Cake/Console/Templates/skel/webroot/test.php
deleted file mode 100644
index c287579435f..00000000000
--- a/lib/Cake/Console/Templates/skel/webroot/test.php
+++ /dev/null
@@ -1,94 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing
- * @package app.webroot
- * @since CakePHP(tm) v 1.2.0.4433
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-set_time_limit(0);
-ini_set('display_errors', 1);
-/**
- * Use the DS to separate the directories in other defines
- */
-if (!defined('DS')) {
- define('DS', DIRECTORY_SEPARATOR);
-}
-
-/**
- * These defines should only be edited if you have cake installed in
- * a directory layout other than the way it is distributed.
- * When using custom settings be sure to use the DS and do not add a trailing DS.
- */
-
-/**
- * The full path to the directory which holds "app", WITHOUT a trailing DS.
- *
- */
-if (!defined('ROOT')) {
- define('ROOT', dirname(dirname(dirname(__FILE__))));
-}
-
-/**
- * The actual directory name for the "app".
- *
- */
-if (!defined('APP_DIR')) {
- define('APP_DIR', basename(dirname(dirname(__FILE__))));
-}
-
-/**
- * The absolute path to the "Cake" directory, WITHOUT a trailing DS.
- *
- * For ease of development CakePHP uses PHP's include_path. If you
- * need to cannot modify your include_path, you can set this path.
- *
- * Leaving this constant undefined will result in it being defined in Cake/bootstrap.php
- */
-//define('CAKE_CORE_INCLUDE_PATH', __CAKE_PATH__);
-
-/**
- * Editing below this line should not be necessary.
- * Change at your own risk.
- *
- */
-if (!defined('WEBROOT_DIR')) {
- define('WEBROOT_DIR', basename(dirname(__FILE__)));
-}
-if (!defined('WWW_ROOT')) {
- define('WWW_ROOT', dirname(__FILE__) . DS);
-}
-
-if (!defined('CAKE_CORE_INCLUDE_PATH')) {
- if (function_exists('ini_set')) {
- ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path'));
- }
- if (!include 'Cake' . DS . 'bootstrap.php') {
- $failed = true;
- }
-} else {
- if (!include CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'bootstrap.php') {
- $failed = true;
- }
-}
-if (!empty($failed)) {
- trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR);
-}
-
-if (Configure::read('debug') < 1) {
- die(__d('cake_dev', 'Debug setting does not allow access to this url.'));
-}
-
-require_once CAKE . 'TestSuite' . DS . 'CakeTestSuiteDispatcher.php';
-
-CakeTestSuiteDispatcher::run();
diff --git a/lib/Cake/Console/cake b/lib/Cake/Console/cake
deleted file mode 100755
index 42486696692..00000000000
--- a/lib/Cake/Console/cake
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env bash
-################################################################################
-#
-# Bake is a shell script for running CakePHP bake script
-# PHP 5
-#
-# CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
-# Copyright 2005-2012, Cake Software Foundation, Inc.
-#
-# Licensed under The MIT License
-# Redistributions of files must retain the above copyright notice.
-#
-# @copyright Copyright 2005-2012, Cake Software Foundation, Inc.
-# @link http://cakephp.org CakePHP(tm) Project
-# @package cake.console
-# @since CakePHP(tm) v 1.2.0.5012
-# @license MIT License (http://www.opensource.org/licenses/mit-license.php)
-#
-################################################################################
-LIB=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && LIB=$LIB/$(basename -- "$0")
-
-while [ -h "$LIB" ]; do
- DIR=$(dirname -- "$LIB")
- SYM=$(readlink "$LIB")
- LIB=$(cd "$DIR" && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
-done
-
-LIB=$(dirname -- "$LIB")/
-APP=`pwd`
-
-exec php -q "$LIB"cake.php -working "$APP" "$@"
-
-exit;
diff --git a/lib/Cake/Console/cake.bat b/lib/Cake/Console/cake.bat
deleted file mode 100644
index 4444f385df3..00000000000
--- a/lib/Cake/Console/cake.bat
+++ /dev/null
@@ -1,32 +0,0 @@
-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-::
-:: Bake is a shell script for running CakePHP bake script
-:: PHP 5
-::
-:: CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
-:: Copyright 2005-2012, Cake Software Foundation, Inc.
-::
-:: Licensed under The MIT License
-:: Redistributions of files must retain the above copyright notice.
-::
-:: @copyright Copyright 2005-2012, Cake Software Foundation, Inc.
-:: @link http://cakephp.org CakePHP(tm) Project
-:: @package cake.console
-:: @since CakePHP(tm) v 1.2.0.5012
-:: @license MIT License (http://www.opensource.org/licenses/mit-license.php)
-::
-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-
-:: In order for this script to work as intended, the cake\console\ folder must be in your PATH
-
-@echo.
-@echo off
-
-SET app=%0
-SET lib=%~dp0
-
-php -q "%lib%cake.php" -working "%CD% " %*
-
-echo.
-
-exit /B %ERRORLEVEL%
diff --git a/lib/Cake/Console/cake.php b/lib/Cake/Console/cake.php
deleted file mode 100644
index bae9cf3325f..00000000000
--- a/lib/Cake/Console/cake.php
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/php -q
-components[] = 'RequestHandler';
- }
- $this->constructClasses();
- $this->Components->trigger('initialize', array(&$this));
-
- $this->_set(array('cacheAction' => false, 'viewPath' => 'Errors'));
- if (isset($this->RequestHandler)) {
- $this->RequestHandler->startup($this);
- }
- }
-
-/**
- * Escapes the viewVars.
- *
- * @return void
- */
- public function beforeRender() {
- parent::beforeRender();
- foreach ($this->viewVars as $key => $value) {
- if (!is_object($value)) {
- $this->viewVars[$key] = h($value);
- }
- }
- }
-
-}
diff --git a/lib/Cake/Controller/Component.php b/lib/Cake/Controller/Component.php
deleted file mode 100644
index cecf39e059a..00000000000
--- a/lib/Cake/Controller/Component.php
+++ /dev/null
@@ -1,165 +0,0 @@
-_Collection = $collection;
- $this->settings = $settings;
- $this->_set($settings);
- if (!empty($this->components)) {
- $this->_componentMap = ComponentCollection::normalizeObjectArray($this->components);
- }
- }
-
-/**
- * Magic method for lazy loading $components.
- *
- * @param string $name Name of component to get.
- * @return mixed A Component object or null.
- */
- public function __get($name) {
- if (isset($this->_componentMap[$name]) && !isset($this->{$name})) {
- $settings = array_merge((array)$this->_componentMap[$name]['settings'], array('enabled' => false));
- $this->{$name} = $this->_Collection->load($this->_componentMap[$name]['class'], $settings);
- }
- if (isset($this->{$name})) {
- return $this->{$name};
- }
- }
-
-/**
- * Called before the Controller::beforeFilter().
- *
- * @param Controller $controller Controller with components to initialize
- * @return void
- * @link http://book.cakephp.org/2.0/en/controllers/components.html#Component::initialize
- */
- public function initialize(Controller $controller) {
- }
-
-/**
- * Called after the Controller::beforeFilter() and before the controller action
- *
- * @param Controller $controller Controller with components to startup
- * @return void
- * @link http://book.cakephp.org/2.0/en/controllers/components.html#Component::startup
- */
- public function startup(Controller $controller) {
- }
-
-/**
- * Called before the Controller::beforeRender(), and before
- * the view class is loaded, and before Controller::render()
- *
- * @param Controller $controller Controller with components to beforeRender
- * @return void
- * @link http://book.cakephp.org/2.0/en/controllers/components.html#Component::beforeRender
- */
- public function beforeRender(Controller $controller) {
- }
-
-/**
- * Called after Controller::render() and before the output is printed to the browser.
- *
- * @param Controller $controller Controller with components to shutdown
- * @return void
- * @link @link http://book.cakephp.org/2.0/en/controllers/components.html#Component::shutdown
- */
- public function shutdown(Controller $controller) {
- }
-
-/**
- * Called before Controller::redirect(). Allows you to replace the url that will
- * be redirected to with a new url. The return of this method can either be an array or a string.
- *
- * If the return is an array and contains a 'url' key. You may also supply the following:
- *
- * - `status` The status code for the redirect
- * - `exit` Whether or not the redirect should exit.
- *
- * If your response is a string or an array that does not contain a 'url' key it will
- * be used as the new url to redirect to.
- *
- * @param Controller $controller Controller with components to beforeRedirect
- * @param string|array $url Either the string or url array that is being redirected to.
- * @param integer $status The status code of the redirect
- * @param boolean $exit Will the script exit.
- * @return array|null Either an array or null.
- * @link @link http://book.cakephp.org/2.0/en/controllers/components.html#Component::beforeRedirect
- */
- public function beforeRedirect(Controller $controller, $url, $status = null, $exit = true) {
- }
-
-}
diff --git a/lib/Cake/Controller/Component/Acl/AclInterface.php b/lib/Cake/Controller/Component/Acl/AclInterface.php
deleted file mode 100644
index 7cd98135b81..00000000000
--- a/lib/Cake/Controller/Component/Acl/AclInterface.php
+++ /dev/null
@@ -1,70 +0,0 @@
-Aro = ClassRegistry::init(array('class' => 'Aro', 'alias' => 'Aro'));
- $this->Aco = ClassRegistry::init(array('class' => 'Aco', 'alias' => 'Aco'));
- }
-
-/**
- * Initializes the containing component and sets the Aro/Aco objects to it.
- *
- * @param AclComponent $component
- * @return void
- */
- public function initialize(Component $component) {
- $component->Aro = $this->Aro;
- $component->Aco = $this->Aco;
- }
-
-/**
- * Checks if the given $aro has access to action $action in $aco
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $action Action (defaults to *)
- * @return boolean Success (true if ARO has access to action in ACO, false otherwise)
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#checking-permissions-the-acl-component
- */
- public function check($aro, $aco, $action = "*") {
- if ($aro == null || $aco == null) {
- return false;
- }
-
- $permKeys = $this->_getAcoKeys($this->Aro->Permission->schema());
- $aroPath = $this->Aro->node($aro);
- $acoPath = $this->Aco->node($aco);
-
- if (empty($aroPath) || empty($acoPath)) {
- trigger_error(__d('cake_dev', "DbAcl::check() - Failed ARO/ACO node lookup in permissions check. Node references:\nAro: ") . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING);
- return false;
- }
-
- if ($acoPath == null || $acoPath == array()) {
- trigger_error(__d('cake_dev', "DbAcl::check() - Failed ACO node lookup in permissions check. Node references:\nAro: ") . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING);
- return false;
- }
-
- if ($action != '*' && !in_array('_' . $action, $permKeys)) {
- trigger_error(__d('cake_dev', "ACO permissions key %s does not exist in DbAcl::check()", $action), E_USER_NOTICE);
- return false;
- }
-
- $inherited = array();
- $acoIDs = Set::extract($acoPath, '{n}.' . $this->Aco->alias . '.id');
-
- $count = count($aroPath);
- for ($i = 0; $i < $count; $i++) {
- $permAlias = $this->Aro->Permission->alias;
-
- $perms = $this->Aro->Permission->find('all', array(
- 'conditions' => array(
- "{$permAlias}.aro_id" => $aroPath[$i][$this->Aro->alias]['id'],
- "{$permAlias}.aco_id" => $acoIDs
- ),
- 'order' => array($this->Aco->alias . '.lft' => 'desc'),
- 'recursive' => 0
- ));
-
- if (empty($perms)) {
- continue;
- } else {
- $perms = Set::extract($perms, '{n}.' . $this->Aro->Permission->alias);
- foreach ($perms as $perm) {
- if ($action == '*') {
-
- foreach ($permKeys as $key) {
- if (!empty($perm)) {
- if ($perm[$key] == -1) {
- return false;
- } elseif ($perm[$key] == 1) {
- $inherited[$key] = 1;
- }
- }
- }
-
- if (count($inherited) === count($permKeys)) {
- return true;
- }
- } else {
- switch ($perm['_' . $action]) {
- case -1:
- return false;
- case 0:
- continue;
- break;
- case 1:
- return true;
- break;
- }
- }
- }
- }
- }
- return false;
- }
-
-/**
- * Allow $aro to have access to action $actions in $aco
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $actions Action (defaults to *)
- * @param integer $value Value to indicate access type (1 to give access, -1 to deny, 0 to inherit)
- * @return boolean Success
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#assigning-permissions
- */
- public function allow($aro, $aco, $actions = "*", $value = 1) {
- $perms = $this->getAclLink($aro, $aco);
- $permKeys = $this->_getAcoKeys($this->Aro->Permission->schema());
- $save = array();
-
- if ($perms == false) {
- trigger_error(__d('cake_dev', 'DbAcl::allow() - Invalid node'), E_USER_WARNING);
- return false;
- }
- if (isset($perms[0])) {
- $save = $perms[0][$this->Aro->Permission->alias];
- }
-
- if ($actions == "*") {
- $permKeys = $this->_getAcoKeys($this->Aro->Permission->schema());
- $save = array_combine($permKeys, array_pad(array(), count($permKeys), $value));
- } else {
- if (!is_array($actions)) {
- $actions = array('_' . $actions);
- }
- if (is_array($actions)) {
- foreach ($actions as $action) {
- if ($action{0} != '_') {
- $action = '_' . $action;
- }
- if (in_array($action, $permKeys)) {
- $save[$action] = $value;
- }
- }
- }
- }
- list($save['aro_id'], $save['aco_id']) = array($perms['aro'], $perms['aco']);
-
- if ($perms['link'] != null && !empty($perms['link'])) {
- $save['id'] = $perms['link'][0][$this->Aro->Permission->alias]['id'];
- } else {
- unset($save['id']);
- $this->Aro->Permission->id = null;
- }
- return ($this->Aro->Permission->save($save) !== false);
- }
-
-/**
- * Deny access for $aro to action $action in $aco
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $action Action (defaults to *)
- * @return boolean Success
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#assigning-permissions
- */
- public function deny($aro, $aco, $action = "*") {
- return $this->allow($aro, $aco, $action, -1);
- }
-
-/**
- * Let access for $aro to action $action in $aco be inherited
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $action Action (defaults to *)
- * @return boolean Success
- */
- public function inherit($aro, $aco, $action = "*") {
- return $this->allow($aro, $aco, $action, 0);
- }
-
-/**
- * Allow $aro to have access to action $actions in $aco
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $action Action (defaults to *)
- * @return boolean Success
- * @see allow()
- */
- public function grant($aro, $aco, $action = "*") {
- return $this->allow($aro, $aco, $action);
- }
-
-/**
- * Deny access for $aro to action $action in $aco
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $action Action (defaults to *)
- * @return boolean Success
- * @see deny()
- */
- public function revoke($aro, $aco, $action = "*") {
- return $this->deny($aro, $aco, $action);
- }
-
-/**
- * Get an array of access-control links between the given Aro and Aco
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @return array Indexed array with: 'aro', 'aco' and 'link'
- */
- public function getAclLink($aro, $aco) {
- $obj = array();
- $obj['Aro'] = $this->Aro->node($aro);
- $obj['Aco'] = $this->Aco->node($aco);
-
- if (empty($obj['Aro']) || empty($obj['Aco'])) {
- return false;
- }
-
- return array(
- 'aro' => Set::extract($obj, 'Aro.0.' . $this->Aro->alias . '.id'),
- 'aco' => Set::extract($obj, 'Aco.0.' . $this->Aco->alias . '.id'),
- 'link' => $this->Aro->Permission->find('all', array('conditions' => array(
- $this->Aro->Permission->alias . '.aro_id' => Set::extract($obj, 'Aro.0.' . $this->Aro->alias . '.id'),
- $this->Aro->Permission->alias . '.aco_id' => Set::extract($obj, 'Aco.0.' . $this->Aco->alias . '.id')
- )))
- );
- }
-
-/**
- * Get the keys used in an ACO
- *
- * @param array $keys Permission model info
- * @return array ACO keys
- */
- protected function _getAcoKeys($keys) {
- $newKeys = array();
- $keys = array_keys($keys);
- foreach ($keys as $key) {
- if (!in_array($key, array('id', 'aro_id', 'aco_id'))) {
- $newKeys[] = $key;
- }
- }
- return $newKeys;
- }
-
-}
diff --git a/lib/Cake/Controller/Component/Acl/IniAcl.php b/lib/Cake/Controller/Component/Acl/IniAcl.php
deleted file mode 100644
index 8af85ca5061..00000000000
--- a/lib/Cake/Controller/Component/Acl/IniAcl.php
+++ /dev/null
@@ -1,172 +0,0 @@
-config == null) {
- $this->config = $this->readConfigFile(APP . 'Config' . DS . 'acl.ini.php');
- }
- $aclConfig = $this->config;
-
- if (is_array($aro)) {
- $aro = Set::classicExtract($aro, $this->userPath);
- }
-
- if (isset($aclConfig[$aro]['deny'])) {
- $userDenies = $this->arrayTrim(explode(",", $aclConfig[$aro]['deny']));
-
- if (array_search($aco, $userDenies)) {
- return false;
- }
- }
-
- if (isset($aclConfig[$aro]['allow'])) {
- $userAllows = $this->arrayTrim(explode(",", $aclConfig[$aro]['allow']));
-
- if (array_search($aco, $userAllows)) {
- return true;
- }
- }
-
- if (isset($aclConfig[$aro]['groups'])) {
- $userGroups = $this->arrayTrim(explode(",", $aclConfig[$aro]['groups']));
-
- foreach ($userGroups as $group) {
- if (array_key_exists($group, $aclConfig)) {
- if (isset($aclConfig[$group]['deny'])) {
- $groupDenies = $this->arrayTrim(explode(",", $aclConfig[$group]['deny']));
-
- if (array_search($aco, $groupDenies)) {
- return false;
- }
- }
-
- if (isset($aclConfig[$group]['allow'])) {
- $groupAllows = $this->arrayTrim(explode(",", $aclConfig[$group]['allow']));
-
- if (array_search($aco, $groupAllows)) {
- return true;
- }
- }
- }
- }
- }
- return false;
- }
-
-/**
- * Parses an INI file and returns an array that reflects the
- * INI file's section structure. Double-quote friendly.
- *
- * @param string $filename File
- * @return array INI section structure
- */
- public function readConfigFile($filename) {
- App::uses('IniReader', 'Configure');
- $iniFile = new IniReader(dirname($filename) . DS);
- return $iniFile->read(basename($filename));
- }
-
-/**
- * Removes trailing spaces on all array elements (to prepare for searching)
- *
- * @param array $array Array to trim
- * @return array Trimmed array
- */
- public function arrayTrim($array) {
- foreach ($array as $key => $value) {
- $array[$key] = trim($value);
- }
- array_unshift($array, "");
- return $array;
- }
-
-}
diff --git a/lib/Cake/Controller/Component/Acl/PhpAcl.php b/lib/Cake/Controller/Component/Acl/PhpAcl.php
deleted file mode 100644
index d2af2f960f9..00000000000
--- a/lib/Cake/Controller/Component/Acl/PhpAcl.php
+++ /dev/null
@@ -1,539 +0,0 @@
-options = array(
- 'policy' => self::DENY,
- 'config' => APP . 'Config' . DS . 'acl.php',
- );
- }
-
-/**
- * Initialize method
- *
- * @param AclComponent $Component Component instance
- * @return void
- */
- public function initialize(Component $Component) {
- if (!empty($Component->settings['adapter'])) {
- $this->options = array_merge($this->options, $Component->settings['adapter']);
- }
-
- App::uses('PhpReader', 'Configure');
- $Reader = new PhpReader(dirname($this->options['config']) . DS);
- $config = $Reader->read(basename($this->options['config']));
- $this->build($config);
- $Component->Aco = $this->Aco;
- $Component->Aro = $this->Aro;
- }
-
-/**
- * build and setup internal ACL representation
- *
- * @param array $config configuration array, see docs
- * @return void
- * @throws AclException When required keys are missing.
- */
- public function build(array $config) {
- if (empty($config['roles'])) {
- throw new AclException(__d('cake_dev','"roles" section not found in configuration.'));
- }
-
- if (empty($config['rules']['allow']) && empty($config['rules']['deny'])) {
- throw new AclException(__d('cake_dev','Neither "allow" nor "deny" rules were provided in configuration.'));
- }
-
- $rules['allow'] = !empty($config['rules']['allow']) ? $config['rules']['allow'] : array();
- $rules['deny'] = !empty($config['rules']['deny']) ? $config['rules']['deny'] : array();
- $roles = !empty($config['roles']) ? $config['roles'] : array();
- $map = !empty($config['map']) ? $config['map'] : array();
- $alias = !empty($config['alias']) ? $config['alias'] : array();
-
- $this->Aro = new PhpAro($roles, $map, $alias);
- $this->Aco = new PhpAco($rules);
- }
-
-/**
- * No op method, allow cannot be done with PhpAcl
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $action Action (defaults to *)
- * @return boolean Success
- */
- public function allow($aro, $aco, $action = "*") {
- return $this->Aco->access($this->Aro->resolve($aro), $aco, $action, 'allow');
- }
-
-/**
- * deny ARO access to ACO
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $action Action (defaults to *)
- * @return boolean Success
- */
- public function deny($aro, $aco, $action = "*") {
- return $this->Aco->access($this->Aro->resolve($aro), $aco, $action, 'deny');
- }
-
-/**
- * No op method
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $action Action (defaults to *)
- * @return boolean Success
- */
- public function inherit($aro, $aco, $action = "*") {
- return false;
- }
-
-/**
- * Main ACL check function. Checks to see if the ARO (access request object) has access to the
- * ACO (access control object).
- *
- * @param string $aro ARO
- * @param string $aco ACO
- * @param string $action Action
- * @return boolean true if access is granted, false otherwise
- */
- public function check($aro, $aco, $action = "*") {
- $allow = $this->options['policy'];
- $prioritizedAros = $this->Aro->roles($aro);
-
- if ($action && $action != "*") {
- $aco .= '/' . $action;
- }
-
- $path = $this->Aco->path($aco);
-
- if (empty($path)) {
- return $allow;
- }
-
- foreach ($path as $depth => $node) {
- foreach ($prioritizedAros as $aros) {
- if (!empty($node['allow'])) {
- $allow = $allow || count(array_intersect($node['allow'], $aros)) > 0;
- }
-
- if (!empty($node['deny'])) {
- $allow = $allow && count(array_intersect($node['deny'], $aros)) == 0;
- }
- }
- }
-
- return $allow;
- }
-
-}
-
-/**
- * Access Control Object
- *
- */
-class PhpAco {
-
-/**
- * holds internal ACO representation
- *
- * @var array
- */
- protected $_tree = array();
-
-/**
- * map modifiers for ACO paths to their respective PCRE pattern
- *
- * @var array
- */
- public static $modifiers = array(
- '*' => '.*',
- );
-
- public function __construct(array $rules = array()) {
- foreach (array('allow', 'deny') as $type) {
- if (empty($rules[$type])) {
- $rules[$type] = array();
- }
- }
-
- $this->build($rules['allow'], $rules['deny']);
- }
-
-/**
- * return path to the requested ACO with allow and deny rules attached on each level
- *
- * @return array
- */
- public function path($aco) {
- $aco = $this->resolve($aco);
- $path = array();
- $level = 0;
- $root = $this->_tree;
- $stack = array(array($root, 0));
-
- while (!empty($stack)) {
- list($root, $level) = array_pop($stack);
-
- if (empty($path[$level])) {
- $path[$level] = array();
- }
-
- foreach ($root as $node => $elements) {
- $pattern = '/^' . str_replace(array_keys(self::$modifiers), array_values(self::$modifiers), $node) . '$/';
-
- if ($node == $aco[$level] || preg_match($pattern, $aco[$level])) {
- // merge allow/denies with $path of current level
- foreach (array('allow', 'deny') as $policy) {
- if (!empty($elements[$policy])) {
- if (empty($path[$level][$policy])) {
- $path[$level][$policy] = array();
- }
- $path[$level][$policy] = array_merge($path[$level][$policy], $elements[$policy]);
- }
- }
-
- // traverse
- if (!empty($elements['children']) && isset($aco[$level + 1])) {
- array_push($stack, array($elements['children'], $level + 1));
- }
- }
- }
- }
-
- return $path;
- }
-
-/**
- * allow/deny ARO access to ARO
- *
- * @return void
- */
- public function access($aro, $aco, $action, $type = 'deny') {
- $aco = $this->resolve($aco);
- $depth = count($aco);
- $root = $this->_tree;
- $tree = &$root;
-
- foreach ($aco as $i => $node) {
- if (!isset($tree[$node])) {
- $tree[$node] = array(
- 'children' => array(),
- );
- }
-
- if ($i < $depth - 1) {
- $tree = &$tree[$node]['children'];
- } else {
- if (empty($tree[$node][$type])) {
- $tree[$node][$type] = array();
- }
-
- $tree[$node][$type] = array_merge(is_array($aro) ? $aro : array($aro), $tree[$node][$type]);
- }
- }
-
- $this->_tree = &$root;
- }
-
-/**
- * resolve given ACO string to a path
- *
- * @param string $aco ACO string
- * @return array path
- */
- public function resolve($aco) {
- if (is_array($aco)) {
- return array_map('strtolower', $aco);
- }
-
- // strip multiple occurences of '/'
- $aco = preg_replace('#/+#', '/', $aco);
- // make case insensitive
- $aco = ltrim(strtolower($aco), '/');
- return array_filter(array_map('trim', explode('/', $aco)));
- }
-
-/**
- * build a tree representation from the given allow/deny informations for ACO paths
- *
- * @param array $allow ACO allow rules
- * @param array $deny ACO deny rules
- * @return void
- */
- public function build(array $allow, array $deny = array()) {
- $stack = array();
- $this->_tree = array();
- $tree = array();
- $root = &$tree;
-
- foreach ($allow as $dotPath => $aros) {
- if (is_string($aros)) {
- $aros = array_map('trim', explode(',', $aros));
- }
-
- $this->access($aros, $dotPath, null, 'allow');
- }
-
- foreach ($deny as $dotPath => $aros) {
- if (is_string($aros)) {
- $aros = array_map('trim', explode(',', $aros));
- }
-
- $this->access($aros, $dotPath, null, 'deny');
- }
- }
-
-}
-
-/**
- * Access Request Object
- *
- */
-class PhpAro {
-
-/**
- * role to resolve to when a provided ARO is not listed in
- * the internal tree
- *
- * @var string
- */
- const DEFAULT_ROLE = 'Role/default';
-
-/**
- * map external identifiers. E.g. if
- *
- * array('User' => array('username' => 'jeff', 'role' => 'editor'))
- *
- * is passed as an ARO to one of the methods of AclComponent, PhpAcl
- * will check if it can be resolved to an User or a Role defined in the
- * configuration file.
- *
- * @var array
- * @see app/Config/acl.php
- */
- public $map = array(
- 'User' => 'User/username',
- 'Role' => 'User/role',
- );
-
-/**
- * aliases to map
- *
- * @var array
- */
- public $aliases = array();
-
-/**
- * internal ARO representation
- *
- * @var array
- */
- protected $_tree = array();
-
- public function __construct(array $aro = array(), array $map = array(), array $aliases = array()) {
- if (!empty($map)) {
- $this->map = $map;
- }
-
- $this->aliases = $aliases;
- $this->build($aro);
- }
-
-/**
- * From the perspective of the given ARO, walk down the tree and
- * collect all inherited AROs levelwise such that AROs from different
- * branches with equal distance to the requested ARO will be collected at the same
- * index. The resulting array will contain a prioritized list of (list of) roles ordered from
- * the most distant AROs to the requested one itself.
- *
- * @param mixed $aro An ARO identifier
- * @return array prioritized AROs
- */
- public function roles($aro) {
- $aros = array();
- $aro = $this->resolve($aro);
- $stack = array(array($aro, 0));
-
- while (!empty($stack)) {
- list($element, $depth) = array_pop($stack);
- $aros[$depth][] = $element;
-
- foreach ($this->_tree as $node => $children) {
- if (in_array($element, $children)) {
- array_push($stack, array($node, $depth + 1));
- }
- }
- }
-
- return array_reverse($aros);
- }
-
-/**
- * resolve an ARO identifier to an internal ARO string using
- * the internal mapping information.
- *
- * @param mixed $aro ARO identifier (User.jeff, array('User' => ...), etc)
- * @return string internal aro string (e.g. User/jeff, Role/default)
- */
- public function resolve($aro) {
- foreach ($this->map as $aroGroup => $map) {
- list ($model, $field) = explode('/', $map, 2);
- $mapped = '';
-
- if (is_array($aro)) {
- if (isset($aro['model']) && isset($aro['foreign_key']) && $aro['model'] == $aroGroup) {
- $mapped = $aroGroup . '/' . $aro['foreign_key'];
- } elseif (isset($aro[$model][$field])) {
- $mapped = $aroGroup . '/' . $aro[$model][$field];
- } elseif (isset($aro[$field])) {
- $mapped = $aroGroup . '/' . $aro[$field];
- }
- } elseif (is_string($aro)) {
- $aro = ltrim($aro, '/');
-
- if (strpos($aro, '/') === false) {
- $mapped = $aroGroup . '/' . $aro;
- } else {
- list($aroModel, $aroValue) = explode('/', $aro, 2);
-
- $aroModel = Inflector::camelize($aroModel);
-
- if ($aroModel == $model || $aroModel == $aroGroup) {
- $mapped = $aroGroup . '/' . $aroValue;
- }
- }
- }
-
- if (isset($this->_tree[$mapped])) {
- return $mapped;
- }
-
- // is there a matching alias defined (e.g. Role/1 => Role/admin)?
- if (!empty($this->aliases[$mapped])) {
- return $this->aliases[$mapped];
- }
- }
- return self::DEFAULT_ROLE;
- }
-
-/**
- * adds a new ARO to the tree
- *
- * @param array $aro one or more ARO records
- * @return void
- */
- public function addRole(array $aro) {
- foreach ($aro as $role => $inheritedRoles) {
- if (!isset($this->_tree[$role])) {
- $this->_tree[$role] = array();
- }
-
- if (!empty($inheritedRoles)) {
- if (is_string($inheritedRoles)) {
- $inheritedRoles = array_map('trim', explode(',', $inheritedRoles));
- }
-
- foreach ($inheritedRoles as $dependency) {
- // detect cycles
- $roles = $this->roles($dependency);
-
- if (in_array($role, Set::flatten($roles))) {
- $path = '';
-
- foreach ($roles as $roleDependencies) {
- $path .= implode('|', (array)$roleDependencies) . ' -> ';
- }
-
- trigger_error(__d('cake_dev', 'cycle detected when inheriting %s from %s. Path: %s', $role, $dependency, $path . $role));
- continue;
- }
-
- if (!isset($this->_tree[$dependency])) {
- $this->_tree[$dependency] = array();
- }
-
- $this->_tree[$dependency][] = $role;
- }
- }
- }
- }
-
-/**
- * adds one or more aliases to the internal map. Overwrites existing entries.
- *
- * @param array $alias alias from => to (e.g. Role/13 -> Role/editor)
- * @return void
- */
- public function addAlias(array $alias) {
- $this->aliases = array_merge($this->aliases, $alias);
- }
-
-/**
- * build an ARO tree structure for internal processing
- *
- * @param array $aros array of AROs as key and their inherited AROs as values
- * @return void
- */
- public function build(array $aros) {
- $this->_tree = array();
- $this->addRole($aros);
- }
-
-}
diff --git a/lib/Cake/Controller/Component/AclComponent.php b/lib/Cake/Controller/Component/AclComponent.php
deleted file mode 100644
index 659a503cb76..00000000000
--- a/lib/Cake/Controller/Component/AclComponent.php
+++ /dev/null
@@ -1,181 +0,0 @@
-adapter($name);
- }
-
-/**
- * Sets or gets the Adapter object currently in the AclComponent.
- *
- * `$this->Acl->adapter();` will get the current adapter class while
- * `$this->Acl->adapter($obj);` will set the adapter class
- *
- * Will call the initialize method on the adapter if setting a new one.
- *
- * @param mixed $adapter Instance of AclInterface or a string name of the class to use. (optional)
- * @return mixed either null, or the adapter implementation.
- * @throws CakeException when the given class is not an instance of AclInterface
- */
- public function adapter($adapter = null) {
- if ($adapter) {
- if (is_string($adapter)) {
- $adapter = new $adapter();
- }
- if (!$adapter instanceof AclInterface) {
- throw new CakeException(__d('cake_dev', 'AclComponent adapters must implement AclInterface'));
- }
- $this->_Instance = $adapter;
- $this->_Instance->initialize($this);
- return;
- }
- return $this->_Instance;
- }
-
-/**
- * Pass-thru function for ACL check instance. Check methods
- * are used to check whether or not an ARO can access an ACO
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $action Action (defaults to *)
- * @return boolean Success
- */
- public function check($aro, $aco, $action = "*") {
- return $this->_Instance->check($aro, $aco, $action);
- }
-
-/**
- * Pass-thru function for ACL allow instance. Allow methods
- * are used to grant an ARO access to an ACO.
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $action Action (defaults to *)
- * @return boolean Success
- */
- public function allow($aro, $aco, $action = "*") {
- return $this->_Instance->allow($aro, $aco, $action);
- }
-
-/**
- * Pass-thru function for ACL deny instance. Deny methods
- * are used to remove permission from an ARO to access an ACO.
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $action Action (defaults to *)
- * @return boolean Success
- */
- public function deny($aro, $aco, $action = "*") {
- return $this->_Instance->deny($aro, $aco, $action);
- }
-
-/**
- * Pass-thru function for ACL inherit instance. Inherit methods
- * modify the permission for an ARO to be that of its parent object.
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $action Action (defaults to *)
- * @return boolean Success
- */
- public function inherit($aro, $aco, $action = "*") {
- return $this->_Instance->inherit($aro, $aco, $action);
- }
-
-/**
- * Pass-thru function for ACL grant instance. An alias for AclComponent::allow()
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $action Action (defaults to *)
- * @return boolean Success
- * @deprecated
- */
- public function grant($aro, $aco, $action = "*") {
- trigger_error(__d('cake_dev', 'AclComponent::grant() is deprecated, use allow() instead'), E_USER_WARNING);
- return $this->_Instance->allow($aro, $aco, $action);
- }
-
-/**
- * Pass-thru function for ACL grant instance. An alias for AclComponent::deny()
- *
- * @param string $aro ARO The requesting object identifier.
- * @param string $aco ACO The controlled object identifier.
- * @param string $action Action (defaults to *)
- * @return boolean Success
- * @deprecated
- */
- public function revoke($aro, $aco, $action = "*") {
- trigger_error(__d('cake_dev', 'AclComponent::revoke() is deprecated, use deny() instead'), E_USER_WARNING);
- return $this->_Instance->deny($aro, $aco, $action);
- }
-
-}
diff --git a/lib/Cake/Controller/Component/Auth/ActionsAuthorize.php b/lib/Cake/Controller/Component/Auth/ActionsAuthorize.php
deleted file mode 100644
index 3f279b0787d..00000000000
--- a/lib/Cake/Controller/Component/Auth/ActionsAuthorize.php
+++ /dev/null
@@ -1,42 +0,0 @@
-_Collection->load('Acl');
- $user = array($this->settings['userModel'] => $user);
- return $Acl->check($user, $this->action($request));
- }
-
-}
diff --git a/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php b/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php
deleted file mode 100644
index bcb519b33ce..00000000000
--- a/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php
+++ /dev/null
@@ -1,138 +0,0 @@
- 1).`
- * - `recursive` The value of the recursive key passed to find(). Defaults to 0.
- *
- * @var array
- */
- public $settings = array(
- 'fields' => array(
- 'username' => 'username',
- 'password' => 'password'
- ),
- 'userModel' => 'User',
- 'scope' => array(),
- 'recursive' => 0
- );
-
-/**
- * A Component collection, used to get more components.
- *
- * @var ComponentCollection
- */
- protected $_Collection;
-
-/**
- * Constructor
- *
- * @param ComponentCollection $collection The Component collection used on this request.
- * @param array $settings Array of settings to use.
- */
- public function __construct(ComponentCollection $collection, $settings) {
- $this->_Collection = $collection;
- $this->settings = Set::merge($this->settings, $settings);
- }
-
-/**
- * Find a user record using the standard options.
- *
- * @param string $username The username/identifier.
- * @param string $password The unhashed password.
- * @return Mixed Either false on failure, or an array of user data.
- */
- protected function _findUser($username, $password) {
- $userModel = $this->settings['userModel'];
- list($plugin, $model) = pluginSplit($userModel);
- $fields = $this->settings['fields'];
-
- $conditions = array(
- $model . '.' . $fields['username'] => $username,
- $model . '.' . $fields['password'] => $this->_password($password),
- );
- if (!empty($this->settings['scope'])) {
- $conditions = array_merge($conditions, $this->settings['scope']);
- }
- $result = ClassRegistry::init($userModel)->find('first', array(
- 'conditions' => $conditions,
- 'recursive' => (int)$this->settings['recursive']
- ));
- if (empty($result) || empty($result[$model])) {
- return false;
- }
- unset($result[$model][$fields['password']]);
- return $result[$model];
- }
-
-/**
- * Hash the plain text password so that it matches the hashed/encrypted password
- * in the datasource.
- *
- * @param string $password The plain text password.
- * @return string The hashed form of the password.
- */
- protected function _password($password) {
- return Security::hash($password, null, true);
- }
-
-/**
- * Authenticate a user based on the request information.
- *
- * @param CakeRequest $request Request to get authentication information from.
- * @param CakeResponse $response A response object that can have headers added.
- * @return mixed Either false on failure, or an array of user data on success.
- */
- abstract public function authenticate(CakeRequest $request, CakeResponse $response);
-
-/**
- * Allows you to hook into AuthComponent::logout(),
- * and implement specialized logout behavior.
- *
- * All attached authentication objects will have this method
- * called when a user logs out.
- *
- * @param array $user The user about to be logged out.
- * @return void
- */
- public function logout($user) {
- }
-
-/**
- * Get a user based on information in the request. Primarily used by stateless authentication
- * systems like basic and digest auth.
- *
- * @param CakeRequest $request Request object.
- * @return mixed Either false or an array of user information
- */
- public function getUser($request) {
- return false;
- }
-
-}
diff --git a/lib/Cake/Controller/Component/Auth/BaseAuthorize.php b/lib/Cake/Controller/Component/Auth/BaseAuthorize.php
deleted file mode 100644
index 432886c78f4..00000000000
--- a/lib/Cake/Controller/Component/Auth/BaseAuthorize.php
+++ /dev/null
@@ -1,161 +0,0 @@
-action();
- * - `actionMap` - Action -> crud mappings. Used by authorization objects that want to map actions to CRUD roles.
- * - `userModel` - Model name that ARO records can be found under. Defaults to 'User'.
- *
- * @var array
- */
- public $settings = array(
- 'actionPath' => null,
- 'actionMap' => array(
- 'index' => 'read',
- 'add' => 'create',
- 'edit' => 'update',
- 'view' => 'read',
- 'delete' => 'delete',
- 'remove' => 'delete'
- ),
- 'userModel' => 'User'
- );
-
-/**
- * Constructor
- *
- * @param ComponentCollection $collection The controller for this request.
- * @param string $settings An array of settings. This class does not use any settings.
- */
- public function __construct(ComponentCollection $collection, $settings = array()) {
- $this->_Collection = $collection;
- $controller = $collection->getController();
- $this->controller($controller);
- $this->settings = Set::merge($this->settings, $settings);
- }
-
-/**
- * Checks user authorization.
- *
- * @param array $user Active user data
- * @param CakeRequest $request
- * @return boolean
- */
- abstract public function authorize($user, CakeRequest $request);
-
-/**
- * Accessor to the controller object.
- *
- * @param mixed $controller null to get, a controller to set.
- * @return mixed
- * @throws CakeException
- */
- public function controller(Controller $controller = null) {
- if ($controller) {
- if (!$controller instanceof Controller) {
- throw new CakeException(__d('cake_dev', '$controller needs to be an instance of Controller'));
- }
- $this->_Controller = $controller;
- return true;
- }
- return $this->_Controller;
- }
-
-/**
- * Get the action path for a given request. Primarily used by authorize objects
- * that need to get information about the plugin, controller, and action being invoked.
- *
- * @param CakeRequest $request The request a path is needed for.
- * @param string $path
- * @return string the action path for the given request.
- */
- public function action($request, $path = '/:plugin/:controller/:action') {
- $plugin = empty($request['plugin']) ? null : Inflector::camelize($request['plugin']) . '/';
- $path = str_replace(
- array(':controller', ':action', ':plugin/'),
- array(Inflector::camelize($request['controller']), $request['action'], $plugin),
- $this->settings['actionPath'] . $path
- );
- $path = str_replace('//', '/', $path);
- return trim($path, '/');
- }
-
-/**
- * Maps crud actions to actual action names. Used to modify or get the current mapped actions.
- *
- * Create additional mappings for a standard CRUD operation:
- *
- * {{{
- * $this->Auth->mapActions(array('create' => array('add', 'register'));
- * }}}
- *
- * Create mappings for custom CRUD operations:
- *
- * {{{
- * $this->Auth->mapActions(array('my_action' => 'admin'));
- * }}}
- *
- * You can use the custom CRUD operations to create additional generic permissions
- * that behave like CRUD operations. Doing this will require additional columns on the
- * permissions lookup. When using with DbAcl, you'll have to add additional _admin type columns
- * to the `aros_acos` table.
- *
- * @param mixed $map Either an array of mappings, or undefined to get current values.
- * @return mixed Either the current mappings or null when setting.
- * @see AuthComponent::mapActions()
- */
- public function mapActions($map = array()) {
- if (empty($map)) {
- return $this->settings['actionMap'];
- }
- $crud = array('create', 'read', 'update', 'delete');
- foreach ($map as $action => $type) {
- if (in_array($action, $crud) && is_array($type)) {
- foreach ($type as $typedAction) {
- $this->settings['actionMap'][$typedAction] = $action;
- }
- } else {
- $this->settings['actionMap'][$action] = $type;
- }
- }
- }
-
-}
diff --git a/lib/Cake/Controller/Component/Auth/BasicAuthenticate.php b/lib/Cake/Controller/Component/Auth/BasicAuthenticate.php
deleted file mode 100644
index c8e772e1cb7..00000000000
--- a/lib/Cake/Controller/Component/Auth/BasicAuthenticate.php
+++ /dev/null
@@ -1,126 +0,0 @@
- array(
- * 'authenticate' => array('Basic')
- * )
- * );
- * }}}
- *
- * In your login function just call `$this->Auth->login()` without any checks for POST data. This
- * will send the authentication headers, and trigger the login dialog in the browser/client.
- *
- * @package Cake.Controller.Component.Auth
- * @since 2.0
- */
-class BasicAuthenticate extends BaseAuthenticate {
-
-/**
- * Settings for this object.
- *
- * - `fields` The fields to use to identify a user by.
- * - `userModel` The model name of the User, defaults to User.
- * - `scope` Additional conditions to use when looking up and authenticating users,
- * i.e. `array('User.is_active' => 1).`
- * - `recursive` The value of the recursive key passed to find(). Defaults to 0.
- * - `realm` The realm authentication is for. Defaults the server name.
- *
- * @var array
- */
- public $settings = array(
- 'fields' => array(
- 'username' => 'username',
- 'password' => 'password'
- ),
- 'userModel' => 'User',
- 'scope' => array(),
- 'recursive' => 0,
- 'realm' => '',
- );
-
-/**
- * Constructor, completes configuration for basic authentication.
- *
- * @param ComponentCollection $collection The Component collection used on this request.
- * @param array $settings An array of settings.
- */
- public function __construct(ComponentCollection $collection, $settings) {
- parent::__construct($collection, $settings);
- if (empty($this->settings['realm'])) {
- $this->settings['realm'] = env('SERVER_NAME');
- }
- }
-
-/**
- * Authenticate a user using basic HTTP auth. Will use the configured User model and attempt a
- * login using basic HTTP auth.
- *
- * @param CakeRequest $request The request to authenticate with.
- * @param CakeResponse $response The response to add headers to.
- * @return mixed Either false on failure, or an array of user data on success.
- */
- public function authenticate(CakeRequest $request, CakeResponse $response) {
- $result = $this->getUser($request);
-
- if (empty($result)) {
- $response->header($this->loginHeaders());
- $response->statusCode(401);
- $response->send();
- return false;
- }
- return $result;
- }
-
-/**
- * Get a user based on information in the request. Used by cookie-less auth for stateless clients.
- *
- * @param CakeRequest $request Request object.
- * @return mixed Either false or an array of user information
- */
- public function getUser($request) {
- $username = env('PHP_AUTH_USER');
- $pass = env('PHP_AUTH_PW');
-
- if (empty($username) || empty($pass)) {
- return false;
- }
- return $this->_findUser($username, $pass);
- }
-
-/**
- * Generate the login headers
- *
- * @return string Headers for logging in.
- */
- public function loginHeaders() {
- return sprintf('WWW-Authenticate: Basic realm="%s"', $this->settings['realm']);
- }
-
-}
diff --git a/lib/Cake/Controller/Component/Auth/ControllerAuthorize.php b/lib/Cake/Controller/Component/Auth/ControllerAuthorize.php
deleted file mode 100644
index d3c502aa788..00000000000
--- a/lib/Cake/Controller/Component/Auth/ControllerAuthorize.php
+++ /dev/null
@@ -1,67 +0,0 @@
-request->params['admin'])) {
- * return $user['role'] == 'admin';
- * }
- * return !empty($user);
- * }
- * }}}
- *
- * the above is simple implementation that would only authorize users of the 'admin' role to access
- * admin routing.
- *
- * @package Cake.Controller.Component.Auth
- * @since 2.0
- * @see AuthComponent::$authenticate
- */
-class ControllerAuthorize extends BaseAuthorize {
-
-/**
- * Get/set the controller this authorize object will be working with. Also checks that isAuthorized is implemented.
- *
- * @param mixed $controller null to get, a controller to set.
- * @return mixed
- * @throws CakeException
- */
- public function controller(Controller $controller = null) {
- if ($controller) {
- if (!method_exists($controller, 'isAuthorized')) {
- throw new CakeException(__d('cake_dev', '$controller does not implement an isAuthorized() method.'));
- }
- }
- return parent::controller($controller);
- }
-
-/**
- * Checks user authorization using a controller callback.
- *
- * @param array $user Active user data
- * @param CakeRequest $request
- * @return boolean
- */
- public function authorize($user, CakeRequest $request) {
- return (bool)$this->_Controller->isAuthorized($user);
- }
-
-}
diff --git a/lib/Cake/Controller/Component/Auth/CrudAuthorize.php b/lib/Cake/Controller/Component/Auth/CrudAuthorize.php
deleted file mode 100644
index 83761b1e22b..00000000000
--- a/lib/Cake/Controller/Component/Auth/CrudAuthorize.php
+++ /dev/null
@@ -1,102 +0,0 @@
-_setPrefixMappings();
- }
-
-/**
- * sets the crud mappings for prefix routes.
- *
- * @return void
- */
- protected function _setPrefixMappings() {
- $crud = array('create', 'read', 'update', 'delete');
- $map = array_combine($crud, $crud);
-
- $prefixes = Router::prefixes();
- if (!empty($prefixes)) {
- foreach ($prefixes as $prefix) {
- $map = array_merge($map, array(
- $prefix . '_index' => 'read',
- $prefix . '_add' => 'create',
- $prefix . '_edit' => 'update',
- $prefix . '_view' => 'read',
- $prefix . '_remove' => 'delete',
- $prefix . '_create' => 'create',
- $prefix . '_read' => 'read',
- $prefix . '_update' => 'update',
- $prefix . '_delete' => 'delete'
- ));
- }
- }
- $this->mapActions($map);
- }
-
-/**
- * Authorize a user using the mapped actions and the AclComponent.
- *
- * @param array $user The user to authorize
- * @param CakeRequest $request The request needing authorization.
- * @return boolean
- */
- public function authorize($user, CakeRequest $request) {
- if (!isset($this->settings['actionMap'][$request->params['action']])) {
- trigger_error(__d('cake_dev',
- 'CrudAuthorize::authorize() - Attempted access of un-mapped action "%1$s" in controller "%2$s"',
- $request->action,
- $request->controller
- ),
- E_USER_WARNING
- );
- return false;
- }
- $user = array($this->settings['userModel'] => $user);
- $Acl = $this->_Collection->load('Acl');
- return $Acl->check(
- $user,
- $this->action($request, ':controller'),
- $this->settings['actionMap'][$request->params['action']]
- );
- }
-
-}
diff --git a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php
deleted file mode 100644
index 27722a9c778..00000000000
--- a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php
+++ /dev/null
@@ -1,268 +0,0 @@
- array(
- * 'authenticate' => array('Digest')
- * )
- * );
- * }}}
- *
- * In your login function just call `$this->Auth->login()` without any checks for POST data. This
- * will send the authentication headers, and trigger the login dialog in the browser/client.
- *
- * ### Generating passwords compatible with Digest authentication.
- *
- * Due to the Digest authentication specification, digest auth requires a special password value. You
- * can generate this password using `DigestAuthenticate::password()`
- *
- * `$digestPass = DigestAuthenticate::password($username, env('SERVER_NAME'), $password);`
- *
- * Its recommended that you store this digest auth only password separate from password hashes used for other
- * login methods. For example `User.digest_pass` could be used for a digest password, while `User.password` would
- * store the password hash for use with other methods like Basic or Form.
- *
- * @package Cake.Controller.Component.Auth
- * @since 2.0
- */
-class DigestAuthenticate extends BaseAuthenticate {
-
-/**
- * Settings for this object.
- *
- * - `fields` The fields to use to identify a user by.
- * - `userModel` The model name of the User, defaults to User.
- * - `scope` Additional conditions to use when looking up and authenticating users,
- * i.e. `array('User.is_active' => 1).`
- * - `realm` The realm authentication is for, Defaults to the servername.
- * - `nonce` A nonce used for authentication. Defaults to `uniqid()`.
- * - `qop` Defaults to auth, no other values are supported at this time.
- * - `opaque` A string that must be returned unchanged by clients.
- * Defaults to `md5($settings['realm'])`
- *
- * @var array
- */
- public $settings = array(
- 'fields' => array(
- 'username' => 'username',
- 'password' => 'password'
- ),
- 'userModel' => 'User',
- 'scope' => array(),
- 'recursive' => 0,
- 'realm' => '',
- 'qop' => 'auth',
- 'nonce' => '',
- 'opaque' => ''
- );
-
-/**
- * Constructor, completes configuration for digest authentication.
- *
- * @param ComponentCollection $collection The Component collection used on this request.
- * @param array $settings An array of settings.
- */
- public function __construct(ComponentCollection $collection, $settings) {
- parent::__construct($collection, $settings);
- if (empty($this->settings['realm'])) {
- $this->settings['realm'] = env('SERVER_NAME');
- }
- if (empty($this->settings['nonce'])) {
- $this->settings['nonce'] = uniqid('');
- }
- if (empty($this->settings['opaque'])) {
- $this->settings['opaque'] = md5($this->settings['realm']);
- }
- }
-
-/**
- * Authenticate a user using Digest HTTP auth. Will use the configured User model and attempt a
- * login using Digest HTTP auth.
- *
- * @param CakeRequest $request The request to authenticate with.
- * @param CakeResponse $response The response to add headers to.
- * @return mixed Either false on failure, or an array of user data on success.
- */
- public function authenticate(CakeRequest $request, CakeResponse $response) {
- $user = $this->getUser($request);
-
- if (empty($user)) {
- $response->header($this->loginHeaders());
- $response->statusCode(401);
- $response->send();
- return false;
- }
- return $user;
- }
-
-/**
- * Get a user based on information in the request. Used by cookie-less auth for stateless clients.
- *
- * @param CakeRequest $request Request object.
- * @return mixed Either false or an array of user information
- */
- public function getUser($request) {
- $digest = $this->_getDigest();
- if (empty($digest)) {
- return false;
- }
- $user = $this->_findUser($digest['username'], null);
- if (empty($user)) {
- return false;
- }
- $password = $user[$this->settings['fields']['password']];
- unset($user[$this->settings['fields']['password']]);
- if ($digest['response'] === $this->generateResponseHash($digest, $password)) {
- return $user;
- }
- return false;
- }
-
-/**
- * Find a user record using the standard options.
- *
- * @param string $username The username/identifier.
- * @param string $password Unused password, digest doesn't require passwords.
- * @return Mixed Either false on failure, or an array of user data.
- */
- protected function _findUser($username, $password) {
- $userModel = $this->settings['userModel'];
- list($plugin, $model) = pluginSplit($userModel);
- $fields = $this->settings['fields'];
-
- $conditions = array(
- $model . '.' . $fields['username'] => $username,
- );
- if (!empty($this->settings['scope'])) {
- $conditions = array_merge($conditions, $this->settings['scope']);
- }
- $result = ClassRegistry::init($userModel)->find('first', array(
- 'conditions' => $conditions,
- 'recursive' => (int)$this->settings['recursive']
- ));
- if (empty($result) || empty($result[$model])) {
- return false;
- }
- return $result[$model];
- }
-
-/**
- * Gets the digest headers from the request/environment.
- *
- * @return array Array of digest information.
- */
- protected function _getDigest() {
- $digest = env('PHP_AUTH_DIGEST');
- if (empty($digest) && function_exists('apache_request_headers')) {
- $headers = apache_request_headers();
- if (!empty($headers['Authorization']) && substr($headers['Authorization'], 0, 7) == 'Digest ') {
- $digest = substr($headers['Authorization'], 7);
- }
- }
- if (empty($digest)) {
- return false;
- }
- return $this->parseAuthData($digest);
- }
-
-/**
- * Parse the digest authentication headers and split them up.
- *
- * @param string $digest The raw digest authentication headers.
- * @return array An array of digest authentication headers
- */
- public function parseAuthData($digest) {
- if (substr($digest, 0, 7) == 'Digest ') {
- $digest = substr($digest, 7);
- }
- $keys = $match = array();
- $req = array('nonce' => 1, 'nc' => 1, 'cnonce' => 1, 'qop' => 1, 'username' => 1, 'uri' => 1, 'response' => 1);
- preg_match_all('/(\w+)=([\'"]?)([a-zA-Z0-9@=.\/_-]+)\2/', $digest, $match, PREG_SET_ORDER);
-
- foreach ($match as $i) {
- $keys[$i[1]] = $i[3];
- unset($req[$i[1]]);
- }
-
- if (empty($req)) {
- return $keys;
- }
- return null;
- }
-
-/**
- * Generate the response hash for a given digest array.
- *
- * @param array $digest Digest information containing data from DigestAuthenticate::parseAuthData().
- * @param string $password The digest hash password generated with DigestAuthenticate::password()
- * @return string Response hash
- */
- public function generateResponseHash($digest, $password) {
- return md5(
- $password .
- ':' . $digest['nonce'] . ':' . $digest['nc'] . ':' . $digest['cnonce'] . ':' . $digest['qop'] . ':' .
- md5(env('REQUEST_METHOD') . ':' . $digest['uri'])
- );
- }
-
-/**
- * Creates an auth digest password hash to store
- *
- * @param string $username The username to use in the digest hash.
- * @param string $password The unhashed password to make a digest hash for.
- * @param string $realm The realm the password is for.
- * @return string the hashed password that can later be used with Digest authentication.
- */
- public static function password($username, $password, $realm) {
- return md5($username . ':' . $realm . ':' . $password);
- }
-
-/**
- * Generate the login headers
- *
- * @return string Headers for logging in.
- */
- public function loginHeaders() {
- $options = array(
- 'realm' => $this->settings['realm'],
- 'qop' => $this->settings['qop'],
- 'nonce' => $this->settings['nonce'],
- 'opaque' => $this->settings['opaque']
- );
- $opts = array();
- foreach ($options as $k => $v) {
- $opts[] = sprintf('%s="%s"', $k, $v);
- }
- return 'WWW-Authenticate: Digest ' . implode(',', $opts);
- }
-
-}
diff --git a/lib/Cake/Controller/Component/Auth/FormAuthenticate.php b/lib/Cake/Controller/Component/Auth/FormAuthenticate.php
deleted file mode 100644
index 0a51f527efe..00000000000
--- a/lib/Cake/Controller/Component/Auth/FormAuthenticate.php
+++ /dev/null
@@ -1,68 +0,0 @@
-Auth->authenticate = array(
- * 'Form' => array(
- * 'scope' => array('User.active' => 1)
- * )
- * )
- * }}}
- *
- * When configuring FormAuthenticate you can pass in settings to which fields, model and additional conditions
- * are used. See FormAuthenticate::$settings for more information.
- *
- * @package Cake.Controller.Component.Auth
- * @since 2.0
- * @see AuthComponent::$authenticate
- */
-class FormAuthenticate extends BaseAuthenticate {
-
-/**
- * Authenticates the identity contained in a request. Will use the `settings.userModel`, and `settings.fields`
- * to find POST data that is used to find a matching record in the `settings.userModel`. Will return false if
- * there is no post data, either username or password is missing, of if the scope conditions have not been met.
- *
- * @param CakeRequest $request The request that contains login information.
- * @param CakeResponse $response Unused response object.
- * @return mixed. False on login failure. An array of User data on success.
- */
- public function authenticate(CakeRequest $request, CakeResponse $response) {
- $userModel = $this->settings['userModel'];
- list($plugin, $model) = pluginSplit($userModel);
-
- $fields = $this->settings['fields'];
- if (empty($request->data[$model])) {
- return false;
- }
- if (
- empty($request->data[$model][$fields['username']]) ||
- empty($request->data[$model][$fields['password']])
- ) {
- return false;
- }
- return $this->_findUser(
- $request->data[$model][$fields['username']],
- $request->data[$model][$fields['password']]
- );
- }
-
-}
diff --git a/lib/Cake/Controller/Component/AuthComponent.php b/lib/Cake/Controller/Component/AuthComponent.php
deleted file mode 100644
index 24a812f695c..00000000000
--- a/lib/Cake/Controller/Component/AuthComponent.php
+++ /dev/null
@@ -1,722 +0,0 @@
-Auth->authenticate = array(
- * 'Form' => array(
- * 'userModel' => 'Users.User'
- * )
- * );
- * }}}
- *
- * Using the class name without 'Authenticate' as the key, you can pass in an array of settings for each
- * authentication object. Additionally you can define settings that should be set to all authentications objects
- * using the 'all' key:
- *
- * {{{
- * $this->Auth->authenticate = array(
- * 'all' => array(
- * 'userModel' => 'Users.User',
- * 'scope' => array('User.active' => 1)
- * ),
- * 'Form',
- * 'Basic'
- * );
- * }}}
- *
- * You can also use AuthComponent::ALL instead of the string 'all'.
- *
- * @var array
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html
- */
- public $authenticate = array('Form');
-
-/**
- * Objects that will be used for authentication checks.
- *
- * @var array
- */
- protected $_authenticateObjects = array();
-
-/**
- * An array of authorization objects to use for authorizing users. You can configure
- * multiple adapters and they will be checked sequentially when authorization checks are done.
- *
- * {{{
- * $this->Auth->authorize = array(
- * 'Crud' => array(
- * 'actionPath' => 'controllers/'
- * )
- * );
- * }}}
- *
- * Using the class name without 'Authorize' as the key, you can pass in an array of settings for each
- * authorization object. Additionally you can define settings that should be set to all authorization objects
- * using the 'all' key:
- *
- * {{{
- * $this->Auth->authorize = array(
- * 'all' => array(
- * 'actionPath' => 'controllers/'
- * ),
- * 'Crud',
- * 'CustomAuth'
- * );
- * }}}
- *
- * You can also use AuthComponent::ALL instead of the string 'all'
- *
- * @var mixed
- * @link http://book.cakephp.org/view/1275/authorize
- */
- public $authorize = false;
-
-/**
- * Objects that will be used for authorization checks.
- *
- * @var array
- */
- protected $_authorizeObjects = array();
-
-/**
- * The name of an optional view element to render when an Ajax request is made
- * with an invalid or expired session
- *
- * @var string
- */
- public $ajaxLogin = null;
-
-/**
- * Settings to use when Auth needs to do a flash message with SessionComponent::setFlash().
- * Available keys are:
- *
- * - `element` - The element to use, defaults to 'default'.
- * - `key` - The key to use, defaults to 'auth'
- * - `params` - The array of additional params to use, defaults to array()
- *
- * @var array
- */
- public $flash = array(
- 'element' => 'default',
- 'key' => 'auth',
- 'params' => array()
- );
-
-/**
- * The session key name where the record of the current user is stored. If
- * unspecified, it will be "Auth.User".
- *
- * @var string
- */
- public static $sessionKey = 'Auth.User';
-
-/**
- * The current user, used for stateless authentication when
- * sessions are not available.
- *
- * @var array
- */
- protected static $_user = array();
-
-/**
- * A URL (defined as a string or array) to the controller action that handles
- * logins. Defaults to `/users/login`
- *
- * @var mixed
- */
- public $loginAction = array(
- 'controller' => 'users',
- 'action' => 'login',
- 'plugin' => null
- );
-
-/**
- * Normally, if a user is redirected to the $loginAction page, the location they
- * were redirected from will be stored in the session so that they can be
- * redirected back after a successful login. If this session value is not
- * set, the user will be redirected to the page specified in $loginRedirect.
- *
- * @var mixed
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#AuthComponent::$loginRedirect
- */
- public $loginRedirect = null;
-
-/**
- * The default action to redirect to after the user is logged out. While AuthComponent does
- * not handle post-logout redirection, a redirect URL will be returned from AuthComponent::logout().
- * Defaults to AuthComponent::$loginAction.
- *
- * @var mixed
- * @see AuthComponent::$loginAction
- * @see AuthComponent::logout()
- */
- public $logoutRedirect = null;
-
-/**
- * Error to display when user attempts to access an object or action to which they do not have
- * access.
- *
- * @var string
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#AuthComponent::$authError
- */
- public $authError = null;
-
-/**
- * Controller actions for which user validation is not required.
- *
- * @var array
- * @see AuthComponent::allow()
- */
- public $allowedActions = array();
-
-/**
- * Request object
- *
- * @var CakeRequest
- */
- public $request;
-
-/**
- * Response object
- *
- * @var CakeResponse
- */
- public $response;
-
-/**
- * Method list for bound controller
- *
- * @var array
- */
- protected $_methods = array();
-
-/**
- * Initializes AuthComponent for use in the controller
- *
- * @param Controller $controller A reference to the instantiating controller object
- * @return void
- */
- public function initialize(Controller $controller) {
- $this->request = $controller->request;
- $this->response = $controller->response;
- $this->_methods = $controller->methods;
-
- if (Configure::read('debug') > 0) {
- Debugger::checkSecurityKeys();
- }
- }
-
-/**
- * Main execution method. Handles redirecting of invalid users, and processing
- * of login form data.
- *
- * @param Controller $controller A reference to the instantiating controller object
- * @return boolean
- */
- public function startup(Controller $controller) {
- if ($controller->name == 'CakeError') {
- return true;
- }
-
- $methods = array_flip(array_map('strtolower', $controller->methods));
- $action = strtolower($controller->request->params['action']);
-
- $isMissingAction = (
- $controller->scaffold === false &&
- !isset($methods[$action])
- );
-
- if ($isMissingAction) {
- return true;
- }
-
- if (!$this->_setDefaults()) {
- return false;
- }
- $request = $controller->request;
-
- $url = '';
-
- if (isset($request->url)) {
- $url = $request->url;
- }
- $url = Router::normalize($url);
- $loginAction = Router::normalize($this->loginAction);
-
- $allowedActions = $this->allowedActions;
- $isAllowed = (
- $this->allowedActions == array('*') ||
- in_array($action, array_map('strtolower', $allowedActions))
- );
-
- if ($loginAction != $url && $isAllowed) {
- return true;
- }
-
- if ($loginAction == $url) {
- if (empty($request->data)) {
- if (!$this->Session->check('Auth.redirect') && !$this->loginRedirect && env('HTTP_REFERER')) {
- $this->Session->write('Auth.redirect', $controller->referer(null, true));
- }
- }
- return true;
- } else {
- if (!$this->_getUser()) {
- if (!$request->is('ajax')) {
- $this->flash($this->authError);
- $this->Session->write('Auth.redirect', $request->here());
- $controller->redirect($loginAction);
- return false;
- } elseif (!empty($this->ajaxLogin)) {
- $controller->viewPath = 'Elements';
- echo $controller->render($this->ajaxLogin, $this->RequestHandler->ajaxLayout);
- $this->_stop();
- return false;
- } else {
- $controller->redirect(null, 403);
- }
- }
- }
- if (empty($this->authorize) || $this->isAuthorized($this->user())) {
- return true;
- }
-
- $this->flash($this->authError);
- $controller->redirect($controller->referer('/'), null, true);
- return false;
- }
-
-/**
- * Attempts to introspect the correct values for object properties.
- *
- * @return boolean
- */
- protected function _setDefaults() {
- $defaults = array(
- 'logoutRedirect' => $this->loginAction,
- 'authError' => __d('cake', 'You are not authorized to access that location.')
- );
- foreach ($defaults as $key => $value) {
- if (empty($this->{$key})) {
- $this->{$key} = $value;
- }
- }
- return true;
- }
-
-/**
- * Uses the configured Authorization adapters to check whether or not a user is authorized.
- * Each adapter will be checked in sequence, if any of them return true, then the user will
- * be authorized for the request.
- *
- * @param mixed $user The user to check the authorization of. If empty the user in the session will be used.
- * @param CakeRequest $request The request to authenticate for. If empty, the current request will be used.
- * @return boolean True if $user is authorized, otherwise false
- */
- public function isAuthorized($user = null, $request = null) {
- if (empty($user) && !$this->user()) {
- return false;
- } elseif (empty($user)) {
- $user = $this->user();
- }
- if (empty($request)) {
- $request = $this->request;
- }
- if (empty($this->_authorizeObjects)) {
- $this->constructAuthorize();
- }
- foreach ($this->_authorizeObjects as $authorizer) {
- if ($authorizer->authorize($user, $request) === true) {
- return true;
- }
- }
- return false;
- }
-
-/**
- * Loads the authorization objects configured.
- *
- * @return mixed Either null when authorize is empty, or the loaded authorization objects.
- * @throws CakeException
- */
- public function constructAuthorize() {
- if (empty($this->authorize)) {
- return;
- }
- $this->_authorizeObjects = array();
- $config = Set::normalize($this->authorize);
- $global = array();
- if (isset($config[AuthComponent::ALL])) {
- $global = $config[AuthComponent::ALL];
- unset($config[AuthComponent::ALL]);
- }
- foreach ($config as $class => $settings) {
- list($plugin, $class) = pluginSplit($class, true);
- $className = $class . 'Authorize';
- App::uses($className, $plugin . 'Controller/Component/Auth');
- if (!class_exists($className)) {
- throw new CakeException(__d('cake_dev', 'Authorization adapter "%s" was not found.', $class));
- }
- if (!method_exists($className, 'authorize')) {
- throw new CakeException(__d('cake_dev', 'Authorization objects must implement an authorize method.'));
- }
- $settings = array_merge($global, (array)$settings);
- $this->_authorizeObjects[] = new $className($this->_Collection, $settings);
- }
- return $this->_authorizeObjects;
- }
-
-/**
- * Takes a list of actions in the current controller for which authentication is not required, or
- * no parameters to allow all actions.
- *
- * You can use allow with either an array, or var args.
- *
- * `$this->Auth->allow(array('edit', 'add'));` or
- * `$this->Auth->allow('edit', 'add');` or
- * `$this->Auth->allow();` to allow all actions
- *
- * @param mixed $action,... Controller action name or array of actions
- * @return void
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#making-actions-public
- */
- public function allow($action = null) {
- $args = func_get_args();
- if (empty($args) || $action === null) {
- $this->allowedActions = $this->_methods;
- } else {
- if (isset($args[0]) && is_array($args[0])) {
- $args = $args[0];
- }
- $this->allowedActions = array_merge($this->allowedActions, $args);
- }
- }
-
-/**
- * Removes items from the list of allowed/no authentication required actions.
- *
- * You can use deny with either an array, or var args.
- *
- * `$this->Auth->deny(array('edit', 'add'));` or
- * `$this->Auth->deny('edit', 'add');` or
- * `$this->Auth->deny();` to remove all items from the allowed list
- *
- * @param mixed $action,... Controller action name or array of actions
- * @return void
- * @see AuthComponent::allow()
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#making-actions-require-authorization
- */
- public function deny($action = null) {
- $args = func_get_args();
- if (empty($args) || $action === null) {
- $this->allowedActions = array();
- } else {
- if (isset($args[0]) && is_array($args[0])) {
- $args = $args[0];
- }
- foreach ($args as $arg) {
- $i = array_search($arg, $this->allowedActions);
- if (is_int($i)) {
- unset($this->allowedActions[$i]);
- }
- }
- $this->allowedActions = array_values($this->allowedActions);
- }
- }
-
-/**
- * Maps action names to CRUD operations. Used for controller-based authentication. Make sure
- * to configure the authorize property before calling this method. As it delegates $map to all the
- * attached authorize objects.
- *
- * @param array $map Actions to map
- * @return void
- * @see BaseAuthorize::mapActions()
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#mapping-actions-when-using-crudauthorize
- */
- public function mapActions($map = array()) {
- if (empty($this->_authorizeObjects)) {
- $this->constructAuthorize();
- }
- foreach ($this->_authorizeObjects as $auth) {
- $auth->mapActions($map);
- }
- }
-
-/**
- * Log a user in. If a $user is provided that data will be stored as the logged in user. If `$user` is empty or not
- * specified, the request will be used to identify a user. If the identification was successful,
- * the user record is written to the session key specified in AuthComponent::$sessionKey. Logging in
- * will also change the session id in order to help mitigate session replays.
- *
- * @param mixed $user Either an array of user data, or null to identify a user using the current request.
- * @return boolean True on login success, false on failure
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#identifying-users-and-logging-them-in
- */
- public function login($user = null) {
- $this->_setDefaults();
-
- if (empty($user)) {
- $user = $this->identify($this->request, $this->response);
- }
- if ($user) {
- $this->Session->renew();
- $this->Session->write(self::$sessionKey, $user);
- }
- return $this->loggedIn();
- }
-
-/**
- * Logs a user out, and returns the login action to redirect to.
- * Triggers the logout() method of all the authenticate objects, so they can perform
- * custom logout logic. AuthComponent will remove the session data, so
- * there is no need to do that in an authentication object. Logging out
- * will also renew the session id. This helps mitigate issues with session replays.
- *
- * @return string AuthComponent::$logoutRedirect
- * @see AuthComponent::$logoutRedirect
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#logging-users-out
- */
- public function logout() {
- $this->_setDefaults();
- if (empty($this->_authenticateObjects)) {
- $this->constructAuthenticate();
- }
- $user = $this->user();
- foreach ($this->_authenticateObjects as $auth) {
- $auth->logout($user);
- }
- $this->Session->delete(self::$sessionKey);
- $this->Session->delete('Auth.redirect');
- $this->Session->renew();
- return Router::normalize($this->logoutRedirect);
- }
-
-/**
- * Get the current user.
- *
- * Will prefer the static user cache over sessions. The static user
- * cache is primarily used for stateless authentication. For stateful authentication,
- * cookies + sessions will be used.
- *
- * @param string $key field to retrieve. Leave null to get entire User record
- * @return mixed User record. or null if no user is logged in.
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#accessing-the-logged-in-user
- */
- public static function user($key = null) {
- if (empty(self::$_user) && !CakeSession::check(self::$sessionKey)) {
- return null;
- }
- if (!empty(self::$_user)) {
- $user = self::$_user;
- } else {
- $user = CakeSession::read(self::$sessionKey);
- }
- if ($key === null) {
- return $user;
- }
- if (isset($user[$key])) {
- return $user[$key];
- }
- return null;
- }
-
-/**
- * Similar to AuthComponent::user() except if the session user cannot be found, connected authentication
- * objects will have their getUser() methods called. This lets stateless authentication methods function correctly.
- *
- * @return boolean true if a user can be found, false if one cannot.
- */
- protected function _getUser() {
- $user = $this->user();
- if ($user) {
- return true;
- }
- if (empty($this->_authenticateObjects)) {
- $this->constructAuthenticate();
- }
- foreach ($this->_authenticateObjects as $auth) {
- $result = $auth->getUser($this->request);
- if (!empty($result) && is_array($result)) {
- self::$_user = $result;
- return true;
- }
- }
- return false;
- }
-
-/**
- * If no parameter is passed, gets the authentication redirect URL. Pass a url in to
- * set the destination a user should be redirected to upon logging in. Will fallback to
- * AuthComponent::$loginRedirect if there is no stored redirect value.
- *
- * @param mixed $url Optional URL to write as the login redirect URL.
- * @return string Redirect URL
- */
- public function redirect($url = null) {
- if (!is_null($url)) {
- $redir = $url;
- $this->Session->write('Auth.redirect', $redir);
- } elseif ($this->Session->check('Auth.redirect')) {
- $redir = $this->Session->read('Auth.redirect');
- $this->Session->delete('Auth.redirect');
-
- if (Router::normalize($redir) == Router::normalize($this->loginAction)) {
- $redir = $this->loginRedirect;
- }
- } else {
- $redir = $this->loginRedirect;
- }
- return Router::normalize($redir);
- }
-
-/**
- * Use the configured authentication adapters, and attempt to identify the user
- * by credentials contained in $request.
- *
- * @param CakeRequest $request The request that contains authentication data.
- * @param CakeResponse $response The response
- * @return array User record data, or false, if the user could not be identified.
- */
- public function identify(CakeRequest $request, CakeResponse $response) {
- if (empty($this->_authenticateObjects)) {
- $this->constructAuthenticate();
- }
- foreach ($this->_authenticateObjects as $auth) {
- $result = $auth->authenticate($request, $response);
- if (!empty($result) && is_array($result)) {
- return $result;
- }
- }
- return false;
- }
-
-/**
- * loads the configured authentication objects.
- *
- * @return mixed either null on empty authenticate value, or an array of loaded objects.
- * @throws CakeException
- */
- public function constructAuthenticate() {
- if (empty($this->authenticate)) {
- return;
- }
- $this->_authenticateObjects = array();
- $config = Set::normalize($this->authenticate);
- $global = array();
- if (isset($config[AuthComponent::ALL])) {
- $global = $config[AuthComponent::ALL];
- unset($config[AuthComponent::ALL]);
- }
- foreach ($config as $class => $settings) {
- list($plugin, $class) = pluginSplit($class, true);
- $className = $class . 'Authenticate';
- App::uses($className, $plugin . 'Controller/Component/Auth');
- if (!class_exists($className)) {
- throw new CakeException(__d('cake_dev', 'Authentication adapter "%s" was not found.', $class));
- }
- if (!method_exists($className, 'authenticate')) {
- throw new CakeException(__d('cake_dev', 'Authentication objects must implement an authenticate method.'));
- }
- $settings = array_merge($global, (array)$settings);
- $this->_authenticateObjects[] = new $className($this->_Collection, $settings);
- }
- return $this->_authenticateObjects;
- }
-
-/**
- * Hash a password with the application's salt value (as defined with Configure::write('Security.salt');
- *
- * This method is intended as a convenience wrapper for Security::hash(). If you want to use
- * a hashing/encryption system not supported by that method, do not use this method.
- *
- * @param string $password Password to hash
- * @return string Hashed password
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#hashing-passwords
- */
- public static function password($password) {
- return Security::hash($password, null, true);
- }
-
-/**
- * Component shutdown. If user is logged in, wipe out redirect.
- *
- * @param Controller $controller Instantiating controller
- * @return void
- */
- public function shutdown(Controller $controller) {
- if ($this->loggedIn()) {
- $this->Session->delete('Auth.redirect');
- }
- }
-
-/**
- * Check whether or not the current user has data in the session, and is considered logged in.
- *
- * @return boolean true if the user is logged in, false otherwise
- */
- public function loggedIn() {
- return $this->user() != array();
- }
-
-/**
- * Set a flash message. Uses the Session component, and values from AuthComponent::$flash.
- *
- * @param string $message The message to set.
- * @return void
- */
- public function flash($message) {
- $this->Session->setFlash($message, $this->flash['element'], $this->flash['params'], $this->flash['key']);
- }
-
-}
diff --git a/lib/Cake/Controller/Component/CookieComponent.php b/lib/Cake/Controller/Component/CookieComponent.php
deleted file mode 100644
index 31d2778f6e7..00000000000
--- a/lib/Cake/Controller/Component/CookieComponent.php
+++ /dev/null
@@ -1,514 +0,0 @@
-Cookie->name = 'CookieName';
- *
- * @var string
- */
- public $name = 'CakeCookie';
-
-/**
- * The time a cookie will remain valid.
- *
- * Can be either integer Unix timestamp or a date string.
- *
- * Overridden with the controller beforeFilter();
- * $this->Cookie->time = '5 Days';
- *
- * @var mixed
- */
- public $time = null;
-
-/**
- * Cookie path.
- *
- * Overridden with the controller beforeFilter();
- * $this->Cookie->path = '/';
- *
- * The path on the server in which the cookie will be available on.
- * If public $cookiePath is set to '/foo/', the cookie will only be available
- * within the /foo/ directory and all sub-directories such as /foo/bar/ of domain.
- * The default value is the entire domain.
- *
- * @var string
- */
- public $path = '/';
-
-/**
- * Domain path.
- *
- * The domain that the cookie is available.
- *
- * Overridden with the controller beforeFilter();
- * $this->Cookie->domain = '.example.com';
- *
- * To make the cookie available on all subdomains of example.com.
- * Set $this->Cookie->domain = '.example.com'; in your controller beforeFilter
- *
- * @var string
- */
- public $domain = '';
-
-/**
- * Secure HTTPS only cookie.
- *
- * Overridden with the controller beforeFilter();
- * $this->Cookie->secure = true;
- *
- * Indicates that the cookie should only be transmitted over a secure HTTPS connection.
- * When set to true, the cookie will only be set if a secure connection exists.
- *
- * @var boolean
- */
- public $secure = false;
-
-/**
- * Encryption key.
- *
- * Overridden with the controller beforeFilter();
- * $this->Cookie->key = 'SomeRandomString';
- *
- * @var string
- */
- public $key = null;
-
-/**
- * HTTP only cookie
- *
- * Set to true to make HTTP only cookies. Cookies that are HTTP only
- * are not accessible in Javascript.
- *
- * @var boolean
- */
- public $httpOnly = false;
-
-/**
- * Values stored in the cookie.
- *
- * Accessed in the controller using $this->Cookie->read('Name.key');
- *
- * @see CookieComponent::read();
- * @var string
- */
- protected $_values = array();
-
-/**
- * Type of encryption to use.
- *
- * Currently only one method is available
- * Defaults to Security::cipher();
- *
- * @var string
- * @todo add additional encryption methods
- */
- protected $_type = 'cipher';
-
-/**
- * Used to reset cookie time if $expire is passed to CookieComponent::write()
- *
- * @var string
- */
- protected $_reset = null;
-
-/**
- * Expire time of the cookie
- *
- * This is controlled by CookieComponent::time;
- *
- * @var string
- */
- protected $_expires = 0;
-
-/**
- * A reference to the Controller's CakeResponse object
- *
- * @var CakeResponse
- */
- protected $_response = null;
-
-/**
- * Constructor
- *
- * @param ComponentCollection $collection A ComponentCollection for this component
- * @param array $settings Array of settings.
- */
- public function __construct(ComponentCollection $collection, $settings = array()) {
- $this->key = Configure::read('Security.salt');
- parent::__construct($collection, $settings);
- if (isset($this->time)) {
- $this->_expire($this->time);
- }
-
- $controller = $collection->getController();
- if ($controller && isset($controller->response)) {
- $this->_response = $controller->response;
- } else {
- $this->_response = new CakeResponse(array('charset' => Configure::read('App.encoding')));
- }
- }
-
-/**
- * Start CookieComponent for use in the controller
- *
- * @param Controller $controller
- * @return void
- */
- public function startup(Controller $controller) {
- $this->_expire($this->time);
-
- $this->_values[$this->name] = array();
- if (isset($_COOKIE[$this->name])) {
- $this->_values[$this->name] = $this->_decrypt($_COOKIE[$this->name]);
- }
- }
-
-/**
- * Write a value to the $_COOKIE[$key];
- *
- * Optional [Name.], required key, optional $value, optional $encrypt, optional $expires
- * $this->Cookie->write('[Name.]key, $value);
- *
- * By default all values are encrypted.
- * You must pass $encrypt false to store values in clear test
- *
- * You must use this method before any output is sent to the browser.
- * Failure to do so will result in header already sent errors.
- *
- * @param mixed $key Key for the value
- * @param mixed $value Value
- * @param boolean $encrypt Set to true to encrypt value, false otherwise
- * @param string $expires Can be either Unix timestamp, or date string
- * @return void
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html#CookieComponent::write
- */
- public function write($key, $value = null, $encrypt = true, $expires = null) {
- if (empty($this->_values[$this->name])) {
- $this->read();
- }
-
- if (is_null($encrypt)) {
- $encrypt = true;
- }
- $this->_encrypted = $encrypt;
- $this->_expire($expires);
-
- if (!is_array($key)) {
- $key = array($key => $value);
- }
-
- foreach ($key as $name => $value) {
- if (strpos($name, '.') === false) {
- $this->_values[$this->name][$name] = $value;
- $this->_write("[$name]", $value);
- } else {
- $names = explode('.', $name, 2);
- if (!isset($this->_values[$this->name][$names[0]])) {
- $this->_values[$this->name][$names[0]] = array();
- }
- $this->_values[$this->name][$names[0]] = Set::insert($this->_values[$this->name][$names[0]], $names[1], $value);
- $this->_write('[' . implode('][', $names) . ']', $value);
- }
- }
- $this->_encrypted = true;
- }
-
-/**
- * Read the value of the $_COOKIE[$key];
- *
- * Optional [Name.], required key
- * $this->Cookie->read(Name.key);
- *
- * @param mixed $key Key of the value to be obtained. If none specified, obtain map key => values
- * @return string or null, value for specified key
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html#CookieComponent::read
- */
- public function read($key = null) {
- if (empty($this->_values[$this->name]) && isset($_COOKIE[$this->name])) {
- $this->_values[$this->name] = $this->_decrypt($_COOKIE[$this->name]);
- }
- if (empty($this->_values[$this->name])) {
- $this->_values[$this->name] = array();
- }
- if (is_null($key)) {
- return $this->_values[$this->name];
- }
-
- if (strpos($key, '.') !== false) {
- $names = explode('.', $key, 2);
- $key = $names[0];
- }
- if (!isset($this->_values[$this->name][$key])) {
- return null;
- }
-
- if (!empty($names[1])) {
- return Set::extract($this->_values[$this->name][$key], $names[1]);
- }
- return $this->_values[$this->name][$key];
- }
-
-/**
- * Delete a cookie value
- *
- * Optional [Name.], required key
- * $this->Cookie->read('Name.key);
- *
- * You must use this method before any output is sent to the browser.
- * Failure to do so will result in header already sent errors.
- *
- * @param string $key Key of the value to be deleted
- * @return void
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html#CookieComponent::delete
- */
- public function delete($key) {
- if (empty($this->_values[$this->name])) {
- $this->read();
- }
- if (strpos($key, '.') === false) {
- if (isset($this->_values[$this->name][$key]) && is_array($this->_values[$this->name][$key])) {
- foreach ($this->_values[$this->name][$key] as $idx => $val) {
- $this->_delete("[$key][$idx]");
- }
- }
- $this->_delete("[$key]");
- unset($this->_values[$this->name][$key]);
- return;
- }
- $names = explode('.', $key, 2);
- if (isset($this->_values[$this->name][$names[0]])) {
- $this->_values[$this->name][$names[0]] = Set::remove($this->_values[$this->name][$names[0]], $names[1]);
- }
- $this->_delete('[' . implode('][', $names) . ']');
- }
-
-/**
- * Destroy current cookie
- *
- * You must use this method before any output is sent to the browser.
- * Failure to do so will result in header already sent errors.
- *
- * @return void
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html#CookieComponent::destroy
- */
- public function destroy() {
- if (isset($_COOKIE[$this->name])) {
- $this->_values[$this->name] = $this->_decrypt($_COOKIE[$this->name]);
- }
-
- foreach ($this->_values[$this->name] as $name => $value) {
- if (is_array($value)) {
- foreach ($value as $key => $val) {
- unset($this->_values[$this->name][$name][$key]);
- $this->_delete("[$name][$key]");
- }
- }
- unset($this->_values[$this->name][$name]);
- $this->_delete("[$name]");
- }
- }
-
-/**
- * Will allow overriding default encryption method.
- *
- * @param string $type Encryption method
- * @return void
- * @todo NOT IMPLEMENTED
- */
- public function type($type = 'cipher') {
- $this->_type = 'cipher';
- }
-
-/**
- * Set the expire time for a session variable.
- *
- * Creates a new expire time for a session variable.
- * $expire can be either integer Unix timestamp or a date string.
- *
- * Used by write()
- * CookieComponent::write(string, string, boolean, 8400);
- * CookieComponent::write(string, string, boolean, '5 Days');
- *
- * @param mixed $expires Can be either Unix timestamp, or date string
- * @return integer Unix timestamp
- */
- protected function _expire($expires = null) {
- $now = time();
- if (is_null($expires)) {
- return $this->_expires;
- }
- $this->_reset = $this->_expires;
-
- if ($expires == 0) {
- return $this->_expires = 0;
- }
-
- if (is_integer($expires) || is_numeric($expires)) {
- return $this->_expires = $now + intval($expires);
- }
- return $this->_expires = strtotime($expires, $now);
- }
-
-/**
- * Set cookie
- *
- * @param string $name Name for cookie
- * @param string $value Value for cookie
- * @return void
- */
- protected function _write($name, $value) {
- $this->_response->cookie(array(
- 'name' => $this->name . $name,
- 'value' => $this->_encrypt($value),
- 'expire' => $this->_expires,
- 'path' => $this->path,
- 'domain' => $this->domain,
- 'secure' => $this->secure,
- 'httpOnly' => $this->httpOnly
- ));
-
- if (!is_null($this->_reset)) {
- $this->_expires = $this->_reset;
- $this->_reset = null;
- }
- }
-
-/**
- * Sets a cookie expire time to remove cookie value
- *
- * @param string $name Name of cookie
- * @return void
- */
- protected function _delete($name) {
- $this->_response->cookie(array(
- 'name' => $this->name . $name,
- 'value' => '',
- 'expire' => time() - 42000,
- 'path' => $this->path,
- 'domain' => $this->domain,
- 'secure' => $this->secure,
- 'httpOnly' => $this->httpOnly
- ));
- }
-
-/**
- * Encrypts $value using public $type method in Security class
- *
- * @param string $value Value to encrypt
- * @return string encrypted string
- * @return string Encoded values
- */
- protected function _encrypt($value) {
- if (is_array($value)) {
- $value = $this->_implode($value);
- }
-
- if ($this->_encrypted === true) {
- $type = $this->_type;
- $value = "Q2FrZQ==." . base64_encode(Security::$type($value, $this->key));
- }
- return $value;
- }
-
-/**
- * Decrypts $value using public $type method in Security class
- *
- * @param array $values Values to decrypt
- * @return string decrypted string
- */
- protected function _decrypt($values) {
- $decrypted = array();
- $type = $this->_type;
-
- foreach ((array)$values as $name => $value) {
- if (is_array($value)) {
- foreach ($value as $key => $val) {
- $pos = strpos($val, 'Q2FrZQ==.');
- $decrypted[$name][$key] = $this->_explode($val);
-
- if ($pos !== false) {
- $val = substr($val, 8);
- $decrypted[$name][$key] = $this->_explode(Security::$type(base64_decode($val), $this->key));
- }
- }
- } else {
- $pos = strpos($value, 'Q2FrZQ==.');
- $decrypted[$name] = $this->_explode($value);
-
- if ($pos !== false) {
- $value = substr($value, 8);
- $decrypted[$name] = $this->_explode(Security::$type(base64_decode($value), $this->key));
- }
- }
- }
- return $decrypted;
- }
-
-/**
- * Implode method to keep keys are multidimensional arrays
- *
- * @param array $array Map of key and values
- * @return string A json encoded string.
- */
- protected function _implode(array $array) {
- return json_encode($array);
- }
-
-/**
- * Explode method to return array from string set in CookieComponent::_implode()
- * Maintains reading backwards compatibility with 1.x CookieComponent::_implode().
- *
- * @param string $string A string containing JSON encoded data, or a bare string.
- * @return array Map of key and values
- */
- protected function _explode($string) {
- $first = substr($string, 0, 1);
- if ($first === '{' || $first === '[') {
- $ret = json_decode($string, true);
- return ($ret != null) ? $ret : $string;
- }
- $array = array();
- foreach (explode(',', $string) as $pair) {
- $key = explode('|', $pair);
- if (!isset($key[1])) {
- return $key[0];
- }
- $array[$key[0]] = $key[1];
- }
- return $array;
- }
-}
-
diff --git a/lib/Cake/Controller/Component/EmailComponent.php b/lib/Cake/Controller/Component/EmailComponent.php
deleted file mode 100644
index 5b2dd1d9f33..00000000000
--- a/lib/Cake/Controller/Component/EmailComponent.php
+++ /dev/null
@@ -1,489 +0,0 @@
-_controller = $collection->getController();
- parent::__construct($collection, $settings);
- }
-
-/**
- * Initialize component
- *
- * @param Controller $controller Instantiating controller
- * @return void
- */
- public function initialize(Controller $controller) {
- if (Configure::read('App.encoding') !== null) {
- $this->charset = Configure::read('App.encoding');
- }
- }
-
-/**
- * Send an email using the specified content, template and layout
- *
- * @param mixed $content Either an array of text lines, or a string with contents
- * If you are rendering a template this variable will be sent to the templates as `$content`
- * @param string $template Template to use when sending email
- * @param string $layout Layout to use to enclose email body
- * @return boolean Success
- */
- public function send($content = null, $template = null, $layout = null) {
- $lib = new CakeEmail();
- $lib->charset = $this->charset;
-
- $lib->from($this->_formatAddresses((array)$this->from));
- if (!empty($this->to)) {
- $lib->to($this->_formatAddresses((array)$this->to));
- }
- if (!empty($this->cc)) {
- $lib->cc($this->_formatAddresses((array)$this->cc));
- }
- if (!empty($this->bcc)) {
- $lib->bcc($this->_formatAddresses((array)$this->bcc));
- }
- if (!empty($this->replyTo)) {
- $lib->replyTo($this->_formatAddresses((array)$this->replyTo));
- }
- if (!empty($this->return)) {
- $lib->returnPath($this->_formatAddresses((array)$this->return));
- }
- if (!empty($readReceipt)) {
- $lib->readReceipt($this->_formatAddresses((array)$this->readReceipt));
- }
-
- $lib->subject($this->subject)->messageID($this->messageId);
- $lib->helpers($this->_controller->helpers);
-
- $headers = array('X-Mailer' => $this->xMailer);
- foreach ($this->headers as $key => $value) {
- $headers['X-' . $key] = $value;
- }
- if ($this->date != false) {
- $headers['Date'] = $this->date;
- }
- $lib->setHeaders($headers);
-
- if ($template) {
- $this->template = $template;
- }
- if ($layout) {
- $this->layout = $layout;
- }
- $lib->template($this->template, $this->layout)->viewVars($this->_controller->viewVars)->emailFormat($this->sendAs);
-
- if (!empty($this->attachments)) {
- $lib->attachments($this->_formatAttachFiles());
- }
-
- $lib->transport(ucfirst($this->delivery));
- if ($this->delivery === 'mail') {
- $lib->config(array('eol' => $this->lineFeed, 'additionalParameters' => $this->additionalParams));
- } elseif ($this->delivery === 'smtp') {
- $lib->config($this->smtpOptions);
- } else {
- $lib->config(array());
- }
-
- $sent = $lib->send($content);
-
- $this->htmlMessage = $lib->message(CakeEmail::MESSAGE_HTML);
- if (empty($this->htmlMessage)) {
- $this->htmlMessage = null;
- }
- $this->textMessage = $lib->message(CakeEmail::MESSAGE_TEXT);
- if (empty($this->textMessage)) {
- $this->textMessage = null;
- }
-
- $this->_header = array();
- $this->_message = array();
-
- return $sent;
- }
-
-/**
- * Reset all EmailComponent internal variables to be able to send out a new email.
- *
- * @return void
- */
- public function reset() {
- $this->template = null;
- $this->to = array();
- $this->from = null;
- $this->replyTo = null;
- $this->return = null;
- $this->cc = array();
- $this->bcc = array();
- $this->subject = null;
- $this->additionalParams = null;
- $this->date = null;
- $this->attachments = array();
- $this->htmlMessage = null;
- $this->textMessage = null;
- $this->messageId = true;
- $this->delivery = 'mail';
- }
-
-/**
- * Format the attach array
- *
- * @return array
- */
- protected function _formatAttachFiles() {
- $files = array();
- foreach ($this->attachments as $filename => $attachment) {
- $file = $this->_findFiles($attachment);
- if (!empty($file)) {
- if (is_int($filename)) {
- $filename = basename($file);
- }
- $files[$filename] = $file;
- }
- }
- return $files;
- }
-
-/**
- * Find the specified attachment in the list of file paths
- *
- * @param string $attachment Attachment file name to find
- * @return string Path to located file
- */
- protected function _findFiles($attachment) {
- if (file_exists($attachment)) {
- return $attachment;
- }
- foreach ($this->filePaths as $path) {
- if (file_exists($path . DS . $attachment)) {
- $file = $path . DS . $attachment;
- return $file;
- }
- }
- return null;
- }
-
-/**
- * Encode the specified string using the current charset
- *
- * @param string $subject String to encode
- * @return string Encoded string
- */
- protected function _encode($subject) {
- $subject = $this->_strip($subject);
-
- $nl = "\r\n";
- if ($this->delivery == 'mail') {
- $nl = '';
- }
- $internalEncoding = function_exists('mb_internal_encoding');
- if ($internalEncoding) {
- $restore = mb_internal_encoding();
- mb_internal_encoding($this->charset);
- }
- $return = mb_encode_mimeheader($subject, $this->charset, 'B', $nl);
- if ($internalEncoding) {
- mb_internal_encoding($restore);
- }
- return $return;
- }
-
-/**
- * Format addresses to be an array with email as key and alias as value
- *
- * @param array $addresses
- * @return array
- */
- protected function _formatAddresses($addresses) {
- $formatted = array();
- foreach ($addresses as $address) {
- if (preg_match('/((.*))?\s?<(.+)>/', $address, $matches) && !empty($matches[2])) {
- $formatted[$this->_strip($matches[3])] = $this->_encode($matches[2]);
- } else {
- $address = $this->_strip($address);
- $formatted[$address] = $address;
- }
- }
- return $formatted;
- }
-
-/**
- * Remove certain elements (such as bcc:, to:, %0a) from given value.
- * Helps prevent header injection / manipulation on user content.
- *
- * @param string $value Value to strip
- * @param boolean $message Set to true to indicate main message content
- * @return string Stripped value
- */
- protected function _strip($value, $message = false) {
- $search = '%0a|%0d|Content-(?:Type|Transfer-Encoding)\:';
- $search .= '|charset\=|mime-version\:|multipart/mixed|(?:[^a-z]to|b?cc)\:.*';
-
- if ($message !== true) {
- $search .= '|\r|\n';
- }
- $search = '#(?:' . $search . ')#i';
- while (preg_match($search, $value)) {
- $value = preg_replace($search, '', $value);
- }
- return $value;
- }
-
-}
diff --git a/lib/Cake/Controller/Component/PaginatorComponent.php b/lib/Cake/Controller/Component/PaginatorComponent.php
deleted file mode 100644
index 9758e66ebf7..00000000000
--- a/lib/Cake/Controller/Component/PaginatorComponent.php
+++ /dev/null
@@ -1,381 +0,0 @@
-Paginator->settings = array(
- * 'limit' => 20,
- * 'maxLimit' => 100
- * );
- * }}}
- *
- * The above settings will be used to paginate any model. You can configure model specific settings by
- * keying the settings with the model name.
- *
- * {{{
- * $this->Paginator->settings = array(
- * 'Post' => array(
- * 'limit' => 20,
- * 'maxLimit' => 100
- * ),
- * 'Comment' => array( ... )
- * );
- * }}}
- *
- * This would allow you to have different pagination settings for `Comment` and `Post` models.
- *
- * @package Cake.Controller.Component
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/pagination.html
- */
-class PaginatorComponent extends Component {
-
-/**
- * Pagination settings. These settings control pagination at a general level.
- * You can also define sub arrays for pagination settings for specific models.
- *
- * - `maxLimit` The maximum limit users can choose to view. Defaults to 100
- * - `limit` The initial number of items per page. Defaults to 20.
- * - `page` The starting page, defaults to 1.
- * - `paramType` What type of parameters you want pagination to use?
- * - `named` Use named parameters / routed parameters.
- * - `querystring` Use query string parameters.
- *
- * @var array
- */
- public $settings = array(
- 'page' => 1,
- 'limit' => 20,
- 'maxLimit' => 100,
- 'paramType' => 'named'
- );
-
-/**
- * A list of parameters users are allowed to set using request parameters. Modifying
- * this list will allow users to have more influence over pagination,
- * be careful with what you permit.
- *
- * @var array
- */
- public $whitelist = array(
- 'limit', 'sort', 'page', 'direction'
- );
-
-/**
- * Constructor
- *
- * @param ComponentCollection $collection A ComponentCollection this component can use to lazy load its components
- * @param array $settings Array of configuration settings.
- */
- public function __construct(ComponentCollection $collection, $settings = array()) {
- $settings = array_merge($this->settings, (array)$settings);
- $this->Controller = $collection->getController();
- parent::__construct($collection, $settings);
- }
-
-/**
- * Handles automatic pagination of model records.
- *
- * @param mixed $object Model to paginate (e.g: model instance, or 'Model', or 'Model.InnerModel')
- * @param mixed $scope Additional find conditions to use while paginating
- * @param array $whitelist List of allowed fields for ordering. This allows you to prevent ordering
- * on non-indexed, or undesirable columns.
- * @return array Model query results
- * @throws MissingModelException
- */
- public function paginate($object = null, $scope = array(), $whitelist = array()) {
- if (is_array($object)) {
- $whitelist = $scope;
- $scope = $object;
- $object = null;
- }
-
- $object = $this->_getObject($object);
-
- if (!is_object($object)) {
- throw new MissingModelException($object);
- }
-
- $options = $this->mergeOptions($object->alias);
- $options = $this->validateSort($object, $options, $whitelist);
- $options = $this->checkLimit($options);
-
- $conditions = $fields = $order = $limit = $page = $recursive = null;
-
- if (!isset($options['conditions'])) {
- $options['conditions'] = array();
- }
-
- $type = 'all';
-
- if (isset($options[0])) {
- $type = $options[0];
- unset($options[0]);
- }
-
- extract($options);
-
- if (is_array($scope) && !empty($scope)) {
- $conditions = array_merge($conditions, $scope);
- } elseif (is_string($scope)) {
- $conditions = array($conditions, $scope);
- }
- if ($recursive === null) {
- $recursive = $object->recursive;
- }
-
- $extra = array_diff_key($options, compact(
- 'conditions', 'fields', 'order', 'limit', 'page', 'recursive'
- ));
- if ($type !== 'all') {
- $extra['type'] = $type;
- }
-
- if (intval($page) < 1) {
- $page = 1;
- }
- $page = $options['page'] = (int)$page;
-
- if ($object->hasMethod('paginate')) {
- $results = $object->paginate(
- $conditions, $fields, $order, $limit, $page, $recursive, $extra
- );
- } else {
- $parameters = compact('conditions', 'fields', 'order', 'limit', 'page');
- if ($recursive != $object->recursive) {
- $parameters['recursive'] = $recursive;
- }
- $results = $object->find($type, array_merge($parameters, $extra));
- }
- $defaults = $this->getDefaults($object->alias);
- unset($defaults[0]);
-
- if ($object->hasMethod('paginateCount')) {
- $count = $object->paginateCount($conditions, $recursive, $extra);
- } else {
- $parameters = compact('conditions');
- if ($recursive != $object->recursive) {
- $parameters['recursive'] = $recursive;
- }
- $count = $object->find('count', array_merge($parameters, $extra));
- }
- $pageCount = intval(ceil($count / $limit));
-
- $paging = array(
- 'page' => $page,
- 'current' => count($results),
- 'count' => $count,
- 'prevPage' => ($page > 1),
- 'nextPage' => ($count > ($page * $limit)),
- 'pageCount' => $pageCount,
- 'order' => $order,
- 'limit' => $limit,
- 'options' => Set::diff($options, $defaults),
- 'paramType' => $options['paramType']
- );
- if (!isset($this->Controller->request['paging'])) {
- $this->Controller->request['paging'] = array();
- }
- $this->Controller->request['paging'] = array_merge(
- (array)$this->Controller->request['paging'],
- array($object->alias => $paging)
- );
-
- if (
- !in_array('Paginator', $this->Controller->helpers) &&
- !array_key_exists('Paginator', $this->Controller->helpers)
- ) {
- $this->Controller->helpers[] = 'Paginator';
- }
- return $results;
- }
-
-/**
- * Get the object pagination will occur on.
- *
- * @param mixed $object The object you are looking for.
- * @return mixed The model object to paginate on.
- */
- protected function _getObject($object) {
- if (is_string($object)) {
- $assoc = null;
- if (strpos($object, '.') !== false) {
- list($object, $assoc) = pluginSplit($object);
- }
-
- if ($assoc && isset($this->Controller->{$object}->{$assoc})) {
- $object = $this->Controller->{$object}->{$assoc};
- } elseif (
- $assoc && isset($this->Controller->{$this->Controller->modelClass}) &&
- isset($this->Controller->{$this->Controller->modelClass}->{$assoc}
- )) {
- $object = $this->Controller->{$this->Controller->modelClass}->{$assoc};
- } elseif (isset($this->Controller->{$object})) {
- $object = $this->Controller->{$object};
- } elseif (
- isset($this->Controller->{$this->Controller->modelClass}) && isset($this->Controller->{$this->Controller->modelClass}->{$object}
- )) {
- $object = $this->Controller->{$this->Controller->modelClass}->{$object};
- }
- } elseif (empty($object) || $object === null) {
- if (isset($this->Controller->{$this->Controller->modelClass})) {
- $object = $this->Controller->{$this->Controller->modelClass};
- } else {
- $className = null;
- $name = $this->Controller->uses[0];
- if (strpos($this->Controller->uses[0], '.') !== false) {
- list($name, $className) = explode('.', $this->Controller->uses[0]);
- }
- if ($className) {
- $object = $this->Controller->{$className};
- } else {
- $object = $this->Controller->{$name};
- }
- }
- }
- return $object;
- }
-
-/**
- * Merges the various options that Pagination uses.
- * Pulls settings together from the following places:
- *
- * - General pagination settings
- * - Model specific settings.
- * - Request parameters
- *
- * The result of this method is the aggregate of all the option sets combined together. You can change
- * PaginatorComponent::$whitelist to modify which options/values can be set using request parameters.
- *
- * @param string $alias Model alias being paginated, if the general settings has a key with this value
- * that key's settings will be used for pagination instead of the general ones.
- * @return array Array of merged options.
- */
- public function mergeOptions($alias) {
- $defaults = $this->getDefaults($alias);
- switch ($defaults['paramType']) {
- case 'named':
- $request = $this->Controller->request->params['named'];
- break;
- case 'querystring':
- $request = $this->Controller->request->query;
- break;
- }
- $request = array_intersect_key($request, array_flip($this->whitelist));
- return array_merge($defaults, $request);
- }
-
-/**
- * Get the default settings for a $model. If there are no settings for a specific model, the general settings
- * will be used.
- *
- * @param string $alias Model name to get default settings for.
- * @return array An array of pagination defaults for a model, or the general settings.
- */
- public function getDefaults($alias) {
- if (isset($this->settings[$alias])) {
- $defaults = $this->settings[$alias];
- } else {
- $defaults = $this->settings;
- }
- return array_merge(
- array('page' => 1, 'limit' => 20, 'maxLimit' => 100, 'paramType' => 'named'),
- $defaults
- );
- }
-
-/**
- * Validate that the desired sorting can be performed on the $object. Only fields or
- * virtualFields can be sorted on. The direction param will also be sanitized. Lastly
- * sort + direction keys will be converted into the model friendly order key.
- *
- * You can use the whitelist parameter to control which columns/fields are available for sorting.
- * This helps prevent users from ordering large result sets on un-indexed values.
- *
- * @param Model $object The model being paginated.
- * @param array $options The pagination options being used for this request.
- * @param array $whitelist The list of columns that can be used for sorting. If empty all keys are allowed.
- * @return array An array of options with sort + direction removed and replaced with order if possible.
- */
- public function validateSort($object, $options, $whitelist = array()) {
- if (isset($options['sort'])) {
- $direction = null;
- if (isset($options['direction'])) {
- $direction = strtolower($options['direction']);
- }
- if ($direction != 'asc' && $direction != 'desc') {
- $direction = 'asc';
- }
- $options['order'] = array($options['sort'] => $direction);
- }
-
- if (!empty($whitelist) && isset($options['order']) && is_array($options['order'])) {
- $field = key($options['order']);
- if (!in_array($field, $whitelist)) {
- $options['order'] = null;
- }
- }
-
- if (!empty($options['order']) && is_array($options['order'])) {
- $order = array();
- foreach ($options['order'] as $key => $value) {
- $field = $key;
- $alias = $object->alias;
- if (strpos($key, '.') !== false) {
- list($alias, $field) = explode('.', $key);
- }
-
- if ($object->hasField($field)) {
- $order[$alias . '.' . $field] = $value;
- } elseif ($object->hasField($key, true)) {
- $order[$field] = $value;
- } elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field, true)) {
- $order[$alias . '.' . $field] = $value;
- }
- }
- $options['order'] = $order;
- }
-
- return $options;
- }
-
-/**
- * Check the limit parameter and ensure its within the maxLimit bounds.
- *
- * @param array $options An array of options with a limit key to be checked.
- * @return array An array of options for pagination
- */
- public function checkLimit($options) {
- $options['limit'] = (int)$options['limit'];
- if (empty($options['limit']) || $options['limit'] < 1) {
- $options['limit'] = 1;
- }
- $options['limit'] = min((int)$options['limit'], $options['maxLimit']);
- return $options;
- }
-
-}
diff --git a/lib/Cake/Controller/Component/RequestHandlerComponent.php b/lib/Cake/Controller/Component/RequestHandlerComponent.php
deleted file mode 100644
index b8831fe1dac..00000000000
--- a/lib/Cake/Controller/Component/RequestHandlerComponent.php
+++ /dev/null
@@ -1,730 +0,0 @@
- array('json_decode', true)
- );
-
-/**
- * Constructor. Parses the accepted content types accepted by the client using HTTP_ACCEPT
- *
- * @param ComponentCollection $collection ComponentCollection object.
- * @param array $settings Array of settings.
- */
- public function __construct(ComponentCollection $collection, $settings = array()) {
- $default = array('checkHttpCache' => true);
- parent::__construct($collection, $settings + $default);
- $this->addInputType('xml', array(array($this, 'convertXml')));
-
- $Controller = $collection->getController();
- $this->request = $Controller->request;
- $this->response = $Controller->response;
- }
-
-/**
- * Checks to see if a file extension has been parsed by the Router, or if the
- * HTTP_ACCEPT_TYPE has matches only one content type with the supported extensions.
- * If there is only one matching type between the supported content types & extensions,
- * and the requested mime-types, RequestHandler::$ext is set to that value.
- *
- * @param Controller $controller A reference to the controller
- * @param array $settings Array of settings to _set().
- * @return void
- * @see Router::parseExtensions()
- */
- public function initialize(Controller $controller, $settings = array()) {
- if (isset($this->request->params['ext'])) {
- $this->ext = $this->request->params['ext'];
- }
- if (empty($this->ext) || $this->ext == 'html') {
- $this->_setExtension();
- }
- $this->params = $controller->params;
- $this->_set($settings);
- }
-
-/**
- * Set the extension based on the accept headers.
- * Compares the accepted types and configured extensions.
- * If there is one common type, that is assigned as the ext/content type
- * for the response.
- *
- * If html is one of the preferred types, no content type will be set, this
- * is to avoid issues with browsers that prefer html and several other content types.
- *
- * @return void
- */
- protected function _setExtension() {
- $accept = $this->request->parseAccept();
- if (empty($accept)) {
- return;
- }
- $extensions = Router::extensions();
- $preferred = array_shift($accept);
- $preferredTypes = $this->response->mapType($preferred);
- $similarTypes = array_intersect($extensions, $preferredTypes);
- if (count($similarTypes) === 1 && !in_array('xhtml', $preferredTypes) && !in_array('html', $preferredTypes)) {
- $this->ext = array_shift($similarTypes);
- }
- }
-
-/**
- * The startup method of the RequestHandler enables several automatic behaviors
- * related to the detection of certain properties of the HTTP request, including:
- *
- * - Disabling layout rendering for Ajax requests (based on the HTTP_X_REQUESTED_WITH header)
- * - If Router::parseExtensions() is enabled, the layout and template type are
- * switched based on the parsed extension or Accept-Type header. For example, if `controller/action.xml`
- * is requested, the view path becomes `app/View/Controller/xml/action.ctp`. Also if
- * `controller/action` is requested with `Accept-Type: application/xml` in the headers
- * the view path will become `app/View/Controller/xml/action.ctp`. Layout and template
- * types will only switch to mime-types recognized by CakeResponse. If you need to declare
- * additional mime-types, you can do so using CakeResponse::type() in your controllers beforeFilter()
- * method.
- * - If a helper with the same name as the extension exists, it is added to the controller.
- * - If the extension is of a type that RequestHandler understands, it will set that
- * Content-type in the response header.
- * - If the XML data is POSTed, the data is parsed into an XML object, which is assigned
- * to the $data property of the controller, which can then be saved to a model object.
- *
- * @param Controller $controller A reference to the controller
- * @return void
- */
- public function startup(Controller $controller) {
- $controller->request->params['isAjax'] = $this->request->is('ajax');
- $isRecognized = (
- !in_array($this->ext, array('html', 'htm')) &&
- $this->response->getMimeType($this->ext)
- );
-
- if (!empty($this->ext) && $isRecognized) {
- $this->renderAs($controller, $this->ext);
- } elseif ($this->request->is('ajax')) {
- $this->renderAs($controller, 'ajax');
- } elseif (empty($this->ext) || in_array($this->ext, array('html', 'htm'))) {
- $this->respondAs('html', array('charset' => Configure::read('App.encoding')));
- }
-
- foreach ($this->_inputTypeMap as $type => $handler) {
- if ($this->requestedWith($type)) {
- $input = call_user_func_array(array($controller->request, 'input'), $handler);
- $controller->request->data = $input;
- }
- }
- }
-
-/**
- * Helper method to parse xml input data, due to lack of anonymous functions
- * this lives here.
- *
- * @param string $xml
- * @return array Xml array data
- */
- public function convertXml($xml) {
- try {
- $xml = Xml::build($xml);
- if (isset($xml->data)) {
- return Xml::toArray($xml->data);
- }
- return Xml::toArray($xml);
- } catch (XmlException $e) {
- return array();
- }
- }
-
-/**
- * Handles (fakes) redirects for Ajax requests using requestAction()
- *
- * @param Controller $controller A reference to the controller
- * @param string|array $url A string or array containing the redirect location
- * @param mixed $status HTTP Status for redirect
- * @param boolean $exit
- * @return void
- */
- public function beforeRedirect(Controller $controller, $url, $status = null, $exit = true) {
- if (!$this->request->is('ajax')) {
- return;
- }
- foreach ($_POST as $key => $val) {
- unset($_POST[$key]);
- }
- if (is_array($url)) {
- $url = Router::url($url + array('base' => false));
- }
- if (!empty($status)) {
- $statusCode = $this->response->httpCodes($status);
- $code = key($statusCode);
- $this->response->statusCode($code);
- }
- $this->response->body($this->requestAction($url, array('return', 'bare' => false)));
- $this->response->send();
- $this->_stop();
- }
-
-/**
- * Checks if the response can be considered different according to the request
- * headers, and the caching response headers. If it was not modified, then the
- * render process is skipped. And the client will get a blank response with a
- * "304 Not Modified" header.
- *
- * @params Controller $controller
- * @return boolean false if the render process should be aborted
- **/
- public function beforeRender(Controller $controller) {
- $shouldCheck = $this->settings['checkHttpCache'];
- if ($shouldCheck && $this->response->checkNotModified($this->request)) {
- return false;
- }
- }
-
-/**
- * Returns true if the current HTTP request is Ajax, false otherwise
- *
- * @return boolean True if call is Ajax
- * @deprecated use `$this->request->is('ajax')` instead.
- */
- public function isAjax() {
- return $this->request->is('ajax');
- }
-
-/**
- * Returns true if the current HTTP request is coming from a Flash-based client
- *
- * @return boolean True if call is from Flash
- * @deprecated use `$this->request->is('flash')` instead.
- */
- public function isFlash() {
- return $this->request->is('flash');
- }
-
-/**
- * Returns true if the current request is over HTTPS, false otherwise.
- *
- * @return boolean True if call is over HTTPS
- * @deprecated use `$this->request->is('ssl')` instead.
- */
- public function isSSL() {
- return $this->request->is('ssl');
- }
-
-/**
- * Returns true if the current call accepts an XML response, false otherwise
- *
- * @return boolean True if client accepts an XML response
- */
- public function isXml() {
- return $this->prefers('xml');
- }
-
-/**
- * Returns true if the current call accepts an RSS response, false otherwise
- *
- * @return boolean True if client accepts an RSS response
- */
- public function isRss() {
- return $this->prefers('rss');
- }
-
-/**
- * Returns true if the current call accepts an Atom response, false otherwise
- *
- * @return boolean True if client accepts an RSS response
- */
- public function isAtom() {
- return $this->prefers('atom');
- }
-
-/**
- * Returns true if user agent string matches a mobile web browser, or if the
- * client accepts WAP content.
- *
- * @return boolean True if user agent is a mobile web browser
- */
- public function isMobile() {
- return $this->request->is('mobile') || $this->accepts('wap');
- }
-
-/**
- * Returns true if the client accepts WAP content
- *
- * @return boolean
- */
- public function isWap() {
- return $this->prefers('wap');
- }
-
-/**
- * Returns true if the current call a POST request
- *
- * @return boolean True if call is a POST
- * @deprecated Use $this->request->is('post'); from your controller.
- */
- public function isPost() {
- return $this->request->is('post');
- }
-
-/**
- * Returns true if the current call a PUT request
- *
- * @return boolean True if call is a PUT
- * @deprecated Use $this->request->is('put'); from your controller.
- */
- public function isPut() {
- return $this->request->is('put');
- }
-
-/**
- * Returns true if the current call a GET request
- *
- * @return boolean True if call is a GET
- * @deprecated Use $this->request->is('get'); from your controller.
- */
- public function isGet() {
- return $this->request->is('get');
- }
-
-/**
- * Returns true if the current call a DELETE request
- *
- * @return boolean True if call is a DELETE
- * @deprecated Use $this->request->is('delete'); from your controller.
- */
- public function isDelete() {
- return $this->request->is('delete');
- }
-
-/**
- * Gets Prototype version if call is Ajax, otherwise empty string.
- * The Prototype library sets a special "Prototype version" HTTP header.
- *
- * @return string Prototype version of component making Ajax call
- */
- public function getAjaxVersion() {
- if (env('HTTP_X_PROTOTYPE_VERSION') != null) {
- return env('HTTP_X_PROTOTYPE_VERSION');
- }
- return false;
- }
-
-/**
- * Adds/sets the Content-type(s) for the given name. This method allows
- * content-types to be mapped to friendly aliases (or extensions), which allows
- * RequestHandler to automatically respond to requests of that type in the
- * startup method.
- *
- * @param string $name The name of the Content-type, i.e. "html", "xml", "css"
- * @param mixed $type The Content-type or array of Content-types assigned to the name,
- * i.e. "text/html", or "application/xml"
- * @return void
- * @deprecated use `$this->response->type()` instead.
- */
- public function setContent($name, $type = null) {
- $this->response->type(array($name => $type));
- }
-
-/**
- * Gets the server name from which this request was referred
- *
- * @return string Server address
- * @deprecated use $this->request->referer() from your controller instead
- */
- public function getReferer() {
- return $this->request->referer(false);
- }
-
-/**
- * Gets remote client IP
- *
- * @param boolean $safe
- * @return string Client IP address
- * @deprecated use $this->request->clientIp() from your, controller instead.
- */
- public function getClientIP($safe = true) {
- return $this->request->clientIp($safe);
- }
-
-/**
- * Determines which content types the client accepts. Acceptance is based on
- * the file extension parsed by the Router (if present), and by the HTTP_ACCEPT
- * header. Unlike CakeRequest::accepts() this method deals entirely with mapped content types.
- *
- * Usage:
- *
- * `$this->RequestHandler->accepts(array('xml', 'html', 'json'));`
- *
- * Returns true if the client accepts any of the supplied types.
- *
- * `$this->RequestHandler->accepts('xml');`
- *
- * Returns true if the client accepts xml.
- *
- * @param mixed $type Can be null (or no parameter), a string type name, or an
- * array of types
- * @return mixed If null or no parameter is passed, returns an array of content
- * types the client accepts. If a string is passed, returns true
- * if the client accepts it. If an array is passed, returns true
- * if the client accepts one or more elements in the array.
- * @see RequestHandlerComponent::setContent()
- */
- public function accepts($type = null) {
- $accepted = $this->request->accepts();
-
- if ($type == null) {
- return $this->mapType($accepted);
- } elseif (is_array($type)) {
- foreach ($type as $t) {
- $t = $this->mapAlias($t);
- if (in_array($t, $accepted)) {
- return true;
- }
- }
- return false;
- } elseif (is_string($type)) {
- $type = $this->mapAlias($type);
- return in_array($type, $accepted);
- }
- return false;
- }
-
-/**
- * Determines the content type of the data the client has sent (i.e. in a POST request)
- *
- * @param mixed $type Can be null (or no parameter), a string type name, or an array of types
- * @return mixed If a single type is supplied a boolean will be returned. If no type is provided
- * The mapped value of CONTENT_TYPE will be returned. If an array is supplied the first type
- * in the request content type will be returned.
- */
- public function requestedWith($type = null) {
- if (!$this->request->is('post') && !$this->request->is('put')) {
- return null;
- }
-
- list($contentType) = explode(';', env('CONTENT_TYPE'));
- if ($type == null) {
- return $this->mapType($contentType);
- } elseif (is_array($type)) {
- foreach ($type as $t) {
- if ($this->requestedWith($t)) {
- return $t;
- }
- }
- return false;
- } elseif (is_string($type)) {
- return ($type == $this->mapType($contentType));
- }
- }
-
-/**
- * Determines which content-types the client prefers. If no parameters are given,
- * the single content-type that the client most likely prefers is returned. If $type is
- * an array, the first item in the array that the client accepts is returned.
- * Preference is determined primarily by the file extension parsed by the Router
- * if provided, and secondarily by the list of content-types provided in
- * HTTP_ACCEPT.
- *
- * @param mixed $type An optional array of 'friendly' content-type names, i.e.
- * 'html', 'xml', 'js', etc.
- * @return mixed If $type is null or not provided, the first content-type in the
- * list, based on preference, is returned. If a single type is provided
- * a boolean will be returned if that type is preferred.
- * If an array of types are provided then the first preferred type is returned.
- * If no type is provided the first preferred type is returned.
- * @see RequestHandlerComponent::setContent()
- */
- public function prefers($type = null) {
- $acceptRaw = $this->request->parseAccept();
-
- if (empty($acceptRaw)) {
- return $this->ext;
- }
- $accepts = array_shift($acceptRaw);
- $accepts = $this->mapType($accepts);
-
- if ($type == null) {
- if (empty($this->ext) && !empty($accepts)) {
- return $accepts[0];
- }
- return $this->ext;
- }
-
- $types = (array)$type;
-
- if (count($types) === 1) {
- if (!empty($this->ext)) {
- return in_array($this->ext, $types);
- }
- return in_array($types[0], $accepts);
- }
-
- $intersect = array_values(array_intersect($accepts, $types));
- if (empty($intersect)) {
- return false;
- }
- return $intersect[0];
- }
-
-/**
- * Sets the layout and template paths for the content type defined by $type.
- *
- * ### Usage:
- *
- * Render the response as an 'ajax' response.
- *
- * `$this->RequestHandler->renderAs($this, 'ajax');`
- *
- * Render the response as an xml file and force the result as a file download.
- *
- * `$this->RequestHandler->renderAs($this, 'xml', array('attachment' => 'myfile.xml');`
- *
- * @param Controller $controller A reference to a controller object
- * @param string $type Type of response to send (e.g: 'ajax')
- * @param array $options Array of options to use
- * @return void
- * @see RequestHandlerComponent::setContent()
- * @see RequestHandlerComponent::respondAs()
- */
- public function renderAs(Controller $controller, $type, $options = array()) {
- $defaults = array('charset' => 'UTF-8');
-
- if (Configure::read('App.encoding') !== null) {
- $defaults['charset'] = Configure::read('App.encoding');
- }
- $options = array_merge($defaults, $options);
-
- if ($type == 'ajax') {
- $controller->layout = $this->ajaxLayout;
- return $this->respondAs('html', $options);
- }
- $controller->ext = '.ctp';
-
- $viewClass = Inflector::classify($type);
- $viewName = $viewClass . 'View';
- if (!class_exists($viewName)) {
- App::uses($viewName, 'View');
- }
- if (class_exists($viewName)) {
- $controller->viewClass = $viewClass;
- } elseif (empty($this->_renderType)) {
- $controller->viewPath .= DS . $type;
- } else {
- $remove = preg_replace("/([\/\\\\]{$this->_renderType})$/", DS . $type, $controller->viewPath);
- $controller->viewPath = $remove;
- }
- $this->_renderType = $type;
- $controller->layoutPath = $type;
-
- if ($this->response->getMimeType($type)) {
- $this->respondAs($type, $options);
- }
-
- $helper = ucfirst($type);
- $isAdded = (
- in_array($helper, $controller->helpers) ||
- array_key_exists($helper, $controller->helpers)
- );
-
- if (!$isAdded) {
- App::uses('AppHelper', 'View/Helper');
- App::uses($helper . 'Helper', 'View/Helper');
- if (class_exists($helper . 'Helper')) {
- $controller->helpers[] = $helper;
- }
- }
- }
-
-/**
- * Sets the response header based on type map index name. This wraps several methods
- * available on CakeResponse. It also allows you to use Content-Type aliases.
- *
- * @param mixed $type Friendly type name, i.e. 'html' or 'xml', or a full content-type,
- * like 'application/x-shockwave'.
- * @param array $options If $type is a friendly type name that is associated with
- * more than one type of content, $index is used to select which content-type to use.
- * @return boolean Returns false if the friendly type name given in $type does
- * not exist in the type map, or if the Content-type header has
- * already been set by this method.
- * @see RequestHandlerComponent::setContent()
- */
- public function respondAs($type, $options = array()) {
- $defaults = array('index' => null, 'charset' => null, 'attachment' => false);
- $options = $options + $defaults;
-
- if (strpos($type, '/') === false) {
- $cType = $this->response->getMimeType($type);
- if ($cType === false) {
- return false;
- }
- if (is_array($cType) && isset($cType[$options['index']])) {
- $cType = $cType[$options['index']];
- }
- if (is_array($cType)) {
- if ($this->prefers($cType)) {
- $cType = $this->prefers($cType);
- } else {
- $cType = $cType[0];
- }
- }
- } else {
- $cType = $type;
- }
-
- if ($cType != null) {
- if (empty($this->request->params['requested'])) {
- $this->response->type($cType);
- }
-
- if (!empty($options['charset'])) {
- $this->response->charset($options['charset']);
- }
- if (!empty($options['attachment'])) {
- $this->response->download($options['attachment']);
- }
- return true;
- }
- return false;
- }
-
-/**
- * Returns the current response type (Content-type header), or null if not alias exists
- *
- * @return mixed A string content type alias, or raw content type if no alias map exists,
- * otherwise null
- */
- public function responseType() {
- return $this->mapType($this->response->type());
- }
-
-/**
- * Maps a content-type back to an alias
- *
- * @param mixed $cType Either a string content type to map, or an array of types.
- * @return mixed Aliases for the types provided.
- * @deprecated Use $this->response->mapType() in your controller instead.
- */
- public function mapType($cType) {
- return $this->response->mapType($cType);
- }
-
-/**
- * Maps a content type alias back to its mime-type(s)
- *
- * @param mixed $alias String alias to convert back into a content type. Or an array of aliases to map.
- * @return mixed Null on an undefined alias. String value of the mapped alias type. If an
- * alias maps to more than one content type, the first one will be returned.
- */
- public function mapAlias($alias) {
- if (is_array($alias)) {
- return array_map(array($this, 'mapAlias'), $alias);
- }
- $type = $this->response->getMimeType($alias);
- if ($type) {
- if (is_array($type)) {
- return $type[0];
- }
- return $type;
- }
- return null;
- }
-
-/**
- * Add a new mapped input type. Mapped input types are automatically
- * converted by RequestHandlerComponent during the startup() callback.
- *
- * @param string $type The type alias being converted, ie. json
- * @param array $handler The handler array for the type. The first index should
- * be the handling callback, all other arguments should be additional parameters
- * for the handler.
- * @return void
- * @throws CakeException
- */
- public function addInputType($type, $handler) {
- if (!is_array($handler) || !isset($handler[0]) || !is_callable($handler[0])) {
- throw new CakeException(__d('cake_dev', 'You must give a handler callback.'));
- }
- $this->_inputTypeMap[$type] = $handler;
- }
-
-}
diff --git a/lib/Cake/Controller/Component/SecurityComponent.php b/lib/Cake/Controller/Component/SecurityComponent.php
deleted file mode 100644
index 1617c46a12b..00000000000
--- a/lib/Cake/Controller/Component/SecurityComponent.php
+++ /dev/null
@@ -1,596 +0,0 @@
-request = $controller->request;
- $this->_action = $this->request->params['action'];
- $this->_methodsRequired($controller);
- $this->_secureRequired($controller);
- $this->_authRequired($controller);
-
- $isPost = ($this->request->is('post') || $this->request->is('put'));
- $isNotRequestAction = (
- !isset($controller->request->params['requested']) ||
- $controller->request->params['requested'] != 1
- );
-
- if ($isPost && $isNotRequestAction && $this->validatePost) {
- if ($this->_validatePost($controller) === false) {
- return $this->blackHole($controller, 'auth');
- }
- }
- if ($isPost && $isNotRequestAction && $this->csrfCheck) {
- if ($this->_validateCsrf($controller) === false) {
- return $this->blackHole($controller, 'csrf');
- }
- }
- $this->generateToken($controller->request);
- if ($isPost) {
- unset($controller->request->data['_Token']);
- }
- }
-
-/**
- * Sets the actions that require a POST request, or empty for all actions
- *
- * @return void
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#SecurityComponent::requirePost
- */
- public function requirePost() {
- $args = func_get_args();
- $this->_requireMethod('Post', $args);
- }
-
-/**
- * Sets the actions that require a GET request, or empty for all actions
- *
- * @return void
- */
- public function requireGet() {
- $args = func_get_args();
- $this->_requireMethod('Get', $args);
- }
-
-/**
- * Sets the actions that require a PUT request, or empty for all actions
- *
- * @return void
- */
- public function requirePut() {
- $args = func_get_args();
- $this->_requireMethod('Put', $args);
- }
-
-/**
- * Sets the actions that require a DELETE request, or empty for all actions
- *
- * @return void
- */
- public function requireDelete() {
- $args = func_get_args();
- $this->_requireMethod('Delete', $args);
- }
-
-/**
- * Sets the actions that require a request that is SSL-secured, or empty for all actions
- *
- * @return void
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#SecurityComponent::requireSecure
- */
- public function requireSecure() {
- $args = func_get_args();
- $this->_requireMethod('Secure', $args);
- }
-
-/**
- * Sets the actions that require an authenticated request, or empty for all actions
- *
- * @return void
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#SecurityComponent::requireAuth
- */
- public function requireAuth() {
- $args = func_get_args();
- $this->_requireMethod('Auth', $args);
- }
-
-/**
- * Black-hole an invalid request with a 400 error or custom callback. If SecurityComponent::$blackHoleCallback
- * is specified, it will use this callback by executing the method indicated in $error
- *
- * @param Controller $controller Instantiating controller
- * @param string $error Error method
- * @return mixed If specified, controller blackHoleCallback's response, or no return otherwise
- * @see SecurityComponent::$blackHoleCallback
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#handling-blackhole-callbacks
- * @throws BadRequestException
- */
- public function blackHole(Controller $controller, $error = '') {
- if ($this->blackHoleCallback == null) {
- throw new BadRequestException(__d('cake_dev', 'The request has been black-holed'));
- } else {
- return $this->_callback($controller, $this->blackHoleCallback, array($error));
- }
- }
-
-/**
- * Sets the actions that require a $method HTTP request, or empty for all actions
- *
- * @param string $method The HTTP method to assign controller actions to
- * @param array $actions Controller actions to set the required HTTP method to.
- * @return void
- */
- protected function _requireMethod($method, $actions = array()) {
- if (isset($actions[0]) && is_array($actions[0])) {
- $actions = $actions[0];
- }
- $this->{'require' . $method} = (empty($actions)) ? array('*'): $actions;
- }
-
-/**
- * Check if HTTP methods are required
- *
- * @param Controller $controller Instantiating controller
- * @return boolean true if $method is required
- */
- protected function _methodsRequired(Controller $controller) {
- foreach (array('Post', 'Get', 'Put', 'Delete') as $method) {
- $property = 'require' . $method;
- if (is_array($this->$property) && !empty($this->$property)) {
- $require = $this->$property;
- if (in_array($this->_action, $require) || $this->$property == array('*')) {
- if (!$this->request->is($method)) {
- if (!$this->blackHole($controller, $method)) {
- return null;
- }
- }
- }
- }
- }
- return true;
- }
-
-/**
- * Check if access requires secure connection
- *
- * @param Controller $controller Instantiating controller
- * @return boolean true if secure connection required
- */
- protected function _secureRequired(Controller $controller) {
- if (is_array($this->requireSecure) && !empty($this->requireSecure)) {
- $requireSecure = $this->requireSecure;
-
- if (in_array($this->_action, $requireSecure) || $this->requireSecure == array('*')) {
- if (!$this->request->is('ssl')) {
- if (!$this->blackHole($controller, 'secure')) {
- return null;
- }
- }
- }
- }
- return true;
- }
-
-/**
- * Check if authentication is required
- *
- * @param Controller $controller Instantiating controller
- * @return boolean true if authentication required
- */
- protected function _authRequired(Controller $controller) {
- if (is_array($this->requireAuth) && !empty($this->requireAuth) && !empty($this->request->data)) {
- $requireAuth = $this->requireAuth;
-
- if (in_array($this->request->params['action'], $requireAuth) || $this->requireAuth == array('*')) {
- if (!isset($controller->request->data['_Token'] )) {
- if (!$this->blackHole($controller, 'auth')) {
- return null;
- }
- }
-
- if ($this->Session->check('_Token')) {
- $tData = $this->Session->read('_Token');
-
- if (
- !empty($tData['allowedControllers']) &&
- !in_array($this->request->params['controller'], $tData['allowedControllers']) ||
- !empty($tData['allowedActions']) &&
- !in_array($this->request->params['action'], $tData['allowedActions'])
- ) {
- if (!$this->blackHole($controller, 'auth')) {
- return null;
- }
- }
- } else {
- if (!$this->blackHole($controller, 'auth')) {
- return null;
- }
- }
- }
- }
- return true;
- }
-
-/**
- * Validate submitted form
- *
- * @param Controller $controller Instantiating controller
- * @return boolean true if submitted form is valid
- */
- protected function _validatePost(Controller $controller) {
- if (empty($controller->request->data)) {
- return true;
- }
- $data = $controller->request->data;
-
- if (!isset($data['_Token']) || !isset($data['_Token']['fields']) || !isset($data['_Token']['unlocked'])) {
- return false;
- }
-
- $locked = '';
- $check = $controller->request->data;
- $token = urldecode($check['_Token']['fields']);
- $unlocked = urldecode($check['_Token']['unlocked']);
-
- if (strpos($token, ':')) {
- list($token, $locked) = explode(':', $token, 2);
- }
- unset($check['_Token']);
-
- $locked = explode('|', $locked);
- $unlocked = explode('|', $unlocked);
-
- $lockedFields = array();
- $fields = Set::flatten($check);
- $fieldList = array_keys($fields);
- $multi = array();
-
- foreach ($fieldList as $i => $key) {
- if (preg_match('/(\.\d+)+$/', $key)) {
- $multi[$i] = preg_replace('/(\.\d+)+$/', '', $key);
- unset($fieldList[$i]);
- }
- }
- if (!empty($multi)) {
- $fieldList += array_unique($multi);
- }
-
- $unlockedFields = array_unique(
- array_merge((array)$this->disabledFields, (array)$this->unlockedFields, $unlocked)
- );
-
- foreach ($fieldList as $i => $key) {
- $isLocked = (is_array($locked) && in_array($key, $locked));
-
- if (!empty($unlockedFields)) {
- foreach ($unlockedFields as $off) {
- $off = explode('.', $off);
- $field = array_values(array_intersect(explode('.', $key), $off));
- $isUnlocked = ($field === $off);
- if ($isUnlocked) {
- break;
- }
- }
- }
-
- if ($isUnlocked || $isLocked) {
- unset($fieldList[$i]);
- if ($isLocked) {
- $lockedFields[$key] = $fields[$key];
- }
- }
- }
- sort($unlocked, SORT_STRING);
- sort($fieldList, SORT_STRING);
- ksort($lockedFields, SORT_STRING);
-
- $fieldList += $lockedFields;
- $unlocked = implode('|', $unlocked);
- $check = Security::hash(serialize($fieldList) . $unlocked . Configure::read('Security.salt'));
- return ($token === $check);
- }
-
-/**
- * Manually add CSRF token information into the provided request object.
- *
- * @param CakeRequest $request The request object to add into.
- * @return boolean
- */
- public function generateToken(CakeRequest $request) {
- if (isset($request->params['requested']) && $request->params['requested'] === 1) {
- if ($this->Session->check('_Token')) {
- $request->params['_Token'] = $this->Session->read('_Token');
- }
- return false;
- }
- $authKey = Security::generateAuthKey();
- $token = array(
- 'key' => $authKey,
- 'allowedControllers' => $this->allowedControllers,
- 'allowedActions' => $this->allowedActions,
- 'unlockedFields' => array_merge($this->disabledFields, $this->unlockedFields),
- 'csrfTokens' => array()
- );
-
- $tokenData = array();
- if ($this->Session->check('_Token')) {
- $tokenData = $this->Session->read('_Token');
- if (!empty($tokenData['csrfTokens']) && is_array($tokenData['csrfTokens'])) {
- $token['csrfTokens'] = $this->_expireTokens($tokenData['csrfTokens']);
- }
- }
- if ($this->csrfUseOnce || empty($token['csrfTokens'])) {
- $token['csrfTokens'][$authKey] = strtotime($this->csrfExpires);
- }
- if (!$this->csrfUseOnce) {
- $csrfTokens = array_keys($token['csrfTokens']);
- $token['key'] = $csrfTokens[0];
- }
- $this->Session->write('_Token', $token);
- $request->params['_Token'] = array(
- 'key' => $token['key'],
- 'unlockedFields' => $token['unlockedFields']
- );
- return true;
- }
-
-/**
- * Validate that the controller has a CSRF token in the POST data
- * and that the token is legit/not expired. If the token is valid
- * it will be removed from the list of valid tokens.
- *
- * @param Controller $controller A controller to check
- * @return boolean Valid csrf token.
- */
- protected function _validateCsrf(Controller $controller) {
- $token = $this->Session->read('_Token');
- $requestToken = $controller->request->data('_Token.key');
- if (isset($token['csrfTokens'][$requestToken]) && $token['csrfTokens'][$requestToken] >= time()) {
- if ($this->csrfUseOnce) {
- $this->Session->delete('_Token.csrfTokens.' . $requestToken);
- }
- return true;
- }
- return false;
- }
-
-/**
- * Expire CSRF nonces and remove them from the valid tokens.
- * Uses a simple timeout to expire the tokens.
- *
- * @param array $tokens An array of nonce => expires.
- * @return array An array of nonce => expires.
- */
- protected function _expireTokens($tokens) {
- $now = time();
- foreach ($tokens as $nonce => $expires) {
- if ($expires < $now) {
- unset($tokens[$nonce]);
- }
- }
- $overflow = count($tokens) - $this->csrfLimit;
- if ($overflow > 0) {
- $tokens = array_slice($tokens, $overflow + 1, null, true);
- }
- return $tokens;
- }
-
-/**
- * Calls a controller callback method
- *
- * @param Controller $controller Controller to run callback on
- * @param string $method Method to execute
- * @param array $params Parameters to send to method
- * @return mixed Controller callback method's response
- */
- protected function _callback(Controller $controller, $method, $params = array()) {
- if (is_callable(array($controller, $method))) {
- return call_user_func_array(array(&$controller, $method), empty($params) ? null : $params);
- } else {
- return null;
- }
- }
-
-}
diff --git a/lib/Cake/Controller/Component/SessionComponent.php b/lib/Cake/Controller/Component/SessionComponent.php
deleted file mode 100644
index 21e6603e7bf..00000000000
--- a/lib/Cake/Controller/Component/SessionComponent.php
+++ /dev/null
@@ -1,186 +0,0 @@
-Session->write('Controller.sessKey', 'session value');
- *
- * @param string $name The name of the key your are setting in the session.
- * This should be in a Controller.key format for better organizing
- * @param string $value The value you want to store in a session.
- * @return boolean Success
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::write
- */
- public function write($name, $value = null) {
- return CakeSession::write($name, $value);
- }
-
-/**
- * Used to read a session values for a key or return values for all keys.
- *
- * In your controller: $this->Session->read('Controller.sessKey');
- * Calling the method without a param will return all session vars
- *
- * @param string $name the name of the session key you want to read
- * @return mixed value from the session vars
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::read
- */
- public function read($name = null) {
- return CakeSession::read($name);
- }
-
-/**
- * Wrapper for SessionComponent::del();
- *
- * In your controller: $this->Session->delete('Controller.sessKey');
- *
- * @param string $name the name of the session key you want to delete
- * @return boolean true is session variable is set and can be deleted, false is variable was not set.
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::delete
- */
- public function delete($name) {
- return CakeSession::delete($name);
- }
-
-/**
- * Used to check if a session variable is set
- *
- * In your controller: $this->Session->check('Controller.sessKey');
- *
- * @param string $name the name of the session key you want to check
- * @return boolean true is session variable is set, false if not
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::check
- */
- public function check($name) {
- return CakeSession::check($name);
- }
-
-/**
- * Used to determine the last error in a session.
- *
- * In your controller: $this->Session->error();
- *
- * @return string Last session error
- */
- public function error() {
- return CakeSession::error();
- }
-
-/**
- * Used to set a session variable that can be used to output messages in the view.
- *
- * In your controller: $this->Session->setFlash('This has been saved');
- *
- * Additional params below can be passed to customize the output, or the Message.[key].
- * You can also set additional parameters when rendering flash messages. See SessionHelper::flash()
- * for more information on how to do that.
- *
- * @param string $message Message to be flashed
- * @param string $element Element to wrap flash message in.
- * @param array $params Parameters to be sent to layout as view variables
- * @param string $key Message key, default is 'flash'
- * @return void
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#creating-notification-messages
- */
- public function setFlash($message, $element = 'default', $params = array(), $key = 'flash') {
- CakeSession::write('Message.' . $key, compact('message', 'element', 'params'));
- }
-
-/**
- * Used to renew a session id
- *
- * In your controller: $this->Session->renew();
- *
- * @return void
- */
- public function renew() {
- return CakeSession::renew();
- }
-
-/**
- * Used to check for a valid session.
- *
- * In your controller: $this->Session->valid();
- *
- * @return boolean true is session is valid, false is session is invalid
- */
- public function valid() {
- return CakeSession::valid();
- }
-
-/**
- * Used to destroy sessions
- *
- * In your controller: $this->Session->destroy();
- *
- * @return void
- * @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::destroy
- */
- public function destroy() {
- return CakeSession::destroy();
- }
-
-/**
- * Returns Session id
- *
- * If $id is passed in a beforeFilter, the Session will be started
- * with the specified id
- *
- * @param string $id
- * @return string
- */
- public function id($id = null) {
- return CakeSession::id($id);
- }
-
-/**
- * Returns a bool, whether or not the session has been started.
- *
- * @return boolean
- */
- public function started() {
- return CakeSession::started();
- }
-
-}
diff --git a/lib/Cake/Controller/ComponentCollection.php b/lib/Cake/Controller/ComponentCollection.php
deleted file mode 100644
index 43dca086f0e..00000000000
--- a/lib/Cake/Controller/ComponentCollection.php
+++ /dev/null
@@ -1,129 +0,0 @@
-components)) {
- return;
- }
- $this->_Controller = $Controller;
- $components = ComponentCollection::normalizeObjectArray($Controller->components);
- foreach ($components as $name => $properties) {
- $Controller->{$name} = $this->load($properties['class'], $properties['settings']);
- }
- }
-
-/**
- * Get the controller associated with the collection.
- *
- * @return Controller.
- */
- public function getController() {
- return $this->_Controller;
- }
-
-/**
- * Loads/constructs a component. Will return the instance in the registry if it already exists.
- * You can use `$settings['enabled'] = false` to disable callbacks on a component when loading it.
- * Callbacks default to on. Disabled component methods work as normal, only callbacks are disabled.
- *
- * You can alias your component as an existing component by setting the 'className' key, i.e.,
- * {{{
- * public $components = array(
- * 'Email' => array(
- * 'className' => 'AliasedEmail'
- * );
- * );
- * }}}
- * All calls to the `Email` component would use `AliasedEmail` instead.
- *
- * @param string $component Component name to load
- * @param array $settings Settings for the component.
- * @return Component A component object, Either the existing loaded component or a new one.
- * @throws MissingComponentException when the component could not be found
- */
- public function load($component, $settings = array()) {
- if (is_array($settings) && isset($settings['className'])) {
- $alias = $component;
- $component = $settings['className'];
- }
- list($plugin, $name) = pluginSplit($component, true);
- if (!isset($alias)) {
- $alias = $name;
- }
- if (isset($this->_loaded[$alias])) {
- return $this->_loaded[$alias];
- }
- $componentClass = $name . 'Component';
- App::uses($componentClass, $plugin . 'Controller/Component');
- if (!class_exists($componentClass)) {
- throw new MissingComponentException(array(
- 'class' => $componentClass,
- 'plugin' => substr($plugin, 0, -1)
- ));
- }
- $this->_loaded[$alias] = new $componentClass($this, $settings);
- $enable = isset($settings['enabled']) ? $settings['enabled'] : true;
- if ($enable) {
- $this->enable($alias);
- }
- return $this->_loaded[$alias];
- }
-
-/**
- * Returns the implemented events that will get routed to the trigger function
- * in order to dispatch them separately on each component
- *
- * @return array
- */
- public function implementedEvents() {
- return array(
- 'Controller.initialize' => array('callable' => 'trigger'),
- 'Controller.startup' => array('callable' => 'trigger'),
- 'Controller.beforeRender' => array('callable' => 'trigger'),
- 'Controller.beforeRedirect' => array('callable' => 'trigger'),
- 'Controller.shutdown' => array('callable' => 'trigger'),
- );
- }
-
-}
diff --git a/lib/Cake/Controller/Controller.php b/lib/Cake/Controller/Controller.php
deleted file mode 100644
index bef8bfcc964..00000000000
--- a/lib/Cake/Controller/Controller.php
+++ /dev/null
@@ -1,1230 +0,0 @@
-request`. The request object contains all the POST, GET and FILES
- * that were part of the request.
- *
- * After performing the required actions, controllers are responsible for creating a response. This usually
- * takes the form of a generated View, or possibly a redirection to another controller action. In either case
- * `$this->response` allows you to manipulate all aspects of the response.
- *
- * Controllers are created by Dispatcher based on request parameters and routing. By default controllers and actions
- * use conventional names. For example `/posts/index` maps to `PostsController::index()`. You can re-map urls
- * using Router::connect().
- *
- * @package Cake.Controller
- * @property AclComponent $Acl
- * @property AuthComponent $Auth
- * @property CookieComponent $Cookie
- * @property EmailComponent $Email
- * @property PaginatorComponent $Paginator
- * @property RequestHandlerComponent $RequestHandler
- * @property SecurityComponent $Security
- * @property SessionComponent $Session
- * @link http://book.cakephp.org/2.0/en/controllers.html
- */
-class Controller extends Object implements CakeEventListener {
-
-/**
- * The name of this controller. Controller names are plural, named after the model they manipulate.
- *
- * @var string
- * @link http://book.cakephp.org/2.0/en/controllers.html#controller-attributes
- */
- public $name = null;
-
-/**
- * An array containing the class names of models this controller uses.
- *
- * Example: `public $uses = array('Product', 'Post', 'Comment');`
- *
- * Can be set to several values to express different options:
- *
- * - `true` Use the default inflected model name.
- * - `array()` Use only models defined in the parent class.
- * - `false` Use no models at all, do not merge with parent class either.
- * - `array('Post', 'Comment')` Use only the Post and Comment models. Models
- * Will also be merged with the parent class.
- *
- * The default value is `true`.
- *
- * @var mixed A single name as a string or a list of names as an array.
- * @link http://book.cakephp.org/2.0/en/controllers.html#components-helpers-and-uses
- */
- public $uses = true;
-
-/**
- * An array containing the names of helpers this controller uses. The array elements should
- * not contain the "Helper" part of the classname.
- *
- * Example: `public $helpers = array('Html', 'Javascript', 'Time', 'Ajax');`
- *
- * @var mixed A single name as a string or a list of names as an array.
- * @link http://book.cakephp.org/2.0/en/controllers.html#components-helpers-and-uses
- */
- public $helpers = array('Session', 'Html', 'Form');
-
-/**
- * An instance of a CakeRequest object that contains information about the current request.
- * This object contains all the information about a request and several methods for reading
- * additional information about the request.
- *
- * @var CakeRequest
- */
- public $request;
-
-/**
- * An instance of a CakeResponse object that contains information about the impending response
- *
- * @var CakeResponse
- */
- public $response;
-
-/**
- * The classname to use for creating the response object.
- *
- * @var string
- */
- protected $_responseClass = 'CakeResponse';
-
-/**
- * The name of the views subfolder containing views for this controller.
- *
- * @var string
- */
- public $viewPath = null;
-
-/**
- * The name of the layouts subfolder containing layouts for this controller.
- *
- * @var string
- */
- public $layoutPath = null;
-
-/**
- * Contains variables to be handed to the view.
- *
- * @var array
- */
- public $viewVars = array();
-
-/**
- * The name of the view file to render. The name specified
- * is the filename in /app/View/ without the .ctp extension.
- *
- * @var string
- */
- public $view = null;
-
-/**
- * The name of the layout file to render the view inside of. The name specified
- * is the filename of the layout in /app/View/Layouts without the .ctp
- * extension.
- *
- * @var string
- */
- public $layout = 'default';
-
-/**
- * Set to true to automatically render the view
- * after action logic.
- *
- * @var boolean
- */
- public $autoRender = true;
-
-/**
- * Set to true to automatically render the layout around views.
- *
- * @var boolean
- */
- public $autoLayout = true;
-
-/**
- * Instance of ComponentCollection used to handle callbacks.
- *
- * @var ComponentCollection
- */
- public $Components = null;
-
-/**
- * Array containing the names of components this controller uses. Component names
- * should not contain the "Component" portion of the classname.
- *
- * Example: `public $components = array('Session', 'RequestHandler', 'Acl');`
- *
- * @var array
- * @link http://book.cakephp.org/view/961/components-helpers-and-uses
- */
- public $components = array('Session');
-
-/**
- * The name of the View class this controller sends output to.
- *
- * @var string
- */
- public $viewClass = 'View';
-
-/**
- * Instance of the View created during rendering. Won't be set until after Controller::render() is called.
- *
- * @var View
- */
- public $View;
-
-/**
- * File extension for view templates. Defaults to Cake's conventional ".ctp".
- *
- * @var string
- */
- public $ext = '.ctp';
-
-/**
- * Automatically set to the name of a plugin.
- *
- * @var string
- */
- public $plugin = null;
-
-/**
- * Used to define methods a controller that will be cached. To cache a
- * single action, the value is set to an array containing keys that match
- * action names and values that denote cache expiration times (in seconds).
- *
- * Example:
- *
- * {{{
- * public $cacheAction = array(
- * 'view/23/' => 21600,
- * 'recalled/' => 86400
- * );
- * }}}
- *
- * $cacheAction can also be set to a strtotime() compatible string. This
- * marks all the actions in the controller for view caching.
- *
- * @var mixed
- * @link http://book.cakephp.org/view/1380/Caching-in-the-Controller
- */
- public $cacheAction = false;
-
-/**
- * Holds all params passed and named.
- *
- * @var mixed
- */
- public $passedArgs = array();
-
-/**
- * Triggers Scaffolding
- *
- * @var mixed
- * @link http://book.cakephp.org/view/1103/Scaffolding
- */
- public $scaffold = false;
-
-/**
- * Holds current methods of the controller. This is a list of all the methods reachable
- * via url. Modifying this array, will allow you to change which methods can be reached.
- *
- * @var array
- */
- public $methods = array();
-
-/**
- * This controller's primary model class name, the Inflector::singularize()'ed version of
- * the controller's $name property.
- *
- * Example: For a controller named 'Comments', the modelClass would be 'Comment'
- *
- * @var string
- */
- public $modelClass = null;
-
-/**
- * This controller's model key name, an underscored version of the controller's $modelClass property.
- *
- * Example: For a controller named 'ArticleComments', the modelKey would be 'article_comment'
- *
- * @var string
- */
- public $modelKey = null;
-
-/**
- * Holds any validation errors produced by the last call of the validateErrors() method/
- *
- * @var array Validation errors, or false if none
- */
- public $validationErrors = null;
-
-/**
- * The class name of the parent class you wish to merge with.
- * Typically this is AppController, but you may wish to merge vars with a different
- * parent class.
- *
- * @var string
- */
- protected $_mergeParent = 'AppController';
-
-/**
- * Instance of the CakeEventManager this controller is using
- * to dispatch inner events.
- *
- * @var CakeEventManager
- */
- protected $_eventManager = null;
-
-/**
- * Constructor.
- *
- * @param CakeRequest $request Request object for this controller. Can be null for testing,
- * but expect that features that use the request parameters will not work.
- * @param CakeResponse $response Response object for this controller.
- */
- public function __construct($request = null, $response = null) {
- if ($this->name === null) {
- $this->name = substr(get_class($this), 0, strlen(get_class($this)) - 10);
- }
-
- if ($this->viewPath == null) {
- $this->viewPath = $this->name;
- }
-
- $this->modelClass = Inflector::singularize($this->name);
- $this->modelKey = Inflector::underscore($this->modelClass);
- $this->Components = new ComponentCollection();
-
- $childMethods = get_class_methods($this);
- $parentMethods = get_class_methods('Controller');
-
- $this->methods = array_diff($childMethods, $parentMethods);
-
- if ($request instanceof CakeRequest) {
- $this->setRequest($request);
- }
- if ($response instanceof CakeResponse) {
- $this->response = $response;
- }
- parent::__construct();
- }
-
-/**
- * Provides backwards compatibility to avoid problems with empty and isset to alias properties.
- * Lazy loads models using the loadModel() method if declared in $uses
- *
- * @param string $name
- * @return void
- */
- public function __isset($name) {
- switch ($name) {
- case 'base':
- case 'here':
- case 'webroot':
- case 'data':
- case 'action':
- case 'params':
- return true;
- }
-
- if (is_array($this->uses)) {
- foreach ($this->uses as $modelClass) {
- list($plugin, $class) = pluginSplit($modelClass, true);
- if ($name === $class) {
- return $this->loadModel($modelClass);
- }
- }
- }
-
- if ($name === $this->modelClass) {
- list($plugin, $class) = pluginSplit($name, true);
- if (!$plugin) {
- $plugin = $this->plugin ? $this->plugin . '.' : null;
- }
- return $this->loadModel($plugin . $this->modelClass);
- }
-
- return false;
- }
-
-/**
- * Provides backwards compatibility access to the request object properties.
- * Also provides the params alias.
- *
- * @param string $name
- * @return void
- */
- public function __get($name) {
- switch ($name) {
- case 'base':
- case 'here':
- case 'webroot':
- case 'data':
- return $this->request->{$name};
- case 'action':
- return isset($this->request->params['action']) ? $this->request->params['action'] : '';
- case 'params':
- return $this->request;
- case 'paginate':
- return $this->Components->load('Paginator')->settings;
- }
-
- if (isset($this->{$name})) {
- return $this->{$name};
- }
-
- return null;
- }
-
-/**
- * Provides backwards compatibility access for setting values to the request object.
- *
- * @param string $name
- * @param mixed $value
- * @return void
- */
- public function __set($name, $value) {
- switch ($name) {
- case 'base':
- case 'here':
- case 'webroot':
- case 'data':
- return $this->request->{$name} = $value;
- case 'action':
- return $this->request->params['action'] = $value;
- case 'params':
- return $this->request->params = $value;
- case 'paginate':
- return $this->Components->load('Paginator')->settings = $value;
- }
- return $this->{$name} = $value;
- }
-
-/**
- * Sets the request objects and configures a number of controller properties
- * based on the contents of the request. The properties that get set are
- *
- * - $this->request - To the $request parameter
- * - $this->plugin - To the $request->params['plugin']
- * - $this->view - To the $request->params['action']
- * - $this->autoLayout - To the false if $request->params['bare']; is set.
- * - $this->autoRender - To false if $request->params['return'] == 1
- * - $this->passedArgs - The the combined results of params['named'] and params['pass]
- *
- * @param CakeRequest $request
- * @return void
- */
- public function setRequest(CakeRequest $request) {
- $this->request = $request;
- $this->plugin = isset($request->params['plugin']) ? Inflector::camelize($request->params['plugin']) : null;
- $this->view = isset($request->params['action']) ? $request->params['action'] : null;
- if (isset($request->params['pass']) && isset($request->params['named'])) {
- $this->passedArgs = array_merge($request->params['pass'], $request->params['named']);
- }
-
- if (array_key_exists('return', $request->params) && $request->params['return'] == 1) {
- $this->autoRender = false;
- }
- if (!empty($request->params['bare'])) {
- $this->autoLayout = false;
- }
- }
-
-/**
- * Dispatches the controller action. Checks that the action
- * exists and isn't private.
- *
- * @param CakeRequest $request
- * @return mixed The resulting response.
- * @throws PrivateActionException When actions are not public or prefixed by _
- * @throws MissingActionException When actions are not defined and scaffolding is
- * not enabled.
- */
- public function invokeAction(CakeRequest $request) {
- try {
- $method = new ReflectionMethod($this, $request->params['action']);
-
- if ($this->_isPrivateAction($method, $request)) {
- throw new PrivateActionException(array(
- 'controller' => $this->name . "Controller",
- 'action' => $request->params['action']
- ));
- }
- return $method->invokeArgs($this, $request->params['pass']);
-
- } catch (ReflectionException $e) {
- if ($this->scaffold !== false) {
- return $this->_getScaffold($request);
- }
- throw new MissingActionException(array(
- 'controller' => $this->name . "Controller",
- 'action' => $request->params['action']
- ));
- }
- }
-
-/**
- * Check if the request's action is marked as private, with an underscore,
- * or if the request is attempting to directly accessing a prefixed action.
- *
- * @param ReflectionMethod $method The method to be invoked.
- * @param CakeRequest $request The request to check.
- * @return boolean
- */
- protected function _isPrivateAction(ReflectionMethod $method, CakeRequest $request) {
- $privateAction = (
- $method->name[0] === '_' ||
- !$method->isPublic() ||
- !in_array($method->name, $this->methods)
- );
- $prefixes = Router::prefixes();
-
- if (!$privateAction && !empty($prefixes)) {
- if (empty($request->params['prefix']) && strpos($request->params['action'], '_') > 0) {
- list($prefix) = explode('_', $request->params['action']);
- $privateAction = in_array($prefix, $prefixes);
- }
- }
- return $privateAction;
- }
-
-/**
- * Returns a scaffold object to use for dynamically scaffolded controllers.
- *
- * @param CakeRequest $request
- * @return Scaffold
- */
- protected function _getScaffold(CakeRequest $request) {
- return new Scaffold($this, $request);
- }
-
-/**
- * Merge components, helpers, and uses vars from
- * Controller::$_mergeParent and PluginAppController.
- *
- * @return void
- */
- protected function _mergeControllerVars() {
- $pluginController = $pluginDot = null;
- $mergeParent = is_subclass_of($this, $this->_mergeParent);
- $pluginVars = array();
- $appVars = array();
-
- if (!empty($this->plugin)) {
- $pluginController = $this->plugin . 'AppController';
- if (!is_subclass_of($this, $pluginController)) {
- $pluginController = null;
- }
- $pluginDot = $this->plugin . '.';
- }
-
- if ($pluginController) {
- $merge = array('components', 'helpers');
- $this->_mergeVars($merge, $pluginController);
- }
-
- if ($mergeParent || !empty($pluginController)) {
- $appVars = get_class_vars($this->_mergeParent);
- $uses = $appVars['uses'];
- $merge = array('components', 'helpers');
- $this->_mergeVars($merge, $this->_mergeParent, true);
- }
-
- if ($this->uses === null) {
- $this->uses = false;
- }
- if ($this->uses === true) {
- $this->uses = array($pluginDot . $this->modelClass);
- }
- if (isset($appVars['uses']) && $appVars['uses'] === $this->uses) {
- array_unshift($this->uses, $pluginDot . $this->modelClass);
- }
- if ($pluginController) {
- $pluginVars = get_class_vars($pluginController);
- }
- if ($this->uses !== false) {
- $this->_mergeUses($pluginVars);
- $this->_mergeUses($appVars);
- } else {
- $this->uses = array();
- $this->modelClass = '';
- }
- }
-
-/**
- * Helper method for merging the $uses property together.
- *
- * Merges the elements not already in $this->uses into
- * $this->uses.
- *
- * @param mixed $merge The data to merge in.
- * @return void
- */
- protected function _mergeUses($merge) {
- if (!isset($merge['uses'])) {
- return;
- }
- if ($merge['uses'] === true) {
- return;
- }
- $this->uses = array_merge(
- $this->uses,
- array_diff($merge['uses'], $this->uses)
- );
- }
-
-/**
- * Returns a list of all events that will fire in the controller during it's lifecycle.
- * You can override this function to add you own listener callbacks
- *
- * @return array
- */
- public function implementedEvents() {
- return array(
- 'Controller.initialize' => 'beforeFilter',
- 'Controller.beforeRender' => 'beforeRender',
- 'Controller.beforeRedirect' => array('callable' => 'beforeRedirect', 'passParams' => true),
- 'Controller.shutdown' => 'afterFilter'
- );
- }
-
-/**
- * Loads Model classes based on the uses property
- * see Controller::loadModel(); for more info.
- * Loads Components and prepares them for initialization.
- *
- * @return mixed true if models found and instance created.
- * @see Controller::loadModel()
- * @link http://book.cakephp.org/2.0/en/controllers.html#Controller::constructClasses
- * @throws MissingModelException
- */
- public function constructClasses() {
- $this->_mergeControllerVars();
- $this->Components->init($this);
- if ($this->uses) {
- $this->uses = (array)$this->uses;
- list(, $this->modelClass) = pluginSplit(current($this->uses));
- }
- return true;
- }
-
-/**
- * Returns the CakeEventManager manager instance that is handling any callbacks.
- * You can use this instance to register any new listeners or callbacks to the
- * controller events, or create your own events and trigger them at will.
- *
- * @return CakeEventManager
- */
- public function getEventManager() {
- if (empty($this->_eventManager)) {
- $this->_eventManager = new CakeEventManager();
- $this->_eventManager->attach($this->Components);
- $this->_eventManager->attach($this);
- }
- return $this->_eventManager;
- }
-
-/**
- * Perform the startup process for this controller.
- * Fire the Components and Controller callbacks in the correct order.
- *
- * - Initializes components, which fires their `initialize` callback
- * - Calls the controller `beforeFilter`.
- * - triggers Component `startup` methods.
- *
- * @return void
- */
- public function startupProcess() {
- $this->getEventManager()->dispatch(new CakeEvent('Controller.initialize', $this));
- $this->getEventManager()->dispatch(new CakeEvent('Controller.startup', $this));
- }
-
-/**
- * Perform the various shutdown processes for this controller.
- * Fire the Components and Controller callbacks in the correct order.
- *
- * - triggers the component `shutdown` callback.
- * - calls the Controller's `afterFilter` method.
- *
- * @return void
- */
- public function shutdownProcess() {
- $this->getEventManager()->dispatch(new CakeEvent('Controller.shutdown', $this));
- }
-
-/**
- * Queries & sets valid HTTP response codes & messages.
- *
- * @param mixed $code If $code is an integer, then the corresponding code/message is
- * returned if it exists, null if it does not exist. If $code is an array,
- * then the 'code' and 'message' keys of each nested array are added to the default
- * HTTP codes. Example:
- *
- * httpCodes(404); // returns array(404 => 'Not Found')
- *
- * httpCodes(array(
- * 701 => 'Unicorn Moved',
- * 800 => 'Unexpected Minotaur'
- * )); // sets these new values, and returns true
- *
- * @return mixed Associative array of the HTTP codes as keys, and the message
- * strings as values, or null of the given $code does not exist.
- * @deprecated Use CakeResponse::httpCodes();
- */
- public function httpCodes($code = null) {
- return $this->response->httpCodes($code);
- }
-
-/**
- * Loads and instantiates models required by this controller.
- * If the model is non existent, it will throw a missing database table error, as Cake generates
- * dynamic models for the time being.
- *
- * @param string $modelClass Name of model class to load
- * @param mixed $id Initial ID the instanced model class should have
- * @return mixed true when single model found and instance created, error returned if model not found.
- * @throws MissingModelException if the model class cannot be found.
- */
- public function loadModel($modelClass = null, $id = null) {
- if ($modelClass === null) {
- $modelClass = $this->modelClass;
- }
-
- $this->uses = ($this->uses) ? (array)$this->uses : array();
- if (!in_array($modelClass, $this->uses)) {
- $this->uses[] = $modelClass;
- }
-
- list($plugin, $modelClass) = pluginSplit($modelClass, true);
-
- $this->{$modelClass} = ClassRegistry::init(array(
- 'class' => $plugin . $modelClass, 'alias' => $modelClass, 'id' => $id
- ));
- if (!$this->{$modelClass}) {
- throw new MissingModelException($modelClass);
- }
- return true;
- }
-
-/**
- * Redirects to given $url, after turning off $this->autoRender.
- * Script execution is halted after the redirect.
- *
- * @param mixed $url A string or array-based URL pointing to another location within the app,
- * or an absolute URL
- * @param integer $status Optional HTTP status code (eg: 404)
- * @param boolean $exit If true, exit() will be called after the redirect
- * @return mixed void if $exit = false. Terminates script if $exit = true
- * @link http://book.cakephp.org/2.0/en/controllers.html#Controller::redirect
- */
- public function redirect($url, $status = null, $exit = true) {
- $this->autoRender = false;
-
- if (is_array($status)) {
- extract($status, EXTR_OVERWRITE);
- }
- $event = new CakeEvent('Controller.beforeRedirect', $this, array($url, $status, $exit));
- //TODO: Remove the following line when the events are fully migrated to the CakeEventManager
- list($event->break, $event->breakOn, $event->collectReturn) = array(true, false, true);
- $this->getEventManager()->dispatch($event);
-
- if ($event->isStopped()) {
- return;
- }
- $response = $event->result;
- extract($this->_parseBeforeRedirect($response, $url, $status, $exit), EXTR_OVERWRITE);
-
- if (function_exists('session_write_close')) {
- session_write_close();
- }
-
- if (!empty($status) && is_string($status)) {
- $codes = array_flip($this->response->httpCodes());
- if (isset($codes[$status])) {
- $status = $codes[$status];
- }
- }
-
- if ($url !== null) {
- $this->response->header('Location', Router::url($url, true));
- }
-
- if (!empty($status) && ($status >= 300 && $status < 400)) {
- $this->response->statusCode($status);
- }
-
- if ($exit) {
- $this->response->send();
- $this->_stop();
- }
- }
-
-/**
- * Parse beforeRedirect Response
- *
- * @param mixed $response Response from beforeRedirect callback
- * @param mixed $url The same value of beforeRedirect
- * @param integer $status The same value of beforeRedirect
- * @param boolean $exit The same value of beforeRedirect
- * @return array Array with keys url, status and exit
- */
- protected function _parseBeforeRedirect($response, $url, $status, $exit) {
- if (is_array($response)) {
- foreach ($response as $resp) {
- if (is_array($resp) && isset($resp['url'])) {
- extract($resp, EXTR_OVERWRITE);
- } elseif ($resp !== null) {
- $url = $resp;
- }
- }
- }
- return compact('url', 'status', 'exit');
- }
-
-/**
- * Convenience and object wrapper method for CakeResponse::header().
- *
- * @param string $status The header message that is being set.
- * @return void
- * @deprecated Use CakeResponse::header()
- */
- public function header($status) {
- $this->response->header($status);
- }
-
-/**
- * Saves a variable for use inside a view template.
- *
- * @param mixed $one A string or an array of data.
- * @param mixed $two Value in case $one is a string (which then works as the key).
- * Unused if $one is an associative array, otherwise serves as the values to $one's keys.
- * @return void
- * @link http://book.cakephp.org/2.0/en/controllers.html#interacting-with-views
- */
- public function set($one, $two = null) {
- if (is_array($one)) {
- if (is_array($two)) {
- $data = array_combine($one, $two);
- } else {
- $data = $one;
- }
- } else {
- $data = array($one => $two);
- }
- $this->viewVars = $data + $this->viewVars;
- }
-
-/**
- * Internally redirects one action to another. Does not perform another HTTP request unlike Controller::redirect()
- *
- * Examples:
- *
- * {{{
- * setAction('another_action');
- * setAction('action_with_parameters', $parameter1);
- * }}}
- *
- * @param string $action The new action to be 'redirected' to
- * @param mixed Any other parameters passed to this method will be passed as
- * parameters to the new action.
- * @return mixed Returns the return value of the called action
- */
- public function setAction($action) {
- $this->request->params['action'] = $action;
- $this->view = $action;
- $args = func_get_args();
- unset($args[0]);
- return call_user_func_array(array(&$this, $action), $args);
- }
-
-/**
- * Returns number of errors in a submitted FORM.
- *
- * @return integer Number of errors
- */
- public function validate() {
- $args = func_get_args();
- $errors = call_user_func_array(array(&$this, 'validateErrors'), $args);
-
- if ($errors === false) {
- return 0;
- }
- return count($errors);
- }
-
-/**
- * Validates models passed by parameters. Example:
- *
- * `$errors = $this->validateErrors($this->Article, $this->User);`
- *
- * @param mixed A list of models as a variable argument
- * @return array Validation errors, or false if none
- */
- public function validateErrors() {
- $objects = func_get_args();
-
- if (empty($objects)) {
- return false;
- }
-
- $errors = array();
- foreach ($objects as $object) {
- if (isset($this->{$object->alias})) {
- $object = $this->{$object->alias};
- }
- $object->set($object->data);
- $errors = array_merge($errors, $object->invalidFields());
- }
-
- return $this->validationErrors = (!empty($errors) ? $errors : false);
- }
-
-/**
- * Instantiates the correct view class, hands it its data, and uses it to render the view output.
- *
- * @param string $view View to use for rendering
- * @param string $layout Layout to use
- * @return CakeResponse A response object containing the rendered view.
- * @link http://book.cakephp.org/2.0/en/controllers.html#Controller::render
- */
- public function render($view = null, $layout = null) {
- $event = new CakeEvent('Controller.beforeRender', $this);
- $this->getEventManager()->dispatch($event);
- if ($event->isStopped()) {
- $this->autoRender = false;
- return $this->response;
- }
-
- if (!empty($this->uses) && is_array($this->uses)) {
- foreach ($this->uses as $model) {
- list($plugin, $className) = pluginSplit($model);
- $this->request->params['models'][$className] = compact('plugin', 'className');
- }
- }
-
- $viewClass = $this->viewClass;
- if ($this->viewClass != 'View') {
- list($plugin, $viewClass) = pluginSplit($viewClass, true);
- $viewClass = $viewClass . 'View';
- App::uses($viewClass, $plugin . 'View');
- }
-
- $View = new $viewClass($this);
-
- $models = ClassRegistry::keys();
- foreach ($models as $currentModel) {
- $currentObject = ClassRegistry::getObject($currentModel);
- if (is_a($currentObject, 'Model')) {
- $className = get_class($currentObject);
- list($plugin) = pluginSplit(App::location($className));
- $this->request->params['models'][$currentObject->alias] = compact('plugin', 'className');
- $View->validationErrors[$currentObject->alias] =& $currentObject->validationErrors;
- }
- }
-
- $this->autoRender = false;
- $this->View = $View;
- $this->response->body($View->render($view, $layout));
- return $this->response;
- }
-
-/**
- * Returns the referring URL for this request.
- *
- * @param string $default Default URL to use if HTTP_REFERER cannot be read from headers
- * @param boolean $local If true, restrict referring URLs to local server
- * @return string Referring URL
- * @link http://book.cakephp.org/2.0/en/controllers.html#Controller::referer
- */
- public function referer($default = null, $local = false) {
- if ($this->request) {
- $referer = $this->request->referer($local);
- if ($referer == '/' && $default != null) {
- return Router::url($default, true);
- }
- return $referer;
- }
- return '/';
- }
-
-/**
- * Forces the user's browser not to cache the results of the current request.
- *
- * @return void
- * @link http://book.cakephp.org/2.0/en/controllers.html#Controller::disableCache
- * @deprecated Use CakeResponse::disableCache()
- */
- public function disableCache() {
- $this->response->disableCache();
- }
-
-/**
- * Shows a message to the user for $pause seconds, then redirects to $url.
- * Uses flash.ctp as the default layout for the message.
- * Does not work if the current debug level is higher than 0.
- *
- * @param string $message Message to display to the user
- * @param mixed $url Relative string or array-based URL to redirect to after the time expires
- * @param integer $pause Time to show the message
- * @param string $layout Layout you want to use, defaults to 'flash'
- * @return void Renders flash layout
- * @link http://book.cakephp.org/2.0/en/controllers.html#Controller::flash
- */
- public function flash($message, $url, $pause = 1, $layout = 'flash') {
- $this->autoRender = false;
- $this->set('url', Router::url($url));
- $this->set('message', $message);
- $this->set('pause', $pause);
- $this->set('page_title', $message);
- $this->render(false, $layout);
- }
-
-/**
- * Converts POST'ed form data to a model conditions array, suitable for use in a Model::find() call.
- *
- * @param array $data POST'ed data organized by model and field
- * @param mixed $op A string containing an SQL comparison operator, or an array matching operators
- * to fields
- * @param string $bool SQL boolean operator: AND, OR, XOR, etc.
- * @param boolean $exclusive If true, and $op is an array, fields not included in $op will not be
- * included in the returned conditions
- * @return array An array of model conditions
- * @deprecated
- */
- public function postConditions($data = array(), $op = null, $bool = 'AND', $exclusive = false) {
- if (!is_array($data) || empty($data)) {
- if (!empty($this->request->data)) {
- $data = $this->request->data;
- } else {
- return null;
- }
- }
- $cond = array();
-
- if ($op === null) {
- $op = '';
- }
-
- $arrayOp = is_array($op);
- foreach ($data as $model => $fields) {
- foreach ($fields as $field => $value) {
- $key = $model . '.' . $field;
- $fieldOp = $op;
- if ($arrayOp) {
- if (array_key_exists($key, $op)) {
- $fieldOp = $op[$key];
- } elseif (array_key_exists($field, $op)) {
- $fieldOp = $op[$field];
- } else {
- $fieldOp = false;
- }
- }
- if ($exclusive && $fieldOp === false) {
- continue;
- }
- $fieldOp = strtoupper(trim($fieldOp));
- if ($fieldOp === 'LIKE') {
- $key = $key . ' LIKE';
- $value = '%' . $value . '%';
- } elseif ($fieldOp && $fieldOp != '=') {
- $key = $key . ' ' . $fieldOp;
- }
- $cond[$key] = $value;
- }
- }
- if ($bool != null && strtoupper($bool) != 'AND') {
- $cond = array($bool => $cond);
- }
- return $cond;
- }
-
-/**
- * Handles automatic pagination of model records.
- *
- * @param mixed $object Model to paginate (e.g: model instance, or 'Model', or 'Model.InnerModel')
- * @param mixed $scope Conditions to use while paginating
- * @param array $whitelist List of allowed options for paging
- * @return array Model query results
- * @link http://book.cakephp.org/2.0/en/controllers.html#Controller::paginate
- * @deprecated Use PaginatorComponent instead
- */
- public function paginate($object = null, $scope = array(), $whitelist = array()) {
- return $this->Components->load('Paginator', $this->paginate)->paginate($object, $scope, $whitelist);
- }
-
-/**
- * Called before the controller action. You can use this method to configure and customize components
- * or perform logic that needs to happen before each controller action.
- *
- * @return void
- * @link http://book.cakephp.org/2.0/en/controllers.html#request-life-cycle-callbacks
- */
- public function beforeFilter() {
- }
-
-/**
- * Called after the controller action is run, but before the view is rendered. You can use this method
- * to perform logic or set view variables that are required on every request.
- *
- * @return void
- * @link http://book.cakephp.org/2.0/en/controllers.html#request-life-cycle-callbacks
- */
- public function beforeRender() {
- }
-
-/**
- * The beforeRedirect method is invoked when the controller's redirect method is called but before any
- * further action. If this method returns false the controller will not continue on to redirect the request.
- * The $url, $status and $exit variables have same meaning as for the controller's method. You can also
- * return a string which will be interpreted as the url to redirect to or return associative array with
- * key 'url' and optionally 'status' and 'exit'.
- *
- * @param mixed $url A string or array-based URL pointing to another location within the app,
- * or an absolute URL
- * @param integer $status Optional HTTP status code (eg: 404)
- * @param boolean $exit If true, exit() will be called after the redirect
- * @return mixed
- * false to stop redirection event,
- * string controllers a new redirection url or
- * array with the keys url, status and exit to be used by the redirect method.
- * @link http://book.cakephp.org/2.0/en/controllers.html#request-life-cycle-callbacks
- */
- public function beforeRedirect($url, $status = null, $exit = true) {
- }
-
-/**
- * Called after the controller action is run and rendered.
- *
- * @return void
- * @link http://book.cakephp.org/2.0/en/controllers.html#request-life-cycle-callbacks
- */
- public function afterFilter() {
- }
-
-/**
- * This method should be overridden in child classes.
- *
- * @param string $method name of method called example index, edit, etc.
- * @return boolean Success
- * @link http://book.cakephp.org/2.0/en/controllers.html#callbacks
- */
- public function beforeScaffold($method) {
- return true;
- }
-
-/**
- * Alias to beforeScaffold()
- *
- * @param string $method
- * @return boolean
- * @see Controller::beforeScaffold()
- * @deprecated
- */
- protected function _beforeScaffold($method) {
- return $this->beforeScaffold($method);
- }
-
-/**
- * This method should be overridden in child classes.
- *
- * @param string $method name of method called either edit or update.
- * @return boolean Success
- * @link http://book.cakephp.org/2.0/en/controllers.html#callbacks
- */
- public function afterScaffoldSave($method) {
- return true;
- }
-
-/**
- * Alias to afterScaffoldSave()
- *
- * @param string $method
- * @return boolean
- * @see Controller::afterScaffoldSave()
- * @deprecated
- */
- protected function _afterScaffoldSave($method) {
- return $this->afterScaffoldSave($method);
- }
-
-/**
- * This method should be overridden in child classes.
- *
- * @param string $method name of method called either edit or update.
- * @return boolean Success
- * @link http://book.cakephp.org/2.0/en/controllers.html#callbacks
- */
- public function afterScaffoldSaveError($method) {
- return true;
- }
-
-/**
- * Alias to afterScaffoldSaveError()
- *
- * @param string $method
- * @return boolean
- * @see Controller::afterScaffoldSaveError()
- * @deprecated
- */
- protected function _afterScaffoldSaveError($method) {
- return $this->afterScaffoldSaveError($method);
- }
-
-/**
- * This method should be overridden in child classes.
- * If not it will render a scaffold error.
- * Method MUST return true in child classes
- *
- * @param string $method name of method called example index, edit, etc.
- * @return boolean Success
- * @link http://book.cakephp.org/2.0/en/controllers.html#callbacks
- */
- public function scaffoldError($method) {
- return false;
- }
-
-/**
- * Alias to scaffoldError()
- *
- * @param string $method
- * @return boolean
- * @see Controller::scaffoldError()
- * @deprecated
- */
- protected function _scaffoldError($method) {
- return $this->scaffoldError($method);
- }
-
-}
diff --git a/lib/Cake/Controller/Scaffold.php b/lib/Cake/Controller/Scaffold.php
deleted file mode 100644
index 1d0fd3e1a0f..00000000000
--- a/lib/Cake/Controller/Scaffold.php
+++ /dev/null
@@ -1,447 +0,0 @@
-controller = $controller;
-
- $count = count($this->_passedVars);
- for ($j = 0; $j < $count; $j++) {
- $var = $this->_passedVars[$j];
- $this->{$var} = $controller->{$var};
- }
-
- $this->redirect = array('action' => 'index');
-
- $this->modelClass = $controller->modelClass;
- $this->modelKey = $controller->modelKey;
-
- if (!is_object($this->controller->{$this->modelClass})) {
- throw new MissingModelException($this->modelClass);
- }
-
- $this->ScaffoldModel = $this->controller->{$this->modelClass};
- $this->scaffoldTitle = Inflector::humanize(Inflector::underscore($this->viewPath));
- $this->scaffoldActions = $controller->scaffold;
- $title = __d('cake', 'Scaffold :: ') . Inflector::humanize($request->action) . ' :: ' . $this->scaffoldTitle;
- $modelClass = $this->controller->modelClass;
- $primaryKey = $this->ScaffoldModel->primaryKey;
- $displayField = $this->ScaffoldModel->displayField;
- $singularVar = Inflector::variable($modelClass);
- $pluralVar = Inflector::variable($this->controller->name);
- $singularHumanName = Inflector::humanize(Inflector::underscore($modelClass));
- $pluralHumanName = Inflector::humanize(Inflector::underscore($this->controller->name));
- $scaffoldFields = array_keys($this->ScaffoldModel->schema());
- $associations = $this->_associations();
-
- $this->controller->set(compact(
- 'title_for_layout', 'modelClass', 'primaryKey', 'displayField', 'singularVar', 'pluralVar',
- 'singularHumanName', 'pluralHumanName', 'scaffoldFields', 'associations'
- ));
- $this->controller->set('title_for_layout', $title);
-
- if ($this->controller->viewClass) {
- $this->controller->viewClass = 'Scaffold';
- }
- $this->_validSession = (
- isset($this->controller->Session) && $this->controller->Session->valid() != false
- );
- $this->_scaffold($request);
- }
-
-/**
- * Renders a view action of scaffolded model.
- *
- * @param CakeRequest $request Request Object for scaffolding
- * @return mixed A rendered view of a row from Models database table
- * @throws NotFoundException
- */
- protected function _scaffoldView(CakeRequest $request) {
- if ($this->controller->beforeScaffold('view')) {
- if (isset($request->params['pass'][0])) {
- $this->ScaffoldModel->id = $request->params['pass'][0];
- }
- if (!$this->ScaffoldModel->exists()) {
- throw new NotFoundException(__d('cake', 'Invalid %s', Inflector::humanize($this->modelKey)));
- }
- $this->ScaffoldModel->recursive = 1;
- $this->controller->request->data = $this->ScaffoldModel->read();
- $this->controller->set(
- Inflector::variable($this->controller->modelClass), $this->request->data
- );
- $this->controller->render($this->request['action'], $this->layout);
- } elseif ($this->controller->scaffoldError('view') === false) {
- return $this->_scaffoldError();
- }
- }
-
-/**
- * Renders index action of scaffolded model.
- *
- * @param array $params Parameters for scaffolding
- * @return mixed A rendered view listing rows from Models database table
- */
- protected function _scaffoldIndex($params) {
- if ($this->controller->beforeScaffold('index')) {
- $this->ScaffoldModel->recursive = 0;
- $this->controller->set(
- Inflector::variable($this->controller->name), $this->controller->paginate()
- );
- $this->controller->render($this->request['action'], $this->layout);
- } elseif ($this->controller->scaffoldError('index') === false) {
- return $this->_scaffoldError();
- }
- }
-
-/**
- * Renders an add or edit action for scaffolded model.
- *
- * @param string $action Action (add or edit)
- * @return mixed A rendered view with a form to edit or add a record in the Models database table
- */
- protected function _scaffoldForm($action = 'edit') {
- $this->controller->viewVars['scaffoldFields'] = array_merge(
- $this->controller->viewVars['scaffoldFields'],
- array_keys($this->ScaffoldModel->hasAndBelongsToMany)
- );
- $this->controller->render($action, $this->layout);
- }
-
-/**
- * Saves or updates the scaffolded model.
- *
- * @param CakeRequest $request Request Object for scaffolding
- * @param string $action add or edit
- * @return mixed Success on save/update, add/edit form if data is empty or error if save or update fails
- * @throws NotFoundException
- */
- protected function _scaffoldSave(CakeRequest $request, $action = 'edit') {
- $formAction = 'edit';
- $success = __d('cake', 'updated');
- if ($action === 'add') {
- $formAction = 'add';
- $success = __d('cake', 'saved');
- }
-
- if ($this->controller->beforeScaffold($action)) {
- if ($action == 'edit') {
- if (isset($request->params['pass'][0])) {
- $this->ScaffoldModel->id = $request['pass'][0];
- }
- if (!$this->ScaffoldModel->exists()) {
- throw new NotFoundException(__d('cake', 'Invalid %s', Inflector::humanize($this->modelKey)));
- }
- }
-
- if (!empty($request->data)) {
- if ($action == 'create') {
- $this->ScaffoldModel->create();
- }
-
- if ($this->ScaffoldModel->save($request->data)) {
- if ($this->controller->afterScaffoldSave($action)) {
- $message = __d('cake',
- 'The %1$s has been %2$s',
- Inflector::humanize($this->modelKey),
- $success
- );
- return $this->_sendMessage($message);
- } else {
- return $this->controller->afterScaffoldSaveError($action);
- }
- } else {
- if ($this->_validSession) {
- $this->controller->Session->setFlash(__d('cake', 'Please correct errors below.'));
- }
- }
- }
-
- if (empty($request->data)) {
- if ($this->ScaffoldModel->id) {
- $this->controller->data = $request->data = $this->ScaffoldModel->read();
- } else {
- $this->controller->data = $request->data = $this->ScaffoldModel->create();
- }
- }
-
- foreach ($this->ScaffoldModel->belongsTo as $assocName => $assocData) {
- $varName = Inflector::variable(Inflector::pluralize(
- preg_replace('/(?:_id)$/', '', $assocData['foreignKey'])
- ));
- $this->controller->set($varName, $this->ScaffoldModel->{$assocName}->find('list'));
- }
- foreach ($this->ScaffoldModel->hasAndBelongsToMany as $assocName => $assocData) {
- $varName = Inflector::variable(Inflector::pluralize($assocName));
- $this->controller->set($varName, $this->ScaffoldModel->{$assocName}->find('list'));
- }
-
- return $this->_scaffoldForm($formAction);
- } elseif ($this->controller->scaffoldError($action) === false) {
- return $this->_scaffoldError();
- }
- }
-
-/**
- * Performs a delete on given scaffolded Model.
- *
- * @param CakeRequest $request Request for scaffolding
- * @return mixed Success on delete, error if delete fails
- * @throws MethodNotAllowedException When HTTP method is not a DELETE
- * @throws NotFoundException When id being deleted does not exist.
- */
- protected function _scaffoldDelete(CakeRequest $request) {
- if ($this->controller->beforeScaffold('delete')) {
- if (!$request->is('post')) {
- throw new MethodNotAllowedException();
- }
- $id = false;
- if (isset($request->params['pass'][0])) {
- $id = $request->params['pass'][0];
- }
- $this->ScaffoldModel->id = $id;
- if (!$this->ScaffoldModel->exists()) {
- throw new NotFoundException(__d('cake', 'Invalid %s', Inflector::humanize($this->modelClass)));
- }
- if ($this->ScaffoldModel->delete()) {
- $message = __d('cake', 'The %1$s with id: %2$d has been deleted.', Inflector::humanize($this->modelClass), $id);
- return $this->_sendMessage($message);
- } else {
- $message = __d('cake',
- 'There was an error deleting the %1$s with id: %2$d',
- Inflector::humanize($this->modelClass),
- $id
- );
- return $this->_sendMessage($message);
- }
- } elseif ($this->controller->scaffoldError('delete') === false) {
- return $this->_scaffoldError();
- }
- }
-
-/**
- * Sends a message to the user. Either uses Sessions or flash messages depending
- * on the availability of a session
- *
- * @param string $message Message to display
- * @return void
- */
- protected function _sendMessage($message) {
- if ($this->_validSession) {
- $this->controller->Session->setFlash($message);
- $this->controller->redirect($this->redirect);
- } else {
- $this->controller->flash($message, $this->redirect);
- }
- }
-
-/**
- * Show a scaffold error
- *
- * @return mixed A rendered view showing the error
- */
- protected function _scaffoldError() {
- return $this->controller->render('error', $this->layout);
- }
-
-/**
- * When methods are now present in a controller
- * scaffoldView is used to call default Scaffold methods if:
- * `public $scaffold;` is placed in the controller's class definition.
- *
- * @param CakeRequest $request Request object for scaffolding
- * @return mixed A rendered view of scaffold action, or showing the error
- * @throws MissingActionException When methods are not scaffolded.
- * @throws MissingDatabaseException When the database connection is undefined.
- */
- protected function _scaffold(CakeRequest $request) {
- $db = ConnectionManager::getDataSource($this->ScaffoldModel->useDbConfig);
- $prefixes = Configure::read('Routing.prefixes');
- $scaffoldPrefix = $this->scaffoldActions;
-
- if (isset($db)) {
- if (empty($this->scaffoldActions)) {
- $this->scaffoldActions = array(
- 'index', 'list', 'view', 'add', 'create', 'edit', 'update', 'delete'
- );
- } elseif (!empty($prefixes) && in_array($scaffoldPrefix, $prefixes)) {
- $this->scaffoldActions = array(
- $scaffoldPrefix . '_index',
- $scaffoldPrefix . '_list',
- $scaffoldPrefix . '_view',
- $scaffoldPrefix . '_add',
- $scaffoldPrefix . '_create',
- $scaffoldPrefix . '_edit',
- $scaffoldPrefix . '_update',
- $scaffoldPrefix . '_delete'
- );
- }
-
- if (in_array($request->params['action'], $this->scaffoldActions)) {
- if (!empty($prefixes)) {
- $request->params['action'] = str_replace($scaffoldPrefix . '_', '', $request->params['action']);
- }
- switch ($request->params['action']) {
- case 'index':
- case 'list':
- $this->_scaffoldIndex($request);
- break;
- case 'view':
- $this->_scaffoldView($request);
- break;
- case 'add':
- case 'create':
- $this->_scaffoldSave($request, 'add');
- break;
- case 'edit':
- case 'update':
- $this->_scaffoldSave($request, 'edit');
- break;
- case 'delete':
- $this->_scaffoldDelete($request);
- break;
- }
- } else {
- throw new MissingActionException(array(
- 'controller' => $this->controller->name,
- 'action' => $request->action
- ));
- }
- } else {
- throw new MissingDatabaseException(array('connection' => $this->ScaffoldModel->useDbConfig));
- }
- }
-
-/**
- * Returns associations for controllers models.
- *
- * @return array Associations for model
- */
- protected function _associations() {
- $keys = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
- $associations = array();
-
- foreach ($keys as $key => $type) {
- foreach ($this->ScaffoldModel->{$type} as $assocKey => $assocData) {
- $associations[$type][$assocKey]['primaryKey'] =
- $this->ScaffoldModel->{$assocKey}->primaryKey;
-
- $associations[$type][$assocKey]['displayField'] =
- $this->ScaffoldModel->{$assocKey}->displayField;
-
- $associations[$type][$assocKey]['foreignKey'] =
- $assocData['foreignKey'];
-
- $associations[$type][$assocKey]['controller'] =
- Inflector::pluralize(Inflector::underscore($assocData['className']));
-
- if ($type == 'hasAndBelongsToMany') {
- $associations[$type][$assocKey]['with'] = $assocData['with'];
- }
- }
- }
- return $associations;
- }
-
-}
diff --git a/lib/Cake/Core/App.php b/lib/Cake/Core/App.php
deleted file mode 100644
index e0817462a0e..00000000000
--- a/lib/Cake/Core/App.php
+++ /dev/null
@@ -1,897 +0,0 @@
- array('extends' => null, 'core' => true),
- 'file' => array('extends' => null, 'core' => true),
- 'model' => array('extends' => 'AppModel', 'core' => false),
- 'behavior' => array('suffix' => 'Behavior', 'extends' => 'Model/ModelBehavior', 'core' => true),
- 'controller' => array('suffix' => 'Controller', 'extends' => 'AppController', 'core' => true),
- 'component' => array('suffix' => 'Component', 'extends' => null, 'core' => true),
- 'lib' => array('extends' => null, 'core' => true),
- 'view' => array('suffix' => 'View', 'extends' => null, 'core' => true),
- 'helper' => array('suffix' => 'Helper', 'extends' => 'AppHelper', 'core' => true),
- 'vendor' => array('extends' => null, 'core' => true),
- 'shell' => array('suffix' => 'Shell', 'extends' => 'AppShell', 'core' => true),
- 'plugin' => array('extends' => null, 'core' => true)
- );
-
-/**
- * Paths to search for files.
- *
- * @var array
- */
- public static $search = array();
-
-/**
- * Whether or not to return the file that is loaded.
- *
- * @var boolean
- */
- public static $return = false;
-
-/**
- * Holds key/value pairs of $type => file path.
- *
- * @var array
- */
- protected static $_map = array();
-
-/**
- * Holds and key => value array of object types.
- *
- * @var array
- */
- protected static $_objects = array();
-
-/**
- * Holds the location of each class
- *
- * @var array
- */
- protected static $_classMap = array();
-
-/**
- * Holds the possible paths for each package name
- *
- * @var array
- */
- protected static $_packages = array();
-
-/**
- * Holds the templates for each customizable package path in the application
- *
- * @var array
- */
- protected static $_packageFormat = array();
-
-/**
- * Maps an old style CakePHP class type to the corresponding package
- *
- * @var array
- */
- public static $legacy = array(
- 'models' => 'Model',
- 'behaviors' => 'Model/Behavior',
- 'datasources' => 'Model/Datasource',
- 'controllers' => 'Controller',
- 'components' => 'Controller/Component',
- 'views' => 'View',
- 'helpers' => 'View/Helper',
- 'shells' => 'Console/Command',
- 'libs' => 'Lib',
- 'vendors' => 'Vendor',
- 'plugins' => 'Plugin',
- 'locales' => 'Locale'
- );
-
-/**
- * Indicates whether the class cache should be stored again because of an addition to it
- *
- * @var boolean
- */
- protected static $_cacheChange = false;
-
-/**
- * Indicates whether the object cache should be stored again because of an addition to it
- *
- * @var boolean
- */
- protected static $_objectCacheChange = false;
-
-/**
- * Indicates the the Application is in the bootstrapping process. Used to better cache
- * loaded classes while the cache libraries have not been yet initialized
- *
- * @var boolean
- */
- public static $bootstrapping = false;
-
-/**
- * Used to read information stored path
- *
- * Usage:
- *
- * `App::path('Model'); will return all paths for models`
- *
- * `App::path('Model/Datasource', 'MyPlugin'); will return the path for datasources under the 'MyPlugin' plugin`
- *
- * @param string $type type of path
- * @param string $plugin name of plugin
- * @return array
- * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::path
- */
- public static function path($type, $plugin = null) {
- if (!empty(self::$legacy[$type])) {
- $type = self::$legacy[$type];
- }
-
- if (!empty($plugin)) {
- $path = array();
- $pluginPath = self::pluginPath($plugin);
- $packageFormat = self::_packageFormat();
- if (!empty($packageFormat[$type])) {
- foreach ($packageFormat[$type] as $f) {
- $path[] = sprintf($f, $pluginPath);
- }
- }
- return $path;
- }
-
- if (!isset(self::$_packages[$type])) {
- return array();
- }
- return self::$_packages[$type];
- }
-
-/**
- * Get all the currently loaded paths from App. Useful for inspecting
- * or storing all paths App knows about. For a paths to a specific package
- * use App::path()
- *
- * @return array An array of packages and their associated paths.
- * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::paths
- */
- public static function paths() {
- return self::$_packages;
- }
-
-/**
- * Sets up each package location on the file system. You can configure multiple search paths
- * for each package, those will be used to look for files one folder at a time in the specified order
- * All paths should be terminated with a Directory separator
- *
- * Usage:
- *
- * `App::build(array(Model' => array('/a/full/path/to/models/'))); will setup a new search path for the Model package`
- *
- * `App::build(array('Model' => array('/path/to/models/')), App::RESET); will setup the path as the only valid path for searching models`
- *
- * `App::build(array('View/Helper' => array('/path/to/helpers/', '/another/path/'))); will setup multiple search paths for helpers`
- *
- * `App::build(array('Service' => array('%s' . 'Service' . DS)), App::REGISTER); will register new package 'Service'`
- *
- * If reset is set to true, all loaded plugins will be forgotten and they will be needed to be loaded again.
- *
- * @param array $paths associative array with package names as keys and a list of directories for new search paths
- * @param mixed $mode App::RESET will set paths, App::APPEND with append paths, App::PREPEND will prepend paths (default)
- * App::REGISTER will register new packages and their paths, %s in path will be replaced by APP path
- * @return void
- * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::build
- */
- public static function build($paths = array(), $mode = App::PREPEND) {
- //Provides Backwards compatibility for old-style package names
- $legacyPaths = array();
- foreach ($paths as $type => $path) {
- if (!empty(self::$legacy[$type])) {
- $type = self::$legacy[$type];
- }
- $legacyPaths[$type] = $path;
- }
- $paths = $legacyPaths;
-
- if ($mode === App::RESET) {
- foreach ($paths as $type => $new) {
- self::$_packages[$type] = (array)$new;
- self::objects($type, null, false);
- }
- return;
- }
-
- if (empty($paths)) {
- self::$_packageFormat = null;
- }
-
- $packageFormat = self::_packageFormat();
-
- if ($mode === App::REGISTER) {
- foreach ($paths as $package => $formats) {
- if (empty($packageFormat[$package])) {
- $packageFormat[$package] = $formats;
- } else {
- $formats = array_merge($packageFormat[$package], $formats);
- $packageFormat[$package] = array_values(array_unique($formats));
- }
- }
- self::$_packageFormat = $packageFormat;
- }
-
- $defaults = array();
- foreach ($packageFormat as $package => $format) {
- foreach ($format as $f) {
- $defaults[$package][] = sprintf($f, APP);
- }
- }
-
- if (empty($paths)) {
- self::$_packages = $defaults;
- return;
- }
-
- if ($mode === App::REGISTER) {
- $paths = array();
- }
-
- foreach ($defaults as $type => $default) {
- if (!empty(self::$_packages[$type])) {
- $path = self::$_packages[$type];
- } else {
- $path = $default;
- }
-
- if (!empty($paths[$type])) {
- $newPath = (array)$paths[$type];
-
- if ($mode === App::PREPEND) {
- $path = array_merge($newPath, $path);
- } else {
- $path = array_merge($path, $newPath);
- }
-
- $path = array_values(array_unique($path));
- }
-
- self::$_packages[$type] = $path;
- }
- }
-
-/**
- * Gets the path that a plugin is on. Searches through the defined plugin paths.
- *
- * Usage:
- *
- * `App::pluginPath('MyPlugin'); will return the full path to 'MyPlugin' plugin'`
- *
- * @param string $plugin CamelCased/lower_cased plugin name to find the path of.
- * @return string full path to the plugin.
- * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::pluginPath
- */
- public static function pluginPath($plugin) {
- return CakePlugin::path($plugin);
- }
-
-/**
- * Finds the path that a theme is on. Searches through the defined theme paths.
- *
- * Usage:
- *
- * `App::themePath('MyTheme'); will return the full path to the 'MyTheme' theme`
- *
- * @param string $theme theme name to find the path of.
- * @return string full path to the theme.
- * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::themePath
- */
- public static function themePath($theme) {
- $themeDir = 'Themed' . DS . Inflector::camelize($theme);
- foreach (self::$_packages['View'] as $path) {
- if (is_dir($path . $themeDir)) {
- return $path . $themeDir . DS;
- }
- }
- return self::$_packages['View'][0] . $themeDir . DS;
- }
-
-/**
- * Returns the full path to a package inside the CakePHP core
- *
- * Usage:
- *
- * `App::core('Cache/Engine'); will return the full path to the cache engines package`
- *
- * @param string $type
- * @return array full path to package
- * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::core
- */
- public static function core($type) {
- return array(CAKE . str_replace('/', DS, $type) . DS);
- }
-
-/**
- * Returns an array of objects of the given type.
- *
- * Example usage:
- *
- * `App::objects('plugin');` returns `array('DebugKit', 'Blog', 'User');`
- *
- * `App::objects('Controller');` returns `array('PagesController', 'BlogController');`
- *
- * You can also search only within a plugin's objects by using the plugin dot
- * syntax.
- *
- * `App::objects('MyPlugin.Model');` returns `array('MyPluginPost', 'MyPluginComment');`
- *
- * When scanning directories, files and directories beginning with `.` will be excluded as these
- * are commonly used by version control systems.
- *
- * @param string $type Type of object, i.e. 'Model', 'Controller', 'View/Helper', 'file', 'class' or 'plugin'
- * @param mixed $path Optional Scan only the path given. If null, paths for the chosen type will be used.
- * @param boolean $cache Set to false to rescan objects of the chosen type. Defaults to true.
- * @return mixed Either false on incorrect / miss. Or an array of found objects.
- * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::objects
- */
- public static function objects($type, $path = null, $cache = true) {
- $extension = '/\.php$/';
- $includeDirectories = false;
- $name = $type;
-
- if ($type === 'plugin') {
- $type = 'plugins';
- }
-
- if ($type == 'plugins') {
- $extension = '/.*/';
- $includeDirectories = true;
- }
-
- list($plugin, $type) = pluginSplit($type);
-
- if (isset(self::$legacy[$type . 's'])) {
- $type = self::$legacy[$type . 's'];
- }
-
- if ($type === 'file' && !$path) {
- return false;
- } elseif ($type === 'file') {
- $extension = '/\.php$/';
- $name = $type . str_replace(DS, '', $path);
- }
-
- if (empty(self::$_objects) && $cache === true) {
- self::$_objects = Cache::read('object_map', '_cake_core_');
- }
-
- $cacheLocation = empty($plugin) ? 'app' : $plugin;
-
- if ($cache !== true || !isset(self::$_objects[$cacheLocation][$name])) {
- $objects = array();
-
- if (empty($path)) {
- $path = self::path($type, $plugin);
- }
-
- foreach ((array)$path as $dir) {
- if ($dir != APP && is_dir($dir)) {
- $files = new RegexIterator(new DirectoryIterator($dir), $extension);
- foreach ($files as $file) {
- $fileName = basename($file);
- if (!$file->isDot() && $fileName[0] !== '.') {
- $isDir = $file->isDir();
- if ($isDir && $includeDirectories) {
- $objects[] = $fileName;
- } elseif (!$includeDirectories && !$isDir) {
- $objects[] = substr($fileName, 0, -4);
- }
- }
- }
- }
- }
-
- if ($type !== 'file') {
- foreach ($objects as $key => $value) {
- $objects[$key] = Inflector::camelize($value);
- }
- }
-
- sort($objects);
- if ($plugin) {
- return $objects;
- }
-
- self::$_objects[$cacheLocation][$name] = $objects;
- if ($cache) {
- self::$_objectCacheChange = true;
- }
- }
-
- return self::$_objects[$cacheLocation][$name];
- }
-
-/**
- * Declares a package for a class. This package location will be used
- * by the automatic class loader if the class is tried to be used
- *
- * Usage:
- *
- * `App::uses('MyCustomController', 'Controller');` will setup the class to be found under Controller package
- *
- * `App::uses('MyHelper', 'MyPlugin.View/Helper');` will setup the helper class to be found in plugin's helper package
- *
- * @param string $className the name of the class to configure package for
- * @param string $location the package name
- * @return void
- * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::uses
- */
- public static function uses($className, $location) {
- self::$_classMap[$className] = $location;
- }
-
-/**
- * Method to handle the automatic class loading. It will look for each class' package
- * defined using App::uses() and with this information it will resolve the package name to a full path
- * to load the class from. File name for each class should follow the class name. For instance,
- * if a class is name `MyCustomClass` the file name should be `MyCustomClass.php`
- *
- * @param string $className the name of the class to load
- * @return boolean
- */
- public static function load($className) {
- if (!isset(self::$_classMap[$className])) {
- return false;
- }
-
- $parts = explode('.', self::$_classMap[$className], 2);
- list($plugin, $package) = count($parts) > 1 ? $parts : array(null, current($parts));
-
- if ($file = self::_mapped($className, $plugin)) {
- return include $file;
- }
- $paths = self::path($package, $plugin);
-
- if (empty($plugin)) {
- $appLibs = empty(self::$_packages['Lib']) ? APPLIBS : current(self::$_packages['Lib']);
- $paths[] = $appLibs . $package . DS;
- $paths[] = APP . $package . DS;
- $paths[] = CAKE . $package . DS;
- } else {
- $pluginPath = self::pluginPath($plugin);
- $paths[] = $pluginPath . 'Lib' . DS . $package . DS;
- $paths[] = $pluginPath . $package . DS;
- }
- foreach ($paths as $path) {
- $file = $path . $className . '.php';
- if (file_exists($file)) {
- self::_map($file, $className, $plugin);
- return include $file;
- }
- }
-
- return false;
- }
-
-/**
- * Returns the package name where a class was defined to be located at
- *
- * @param string $className name of the class to obtain the package name from
- * @return string package name or null if not declared
- * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::location
- */
- public static function location($className) {
- if (!empty(self::$_classMap[$className])) {
- return self::$_classMap[$className];
- }
- return null;
- }
-
-/**
- * Finds classes based on $name or specific file(s) to search. Calling App::import() will
- * not construct any classes contained in the files. It will only find and require() the file.
- *
- * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#including-files-with-app-import
- * @param mixed $type The type of Class if passed as a string, or all params can be passed as
- * an single array to $type,
- * @param string $name Name of the Class or a unique name for the file
- * @param mixed $parent boolean true if Class Parent should be searched, accepts key => value
- * array('parent' => $parent ,'file' => $file, 'search' => $search, 'ext' => '$ext');
- * $ext allows setting the extension of the file name
- * based on Inflector::underscore($name) . ".$ext";
- * @param array $search paths to search for files, array('path 1', 'path 2', 'path 3');
- * @param string $file full name of the file to search for including extension
- * @param boolean $return Return the loaded file, the file must have a return
- * statement in it to work: return $variable;
- * @return boolean true if Class is already in memory or if file is found and loaded, false if not
- */
- public static function import($type = null, $name = null, $parent = true, $search = array(), $file = null, $return = false) {
- $ext = null;
-
- if (is_array($type)) {
- extract($type, EXTR_OVERWRITE);
- }
-
- if (is_array($parent)) {
- extract($parent, EXTR_OVERWRITE);
- }
-
- if ($name == null && $file == null) {
- return false;
- }
-
- if (is_array($name)) {
- foreach ($name as $class) {
- if (!App::import(compact('type', 'parent', 'search', 'file', 'return') + array('name' => $class))) {
- return false;
- }
- }
- return true;
- }
-
- $originalType = strtolower($type);
- $specialPackage = in_array($originalType, array('file', 'vendor'));
- if (!$specialPackage && isset(self::$legacy[$originalType . 's'])) {
- $type = self::$legacy[$originalType . 's'];
- }
- list($plugin, $name) = pluginSplit($name);
- if (!empty($plugin)) {
- if (!CakePlugin::loaded($plugin)) {
- return false;
- }
- }
-
- if (!$specialPackage) {
- return self::_loadClass($name, $plugin, $type, $originalType, $parent);
- }
-
- if ($originalType == 'file' && !empty($file)) {
- return self::_loadFile($name, $plugin, $search, $file, $return);
- }
-
- if ($originalType == 'vendor') {
- return self::_loadVendor($name, $plugin, $file, $ext);
- }
-
- return false;
- }
-
-/**
- * Helper function to include classes
- * This is a compatibility wrapper around using App::uses() and automatic class loading
- *
- * @param string $name unique name of the file for identifying it inside the application
- * @param string $plugin camel cased plugin name if any
- * @param string $type name of the packed where the class is located
- * @param string $originalType type name as supplied initially by the user
- * @param boolean $parent whether to load the class parent or not
- * @return boolean true indicating the successful load and existence of the class
- */
- protected static function _loadClass($name, $plugin, $type, $originalType, $parent) {
- if ($type == 'Console/Command' && $name == 'Shell') {
- $type = 'Console';
- } elseif (isset(self::$types[$originalType]['suffix'])) {
- $suffix = self::$types[$originalType]['suffix'];
- $name .= ($suffix == $name) ? '' : $suffix;
- }
- if ($parent && isset(self::$types[$originalType]['extends'])) {
- $extends = self::$types[$originalType]['extends'];
- $extendType = $type;
- if (strpos($extends, '/') !== false) {
- $parts = explode('/', $extends);
- $extends = array_pop($parts);
- $extendType = implode('/', $parts);
- }
- App::uses($extends, $extendType);
- if ($plugin && in_array($originalType, array('controller', 'model'))) {
- App::uses($plugin . $extends, $plugin . '.' . $type);
- }
- }
- if ($plugin) {
- $plugin .= '.';
- }
- $name = Inflector::camelize($name);
- App::uses($name, $plugin . $type);
- return class_exists($name);
- }
-
-/**
- * Helper function to include single files
- *
- * @param string $name unique name of the file for identifying it inside the application
- * @param string $plugin camel cased plugin name if any
- * @param array $search list of paths to search the file into
- * @param string $file filename if known, the $name param will be used otherwise
- * @param boolean $return whether this function should return the contents of the file after being parsed by php or just a success notice
- * @return mixed if $return contents of the file after php parses it, boolean indicating success otherwise
- */
- protected static function _loadFile($name, $plugin, $search, $file, $return) {
- $mapped = self::_mapped($name, $plugin);
- if ($mapped) {
- $file = $mapped;
- } elseif (!empty($search)) {
- foreach ($search as $path) {
- $found = false;
- if (file_exists($path . $file)) {
- $file = $path . $file;
- $found = true;
- break;
- }
- if (empty($found)) {
- $file = false;
- }
- }
- }
- if (!empty($file) && file_exists($file)) {
- self::_map($file, $name, $plugin);
- $returnValue = include $file;
- if ($return) {
- return $returnValue;
- }
- return (bool)$returnValue;
- }
- return false;
- }
-
-/**
- * Helper function to load files from vendors folders
- *
- * @param string $name unique name of the file for identifying it inside the application
- * @param string $plugin camel cased plugin name if any
- * @param string $file file name if known
- * @param string $ext file extension if known
- * @return boolean true if the file was loaded successfully, false otherwise
- */
- protected static function _loadVendor($name, $plugin, $file, $ext) {
- if ($mapped = self::_mapped($name, $plugin)) {
- return (bool)include_once $mapped;
- }
- $fileTries = array();
- $paths = ($plugin) ? App::path('vendors', $plugin) : App::path('vendors');
- if (empty($ext)) {
- $ext = 'php';
- }
- if (empty($file)) {
- $fileTries[] = $name . '.' . $ext;
- $fileTries[] = Inflector::underscore($name) . '.' . $ext;
- } else {
- $fileTries[] = $file;
- }
-
- foreach ($fileTries as $file) {
- foreach ($paths as $path) {
- if (file_exists($path . $file)) {
- self::_map($path . $file, $name, $plugin);
- return (bool)include $path . $file;
- }
- }
- }
- return false;
- }
-
-/**
- * Initializes the cache for App, registers a shutdown function.
- *
- * @return void
- */
- public static function init() {
- self::$_map += (array)Cache::read('file_map', '_cake_core_');
- self::$_objects += (array)Cache::read('object_map', '_cake_core_');
- register_shutdown_function(array('App', 'shutdown'));
- }
-
-/**
- * Maps the $name to the $file.
- *
- * @param string $file full path to file
- * @param string $name unique name for this map
- * @param string $plugin camelized if object is from a plugin, the name of the plugin
- * @return void
- */
- protected static function _map($file, $name, $plugin = null) {
- $key = $name;
- if ($plugin) {
- $key = 'plugin.' . $name;
- }
- if ($plugin && empty(self::$_map[$name])) {
- self::$_map[$key] = $file;
- }
- if (!$plugin && empty(self::$_map['plugin.' . $name])) {
- self::$_map[$key] = $file;
- }
- if (!self::$bootstrapping) {
- self::$_cacheChange = true;
- }
- }
-
-/**
- * Returns a file's complete path.
- *
- * @param string $name unique name
- * @param string $plugin camelized if object is from a plugin, the name of the plugin
- * @return mixed file path if found, false otherwise
- */
- protected static function _mapped($name, $plugin = null) {
- $key = $name;
- if ($plugin) {
- $key = 'plugin.' . $name;
- }
- return isset(self::$_map[$key]) ? self::$_map[$key] : false;
- }
-
-/**
- * Sets then returns the templates for each customizable package path
- *
- * @return array templates for each customizable package path
- */
- protected static function _packageFormat() {
- if (empty(self::$_packageFormat)) {
- self::$_packageFormat = array(
- 'Model' => array(
- '%s' . 'Model' . DS
- ),
- 'Model/Behavior' => array(
- '%s' . 'Model' . DS . 'Behavior' . DS
- ),
- 'Model/Datasource' => array(
- '%s' . 'Model' . DS . 'Datasource' . DS
- ),
- 'Model/Datasource/Database' => array(
- '%s' . 'Model' . DS . 'Datasource' . DS . 'Database' . DS
- ),
- 'Model/Datasource/Session' => array(
- '%s' . 'Model' . DS . 'Datasource' . DS . 'Session' . DS
- ),
- 'Controller' => array(
- '%s' . 'Controller' . DS
- ),
- 'Controller/Component' => array(
- '%s' . 'Controller' . DS . 'Component' . DS
- ),
- 'Controller/Component/Auth' => array(
- '%s' . 'Controller' . DS . 'Component' . DS . 'Auth' . DS
- ),
- 'Controller/Component/Acl' => array(
- '%s' . 'Controller' . DS . 'Component' . DS . 'Acl' . DS
- ),
- 'View' => array(
- '%s' . 'View' . DS
- ),
- 'View/Helper' => array(
- '%s' . 'View' . DS . 'Helper' . DS
- ),
- 'Console' => array(
- '%s' . 'Console' . DS
- ),
- 'Console/Command' => array(
- '%s' . 'Console' . DS . 'Command' . DS
- ),
- 'Console/Command/Task' => array(
- '%s' . 'Console' . DS . 'Command' . DS . 'Task' . DS
- ),
- 'Lib' => array(
- '%s' . 'Lib' . DS
- ),
- 'Locale' => array(
- '%s' . 'Locale' . DS
- ),
- 'Vendor' => array(
- '%s' . 'Vendor' . DS,
- dirname(dirname(CAKE)) . DS . 'vendors' . DS,
- ),
- 'Plugin' => array(
- APP . 'Plugin' . DS,
- dirname(dirname(CAKE)) . DS . 'plugins' . DS
- )
- );
- }
-
- return self::$_packageFormat;
- }
-
-/**
- * Object destructor.
- *
- * Writes cache file if changes have been made to the $_map
- *
- * @return void
- */
- public static function shutdown() {
- if (self::$_cacheChange) {
- Cache::write('file_map', array_filter(self::$_map), '_cake_core_');
- }
- if (self::$_objectCacheChange) {
- Cache::write('object_map', self::$_objects, '_cake_core_');
- }
- }
-
-}
diff --git a/lib/Cake/Core/CakePlugin.php b/lib/Cake/Core/CakePlugin.php
deleted file mode 100644
index 471057b5d5a..00000000000
--- a/lib/Cake/Core/CakePlugin.php
+++ /dev/null
@@ -1,228 +0,0 @@
- true, 'routes' => true))` will load the bootstrap.php and routes.php files
- * `CakePlugin::load('DebugKit', array('bootstrap' => false, 'routes' => true))` will load routes.php file but not bootstrap.php
- * `CakePlugin::load('DebugKit', array('bootstrap' => array('config1', 'config2')))` will load config1.php and config2.php files
- * `CakePlugin::load('DebugKit', array('bootstrap' => 'aCallableMethod'))` will run the aCallableMethod function to initialize it
- *
- * Bootstrap initialization functions can be expressed as a PHP callback type, including closures. Callbacks will receive two
- * parameters (plugin name, plugin configuration)
- *
- * It is also possible to load multiple plugins at once. Examples:
- *
- * `CakePlugin::load(array('DebugKit', 'ApiGenerator'))` will load the DebugKit and ApiGenerator plugins
- * `CakePlugin::load(array('DebugKit', 'ApiGenerator'), array('bootstrap' => true))` will load bootstrap file for both plugins
- *
- * {{{
- * CakePlugin::load(array(
- * 'DebugKit' => array('routes' => true),
- * 'ApiGenerator'
- * ), array('bootstrap' => true))
- * }}}
- *
- * Will only load the bootstrap for ApiGenerator and only the routes for DebugKit
- *
- * @param mixed $plugin name of the plugin to be loaded in CamelCase format or array or plugins to load
- * @param array $config configuration options for the plugin
- * @throws MissingPluginException if the folder for the plugin to be loaded is not found
- * @return void
- */
- public static function load($plugin, $config = array()) {
- if (is_array($plugin)) {
- foreach ($plugin as $name => $conf) {
- list($name, $conf) = (is_numeric($name)) ? array($conf, $config) : array($name, $conf);
- self::load($name, $conf);
- }
- return;
- }
- $config += array('bootstrap' => false, 'routes' => false);
- if (empty($config['path'])) {
- foreach (App::path('plugins') as $path) {
- if (is_dir($path . $plugin)) {
- self::$_plugins[$plugin] = $config + array('path' => $path . $plugin . DS);
- break;
- }
-
- //Backwards compatibility to make easier to migrate to 2.0
- $underscored = Inflector::underscore($plugin);
- if (is_dir($path . $underscored)) {
- self::$_plugins[$plugin] = $config + array('path' => $path . $underscored . DS);
- break;
- }
- }
- } else {
- self::$_plugins[$plugin] = $config;
- }
-
- if (empty(self::$_plugins[$plugin]['path'])) {
- throw new MissingPluginException(array('plugin' => $plugin));
- }
- if (!empty(self::$_plugins[$plugin]['bootstrap'])) {
- self::bootstrap($plugin);
- }
- }
-
-/**
- * Will load all the plugins located in the configured plugins folders
- * If passed an options array, it will be used as a common default for all plugins to be loaded
- * It is possible to set specific defaults for each plugins in the options array. Examples:
- *
- * {{{
- * CakePlugin::loadAll(array(
- * array('bootstrap' => true),
- * 'DebugKit' => array('routes' => true),
- * ))
- * }}}
- *
- * The above example will load the bootstrap file for all plugins, but for DebugKit it will only load the routes file
- * and will not look for any bootstrap script.
- *
- * @param array $options
- * @return void
- */
- public static function loadAll($options = array()) {
- $plugins = App::objects('plugins');
- foreach ($plugins as $p) {
- $opts = isset($options[$p]) ? $options[$p] : null;
- if ($opts === null && isset($options[0])) {
- $opts = $options[0];
- }
- self::load($p, (array)$opts);
- }
- }
-
-/**
- * Returns the filesystem path for a plugin
- *
- * @param string $plugin name of the plugin in CamelCase format
- * @return string path to the plugin folder
- * @throws MissingPluginException if the folder for plugin was not found or plugin has not been loaded
- */
- public static function path($plugin) {
- if (empty(self::$_plugins[$plugin])) {
- throw new MissingPluginException(array('plugin' => $plugin));
- }
- return self::$_plugins[$plugin]['path'];
- }
-
-/**
- * Loads the bootstrapping files for a plugin, or calls the initialization setup in the configuration
- *
- * @param string $plugin name of the plugin
- * @return mixed
- * @see CakePlugin::load() for examples of bootstrap configuration
- */
- public static function bootstrap($plugin) {
- $config = self::$_plugins[$plugin];
- if ($config['bootstrap'] === false) {
- return false;
- }
- if (is_callable($config['bootstrap'])) {
- return call_user_func_array($config['bootstrap'], array($plugin, $config));
- }
-
- $path = self::path($plugin);
- if ($config['bootstrap'] === true) {
- return include $path . 'Config' . DS . 'bootstrap.php';
- }
-
- $bootstrap = (array)$config['bootstrap'];
- foreach ($bootstrap as $file) {
- include $path . 'Config' . DS . $file . '.php';
- }
-
- return true;
- }
-
-/**
- * Loads the routes file for a plugin, or all plugins configured to load their respective routes file
- *
- * @param string $plugin name of the plugin, if null will operate on all plugins having enabled the
- * loading of routes files
- * @return boolean
- */
- public static function routes($plugin = null) {
- if ($plugin === null) {
- foreach (self::loaded() as $p) {
- self::routes($p);
- }
- return true;
- }
- $config = self::$_plugins[$plugin];
- if ($config['routes'] === false) {
- return false;
- }
- return (bool)include self::path($plugin) . 'Config' . DS . 'routes.php';
- }
-
-/**
- * Returns true if the plugin $plugin is already loaded
- * If plugin is null, it will return a list of all loaded plugins
- *
- * @param string $plugin
- * @return mixed boolean true if $plugin is already loaded.
- * If $plugin is null, returns a list of plugins that have been loaded
- */
- public static function loaded($plugin = null) {
- if ($plugin) {
- return isset(self::$_plugins[$plugin]);
- }
- $return = array_keys(self::$_plugins);
- sort($return);
- return $return;
- }
-
-/**
- * Forgets a loaded plugin or all of them if first parameter is null
- *
- * @param string $plugin name of the plugin to forget
- * @return void
- */
- public static function unload($plugin = null) {
- if (is_null($plugin)) {
- self::$_plugins = array();
- } else {
- unset(self::$_plugins[$plugin]);
- }
- }
-
-}
diff --git a/lib/Cake/Core/Configure.php b/lib/Cake/Core/Configure.php
deleted file mode 100644
index 887b2b1e1cd..00000000000
--- a/lib/Cake/Core/Configure.php
+++ /dev/null
@@ -1,365 +0,0 @@
- 0
- );
-
-/**
- * Configured reader classes, used to load config files from resources
- *
- * @var array
- * @see Configure::load()
- */
- protected static $_readers = array();
-
-/**
- * Initializes configure and runs the bootstrap process.
- * Bootstrapping includes the following steps:
- *
- * - Setup App array in Configure.
- * - Include app/Config/core.php.
- * - Configure core cache configurations.
- * - Load App cache files.
- * - Include app/Config/bootstrap.php.
- * - Setup error/exception handlers.
- *
- * @param boolean $boot
- * @return void
- */
- public static function bootstrap($boot = true) {
- if ($boot) {
- self::write('App', array(
- 'base' => false,
- 'baseUrl' => false,
- 'dir' => APP_DIR,
- 'webroot' => WEBROOT_DIR,
- 'www_root' => WWW_ROOT
- ));
-
- if (!include APP . 'Config' . DS . 'core.php') {
- trigger_error(__d('cake_dev', "Can't find application core file. Please create %score.php, and make sure it is readable by PHP.", APP . 'Config' . DS), E_USER_ERROR);
- }
- App::$bootstrapping = false;
- App::init();
- App::build();
-
- $exception = array(
- 'handler' => 'ErrorHandler::handleException',
- );
- $error = array(
- 'handler' => 'ErrorHandler::handleError',
- 'level' => E_ALL & ~E_DEPRECATED,
- );
- self::_setErrorHandlers($error, $exception);
-
- if (!include APP . 'Config' . DS . 'bootstrap.php') {
- trigger_error(__d('cake_dev', "Can't find application bootstrap file. Please create %sbootstrap.php, and make sure it is readable by PHP.", APP . 'Config' . DS), E_USER_ERROR);
- }
- restore_error_handler();
-
- self::_setErrorHandlers(
- self::$_values['Error'],
- self::$_values['Exception']
- );
- unset($error, $exception);
- }
- }
-
-/**
- * Used to store a dynamic variable in Configure.
- *
- * Usage:
- * {{{
- * Configure::write('One.key1', 'value of the Configure::One[key1]');
- * Configure::write(array('One.key1' => 'value of the Configure::One[key1]'));
- * Configure::write('One', array(
- * 'key1' => 'value of the Configure::One[key1]',
- * 'key2' => 'value of the Configure::One[key2]'
- * );
- *
- * Configure::write(array(
- * 'One.key1' => 'value of the Configure::One[key1]',
- * 'One.key2' => 'value of the Configure::One[key2]'
- * ));
- * }}}
- *
- * @link http://book.cakephp.org/2.0/en/development/configuration.html#Configure::write
- * @param array $config Name of var to write
- * @param mixed $value Value to set for var
- * @return boolean True if write was successful
- */
- public static function write($config, $value = null) {
- if (!is_array($config)) {
- $config = array($config => $value);
- }
-
- foreach ($config as $name => $value) {
- $pointer = &self::$_values;
- foreach (explode('.', $name) as $key) {
- $pointer = &$pointer[$key];
- }
- $pointer = $value;
- unset($pointer);
- }
-
- if (isset($config['debug']) && function_exists('ini_set')) {
- if (self::$_values['debug']) {
- ini_set('display_errors', 1);
- } else {
- ini_set('display_errors', 0);
- }
- }
- return true;
- }
-
-/**
- * Used to read information stored in Configure. Its not
- * possible to store `null` values in Configure.
- *
- * Usage:
- * {{{
- * Configure::read('Name'); will return all values for Name
- * Configure::read('Name.key'); will return only the value of Configure::Name[key]
- * }}}
- *
- * @linkhttp://book.cakephp.org/2.0/en/development/configuration.html#Configure::read
- * @param string $var Variable to obtain. Use '.' to access array elements.
- * @return mixed value stored in configure, or null.
- */
- public static function read($var = null) {
- if ($var === null) {
- return self::$_values;
- }
- if (isset(self::$_values[$var])) {
- return self::$_values[$var];
- }
- $pointer = &self::$_values;
- foreach (explode('.', $var) as $key) {
- if (isset($pointer[$key])) {
- $pointer = &$pointer[$key];
- } else {
- return null;
- }
- }
- return $pointer;
- }
-
-/**
- * Used to delete a variable from Configure.
- *
- * Usage:
- * {{{
- * Configure::delete('Name'); will delete the entire Configure::Name
- * Configure::delete('Name.key'); will delete only the Configure::Name[key]
- * }}}
- *
- * @link http://book.cakephp.org/2.0/en/development/configuration.html#Configure::delete
- * @param string $var the var to be deleted
- * @return void
- */
- public static function delete($var = null) {
- $keys = explode('.', $var);
- $last = array_pop($keys);
- $pointer = &self::$_values;
- foreach ($keys as $key) {
- $pointer = &$pointer[$key];
- }
- unset($pointer[$last]);
- }
-
-/**
- * Add a new reader to Configure. Readers allow you to read configuration
- * files in various formats/storage locations. CakePHP comes with two built-in readers
- * PhpReader and IniReader. You can also implement your own reader classes in your application.
- *
- * To add a new reader to Configure:
- *
- * `Configure::config('ini', new IniReader());`
- *
- * @param string $name The name of the reader being configured. This alias is used later to
- * read values from a specific reader.
- * @param ConfigReaderInterface $reader The reader to append.
- * @return void
- */
- public static function config($name, ConfigReaderInterface $reader) {
- self::$_readers[$name] = $reader;
- }
-
-/**
- * Gets the names of the configured reader objects.
- *
- * @param string $name
- * @return array Array of the configured reader objects.
- */
- public static function configured($name = null) {
- if ($name) {
- return isset(self::$_readers[$name]);
- }
- return array_keys(self::$_readers);
- }
-
-/**
- * Remove a configured reader. This will unset the reader
- * and make any future attempts to use it cause an Exception.
- *
- * @param string $name Name of the reader to drop.
- * @return boolean Success
- */
- public static function drop($name) {
- if (!isset(self::$_readers[$name])) {
- return false;
- }
- unset(self::$_readers[$name]);
- return true;
- }
-
-/**
- * Loads stored configuration information from a resource. You can add
- * config file resource readers with `Configure::config()`.
- *
- * Loaded configuration information will be merged with the current
- * runtime configuration. You can load configuration files from plugins
- * by preceding the filename with the plugin name.
- *
- * `Configure::load('Users.user', 'default')`
- *
- * Would load the 'user' config file using the default config reader. You can load
- * app config files by giving the name of the resource you want loaded.
- *
- * `Configure::load('setup', 'default');`
- *
- * If using `default` config and no reader has been configured for it yet,
- * one will be automatically created using PhpReader
- *
- * @link http://book.cakephp.org/2.0/en/development/configuration.html#Configure::load
- * @param string $key name of configuration resource to load.
- * @param string $config Name of the configured reader to use to read the resource identified by $key.
- * @param boolean $merge if config files should be merged instead of simply overridden
- * @return mixed false if file not found, void if load successful.
- * @throws ConfigureException Will throw any exceptions the reader raises.
- */
- public static function load($key, $config = 'default', $merge = true) {
- if (!isset(self::$_readers[$config])) {
- if ($config === 'default') {
- App::uses('PhpReader', 'Configure');
- self::$_readers[$config] = new PhpReader();
- } else {
- return false;
- }
- }
- $values = self::$_readers[$config]->read($key);
-
- if ($merge) {
- $keys = array_keys($values);
- foreach ($keys as $key) {
- if (($c = self::read($key)) && is_array($values[$key]) && is_array($c)) {
- $values[$key] = Set::merge($c, $values[$key]);
- }
- }
- }
-
- return self::write($values);
- }
-
-/**
- * Used to determine the current version of CakePHP.
- *
- * Usage `Configure::version();`
- *
- * @return string Current version of CakePHP
- */
- public static function version() {
- if (!isset(self::$_values['Cake']['version'])) {
- require CAKE . 'Config' . DS . 'config.php';
- self::write($config);
- }
- return self::$_values['Cake']['version'];
- }
-
-/**
- * Used to write runtime configuration into Cache. Stored runtime configuration can be
- * restored using `Configure::restore()`. These methods can be used to enable configuration managers
- * frontends, or other GUI type interfaces for configuration.
- *
- * @param string $name The storage name for the saved configuration.
- * @param string $cacheConfig The cache configuration to save into. Defaults to 'default'
- * @param array $data Either an array of data to store, or leave empty to store all values.
- * @return boolean Success
- */
- public static function store($name, $cacheConfig = 'default', $data = null) {
- if ($data === null) {
- $data = self::$_values;
- }
- return Cache::write($name, $data, $cacheConfig);
- }
-
-/**
- * Restores configuration data stored in the Cache into configure. Restored
- * values will overwrite existing ones.
- *
- * @param string $name Name of the stored config file to load.
- * @param string $cacheConfig Name of the Cache configuration to read from.
- * @return boolean Success.
- */
- public static function restore($name, $cacheConfig = 'default') {
- $values = Cache::read($name, $cacheConfig);
- if ($values) {
- return self::write($values);
- }
- return false;
- }
-
-/**
- * Set the error and exception handlers.
- *
- * @param array $error The Error handling configuration.
- * @param array $exception The exception handling configuration.
- * @return void
- */
- protected static function _setErrorHandlers($error, $exception) {
- $level = -1;
- if (isset($error['level'])) {
- error_reporting($error['level']);
- $level = $error['level'];
- }
- if (!empty($error['handler'])) {
- set_error_handler($error['handler'], $level);
- }
- if (!empty($exception['handler'])) {
- set_exception_handler($exception['handler']);
- }
- }
-}
diff --git a/lib/Cake/Core/Object.php b/lib/Cake/Core/Object.php
deleted file mode 100644
index 34ea4fbe135..00000000000
--- a/lib/Cake/Core/Object.php
+++ /dev/null
@@ -1,205 +0,0 @@
- 0, 'return' => 1, 'bare' => 1, 'requested' => 1), $extra);
- $data = isset($extra['data']) ? $extra['data'] : null;
- unset($extra['data']);
-
- if (is_string($url) && strpos($url, FULL_BASE_URL) === 0) {
- $url = Router::normalize(str_replace(FULL_BASE_URL, '', $url));
- }
- if (is_string($url)) {
- $request = new CakeRequest($url);
- } elseif (is_array($url)) {
- $params = $url + array('pass' => array(), 'named' => array(), 'base' => false);
- $params = array_merge($params, $extra);
- $request = new CakeRequest(Router::reverse($params), false);
- }
- if (isset($data)) {
- $request->data = $data;
- }
- $dispatcher = new Dispatcher();
- $result = $dispatcher->dispatch($request, new CakeResponse(), $extra);
- Router::popRequest();
- return $result;
- }
-
-/**
- * Calls a method on this object with the given parameters. Provides an OO wrapper
- * for `call_user_func_array`
- *
- * @param string $method Name of the method to call
- * @param array $params Parameter list to use when calling $method
- * @return mixed Returns the result of the method call
- */
- public function dispatchMethod($method, $params = array()) {
- switch (count($params)) {
- case 0:
- return $this->{$method}();
- case 1:
- return $this->{$method}($params[0]);
- case 2:
- return $this->{$method}($params[0], $params[1]);
- case 3:
- return $this->{$method}($params[0], $params[1], $params[2]);
- case 4:
- return $this->{$method}($params[0], $params[1], $params[2], $params[3]);
- case 5:
- return $this->{$method}($params[0], $params[1], $params[2], $params[3], $params[4]);
- default:
- return call_user_func_array(array(&$this, $method), $params);
- break;
- }
- }
-
-/**
- * Stop execution of the current script. Wraps exit() making
- * testing easier.
- *
- * @param integer|string $status see http://php.net/exit for values
- * @return void
- */
- protected function _stop($status = 0) {
- exit($status);
- }
-
-/**
- * Convenience method to write a message to CakeLog. See CakeLog::write()
- * for more information on writing to logs.
- *
- * @param string $msg Log message
- * @param integer $type Error type constant. Defined in app/Config/core.php.
- * @return boolean Success of log write
- */
- public function log($msg, $type = LOG_ERROR) {
- App::uses('CakeLog', 'Log');
- if (!is_string($msg)) {
- $msg = print_r($msg, true);
- }
- return CakeLog::write($type, $msg);
- }
-
-/**
- * Allows setting of multiple properties of the object in a single line of code. Will only set
- * properties that are part of a class declaration.
- *
- * @param array $properties An associative array containing properties and corresponding values.
- * @return void
- */
- protected function _set($properties = array()) {
- if (is_array($properties) && !empty($properties)) {
- $vars = get_object_vars($this);
- foreach ($properties as $key => $val) {
- if (array_key_exists($key, $vars)) {
- $this->{$key} = $val;
- }
- }
- }
- }
-
-/**
- * Merges this objects $property with the property in $class' definition.
- * This classes value for the property will be merged on top of $class'
- *
- * This provides some of the DRY magic CakePHP provides. If you want to shut it off, redefine
- * this method as an empty function.
- *
- * @param array $properties The name of the properties to merge.
- * @param string $class The class to merge the property with.
- * @param boolean $normalize Set to true to run the properties through Set::normalize() before merging.
- * @return void
- */
- protected function _mergeVars($properties, $class, $normalize = true) {
- $classProperties = get_class_vars($class);
- foreach ($properties as $var) {
- if (
- isset($classProperties[$var]) &&
- !empty($classProperties[$var]) &&
- is_array($this->{$var}) &&
- $this->{$var} != $classProperties[$var]
- ) {
- if ($normalize) {
- $classProperties[$var] = Set::normalize($classProperties[$var]);
- $this->{$var} = Set::normalize($this->{$var});
- }
- $this->{$var} = Set::merge($classProperties[$var], $this->{$var});
- }
- }
- }
-
-}
diff --git a/lib/Cake/Error/ErrorHandler.php b/lib/Cake/Error/ErrorHandler.php
deleted file mode 100644
index 55c78bebe10..00000000000
--- a/lib/Cake/Error/ErrorHandler.php
+++ /dev/null
@@ -1,228 +0,0 @@
- 1.
- *
- * ### Uncaught exceptions
- *
- * When debug < 1 a CakeException will render 404 or 500 errors. If an uncaught exception is thrown
- * and it is a type that ErrorHandler does not know about it will be treated as a 500 error.
- *
- * ### Implementing application specific exception handling
- *
- * You can implement application specific exception handling in one of a few ways. Each approach
- * gives you different amounts of control over the exception handling process.
- *
- * - Set Configure::write('Exception.handler', 'YourClass::yourMethod');
- * - Create AppController::appError();
- * - Set Configure::write('Exception.renderer', 'YourClass');
- *
- * #### Create your own Exception handler with `Exception.handler`
- *
- * This gives you full control over the exception handling process. The class you choose should be
- * loaded in your app/Config/bootstrap.php, so its available to handle any exceptions. You can
- * define the handler as any callback type. Using Exception.handler overrides all other exception
- * handling settings and logic.
- *
- * #### Using `AppController::appError();`
- *
- * This controller method is called instead of the default exception rendering. It receives the
- * thrown exception as its only argument. You should implement your error handling in that method.
- * Using AppController::appError(), will supersede any configuration for Exception.renderer.
- *
- * #### Using a custom renderer with `Exception.renderer`
- *
- * If you don't want to take control of the exception handling, but want to change how exceptions are
- * rendered you can use `Exception.renderer` to choose a class to render exception pages. By default
- * `ExceptionRenderer` is used. Your custom exception renderer class should be placed in app/Lib/Error.
- *
- * Your custom renderer should expect an exception in its constructor, and implement a render method.
- * Failing to do so will cause additional errors.
- *
- * #### Logging exceptions
- *
- * Using the built-in exception handling, you can log all the exceptions
- * that are dealt with by ErrorHandler by setting `Exception.log` to true in your core.php.
- * Enabling this will log every exception to CakeLog and the configured loggers.
- *
- * ### PHP errors
- *
- * Error handler also provides the built in features for handling php errors (trigger_error).
- * While in debug mode, errors will be output to the screen using debugger. While in production mode,
- * errors will be logged to CakeLog. You can control which errors are logged by setting
- * `Error.level` in your core.php.
- *
- * #### Logging errors
- *
- * When ErrorHandler is used for handling errors, you can enable error logging by setting `Error.log` to true.
- * This will log all errors to the configured log handlers.
- *
- * #### Controlling what errors are logged/displayed
- *
- * You can control which errors are logged / displayed by ErrorHandler by setting `Error.level`. Setting this
- * to one or a combination of a few of the E_* constants will only enable the specified errors.
- *
- * e.g. `Configure::write('Error.level', E_ALL & ~E_NOTICE);`
- *
- * Would enable handling for all non Notice errors.
- *
- * @package Cake.Error
- * @see ExceptionRenderer for more information on how to customize exception rendering.
- */
-class ErrorHandler {
-
-/**
- * Set as the default exception handler by the CakePHP bootstrap process.
- *
- * This will either use custom exception renderer class if configured,
- * or use the default ExceptionRenderer.
- *
- * @param Exception $exception
- * @return void
- * @see http://php.net/manual/en/function.set-exception-handler.php
- */
- public static function handleException(Exception $exception) {
- $config = Configure::read('Exception');
- if (!empty($config['log'])) {
- $message = sprintf("[%s] %s\n%s",
- get_class($exception),
- $exception->getMessage(),
- $exception->getTraceAsString()
- );
- CakeLog::write(LOG_ERR, $message);
- }
- $renderer = $config['renderer'];
- if ($renderer !== 'ExceptionRenderer') {
- list($plugin, $renderer) = pluginSplit($renderer, true);
- App::uses($renderer, $plugin . 'Error');
- }
- try {
- $error = new $renderer($exception);
- $error->render();
- } catch (Exception $e) {
- set_error_handler(Configure::read('Error.handler')); // Should be using configured ErrorHandler
- Configure::write('Error.trace', false); // trace is useless here since it's internal
- $message = sprintf("[%s] %s\n%s", // Keeping same message format
- get_class($e),
- $e->getMessage(),
- $e->getTraceAsString()
- );
- trigger_error($message, E_USER_ERROR);
- }
- }
-
-/**
- * Set as the default error handler by CakePHP. Use Configure::write('Error.handler', $callback), to use your own
- * error handling methods. This function will use Debugger to display errors when debug > 0. And
- * will log errors to CakeLog, when debug == 0.
- *
- * You can use Configure::write('Error.level', $value); to set what type of errors will be handled here.
- * Stack traces for errors can be enabled with Configure::write('Error.trace', true);
- *
- * @param integer $code Code of error
- * @param string $description Error description
- * @param string $file File on which error occurred
- * @param integer $line Line that triggered the error
- * @param array $context Context
- * @return boolean true if error was handled
- */
- public static function handleError($code, $description, $file = null, $line = null, $context = null) {
- if (error_reporting() === 0) {
- return false;
- }
- $errorConfig = Configure::read('Error');
- list($error, $log) = self::mapErrorCode($code);
-
- $debug = Configure::read('debug');
- if ($debug) {
- $data = array(
- 'level' => $log,
- 'code' => $code,
- 'error' => $error,
- 'description' => $description,
- 'file' => $file,
- 'line' => $line,
- 'context' => $context,
- 'start' => 2,
- 'path' => Debugger::trimPath($file)
- );
- return Debugger::getInstance()->outputError($data);
- } else {
- $message = $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']';
- if (!empty($errorConfig['trace'])) {
- $trace = Debugger::trace(array('start' => 1, 'format' => 'log'));
- $message .= "\nTrace:\n" . $trace . "\n";
- }
- return CakeLog::write($log, $message);
- }
- }
-
-/**
- * Map an error code into an Error word, and log location.
- *
- * @param integer $code Error code to map
- * @return array Array of error word, and log location.
- */
- public static function mapErrorCode($code) {
- $error = $log = null;
- switch ($code) {
- case E_PARSE:
- case E_ERROR:
- case E_CORE_ERROR:
- case E_COMPILE_ERROR:
- case E_USER_ERROR:
- $error = 'Fatal Error';
- $log = LOG_ERROR;
- break;
- case E_WARNING:
- case E_USER_WARNING:
- case E_COMPILE_WARNING:
- case E_RECOVERABLE_ERROR:
- $error = 'Warning';
- $log = LOG_WARNING;
- break;
- case E_NOTICE:
- case E_USER_NOTICE:
- $error = 'Notice';
- $log = LOG_NOTICE;
- break;
- case E_STRICT:
- $error = 'Strict';
- $log = LOG_NOTICE;
- break;
- case E_DEPRECATED:
- case E_USER_DEPRECATED:
- $error = 'Deprecated';
- $log = LOG_NOTICE;
- break;
- }
- return array($error, $log);
- }
-
-}
diff --git a/lib/Cake/Error/ExceptionRenderer.php b/lib/Cake/Error/ExceptionRenderer.php
deleted file mode 100644
index 16c57796953..00000000000
--- a/lib/Cake/Error/ExceptionRenderer.php
+++ /dev/null
@@ -1,290 +0,0 @@
- 1.
- * When debug < 1 a CakeException will render 404 or 500 errors. If an uncaught exception is thrown
- * and it is a type that ExceptionHandler does not know about it will be treated as a 500 error.
- *
- * ### Implementing application specific exception rendering
- *
- * You can implement application specific exception handling in one of a few ways:
- *
- * - Create a AppController::appError();
- * - Create a subclass of ExceptionRenderer and configure it to be the `Exception.renderer`
- *
- * #### Using AppController::appError();
- *
- * This controller method is called instead of the default exception handling. It receives the
- * thrown exception as its only argument. You should implement your error handling in that method.
- *
- * #### Using a subclass of ExceptionRenderer
- *
- * Using a subclass of ExceptionRenderer gives you full control over how Exceptions are rendered, you
- * can configure your class in your core.php, with `Configure::write('Exception.renderer', 'MyClass');`
- * You should place any custom exception renderers in `app/Lib/Error`.
- *
- * @package Cake.Error
- */
-class ExceptionRenderer {
-
-/**
- * Controller instance.
- *
- * @var Controller
- */
- public $controller = null;
-
-/**
- * template to render for CakeException
- *
- * @var string
- */
- public $template = '';
-
-/**
- * The method corresponding to the Exception this object is for.
- *
- * @var string
- */
- public $method = '';
-
-/**
- * The exception being handled.
- *
- * @var Exception
- */
- public $error = null;
-
-/**
- * Creates the controller to perform rendering on the error response.
- * If the error is a CakeException it will be converted to either a 400 or a 500
- * code error depending on the code used to construct the error.
- *
- * @param Exception $exception Exception
- */
- public function __construct(Exception $exception) {
- $this->controller = $this->_getController($exception);
-
- if (method_exists($this->controller, 'apperror')) {
- return $this->controller->appError($exception);
- }
- $method = $template = Inflector::variable(str_replace('Exception', '', get_class($exception)));
- $code = $exception->getCode();
-
- $methodExists = method_exists($this, $method);
-
- if ($exception instanceof CakeException && !$methodExists) {
- $method = '_cakeError';
- if (empty($template)) {
- $template = 'error500';
- }
- if ($template == 'internalError') {
- $template = 'error500';
- }
- } elseif ($exception instanceof PDOException) {
- $method = 'pdoError';
- $template = 'pdo_error';
- $code = 500;
- } elseif (!$methodExists) {
- $method = 'error500';
- if ($code >= 400 && $code < 500) {
- $method = 'error400';
- }
- }
-
- if (Configure::read('debug') == 0) {
- if ($method == '_cakeError') {
- $method = 'error400';
- }
- if ($code == 500) {
- $method = 'error500';
- }
- }
- $this->template = $template;
- $this->method = $method;
- $this->error = $exception;
- }
-
-/**
- * Get the controller instance to handle the exception.
- * Override this method in subclasses to customize the controller used.
- * This method returns the built in `CakeErrorController` normally, or if an error is repeated
- * a bare controller will be used.
- *
- * @param Exception $exception The exception to get a controller for.
- * @return Controller
- */
- protected function _getController($exception) {
- App::uses('CakeErrorController', 'Controller');
- if (!$request = Router::getRequest(false)) {
- $request = new CakeRequest();
- }
- $response = new CakeResponse(array('charset' => Configure::read('App.encoding')));
- try {
- $controller = new CakeErrorController($request, $response);
- } catch (Exception $e) {
- $controller = new Controller($request, $response);
- $controller->viewPath = 'Errors';
- }
- return $controller;
- }
-
-/**
- * Renders the response for the exception.
- *
- * @return void
- */
- public function render() {
- if ($this->method) {
- call_user_func_array(array($this, $this->method), array($this->error));
- }
- }
-
-/**
- * Generic handler for the internal framework errors CakePHP can generate.
- *
- * @param CakeException $error
- * @return void
- */
- protected function _cakeError(CakeException $error) {
- $url = $this->controller->request->here();
- $code = ($error->getCode() >= 400 && $error->getCode() < 506) ? $error->getCode() : 500;
- $this->controller->response->statusCode($code);
- $this->controller->set(array(
- 'code' => $code,
- 'url' => h($url),
- 'name' => $error->getMessage(),
- 'error' => $error,
- '_serialize' => array('code', 'url', 'name')
- ));
- $this->controller->set($error->getAttributes());
- $this->_outputMessage($this->template);
- }
-
-/**
- * Convenience method to display a 400 series page.
- *
- * @param Exception $error
- * @return void
- */
- public function error400($error) {
- $message = $error->getMessage();
- if (Configure::read('debug') == 0 && $error instanceof CakeException) {
- $message = __d('cake', 'Not Found');
- }
- $url = $this->controller->request->here();
- $this->controller->response->statusCode($error->getCode());
- $this->controller->set(array(
- 'name' => $message,
- 'url' => h($url),
- 'error' => $error,
- '_serialize' => array('name', 'url')
- ));
- $this->_outputMessage('error400');
- }
-
-/**
- * Convenience method to display a 500 page.
- *
- * @param Exception $error
- * @return void
- */
- public function error500($error) {
- $message = $error->getMessage();
- if (Configure::read('debug') == 0) {
- $message = __d('cake', 'An Internal Error Has Occurred.');
- }
- $url = $this->controller->request->here();
- $code = ($error->getCode() > 500 && $error->getCode() < 506) ? $error->getCode() : 500;
- $this->controller->response->statusCode($code);
- $this->controller->set(array(
- 'name' => $message,
- 'message' => h($url),
- 'error' => $error,
- '_serialize' => array('name', 'message')
- ));
- $this->_outputMessage('error500');
- }
-
-/**
- * Convenience method to display a PDOException.
- *
- * @param PDOException $error
- * @return void
- */
- public function pdoError(PDOException $error) {
- $url = $this->controller->request->here();
- $code = 500;
- $this->controller->response->statusCode($code);
- $this->controller->set(array(
- 'code' => $code,
- 'url' => h($url),
- 'name' => $error->getMessage(),
- 'error' => $error,
- '_serialize' => array('code', 'url', 'name', 'error')
- ));
- $this->_outputMessage($this->template);
- }
-
-/**
- * Generate the response using the controller object.
- *
- * @param string $template The template to render.
- * @return void
- */
- protected function _outputMessage($template) {
- try {
- $this->controller->render($template);
- $this->controller->afterFilter();
- $this->controller->response->send();
- } catch (Exception $e) {
- $this->_outputMessageSafe('error500');
- }
- }
-
-/**
- * A safer way to render error messages, replaces all helpers, with basics
- * and doesn't call component methods.
- *
- * @param string $template The template to render
- * @return void
- */
- protected function _outputMessageSafe($template) {
- $this->controller->layoutPath = '';
- $this->controller->subDir = '';
- $this->controller->viewPath = 'Errors/';
- $this->controller->viewClass = 'View';
- $this->controller->helpers = array('Form', 'Html', 'Session');
-
- $this->controller->render($template);
- $this->controller->response->type('html');
- $this->controller->response->send();
- }
-
-}
diff --git a/lib/Cake/Error/exceptions.php b/lib/Cake/Error/exceptions.php
deleted file mode 100644
index 6b6d1e26bfd..00000000000
--- a/lib/Cake/Error/exceptions.php
+++ /dev/null
@@ -1,519 +0,0 @@
-_attributes = $message;
- $message = __d('cake_dev', $this->_messageTemplate, $message);
- }
- parent::__construct($message, $code);
- }
-
-/**
- * Get the passed in attributes
- *
- * @return array
- */
- public function getAttributes() {
- return $this->_attributes;
- }
-
-}
-
-/**
- * Missing Controller exception - used when a controller
- * cannot be found.
- *
- * @package Cake.Error
- */
-class MissingControllerException extends CakeException {
-
- protected $_messageTemplate = 'Controller class %s could not be found.';
-
- public function __construct($message, $code = 404) {
- parent::__construct($message, $code);
- }
-
-}
-
-/**
- * Missing Action exception - used when a controller action
- * cannot be found.
- *
- * @package Cake.Error
- */
-class MissingActionException extends CakeException {
-
- protected $_messageTemplate = 'Action %s::%s() could not be found.';
-
- public function __construct($message, $code = 404) {
- parent::__construct($message, $code);
- }
-
-}
-
-/**
- * Private Action exception - used when a controller action
- * starts with a `_`.
- *
- * @package Cake.Error
- */
-class PrivateActionException extends CakeException {
-
- protected $_messageTemplate = 'Private Action %s::%s() is not directly accessible.';
-
- public function __construct($message, $code = 404, Exception $previous = null) {
- parent::__construct($message, $code, $previous);
- }
-
-}
-
-/**
- * Used when a component cannot be found.
- *
- * @package Cake.Error
- */
-class MissingComponentException extends CakeException {
-
- protected $_messageTemplate = 'Component class %s could not be found.';
-
-}
-
-/**
- * Used when a behavior cannot be found.
- *
- * @package Cake.Error
- */
-class MissingBehaviorException extends CakeException {
-
- protected $_messageTemplate = 'Behavior class %s could not be found.';
-
-}
-
-/**
- * Used when a view file cannot be found.
- *
- * @package Cake.Error
- */
-class MissingViewException extends CakeException {
-
- protected $_messageTemplate = 'View file "%s" is missing.';
-
-}
-
-/**
- * Used when a layout file cannot be found.
- *
- * @package Cake.Error
- */
-class MissingLayoutException extends CakeException {
-
- protected $_messageTemplate = 'Layout file "%s" is missing.';
-
-}
-
-/**
- * Used when a helper cannot be found.
- *
- * @package Cake.Error
- */
-class MissingHelperException extends CakeException {
-
- protected $_messageTemplate = 'Helper class %s could not be found.';
-
-}
-
-/**
- * Runtime Exceptions for ConnectionManager
- *
- * @package Cake.Error
- */
-class MissingDatabaseException extends CakeException {
-
- protected $_messageTemplate = 'Database connection "%s" could not be found.';
-
-}
-
-/**
- * Used when no connections can be found.
- *
- * @package Cake.Error
- */
-class MissingConnectionException extends CakeException {
-
- protected $_messageTemplate = 'Database connection "%s" is missing, or could not be created.';
-
-}
-
-/**
- * Used when a Task cannot be found.
- *
- * @package Cake.Error
- */
-class MissingTaskException extends CakeException {
-
- protected $_messageTemplate = 'Task class %s could not be found.';
-
-}
-
-/**
- * Used when a shell method cannot be found.
- *
- * @package Cake.Error
- */
-class MissingShellMethodException extends CakeException {
-
- protected $_messageTemplate = "Unknown command %1\$s %2\$s.\nFor usage try `cake %1\$s --help`";
-
-}
-
-/**
- * Used when a shell cannot be found.
- *
- * @package Cake.Error
- */
-class MissingShellException extends CakeException {
-
- protected $_messageTemplate = 'Shell class %s could not be found.';
-
-}
-
-/**
- * Exception class to be thrown when a datasource configuration is not found
- *
- * @package Cake.Error
- */
-class MissingDatasourceConfigException extends CakeException {
-
- protected $_messageTemplate = 'The datasource configuration "%s" was not found in database.php';
-
-}
-
-/**
- * Used when a datasource cannot be found.
- *
- * @package Cake.Error
- */
-class MissingDatasourceException extends CakeException {
-
- protected $_messageTemplate = 'Datasource class %s could not be found.';
-
-}
-
-/**
- * Exception class to be thrown when a database table is not found in the datasource
- *
- * @package Cake.Error
- */
-class MissingTableException extends CakeException {
-
- protected $_messageTemplate = 'Table %s for model %s was not found in datasource %s.';
-
-}
-
-/**
- * Exception raised when a Model could not be found.
- *
- * @package Cake.Error
- */
-class MissingModelException extends CakeException {
-
- protected $_messageTemplate = 'Model %s could not be found.';
-
-}
-
-/**
- * Exception raised when a test loader could not be found
- *
- * @package Cake.Error
- */
-class MissingTestLoaderException extends CakeException {
-
- protected $_messageTemplate = 'Test loader %s could not be found.';
-
-}
-
-/**
- * Exception raised when a plugin could not be found
- *
- * @package Cake.Error
- */
-class MissingPluginException extends CakeException {
-
- protected $_messageTemplate = 'Plugin %s could not be found.';
-
-}
-
-/**
- * Exception class for AclComponent and Interface implementations.
- *
- * @package Cake.Error
- */
-class AclException extends CakeException {
-}
-
-/**
- * Exception class for Cache. This exception will be thrown from Cache when it
- * encounters an error.
- *
- * @package Cake.Error
- */
-class CacheException extends CakeException {
-}
-
-/**
- * Exception class for Router. This exception will be thrown from Router when it
- * encounters an error.
- *
- * @package Cake.Error
- */
-class RouterException extends CakeException {
-}
-
-/**
- * Exception class for CakeLog. This exception will be thrown from CakeLog when it
- * encounters an error.
- *
- * @package Cake.Error
- */
-class CakeLogException extends CakeException {
-}
-
-/**
- * Exception class for CakeSession. This exception will be thrown from CakeSession when it
- * encounters an error.
- *
- * @package Cake.Error
- */
-class CakeSessionException extends CakeException {
-}
-
-/**
- * Exception class for Configure. This exception will be thrown from Configure when it
- * encounters an error.
- *
- * @package Cake.Error
- */
-class ConfigureException extends CakeException {
-}
-
-/**
- * Exception class for Socket. This exception will be thrown from CakeSocket, CakeEmail, HttpSocket
- * SmtpTransport, MailTransport and HttpResponse when it encounters an error.
- *
- * @package Cake.Error
- */
-class SocketException extends CakeException {
-}
-
-/**
- * Exception class for Xml. This exception will be thrown from Xml when it
- * encounters an error.
- *
- * @package Cake.Error
- */
-class XmlException extends CakeException {
-}
-
-/**
- * Exception class for Console libraries. This exception will be thrown from Console library
- * classes when they encounter an error.
- *
- * @package Cake.Error
- */
-class ConsoleException extends CakeException {
-}
diff --git a/lib/Cake/Event/CakeEvent.php b/lib/Cake/Event/CakeEvent.php
deleted file mode 100644
index 52de3cf2346..00000000000
--- a/lib/Cake/Event/CakeEvent.php
+++ /dev/null
@@ -1,132 +0,0 @@
- $userData));
- * $event = new CakeEvent('User.afterRegister', $UserModel);
- * }}}
- *
- */
- public function __construct($name, $subject = null, $data = null) {
- $this->_name = $name;
- $this->data = $data;
- $this->_subject = $subject;
- }
-
-/**
- * Dynamically returns the name and subject if accessed directly
- *
- * @param string $attribute
- * @return mixed
- */
- public function __get($attribute) {
- if ($attribute === 'name' || $attribute === 'subject') {
- return $this->{$attribute}();
- }
- }
-
-/**
- * Returns the name of this event. This is usually used as the event identifier
- *
- * @return string
- */
- public function name() {
- return $this->_name;
- }
-
-/**
- * Returns the subject of this event
- *
- * @return string
- */
- public function subject() {
- return $this->_subject;
- }
-
-/**
- * Stops the event from being used anymore
- *
- * @return void
- */
- public function stopPropagation() {
- return $this->_stopped = true;
- }
-
-/**
- * Check if the event is stopped
- *
- * @return boolean True if the event is stopped
- */
- public function isStopped() {
- return $this->_stopped;
- }
-
-}
diff --git a/lib/Cake/Event/CakeEventListener.php b/lib/Cake/Event/CakeEventListener.php
deleted file mode 100644
index c4915949db1..00000000000
--- a/lib/Cake/Event/CakeEventListener.php
+++ /dev/null
@@ -1,48 +0,0 @@
- 'sendEmail',
- * 'Article.afterBuy' => 'decrementInventory',
- * 'User.onRegister' => array('callable' => 'logRegistration', 'priority' => 20, 'passParams' => true)
- * );
- * }
- * }}}
- *
- * @return array associative array or event key names pointing to the function
- * that should be called in the object when the respective event is fired
- */
- public function implementedEvents();
-
-}
diff --git a/lib/Cake/Event/CakeEventManager.php b/lib/Cake/Event/CakeEventManager.php
deleted file mode 100644
index 10e657f6f4f..00000000000
--- a/lib/Cake/Event/CakeEventManager.php
+++ /dev/null
@@ -1,276 +0,0 @@
-_isGlobal = true;
- return self::$_generalManager;
- }
-
-/**
- * Adds a new listener to an event. Listeners
- *
- * @param callback|CakeEventListener $callable PHP valid callback type or instance of CakeEventListener to be called
- * when the event named with $eventKey is triggered. If a CakeEventListener instances is passed, then the `implementedEvents`
- * method will be called on the object to register the declared events individually as methods to be managed by this class.
- * It is possible to define multiple event handlers per event name.
- *
- * @param mixed $eventKey The event unique identifier name to with the callback will be associated. If $callable
- * is an instance of CakeEventListener this argument will be ignored
- *
- * @param array $options used to set the `priority` and `passParams` flags to the listener.
- * Priorities are handled like queues, and multiple attachments into the same priority queue will be treated in
- * the order of insertion. `passParams` means that the event data property will be converted to function arguments
- * when the listener is called. If $called is an instance of CakeEventListener, this parameter will be ignored
- *
- * @return void
- * @throws InvalidArgumentException When event key is missing or callable is not an
- * instance of CakeEventListener.
- */
- public function attach($callable, $eventKey = null, $options = array()) {
- if (!$eventKey && !($callable instanceof CakeEventListener)) {
- throw new InvalidArgumentException(__d('cake_dev', 'The eventKey variable is required'));
- }
- if ($callable instanceof CakeEventListener) {
- $this->_attachSubscriber($callable);
- return;
- }
- $options = $options + array('priority' => self::$defaultPriority, 'passParams' => false);
- $this->_listeners[$eventKey][$options['priority']][] = array(
- 'callable' => $callable,
- 'passParams' => $options['passParams'],
- );
- }
-
-/**
- * Auxiliary function to attach all implemented callbacks of a CakeEventListener class instance
- * as individual methods on this manager
- *
- * @param CakeEventListener $subscriber
- * @return void
- */
- protected function _attachSubscriber(CakeEventListener $subscriber) {
- foreach ($subscriber->implementedEvents() as $eventKey => $function) {
- $options = array();
- $method = $function;
- if (is_array($function) && isset($function['callable'])) {
- list($method, $options) = $this->_extractCallable($function, $subscriber);
- } elseif (is_array($function) && is_numeric(key($function))) {
- foreach ($function as $f) {
- list($method, $options) = $this->_extractCallable($f, $subscriber);
- $this->attach($method, $eventKey, $options);
- }
- continue;
- }
- if (is_string($method)) {
- $method = array($subscriber, $function);
- }
- $this->attach($method, $eventKey, $options);
- }
- }
-
-/**
- * Auxiliary function to extract and return a PHP callback type out of the callable definition
- * from the return value of the `implementedEvents` method on a CakeEventListener
- *
- * @param array $function the array taken from a handler definition for a event
- * @param CakeEventListener $object The handler object
- * @return callback
- */
- protected function _extractCallable($function, $object) {
- $method = $function['callable'];
- $options = $function;
- unset($options['callable']);
- if (is_string($method)) {
- $method = array($object, $method);
- }
- return array($method, $options);
- }
-
-/**
- * Removes a listener from the active listeners.
- *
- * @param callback|CakeEventListener $callable any valid PHP callback type or an instance of CakeEventListener
- * @return void
- */
- public function detach($callable, $eventKey = null) {
- if ($callable instanceof CakeEventListener) {
- return $this->_detachSubscriber($callable, $eventKey);
- }
- if (empty($eventKey)) {
- foreach (array_keys($this->_listeners) as $eventKey) {
- $this->detach($callable, $eventKey);
- }
- return;
- }
- if (empty($this->_listeners[$eventKey])) {
- return;
- }
- foreach ($this->_listeners[$eventKey] as $priority => $callables) {
- foreach ($callables as $k => $callback) {
- if ($callback['callable'] === $callable) {
- unset($this->_listeners[$eventKey][$priority][$k]);
- break;
- }
- }
- }
- }
-
-/**
- * Auxiliary function to help detach all listeners provided by an object implementing CakeEventListener
- *
- * @param CakeEventListener $subscriber the subscriber to be detached
- * @param string $eventKey optional event key name to unsubscribe the listener from
- * @return void
- */
- protected function _detachSubscriber(CakeEventListener $subscriber, $eventKey = null) {
- $events = $subscriber->implementedEvents();
- if (!empty($eventKey) && empty($events[$eventKey])) {
- return;
- } elseif (!empty($eventKey)) {
- $events = array($eventKey => $events[$eventKey]);
- }
- foreach ($events as $key => $function) {
- if (is_array($function)) {
- if (is_numeric(key($function))) {
- foreach ($function as $handler) {
- $handler = isset($handler['callable']) ? $handler['callable'] : $handler;
- $this->detach(array($subscriber, $handler), $key);
- }
- continue;
- }
- $function = $function['callable'];
- }
- $this->detach(array($subscriber, $function), $key);
- }
- }
-
-/**
- * Dispatches a new event to all configured listeners
- *
- * @param mixed $event the event key name or instance of CakeEvent
- * @return void
- */
- public function dispatch($event) {
- if (is_string($event)) {
- $event = new CakeEvent($event);
- }
-
- if (!$this->_isGlobal) {
- self::instance()->dispatch($event);
- }
-
- if (empty($this->_listeners[$event->name()])) {
- return;
- }
-
- foreach ($this->listeners($event->name()) as $listener) {
- if ($event->isStopped()) {
- break;
- }
- if ($listener['passParams'] === true) {
- $result = call_user_func_array($listener['callable'], $event->data);
- } else {
- $result = call_user_func($listener['callable'], $event);
- }
- if ($result === false) {
- $event->stopPropagation();
- }
- if ($result !== null) {
- $event->result = $result;
- }
- continue;
- }
- }
-
-/**
- * Returns a list of all listeners for a eventKey in the order they should be called
- *
- * @param string $eventKey
- * @return array
- */
- public function listeners($eventKey) {
- if (empty($this->_listeners[$eventKey])) {
- return array();
- }
- ksort($this->_listeners[$eventKey]);
- $result = array();
- foreach ($this->_listeners[$eventKey] as $priorityQ) {
- $result = array_merge($result, $priorityQ);
- }
- return $result;
- }
-
-}
diff --git a/lib/Cake/I18n/I18n.php b/lib/Cake/I18n/I18n.php
deleted file mode 100644
index 856f8f82461..00000000000
--- a/lib/Cake/I18n/I18n.php
+++ /dev/null
@@ -1,631 +0,0 @@
-l10n = new L10n();
- }
-
-/**
- * Return a static instance of the I18n class
- *
- * @return I18n
- */
- public static function &getInstance() {
- static $instance = array();
- if (!$instance) {
- $instance[0] = new I18n();
- }
- return $instance[0];
- }
-
-/**
- * Used by the translation functions in basics.php
- * Returns a translated string based on current language and translation files stored in locale folder
- *
- * @param string $singular String to translate
- * @param string $plural Plural string (if any)
- * @param string $domain Domain The domain of the translation. Domains are often used by plugin translations
- * @param string $category Category The integer value of the category to use.
- * @param integer $count Count Count is used with $plural to choose the correct plural form.
- * @param string $language Language to translate string to.
- * If null it checks for language in session followed by Config.language configuration variable.
- * @return string translated string.
- */
- public static function translate($singular, $plural = null, $domain = null, $category = 6, $count = null, $language = null) {
- $_this = I18n::getInstance();
-
- if (strpos($singular, "\r\n") !== false) {
- $singular = str_replace("\r\n", "\n", $singular);
- }
- if ($plural !== null && strpos($plural, "\r\n") !== false) {
- $plural = str_replace("\r\n", "\n", $plural);
- }
-
- if (is_numeric($category)) {
- $_this->category = $_this->_categories[$category];
- }
-
- if (empty($language)) {
- if (!empty($_SESSION['Config']['language'])) {
- $language = $_SESSION['Config']['language'];
- } else {
- $language = Configure::read('Config.language');
- }
- }
-
- if (($_this->_lang && $_this->_lang !== $language) || !$_this->_lang) {
- $lang = $_this->l10n->get($language);
- $_this->_lang = $lang;
- }
-
- if (is_null($domain)) {
- $domain = self::$defaultDomain;
- }
-
- $_this->domain = $domain . '_' . $_this->l10n->lang;
-
- if (!isset($_this->_domains[$domain][$_this->_lang])) {
- $_this->_domains[$domain][$_this->_lang] = Cache::read($_this->domain, '_cake_core_');
- }
-
- if (!isset($_this->_domains[$domain][$_this->_lang][$_this->category])) {
- $_this->_bindTextDomain($domain);
- Cache::write($_this->domain, $_this->_domains[$domain][$_this->_lang], '_cake_core_');
- }
-
- if ($_this->category == 'LC_TIME') {
- return $_this->_translateTime($singular, $domain);
- }
-
- if (!isset($count)) {
- $plurals = 0;
- } elseif (!empty($_this->_domains[$domain][$_this->_lang][$_this->category]["%plural-c"]) && $_this->_noLocale === false) {
- $header = $_this->_domains[$domain][$_this->_lang][$_this->category]["%plural-c"];
- $plurals = $_this->_pluralGuess($header, $count);
- } else {
- if ($count != 1) {
- $plurals = 1;
- } else {
- $plurals = 0;
- }
- }
-
- if (!empty($_this->_domains[$domain][$_this->_lang][$_this->category][$singular])) {
- if (($trans = $_this->_domains[$domain][$_this->_lang][$_this->category][$singular]) || ($plurals) && ($trans = $_this->_domains[$domain][$_this->_lang][$_this->category][$plural])) {
- if (is_array($trans)) {
- if (isset($trans[$plurals])) {
- $trans = $trans[$plurals];
- } else {
- trigger_error(
- __d('cake_dev',
- 'Missing plural form translation for "%s" in "%s" domain, "%s" locale. ' .
- ' Check your po file for correct plurals and valid Plural-Forms header.',
- $singular,
- $domain,
- $_this->_lang
- ),
- E_USER_WARNING
- );
- $trans = $trans[0];
- }
- }
- if (strlen($trans)) {
- return $trans;
- }
- }
- }
-
- if (!empty($plurals)) {
- return $plural;
- }
- return $singular;
- }
-
-/**
- * Clears the domains internal data array. Useful for testing i18n.
- *
- * @return void
- */
- public static function clear() {
- $self = I18n::getInstance();
- $self->_domains = array();
- }
-
-/**
- * Get the loaded domains cache.
- *
- * @return array
- */
- public static function domains() {
- $self = I18n::getInstance();
- return $self->_domains;
- }
-
-/**
- * Attempts to find the plural form of a string.
- *
- * @param string $header Type
- * @param integer $n Number
- * @return integer plural match
- */
- protected function _pluralGuess($header, $n) {
- if (!is_string($header) || $header === "nplurals=1;plural=0;" || !isset($header[0])) {
- return 0;
- }
-
- if ($header === "nplurals=2;plural=n!=1;") {
- return $n != 1 ? 1 : 0;
- } elseif ($header === "nplurals=2;plural=n>1;") {
- return $n > 1 ? 1 : 0;
- }
-
- if (strpos($header, "plurals=3")) {
- if (strpos($header, "100!=11")) {
- if (strpos($header, "10<=4")) {
- return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
- } elseif (strpos($header, "100<10")) {
- return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n % 10 >= 2 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
- }
- return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n != 0 ? 1 : 2);
- } elseif (strpos($header, "n==2")) {
- return $n == 1 ? 0 : ($n == 2 ? 1 : 2);
- } elseif (strpos($header, "n==0")) {
- return $n == 1 ? 0 : ($n == 0 || ($n % 100 > 0 && $n % 100 < 20) ? 1 : 2);
- } elseif (strpos($header, "n>=2")) {
- return $n == 1 ? 0 : ($n >= 2 && $n <= 4 ? 1 : 2);
- } elseif (strpos($header, "10>=2")) {
- return $n == 1 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
- }
- return $n % 10 == 1 ? 0 : ($n % 10 == 2 ? 1 : 2);
- } elseif (strpos($header, "plurals=4")) {
- if (strpos($header, "100==2")) {
- return $n % 100 == 1 ? 0 : ($n % 100 == 2 ? 1 : ($n % 100 == 3 || $n % 100 == 4 ? 2 : 3));
- } elseif (strpos($header, "n>=3")) {
- return $n == 1 ? 0 : ($n == 2 ? 1 : ($n == 0 || ($n >= 3 && $n <= 10) ? 2 : 3));
- } elseif (strpos($header, "100>=1")) {
- return $n == 1 ? 0 : ($n == 0 || ($n % 100 >= 1 && $n % 100 <= 10) ? 1 : ($n % 100 >= 11 && $n % 100 <= 20 ? 2 : 3));
- }
- } elseif (strpos($header, "plurals=5")) {
- return $n == 1 ? 0 : ($n == 2 ? 1 : ($n >= 3 && $n <= 6 ? 2 : ($n >= 7 && $n <= 10 ? 3 : 4)));
- }
- }
-
-/**
- * Binds the given domain to a file in the specified directory.
- *
- * @param string $domain Domain to bind
- * @return string Domain binded
- */
- protected function _bindTextDomain($domain) {
- $this->_noLocale = true;
- $core = true;
- $merge = array();
- $searchPaths = App::path('locales');
- $plugins = CakePlugin::loaded();
-
- if (!empty($plugins)) {
- foreach ($plugins as $plugin) {
- $pluginDomain = Inflector::underscore($plugin);
- if ($pluginDomain === $domain) {
- $searchPaths[] = CakePlugin::path($plugin) . 'Locale' . DS;
- $searchPaths = array_reverse($searchPaths);
- break;
- }
- }
- }
-
- foreach ($searchPaths as $directory) {
- foreach ($this->l10n->languagePath as $lang) {
- $localeDef = $directory . $lang . DS . $this->category;
- if (is_file($localeDef)) {
- $definitions = self::loadLocaleDefinition($localeDef);
- if ($definitions !== false) {
- $this->_domains[$domain][$this->_lang][$this->category] = self::loadLocaleDefinition($localeDef);
- $this->_noLocale = false;
- return $domain;
- }
- }
-
- if ($core) {
- $app = $directory . $lang . DS . $this->category . DS . 'core';
- $translations = false;
-
- if (is_file($app . '.mo')) {
- $translations = self::loadMo($app . '.mo');
- }
- if ($translations === false && is_file($app . '.po')) {
- $translations = self::loadPo($app . '.po');
- }
-
- if ($translations !== false) {
- $this->_domains[$domain][$this->_lang][$this->category] = $translations;
- $merge[$domain][$this->_lang][$this->category] = $this->_domains[$domain][$this->_lang][$this->category];
- $this->_noLocale = false;
- $core = null;
- }
- }
-
- $file = $directory . $lang . DS . $this->category . DS . $domain;
- $translations = false;
-
- if (is_file($file . '.mo')) {
- $translations = self::loadMo($file . '.mo');
- }
- if ($translations === false && is_file($file . '.po')) {
- $translations = self::loadPo($file . '.po');
- }
-
- if ($translations !== false) {
- $this->_domains[$domain][$this->_lang][$this->category] = $translations;
- $this->_noLocale = false;
- break 2;
- }
- }
- }
-
- if (empty($this->_domains[$domain][$this->_lang][$this->category])) {
- $this->_domains[$domain][$this->_lang][$this->category] = array();
- return $domain;
- }
-
- if (isset($this->_domains[$domain][$this->_lang][$this->category][""])) {
- $head = $this->_domains[$domain][$this->_lang][$this->category][""];
-
- foreach (explode("\n", $head) as $line) {
- $header = strtok($line,":");
- $line = trim(strtok("\n"));
- $this->_domains[$domain][$this->_lang][$this->category]["%po-header"][strtolower($header)] = $line;
- }
-
- if (isset($this->_domains[$domain][$this->_lang][$this->category]["%po-header"]["plural-forms"])) {
- $switch = preg_replace("/(?:[() {}\\[\\]^\\s*\\]]+)/", "", $this->_domains[$domain][$this->_lang][$this->category]["%po-header"]["plural-forms"]);
- $this->_domains[$domain][$this->_lang][$this->category]["%plural-c"] = $switch;
- unset($this->_domains[$domain][$this->_lang][$this->category]["%po-header"]);
- }
- $this->_domains = Set::pushDiff($this->_domains, $merge);
-
- if (isset($this->_domains[$domain][$this->_lang][$this->category][null])) {
- unset($this->_domains[$domain][$this->_lang][$this->category][null]);
- }
- }
-
- return $domain;
- }
-
-/**
- * Loads the binary .mo file and returns array of translations
- *
- * @param string $filename Binary .mo file to load
- * @return mixed Array of translations on success or false on failure
- */
- public static function loadMo($filename) {
- $translations = false;
-
- // @codingStandardsIgnoreStart
- // Binary files extracted makes non-standard local variables
- if ($data = file_get_contents($filename)) {
- $translations = array();
- $header = substr($data, 0, 20);
- $header = unpack("L1magic/L1version/L1count/L1o_msg/L1o_trn", $header);
- extract($header);
-
- if ((dechex($magic) == '950412de' || dechex($magic) == 'ffffffff950412de') && $version == 0) {
- for ($n = 0; $n < $count; $n++) {
- $r = unpack("L1len/L1offs", substr($data, $o_msg + $n * 8, 8));
- $msgid = substr($data, $r["offs"], $r["len"]);
- unset($msgid_plural);
-
- if (strpos($msgid, "\000")) {
- list($msgid, $msgid_plural) = explode("\000", $msgid);
- }
- $r = unpack("L1len/L1offs", substr($data, $o_trn + $n * 8, 8));
- $msgstr = substr($data, $r["offs"], $r["len"]);
-
- if (strpos($msgstr, "\000")) {
- $msgstr = explode("\000", $msgstr);
- }
- $translations[$msgid] = $msgstr;
-
- if (isset($msgid_plural)) {
- $translations[$msgid_plural] =& $translations[$msgid];
- }
- }
- }
- }
- // @codingStandardsIgnoreEnd
-
- return $translations;
- }
-
-/**
- * Loads the text .po file and returns array of translations
- *
- * @param string $filename Text .po file to load
- * @return mixed Array of translations on success or false on failure
- */
- public static function loadPo($filename) {
- if (!$file = fopen($filename, "r")) {
- return false;
- }
-
- $type = 0;
- $translations = array();
- $translationKey = "";
- $plural = 0;
- $header = "";
-
- do {
- $line = trim(fgets($file));
- if ($line == "" || $line[0] == "#") {
- continue;
- }
- if (preg_match("/msgid[[:space:]]+\"(.+)\"$/i", $line, $regs)) {
- $type = 1;
- $translationKey = stripcslashes($regs[1]);
- } elseif (preg_match("/msgid[[:space:]]+\"\"$/i", $line, $regs)) {
- $type = 2;
- $translationKey = "";
- } elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && ($type == 1 || $type == 2 || $type == 3)) {
- $type = 3;
- $translationKey .= stripcslashes($regs[1]);
- } elseif (preg_match("/msgstr[[:space:]]+\"(.+)\"$/i", $line, $regs) && ($type == 1 || $type == 3) && $translationKey) {
- $translations[$translationKey] = stripcslashes($regs[1]);
- $type = 4;
- } elseif (preg_match("/msgstr[[:space:]]+\"\"$/i", $line, $regs) && ($type == 1 || $type == 3) && $translationKey) {
- $type = 4;
- $translations[$translationKey] = "";
- } elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 4 && $translationKey) {
- $translations[$translationKey] .= stripcslashes($regs[1]);
- } elseif (preg_match("/msgid_plural[[:space:]]+\".*\"$/i", $line, $regs)) {
- $type = 6;
- } elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 6 && $translationKey) {
- $type = 6;
- } elseif (preg_match("/msgstr\[(\d+)\][[:space:]]+\"(.+)\"$/i", $line, $regs) && ($type == 6 || $type == 7) && $translationKey) {
- $plural = $regs[1];
- $translations[$translationKey][$plural] = stripcslashes($regs[2]);
- $type = 7;
- } elseif (preg_match("/msgstr\[(\d+)\][[:space:]]+\"\"$/i", $line, $regs) && ($type == 6 || $type == 7) && $translationKey) {
- $plural = $regs[1];
- $translations[$translationKey][$plural] = "";
- $type = 7;
- } elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 7 && $translationKey) {
- $translations[$translationKey][$plural] .= stripcslashes($regs[1]);
- } elseif (preg_match("/msgstr[[:space:]]+\"(.+)\"$/i", $line, $regs) && $type == 2 && !$translationKey) {
- $header .= stripcslashes($regs[1]);
- $type = 5;
- } elseif (preg_match("/msgstr[[:space:]]+\"\"$/i", $line, $regs) && !$translationKey) {
- $header = "";
- $type = 5;
- } elseif (preg_match("/^\"(.*)\"$/i", $line, $regs) && $type == 5) {
- $header .= stripcslashes($regs[1]);
- } else {
- unset($translations[$translationKey]);
- $type = 0;
- $translationKey = "";
- $plural = 0;
- }
- } while (!feof($file));
- fclose($file);
-
- $merge[""] = $header;
- return array_merge($merge, $translations);
- }
-
-/**
- * Parses a locale definition file following the POSIX standard
- *
- * @param string $filename Locale definition filename
- * @return mixed Array of definitions on success or false on failure
- */
- public static function loadLocaleDefinition($filename) {
- if (!$file = fopen($filename, "r")) {
- return false;
- }
-
- $definitions = array();
- $comment = '#';
- $escape = '\\';
- $currentToken = false;
- $value = '';
- $_this = I18n::getInstance();
- while ($line = fgets($file)) {
- $line = trim($line);
- if (empty($line) || $line[0] === $comment) {
- continue;
- }
- $parts = preg_split("/[[:space:]]+/", $line);
- if ($parts[0] === 'comment_char') {
- $comment = $parts[1];
- continue;
- }
- if ($parts[0] === 'escape_char') {
- $escape = $parts[1];
- continue;
- }
- $count = count($parts);
- if ($count == 2) {
- $currentToken = $parts[0];
- $value = $parts[1];
- } elseif ($count == 1) {
- $value .= $parts[0];
- } else {
- continue;
- }
-
- $len = strlen($value) - 1;
- if ($value[$len] === $escape) {
- $value = substr($value, 0, $len);
- continue;
- }
-
- $mustEscape = array($escape . ',', $escape . ';', $escape . '<', $escape . '>', $escape . $escape);
- $replacements = array_map('crc32', $mustEscape);
- $value = str_replace($mustEscape, $replacements, $value);
- $value = explode(';', $value);
- $_this->_escape = $escape;
- foreach ($value as $i => $val) {
- $val = trim($val, '"');
- $val = preg_replace_callback('/(?:<)?(.[^>]*)(?:>)?/', array(&$_this, '_parseLiteralValue'), $val);
- $val = str_replace($replacements, $mustEscape, $val);
- $value[$i] = $val;
- }
- if (count($value) == 1) {
- $definitions[$currentToken] = array_pop($value);
- } else {
- $definitions[$currentToken] = $value;
- }
- }
-
- return $definitions;
- }
-
-/**
- * Auxiliary function to parse a symbol from a locale definition file
- *
- * @param string $string Symbol to be parsed
- * @return string parsed symbol
- */
- protected function _parseLiteralValue($string) {
- $string = $string[1];
- if (substr($string, 0, 2) === $this->_escape . 'x') {
- $delimiter = $this->_escape . 'x';
- return join('', array_map('chr', array_map('hexdec',array_filter(explode($delimiter, $string)))));
- }
- if (substr($string, 0, 2) === $this->_escape . 'd') {
- $delimiter = $this->_escape . 'd';
- return join('', array_map('chr', array_filter(explode($delimiter, $string))));
- }
- if ($string[0] === $this->_escape && isset($string[1]) && is_numeric($string[1])) {
- $delimiter = $this->_escape;
- return join('', array_map('chr', array_filter(explode($delimiter, $string))));
- }
- if (substr($string, 0, 3) === 'U00') {
- $delimiter = 'U00';
- return join('', array_map('chr', array_map('hexdec', array_filter(explode($delimiter, $string)))));
- }
- if (preg_match('/U([0-9a-fA-F]{4})/', $string, $match)) {
- return Multibyte::ascii(array(hexdec($match[1])));
- }
- return $string;
- }
-
-/**
- * Returns a Time format definition from corresponding domain
- *
- * @param string $format Format to be translated
- * @param string $domain Domain where format is stored
- * @return mixed translated format string if only value or array of translated strings for corresponding format.
- */
- protected function _translateTime($format, $domain) {
- if (!empty($this->_domains[$domain][$this->_lang]['LC_TIME'][$format])) {
- if (($trans = $this->_domains[$domain][$this->_lang][$this->category][$format])) {
- return $trans;
- }
- }
- return $format;
- }
-
-}
diff --git a/lib/Cake/I18n/L10n.php b/lib/Cake/I18n/L10n.php
deleted file mode 100644
index 587db27fd35..00000000000
--- a/lib/Cake/I18n/L10n.php
+++ /dev/null
@@ -1,473 +0,0 @@
- 'af',
- /* Albanian */ 'alb' => 'sq',
- /* Arabic */ 'ara' => 'ar',
- /* Armenian - Armenia */ 'hye' => 'hy',
- /* Basque */ 'baq' => 'eu',
- /* Tibetan */ 'bod' => 'bo',
- /* Bosnian */ 'bos' => 'bs',
- /* Bulgarian */ 'bul' => 'bg',
- /* Byelorussian */ 'bel' => 'be',
- /* Catalan */ 'cat' => 'ca',
- /* Chinese */ 'chi' => 'zh',
- /* Chinese */ 'zho' => 'zh',
- /* Croatian */ 'hrv' => 'hr',
- /* Czech */ 'cze' => 'cs',
- /* Czech */ 'ces' => 'cs',
- /* Danish */ 'dan' => 'da',
- /* Dutch (Standard) */ 'dut' => 'nl',
- /* Dutch (Standard) */ 'nld' => 'nl',
- /* English */ 'eng' => 'en',
- /* Estonian */ 'est' => 'et',
- /* Faeroese */ 'fao' => 'fo',
- /* Farsi */ 'fas' => 'fa',
- /* Farsi */ 'per' => 'fa',
- /* Finnish */ 'fin' => 'fi',
- /* French (Standard) */ 'fre' => 'fr',
- /* French (Standard) */ 'fra' => 'fr',
- /* Gaelic (Scots) */ 'gla' => 'gd',
- /* Galician */ 'glg' => 'gl',
- /* German (Standard) */ 'deu' => 'de',
- /* German (Standard) */ 'ger' => 'de',
- /* Greek */ 'gre' => 'el',
- /* Greek */ 'ell' => 'el',
- /* Hebrew */ 'heb' => 'he',
- /* Hindi */ 'hin' => 'hi',
- /* Hungarian */ 'hun' => 'hu',
- /* Icelandic */ 'ice' => 'is',
- /* Icelandic */ 'isl' => 'is',
- /* Indonesian */ 'ind' => 'id',
- /* Irish */ 'gle' => 'ga',
- /* Italian */ 'ita' => 'it',
- /* Japanese */ 'jpn' => 'ja',
- /* Korean */ 'kor' => 'ko',
- /* Latvian */ 'lav' => 'lv',
- /* Lithuanian */ 'lit' => 'lt',
- /* Macedonian */ 'mac' => 'mk',
- /* Macedonian */ 'mkd' => 'mk',
- /* Malaysian */ 'may' => 'ms',
- /* Malaysian */ 'msa' => 'ms',
- /* Maltese */ 'mlt' => 'mt',
- /* Norwegian */ 'nor' => 'no',
- /* Norwegian Bokmal */ 'nob' => 'nb',
- /* Norwegian Nynorsk */ 'nno' => 'nn',
- /* Polish */ 'pol' => 'pl',
- /* Portuguese (Portugal) */ 'por' => 'pt',
- /* Rhaeto-Romanic */ 'roh' => 'rm',
- /* Romanian */ 'rum' => 'ro',
- /* Romanian */ 'ron' => 'ro',
- /* Russian */ 'rus' => 'ru',
- /* Sami (Lappish) */ 'smi' => 'sz',
- /* Serbian */ 'scc' => 'sr',
- /* Serbian */ 'srp' => 'sr',
- /* Slovak */ 'slo' => 'sk',
- /* Slovak */ 'slk' => 'sk',
- /* Slovenian */ 'slv' => 'sl',
- /* Sorbian */ 'wen' => 'sb',
- /* Spanish (Spain - Traditional) */ 'spa' => 'es',
- /* Swedish */ 'swe' => 'sv',
- /* Thai */ 'tha' => 'th',
- /* Tsonga */ 'tso' => 'ts',
- /* Tswana */ 'tsn' => 'tn',
- /* Turkish */ 'tur' => 'tr',
- /* Ukrainian */ 'ukr' => 'uk',
- /* Urdu */ 'urd' => 'ur',
- /* Venda */ 'ven' => 've',
- /* Vietnamese */ 'vie' => 'vi',
- /* Welsh */ 'cym' => 'cy',
- /* Xhosa */ 'xho' => 'xh',
- /* Yiddish */ 'yid' => 'yi',
- /* Zulu */ 'zul' => 'zu');
-
-/**
- * HTTP_ACCEPT_LANGUAGE catalog
- *
- * holds all information related to a language
- *
- * @var array
- */
- protected $_l10nCatalog = array('af' => array('language' => 'Afrikaans', 'locale' => 'afr', 'localeFallback' => 'afr', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ar' => array('language' => 'Arabic', 'locale' => 'ara', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-ae' => array('language' => 'Arabic (U.A.E.)', 'locale' => 'ar_ae', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-bh' => array('language' => 'Arabic (Bahrain)', 'locale' => 'ar_bh', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-dz' => array('language' => 'Arabic (Algeria)', 'locale' => 'ar_dz', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-eg' => array('language' => 'Arabic (Egypt)', 'locale' => 'ar_eg', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-iq' => array('language' => 'Arabic (Iraq)', 'locale' => 'ar_iq', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-jo' => array('language' => 'Arabic (Jordan)', 'locale' => 'ar_jo', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-kw' => array('language' => 'Arabic (Kuwait)', 'locale' => 'ar_kw', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-lb' => array('language' => 'Arabic (Lebanon)', 'locale' => 'ar_lb', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-ly' => array('language' => 'Arabic (Libya)', 'locale' => 'ar_ly', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-ma' => array('language' => 'Arabic (Morocco)', 'locale' => 'ar_ma', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-om' => array('language' => 'Arabic (Oman)', 'locale' => 'ar_om', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-qa' => array('language' => 'Arabic (Qatar)', 'locale' => 'ar_qa', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-sa' => array('language' => 'Arabic (Saudi Arabia)', 'locale' => 'ar_sa', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-sy' => array('language' => 'Arabic (Syria)', 'locale' => 'ar_sy', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-tn' => array('language' => 'Arabic (Tunisia)', 'locale' => 'ar_tn', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'ar-ye' => array('language' => 'Arabic (Yemen)', 'locale' => 'ar_ye', 'localeFallback' => 'ara', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'be' => array('language' => 'Byelorussian', 'locale' => 'bel', 'localeFallback' => 'bel', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'bg' => array('language' => 'Bulgarian', 'locale' => 'bul', 'localeFallback' => 'bul', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'bo' => array('language' => 'Tibetan', 'locale' => 'bod', 'localeFallback' => 'bod', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'bo-cn' => array('language' => 'Tibetan (China)', 'locale' => 'bo_cn', 'localeFallback' => 'bod', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'bo-in' => array('language' => 'Tibetan (India)', 'locale' => 'bo_in', 'localeFallback' => 'bod', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'bs' => array('language' => 'Bosnian', 'locale' => 'bos', 'localeFallback' => 'bos', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ca' => array('language' => 'Catalan', 'locale' => 'cat', 'localeFallback' => 'cat', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'cs' => array('language' => 'Czech', 'locale' => 'cze', 'localeFallback' => 'cze', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'da' => array('language' => 'Danish', 'locale' => 'dan', 'localeFallback' => 'dan', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'de' => array('language' => 'German (Standard)', 'locale' => 'deu', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'de-at' => array('language' => 'German (Austria)', 'locale' => 'de_at', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'de-ch' => array('language' => 'German (Swiss)', 'locale' => 'de_ch', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'de-de' => array('language' => 'German (Germany)', 'locale' => 'de_de', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'de-li' => array('language' => 'German (Liechtenstein)', 'locale' => 'de_li', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'de-lu' => array('language' => 'German (Luxembourg)', 'locale' => 'de_lu', 'localeFallback' => 'deu', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'e' => array('language' => 'Greek', 'locale' => 'gre', 'localeFallback' => 'gre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'el' => array('language' => 'Greek', 'locale' => 'gre', 'localeFallback' => 'gre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'en' => array('language' => 'English', 'locale' => 'eng', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'en-au' => array('language' => 'English (Australian)', 'locale' => 'en_au', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'en-bz' => array('language' => 'English (Belize)', 'locale' => 'en_bz', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'en-ca' => array('language' => 'English (Canadian)', 'locale' => 'en_ca', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'en-gb' => array('language' => 'English (British)', 'locale' => 'en_gb', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'en-ie' => array('language' => 'English (Ireland)', 'locale' => 'en_ie', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'en-jm' => array('language' => 'English (Jamaica)', 'locale' => 'en_jm', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'en-nz' => array('language' => 'English (New Zealand)', 'locale' => 'en_nz', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'en-tt' => array('language' => 'English (Trinidad)', 'locale' => 'en_tt', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'en-us' => array('language' => 'English (United States)', 'locale' => 'en_us', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'en-za' => array('language' => 'English (South Africa)', 'locale' => 'en_za', 'localeFallback' => 'eng', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es' => array('language' => 'Spanish (Spain - Traditional)', 'locale' => 'spa', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-ar' => array('language' => 'Spanish (Argentina)', 'locale' => 'es_ar', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-bo' => array('language' => 'Spanish (Bolivia)', 'locale' => 'es_bo', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-cl' => array('language' => 'Spanish (Chile)', 'locale' => 'es_cl', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-co' => array('language' => 'Spanish (Colombia)', 'locale' => 'es_co', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-cr' => array('language' => 'Spanish (Costa Rica)', 'locale' => 'es_cr', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-do' => array('language' => 'Spanish (Dominican Republic)', 'locale' => 'es_do', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-ec' => array('language' => 'Spanish (Ecuador)', 'locale' => 'es_ec', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-es' => array('language' => 'Spanish (Spain)', 'locale' => 'es_es', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-gt' => array('language' => 'Spanish (Guatemala)', 'locale' => 'es_gt', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-hn' => array('language' => 'Spanish (Honduras)', 'locale' => 'es_hn', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-mx' => array('language' => 'Spanish (Mexican)', 'locale' => 'es_mx', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-ni' => array('language' => 'Spanish (Nicaragua)', 'locale' => 'es_ni', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-pa' => array('language' => 'Spanish (Panama)', 'locale' => 'es_pa', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-pe' => array('language' => 'Spanish (Peru)', 'locale' => 'es_pe', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-pr' => array('language' => 'Spanish (Puerto Rico)', 'locale' => 'es_pr', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-py' => array('language' => 'Spanish (Paraguay)', 'locale' => 'es_py', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-sv' => array('language' => 'Spanish (El Salvador)', 'locale' => 'es_sv', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-uy' => array('language' => 'Spanish (Uruguay)', 'locale' => 'es_uy', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'es-ve' => array('language' => 'Spanish (Venezuela)', 'locale' => 'es_ve', 'localeFallback' => 'spa', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'et' => array('language' => 'Estonian', 'locale' => 'est', 'localeFallback' => 'est', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'eu' => array('language' => 'Basque', 'locale' => 'baq', 'localeFallback' => 'baq', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fa' => array('language' => 'Farsi', 'locale' => 'per', 'localeFallback' => 'per', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'fi' => array('language' => 'Finnish', 'locale' => 'fin', 'localeFallback' => 'fin', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fo' => array('language' => 'Faeroese', 'locale' => 'fao', 'localeFallback' => 'fao', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr' => array('language' => 'French (Standard)', 'locale' => 'fre', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-be' => array('language' => 'French (Belgium)', 'locale' => 'fr_be', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-ca' => array('language' => 'French (Canadian)', 'locale' => 'fr_ca', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-ch' => array('language' => 'French (Swiss)', 'locale' => 'fr_ch', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-fr' => array('language' => 'French (France)', 'locale' => 'fr_fr', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'fr-lu' => array('language' => 'French (Luxembourg)', 'locale' => 'fr_lu', 'localeFallback' => 'fre', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ga' => array('language' => 'Irish', 'locale' => 'gle', 'localeFallback' => 'gle', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'gd' => array('language' => 'Gaelic (Scots)', 'locale' => 'gla', 'localeFallback' => 'gla', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'gd-ie' => array('language' => 'Gaelic (Irish)', 'locale' => 'gd_ie', 'localeFallback' => 'gla', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'gl' => array('language' => 'Galician', 'locale' => 'glg', 'localeFallback' => 'glg', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'he' => array('language' => 'Hebrew', 'locale' => 'heb', 'localeFallback' => 'heb', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 'hi' => array('language' => 'Hindi', 'locale' => 'hin', 'localeFallback' => 'hin', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'hr' => array('language' => 'Croatian', 'locale' => 'hrv', 'localeFallback' => 'hrv', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'hu' => array('language' => 'Hungarian', 'locale' => 'hun', 'localeFallback' => 'hun', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'hy' => array('language' => 'Armenian - Armenia', 'locale' => 'hye', 'localeFallback' => 'hye', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'id' => array('language' => 'Indonesian', 'locale' => 'ind', 'localeFallback' => 'ind', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'in' => array('language' => 'Indonesian', 'locale' => 'ind', 'localeFallback' => 'ind', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'is' => array('language' => 'Icelandic', 'locale' => 'ice', 'localeFallback' => 'ice', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'it' => array('language' => 'Italian', 'locale' => 'ita', 'localeFallback' => 'ita', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'it-ch' => array('language' => 'Italian (Swiss) ', 'locale' => 'it_ch', 'localeFallback' => 'ita', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ja' => array('language' => 'Japanese', 'locale' => 'jpn', 'localeFallback' => 'jpn', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ko' => array('language' => 'Korean', 'locale' => 'kor', 'localeFallback' => 'kor', 'charset' => 'kr', 'direction' => 'ltr'),
- 'ko-kp' => array('language' => 'Korea (North)', 'locale' => 'ko_kp', 'localeFallback' => 'kor', 'charset' => 'kr', 'direction' => 'ltr'),
- 'ko-kr' => array('language' => 'Korea (South)', 'locale' => 'ko_kr', 'localeFallback' => 'kor', 'charset' => 'kr', 'direction' => 'ltr'),
- 'koi8-r' => array('language' => 'Russian', 'locale' => 'koi8_r', 'localeFallback' => 'rus', 'charset' => 'koi8-r', 'direction' => 'ltr'),
- 'lt' => array('language' => 'Lithuanian', 'locale' => 'lit', 'localeFallback' => 'lit', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'lv' => array('language' => 'Latvian', 'locale' => 'lav', 'localeFallback' => 'lav', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'mk' => array('language' => 'FYRO Macedonian', 'locale' => 'mk', 'localeFallback' => 'mac', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'mk-mk' => array('language' => 'Macedonian', 'locale' => 'mk_mk', 'localeFallback' => 'mac', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ms' => array('language' => 'Malaysian', 'locale' => 'may', 'localeFallback' => 'may', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'mt' => array('language' => 'Maltese', 'locale' => 'mlt', 'localeFallback' => 'mlt', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'n' => array('language' => 'Dutch (Standard)', 'locale' => 'dut', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'nb' => array('language' => 'Norwegian Bokmal', 'locale' => 'nob', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'nl' => array('language' => 'Dutch (Standard)', 'locale' => 'dut', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'nl-be' => array('language' => 'Dutch (Belgium)', 'locale' => 'nl_be', 'localeFallback' => 'dut', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'nn' => array('language' => 'Norwegian Nynorsk', 'locale' => 'nno', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'no' => array('language' => 'Norwegian', 'locale' => 'nor', 'localeFallback' => 'nor', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'p' => array('language' => 'Polish', 'locale' => 'pol', 'localeFallback' => 'pol', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'pl' => array('language' => 'Polish', 'locale' => 'pol', 'localeFallback' => 'pol', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'pt' => array('language' => 'Portuguese (Portugal)', 'locale' => 'por', 'localeFallback' => 'por', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'pt-br' => array('language' => 'Portuguese (Brazil)', 'locale' => 'pt_br', 'localeFallback' => 'por', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'rm' => array('language' => 'Rhaeto-Romanic', 'locale' => 'roh', 'localeFallback' => 'roh', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ro' => array('language' => 'Romanian', 'locale' => 'rum', 'localeFallback' => 'rum', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ro-mo' => array('language' => 'Romanian (Moldavia)', 'locale' => 'ro_mo', 'localeFallback' => 'rum', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ru' => array('language' => 'Russian', 'locale' => 'rus', 'localeFallback' => 'rus', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ru-mo' => array('language' => 'Russian (Moldavia)', 'locale' => 'ru_mo', 'localeFallback' => 'rus', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'sb' => array('language' => 'Sorbian', 'locale' => 'wen', 'localeFallback' => 'wen', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'sk' => array('language' => 'Slovak', 'locale' => 'slo', 'localeFallback' => 'slo', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'sl' => array('language' => 'Slovenian', 'locale' => 'slv', 'localeFallback' => 'slv', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'sq' => array('language' => 'Albanian', 'locale' => 'alb', 'localeFallback' => 'alb', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'sr' => array('language' => 'Serbian', 'locale' => 'scc', 'localeFallback' => 'scc', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'sv' => array('language' => 'Swedish', 'locale' => 'swe', 'localeFallback' => 'swe', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'sv-fi' => array('language' => 'Swedish (Finland)', 'locale' => 'sv_fi', 'localeFallback' => 'swe', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'sx' => array('language' => 'Sutu', 'locale' => 'sx', 'localeFallback' => 'sx', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'sz' => array('language' => 'Sami (Lappish)', 'locale' => 'smi', 'localeFallback' => 'smi', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'th' => array('language' => 'Thai', 'locale' => 'tha', 'localeFallback' => 'tha', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'tn' => array('language' => 'Tswana', 'locale' => 'tsn', 'localeFallback' => 'tsn', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'tr' => array('language' => 'Turkish', 'locale' => 'tur', 'localeFallback' => 'tur', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ts' => array('language' => 'Tsonga', 'locale' => 'tso', 'localeFallback' => 'tso', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'uk' => array('language' => 'Ukrainian', 'locale' => 'ukr', 'localeFallback' => 'ukr', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'ur' => array('language' => 'Urdu', 'locale' => 'urd', 'localeFallback' => 'urd', 'charset' => 'utf-8', 'direction' => 'rtl'),
- 've' => array('language' => 'Venda', 'locale' => 'ven', 'localeFallback' => 'ven', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'vi' => array('language' => 'Vietnamese', 'locale' => 'vie', 'localeFallback' => 'vie', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'cy' => array('language' => 'Welsh', 'locale' => 'cym', 'localeFallback' => 'cym', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'xh' => array('language' => 'Xhosa', 'locale' => 'xho', 'localeFallback' => 'xho', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'yi' => array('language' => 'Yiddish', 'locale' => 'yid', 'localeFallback' => 'yid', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'zh' => array('language' => 'Chinese', 'locale' => 'chi', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'zh-cn' => array('language' => 'Chinese (PRC)', 'locale' => 'zh_cn', 'localeFallback' => 'chi', 'charset' => 'GB2312', 'direction' => 'ltr'),
- 'zh-hk' => array('language' => 'Chinese (Hong Kong)', 'locale' => 'zh_hk', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'zh-sg' => array('language' => 'Chinese (Singapore)', 'locale' => 'zh_sg', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'zh-tw' => array('language' => 'Chinese (Taiwan)', 'locale' => 'zh_tw', 'localeFallback' => 'chi', 'charset' => 'utf-8', 'direction' => 'ltr'),
- 'zu' => array('language' => 'Zulu', 'locale' => 'zul', 'localeFallback' => 'zul', 'charset' => 'utf-8', 'direction' => 'ltr'));
-
-/**
- * Class constructor
- */
- public function __construct() {
- if (defined('DEFAULT_LANGUAGE')) {
- $this->default = DEFAULT_LANGUAGE;
- }
- }
-
-/**
- * Gets the settings for $language.
- * If $language is null it attempt to get settings from L10n::_autoLanguage(); if this fails
- * the method will get the settings from L10n::_setLanguage();
- *
- * @param string $language Language (if null will use DEFAULT_LANGUAGE if defined)
- * @return mixed
- */
- public function get($language = null) {
- if ($language !== null) {
- return $this->_setLanguage($language);
- } elseif ($this->_autoLanguage() === false) {
- return $this->_setLanguage();
- }
- }
-
-/**
- * Sets the class vars to correct values for $language.
- * If $language is null it will use the DEFAULT_LANGUAGE if defined
- *
- * @param string $language Language (if null will use DEFAULT_LANGUAGE if defined)
- * @return mixed
- */
- protected function _setLanguage($language = null) {
- $langKey = null;
- if ($language !== null && isset($this->_l10nMap[$language]) && isset($this->_l10nCatalog[$this->_l10nMap[$language]])) {
- $langKey = $this->_l10nMap[$language];
- } elseif ($language !== null && isset($this->_l10nCatalog[$language])) {
- $langKey = $language;
- } elseif (defined('DEFAULT_LANGUAGE')) {
- $langKey = $language = DEFAULT_LANGUAGE;
- }
-
- if ($langKey !== null && isset($this->_l10nCatalog[$langKey])) {
- $this->language = $this->_l10nCatalog[$langKey]['language'];
- $this->languagePath = array(
- $this->_l10nCatalog[$langKey]['locale'],
- $this->_l10nCatalog[$langKey]['localeFallback']
- );
- $this->lang = $language;
- $this->locale = $this->_l10nCatalog[$langKey]['locale'];
- $this->charset = $this->_l10nCatalog[$langKey]['charset'];
- $this->direction = $this->_l10nCatalog[$langKey]['direction'];
- } else {
- $this->lang = $language;
- $this->languagePath = array($language);
- }
-
- if ($this->default) {
- if (isset($this->_l10nMap[$this->default]) && isset($this->_l10nCatalog[$this->_l10nMap[$this->default]])) {
- $this->languagePath[] = $this->_l10nCatalog[$this->_l10nMap[$this->default]]['localeFallback'];
- } elseif (isset($this->_l10nCatalog[$this->default])) {
- $this->languagePath[] = $this->_l10nCatalog[$this->default]['localeFallback'];
- }
- }
- $this->found = true;
-
- if (Configure::read('Config.language') === null) {
- Configure::write('Config.language', $this->lang);
- }
-
- if ($language) {
- return $language;
- }
- }
-
-/**
- * Attempts to find the locale settings based on the HTTP_ACCEPT_LANGUAGE variable
- *
- * @return boolean Success
- */
- protected function _autoLanguage() {
- $_detectableLanguages = CakeRequest::acceptLanguage();
- foreach ($_detectableLanguages as $key => $langKey) {
- if (isset($this->_l10nCatalog[$langKey])) {
- $this->_setLanguage($langKey);
- return true;
- } elseif (strpos($langKey, '-') !== false) {
- $langKey = substr($langKey, 0, 2);
- if (isset($this->_l10nCatalog[$langKey])) {
- $this->_setLanguage($langKey);
- return true;
- }
- }
- }
- return false;
- }
-
-/**
- * Attempts to find locale for language, or language for locale
- *
- * @param mixed $mixed 2/3 char string (language/locale), array of those strings, or null
- * @return mixed string language/locale, array of those values, whole map as an array,
- * or false when language/locale doesn't exist
- */
- public function map($mixed = null) {
- if (is_array($mixed)) {
- $result = array();
- foreach ($mixed as $_mixed) {
- if ($_result = $this->map($_mixed)) {
- $result[$_mixed] = $_result;
- }
- }
- return $result;
- } elseif (is_string($mixed)) {
- if (strlen($mixed) === 2 && in_array($mixed, $this->_l10nMap)) {
- return array_search($mixed, $this->_l10nMap);
- } elseif (isset($this->_l10nMap[$mixed])) {
- return $this->_l10nMap[$mixed];
- }
- return false;
- }
- return $this->_l10nMap;
- }
-
-/**
- * Attempts to find catalog record for requested language
- *
- * @param mixed $language string requested language, array of requested languages, or null for whole catalog
- * @return mixed array catalog record for requested language, array of catalog records, whole catalog,
- * or false when language doesn't exist
- */
- public function catalog($language = null) {
- if (is_array($language)) {
- $result = array();
- foreach ($language as $_language) {
- if ($_result = $this->catalog($_language)) {
- $result[$_language] = $_result;
- }
- }
- return $result;
- } elseif (is_string($language)) {
- if (isset($this->_l10nCatalog[$language])) {
- return $this->_l10nCatalog[$language];
- } elseif (isset($this->_l10nMap[$language]) && isset($this->_l10nCatalog[$this->_l10nMap[$language]])) {
- return $this->_l10nCatalog[$this->_l10nMap[$language]];
- }
- return false;
- }
- return $this->_l10nCatalog;
- }
-
-}
diff --git a/lib/Cake/I18n/Multibyte.php b/lib/Cake/I18n/Multibyte.php
deleted file mode 100644
index b741ef4d604..00000000000
--- a/lib/Cake/I18n/Multibyte.php
+++ /dev/null
@@ -1,1134 +0,0 @@
- 1) {
- $matches[$needle[0]] = $matches[$needle[0]] - 1;
- } elseif ($i === $needleCount) {
- $found = true;
- }
- }
-
- if (!$found && isset($haystack[$position])) {
- $parts[] = $haystack[$position];
- unset($haystack[$position]);
- }
- $position++;
- }
-
- if ($found && $part && !empty($parts)) {
- return Multibyte::ascii($parts);
- } elseif ($found && !empty($haystack)) {
- return Multibyte::ascii($haystack);
- }
- return false;
- }
-
-/**
- * Finds the last occurrence of a character in a string within another, case insensitive.
- *
- * @param string $haystack The string from which to get the last occurrence of $needle.
- * @param string $needle The string to find in $haystack.
- * @param boolean $part Determines which portion of $haystack this function returns.
- * If set to true, it returns all of $haystack from the beginning to the last occurrence of $needle.
- * If set to false, it returns all of $haystack from the last occurrence of $needle to the end,
- * Default value is false.
- * @return string|boolean The portion of $haystack. or false if $needle is not found.
- */
- public static function strrichr($haystack, $needle, $part = false) {
- $check = Multibyte::strtoupper($haystack);
- $check = Multibyte::utf8($check);
- $found = false;
-
- $haystack = Multibyte::utf8($haystack);
- $haystackCount = count($haystack);
-
- $matches = array_count_values($check);
-
- $needle = Multibyte::strtoupper($needle);
- $needle = Multibyte::utf8($needle);
- $needleCount = count($needle);
-
- $parts = array();
- $position = 0;
-
- while (($found === false) && ($position < $haystackCount)) {
- if (isset($needle[0]) && $needle[0] === $check[$position]) {
- for ($i = 1; $i < $needleCount; $i++) {
- if ($needle[$i] !== $check[$position + $i]) {
- if ($needle[$i] === $check[($position + $i) - 1]) {
- $found = true;
- }
- unset($parts[$position - 1]);
- $haystack = array_merge(array($haystack[$position]), $haystack);
- break;
- }
- }
- if (isset($matches[$needle[0]]) && $matches[$needle[0]] > 1) {
- $matches[$needle[0]] = $matches[$needle[0]] - 1;
- } elseif ($i === $needleCount) {
- $found = true;
- }
- }
-
- if (!$found && isset($haystack[$position])) {
- $parts[] = $haystack[$position];
- unset($haystack[$position]);
- }
- $position++;
- }
-
- if ($found && $part && !empty($parts)) {
- return Multibyte::ascii($parts);
- } elseif ($found && !empty($haystack)) {
- return Multibyte::ascii($haystack);
- }
- return false;
- }
-
-/**
- * Finds position of last occurrence of a string within another, case insensitive
- *
- * @param string $haystack The string from which to get the position of the last occurrence of $needle.
- * @param string $needle The string to find in $haystack.
- * @param integer $offset The position in $haystack to start searching.
- * @return integer|boolean The numeric position of the last occurrence of $needle in the $haystack string,
- * or false if $needle is not found.
- */
- public static function strripos($haystack, $needle, $offset = 0) {
- if (Multibyte::checkMultibyte($haystack)) {
- $found = false;
- $haystack = Multibyte::strtoupper($haystack);
- $haystack = Multibyte::utf8($haystack);
- $haystackCount = count($haystack);
-
- $matches = array_count_values($haystack);
-
- $needle = Multibyte::strtoupper($needle);
- $needle = Multibyte::utf8($needle);
- $needleCount = count($needle);
-
- $position = $offset;
-
- while (($found === false) && ($position < $haystackCount)) {
- if (isset($needle[0]) && $needle[0] === $haystack[$position]) {
- for ($i = 1; $i < $needleCount; $i++) {
- if ($needle[$i] !== $haystack[$position + $i]) {
- if ($needle[$i] === $haystack[($position + $i) - 1]) {
- $position--;
- $found = true;
- continue;
- }
- }
- }
-
- if (!$offset && isset($matches[$needle[0]]) && $matches[$needle[0]] > 1) {
- $matches[$needle[0]] = $matches[$needle[0]] - 1;
- } elseif ($i === $needleCount) {
- $found = true;
- $position--;
- }
- }
- $position++;
- }
- return ($found) ? $position : false;
- }
- return strripos($haystack, $needle, $offset);
- }
-
-/**
- * Find position of last occurrence of a string in a string.
- *
- * @param string $haystack The string being checked, for the last occurrence of $needle.
- * @param string $needle The string to find in $haystack.
- * @param integer $offset May be specified to begin searching an arbitrary number of characters into the string.
- * Negative values will stop searching at an arbitrary point prior to the end of the string.
- * @return integer|boolean The numeric position of the last occurrence of $needle in the $haystack string.
- * If $needle is not found, it returns false.
- */
- public static function strrpos($haystack, $needle, $offset = 0) {
- if (Multibyte::checkMultibyte($haystack)) {
- $found = false;
-
- $haystack = Multibyte::utf8($haystack);
- $haystackCount = count($haystack);
-
- $matches = array_count_values($haystack);
-
- $needle = Multibyte::utf8($needle);
- $needleCount = count($needle);
-
- $position = $offset;
-
- while (($found === false) && ($position < $haystackCount)) {
- if (isset($needle[0]) && $needle[0] === $haystack[$position]) {
- for ($i = 1; $i < $needleCount; $i++) {
- if ($needle[$i] !== $haystack[$position + $i]) {
- if ($needle[$i] === $haystack[($position + $i) - 1]) {
- $position--;
- $found = true;
- continue;
- }
- }
- }
-
- if (!$offset && isset($matches[$needle[0]]) && $matches[$needle[0]] > 1) {
- $matches[$needle[0]] = $matches[$needle[0]] - 1;
- } elseif ($i === $needleCount) {
- $found = true;
- $position--;
- }
- }
- $position++;
- }
- return ($found) ? $position : false;
- }
- return strrpos($haystack, $needle, $offset);
- }
-
-/**
- * Finds first occurrence of a string within another
- *
- * @param string $haystack The string from which to get the first occurrence of $needle.
- * @param string $needle The string to find in $haystack
- * @param boolean $part Determines which portion of $haystack this function returns.
- * If set to true, it returns all of $haystack from the beginning to the first occurrence of $needle.
- * If set to false, it returns all of $haystack from the first occurrence of $needle to the end,
- * Default value is FALSE.
- * @return string|boolean The portion of $haystack, or true if $needle is not found.
- */
- public static function strstr($haystack, $needle, $part = false) {
- $php = (PHP_VERSION < 5.3);
-
- if (($php && $part) || Multibyte::checkMultibyte($haystack)) {
- $check = Multibyte::utf8($haystack);
- $found = false;
-
- $haystack = Multibyte::utf8($haystack);
- $haystackCount = count($haystack);
-
- $needle = Multibyte::utf8($needle);
- $needleCount = count($needle);
-
- $parts = array();
- $position = 0;
-
- while (($found === false) && ($position < $haystackCount)) {
- if (isset($needle[0]) && $needle[0] === $check[$position]) {
- for ($i = 1; $i < $needleCount; $i++) {
- if ($needle[$i] !== $check[$position + $i]) {
- break;
- }
- }
- if ($i === $needleCount) {
- $found = true;
- }
- }
- if (!$found) {
- $parts[] = $haystack[$position];
- unset($haystack[$position]);
- }
- $position++;
- }
-
- if ($found && $part && !empty($parts)) {
- return Multibyte::ascii($parts);
- } elseif ($found && !empty($haystack)) {
- return Multibyte::ascii($haystack);
- }
- return false;
- }
-
- if (!$php) {
- return strstr($haystack, $needle, $part);
- }
- return strstr($haystack, $needle);
- }
-
-/**
- * Make a string lowercase
- *
- * @param string $string The string being lowercased.
- * @return string with all alphabetic characters converted to lowercase.
- */
- public static function strtolower($string) {
- $utf8Map = Multibyte::utf8($string);
-
- $length = count($utf8Map);
- $lowerCase = array();
-
- for ($i = 0; $i < $length; $i++) {
- $char = $utf8Map[$i];
-
- if ($char < 128) {
- $str = strtolower(chr($char));
- $strlen = strlen($str);
- for ($ii = 0; $ii < $strlen; $ii++) {
- $lower = ord(substr($str, $ii, 1));
- }
- $lowerCase[] = $lower;
- $matched = true;
- } else {
- $matched = false;
- $keys = self::_find($char, 'upper');
-
- if (!empty($keys)) {
- foreach ($keys as $key => $value) {
- if ($keys[$key]['upper'] == $char && count($keys[$key]['lower'][0]) === 1) {
- $lowerCase[] = $keys[$key]['lower'][0];
- $matched = true;
- break 1;
- }
- }
- }
- }
- if ($matched === false) {
- $lowerCase[] = $char;
- }
- }
- return Multibyte::ascii($lowerCase);
- }
-
-/**
- * Make a string uppercase
- *
- * @param string $string The string being uppercased.
- * @return string with all alphabetic characters converted to uppercase.
- */
- public static function strtoupper($string) {
- $utf8Map = Multibyte::utf8($string);
-
- $length = count($utf8Map);
- $replaced = array();
- $upperCase = array();
-
- for ($i = 0; $i < $length; $i++) {
- $char = $utf8Map[$i];
-
- if ($char < 128) {
- $str = strtoupper(chr($char));
- $strlen = strlen($str);
- for ($ii = 0; $ii < $strlen; $ii++) {
- $upper = ord(substr($str, $ii, 1));
- }
- $upperCase[] = $upper;
- $matched = true;
-
- } else {
- $matched = false;
- $keys = self::_find($char);
- $keyCount = count($keys);
-
- if (!empty($keys)) {
- foreach ($keys as $key => $value) {
- $matched = false;
- $replace = 0;
- if ($length > 1 && count($keys[$key]['lower']) > 1) {
- $j = 0;
-
- for ($ii = 0, $count = count($keys[$key]['lower']); $ii < $count; $ii++) {
- $nextChar = $utf8Map[$i + $ii];
-
- if (isset($nextChar) && ($nextChar == $keys[$key]['lower'][$j + $ii])) {
- $replace++;
- }
- }
- if ($replace == $count) {
- $upperCase[] = $keys[$key]['upper'];
- $replaced = array_merge($replaced, array_values($keys[$key]['lower']));
- $matched = true;
- break 1;
- }
- } elseif ($length > 1 && $keyCount > 1) {
- $j = 0;
- for ($ii = 1; $ii < $keyCount; $ii++) {
- $nextChar = $utf8Map[$i + $ii - 1];
-
- if (in_array($nextChar, $keys[$ii]['lower'])) {
-
- for ($jj = 0, $count = count($keys[$ii]['lower']); $jj < $count; $jj++) {
- $nextChar = $utf8Map[$i + $jj];
-
- if (isset($nextChar) && ($nextChar == $keys[$ii]['lower'][$j + $jj])) {
- $replace++;
- }
- }
- if ($replace == $count) {
- $upperCase[] = $keys[$ii]['upper'];
- $replaced = array_merge($replaced, array_values($keys[$ii]['lower']));
- $matched = true;
- break 2;
- }
- }
- }
- }
- if ($keys[$key]['lower'][0] == $char) {
- $upperCase[] = $keys[$key]['upper'];
- $matched = true;
- break 1;
- }
- }
- }
- }
- if ($matched === false && !in_array($char, $replaced, true)) {
- $upperCase[] = $char;
- }
- }
- return Multibyte::ascii($upperCase);
- }
-
-/**
- * Count the number of substring occurrences
- *
- * @param string $haystack The string being checked.
- * @param string $needle The string being found.
- * @return integer The number of times the $needle substring occurs in the $haystack string.
- */
- public static function substrCount($haystack, $needle) {
- $count = 0;
- $haystack = Multibyte::utf8($haystack);
- $haystackCount = count($haystack);
- $matches = array_count_values($haystack);
- $needle = Multibyte::utf8($needle);
- $needleCount = count($needle);
-
- if ($needleCount === 1 && isset($matches[$needle[0]])) {
- return $matches[$needle[0]];
- }
-
- for ($i = 0; $i < $haystackCount; $i++) {
- if (isset($needle[0]) && $needle[0] === $haystack[$i]) {
- for ($ii = 1; $ii < $needleCount; $ii++) {
- if ($needle[$ii] === $haystack[$i + 1]) {
- if ((isset($needle[$ii + 1]) && $haystack[$i + 2]) && $needle[$ii + 1] !== $haystack[$i + 2]) {
- $count--;
- } else {
- $count++;
- }
- }
- }
- }
- }
- return $count;
- }
-
-/**
- * Get part of string
- *
- * @param string $string The string being checked.
- * @param integer $start The first position used in $string.
- * @param integer $length The maximum length of the returned string.
- * @return string The portion of $string specified by the $string and $length parameters.
- */
- public static function substr($string, $start, $length = null) {
- if ($start === 0 && $length === null) {
- return $string;
- }
-
- $string = Multibyte::utf8($string);
-
- for ($i = 1; $i <= $start; $i++) {
- unset($string[$i - 1]);
- }
-
- if ($length === null || count($string) < $length) {
- return Multibyte::ascii($string);
- }
- $string = array_values($string);
-
- $value = array();
- for ($i = 0; $i < $length; $i++) {
- $value[] = $string[$i];
- }
- return Multibyte::ascii($value);
- }
-
-/**
- * Prepare a string for mail transport, using the provided encoding
- *
- * @param string $string value to encode
- * @param string $charset charset to use for encoding. defaults to UTF-8
- * @param string $newline
- * @return string
- * @TODO: add support for 'Q'('Quoted Printable') encoding
- */
- public static function mimeEncode($string, $charset = null, $newline = "\r\n") {
- if (!Multibyte::checkMultibyte($string) && strlen($string) < 75) {
- return $string;
- }
-
- if (empty($charset)) {
- $charset = Configure::read('App.encoding');
- }
- $charset = strtoupper($charset);
-
- $start = '=?' . $charset . '?B?';
- $end = '?=';
- $spacer = $end . $newline . ' ' . $start;
-
- $length = 75 - strlen($start) - strlen($end);
- $length = $length - ($length % 4);
- if ($charset == 'UTF-8') {
- $parts = array();
- $maxchars = floor(($length * 3) / 4);
- while (strlen($string) > $maxchars) {
- $i = (int)$maxchars;
- $test = ord($string[$i]);
- while ($test >= 128 && $test <= 191) {
- $i--;
- $test = ord($string[$i]);
- }
- $parts[] = base64_encode(substr($string, 0, $i));
- $string = substr($string, $i);
- }
- $parts[] = base64_encode($string);
- $string = implode($spacer, $parts);
- } else {
- $string = chunk_split(base64_encode($string), $length, $spacer);
- $string = preg_replace('/' . preg_quote($spacer) . '$/', '', $string);
- }
- return $start . $string . $end;
- }
-
-/**
- * Return the Code points range for Unicode characters
- *
- * @param integer $decimal
- * @return string
- */
- protected static function _codepoint($decimal) {
- if ($decimal > 128 && $decimal < 256) {
- $return = '0080_00ff'; // Latin-1 Supplement
- } elseif ($decimal < 384) {
- $return = '0100_017f'; // Latin Extended-A
- } elseif ($decimal < 592) {
- $return = '0180_024F'; // Latin Extended-B
- } elseif ($decimal < 688) {
- $return = '0250_02af'; // IPA Extensions
- } elseif ($decimal >= 880 && $decimal < 1024) {
- $return = '0370_03ff'; // Greek and Coptic
- } elseif ($decimal < 1280) {
- $return = '0400_04ff'; // Cyrillic
- } elseif ($decimal < 1328) {
- $return = '0500_052f'; // Cyrillic Supplement
- } elseif ($decimal < 1424) {
- $return = '0530_058f'; // Armenian
- } elseif ($decimal >= 7680 && $decimal < 7936) {
- $return = '1e00_1eff'; // Latin Extended Additional
- } elseif ($decimal < 8192) {
- $return = '1f00_1fff'; // Greek Extended
- } elseif ($decimal >= 8448 && $decimal < 8528) {
- $return = '2100_214f'; // Letterlike Symbols
- } elseif ($decimal < 8592) {
- $return = '2150_218f'; // Number Forms
- } elseif ($decimal >= 9312 && $decimal < 9472) {
- $return = '2460_24ff'; // Enclosed Alphanumerics
- } elseif ($decimal >= 11264 && $decimal < 11360) {
- $return = '2c00_2c5f'; // Glagolitic
- } elseif ($decimal < 11392) {
- $return = '2c60_2c7f'; // Latin Extended-C
- } elseif ($decimal < 11520) {
- $return = '2c80_2cff'; // Coptic
- } elseif ($decimal >= 65280 && $decimal < 65520) {
- $return = 'ff00_ffef'; // Halfwidth and Fullwidth Forms
- } else {
- $return = false;
- }
- self::$_codeRange[$decimal] = $return;
- return $return;
- }
-
-/**
- * Find the related code folding values for $char
- *
- * @param integer $char decimal value of character
- * @param string $type
- * @return array
- */
- protected static function _find($char, $type = 'lower') {
- $found = array();
- if (!isset(self::$_codeRange[$char])) {
- $range = self::_codepoint($char);
- if ($range === false) {
- return null;
- }
- if (!Configure::configured('_cake_core_')) {
- App::uses('PhpReader', 'Configure');
- Configure::config('_cake_core_', new PhpReader(CAKE . 'Config' . DS));
- }
- Configure::load('unicode' . DS . 'casefolding' . DS . $range, '_cake_core_');
- self::$_caseFold[$range] = Configure::read($range);
- Configure::delete($range);
- }
-
- if (!self::$_codeRange[$char]) {
- return null;
- }
- self::$_table = self::$_codeRange[$char];
- $count = count(self::$_caseFold[self::$_table]);
-
- for ($i = 0; $i < $count; $i++) {
- if ($type === 'lower' && self::$_caseFold[self::$_table][$i][$type][0] === $char) {
- $found[] = self::$_caseFold[self::$_table][$i];
- } elseif ($type === 'upper' && self::$_caseFold[self::$_table][$i][$type] === $char) {
- $found[] = self::$_caseFold[self::$_table][$i];
- }
- }
- return $found;
- }
-
-/**
- * Check the $string for multibyte characters
- * @param string $string value to test
- * @return boolean
- */
- public static function checkMultibyte($string) {
- $length = strlen($string);
-
- for ($i = 0; $i < $length; $i++ ) {
- $value = ord(($string[$i]));
- if ($value > 128) {
- return true;
- }
- }
- return false;
- }
-
-}
diff --git a/lib/Cake/LICENSE.txt b/lib/Cake/LICENSE.txt
deleted file mode 100644
index b4d0c66a26c..00000000000
--- a/lib/Cake/LICENSE.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-The MIT License
-
-CakePHP(tm) : The Rapid Development PHP Framework (http://cakephp.org)
-Copyright 2005-2012, Cake Software Foundation, Inc.
-
-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.
\ No newline at end of file
diff --git a/lib/Cake/Log/CakeLog.php b/lib/Cake/Log/CakeLog.php
deleted file mode 100644
index 5b718ebcb4c..00000000000
--- a/lib/Cake/Log/CakeLog.php
+++ /dev/null
@@ -1,209 +0,0 @@
- 'FileLog'));`
- *
- * See the documentation on CakeLog::config() for more detail.
- *
- * ### Writing to the log
- *
- * You write to the logs using CakeLog::write(). See its documentation for more information.
- *
- * @package Cake.Log
- */
-class CakeLog {
-
-/**
- * An array of connected streams.
- * Each stream represents a callable that will be called when write() is called.
- *
- * @var array
- */
- protected static $_streams = array();
-
-/**
- * Configure and add a new logging stream to CakeLog
- * You can use add loggers from app/Log/Engine use app.loggername, or any plugin/Log/Engine using plugin.loggername.
- *
- * ### Usage:
- *
- * {{{
- * CakeLog::config('second_file', array(
- * 'engine' => 'FileLog',
- * 'path' => '/var/logs/my_app/'
- * ));
- * }}}
- *
- * Will configure a FileLog instance to use the specified path. All options that are not `engine`
- * are passed onto the logging adapter, and handled there. Any class can be configured as a logging
- * adapter as long as it implements the methods in CakeLogInterface.
- *
- * @param string $key The keyname for this logger, used to remove the logger later.
- * @param array $config Array of configuration information for the logger
- * @return boolean success of configuration.
- * @throws CakeLogException
- */
- public static function config($key, $config) {
- if (empty($config['engine'])) {
- throw new CakeLogException(__d('cake_dev', 'Missing logger classname'));
- }
- $loggerName = $config['engine'];
- unset($config['engine']);
- $className = self::_getLogger($loggerName);
- $logger = new $className($config);
- if (!$logger instanceof CakeLogInterface) {
- throw new CakeLogException(sprintf(
- __d('cake_dev', 'logger class %s does not implement a write method.'), $loggerName
- ));
- }
- self::$_streams[$key] = $logger;
- return true;
- }
-
-/**
- * Attempts to import a logger class from the various paths it could be on.
- * Checks that the logger class implements a write method as well.
- *
- * @param string $loggerName the plugin.className of the logger class you want to build.
- * @return mixed boolean false on any failures, string of classname to use if search was successful.
- * @throws CakeLogException
- */
- protected static function _getLogger($loggerName) {
- list($plugin, $loggerName) = pluginSplit($loggerName, true);
-
- App::uses($loggerName, $plugin . 'Log/Engine');
- if (!class_exists($loggerName)) {
- throw new CakeLogException(__d('cake_dev', 'Could not load class %s', $loggerName));
- }
- return $loggerName;
- }
-
-/**
- * Returns the keynames of the currently active streams
- *
- * @return array Array of configured log streams.
- */
- public static function configured() {
- return array_keys(self::$_streams);
- }
-
-/**
- * Removes a stream from the active streams. Once a stream has been removed
- * it will no longer have messages sent to it.
- *
- * @param string $streamName Key name of a configured stream to remove.
- * @return void
- */
- public static function drop($streamName) {
- unset(self::$_streams[$streamName]);
- }
-
-/**
- * Configures the automatic/default stream a FileLog.
- *
- * @return void
- */
- protected static function _autoConfig() {
- self::_getLogger('FileLog');
- self::$_streams['default'] = new FileLog(array('path' => LOGS));
- }
-
-/**
- * Writes the given message and type to all of the configured log adapters.
- * Configured adapters are passed both the $type and $message variables. $type
- * is one of the following strings/values.
- *
- * ### Types:
- *
- * - `LOG_WARNING` => 'warning',
- * - `LOG_NOTICE` => 'notice',
- * - `LOG_INFO` => 'info',
- * - `LOG_DEBUG` => 'debug',
- * - `LOG_ERR` => 'error',
- * - `LOG_ERROR` => 'error'
- *
- * ### Usage:
- *
- * Write a message to the 'warning' log:
- *
- * `CakeLog::write('warning', 'Stuff is broken here');`
- *
- * @param string $type Type of message being written
- * @param string $message Message content to log
- * @return boolean Success
- */
- public static function write($type, $message) {
- if (!defined('LOG_ERROR')) {
- define('LOG_ERROR', 2);
- }
- if (!defined('LOG_ERR')) {
- define('LOG_ERR', LOG_ERROR);
- }
- $levels = array(
- LOG_WARNING => 'warning',
- LOG_NOTICE => 'notice',
- LOG_INFO => 'info',
- LOG_DEBUG => 'debug',
- LOG_ERR => 'error',
- LOG_ERROR => 'error'
- );
-
- if (is_int($type) && isset($levels[$type])) {
- $type = $levels[$type];
- }
- if (empty(self::$_streams)) {
- self::_autoConfig();
- }
- foreach (self::$_streams as $logger) {
- $logger->write($type, $message);
- }
- return true;
- }
-
-}
diff --git a/lib/Cake/Log/CakeLogInterface.php b/lib/Cake/Log/CakeLogInterface.php
deleted file mode 100644
index d31e863f8f2..00000000000
--- a/lib/Cake/Log/CakeLogInterface.php
+++ /dev/null
@@ -1,37 +0,0 @@
- LOGS);
- $this->_path = $options['path'];
- }
-
-/**
- * Implements writing to log files.
- *
- * @param string $type The type of log you are making.
- * @param string $message The message you want to log.
- * @return boolean success of write.
- */
- public function write($type, $message) {
- $debugTypes = array('notice', 'info', 'debug');
-
- if ($type == 'error' || $type == 'warning') {
- $filename = $this->_path . 'error.log';
- } elseif (in_array($type, $debugTypes)) {
- $filename = $this->_path . 'debug.log';
- } else {
- $filename = $this->_path . $type . '.log';
- }
- $output = date('Y-m-d H:i:s') . ' ' . ucfirst($type) . ': ' . $message . "\n";
- return file_put_contents($filename, $output, FILE_APPEND);
- }
-
-}
diff --git a/lib/Cake/Model/AclNode.php b/lib/Cake/Model/AclNode.php
deleted file mode 100644
index a832f6526a0..00000000000
--- a/lib/Cake/Model/AclNode.php
+++ /dev/null
@@ -1,182 +0,0 @@
- array('type' => 'nested'));
-
-/**
- * Constructor
- *
- */
- public function __construct() {
- $config = Configure::read('Acl.database');
- if (isset($config)) {
- $this->useDbConfig = $config;
- }
- parent::__construct();
- }
-
-/**
- * Retrieves the Aro/Aco node for this model
- *
- * @param mixed $ref Array with 'model' and 'foreign_key', model object, or string value
- * @return array Node found in database
- * @throws CakeException when binding to a model that doesn't exist.
- */
- public function node($ref = null) {
- $db = $this->getDataSource();
- $type = $this->alias;
- $result = null;
-
- if (!empty($this->useTable)) {
- $table = $this->useTable;
- } else {
- $table = Inflector::pluralize(Inflector::underscore($type));
- }
-
- if (empty($ref)) {
- return null;
- } elseif (is_string($ref)) {
- $path = explode('/', $ref);
- $start = $path[0];
- unset($path[0]);
-
- $queryData = array(
- 'conditions' => array(
- $db->name("{$type}.lft") . ' <= ' . $db->name("{$type}0.lft"),
- $db->name("{$type}.rght") . ' >= ' . $db->name("{$type}0.rght")),
- 'fields' => array('id', 'parent_id', 'model', 'foreign_key', 'alias'),
- 'joins' => array(array(
- 'table' => $table,
- 'alias' => "{$type}0",
- 'type' => 'LEFT',
- 'conditions' => array("{$type}0.alias" => $start)
- )),
- 'order' => $db->name("{$type}.lft") . ' DESC'
- );
-
- foreach ($path as $i => $alias) {
- $j = $i - 1;
-
- $queryData['joins'][] = array(
- 'table' => $table,
- 'alias' => "{$type}{$i}",
- 'type' => 'LEFT',
- 'conditions' => array(
- $db->name("{$type}{$i}.lft") . ' > ' . $db->name("{$type}{$j}.lft"),
- $db->name("{$type}{$i}.rght") . ' < ' . $db->name("{$type}{$j}.rght"),
- $db->name("{$type}{$i}.alias") . ' = ' . $db->value($alias, 'string'),
- $db->name("{$type}{$j}.id") . ' = ' . $db->name("{$type}{$i}.parent_id")
- )
- );
-
- $queryData['conditions'] = array('or' => array(
- $db->name("{$type}.lft") . ' <= ' . $db->name("{$type}0.lft") . ' AND ' . $db->name("{$type}.rght") . ' >= ' . $db->name("{$type}0.rght"),
- $db->name("{$type}.lft") . ' <= ' . $db->name("{$type}{$i}.lft") . ' AND ' . $db->name("{$type}.rght") . ' >= ' . $db->name("{$type}{$i}.rght"))
- );
- }
- $result = $db->read($this, $queryData, -1);
- $path = array_values($path);
-
- if (
- !isset($result[0][$type]) ||
- (!empty($path) && $result[0][$type]['alias'] != $path[count($path) - 1]) ||
- (empty($path) && $result[0][$type]['alias'] != $start)
- ) {
- return false;
- }
- } elseif (is_object($ref) && is_a($ref, 'Model')) {
- $ref = array('model' => $ref->name, 'foreign_key' => $ref->id);
- } elseif (is_array($ref) && !(isset($ref['model']) && isset($ref['foreign_key']))) {
- $name = key($ref);
- list($plugin, $alias) = pluginSplit($name);
-
- $model = ClassRegistry::init(array('class' => $name, 'alias' => $alias));
-
- if (empty($model)) {
- throw new CakeException('cake_dev', "Model class '%s' not found in AclNode::node() when trying to bind %s object", $type, $this->alias);
- }
-
- $tmpRef = null;
- if (method_exists($model, 'bindNode')) {
- $tmpRef = $model->bindNode($ref);
- }
- if (empty($tmpRef)) {
- $ref = array('model' => $alias, 'foreign_key' => $ref[$name][$model->primaryKey]);
- } else {
- if (is_string($tmpRef)) {
- return $this->node($tmpRef);
- }
- $ref = $tmpRef;
- }
- }
- if (is_array($ref)) {
- if (is_array(current($ref)) && is_string(key($ref))) {
- $name = key($ref);
- $ref = current($ref);
- }
- foreach ($ref as $key => $val) {
- if (strpos($key, $type) !== 0 && strpos($key, '.') === false) {
- unset($ref[$key]);
- $ref["{$type}0.{$key}"] = $val;
- }
- }
- $queryData = array(
- 'conditions' => $ref,
- 'fields' => array('id', 'parent_id', 'model', 'foreign_key', 'alias'),
- 'joins' => array(array(
- 'table' => $table,
- 'alias' => "{$type}0",
- 'type' => 'LEFT',
- 'conditions' => array(
- $db->name("{$type}.lft") . ' <= ' . $db->name("{$type}0.lft"),
- $db->name("{$type}.rght") . ' >= ' . $db->name("{$type}0.rght")
- )
- )),
- 'order' => $db->name("{$type}.lft") . ' DESC'
- );
- $result = $db->read($this, $queryData, -1);
-
- if (!$result) {
- throw new CakeException(__d('cake_dev', "AclNode::node() - Couldn't find %s node identified by \"%s\"", $type, print_r($ref, true)));
- }
- }
- return $result;
- }
-
-}
diff --git a/lib/Cake/Model/Aco.php b/lib/Cake/Model/Aco.php
deleted file mode 100644
index 0ee696e070b..00000000000
--- a/lib/Cake/Model/Aco.php
+++ /dev/null
@@ -1,41 +0,0 @@
- array('with' => 'Permission'));
-}
\ No newline at end of file
diff --git a/lib/Cake/Model/AcoAction.php b/lib/Cake/Model/AcoAction.php
deleted file mode 100644
index 2783600b9c4..00000000000
--- a/lib/Cake/Model/AcoAction.php
+++ /dev/null
@@ -1,41 +0,0 @@
- array('with' => 'Permission'));
-}
diff --git a/lib/Cake/Model/Behavior/AclBehavior.php b/lib/Cake/Model/Behavior/AclBehavior.php
deleted file mode 100644
index 0998784ed80..00000000000
--- a/lib/Cake/Model/Behavior/AclBehavior.php
+++ /dev/null
@@ -1,141 +0,0 @@
- 'Aro', 'controlled' => 'Aco', 'both' => array('Aro', 'Aco'));
-
-/**
- * Sets up the configuration for the model, and loads ACL models if they haven't been already
- *
- * @param Model $model
- * @param array $config
- * @return void
- */
- public function setup(Model $model, $config = array()) {
- if (isset($config[0])) {
- $config['type'] = $config[0];
- unset($config[0]);
- }
- $this->settings[$model->name] = array_merge(array('type' => 'controlled'), $config);
- $this->settings[$model->name]['type'] = strtolower($this->settings[$model->name]['type']);
-
- $types = $this->_typeMaps[$this->settings[$model->name]['type']];
-
- if (!is_array($types)) {
- $types = array($types);
- }
- foreach ($types as $type) {
- $model->{$type} = ClassRegistry::init($type);
- }
- if (!method_exists($model, 'parentNode')) {
- trigger_error(__d('cake_dev', 'Callback parentNode() not defined in %s', $model->alias), E_USER_WARNING);
- }
- }
-
-/**
- * Retrieves the Aro/Aco node for this model
- *
- * @param Model $model
- * @param mixed $ref
- * @param string $type Only needed when Acl is set up as 'both', specify 'Aro' or 'Aco' to get the correct node
- * @return array
- * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/acl.html#node
- */
- public function node(Model $model, $ref = null, $type = null) {
- if (empty($type)) {
- $type = $this->_typeMaps[$this->settings[$model->name]['type']];
- if (is_array($type)) {
- trigger_error(__d('cake_dev', 'AclBehavior is setup with more then one type, please specify type parameter for node()'), E_USER_WARNING);
- return null;
- }
- }
- if (empty($ref)) {
- $ref = array('model' => $model->name, 'foreign_key' => $model->id);
- }
- return $model->{$type}->node($ref);
- }
-
-/**
- * Creates a new ARO/ACO node bound to this record
- *
- * @param Model $model
- * @param boolean $created True if this is a new record
- * @return void
- */
- public function afterSave(Model $model, $created) {
- $types = $this->_typeMaps[$this->settings[$model->name]['type']];
- if (!is_array($types)) {
- $types = array($types);
- }
- foreach ($types as $type) {
- $parent = $model->parentNode();
- if (!empty($parent)) {
- $parent = $this->node($model, $parent, $type);
- }
- $data = array(
- 'parent_id' => isset($parent[0][$type]['id']) ? $parent[0][$type]['id'] : null,
- 'model' => $model->name,
- 'foreign_key' => $model->id
- );
- if (!$created) {
- $node = $this->node($model, null, $type);
- $data['id'] = isset($node[0][$type]['id']) ? $node[0][$type]['id'] : null;
- }
- $model->{$type}->create();
- $model->{$type}->save($data);
- }
- }
-
-/**
- * Destroys the ARO/ACO node bound to the deleted record
- *
- * @param Model $model
- * @return void
- */
- public function afterDelete(Model $model) {
- $types = $this->_typeMaps[$this->settings[$model->name]['type']];
- if (!is_array($types)) {
- $types = array($types);
- }
- foreach ($types as $type) {
- $node = Set::extract($this->node($model, null, $type), "0.{$type}.id");
- if (!empty($node)) {
- $model->{$type}->delete($node);
- }
- }
- }
-
-}
diff --git a/lib/Cake/Model/Behavior/ContainableBehavior.php b/lib/Cake/Model/Behavior/ContainableBehavior.php
deleted file mode 100644
index e5929f29a10..00000000000
--- a/lib/Cake/Model/Behavior/ContainableBehavior.php
+++ /dev/null
@@ -1,428 +0,0 @@
-settings[$Model->alias])) {
- $this->settings[$Model->alias] = array('recursive' => true, 'notices' => true, 'autoFields' => true);
- }
- $this->settings[$Model->alias] = array_merge($this->settings[$Model->alias], $settings);
- }
-
-/**
- * Runs before a find() operation. Used to allow 'contain' setting
- * as part of the find call, like this:
- *
- * `Model->find('all', array('contain' => array('Model1', 'Model2')));`
- *
- * {{{
- * Model->find('all', array('contain' => array(
- * 'Model1' => array('Model11', 'Model12'),
- * 'Model2',
- * 'Model3' => array(
- * 'Model31' => 'Model311',
- * 'Model32',
- * 'Model33' => array('Model331', 'Model332')
- * )));
- * }}}
- *
- * @param Model $Model Model using the behavior
- * @param array $query Query parameters as set by cake
- * @return array
- */
- public function beforeFind(Model $Model, $query) {
- $reset = (isset($query['reset']) ? $query['reset'] : true);
- $noContain = (
- (isset($this->runtime[$Model->alias]['contain']) && empty($this->runtime[$Model->alias]['contain'])) ||
- (isset($query['contain']) && empty($query['contain']))
- );
- $contain = array();
- if (isset($this->runtime[$Model->alias]['contain'])) {
- $contain = $this->runtime[$Model->alias]['contain'];
- unset($this->runtime[$Model->alias]['contain']);
- }
- if (isset($query['contain'])) {
- $contain = array_merge($contain, (array)$query['contain']);
- }
- if (
- $noContain || !$contain || in_array($contain, array(null, false), true) ||
- (isset($contain[0]) && $contain[0] === null)
- ) {
- if ($noContain) {
- $query['recursive'] = -1;
- }
- return $query;
- }
- if ((isset($contain[0]) && is_bool($contain[0])) || is_bool(end($contain))) {
- $reset = is_bool(end($contain))
- ? array_pop($contain)
- : array_shift($contain);
- }
- $containments = $this->containments($Model, $contain);
- $map = $this->containmentsMap($containments);
-
- $mandatory = array();
- foreach ($containments['models'] as $name => $model) {
- $instance = $model['instance'];
- $needed = $this->fieldDependencies($instance, $map, false);
- if (!empty($needed)) {
- $mandatory = array_merge($mandatory, $needed);
- }
- if ($contain) {
- $backupBindings = array();
- foreach ($this->types as $relation) {
- if (!empty($instance->__backAssociation[$relation])) {
- $backupBindings[$relation] = $instance->__backAssociation[$relation];
- } else {
- $backupBindings[$relation] = $instance->{$relation};
- }
- }
- foreach ($this->types as $type) {
- $unbind = array();
- foreach ($instance->{$type} as $assoc => $options) {
- if (!isset($model['keep'][$assoc])) {
- $unbind[] = $assoc;
- }
- }
- if (!empty($unbind)) {
- if (!$reset && empty($instance->__backOriginalAssociation)) {
- $instance->__backOriginalAssociation = $backupBindings;
- }
- $instance->unbindModel(array($type => $unbind), $reset);
- }
- foreach ($instance->{$type} as $assoc => $options) {
- if (isset($model['keep'][$assoc]) && !empty($model['keep'][$assoc])) {
- if (isset($model['keep'][$assoc]['fields'])) {
- $model['keep'][$assoc]['fields'] = $this->fieldDependencies($containments['models'][$assoc]['instance'], $map, $model['keep'][$assoc]['fields']);
- }
- if (!$reset && empty($instance->__backOriginalAssociation)) {
- $instance->__backOriginalAssociation = $backupBindings;
- } elseif ($reset) {
- $instance->__backAssociation[$type] = $backupBindings[$type];
- }
- $instance->{$type}[$assoc] = array_merge($instance->{$type}[$assoc], $model['keep'][$assoc]);
- }
- if (!$reset) {
- $instance->__backInnerAssociation[] = $assoc;
- }
- }
- }
- }
- }
-
- if ($this->settings[$Model->alias]['recursive']) {
- $query['recursive'] = (isset($query['recursive'])) ? $query['recursive'] : $containments['depth'];
- }
-
- $autoFields = ($this->settings[$Model->alias]['autoFields']
- && !in_array($Model->findQueryType, array('list', 'count'))
- && !empty($query['fields']));
-
- if (!$autoFields) {
- return $query;
- }
-
- $query['fields'] = (array)$query['fields'];
- foreach (array('hasOne', 'belongsTo') as $type) {
- if (!empty($Model->{$type})) {
- foreach ($Model->{$type} as $assoc => $data) {
- if ($Model->useDbConfig == $Model->{$assoc}->useDbConfig && !empty($data['fields'])) {
- foreach ((array)$data['fields'] as $field) {
- $query['fields'][] = (strpos($field, '.') === false ? $assoc . '.' : '') . $field;
- }
- }
- }
- }
- }
-
- if (!empty($mandatory[$Model->alias])) {
- foreach ($mandatory[$Model->alias] as $field) {
- if ($field == '--primaryKey--') {
- $field = $Model->primaryKey;
- } elseif (preg_match('/^.+\.\-\-[^-]+\-\-$/', $field)) {
- list($modelName, $field) = explode('.', $field);
- if ($Model->useDbConfig == $Model->{$modelName}->useDbConfig) {
- $field = $modelName . '.' . (
- ($field === '--primaryKey--') ? $Model->$modelName->primaryKey : $field
- );
- } else {
- $field = null;
- }
- }
- if ($field !== null) {
- $query['fields'][] = $field;
- }
- }
- }
- $query['fields'] = array_unique($query['fields']);
- return $query;
- }
-
-/**
- * Unbinds all relations from a model except the specified ones. Calling this function without
- * parameters unbinds all related models.
- *
- * @param Model $Model Model on which binding restriction is being applied
- * @return void
- * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html#using-containable
- */
- public function contain(Model $Model) {
- $args = func_get_args();
- $contain = call_user_func_array('am', array_slice($args, 1));
- $this->runtime[$Model->alias]['contain'] = $contain;
- }
-
-/**
- * Permanently restore the original binding settings of given model, useful
- * for restoring the bindings after using 'reset' => false as part of the
- * contain call.
- *
- * @param Model $Model Model on which to reset bindings
- * @return void
- */
- public function resetBindings(Model $Model) {
- if (!empty($Model->__backOriginalAssociation)) {
- $Model->__backAssociation = $Model->__backOriginalAssociation;
- unset($Model->__backOriginalAssociation);
- }
- $Model->resetAssociations();
- if (!empty($Model->__backInnerAssociation)) {
- $assocs = $Model->__backInnerAssociation;
- $Model->__backInnerAssociation = array();
- foreach ($assocs as $currentModel) {
- $this->resetBindings($Model->$currentModel);
- }
- }
- }
-
-/**
- * Process containments for model.
- *
- * @param Model $Model Model on which binding restriction is being applied
- * @param array $contain Parameters to use for restricting this model
- * @param array $containments Current set of containments
- * @param boolean $throwErrors Whether non-existent bindings show throw errors
- * @return array Containments
- */
- public function containments(Model $Model, $contain, $containments = array(), $throwErrors = null) {
- $options = array('className', 'joinTable', 'with', 'foreignKey', 'associationForeignKey', 'conditions', 'fields', 'order', 'limit', 'offset', 'unique', 'finderQuery', 'deleteQuery', 'insertQuery');
- $keep = array();
- if ($throwErrors === null) {
- $throwErrors = (empty($this->settings[$Model->alias]) ? true : $this->settings[$Model->alias]['notices']);
- }
- foreach ((array)$contain as $name => $children) {
- if (is_numeric($name)) {
- $name = $children;
- $children = array();
- }
- if (preg_match('/(? $children);
- }
-
- $children = (array)$children;
- foreach ($children as $key => $val) {
- if (is_string($key) && is_string($val) && !in_array($key, $options, true)) {
- $children[$key] = (array)$val;
- }
- }
-
- $keys = array_keys($children);
- if ($keys && isset($children[0])) {
- $keys = array_merge(array_values($children), $keys);
- }
-
- foreach ($keys as $i => $key) {
- if (is_array($key)) {
- continue;
- }
- $optionKey = in_array($key, $options, true);
- if (!$optionKey && is_string($key) && preg_match('/^[a-z(]/', $key) && (!isset($Model->{$key}) || !is_object($Model->{$key}))) {
- $option = 'fields';
- $val = array($key);
- if ($key{0} == '(') {
- $val = preg_split('/\s*,\s*/', substr(substr($key, 1), 0, -1));
- } elseif (preg_match('/ASC|DESC$/', $key)) {
- $option = 'order';
- $val = $Model->{$name}->alias . '.' . $key;
- } elseif (preg_match('/[ =!]/', $key)) {
- $option = 'conditions';
- $val = $Model->{$name}->alias . '.' . $key;
- }
- $children[$option] = is_array($val) ? $val : array($val);
- $newChildren = null;
- if (!empty($name) && !empty($children[$key])) {
- $newChildren = $children[$key];
- }
- unset($children[$key], $children[$i]);
- $key = $option;
- $optionKey = true;
- if (!empty($newChildren)) {
- $children = Set::merge($children, $newChildren);
- }
- }
- if ($optionKey && isset($children[$key])) {
- if (!empty($keep[$name][$key]) && is_array($keep[$name][$key])) {
- $keep[$name][$key] = array_merge((isset($keep[$name][$key]) ? $keep[$name][$key] : array()), (array)$children[$key]);
- } else {
- $keep[$name][$key] = $children[$key];
- }
- unset($children[$key]);
- }
- }
-
- if (!isset($Model->{$name}) || !is_object($Model->{$name})) {
- if ($throwErrors) {
- trigger_error(__d('cake_dev', 'Model "%s" is not associated with model "%s"', $Model->alias, $name), E_USER_WARNING);
- }
- continue;
- }
-
- $containments = $this->containments($Model->{$name}, $children, $containments);
- $depths[] = $containments['depth'] + 1;
- if (!isset($keep[$name])) {
- $keep[$name] = array();
- }
- }
-
- if (!isset($containments['models'][$Model->alias])) {
- $containments['models'][$Model->alias] = array('keep' => array(), 'instance' => &$Model);
- }
-
- $containments['models'][$Model->alias]['keep'] = array_merge($containments['models'][$Model->alias]['keep'], $keep);
- $containments['depth'] = empty($depths) ? 0 : max($depths);
- return $containments;
- }
-
-/**
- * Calculate needed fields to fetch the required bindings for the given model.
- *
- * @param Model $Model Model
- * @param array $map Map of relations for given model
- * @param mixed $fields If array, fields to initially load, if false use $Model as primary model
- * @return array Fields
- */
- public function fieldDependencies(Model $Model, $map, $fields = array()) {
- if ($fields === false) {
- foreach ($map as $parent => $children) {
- foreach ($children as $type => $bindings) {
- foreach ($bindings as $dependency) {
- if ($type == 'hasAndBelongsToMany') {
- $fields[$parent][] = '--primaryKey--';
- } elseif ($type == 'belongsTo') {
- $fields[$parent][] = $dependency . '.--primaryKey--';
- }
- }
- }
- }
- return $fields;
- }
- if (empty($map[$Model->alias])) {
- return $fields;
- }
- foreach ($map[$Model->alias] as $type => $bindings) {
- foreach ($bindings as $dependency) {
- $innerFields = array();
- switch ($type) {
- case 'belongsTo':
- $fields[] = $Model->{$type}[$dependency]['foreignKey'];
- break;
- case 'hasOne':
- case 'hasMany':
- $innerFields[] = $Model->$dependency->primaryKey;
- $fields[] = $Model->primaryKey;
- break;
- }
- if (!empty($innerFields) && !empty($Model->{$type}[$dependency]['fields'])) {
- $Model->{$type}[$dependency]['fields'] = array_unique(array_merge($Model->{$type}[$dependency]['fields'], $innerFields));
- }
- }
- }
- return array_unique($fields);
- }
-
-/**
- * Build the map of containments
- *
- * @param array $containments Containments
- * @return array Built containments
- */
- public function containmentsMap($containments) {
- $map = array();
- foreach ($containments['models'] as $name => $model) {
- $instance = $model['instance'];
- foreach ($this->types as $type) {
- foreach ($instance->{$type} as $assoc => $options) {
- if (isset($model['keep'][$assoc])) {
- $map[$name][$type] = isset($map[$name][$type]) ? array_merge($map[$name][$type], (array)$assoc) : (array)$assoc;
- }
- }
- }
- }
- return $map;
- }
-
-}
diff --git a/lib/Cake/Model/Behavior/TranslateBehavior.php b/lib/Cake/Model/Behavior/TranslateBehavior.php
deleted file mode 100644
index 5f3f2f32ac4..00000000000
--- a/lib/Cake/Model/Behavior/TranslateBehavior.php
+++ /dev/null
@@ -1,577 +0,0 @@
- array('field_one',
- * 'field_two' => 'FieldAssoc', 'field_three'))
- *
- * With above example only one permanent hasMany will be joined (for field_two
- * as FieldAssoc)
- *
- * $config could be empty - and translations configured dynamically by
- * bindTranslation() method
- *
- * @param Model $model Model the behavior is being attached to.
- * @param array $config Array of configuration information.
- * @return mixed
- */
- public function setup(Model $model, $config = array()) {
- $db = ConnectionManager::getDataSource($model->useDbConfig);
- if (!$db->connected) {
- trigger_error(
- __d('cake_dev', 'Datasource %s for TranslateBehavior of model %s is not connected', $model->useDbConfig, $model->alias),
- E_USER_ERROR
- );
- return false;
- }
-
- $this->settings[$model->alias] = array();
- $this->runtime[$model->alias] = array('fields' => array());
- $this->translateModel($model);
- return $this->bindTranslation($model, $config, false);
- }
-
-/**
- * Cleanup Callback unbinds bound translations and deletes setting information.
- *
- * @param Model $model Model being detached.
- * @return void
- */
- public function cleanup(Model $model) {
- $this->unbindTranslation($model);
- unset($this->settings[$model->alias]);
- unset($this->runtime[$model->alias]);
- }
-
-/**
- * beforeFind Callback
- *
- * @param Model $model Model find is being run on.
- * @param array $query Array of Query parameters.
- * @return array Modified query
- */
- public function beforeFind(Model $model, $query) {
- $this->runtime[$model->alias]['virtualFields'] = $model->virtualFields;
- $locale = $this->_getLocale($model);
- if (empty($locale)) {
- return $query;
- }
- $db = $model->getDataSource();
- $RuntimeModel = $this->translateModel($model);
-
- if (!empty($RuntimeModel->tablePrefix)) {
- $tablePrefix = $RuntimeModel->tablePrefix;
- } else {
- $tablePrefix = $db->config['prefix'];
- }
- $joinTable = new StdClass();
- $joinTable->tablePrefix = $tablePrefix;
- $joinTable->table = $RuntimeModel->table;
- $joinTable->schemaName = $RuntimeModel->getDataSource()->getSchemaName();
-
- $this->_joinTable = $joinTable;
- $this->_runtimeModel = $RuntimeModel;
-
- if (is_string($query['fields']) && 'COUNT(*) AS ' . $db->name('count') == $query['fields']) {
- $query['fields'] = 'COUNT(DISTINCT(' . $db->name($model->alias . '.' . $model->primaryKey) . ')) ' . $db->alias . 'count';
- $query['joins'][] = array(
- 'type' => 'INNER',
- 'alias' => $RuntimeModel->alias,
- 'table' => $joinTable,
- 'conditions' => array(
- $model->alias . '.' . $model->primaryKey => $db->identifier($RuntimeModel->alias . '.foreign_key'),
- $RuntimeModel->alias . '.model' => $model->name,
- $RuntimeModel->alias . '.locale' => $locale
- )
- );
- $conditionFields = $this->_checkConditions($model, $query);
- foreach ($conditionFields as $field) {
- $query = $this->_addJoin($model, $query, $field, $field, $locale);
- }
- unset($this->_joinTable, $this->_runtimeModel);
- return $query;
- }
-
- $fields = array_merge($this->settings[$model->alias], $this->runtime[$model->alias]['fields']);
- $addFields = array();
- if (empty($query['fields'])) {
- $addFields = $fields;
- } elseif (is_array($query['fields'])) {
- foreach ($fields as $key => $value) {
- $field = (is_numeric($key)) ? $value : $key;
-
- if (in_array($model->alias . '.*', $query['fields']) || in_array($model->alias . '.' . $field, $query['fields']) || in_array($field, $query['fields'])) {
- $addFields[] = $field;
- }
- }
- }
-
- $this->runtime[$model->alias]['virtualFields'] = $model->virtualFields;
- if ($addFields) {
- foreach ($addFields as $_f => $field) {
- $aliasField = is_numeric($_f) ? $field : $_f;
-
- foreach (array($aliasField, $model->alias . '.' . $aliasField) as $_field) {
- $key = array_search($_field, (array)$query['fields']);
-
- if ($key !== false) {
- unset($query['fields'][$key]);
- }
- }
- $query = $this->_addJoin($model, $query, $field, $aliasField, $locale);
- }
- }
- $this->runtime[$model->alias]['beforeFind'] = $addFields;
- unset($this->_joinTable, $this->_runtimeModel);
- return $query;
- }
-
-/**
- * Check a query's conditions for translated fields.
- * Return an array of translated fields found in the conditions.
- *
- * @param Model $model The model being read.
- * @param array $query The query array.
- * @return array The list of translated fields that are in the conditions.
- */
- protected function _checkConditions(Model $model, $query) {
- $conditionFields = array();
- if (empty($query['conditions']) || (!empty($query['conditions']) && !is_array($query['conditions'])) ) {
- return $conditionFields;
- }
- foreach ($query['conditions'] as $col => $val) {
- foreach ($this->settings[$model->alias] as $field => $assoc) {
- if (is_numeric($field)) {
- $field = $assoc;
- }
- if (strpos($col, $field) !== false) {
- $conditionFields[] = $field;
- }
- }
- }
- return $conditionFields;
- }
-
-/**
- * Appends a join for translated fields and possibly a field.
- *
- * @param Model $model The model being worked on.
- * @param object $joinTable The jointable object.
- * @param array $query The query array to append a join to.
- * @param string $field The field name being joined.
- * @param string $aliasField The aliased field name being joined.
- * @param mixed $locale The locale(s) having joins added.
- * @param boolean $addField Whether or not to add a field.
- * @return array The modfied query
- */
- protected function _addJoin(Model $model, $query, $field, $aliasField, $locale, $addField = false) {
- $db = ConnectionManager::getDataSource($model->useDbConfig);
-
- $RuntimeModel = $this->_runtimeModel;
- $joinTable = $this->_joinTable;
-
- if (is_array($locale)) {
- foreach ($locale as $_locale) {
- $model->virtualFields['i18n_' . $field . '_' . $_locale] = 'I18n__' . $field . '__' . $_locale . '.content';
- if (!empty($query['fields']) && is_array($query['fields'])) {
- $query['fields'][] = 'i18n_' . $field . '_' . $_locale;
- }
- $query['joins'][] = array(
- 'type' => 'LEFT',
- 'alias' => 'I18n__' . $field . '__' . $_locale,
- 'table' => $joinTable,
- 'conditions' => array(
- $model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}__{$_locale}.foreign_key"),
- 'I18n__' . $field . '__' . $_locale . '.model' => $model->name,
- 'I18n__' . $field . '__' . $_locale . '.' . $RuntimeModel->displayField => $aliasField,
- 'I18n__' . $field . '__' . $_locale . '.locale' => $_locale
- )
- );
- }
- } else {
- $model->virtualFields['i18n_' . $field] = 'I18n__' . $field . '.content';
- if (!empty($query['fields']) && is_array($query['fields'])) {
- $query['fields'][] = 'i18n_' . $field;
- }
- $query['joins'][] = array(
- 'type' => 'INNER',
- 'alias' => 'I18n__' . $field,
- 'table' => $joinTable,
- 'conditions' => array(
- $model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}.foreign_key"),
- 'I18n__' . $field . '.model' => $model->name,
- 'I18n__' . $field . '.' . $RuntimeModel->displayField => $aliasField,
- 'I18n__' . $field . '.locale' => $locale
- )
- );
- }
- return $query;
- }
-
-/**
- * afterFind Callback
- *
- * @param Model $model Model find was run on
- * @param array $results Array of model results.
- * @param boolean $primary Did the find originate on $model.
- * @return array Modified results
- */
- public function afterFind(Model $model, $results, $primary) {
- $model->virtualFields = $this->runtime[$model->alias]['virtualFields'];
- $this->runtime[$model->alias]['virtualFields'] = $this->runtime[$model->alias]['fields'] = array();
- $locale = $this->_getLocale($model);
-
- if (empty($locale) || empty($results) || empty($this->runtime[$model->alias]['beforeFind'])) {
- return $results;
- }
- $beforeFind = $this->runtime[$model->alias]['beforeFind'];
-
- foreach ($results as $key => &$row) {
- $results[$key][$model->alias]['locale'] = (is_array($locale)) ? current($locale) : $locale;
- foreach ($beforeFind as $_f => $field) {
- $aliasField = is_numeric($_f) ? $field : $_f;
-
- if (is_array($locale)) {
- foreach ($locale as $_locale) {
- if (!isset($row[$model->alias][$aliasField]) && !empty($row[$model->alias]['i18n_' . $field . '_' . $_locale])) {
- $row[$model->alias][$aliasField] = $row[$model->alias]['i18n_' . $field . '_' . $_locale];
- $row[$model->alias]['locale'] = $_locale;
- }
- unset($row[$model->alias]['i18n_' . $field . '_' . $_locale]);
- }
-
- if (!isset($row[$model->alias][$aliasField])) {
- $row[$model->alias][$aliasField] = '';
- }
- } else {
- $value = '';
- if (!empty($row[$model->alias]['i18n_' . $field])) {
- $value = $row[$model->alias]['i18n_' . $field];
- }
- $row[$model->alias][$aliasField] = $value;
- unset($row[$model->alias]['i18n_' . $field]);
- }
- }
- }
- return $results;
- }
-
-/**
- * beforeValidate Callback
- *
- * @param Model $model Model invalidFields was called on.
- * @return boolean
- */
- public function beforeValidate(Model $model) {
- $locale = $this->_getLocale($model);
- if (empty($locale)) {
- return true;
- }
- $fields = array_merge($this->settings[$model->alias], $this->runtime[$model->alias]['fields']);
- $tempData = array();
-
- foreach ($fields as $key => $value) {
- $field = (is_numeric($key)) ? $value : $key;
-
- if (isset($model->data[$model->alias][$field])) {
- $tempData[$field] = $model->data[$model->alias][$field];
- if (is_array($model->data[$model->alias][$field])) {
- if (is_string($locale) && !empty($model->data[$model->alias][$field][$locale])) {
- $model->data[$model->alias][$field] = $model->data[$model->alias][$field][$locale];
- } else {
- $values = array_values($model->data[$model->alias][$field]);
- $model->data[$model->alias][$field] = $values[0];
- }
- }
- }
- }
- $this->runtime[$model->alias]['beforeSave'] = $tempData;
- return true;
- }
-
-/**
- * afterSave Callback
- *
- * @param Model $model Model the callback is called on
- * @param boolean $created Whether or not the save created a record.
- * @return void
- */
- public function afterSave(Model $model, $created) {
- if (!isset($this->runtime[$model->alias]['beforeSave'])) {
- return true;
- }
- $locale = $this->_getLocale($model);
- $tempData = $this->runtime[$model->alias]['beforeSave'];
- unset($this->runtime[$model->alias]['beforeSave']);
- $conditions = array('model' => $model->alias, 'foreign_key' => $model->id);
- $RuntimeModel = $this->translateModel($model);
-
- foreach ($tempData as $field => $value) {
- unset($conditions['content']);
- $conditions['field'] = $field;
- if (is_array($value)) {
- $conditions['locale'] = array_keys($value);
- } else {
- $conditions['locale'] = $locale;
- if (is_array($locale)) {
- $value = array($locale[0] => $value);
- } else {
- $value = array($locale => $value);
- }
- }
- $translations = $RuntimeModel->find('list', array('conditions' => $conditions, 'fields' => array($RuntimeModel->alias . '.locale', $RuntimeModel->alias . '.id')));
- foreach ($value as $_locale => $_value) {
- $RuntimeModel->create();
- $conditions['locale'] = $_locale;
- $conditions['content'] = $_value;
- if (array_key_exists($_locale, $translations)) {
- $RuntimeModel->save(array($RuntimeModel->alias => array_merge($conditions, array('id' => $translations[$_locale]))));
- } else {
- $RuntimeModel->save(array($RuntimeModel->alias => $conditions));
- }
- }
- }
- }
-
-/**
- * afterDelete Callback
- *
- * @param Model $model Model the callback was run on.
- * @return void
- */
- public function afterDelete(Model $model) {
- $RuntimeModel = $this->translateModel($model);
- $conditions = array('model' => $model->alias, 'foreign_key' => $model->id);
- $RuntimeModel->deleteAll($conditions);
- }
-
-/**
- * Get selected locale for model
- *
- * @param Model $model Model the locale needs to be set/get on.
- * @return mixed string or false
- */
- protected function _getLocale(Model $model) {
- if (!isset($model->locale) || is_null($model->locale)) {
- $I18n = I18n::getInstance();
- $I18n->l10n->get(Configure::read('Config.language'));
- $model->locale = $I18n->l10n->locale;
- }
-
- return $model->locale;
- }
-
-/**
- * Get instance of model for translations.
- *
- * If the model has a translateModel property set, this will be used as the class
- * name to find/use. If no translateModel property is found 'I18nModel' will be used.
- *
- * @param Model $model Model to get a translatemodel for.
- * @return Model
- */
- public function translateModel(Model $model) {
- if (!isset($this->runtime[$model->alias]['model'])) {
- if (!isset($model->translateModel) || empty($model->translateModel)) {
- $className = 'I18nModel';
- } else {
- $className = $model->translateModel;
- }
-
- $this->runtime[$model->alias]['model'] = ClassRegistry::init($className, 'Model');
- }
- if (!empty($model->translateTable) && $model->translateTable !== $this->runtime[$model->alias]['model']->useTable) {
- $this->runtime[$model->alias]['model']->setSource($model->translateTable);
- } elseif (empty($model->translateTable) && empty($model->translateModel)) {
- $this->runtime[$model->alias]['model']->setSource('i18n');
- }
- return $this->runtime[$model->alias]['model'];
- }
-
-/**
- * Bind translation for fields, optionally with hasMany association for
- * fake field.
- *
- * *Note* You should avoid binding translations that overlap existing model properties.
- * This can cause un-expected and un-desirable behavior.
- *
- * @param Model $model instance of model
- * @param string|array $fields string with field or array(field1, field2=>AssocName, field3)
- * @param boolean $reset
- * @return boolean
- * @throws CakeException when attempting to bind a translating called name. This is not allowed
- * as it shadows Model::$name.
- */
- public function bindTranslation(Model $model, $fields, $reset = true) {
- if (is_string($fields)) {
- $fields = array($fields);
- }
- $associations = array();
- $RuntimeModel = $this->translateModel($model);
- $default = array('className' => $RuntimeModel->alias, 'foreignKey' => 'foreign_key');
-
- foreach ($fields as $key => $value) {
- if (is_numeric($key)) {
- $field = $value;
- $association = null;
- } else {
- $field = $key;
- $association = $value;
- }
- if ($association === 'name') {
- throw new CakeException(
- __d('cake_dev', 'You cannot bind a translation named "name".')
- );
- }
-
- if (array_key_exists($field, $this->settings[$model->alias])) {
- unset($this->settings[$model->alias][$field]);
- } elseif (in_array($field, $this->settings[$model->alias])) {
- $this->settings[$model->alias] = array_merge(array_diff_assoc($this->settings[$model->alias], array($field)));
- }
-
- if (array_key_exists($field, $this->runtime[$model->alias]['fields'])) {
- unset($this->runtime[$model->alias]['fields'][$field]);
- } elseif (in_array($field, $this->runtime[$model->alias]['fields'])) {
- $this->runtime[$model->alias]['fields'] = array_merge(array_diff_assoc($this->runtime[$model->alias]['fields'], array($field)));
- }
-
- if (is_null($association)) {
- if ($reset) {
- $this->runtime[$model->alias]['fields'][] = $field;
- } else {
- $this->settings[$model->alias][] = $field;
- }
- } else {
- if ($reset) {
- $this->runtime[$model->alias]['fields'][$field] = $association;
- } else {
- $this->settings[$model->alias][$field] = $association;
- }
-
- foreach (array('hasOne', 'hasMany', 'belongsTo', 'hasAndBelongsToMany') as $type) {
- if (isset($model->{$type}[$association]) || isset($model->__backAssociation[$type][$association])) {
- trigger_error(
- __d('cake_dev', 'Association %s is already bound to model %s', $association, $model->alias),
- E_USER_ERROR
- );
- return false;
- }
- }
- $associations[$association] = array_merge($default, array('conditions' => array(
- 'model' => $model->alias,
- $RuntimeModel->displayField => $field
- )));
- }
- }
-
- if (!empty($associations)) {
- $model->bindModel(array('hasMany' => $associations), $reset);
- }
- return true;
- }
-
-/**
- * Unbind translation for fields, optionally unbinds hasMany association for
- * fake field
- *
- * @param Model $model instance of model
- * @param mixed $fields string with field, or array(field1, field2=>AssocName, field3), or null for
- * unbind all original translations
- * @return boolean
- */
- public function unbindTranslation(Model $model, $fields = null) {
- if (empty($fields) && empty($this->settings[$model->alias])) {
- return false;
- }
- if (empty($fields)) {
- return $this->unbindTranslation($model, $this->settings[$model->alias]);
- }
-
- if (is_string($fields)) {
- $fields = array($fields);
- }
- $RuntimeModel = $this->translateModel($model);
- $associations = array();
-
- foreach ($fields as $key => $value) {
- if (is_numeric($key)) {
- $field = $value;
- $association = null;
- } else {
- $field = $key;
- $association = $value;
- }
-
- if (array_key_exists($field, $this->settings[$model->alias])) {
- unset($this->settings[$model->alias][$field]);
- } elseif (in_array($field, $this->settings[$model->alias])) {
- $this->settings[$model->alias] = array_merge(array_diff_assoc($this->settings[$model->alias], array($field)));
- }
-
- if (array_key_exists($field, $this->runtime[$model->alias]['fields'])) {
- unset($this->runtime[$model->alias]['fields'][$field]);
- } elseif (in_array($field, $this->runtime[$model->alias]['fields'])) {
- $this->runtime[$model->alias]['fields'] = array_merge(array_diff_assoc($this->runtime[$model->alias]['fields'], array($field)));
- }
-
- if (!is_null($association) && (isset($model->hasMany[$association]) || isset($model->__backAssociation['hasMany'][$association]))) {
- $associations[] = $association;
- }
- }
-
- if (!empty($associations)) {
- $model->unbindModel(array('hasMany' => $associations), false);
- }
- return true;
- }
-
-}
-
diff --git a/lib/Cake/Model/Behavior/TreeBehavior.php b/lib/Cake/Model/Behavior/TreeBehavior.php
deleted file mode 100644
index 03a8f2662f8..00000000000
--- a/lib/Cake/Model/Behavior/TreeBehavior.php
+++ /dev/null
@@ -1,1003 +0,0 @@
- 'parent_id', 'left' => 'lft', 'right' => 'rght',
- 'scope' => '1 = 1', 'type' => 'nested', '__parentChange' => false, 'recursive' => -1
- );
-
-/**
- * Used to preserve state between delete callbacks.
- *
- * @var array
- */
- protected $_deletedRow = null;
-
-/**
- * Initiate Tree behavior
- *
- * @param Model $Model instance of model
- * @param array $config array of configuration settings.
- * @return void
- */
- public function setup(Model $Model, $config = array()) {
- if (isset($config[0])) {
- $config['type'] = $config[0];
- unset($config[0]);
- }
- $settings = array_merge($this->_defaults, $config);
-
- if (in_array($settings['scope'], $Model->getAssociated('belongsTo'))) {
- $data = $Model->getAssociated($settings['scope']);
- $parent = $Model->{$settings['scope']};
- $settings['scope'] = $Model->alias . '.' . $data['foreignKey'] . ' = ' . $parent->alias . '.' . $parent->primaryKey;
- $settings['recursive'] = 0;
- }
- $this->settings[$Model->alias] = $settings;
- }
-
-/**
- * After save method. Called after all saves
- *
- * Overridden to transparently manage setting the lft and rght fields if and only if the parent field is included in the
- * parameters to be saved.
- *
- * @param Model $Model Model instance.
- * @param boolean $created indicates whether the node just saved was created or updated
- * @return boolean true on success, false on failure
- */
- public function afterSave(Model $Model, $created) {
- extract($this->settings[$Model->alias]);
- if ($created) {
- if ((isset($Model->data[$Model->alias][$parent])) && $Model->data[$Model->alias][$parent]) {
- return $this->_setParent($Model, $Model->data[$Model->alias][$parent], $created);
- }
- } elseif ($this->settings[$Model->alias]['__parentChange']) {
- $this->settings[$Model->alias]['__parentChange'] = false;
- return $this->_setParent($Model, $Model->data[$Model->alias][$parent]);
- }
- }
-
-/**
- * Runs before a find() operation
- *
- * @param Model $Model Model using the behavior
- * @param array $query Query parameters as set by cake
- * @return array
- */
- public function beforeFind(Model $Model, $query) {
- if ($Model->findQueryType == 'threaded' && !isset($query['parent'])) {
- $query['parent'] = $this->settings[$Model->alias]['parent'];
- }
- return $query;
- }
-
-/**
- * Stores the record about to be deleted.
- *
- * This is used to delete child nodes in the afterDelete.
- *
- * @param Model $Model Model instance
- * @param boolean $cascade
- * @return boolean
- */
- public function beforeDelete(Model $Model, $cascade = true) {
- extract($this->settings[$Model->alias]);
- $data = current($Model->find('first', array(
- 'conditions' => array($Model->alias . '.' . $Model->primaryKey => $Model->id),
- 'fields' => array($Model->alias . '.' . $left, $Model->alias . '.' . $right),
- 'recursive' => -1)));
- $this->_deletedRow = $data;
- return true;
- }
-
-/**
- * After delete method.
- *
- * Will delete the current node and all children using the deleteAll method and sync the table
- *
- * @param Model $Model Model instance
- * @return boolean true to continue, false to abort the delete
- */
- public function afterDelete(Model $Model) {
- extract($this->settings[$Model->alias]);
- $data = $this->_deletedRow;
- $this->_deletedRow = null;
-
- if (!$data[$right] || !$data[$left]) {
- return true;
- }
- $diff = $data[$right] - $data[$left] + 1;
-
- if ($diff > 2) {
- if (is_string($scope)) {
- $scope = array($scope);
- }
- $scope[]["{$Model->alias}.{$left} BETWEEN ? AND ?"] = array($data[$left] + 1, $data[$right] - 1);
- $Model->deleteAll($scope);
- }
- $this->_sync($Model, $diff, '-', '> ' . $data[$right]);
- return true;
- }
-
-/**
- * Before save method. Called before all saves
- *
- * Overridden to transparently manage setting the lft and rght fields if and only if the parent field is included in the
- * parameters to be saved. For newly created nodes with NO parent the left and right field values are set directly by
- * this method bypassing the setParent logic.
- *
- * @since 1.2
- * @param Model $Model Model instance
- * @return boolean true to continue, false to abort the save
- */
- public function beforeSave(Model $Model) {
- extract($this->settings[$Model->alias]);
-
- $this->_addToWhitelist($Model, array($left, $right));
- if (!$Model->id) {
- if (array_key_exists($parent, $Model->data[$Model->alias]) && $Model->data[$Model->alias][$parent]) {
- $parentNode = $Model->find('first', array(
- 'conditions' => array($scope, $Model->escapeField() => $Model->data[$Model->alias][$parent]),
- 'fields' => array($Model->primaryKey, $right), 'recursive' => $recursive
- ));
- if (!$parentNode) {
- return false;
- }
- list($parentNode) = array_values($parentNode);
- $Model->data[$Model->alias][$left] = 0;
- $Model->data[$Model->alias][$right] = 0;
- } else {
- $edge = $this->_getMax($Model, $scope, $right, $recursive);
- $Model->data[$Model->alias][$left] = $edge + 1;
- $Model->data[$Model->alias][$right] = $edge + 2;
- }
- } elseif (array_key_exists($parent, $Model->data[$Model->alias])) {
- if ($Model->data[$Model->alias][$parent] != $Model->field($parent)) {
- $this->settings[$Model->alias]['__parentChange'] = true;
- }
- if (!$Model->data[$Model->alias][$parent]) {
- $Model->data[$Model->alias][$parent] = null;
- $this->_addToWhitelist($Model, $parent);
- } else {
- $values = $Model->find('first', array(
- 'conditions' => array($scope, $Model->escapeField() => $Model->id),
- 'fields' => array($Model->primaryKey, $parent, $left, $right), 'recursive' => $recursive)
- );
-
- if ($values === false) {
- return false;
- }
- list($node) = array_values($values);
-
- $parentNode = $Model->find('first', array(
- 'conditions' => array($scope, $Model->escapeField() => $Model->data[$Model->alias][$parent]),
- 'fields' => array($Model->primaryKey, $left, $right), 'recursive' => $recursive
- ));
- if (!$parentNode) {
- return false;
- }
- list($parentNode) = array_values($parentNode);
-
- if (($node[$left] < $parentNode[$left]) && ($parentNode[$right] < $node[$right])) {
- return false;
- } elseif ($node[$Model->primaryKey] == $parentNode[$Model->primaryKey]) {
- return false;
- }
- }
- }
- return true;
- }
-
-/**
- * Get the number of child nodes
- *
- * If the direct parameter is set to true, only the direct children are counted (based upon the parent_id field)
- * If false is passed for the id parameter, all top level nodes are counted, or all nodes are counted.
- *
- * @param Model $Model Model instance
- * @param mixed $id The ID of the record to read or false to read all top level nodes
- * @param boolean $direct whether to count direct, or all, children
- * @return integer number of child nodes
- * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::childCount
- */
- public function childCount(Model $Model, $id = null, $direct = false) {
- if (is_array($id)) {
- extract (array_merge(array('id' => null), $id));
- }
- if ($id === null && $Model->id) {
- $id = $Model->id;
- } elseif (!$id) {
- $id = null;
- }
- extract($this->settings[$Model->alias]);
-
- if ($direct) {
- return $Model->find('count', array('conditions' => array($scope, $Model->escapeField($parent) => $id)));
- }
-
- if ($id === null) {
- return $Model->find('count', array('conditions' => $scope));
- } elseif ($Model->id === $id && isset($Model->data[$Model->alias][$left]) && isset($Model->data[$Model->alias][$right])) {
- $data = $Model->data[$Model->alias];
- } else {
- $data = $Model->find('first', array('conditions' => array($scope, $Model->escapeField() => $id), 'recursive' => $recursive));
- if (!$data) {
- return 0;
- }
- $data = $data[$Model->alias];
- }
- return ($data[$right] - $data[$left] - 1) / 2;
- }
-
-/**
- * Get the child nodes of the current model
- *
- * If the direct parameter is set to true, only the direct children are returned (based upon the parent_id field)
- * If false is passed for the id parameter, top level, or all (depending on direct parameter appropriate) are counted.
- *
- * @param Model $Model Model instance
- * @param mixed $id The ID of the record to read
- * @param boolean $direct whether to return only the direct, or all, children
- * @param mixed $fields Either a single string of a field name, or an array of field names
- * @param string $order SQL ORDER BY conditions (e.g. "price DESC" or "name ASC") defaults to the tree order
- * @param integer $limit SQL LIMIT clause, for calculating items per page.
- * @param integer $page Page number, for accessing paged data
- * @param integer $recursive The number of levels deep to fetch associated records
- * @return array Array of child nodes
- * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::children
- */
- public function children(Model $Model, $id = null, $direct = false, $fields = null, $order = null, $limit = null, $page = 1, $recursive = null) {
- if (is_array($id)) {
- extract (array_merge(array('id' => null), $id));
- }
- $overrideRecursive = $recursive;
-
- if ($id === null && $Model->id) {
- $id = $Model->id;
- } elseif (!$id) {
- $id = null;
- }
-
- extract($this->settings[$Model->alias]);
-
- if (!is_null($overrideRecursive)) {
- $recursive = $overrideRecursive;
- }
- if (!$order) {
- $order = $Model->alias . '.' . $left . ' asc';
- }
- if ($direct) {
- $conditions = array($scope, $Model->escapeField($parent) => $id);
- return $Model->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive'));
- }
-
- if (!$id) {
- $conditions = $scope;
- } else {
- $result = array_values((array)$Model->find('first', array(
- 'conditions' => array($scope, $Model->escapeField() => $id),
- 'fields' => array($left, $right),
- 'recursive' => $recursive
- )));
-
- if (empty($result) || !isset($result[0])) {
- return array();
- }
- $conditions = array($scope,
- $Model->escapeField($right) . ' <' => $result[0][$right],
- $Model->escapeField($left) . ' >' => $result[0][$left]
- );
- }
- return $Model->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive'));
- }
-
-/**
- * A convenience method for returning a hierarchical array used for HTML select boxes
- *
- * @param Model $Model Model instance
- * @param mixed $conditions SQL conditions as a string or as an array('field' =>'value',...)
- * @param string $keyPath A string path to the key, i.e. "{n}.Post.id"
- * @param string $valuePath A string path to the value, i.e. "{n}.Post.title"
- * @param string $spacer The character or characters which will be repeated
- * @param integer $recursive The number of levels deep to fetch associated records
- * @return array An associative array of records, where the id is the key, and the display field is the value
- * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::generateTreeList
- */
- public function generateTreeList(Model $Model, $conditions = null, $keyPath = null, $valuePath = null, $spacer = '_', $recursive = null) {
- $overrideRecursive = $recursive;
- extract($this->settings[$Model->alias]);
- if (!is_null($overrideRecursive)) {
- $recursive = $overrideRecursive;
- }
-
- if ($keyPath == null && $valuePath == null && $Model->hasField($Model->displayField)) {
- $fields = array($Model->primaryKey, $Model->displayField, $left, $right);
- } else {
- $fields = null;
- }
-
- if ($keyPath == null) {
- $keyPath = '{n}.' . $Model->alias . '.' . $Model->primaryKey;
- }
-
- if ($valuePath == null) {
- $valuePath = array('{0}{1}', '{n}.tree_prefix', '{n}.' . $Model->alias . '.' . $Model->displayField);
-
- } elseif (is_string($valuePath)) {
- $valuePath = array('{0}{1}', '{n}.tree_prefix', $valuePath);
-
- } else {
- $valuePath[0] = '{' . (count($valuePath) - 1) . '}' . $valuePath[0];
- $valuePath[] = '{n}.tree_prefix';
- }
- $order = $Model->alias . '.' . $left . ' asc';
- $results = $Model->find('all', compact('conditions', 'fields', 'order', 'recursive'));
- $stack = array();
-
- foreach ($results as $i => $result) {
- while ($stack && ($stack[count($stack) - 1] < $result[$Model->alias][$right])) {
- array_pop($stack);
- }
- $results[$i]['tree_prefix'] = str_repeat($spacer, count($stack));
- $stack[] = $result[$Model->alias][$right];
- }
- if (empty($results)) {
- return array();
- }
- return Set::combine($results, $keyPath, $valuePath);
- }
-
-/**
- * Get the parent node
- *
- * reads the parent id and returns this node
- *
- * @param Model $Model Model instance
- * @param mixed $id The ID of the record to read
- * @param string|array $fields
- * @param integer $recursive The number of levels deep to fetch associated records
- * @return array|boolean Array of data for the parent node
- * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::getParentNode
- */
- public function getParentNode(Model $Model, $id = null, $fields = null, $recursive = null) {
- if (is_array($id)) {
- extract (array_merge(array('id' => null), $id));
- }
- $overrideRecursive = $recursive;
- if (empty ($id)) {
- $id = $Model->id;
- }
- extract($this->settings[$Model->alias]);
- if (!is_null($overrideRecursive)) {
- $recursive = $overrideRecursive;
- }
- $parentId = $Model->find('first', array('conditions' => array($Model->primaryKey => $id), 'fields' => array($parent), 'recursive' => -1));
-
- if ($parentId) {
- $parentId = $parentId[$Model->alias][$parent];
- $parent = $Model->find('first', array('conditions' => array($Model->escapeField() => $parentId), 'fields' => $fields, 'recursive' => $recursive));
-
- return $parent;
- }
- return false;
- }
-
-/**
- * Get the path to the given node
- *
- * @param Model $Model Model instance
- * @param mixed $id The ID of the record to read
- * @param mixed $fields Either a single string of a field name, or an array of field names
- * @param integer $recursive The number of levels deep to fetch associated records
- * @return array Array of nodes from top most parent to current node
- * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::getPath
- */
- public function getPath(Model $Model, $id = null, $fields = null, $recursive = null) {
- if (is_array($id)) {
- extract (array_merge(array('id' => null), $id));
- }
- $overrideRecursive = $recursive;
- if (empty ($id)) {
- $id = $Model->id;
- }
- extract($this->settings[$Model->alias]);
- if (!is_null($overrideRecursive)) {
- $recursive = $overrideRecursive;
- }
- $result = $Model->find('first', array('conditions' => array($Model->escapeField() => $id), 'fields' => array($left, $right), 'recursive' => $recursive));
- if ($result) {
- $result = array_values($result);
- } else {
- return null;
- }
- $item = $result[0];
- $results = $Model->find('all', array(
- 'conditions' => array($scope, $Model->escapeField($left) . ' <=' => $item[$left], $Model->escapeField($right) . ' >=' => $item[$right]),
- 'fields' => $fields, 'order' => array($Model->escapeField($left) => 'asc'), 'recursive' => $recursive
- ));
- return $results;
- }
-
-/**
- * Reorder the node without changing the parent.
- *
- * If the node is the last child, or is a top level node with no subsequent node this method will return false
- *
- * @param Model $Model Model instance
- * @param mixed $id The ID of the record to move
- * @param integer|boolean $number how many places to move the node or true to move to last position
- * @return boolean true on success, false on failure
- * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::moveDown
- */
- public function moveDown(Model $Model, $id = null, $number = 1) {
- if (is_array($id)) {
- extract (array_merge(array('id' => null), $id));
- }
- if (!$number) {
- return false;
- }
- if (empty ($id)) {
- $id = $Model->id;
- }
- extract($this->settings[$Model->alias]);
- list($node) = array_values($Model->find('first', array(
- 'conditions' => array($scope, $Model->escapeField() => $id),
- 'fields' => array($Model->primaryKey, $left, $right, $parent), 'recursive' => $recursive
- )));
- if ($node[$parent]) {
- list($parentNode) = array_values($Model->find('first', array(
- 'conditions' => array($scope, $Model->escapeField() => $node[$parent]),
- 'fields' => array($Model->primaryKey, $left, $right), 'recursive' => $recursive
- )));
- if (($node[$right] + 1) == $parentNode[$right]) {
- return false;
- }
- }
- $nextNode = $Model->find('first', array(
- 'conditions' => array($scope, $Model->escapeField($left) => ($node[$right] + 1)),
- 'fields' => array($Model->primaryKey, $left, $right), 'recursive' => $recursive)
- );
- if ($nextNode) {
- list($nextNode) = array_values($nextNode);
- } else {
- return false;
- }
- $edge = $this->_getMax($Model, $scope, $right, $recursive);
- $this->_sync($Model, $edge - $node[$left] + 1, '+', 'BETWEEN ' . $node[$left] . ' AND ' . $node[$right]);
- $this->_sync($Model, $nextNode[$left] - $node[$left], '-', 'BETWEEN ' . $nextNode[$left] . ' AND ' . $nextNode[$right]);
- $this->_sync($Model, $edge - $node[$left] - ($nextNode[$right] - $nextNode[$left]), '-', '> ' . $edge);
-
- if (is_int($number)) {
- $number--;
- }
- if ($number) {
- $this->moveDown($Model, $id, $number);
- }
- return true;
- }
-
-/**
- * Reorder the node without changing the parent.
- *
- * If the node is the first child, or is a top level node with no previous node this method will return false
- *
- * @param Model $Model Model instance
- * @param mixed $id The ID of the record to move
- * @param integer|boolean $number how many places to move the node, or true to move to first position
- * @return boolean true on success, false on failure
- * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::moveUp
- */
- public function moveUp(Model $Model, $id = null, $number = 1) {
- if (is_array($id)) {
- extract (array_merge(array('id' => null), $id));
- }
- if (!$number) {
- return false;
- }
- if (empty ($id)) {
- $id = $Model->id;
- }
- extract($this->settings[$Model->alias]);
- list($node) = array_values($Model->find('first', array(
- 'conditions' => array($scope, $Model->escapeField() => $id),
- 'fields' => array($Model->primaryKey, $left, $right, $parent), 'recursive' => $recursive
- )));
- if ($node[$parent]) {
- list($parentNode) = array_values($Model->find('first', array(
- 'conditions' => array($scope, $Model->escapeField() => $node[$parent]),
- 'fields' => array($Model->primaryKey, $left, $right), 'recursive' => $recursive
- )));
- if (($node[$left] - 1) == $parentNode[$left]) {
- return false;
- }
- }
- $previousNode = $Model->find('first', array(
- 'conditions' => array($scope, $Model->escapeField($right) => ($node[$left] - 1)),
- 'fields' => array($Model->primaryKey, $left, $right),
- 'recursive' => $recursive
- ));
-
- if ($previousNode) {
- list($previousNode) = array_values($previousNode);
- } else {
- return false;
- }
- $edge = $this->_getMax($Model, $scope, $right, $recursive);
- $this->_sync($Model, $edge - $previousNode[$left] + 1, '+', 'BETWEEN ' . $previousNode[$left] . ' AND ' . $previousNode[$right]);
- $this->_sync($Model, $node[$left] - $previousNode[$left], '-', 'BETWEEN ' . $node[$left] . ' AND ' . $node[$right]);
- $this->_sync($Model, $edge - $previousNode[$left] - ($node[$right] - $node[$left]), '-', '> ' . $edge);
- if (is_int($number)) {
- $number--;
- }
- if ($number) {
- $this->moveUp($Model, $id, $number);
- }
- return true;
- }
-
-/**
- * Recover a corrupted tree
- *
- * The mode parameter is used to specify the source of info that is valid/correct. The opposite source of data
- * will be populated based upon that source of info. E.g. if the MPTT fields are corrupt or empty, with the $mode
- * 'parent' the values of the parent_id field will be used to populate the left and right fields. The missingParentAction
- * parameter only applies to "parent" mode and determines what to do if the parent field contains an id that is not present.
- *
- * @todo Could be written to be faster, *maybe*. Ideally using a subquery and putting all the logic burden on the DB.
- * @param Model $Model Model instance
- * @param string $mode parent or tree
- * @param mixed $missingParentAction 'return' to do nothing and return, 'delete' to
- * delete, or the id of the parent to set as the parent_id
- * @return boolean true on success, false on failure
- * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::recover
- */
- public function recover(Model $Model, $mode = 'parent', $missingParentAction = null) {
- if (is_array($mode)) {
- extract (array_merge(array('mode' => 'parent'), $mode));
- }
- extract($this->settings[$Model->alias]);
- $Model->recursive = $recursive;
- if ($mode == 'parent') {
- $Model->bindModel(array('belongsTo' => array('VerifyParent' => array(
- 'className' => $Model->name,
- 'foreignKey' => $parent,
- 'fields' => array($Model->primaryKey, $left, $right, $parent),
- ))));
- $missingParents = $Model->find('list', array(
- 'recursive' => 0,
- 'conditions' => array($scope, array(
- 'NOT' => array($Model->escapeField($parent) => null), $Model->VerifyParent->escapeField() => null
- ))
- ));
- $Model->unbindModel(array('belongsTo' => array('VerifyParent')));
- if ($missingParents) {
- if ($missingParentAction == 'return') {
- foreach ($missingParents as $id => $display) {
- $this->errors[] = 'cannot find the parent for ' . $Model->alias . ' with id ' . $id . '(' . $display . ')';
- }
- return false;
- } elseif ($missingParentAction == 'delete') {
- $Model->deleteAll(array($Model->primaryKey => array_flip($missingParents)));
- } else {
- $Model->updateAll(array($parent => $missingParentAction), array($Model->escapeField($Model->primaryKey) => array_flip($missingParents)));
- }
- }
- $count = 1;
- foreach ($Model->find('all', array('conditions' => $scope, 'fields' => array($Model->primaryKey), 'order' => $left)) as $array) {
- $lft = $count++;
- $rght = $count++;
- $Model->create(false);
- $Model->id = $array[$Model->alias][$Model->primaryKey];
- $Model->save(array($left => $lft, $right => $rght), array('callbacks' => false, 'validate' => false));
- }
- foreach ($Model->find('all', array('conditions' => $scope, 'fields' => array($Model->primaryKey, $parent), 'order' => $left)) as $array) {
- $Model->create(false);
- $Model->id = $array[$Model->alias][$Model->primaryKey];
- $this->_setParent($Model, $array[$Model->alias][$parent]);
- }
- } else {
- $db = ConnectionManager::getDataSource($Model->useDbConfig);
- foreach ($Model->find('all', array('conditions' => $scope, 'fields' => array($Model->primaryKey, $parent), 'order' => $left)) as $array) {
- $path = $this->getPath($Model, $array[$Model->alias][$Model->primaryKey]);
- if ($path == null || count($path) < 2) {
- $parentId = null;
- } else {
- $parentId = $path[count($path) - 2][$Model->alias][$Model->primaryKey];
- }
- $Model->updateAll(array($parent => $db->value($parentId, $parent)), array($Model->escapeField() => $array[$Model->alias][$Model->primaryKey]));
- }
- }
- return true;
- }
-
-/**
- * Reorder method.
- *
- * Reorders the nodes (and child nodes) of the tree according to the field and direction specified in the parameters.
- * This method does not change the parent of any node.
- *
- * Requires a valid tree, by default it verifies the tree before beginning.
- *
- * Options:
- *
- * - 'id' id of record to use as top node for reordering
- * - 'field' Which field to use in reordering defaults to displayField
- * - 'order' Direction to order either DESC or ASC (defaults to ASC)
- * - 'verify' Whether or not to verify the tree before reorder. defaults to true.
- *
- * @param Model $Model Model instance
- * @param array $options array of options to use in reordering.
- * @return boolean true on success, false on failure
- * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::reorder
- */
- public function reorder(Model $Model, $options = array()) {
- $options = array_merge(array('id' => null, 'field' => $Model->displayField, 'order' => 'ASC', 'verify' => true), $options);
- extract($options);
- if ($verify && !$this->verify($Model)) {
- return false;
- }
- $verify = false;
- extract($this->settings[$Model->alias]);
- $fields = array($Model->primaryKey, $field, $left, $right);
- $sort = $field . ' ' . $order;
- $nodes = $this->children($Model, $id, true, $fields, $sort, null, null, $recursive);
-
- $cacheQueries = $Model->cacheQueries;
- $Model->cacheQueries = false;
- if ($nodes) {
- foreach ($nodes as $node) {
- $id = $node[$Model->alias][$Model->primaryKey];
- $this->moveDown($Model, $id, true);
- if ($node[$Model->alias][$left] != $node[$Model->alias][$right] - 1) {
- $this->reorder($Model, compact('id', 'field', 'order', 'verify'));
- }
- }
- }
- $Model->cacheQueries = $cacheQueries;
- return true;
- }
-
-/**
- * Remove the current node from the tree, and reparent all children up one level.
- *
- * If the parameter delete is false, the node will become a new top level node. Otherwise the node will be deleted
- * after the children are reparented.
- *
- * @param Model $Model Model instance
- * @param mixed $id The ID of the record to remove
- * @param boolean $delete whether to delete the node after reparenting children (if any)
- * @return boolean true on success, false on failure
- * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::removeFromTree
- */
- public function removeFromTree(Model $Model, $id = null, $delete = false) {
- if (is_array($id)) {
- extract (array_merge(array('id' => null), $id));
- }
- extract($this->settings[$Model->alias]);
-
- list($node) = array_values($Model->find('first', array(
- 'conditions' => array($scope, $Model->escapeField() => $id),
- 'fields' => array($Model->primaryKey, $left, $right, $parent),
- 'recursive' => $recursive
- )));
-
- if ($node[$right] == $node[$left] + 1) {
- if ($delete) {
- return $Model->delete($id);
- } else {
- $Model->id = $id;
- return $Model->saveField($parent, null);
- }
- } elseif ($node[$parent]) {
- list($parentNode) = array_values($Model->find('first', array(
- 'conditions' => array($scope, $Model->escapeField() => $node[$parent]),
- 'fields' => array($Model->primaryKey, $left, $right),
- 'recursive' => $recursive
- )));
- } else {
- $parentNode[$right] = $node[$right] + 1;
- }
-
- $db = ConnectionManager::getDataSource($Model->useDbConfig);
- $Model->updateAll(
- array($parent => $db->value($node[$parent], $parent)),
- array($Model->escapeField($parent) => $node[$Model->primaryKey])
- );
- $this->_sync($Model, 1, '-', 'BETWEEN ' . ($node[$left] + 1) . ' AND ' . ($node[$right] - 1));
- $this->_sync($Model, 2, '-', '> ' . ($node[$right]));
- $Model->id = $id;
-
- if ($delete) {
- $Model->updateAll(
- array(
- $Model->escapeField($left) => 0,
- $Model->escapeField($right) => 0,
- $Model->escapeField($parent) => null
- ),
- array($Model->escapeField() => $id)
- );
- return $Model->delete($id);
- } else {
- $edge = $this->_getMax($Model, $scope, $right, $recursive);
- if ($node[$right] == $edge) {
- $edge = $edge - 2;
- }
- $Model->id = $id;
- return $Model->save(
- array($left => $edge + 1, $right => $edge + 2, $parent => null),
- array('callbacks' => false, 'validate' => false)
- );
- }
- }
-
-/**
- * Check if the current tree is valid.
- *
- * Returns true if the tree is valid otherwise an array of (type, incorrect left/right index, message)
- *
- * @param Model $Model Model instance
- * @return mixed true if the tree is valid or empty, otherwise an array of (error type [index, node],
- * [incorrect left/right index,node id], message)
- * @link http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html#TreeBehavior::verify
- */
- public function verify(Model $Model) {
- extract($this->settings[$Model->alias]);
- if (!$Model->find('count', array('conditions' => $scope))) {
- return true;
- }
- $min = $this->_getMin($Model, $scope, $left, $recursive);
- $edge = $this->_getMax($Model, $scope, $right, $recursive);
- $errors = array();
-
- for ($i = $min; $i <= $edge; $i++) {
- $count = $Model->find('count', array('conditions' => array(
- $scope, 'OR' => array($Model->escapeField($left) => $i, $Model->escapeField($right) => $i)
- )));
- if ($count != 1) {
- if ($count == 0) {
- $errors[] = array('index', $i, 'missing');
- } else {
- $errors[] = array('index', $i, 'duplicate');
- }
- }
- }
- $node = $Model->find('first', array('conditions' => array($scope, $Model->escapeField($right) . '< ' . $Model->escapeField($left)), 'recursive' => 0));
- if ($node) {
- $errors[] = array('node', $node[$Model->alias][$Model->primaryKey], 'left greater than right.');
- }
-
- $Model->bindModel(array('belongsTo' => array('VerifyParent' => array(
- 'className' => $Model->name,
- 'foreignKey' => $parent,
- 'fields' => array($Model->primaryKey, $left, $right, $parent)
- ))));
-
- foreach ($Model->find('all', array('conditions' => $scope, 'recursive' => 0)) as $instance) {
- if (is_null($instance[$Model->alias][$left]) || is_null($instance[$Model->alias][$right])) {
- $errors[] = array('node', $instance[$Model->alias][$Model->primaryKey],
- 'has invalid left or right values');
- } elseif ($instance[$Model->alias][$left] == $instance[$Model->alias][$right]) {
- $errors[] = array('node', $instance[$Model->alias][$Model->primaryKey],
- 'left and right values identical');
- } elseif ($instance[$Model->alias][$parent]) {
- if (!$instance['VerifyParent'][$Model->primaryKey]) {
- $errors[] = array('node', $instance[$Model->alias][$Model->primaryKey],
- 'The parent node ' . $instance[$Model->alias][$parent] . ' doesn\'t exist');
- } elseif ($instance[$Model->alias][$left] < $instance['VerifyParent'][$left]) {
- $errors[] = array('node', $instance[$Model->alias][$Model->primaryKey],
- 'left less than parent (node ' . $instance['VerifyParent'][$Model->primaryKey] . ').');
- } elseif ($instance[$Model->alias][$right] > $instance['VerifyParent'][$right]) {
- $errors[] = array('node', $instance[$Model->alias][$Model->primaryKey],
- 'right greater than parent (node ' . $instance['VerifyParent'][$Model->primaryKey] . ').');
- }
- } elseif ($Model->find('count', array('conditions' => array($scope, $Model->escapeField($left) . ' <' => $instance[$Model->alias][$left], $Model->escapeField($right) . ' >' => $instance[$Model->alias][$right]), 'recursive' => 0))) {
- $errors[] = array('node', $instance[$Model->alias][$Model->primaryKey], 'The parent field is blank, but has a parent');
- }
- }
- if ($errors) {
- return $errors;
- }
- return true;
- }
-
-/**
- * Sets the parent of the given node
- *
- * The force parameter is used to override the "don't change the parent to the current parent" logic in the event
- * of recovering a corrupted table, or creating new nodes. Otherwise it should always be false. In reality this
- * method could be private, since calling save with parent_id set also calls setParent
- *
- * @param Model $Model Model instance
- * @param mixed $parentId
- * @param boolean $created
- * @return boolean true on success, false on failure
- */
- protected function _setParent(Model $Model, $parentId = null, $created = false) {
- extract($this->settings[$Model->alias]);
- list($node) = array_values($Model->find('first', array(
- 'conditions' => array($scope, $Model->escapeField() => $Model->id),
- 'fields' => array($Model->primaryKey, $parent, $left, $right),
- 'recursive' => $recursive
- )));
- $edge = $this->_getMax($Model, $scope, $right, $recursive, $created);
-
- if (empty ($parentId)) {
- $this->_sync($Model, $edge - $node[$left] + 1, '+', 'BETWEEN ' . $node[$left] . ' AND ' . $node[$right], $created);
- $this->_sync($Model, $node[$right] - $node[$left] + 1, '-', '> ' . $node[$left], $created);
- } else {
- $values = $Model->find('first', array(
- 'conditions' => array($scope, $Model->escapeField() => $parentId),
- 'fields' => array($Model->primaryKey, $left, $right),
- 'recursive' => $recursive
- ));
-
- if ($values === false) {
- return false;
- }
- $parentNode = array_values($values);
-
- if (empty($parentNode) || empty($parentNode[0])) {
- return false;
- }
- $parentNode = $parentNode[0];
-
- if (($Model->id == $parentId)) {
- return false;
- } elseif (($node[$left] < $parentNode[$left]) && ($parentNode[$right] < $node[$right])) {
- return false;
- }
- if (empty($node[$left]) && empty($node[$right])) {
- $this->_sync($Model, 2, '+', '>= ' . $parentNode[$right], $created);
- $result = $Model->save(
- array($left => $parentNode[$right], $right => $parentNode[$right] + 1, $parent => $parentId),
- array('validate' => false, 'callbacks' => false)
- );
- $Model->data = $result;
- } else {
- $this->_sync($Model, $edge - $node[$left] + 1, '+', 'BETWEEN ' . $node[$left] . ' AND ' . $node[$right], $created);
- $diff = $node[$right] - $node[$left] + 1;
-
- if ($node[$left] > $parentNode[$left]) {
- if ($node[$right] < $parentNode[$right]) {
- $this->_sync($Model, $diff, '-', 'BETWEEN ' . $node[$right] . ' AND ' . ($parentNode[$right] - 1), $created);
- $this->_sync($Model, $edge - $parentNode[$right] + $diff + 1, '-', '> ' . $edge, $created);
- } else {
- $this->_sync($Model, $diff, '+', 'BETWEEN ' . $parentNode[$right] . ' AND ' . $node[$right], $created);
- $this->_sync($Model, $edge - $parentNode[$right] + 1, '-', '> ' . $edge, $created);
- }
- } else {
- $this->_sync($Model, $diff, '-', 'BETWEEN ' . $node[$right] . ' AND ' . ($parentNode[$right] - 1), $created);
- $this->_sync($Model, $edge - $parentNode[$right] + $diff + 1, '-', '> ' . $edge, $created);
- }
- }
- }
- return true;
- }
-
-/**
- * get the maximum index value in the table.
- *
- * @param Model $Model
- * @param string $scope
- * @param string $right
- * @param integer $recursive
- * @param boolean $created
- * @return integer
- */
- protected function _getMax(Model $Model, $scope, $right, $recursive = -1, $created = false) {
- $db = ConnectionManager::getDataSource($Model->useDbConfig);
- if ($created) {
- if (is_string($scope)) {
- $scope .= " AND {$Model->alias}.{$Model->primaryKey} <> ";
- $scope .= $db->value($Model->id, $Model->getColumnType($Model->primaryKey));
- } else {
- $scope['NOT'][$Model->alias . '.' . $Model->primaryKey] = $Model->id;
- }
- }
- $name = $Model->alias . '.' . $right;
- list($edge) = array_values($Model->find('first', array(
- 'conditions' => $scope,
- 'fields' => $db->calculate($Model, 'max', array($name, $right)),
- 'recursive' => $recursive
- )));
- return (empty($edge[$right])) ? 0 : $edge[$right];
- }
-
-/**
- * get the minimum index value in the table.
- *
- * @param Model $Model
- * @param string $scope
- * @param string $left
- * @param integer $recursive
- * @return integer
- */
- protected function _getMin(Model $Model, $scope, $left, $recursive = -1) {
- $db = ConnectionManager::getDataSource($Model->useDbConfig);
- $name = $Model->alias . '.' . $left;
- list($edge) = array_values($Model->find('first', array(
- 'conditions' => $scope,
- 'fields' => $db->calculate($Model, 'min', array($name, $left)),
- 'recursive' => $recursive
- )));
- return (empty($edge[$left])) ? 0 : $edge[$left];
- }
-
-/**
- * Table sync method.
- *
- * Handles table sync operations, Taking account of the behavior scope.
- *
- * @param Model $Model
- * @param integer $shift
- * @param string $dir
- * @param array $conditions
- * @param boolean $created
- * @param string $field
- * @return void
- */
- protected function _sync(Model $Model, $shift, $dir = '+', $conditions = array(), $created = false, $field = 'both') {
- $ModelRecursive = $Model->recursive;
- extract($this->settings[$Model->alias]);
- $Model->recursive = $recursive;
-
- if ($field == 'both') {
- $this->_sync($Model, $shift, $dir, $conditions, $created, $left);
- $field = $right;
- }
- if (is_string($conditions)) {
- $conditions = array("{$Model->alias}.{$field} {$conditions}");
- }
- if (($scope != '1 = 1' && $scope !== true) && $scope) {
- $conditions[] = $scope;
- }
- if ($created) {
- $conditions['NOT'][$Model->alias . '.' . $Model->primaryKey] = $Model->id;
- }
- $Model->updateAll(array($Model->alias . '.' . $field => $Model->escapeField($field) . ' ' . $dir . ' ' . $shift), $conditions);
- $Model->recursive = $ModelRecursive;
- }
-
-}
diff --git a/lib/Cake/Model/BehaviorCollection.php b/lib/Cake/Model/BehaviorCollection.php
deleted file mode 100644
index 76c1996283d..00000000000
--- a/lib/Cake/Model/BehaviorCollection.php
+++ /dev/null
@@ -1,295 +0,0 @@
-modelName = $modelName;
-
- if (!empty($behaviors)) {
- foreach (BehaviorCollection::normalizeObjectArray($behaviors) as $behavior => $config) {
- $this->load($config['class'], $config['settings']);
- }
- }
- }
-
-/**
- * Backwards compatible alias for load()
- *
- * @param string $behavior
- * @param array $config
- * @return void
- * @deprecated Replaced with load()
- */
- public function attach($behavior, $config = array()) {
- return $this->load($behavior, $config);
- }
-
-/**
- * Loads a behavior into the collection. You can use use `$config['enabled'] = false`
- * to load a behavior with callbacks disabled. By default callbacks are enabled. Disable behaviors
- * can still be used as normal.
- *
- * You can alias your behavior as an existing behavior by setting the 'className' key, i.e.,
- * {{{
- * public $actsAs = array(
- * 'Tree' => array(
- * 'className' => 'AliasedTree'
- * );
- * );
- * }}}
- * All calls to the `Tree` behavior would use `AliasedTree` instead.
- *
- * @param string $behavior CamelCased name of the behavior to load
- * @param array $config Behavior configuration parameters
- * @return boolean True on success, false on failure
- * @throws MissingBehaviorException when a behavior could not be found.
- */
- public function load($behavior, $config = array()) {
- if (is_array($config) && isset($config['className'])) {
- $alias = $behavior;
- $behavior = $config['className'];
- }
- $configDisabled = isset($config['enabled']) && $config['enabled'] === false;
- unset($config['enabled'], $config['className']);
-
- list($plugin, $name) = pluginSplit($behavior, true);
- if (!isset($alias)) {
- $alias = $name;
- }
-
- $class = $name . 'Behavior';
-
- App::uses($class, $plugin . 'Model/Behavior');
- if (!class_exists($class)) {
- throw new MissingBehaviorException(array(
- 'class' => $class,
- 'plugin' => substr($plugin, 0, -1)
- ));
- }
-
- if (!isset($this->{$alias})) {
- if (ClassRegistry::isKeySet($class)) {
- $this->_loaded[$alias] = ClassRegistry::getObject($class);
- } else {
- $this->_loaded[$alias] = new $class();
- ClassRegistry::addObject($class, $this->_loaded[$alias]);
- if (!empty($plugin)) {
- ClassRegistry::addObject($plugin . '.' . $class, $this->_loaded[$alias]);
- }
- }
- } elseif (isset($this->_loaded[$alias]->settings) && isset($this->_loaded[$alias]->settings[$this->modelName])) {
- if ($config !== null && $config !== false) {
- $config = array_merge($this->_loaded[$alias]->settings[$this->modelName], $config);
- } else {
- $config = array();
- }
- }
- if (empty($config)) {
- $config = array();
- }
- $this->_loaded[$alias]->setup(ClassRegistry::getObject($this->modelName), $config);
-
- foreach ($this->_loaded[$alias]->mapMethods as $method => $methodAlias) {
- $this->_mappedMethods[$method] = array($alias, $methodAlias);
- }
- $methods = get_class_methods($this->_loaded[$alias]);
- $parentMethods = array_flip(get_class_methods('ModelBehavior'));
- $callbacks = array(
- 'setup', 'cleanup', 'beforeFind', 'afterFind', 'beforeSave', 'afterSave',
- 'beforeDelete', 'afterDelete', 'onError'
- );
-
- foreach ($methods as $m) {
- if (!isset($parentMethods[$m])) {
- $methodAllowed = (
- $m[0] != '_' && !array_key_exists($m, $this->_methods) &&
- !in_array($m, $callbacks)
- );
- if ($methodAllowed) {
- $this->_methods[$m] = array($alias, $m);
- }
- }
- }
-
- if (!in_array($alias, $this->_enabled) && !$configDisabled) {
- $this->enable($alias);
- } else {
- $this->disable($alias);
- }
- return true;
- }
-
-/**
- * Detaches a behavior from a model
- *
- * @param string $name CamelCased name of the behavior to unload
- * @return void
- */
- public function unload($name) {
- list($plugin, $name) = pluginSplit($name);
- if (isset($this->_loaded[$name])) {
- $this->_loaded[$name]->cleanup(ClassRegistry::getObject($this->modelName));
- parent::unload($name);
- }
- foreach ($this->_methods as $m => $callback) {
- if (is_array($callback) && $callback[0] == $name) {
- unset($this->_methods[$m]);
- }
- }
- }
-
-/**
- * Backwards compatible alias for unload()
- *
- * @param string $name Name of behavior
- * @return void
- * @deprecated Use unload instead.
- */
- public function detach($name) {
- return $this->unload($name);
- }
-
-/**
- * Dispatches a behavior method. Will call either normal methods or mapped methods.
- *
- * If a method is not handled by the BehaviorCollection, and $strict is false, a
- * special return of `array('unhandled')` will be returned to signal the method was not found.
- *
- * @param Model $model The model the method was originally called on.
- * @param string $method The method called.
- * @param array $params Parameters for the called method.
- * @param boolean $strict If methods are not found, trigger an error.
- * @return array All methods for all behaviors attached to this object
- */
- public function dispatchMethod($model, $method, $params = array(), $strict = false) {
- $method = $this->hasMethod($method, true);
-
- if ($strict && empty($method)) {
- trigger_error(__d('cake_dev', "BehaviorCollection::dispatchMethod() - Method %s not found in any attached behavior", $method), E_USER_WARNING);
- return null;
- }
- if (empty($method)) {
- return array('unhandled');
- }
- if (count($method) === 3) {
- array_unshift($params, $method[2]);
- unset($method[2]);
- }
- return call_user_func_array(
- array($this->_loaded[$method[0]], $method[1]),
- array_merge(array(&$model), $params)
- );
- }
-
-/**
- * Gets the method list for attached behaviors, i.e. all public, non-callback methods.
- * This does not include mappedMethods.
- *
- * @return array All public methods for all behaviors attached to this collection
- */
- public function methods() {
- return $this->_methods;
- }
-
-/**
- * Check to see if a behavior in this collection implements the provided method. Will
- * also check mappedMethods.
- *
- * @param string $method The method to find.
- * @param boolean $callback Return the callback for the method.
- * @return mixed If $callback is false, a boolean will be returned, if its true, an array
- * containing callback information will be returned. For mapped methods the array will have 3 elements.
- */
- public function hasMethod($method, $callback = false) {
- if (isset($this->_methods[$method])) {
- return $callback ? $this->_methods[$method] : true;
- }
- foreach ($this->_mappedMethods as $pattern => $target) {
- if (preg_match($pattern . 'i', $method)) {
- if ($callback) {
- $target[] = $method;
- return $target;
- }
- return true;
- }
- }
- return false;
- }
-
-/**
- * Returns the implemented events that will get routed to the trigger function
- * in order to dispatch them separately on each behavior
- *
- * @return array
- */
- public function implementedEvents() {
- return array(
- 'Model.beforeFind' => 'trigger',
- 'Model.afterFind' => 'trigger',
- 'Model.beforeValidate' => 'trigger',
- 'Model.beforeSave' => 'trigger',
- 'Model.afterSave' => 'trigger',
- 'Model.beforeDelete' => 'trigger',
- 'Model.afterDelete' => 'trigger'
- );
- }
-
-}
diff --git a/lib/Cake/Model/CakeSchema.php b/lib/Cake/Model/CakeSchema.php
deleted file mode 100644
index b9ae0ad0d0a..00000000000
--- a/lib/Cake/Model/CakeSchema.php
+++ /dev/null
@@ -1,707 +0,0 @@
-name = preg_replace('/schema$/i', '', get_class($this));
- }
- if (!empty($options['plugin'])) {
- $this->plugin = $options['plugin'];
- }
-
- if (strtolower($this->name) === 'cake') {
- $this->name = Inflector::camelize(Inflector::slug(Configure::read('App.dir')));
- }
-
- if (empty($options['path'])) {
- $this->path = APP . 'Config' . DS . 'Schema';
- }
-
- $options = array_merge(get_object_vars($this), $options);
- $this->build($options);
- }
-
-/**
- * Builds schema object properties
- *
- * @param array $data loaded object properties
- * @return void
- */
- public function build($data) {
- $file = null;
- foreach ($data as $key => $val) {
- if (!empty($val)) {
- if (!in_array($key, array('plugin', 'name', 'path', 'file', 'connection', 'tables', '_log'))) {
- if ($key[0] === '_') {
- continue;
- }
- $this->tables[$key] = $val;
- unset($this->{$key});
- } elseif ($key !== 'tables') {
- if ($key === 'name' && $val !== $this->name && !isset($data['file'])) {
- $file = Inflector::underscore($val) . '.php';
- }
- $this->{$key} = $val;
- }
- }
- }
- if (file_exists($this->path . DS . $file) && is_file($this->path . DS . $file)) {
- $this->file = $file;
- } elseif (!empty($this->plugin)) {
- $this->path = CakePlugin::path($this->plugin) . 'Config' . DS . 'Schema';
- }
- }
-
-/**
- * Before callback to be implemented in subclasses
- *
- * @param array $event schema object properties
- * @return boolean Should process continue
- */
- public function before($event = array()) {
- return true;
- }
-
-/**
- * After callback to be implemented in subclasses
- *
- * @param array $event schema object properties
- * @return void
- */
- public function after($event = array()) {
- }
-
-/**
- * Reads database and creates schema tables
- *
- * @param array $options schema object properties
- * @return array Set of name and tables
- */
- public function load($options = array()) {
- if (is_string($options)) {
- $options = array('path' => $options);
- }
-
- $this->build($options);
- extract(get_object_vars($this));
-
- $class = $name . 'Schema';
-
- if (!class_exists($class)) {
- if (file_exists($path . DS . $file) && is_file($path . DS . $file)) {
- require_once $path . DS . $file;
- } elseif (file_exists($path . DS . 'schema.php') && is_file($path . DS . 'schema.php')) {
- require_once $path . DS . 'schema.php';
- }
- }
-
- if (class_exists($class)) {
- $Schema = new $class($options);
- return $Schema;
- }
- return false;
- }
-
-/**
- * Reads database and creates schema tables
- *
- * Options
- *
- * - 'connection' - the db connection to use
- * - 'name' - name of the schema
- * - 'models' - a list of models to use, or false to ignore models
- *
- * @param array $options schema object properties
- * @return array Array indexed by name and tables
- */
- public function read($options = array()) {
- extract(array_merge(
- array(
- 'connection' => $this->connection,
- 'name' => $this->name,
- 'models' => true,
- ),
- $options
- ));
- $db = ConnectionManager::getDataSource($connection);
-
- if (isset($this->plugin)) {
- App::uses($this->plugin . 'AppModel', $this->plugin . '.Model');
- }
-
- $tables = array();
- $currentTables = (array)$db->listSources();
-
- $prefix = null;
- if (isset($db->config['prefix'])) {
- $prefix = $db->config['prefix'];
- }
-
- if (!is_array($models) && $models !== false) {
- if (isset($this->plugin)) {
- $models = App::objects($this->plugin . '.Model', null, false);
- } else {
- $models = App::objects('Model');
- }
- }
-
- if (is_array($models)) {
- foreach ($models as $model) {
- $importModel = $model;
- $plugin = null;
- if ($model == 'AppModel') {
- continue;
- }
-
- if (isset($this->plugin)) {
- if ($model == $this->plugin . 'AppModel') {
- continue;
- }
- $importModel = $model;
- $plugin = $this->plugin . '.';
- }
-
- App::uses($importModel, $plugin . 'Model');
- if (!class_exists($importModel)) {
- continue;
- }
-
- $vars = get_class_vars($model);
- if (empty($vars['useDbConfig']) || $vars['useDbConfig'] != $connection) {
- continue;
- }
-
- try {
- $Object = ClassRegistry::init(array('class' => $model, 'ds' => $connection));
- } catch (CakeException $e) {
- continue;
- }
-
- $db = $Object->getDataSource();
- if (is_object($Object) && $Object->useTable !== false) {
- $fulltable = $table = $db->fullTableName($Object, false, false);
- if ($prefix && strpos($table, $prefix) !== 0) {
- continue;
- }
- $table = $this->_noPrefixTable($prefix, $table);
-
- if (in_array($fulltable, $currentTables)) {
- $key = array_search($fulltable, $currentTables);
- if (empty($tables[$table])) {
- $tables[$table] = $this->_columns($Object);
- $tables[$table]['indexes'] = $db->index($Object);
- $tables[$table]['tableParameters'] = $db->readTableParameters($fulltable);
- unset($currentTables[$key]);
- }
- if (!empty($Object->hasAndBelongsToMany)) {
- foreach ($Object->hasAndBelongsToMany as $Assoc => $assocData) {
- if (isset($assocData['with'])) {
- $class = $assocData['with'];
- }
- if (is_object($Object->$class)) {
- $withTable = $db->fullTableName($Object->$class, false, false);
- if ($prefix && strpos($withTable, $prefix) !== 0) {
- continue;
- }
- if (in_array($withTable, $currentTables)) {
- $key = array_search($withTable, $currentTables);
- $noPrefixWith = $this->_noPrefixTable($prefix, $withTable);
-
- $tables[$noPrefixWith] = $this->_columns($Object->$class);
- $tables[$noPrefixWith]['indexes'] = $db->index($Object->$class);
- $tables[$noPrefixWith]['tableParameters'] = $db->readTableParameters($withTable);
- unset($currentTables[$key]);
- }
- }
- }
- }
- }
- }
- }
- }
-
- if (!empty($currentTables)) {
- foreach ($currentTables as $table) {
- if ($prefix) {
- if (strpos($table, $prefix) !== 0) {
- continue;
- }
- $table = $this->_noPrefixTable($prefix, $table);
- }
- $Object = new AppModel(array(
- 'name' => Inflector::classify($table), 'table' => $table, 'ds' => $connection
- ));
-
- $systemTables = array(
- 'aros', 'acos', 'aros_acos', Configure::read('Session.table'), 'i18n'
- );
-
- $fulltable = $db->fullTableName($Object, false, false);
-
- if (in_array($table, $systemTables)) {
- $tables[$Object->table] = $this->_columns($Object);
- $tables[$Object->table]['indexes'] = $db->index($Object);
- $tables[$Object->table]['tableParameters'] = $db->readTableParameters($fulltable);
- } elseif ($models === false) {
- $tables[$table] = $this->_columns($Object);
- $tables[$table]['indexes'] = $db->index($Object);
- $tables[$table]['tableParameters'] = $db->readTableParameters($fulltable);
- } else {
- $tables['missing'][$table] = $this->_columns($Object);
- $tables['missing'][$table]['indexes'] = $db->index($Object);
- $tables['missing'][$table]['tableParameters'] = $db->readTableParameters($fulltable);
- }
- }
- }
-
- ksort($tables);
- return compact('name', 'tables');
- }
-
-/**
- * Writes schema file from object or options
- *
- * @param mixed $object schema object or options array
- * @param array $options schema object properties to override object
- * @return mixed false or string written to file
- */
- public function write($object, $options = array()) {
- if (is_object($object)) {
- $object = get_object_vars($object);
- $this->build($object);
- }
-
- if (is_array($object)) {
- $options = $object;
- unset($object);
- }
-
- extract(array_merge(
- get_object_vars($this), $options
- ));
-
- $out = "class {$name}Schema extends CakeSchema {\n\n";
-
- if ($path !== $this->path) {
- $out .= "\tpublic \$path = '{$path}';\n\n";
- }
-
- if ($file !== $this->file) {
- $out .= "\tpublic \$file = '{$file}';\n\n";
- }
-
- if ($connection !== 'default') {
- $out .= "\tpublic \$connection = '{$connection}';\n\n";
- }
-
- $out .= "\tpublic function before(\$event = array()) {\n\t\treturn true;\n\t}\n\n\tpublic function after(\$event = array()) {\n\t}\n\n";
-
- if (empty($tables)) {
- $this->read();
- }
-
- foreach ($tables as $table => $fields) {
- if (!is_numeric($table) && $table !== 'missing') {
- $out .= $this->generateTable($table, $fields);
- }
- }
- $out .= "}\n";
-
- $file = new File($path . DS . $file, true);
- $content = "write($content)) {
- return $content;
- }
- return false;
- }
-
-/**
- * Generate the code for a table. Takes a table name and $fields array
- * Returns a completed variable declaration to be used in schema classes
- *
- * @param string $table Table name you want returned.
- * @param array $fields Array of field information to generate the table with.
- * @return string Variable declaration for a schema class
- */
- public function generateTable($table, $fields) {
- $out = "\tpublic \${$table} = array(\n";
- if (is_array($fields)) {
- $cols = array();
- foreach ($fields as $field => $value) {
- if ($field != 'indexes' && $field != 'tableParameters') {
- if (is_string($value)) {
- $type = $value;
- $value = array('type' => $type);
- }
- $col = "\t\t'{$field}' => array('type' => '" . $value['type'] . "', ";
- unset($value['type']);
- $col .= join(', ', $this->_values($value));
- } elseif ($field == 'indexes') {
- $col = "\t\t'indexes' => array(";
- $props = array();
- foreach ((array)$value as $key => $index) {
- $props[] = "'{$key}' => array(" . join(', ', $this->_values($index)) . ")";
- }
- $col .= join(', ', $props);
- } elseif ($field == 'tableParameters') {
- $col = "\t\t'tableParameters' => array(";
- $props = array();
- foreach ((array)$value as $key => $param) {
- $props[] = "'{$key}' => '$param'";
- }
- $col .= join(', ', $props);
- }
- $col .= ")";
- $cols[] = $col;
- }
- $out .= join(",\n", $cols);
- }
- $out .= "\n\t);\n";
- return $out;
- }
-
-/**
- * Compares two sets of schemas
- *
- * @param mixed $old Schema object or array
- * @param mixed $new Schema object or array
- * @return array Tables (that are added, dropped, or changed)
- */
- public function compare($old, $new = null) {
- if (empty($new)) {
- $new = $this;
- }
- if (is_array($new)) {
- if (isset($new['tables'])) {
- $new = $new['tables'];
- }
- } else {
- $new = $new->tables;
- }
-
- if (is_array($old)) {
- if (isset($old['tables'])) {
- $old = $old['tables'];
- }
- } else {
- $old = $old->tables;
- }
- $tables = array();
- foreach ($new as $table => $fields) {
- if ($table == 'missing') {
- continue;
- }
- if (!array_key_exists($table, $old)) {
- $tables[$table]['add'] = $fields;
- } else {
- $diff = $this->_arrayDiffAssoc($fields, $old[$table]);
- if (!empty($diff)) {
- $tables[$table]['add'] = $diff;
- }
- $diff = $this->_arrayDiffAssoc($old[$table], $fields);
- if (!empty($diff)) {
- $tables[$table]['drop'] = $diff;
- }
- }
-
- foreach ($fields as $field => $value) {
- if (!empty($old[$table][$field])) {
- $diff = $this->_arrayDiffAssoc($value, $old[$table][$field]);
- if (!empty($diff) && $field !== 'indexes' && $field !== 'tableParameters') {
- $tables[$table]['change'][$field] = $value;
- }
- }
-
- if (isset($tables[$table]['add'][$field]) && $field !== 'indexes' && $field !== 'tableParameters') {
- $wrapper = array_keys($fields);
- if ($column = array_search($field, $wrapper)) {
- if (isset($wrapper[$column - 1])) {
- $tables[$table]['add'][$field]['after'] = $wrapper[$column - 1];
- }
- }
- }
- }
-
- if (isset($old[$table]['indexes']) && isset($new[$table]['indexes'])) {
- $diff = $this->_compareIndexes($new[$table]['indexes'], $old[$table]['indexes']);
- if ($diff) {
- if (!isset($tables[$table])) {
- $tables[$table] = array();
- }
- if (isset($diff['drop'])) {
- $tables[$table]['drop']['indexes'] = $diff['drop'];
- }
- if ($diff && isset($diff['add'])) {
- $tables[$table]['add']['indexes'] = $diff['add'];
- }
- }
- }
- if (isset($old[$table]['tableParameters']) && isset($new[$table]['tableParameters'])) {
- $diff = $this->_compareTableParameters($new[$table]['tableParameters'], $old[$table]['tableParameters']);
- if ($diff) {
- $tables[$table]['change']['tableParameters'] = $diff;
- }
- }
- }
- return $tables;
- }
-
-/**
- * Extended array_diff_assoc noticing change from/to NULL values
- *
- * It behaves almost the same way as array_diff_assoc except for NULL values: if
- * one of the values is not NULL - change is detected. It is useful in situation
- * where one value is strval('') ant other is strval(null) - in string comparing
- * methods this results as EQUAL, while it is not.
- *
- * @param array $array1 Base array
- * @param array $array2 Corresponding array checked for equality
- * @return array Difference as array with array(keys => values) from input array
- * where match was not found.
- */
- protected function _arrayDiffAssoc($array1, $array2) {
- $difference = array();
- foreach ($array1 as $key => $value) {
- if (!array_key_exists($key, $array2)) {
- $difference[$key] = $value;
- continue;
- }
- $correspondingValue = $array2[$key];
- if (is_null($value) !== is_null($correspondingValue)) {
- $difference[$key] = $value;
- continue;
- }
- if (is_bool($value) !== is_bool($correspondingValue)) {
- $difference[$key] = $value;
- continue;
- }
- if (is_array($value) && is_array($correspondingValue)) {
- continue;
- }
- if ($value === $correspondingValue) {
- continue;
- }
- $difference[$key] = $value;
- }
- return $difference;
- }
-
-/**
- * Formats Schema columns from Model Object
- *
- * @param array $values options keys(type, null, default, key, length, extra)
- * @return array Formatted values
- */
- protected function _values($values) {
- $vals = array();
- if (is_array($values)) {
- foreach ($values as $key => $val) {
- if (is_array($val)) {
- $vals[] = "'{$key}' => array('" . implode("', '", $val) . "')";
- } elseif (!is_numeric($key)) {
- $val = var_export($val, true);
- $vals[] = "'{$key}' => {$val}";
- }
- }
- }
- return $vals;
- }
-
-/**
- * Formats Schema columns from Model Object
- *
- * @param array $Obj model object
- * @return array Formatted columns
- */
- protected function _columns(&$Obj) {
- $db = $Obj->getDataSource();
- $fields = $Obj->schema(true);
-
- $columns = $props = array();
- foreach ($fields as $name => $value) {
- if ($Obj->primaryKey == $name) {
- $value['key'] = 'primary';
- }
- if (!isset($db->columns[$value['type']])) {
- trigger_error(__d('cake_dev', 'Schema generation error: invalid column type %s for %s.%s does not exist in DBO', $value['type'], $Obj->name, $name), E_USER_NOTICE);
- continue;
- } else {
- $defaultCol = $db->columns[$value['type']];
- if (isset($defaultCol['limit']) && $defaultCol['limit'] == $value['length']) {
- unset($value['length']);
- } elseif (isset($defaultCol['length']) && $defaultCol['length'] == $value['length']) {
- unset($value['length']);
- }
- unset($value['limit']);
- }
-
- if (isset($value['default']) && ($value['default'] === '' || $value['default'] === false)) {
- unset($value['default']);
- }
- if (empty($value['length'])) {
- unset($value['length']);
- }
- if (empty($value['key'])) {
- unset($value['key']);
- }
- $columns[$name] = $value;
- }
-
- return $columns;
- }
-
-/**
- * Compare two schema files table Parameters
- *
- * @param array $new New indexes
- * @param array $old Old indexes
- * @return mixed False on failure, or an array of parameters to add & drop.
- */
- protected function _compareTableParameters($new, $old) {
- if (!is_array($new) || !is_array($old)) {
- return false;
- }
- $change = $this->_arrayDiffAssoc($new, $old);
- return $change;
- }
-
-/**
- * Compare two schema indexes
- *
- * @param array $new New indexes
- * @param array $old Old indexes
- * @return mixed false on failure or array of indexes to add and drop
- */
- protected function _compareIndexes($new, $old) {
- if (!is_array($new) || !is_array($old)) {
- return false;
- }
-
- $add = $drop = array();
-
- $diff = $this->_arrayDiffAssoc($new, $old);
- if (!empty($diff)) {
- $add = $diff;
- }
-
- $diff = $this->_arrayDiffAssoc($old, $new);
- if (!empty($diff)) {
- $drop = $diff;
- }
-
- foreach ($new as $name => $value) {
- if (isset($old[$name])) {
- $newUnique = isset($value['unique']) ? $value['unique'] : 0;
- $oldUnique = isset($old[$name]['unique']) ? $old[$name]['unique'] : 0;
- $newColumn = $value['column'];
- $oldColumn = $old[$name]['column'];
-
- $diff = false;
-
- if ($newUnique != $oldUnique) {
- $diff = true;
- } elseif (is_array($newColumn) && is_array($oldColumn)) {
- $diff = ($newColumn !== $oldColumn);
- } elseif (is_string($newColumn) && is_string($oldColumn)) {
- $diff = ($newColumn != $oldColumn);
- } else {
- $diff = true;
- }
- if ($diff) {
- $drop[$name] = null;
- $add[$name] = $value;
- }
- }
- }
- return array_filter(compact('add', 'drop'));
- }
-
-/**
- * Trim the table prefix from the full table name, and return the prefix-less table
- *
- * @param string $prefix Table prefix
- * @param string $table Full table name
- * @return string Prefix-less table name
- */
- protected function _noPrefixTable($prefix, $table) {
- return preg_replace('/^' . preg_quote($prefix) . '/', '', $table);
- }
-
-}
diff --git a/lib/Cake/Model/ConnectionManager.php b/lib/Cake/Model/ConnectionManager.php
deleted file mode 100644
index 57bb9ed3e3f..00000000000
--- a/lib/Cake/Model/ConnectionManager.php
+++ /dev/null
@@ -1,266 +0,0 @@
-{$name});
- self::$_dataSources[$name]->configKeyName = $name;
-
- return self::$_dataSources[$name];
- }
-
-/**
- * Gets the list of available DataSource connections
- * This will only return the datasources instantiated by this manager
- * It differs from enumConnectionObjects, since the latter will return all configured connections
- *
- * @return array List of available connections
- */
- public static function sourceList() {
- if (empty(self::$_init)) {
- self::_init();
- }
- return array_keys(self::$_dataSources);
- }
-
-/**
- * Gets a DataSource name from an object reference.
- *
- * @param DataSource $source DataSource object
- * @return string Datasource name, or null if source is not present
- * in the ConnectionManager.
- */
- public static function getSourceName($source) {
- if (empty(self::$_init)) {
- self::_init();
- }
- foreach (self::$_dataSources as $name => $ds) {
- if ($ds === $source) {
- return $name;
- }
- }
- return null;
- }
-
-/**
- * Loads the DataSource class for the given connection name
- *
- * @param mixed $connName A string name of the connection, as defined in app/Config/database.php,
- * or an array containing the filename (without extension) and class name of the object,
- * to be found in app/Model/Datasource/ or lib/Cake/Model/Datasource/.
- * @return boolean True on success, null on failure or false if the class is already loaded
- * @throws MissingDatasourceException
- */
- public static function loadDataSource($connName) {
- if (empty(self::$_init)) {
- self::_init();
- }
-
- if (is_array($connName)) {
- $conn = $connName;
- } else {
- $conn = self::$_connectionsEnum[$connName];
- }
-
- if (class_exists($conn['classname'], false)) {
- return false;
- }
-
- $plugin = $package = null;
- if (!empty($conn['plugin'])) {
- $plugin = $conn['plugin'] . '.';
- }
- if (!empty($conn['package'])) {
- $package = '/' . $conn['package'];
- }
-
- App::uses($conn['classname'], $plugin . 'Model/Datasource' . $package);
- if (!class_exists($conn['classname'])) {
- throw new MissingDatasourceException(array(
- 'class' => $conn['classname'],
- 'plugin' => substr($plugin, 0, -1)
- ));
- }
- return true;
- }
-
-/**
- * Return a list of connections
- *
- * @return array An associative array of elements where the key is the connection name
- * (as defined in Connections), and the value is an array with keys 'filename' and 'classname'.
- */
- public static function enumConnectionObjects() {
- if (empty(self::$_init)) {
- self::_init();
- }
- return (array)self::$config;
- }
-
-/**
- * Dynamically creates a DataSource object at runtime, with the given name and settings
- *
- * @param string $name The DataSource name
- * @param array $config The DataSource configuration settings
- * @return DataSource A reference to the DataSource object, or null if creation failed
- */
- public static function create($name = '', $config = array()) {
- if (empty(self::$_init)) {
- self::_init();
- }
-
- if (empty($name) || empty($config) || array_key_exists($name, self::$_connectionsEnum)) {
- return null;
- }
- self::$config->{$name} = $config;
- self::$_connectionsEnum[$name] = self::_connectionData($config);
- $return = self::getDataSource($name);
- return $return;
- }
-
-/**
- * Removes a connection configuration at runtime given its name
- *
- * @param string $name the connection name as it was created
- * @return boolean success if connection was removed, false if it does not exist
- */
- public static function drop($name) {
- if (empty(self::$_init)) {
- self::_init();
- }
-
- if (!isset(self::$config->{$name})) {
- return false;
- }
- unset(self::$_connectionsEnum[$name], self::$_dataSources[$name], self::$config->{$name});
- return true;
- }
-
-/**
- * Gets a list of class and file names associated with the user-defined DataSource connections
- *
- * @param string $name Connection name
- * @return void
- * @throws MissingDatasourceConfigException
- */
- protected static function _getConnectionObject($name) {
- if (!empty(self::$config->{$name})) {
- self::$_connectionsEnum[$name] = self::_connectionData(self::$config->{$name});
- } else {
- throw new MissingDatasourceConfigException(array('config' => $name));
- }
- }
-
-/**
- * Returns the file, class name, and parent for the given driver.
- *
- * @param array $config Array with connection configuration. Key 'datasource' is required
- * @return array An indexed array with: filename, classname, plugin and parent
- */
- protected static function _connectionData($config) {
- $package = $classname = $plugin = null;
-
- list($plugin, $classname) = pluginSplit($config['datasource']);
- if (strpos($classname, '/') !== false) {
- $package = dirname($classname);
- $classname = basename($classname);
- }
- return compact('package', 'classname', 'plugin');
- }
-
-}
diff --git a/lib/Cake/Model/Datasource/CakeSession.php b/lib/Cake/Model/Datasource/CakeSession.php
deleted file mode 100644
index 2abddbaec0a..00000000000
--- a/lib/Cake/Model/Datasource/CakeSession.php
+++ /dev/null
@@ -1,678 +0,0 @@
- values
- * @param array $new New set of variable => value
- * @return void
- */
- protected static function _overwrite(&$old, $new) {
- if (!empty($old)) {
- foreach ($old as $key => $var) {
- if (!isset($new[$key])) {
- unset($old[$key]);
- }
- }
- }
- foreach ($new as $key => $var) {
- $old[$key] = $var;
- }
- }
-
-/**
- * Return error description for given error number.
- *
- * @param integer $errorNumber Error to set
- * @return string Error as string
- */
- protected static function _error($errorNumber) {
- if (!is_array(self::$error) || !array_key_exists($errorNumber, self::$error)) {
- return false;
- } else {
- return self::$error[$errorNumber];
- }
- }
-
-/**
- * Returns last occurred error as a string, if any.
- *
- * @return mixed Error description as a string, or false.
- */
- public static function error() {
- if (self::$lastError) {
- return self::_error(self::$lastError);
- }
- return false;
- }
-
-/**
- * Returns true if session is valid.
- *
- * @return boolean Success
- */
- public static function valid() {
- if (self::read('Config')) {
- if (self::_validAgentAndTime() && self::$error === false) {
- self::$valid = true;
- } else {
- self::$valid = false;
- self::_setError(1, 'Session Highjacking Attempted !!!');
- }
- }
- return self::$valid;
- }
-
-/**
- * Tests that the user agent is valid and that the session hasn't 'timed out'.
- * Since timeouts are implemented in CakeSession it checks the current self::$time
- * against the time the session is set to expire. The User agent is only checked
- * if Session.checkAgent == true.
- *
- * @return boolean
- */
- protected static function _validAgentAndTime() {
- $config = self::read('Config');
- $validAgent = (
- Configure::read('Session.checkAgent') === false ||
- self::$_userAgent == $config['userAgent']
- );
- return ($validAgent && self::$time <= $config['time']);
- }
-
-/**
- * Get / Set the userAgent
- *
- * @param string $userAgent Set the userAgent
- * @return void
- */
- public static function userAgent($userAgent = null) {
- if ($userAgent) {
- self::$_userAgent = $userAgent;
- }
- if (empty(self::$_userAgent)) {
- CakeSession::init(self::$path);
- }
- return self::$_userAgent;
- }
-
-/**
- * Returns given session variable, or all of them, if no parameters given.
- *
- * @param mixed $name The name of the session variable (or a path as sent to Set.extract)
- * @return mixed The value of the session variable
- */
- public static function read($name = null) {
- if (!self::started() && !self::start()) {
- return false;
- }
- if (is_null($name)) {
- return self::_returnSessionVars();
- }
- if (empty($name)) {
- return false;
- }
- $result = Set::classicExtract($_SESSION, $name);
-
- if (!is_null($result)) {
- return $result;
- }
- self::_setError(2, "$name doesn't exist");
- return null;
- }
-
-/**
- * Returns all session variables.
- *
- * @return mixed Full $_SESSION array, or false on error.
- */
- protected static function _returnSessionVars() {
- if (!empty($_SESSION)) {
- return $_SESSION;
- }
- self::_setError(2, 'No Session vars set');
- return false;
- }
-
-/**
- * Writes value to given session variable name.
- *
- * @param mixed $name Name of variable
- * @param string $value Value to write
- * @return boolean True if the write was successful, false if the write failed
- */
- public static function write($name, $value = null) {
- if (!self::started() && !self::start()) {
- return false;
- }
- if (empty($name)) {
- return false;
- }
- $write = $name;
- if (!is_array($name)) {
- $write = array($name => $value);
- }
- foreach ($write as $key => $val) {
- self::_overwrite($_SESSION, Set::insert($_SESSION, $key, $val));
- if (Set::classicExtract($_SESSION, $key) !== $val) {
- return false;
- }
- }
- return true;
- }
-
-/**
- * Helper method to destroy invalid sessions.
- *
- * @return void
- */
- public static function destroy() {
- if (self::started()) {
- session_destroy();
- }
- self::clear();
- }
-
-/**
- * Clears the session, the session id, and renew's the session.
- *
- * @return void
- */
- public static function clear() {
- $_SESSION = null;
- self::$id = null;
- self::start();
- self::renew();
- }
-
-/**
- * Helper method to initialize a session, based on Cake core settings.
- *
- * Sessions can be configured with a few shortcut names as well as have any number of ini settings declared.
- *
- * @return void
- * @throws CakeSessionException Throws exceptions when ini_set() fails.
- */
- protected static function _configureSession() {
- $sessionConfig = Configure::read('Session');
- $iniSet = function_exists('ini_set');
-
- if (isset($sessionConfig['defaults'])) {
- $defaults = self::_defaultConfig($sessionConfig['defaults']);
- if ($defaults) {
- $sessionConfig = Set::merge($defaults, $sessionConfig);
- }
- }
- if (!isset($sessionConfig['ini']['session.cookie_secure']) && env('HTTPS')) {
- $sessionConfig['ini']['session.cookie_secure'] = 1;
- }
- if (isset($sessionConfig['timeout']) && !isset($sessionConfig['cookieTimeout'])) {
- $sessionConfig['cookieTimeout'] = $sessionConfig['timeout'];
- }
- if (!isset($sessionConfig['ini']['session.cookie_lifetime'])) {
- $sessionConfig['ini']['session.cookie_lifetime'] = $sessionConfig['cookieTimeout'] * 60;
- }
- if (!isset($sessionConfig['ini']['session.name'])) {
- $sessionConfig['ini']['session.name'] = $sessionConfig['cookie'];
- }
- if (!empty($sessionConfig['handler'])) {
- $sessionConfig['ini']['session.save_handler'] = 'user';
- }
-
- if (empty($_SESSION)) {
- if (!empty($sessionConfig['ini']) && is_array($sessionConfig['ini'])) {
- foreach ($sessionConfig['ini'] as $setting => $value) {
- if (ini_set($setting, $value) === false) {
- throw new CakeSessionException(sprintf(
- __d('cake_dev', 'Unable to configure the session, setting %s failed.'),
- $setting
- ));
- }
- }
- }
- }
- if (!empty($sessionConfig['handler']) && !isset($sessionConfig['handler']['engine'])) {
- call_user_func_array('session_set_save_handler', $sessionConfig['handler']);
- }
- if (!empty($sessionConfig['handler']['engine'])) {
- $handler = self::_getHandler($sessionConfig['handler']['engine']);
- session_set_save_handler(
- array($handler, 'open'),
- array($handler, 'close'),
- array($handler, 'read'),
- array($handler, 'write'),
- array($handler, 'destroy'),
- array($handler, 'gc')
- );
- }
- Configure::write('Session', $sessionConfig);
- self::$sessionTime = self::$time + ($sessionConfig['timeout'] * 60);
- }
-
-/**
- * Find the handler class and make sure it implements the correct interface.
- *
- * @param string $handler
- * @return void
- * @throws CakeSessionException
- */
- protected static function _getHandler($handler) {
- list($plugin, $class) = pluginSplit($handler, true);
- App::uses($class, $plugin . 'Model/Datasource/Session');
- if (!class_exists($class)) {
- throw new CakeSessionException(__d('cake_dev', 'Could not load %s to handle the session.', $class));
- }
- $handler = new $class();
- if ($handler instanceof CakeSessionHandlerInterface) {
- return $handler;
- }
- throw new CakeSessionException(__d('cake_dev', 'Chosen SessionHandler does not implement CakeSessionHandlerInterface it cannot be used with an engine key.'));
- }
-
-/**
- * Get one of the prebaked default session configurations.
- *
- * @param string $name
- * @return boolean|array
- */
- protected static function _defaultConfig($name) {
- $defaults = array(
- 'php' => array(
- 'cookie' => 'CAKEPHP',
- 'timeout' => 240,
- 'ini' => array(
- 'session.use_trans_sid' => 0,
- 'session.cookie_path' => self::$path
- )
- ),
- 'cake' => array(
- 'cookie' => 'CAKEPHP',
- 'timeout' => 240,
- 'ini' => array(
- 'session.use_trans_sid' => 0,
- 'url_rewriter.tags' => '',
- 'session.serialize_handler' => 'php',
- 'session.use_cookies' => 1,
- 'session.cookie_path' => self::$path,
- 'session.auto_start' => 0,
- 'session.save_path' => TMP . 'sessions',
- 'session.save_handler' => 'files'
- )
- ),
- 'cache' => array(
- 'cookie' => 'CAKEPHP',
- 'timeout' => 240,
- 'ini' => array(
- 'session.use_trans_sid' => 0,
- 'url_rewriter.tags' => '',
- 'session.auto_start' => 0,
- 'session.use_cookies' => 1,
- 'session.cookie_path' => self::$path,
- 'session.save_handler' => 'user',
- ),
- 'handler' => array(
- 'engine' => 'CacheSession',
- 'config' => 'default'
- )
- ),
- 'database' => array(
- 'cookie' => 'CAKEPHP',
- 'timeout' => 240,
- 'ini' => array(
- 'session.use_trans_sid' => 0,
- 'url_rewriter.tags' => '',
- 'session.auto_start' => 0,
- 'session.use_cookies' => 1,
- 'session.cookie_path' => self::$path,
- 'session.save_handler' => 'user',
- 'session.serialize_handler' => 'php',
- ),
- 'handler' => array(
- 'engine' => 'DatabaseSession',
- 'model' => 'Session'
- )
- )
- );
- if (isset($defaults[$name])) {
- return $defaults[$name];
- }
- return false;
- }
-
-/**
- * Helper method to start a session
- *
- * @return boolean Success
- */
- protected static function _startSession() {
- if (headers_sent()) {
- if (empty($_SESSION)) {
- $_SESSION = array();
- }
- } else {
- session_start();
- }
- return true;
- }
-
-/**
- * Helper method to create a new session.
- *
- * @return void
- */
- protected static function _checkValid() {
- if (!self::started() && !self::start()) {
- self::$valid = false;
- return false;
- }
- if ($config = self::read('Config')) {
- $sessionConfig = Configure::read('Session');
-
- if (self::_validAgentAndTime()) {
- self::write('Config.time', self::$sessionTime);
- if (isset($sessionConfig['autoRegenerate']) && $sessionConfig['autoRegenerate'] === true) {
- $check = $config['countdown'];
- $check -= 1;
- self::write('Config.countdown', $check);
-
- if ($check < 1) {
- self::renew();
- self::write('Config.countdown', self::$requestCountdown);
- }
- }
- self::$valid = true;
- } else {
- self::destroy();
- self::$valid = false;
- self::_setError(1, 'Session Highjacking Attempted !!!');
- }
- } else {
- self::write('Config.userAgent', self::$_userAgent);
- self::write('Config.time', self::$sessionTime);
- self::write('Config.countdown', self::$requestCountdown);
- self::$valid = true;
- }
- }
-
-/**
- * Restarts this session.
- *
- * @return void
- */
- public static function renew() {
- if (session_id()) {
- if (session_id() != '' || isset($_COOKIE[session_name()])) {
- setcookie(Configure::read('Session.cookie'), '', time() - 42000, self::$path);
- }
- session_regenerate_id(true);
- }
- }
-
-/**
- * Helper method to set an internal error message.
- *
- * @param integer $errorNumber Number of the error
- * @param string $errorMessage Description of the error
- * @return void
- */
- protected static function _setError($errorNumber, $errorMessage) {
- if (self::$error === false) {
- self::$error = array();
- }
- self::$error[$errorNumber] = $errorMessage;
- self::$lastError = $errorNumber;
- }
-
-}
diff --git a/lib/Cake/Model/Datasource/DataSource.php b/lib/Cake/Model/Datasource/DataSource.php
deleted file mode 100644
index 085a2c91009..00000000000
--- a/lib/Cake/Model/Datasource/DataSource.php
+++ /dev/null
@@ -1,432 +0,0 @@
-setConfig($config);
- }
-
-/**
- * Caches/returns cached results for child instances
- *
- * @param mixed $data
- * @return array Array of sources available in this datasource.
- */
- public function listSources($data = null) {
- if ($this->cacheSources === false) {
- return null;
- }
-
- if ($this->_sources !== null) {
- return $this->_sources;
- }
-
- $key = ConnectionManager::getSourceName($this) . '_' . $this->config['database'] . '_list';
- $key = preg_replace('/[^A-Za-z0-9_\-.+]/', '_', $key);
- $sources = Cache::read($key, '_cake_model_');
-
- if (empty($sources)) {
- $sources = $data;
- Cache::write($key, $data, '_cake_model_');
- }
-
- return $this->_sources = $sources;
- }
-
-/**
- * Returns a Model description (metadata) or null if none found.
- *
- * @param Model|string $model
- * @return array Array of Metadata for the $model
- */
- public function describe($model) {
- if ($this->cacheSources === false) {
- return null;
- }
- if (is_string($model)) {
- $table = $model;
- } else {
- $table = $model->tablePrefix . $model->table;
- }
-
- if (isset($this->_descriptions[$table])) {
- return $this->_descriptions[$table];
- }
- $cache = $this->_cacheDescription($table);
-
- if ($cache !== null) {
- $this->_descriptions[$table] =& $cache;
- return $cache;
- }
- return null;
- }
-
-/**
- * Begin a transaction
- *
- * @return boolean Returns true if a transaction is not in progress
- */
- public function begin() {
- return !$this->_transactionStarted;
- }
-
-/**
- * Commit a transaction
- *
- * @return boolean Returns true if a transaction is in progress
- */
- public function commit() {
- return $this->_transactionStarted;
- }
-
-/**
- * Rollback a transaction
- *
- * @return boolean Returns true if a transaction is in progress
- */
- public function rollback() {
- return $this->_transactionStarted;
- }
-
-/**
- * Converts column types to basic types
- *
- * @param string $real Real column type (i.e. "varchar(255)")
- * @return string Abstract column type (i.e. "string")
- */
- public function column($real) {
- return false;
- }
-
-/**
- * Used to create new records. The "C" CRUD.
- *
- * To-be-overridden in subclasses.
- *
- * @param Model $model The Model to be created.
- * @param array $fields An Array of fields to be saved.
- * @param array $values An Array of values to save.
- * @return boolean success
- */
- public function create(Model $model, $fields = null, $values = null) {
- return false;
- }
-
-/**
- * Used to read records from the Datasource. The "R" in CRUD
- *
- * To-be-overridden in subclasses.
- *
- * @param Model $model The model being read.
- * @param array $queryData An array of query data used to find the data you want
- * @return mixed
- */
- public function read(Model $model, $queryData = array()) {
- return false;
- }
-
-/**
- * Update a record(s) in the datasource.
- *
- * To-be-overridden in subclasses.
- *
- * @param Model $model Instance of the model class being updated
- * @param array $fields Array of fields to be updated
- * @param array $values Array of values to be update $fields to.
- * @return boolean Success
- */
- public function update(Model $model, $fields = null, $values = null) {
- return false;
- }
-
-/**
- * Delete a record(s) in the datasource.
- *
- * To-be-overridden in subclasses.
- *
- * @param Model $model The model class having record(s) deleted
- * @param mixed $conditions The conditions to use for deleting.
- * @return void
- */
- public function delete(Model $model, $id = null) {
- return false;
- }
-
-/**
- * Returns the ID generated from the previous INSERT operation.
- *
- * @param mixed $source
- * @return mixed Last ID key generated in previous INSERT
- */
- public function lastInsertId($source = null) {
- return false;
- }
-
-/**
- * Returns the number of rows returned by last operation.
- *
- * @param mixed $source
- * @return integer Number of rows returned by last operation
- */
- public function lastNumRows($source = null) {
- return false;
- }
-
-/**
- * Returns the number of rows affected by last query.
- *
- * @param mixed $source
- * @return integer Number of rows affected by last query.
- */
- public function lastAffected($source = null) {
- return false;
- }
-
-/**
- * Check whether the conditions for the Datasource being available
- * are satisfied. Often used from connect() to check for support
- * before establishing a connection.
- *
- * @return boolean Whether or not the Datasources conditions for use are met.
- */
- public function enabled() {
- return true;
- }
-
-/**
- * Sets the configuration for the DataSource.
- * Merges the $config information with the _baseConfig and the existing $config property.
- *
- * @param array $config The configuration array
- * @return void
- */
- public function setConfig($config = array()) {
- $this->config = array_merge($this->_baseConfig, $this->config, $config);
- }
-
-/**
- * Cache the DataSource description
- *
- * @param string $object The name of the object (model) to cache
- * @param mixed $data The description of the model, usually a string or array
- * @return mixed
- */
- protected function _cacheDescription($object, $data = null) {
- if ($this->cacheSources === false) {
- return null;
- }
-
- if ($data !== null) {
- $this->_descriptions[$object] =& $data;
- }
-
- $key = ConnectionManager::getSourceName($this) . '_' . $object;
- $cache = Cache::read($key, '_cake_model_');
-
- if (empty($cache)) {
- $cache = $data;
- Cache::write($key, $cache, '_cake_model_');
- }
-
- return $cache;
- }
-
-/**
- * Replaces `{$__cakeID__$}` and `{$__cakeForeignKey__$}` placeholders in query data.
- *
- * @param string $query Query string needing replacements done.
- * @param array $data Array of data with values that will be inserted in placeholders.
- * @param string $association Name of association model being replaced
- * @param array $assocData
- * @param Model $model Instance of the model to replace $__cakeID__$
- * @param Model $linkModel Instance of model to replace $__cakeForeignKey__$
- * @param array $stack
- * @return string String of query data with placeholders replaced.
- * @todo Remove and refactor $assocData, ensure uses of the method have the param removed too.
- */
- public function insertQueryData($query, $data, $association, $assocData, Model $model, Model $linkModel, $stack) {
- $keys = array('{$__cakeID__$}', '{$__cakeForeignKey__$}');
-
- foreach ($keys as $key) {
- $val = null;
- $type = null;
-
- if (strpos($query, $key) !== false) {
- switch ($key) {
- case '{$__cakeID__$}':
- if (isset($data[$model->alias]) || isset($data[$association])) {
- if (isset($data[$model->alias][$model->primaryKey])) {
- $val = $data[$model->alias][$model->primaryKey];
- } elseif (isset($data[$association][$model->primaryKey])) {
- $val = $data[$association][$model->primaryKey];
- }
- } else {
- $found = false;
- foreach (array_reverse($stack) as $assoc) {
- if (isset($data[$assoc]) && isset($data[$assoc][$model->primaryKey])) {
- $val = $data[$assoc][$model->primaryKey];
- $found = true;
- break;
- }
- }
- if (!$found) {
- $val = '';
- }
- }
- $type = $model->getColumnType($model->primaryKey);
- break;
- case '{$__cakeForeignKey__$}':
- foreach ($model->associations() as $id => $name) {
- foreach ($model->$name as $assocName => $assoc) {
- if ($assocName === $association) {
- if (isset($assoc['foreignKey'])) {
- $foreignKey = $assoc['foreignKey'];
- $assocModel = $model->$assocName;
- $type = $assocModel->getColumnType($assocModel->primaryKey);
-
- if (isset($data[$model->alias][$foreignKey])) {
- $val = $data[$model->alias][$foreignKey];
- } elseif (isset($data[$association][$foreignKey])) {
- $val = $data[$association][$foreignKey];
- } else {
- $found = false;
- foreach (array_reverse($stack) as $assoc) {
- if (isset($data[$assoc]) && isset($data[$assoc][$foreignKey])) {
- $val = $data[$assoc][$foreignKey];
- $found = true;
- break;
- }
- }
- if (!$found) {
- $val = '';
- }
- }
- }
- break 3;
- }
- }
- }
- break;
- }
- if (empty($val) && $val !== '0') {
- return false;
- }
- $query = str_replace($key, $this->value($val, $type), $query);
- }
- }
- return $query;
- }
-
-/**
- * To-be-overridden in subclasses.
- *
- * @param Model $model Model instance
- * @param string $key Key name to make
- * @return string Key name for model.
- */
- public function resolveKey(Model $model, $key) {
- return $model->alias . $key;
- }
-
-/**
- * Returns the schema name. Override this in subclasses.
- *
- * @return string schema name
- * @access public
- */
- public function getSchemaName() {
- return null;
- }
-
-/**
- * Closes the current datasource.
- *
- */
- public function __destruct() {
- if ($this->_transactionStarted) {
- $this->rollback();
- }
- if ($this->connected) {
- $this->close();
- }
- }
-
-}
diff --git a/lib/Cake/Model/Datasource/Database/Mysql.php b/lib/Cake/Model/Datasource/Database/Mysql.php
deleted file mode 100644
index b5421f43d93..00000000000
--- a/lib/Cake/Model/Datasource/Database/Mysql.php
+++ /dev/null
@@ -1,699 +0,0 @@
- true,
- 'host' => 'localhost',
- 'login' => 'root',
- 'password' => '',
- 'database' => 'cake',
- 'port' => '3306'
- );
-
-/**
- * Reference to the PDO object connection
- *
- * @var PDO $_connection
- */
- protected $_connection = null;
-
-/**
- * Start quote
- *
- * @var string
- */
- public $startQuote = "`";
-
-/**
- * End quote
- *
- * @var string
- */
- public $endQuote = "`";
-
-/**
- * use alias for update and delete. Set to true if version >= 4.1
- *
- * @var boolean
- */
- protected $_useAlias = true;
-
-/**
- * Index of basic SQL commands
- *
- * @var array
- */
- protected $_commands = array(
- 'begin' => 'START TRANSACTION',
- 'commit' => 'COMMIT',
- 'rollback' => 'ROLLBACK'
- );
-
-/**
- * List of engine specific additional field parameters used on table creating
- *
- * @var array
- */
- public $fieldParameters = array(
- 'charset' => array('value' => 'CHARACTER SET', 'quote' => false, 'join' => ' ', 'column' => false, 'position' => 'beforeDefault'),
- 'collate' => array('value' => 'COLLATE', 'quote' => false, 'join' => ' ', 'column' => 'Collation', 'position' => 'beforeDefault'),
- 'comment' => array('value' => 'COMMENT', 'quote' => true, 'join' => ' ', 'column' => 'Comment', 'position' => 'afterDefault')
- );
-
-/**
- * List of table engine specific parameters used on table creating
- *
- * @var array
- */
- public $tableParameters = array(
- 'charset' => array('value' => 'DEFAULT CHARSET', 'quote' => false, 'join' => '=', 'column' => 'charset'),
- 'collate' => array('value' => 'COLLATE', 'quote' => false, 'join' => '=', 'column' => 'Collation'),
- 'engine' => array('value' => 'ENGINE', 'quote' => false, 'join' => '=', 'column' => 'Engine')
- );
-
-/**
- * MySQL column definition
- *
- * @var array
- */
- public $columns = array(
- 'primary_key' => array('name' => 'NOT NULL AUTO_INCREMENT'),
- 'string' => array('name' => 'varchar', 'limit' => '255'),
- 'text' => array('name' => 'text'),
- 'integer' => array('name' => 'int', 'limit' => '11', 'formatter' => 'intval'),
- 'float' => array('name' => 'float', 'formatter' => 'floatval'),
- 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
- 'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
- 'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
- 'date' => array('name' => 'date', 'format' => 'Y-m-d', 'formatter' => 'date'),
- 'binary' => array('name' => 'blob'),
- 'boolean' => array('name' => 'tinyint', 'limit' => '1')
- );
-
-/**
- * Connects to the database using options in the given configuration array.
- *
- * @return boolean True if the database could be connected, else false
- * @throws MissingConnectionException
- */
- public function connect() {
- $config = $this->config;
- $this->connected = false;
- try {
- $flags = array(
- PDO::ATTR_PERSISTENT => $config['persistent'],
- PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
- PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
- );
- if (!empty($config['encoding'])) {
- $flags[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES ' . $config['encoding'];
- }
- if (empty($config['unix_socket'])) {
- $dsn = "mysql:host={$config['host']};port={$config['port']};dbname={$config['database']}";
- } else {
- $dsn = "mysql:unix_socket={$config['unix_socket']};dbname={$config['database']}";
- }
- $this->_connection = new PDO(
- $dsn,
- $config['login'],
- $config['password'],
- $flags
- );
- $this->connected = true;
- } catch (PDOException $e) {
- throw new MissingConnectionException(array('class' => $e->getMessage()));
- }
-
- $this->_useAlias = (bool)version_compare($this->getVersion(), "4.1", ">=");
-
- return $this->connected;
- }
-
-/**
- * Check whether the MySQL extension is installed/loaded
- *
- * @return boolean
- */
- public function enabled() {
- return in_array('mysql', PDO::getAvailableDrivers());
- }
-
-/**
- * Returns an array of sources (tables) in the database.
- *
- * @param mixed $data
- * @return array Array of table names in the database
- */
- public function listSources($data = null) {
- $cache = parent::listSources();
- if ($cache != null) {
- return $cache;
- }
- $result = $this->_execute('SHOW TABLES FROM ' . $this->name($this->config['database']));
-
- if (!$result) {
- $result->closeCursor();
- return array();
- } else {
- $tables = array();
-
- while ($line = $result->fetch(PDO::FETCH_NUM)) {
- $tables[] = $line[0];
- }
-
- $result->closeCursor();
- parent::listSources($tables);
- return $tables;
- }
- }
-
-/**
- * Builds a map of the columns contained in a result
- *
- * @param PDOStatement $results
- * @return void
- */
- public function resultSet($results) {
- $this->map = array();
- $numFields = $results->columnCount();
- $index = 0;
-
- while ($numFields-- > 0) {
- $column = $results->getColumnMeta($index);
- if (empty($column['native_type'])) {
- $type = ($column['len'] == 1) ? 'boolean' : 'string';
- } else {
- $type = $column['native_type'];
- }
- if (!empty($column['table']) && strpos($column['name'], $this->virtualFieldSeparator) === false) {
- $this->map[$index++] = array($column['table'], $column['name'], $type);
- } else {
- $this->map[$index++] = array(0, $column['name'], $type);
- }
- }
- }
-
-/**
- * Fetches the next row from the current result set
- *
- * @return mixed array with results fetched and mapped to column names or false if there is no results left to fetch
- */
- public function fetchResult() {
- if ($row = $this->_result->fetch(PDO::FETCH_NUM)) {
- $resultRow = array();
- foreach ($this->map as $col => $meta) {
- list($table, $column, $type) = $meta;
- $resultRow[$table][$column] = $row[$col];
- if ($type === 'boolean' && $row[$col] !== null) {
- $resultRow[$table][$column] = $this->boolean($resultRow[$table][$column]);
- }
- }
- return $resultRow;
- }
- $this->_result->closeCursor();
- return false;
- }
-
-/**
- * Gets the database encoding
- *
- * @return string The database encoding
- */
- public function getEncoding() {
- return $this->_execute('SHOW VARIABLES LIKE ?', array('character_set_client'))->fetchObject()->Value;
- }
-
-/**
- * Gets the version string of the database server
- *
- * @return string The database encoding
- */
- public function getVersion() {
- return $this->_connection->getAttribute(PDO::ATTR_SERVER_VERSION);
- }
-
-/**
- * Query charset by collation
- *
- * @param string $name Collation name
- * @return string Character set name
- */
- public function getCharsetName($name) {
- if ((bool)version_compare($this->getVersion(), "5", ">=")) {
- $r = $this->_execute('SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS WHERE COLLATION_NAME = ?', array($name));
- $cols = $r->fetch(PDO::FETCH_ASSOC);
-
- if (isset($cols['CHARACTER_SET_NAME'])) {
- return $cols['CHARACTER_SET_NAME'];
- }
- }
- return false;
- }
-
-/**
- * Returns an array of the fields in given table name.
- *
- * @param Model|string $model Name of database table to inspect or model instance
- * @return array Fields in table. Keys are name and type
- * @throws CakeException
- */
- public function describe($model) {
- $key = $this->fullTableName($model, false);
- $cache = parent::describe($key);
- if ($cache != null) {
- return $cache;
- }
- $table = $this->fullTableName($model);
-
- $fields = false;
- $cols = $this->_execute('SHOW FULL COLUMNS FROM ' . $table);
- if (!$cols) {
- throw new CakeException(__d('cake_dev', 'Could not describe table for %s', $table));
- }
-
- while ($column = $cols->fetch(PDO::FETCH_OBJ)) {
- $fields[$column->Field] = array(
- 'type' => $this->column($column->Type),
- 'null' => ($column->Null === 'YES' ? true : false),
- 'default' => $column->Default,
- 'length' => $this->length($column->Type),
- );
- if (!empty($column->Key) && isset($this->index[$column->Key])) {
- $fields[$column->Field]['key'] = $this->index[$column->Key];
- }
- foreach ($this->fieldParameters as $name => $value) {
- if (!empty($column->{$value['column']})) {
- $fields[$column->Field][$name] = $column->{$value['column']};
- }
- }
- if (isset($fields[$column->Field]['collate'])) {
- $charset = $this->getCharsetName($fields[$column->Field]['collate']);
- if ($charset) {
- $fields[$column->Field]['charset'] = $charset;
- }
- }
- }
- $this->_cacheDescription($key, $fields);
- $cols->closeCursor();
- return $fields;
- }
-
-/**
- * Generates and executes an SQL UPDATE statement for given model, fields, and values.
- *
- * @param Model $model
- * @param array $fields
- * @param array $values
- * @param mixed $conditions
- * @return array
- */
- public function update(Model $model, $fields = array(), $values = null, $conditions = null) {
- if (!$this->_useAlias) {
- return parent::update($model, $fields, $values, $conditions);
- }
-
- if ($values == null) {
- $combined = $fields;
- } else {
- $combined = array_combine($fields, $values);
- }
-
- $alias = $joins = false;
- $fields = $this->_prepareUpdateFields($model, $combined, empty($conditions), !empty($conditions));
- $fields = implode(', ', $fields);
- $table = $this->fullTableName($model);
-
- if (!empty($conditions)) {
- $alias = $this->name($model->alias);
- if ($model->name == $model->alias) {
- $joins = implode(' ', $this->_getJoins($model));
- }
- }
- $conditions = $this->conditions($this->defaultConditions($model, $conditions, $alias), true, true, $model);
-
- if ($conditions === false) {
- return false;
- }
-
- if (!$this->execute($this->renderStatement('update', compact('table', 'alias', 'joins', 'fields', 'conditions')))) {
- $model->onError();
- return false;
- }
- return true;
- }
-
-/**
- * Generates and executes an SQL DELETE statement for given id/conditions on given model.
- *
- * @param Model $model
- * @param mixed $conditions
- * @return boolean Success
- */
- public function delete(Model $model, $conditions = null) {
- if (!$this->_useAlias) {
- return parent::delete($model, $conditions);
- }
- $alias = $this->name($model->alias);
- $table = $this->fullTableName($model);
- $joins = implode(' ', $this->_getJoins($model));
-
- if (empty($conditions)) {
- $alias = $joins = false;
- }
- $complexConditions = false;
- foreach ((array)$conditions as $key => $value) {
- if (strpos($key, $model->alias) === false) {
- $complexConditions = true;
- break;
- }
- }
- if (!$complexConditions) {
- $joins = false;
- }
-
- $conditions = $this->conditions($this->defaultConditions($model, $conditions, $alias), true, true, $model);
- if ($conditions === false) {
- return false;
- }
- if ($this->execute($this->renderStatement('delete', compact('alias', 'table', 'joins', 'conditions'))) === false) {
- $model->onError();
- return false;
- }
- return true;
- }
-
-/**
- * Sets the database encoding
- *
- * @param string $enc Database encoding
- * @return boolean
- */
- public function setEncoding($enc) {
- return $this->_execute('SET NAMES ' . $enc) !== false;
- }
-
-/**
- * Returns an array of the indexes in given datasource name.
- *
- * @param string $model Name of model to inspect
- * @return array Fields in table. Keys are column and unique
- */
- public function index($model) {
- $index = array();
- $table = $this->fullTableName($model);
- $old = version_compare($this->getVersion(), '4.1', '<=');
- if ($table) {
- $indices = $this->_execute('SHOW INDEX FROM ' . $table);
- // @codingStandardsIgnoreStart
- // MySQL columns don't match the cakephp conventions.
- while ($idx = $indices->fetch(PDO::FETCH_OBJ)) {
- if ($old) {
- $idx = (object)current((array)$idx);
- }
- if (!isset($index[$idx->Key_name]['column'])) {
- $col = array();
- $index[$idx->Key_name]['column'] = $idx->Column_name;
- $index[$idx->Key_name]['unique'] = intval($idx->Non_unique == 0);
- } else {
- if (!empty($index[$idx->Key_name]['column']) && !is_array($index[$idx->Key_name]['column'])) {
- $col[] = $index[$idx->Key_name]['column'];
- }
- $col[] = $idx->Column_name;
- $index[$idx->Key_name]['column'] = $col;
- }
- }
- // @codingStandardsIgnoreEnd
- $indices->closeCursor();
- }
- return $index;
- }
-
-/**
- * Generate a MySQL Alter Table syntax for the given Schema comparison
- *
- * @param array $compare Result of a CakeSchema::compare()
- * @param string $table
- * @return array Array of alter statements to make.
- */
- public function alterSchema($compare, $table = null) {
- if (!is_array($compare)) {
- return false;
- }
- $out = '';
- $colList = array();
- foreach ($compare as $curTable => $types) {
- $indexes = $tableParameters = $colList = array();
- if (!$table || $table == $curTable) {
- $out .= 'ALTER TABLE ' . $this->fullTableName($curTable) . " \n";
- foreach ($types as $type => $column) {
- if (isset($column['indexes'])) {
- $indexes[$type] = $column['indexes'];
- unset($column['indexes']);
- }
- if (isset($column['tableParameters'])) {
- $tableParameters[$type] = $column['tableParameters'];
- unset($column['tableParameters']);
- }
- switch ($type) {
- case 'add':
- foreach ($column as $field => $col) {
- $col['name'] = $field;
- $alter = 'ADD ' . $this->buildColumn($col);
- if (isset($col['after'])) {
- $alter .= ' AFTER ' . $this->name($col['after']);
- }
- $colList[] = $alter;
- }
- break;
- case 'drop':
- foreach ($column as $field => $col) {
- $col['name'] = $field;
- $colList[] = 'DROP ' . $this->name($field);
- }
- break;
- case 'change':
- foreach ($column as $field => $col) {
- if (!isset($col['name'])) {
- $col['name'] = $field;
- }
- $colList[] = 'CHANGE ' . $this->name($field) . ' ' . $this->buildColumn($col);
- }
- break;
- }
- }
- $colList = array_merge($colList, $this->_alterIndexes($curTable, $indexes));
- $colList = array_merge($colList, $this->_alterTableParameters($curTable, $tableParameters));
- $out .= "\t" . implode(",\n\t", $colList) . ";\n\n";
- }
- }
- return $out;
- }
-
-/**
- * Generate a MySQL "drop table" statement for the given Schema object
- *
- * @param CakeSchema $schema An instance of a subclass of CakeSchema
- * @param string $table Optional. If specified only the table name given will be generated.
- * Otherwise, all tables defined in the schema are generated.
- * @return string
- */
- public function dropSchema(CakeSchema $schema, $table = null) {
- $out = '';
- foreach ($schema->tables as $curTable => $columns) {
- if (!$table || $table === $curTable) {
- $out .= 'DROP TABLE IF EXISTS ' . $this->fullTableName($curTable) . ";\n";
- }
- }
- return $out;
- }
-
-/**
- * Generate MySQL table parameter alteration statements for a table.
- *
- * @param string $table Table to alter parameters for.
- * @param array $parameters Parameters to add & drop.
- * @return array Array of table property alteration statements.
- * @todo Implement this method.
- */
- protected function _alterTableParameters($table, $parameters) {
- if (isset($parameters['change'])) {
- return $this->buildTableParameters($parameters['change']);
- }
- return array();
- }
-
-/**
- * Generate MySQL index alteration statements for a table.
- *
- * @param string $table Table to alter indexes for
- * @param array $indexes Indexes to add and drop
- * @return array Index alteration statements
- */
- protected function _alterIndexes($table, $indexes) {
- $alter = array();
- if (isset($indexes['drop'])) {
- foreach ($indexes['drop'] as $name => $value) {
- $out = 'DROP ';
- if ($name == 'PRIMARY') {
- $out .= 'PRIMARY KEY';
- } else {
- $out .= 'KEY ' . $name;
- }
- $alter[] = $out;
- }
- }
- if (isset($indexes['add'])) {
- foreach ($indexes['add'] as $name => $value) {
- $out = 'ADD ';
- if ($name == 'PRIMARY') {
- $out .= 'PRIMARY ';
- $name = null;
- } else {
- if (!empty($value['unique'])) {
- $out .= 'UNIQUE ';
- }
- }
- if (is_array($value['column'])) {
- $out .= 'KEY ' . $name . ' (' . implode(', ', array_map(array(&$this, 'name'), $value['column'])) . ')';
- } else {
- $out .= 'KEY ' . $name . ' (' . $this->name($value['column']) . ')';
- }
- $alter[] = $out;
- }
- }
- return $alter;
- }
-
-/**
- * Returns an detailed array of sources (tables) in the database.
- *
- * @param string $name Table name to get parameters
- * @return array Array of table names in the database
- */
- public function listDetailedSources($name = null) {
- $condition = '';
- if (is_string($name)) {
- $condition = ' WHERE name = ' . $this->value($name);
- }
- $result = $this->_connection->query('SHOW TABLE STATUS ' . $condition, PDO::FETCH_ASSOC);
-
- if (!$result) {
- $result->closeCursor();
- return array();
- } else {
- $tables = array();
- foreach ($result as $row) {
- $tables[$row['Name']] = (array)$row;
- unset($tables[$row['Name']]['queryString']);
- if (!empty($row['Collation'])) {
- $charset = $this->getCharsetName($row['Collation']);
- if ($charset) {
- $tables[$row['Name']]['charset'] = $charset;
- }
- }
- }
- $result->closeCursor();
- if (is_string($name) && isset($tables[$name])) {
- return $tables[$name];
- }
- return $tables;
- }
- }
-
-/**
- * Converts database-layer column types to basic types
- *
- * @param string $real Real database-layer column type (i.e. "varchar(255)")
- * @return string Abstract column type (i.e. "string")
- */
- public function column($real) {
- if (is_array($real)) {
- $col = $real['name'];
- if (isset($real['limit'])) {
- $col .= '(' . $real['limit'] . ')';
- }
- return $col;
- }
-
- $col = str_replace(')', '', $real);
- $limit = $this->length($real);
- if (strpos($col, '(') !== false) {
- list($col, $vals) = explode('(', $col);
- }
-
- if (in_array($col, array('date', 'time', 'datetime', 'timestamp'))) {
- return $col;
- }
- if (($col === 'tinyint' && $limit == 1) || $col === 'boolean') {
- return 'boolean';
- }
- if (strpos($col, 'int') !== false) {
- return 'integer';
- }
- if (strpos($col, 'char') !== false || $col === 'tinytext') {
- return 'string';
- }
- if (strpos($col, 'text') !== false) {
- return 'text';
- }
- if (strpos($col, 'blob') !== false || $col === 'binary') {
- return 'binary';
- }
- if (strpos($col, 'float') !== false || strpos($col, 'double') !== false || strpos($col, 'decimal') !== false) {
- return 'float';
- }
- if (strpos($col, 'enum') !== false) {
- return "enum($vals)";
- }
- return 'text';
- }
-
-/**
- * Gets the schema name
- *
- * @return string The schema name
- */
- public function getSchemaName() {
- return $this->config['database'];
- }
-
-}
diff --git a/lib/Cake/Model/Datasource/Database/Postgres.php b/lib/Cake/Model/Datasource/Database/Postgres.php
deleted file mode 100644
index 41d1844d0cc..00000000000
--- a/lib/Cake/Model/Datasource/Database/Postgres.php
+++ /dev/null
@@ -1,909 +0,0 @@
- 'BEGIN',
- 'commit' => 'COMMIT',
- 'rollback' => 'ROLLBACK'
- );
-
-/**
- * Base driver configuration settings. Merged with user settings.
- *
- * @var array
- */
- protected $_baseConfig = array(
- 'persistent' => true,
- 'host' => 'localhost',
- 'login' => 'root',
- 'password' => '',
- 'database' => 'cake',
- 'schema' => 'public',
- 'port' => 5432,
- 'encoding' => ''
- );
-
-/**
- * Columns
- *
- * @var array
- */
- public $columns = array(
- 'primary_key' => array('name' => 'serial NOT NULL'),
- 'string' => array('name' => 'varchar', 'limit' => '255'),
- 'text' => array('name' => 'text'),
- 'integer' => array('name' => 'integer', 'formatter' => 'intval'),
- 'float' => array('name' => 'float', 'formatter' => 'floatval'),
- 'datetime' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
- 'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
- 'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
- 'date' => array('name' => 'date', 'format' => 'Y-m-d', 'formatter' => 'date'),
- 'binary' => array('name' => 'bytea'),
- 'boolean' => array('name' => 'boolean'),
- 'number' => array('name' => 'numeric'),
- 'inet' => array('name' => 'inet')
- );
-
-/**
- * Starting Quote
- *
- * @var string
- */
- public $startQuote = '"';
-
-/**
- * Ending Quote
- *
- * @var string
- */
- public $endQuote = '"';
-
-/**
- * Contains mappings of custom auto-increment sequences, if a table uses a sequence name
- * other than what is dictated by convention.
- *
- * @var array
- */
- protected $_sequenceMap = array();
-
-/**
- * Connects to the database using options in the given configuration array.
- *
- * @return boolean True if successfully connected.
- * @throws MissingConnectionException
- */
- public function connect() {
- $config = $this->config;
- $this->connected = false;
- try {
- $flags = array(
- PDO::ATTR_PERSISTENT => $config['persistent'],
- PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
- );
- $this->_connection = new PDO(
- "pgsql:host={$config['host']};port={$config['port']};dbname={$config['database']}",
- $config['login'],
- $config['password'],
- $flags
- );
-
- $this->connected = true;
- if (!empty($config['encoding'])) {
- $this->setEncoding($config['encoding']);
- }
- if (!empty($config['schema'])) {
- $this->_execute('SET search_path TO ' . $config['schema']);
- }
- } catch (PDOException $e) {
- throw new MissingConnectionException(array('class' => $e->getMessage()));
- }
-
- return $this->connected;
- }
-
-/**
- * Check if PostgreSQL is enabled/loaded
- *
- * @return boolean
- */
- public function enabled() {
- return in_array('pgsql', PDO::getAvailableDrivers());
- }
-
-/**
- * Returns an array of tables in the database. If there are no tables, an error is raised and the application exits.
- *
- * @param mixed $data
- * @return array Array of table names in the database
- */
- public function listSources($data = null) {
- $cache = parent::listSources();
-
- if ($cache != null) {
- return $cache;
- }
-
- $schema = $this->config['schema'];
- $sql = "SELECT table_name as name FROM INFORMATION_SCHEMA.tables WHERE table_schema = ?";
- $result = $this->_execute($sql, array($schema));
-
- if (!$result) {
- return array();
- } else {
- $tables = array();
-
- foreach ($result as $item) {
- $tables[] = $item->name;
- }
-
- $result->closeCursor();
- parent::listSources($tables);
- return $tables;
- }
- }
-
-/**
- * Returns an array of the fields in given table name.
- *
- * @param Model|string $model Name of database table to inspect
- * @return array Fields in table. Keys are name and type
- */
- public function describe($model) {
- $table = $this->fullTableName($model, false, false);
- $fields = parent::describe($table);
- $this->_sequenceMap[$table] = array();
- $cols = null;
-
- if ($fields === null) {
- $cols = $this->_execute(
- "SELECT DISTINCT table_schema AS schema, column_name AS name, data_type AS type, is_nullable AS null,
- column_default AS default, ordinal_position AS position, character_maximum_length AS char_length,
- character_octet_length AS oct_length FROM information_schema.columns
- WHERE table_name = ? AND table_schema = ? ORDER BY position",
- array($table, $this->config['schema'])
- );
-
- // @codingStandardsIgnoreStart
- // Postgres columns don't match the coding standards.
- foreach ($cols as $c) {
- $type = $c->type;
- if (!empty($c->oct_length) && $c->char_length === null) {
- if ($c->type == 'character varying') {
- $length = null;
- $type = 'text';
- } elseif ($c->type == 'uuid') {
- $length = 36;
- } else {
- $length = intval($c->oct_length);
- }
- } elseif (!empty($c->char_length)) {
- $length = intval($c->char_length);
- } else {
- $length = $this->length($c->type);
- }
- if (empty($length)) {
- $length = null;
- }
- $fields[$c->name] = array(
- 'type' => $this->column($type),
- 'null' => ($c->null == 'NO' ? false : true),
- 'default' => preg_replace(
- "/^'(.*)'$/",
- "$1",
- preg_replace('/::.*/', '', $c->default)
- ),
- 'length' => $length
- );
- if ($model instanceof Model) {
- if ($c->name == $model->primaryKey) {
- $fields[$c->name]['key'] = 'primary';
- if ($fields[$c->name]['type'] !== 'string') {
- $fields[$c->name]['length'] = 11;
- }
- }
- }
- if (
- $fields[$c->name]['default'] == 'NULL' ||
- preg_match('/nextval\([\'"]?([\w.]+)/', $c->default, $seq)
- ) {
- $fields[$c->name]['default'] = null;
- if (!empty($seq) && isset($seq[1])) {
- if (strpos($seq[1], '.') === false) {
- $sequenceName = $c->schema . '.' . $seq[1];
- } else {
- $sequenceName = $seq[1];
- }
- $this->_sequenceMap[$table][$c->name] = $sequenceName;
- }
- }
- if ($fields[$c->name]['type'] == 'boolean' && !empty($fields[$c->name]['default'])) {
- $fields[$c->name]['default'] = constant($fields[$c->name]['default']);
- }
- }
- $this->_cacheDescription($table, $fields);
- }
- // @codingStandardsIgnoreEnd
-
- if (isset($model->sequence)) {
- $this->_sequenceMap[$table][$model->primaryKey] = $model->sequence;
- }
-
- if ($cols) {
- $cols->closeCursor();
- }
- return $fields;
- }
-
-/**
- * Returns the ID generated from the previous INSERT operation.
- *
- * @param string $source Name of the database table
- * @param string $field Name of the ID database field. Defaults to "id"
- * @return integer
- */
- public function lastInsertId($source = null, $field = 'id') {
- $seq = $this->getSequence($source, $field);
- return $this->_connection->lastInsertId($seq);
- }
-
-/**
- * Gets the associated sequence for the given table/field
- *
- * @param mixed $table Either a full table name (with prefix) as a string, or a model object
- * @param string $field Name of the ID database field. Defaults to "id"
- * @return string The associated sequence name from the sequence map, defaults to "{$table}_{$field}_seq"
- */
- public function getSequence($table, $field = 'id') {
- if (is_object($table)) {
- $table = $this->fullTableName($table, false, false);
- }
- if (isset($this->_sequenceMap[$table]) && isset($this->_sequenceMap[$table][$field])) {
- return $this->_sequenceMap[$table][$field];
- } else {
- return "{$table}_{$field}_seq";
- }
- }
-
-/**
- * Deletes all the records in a table and drops all associated auto-increment sequences
- *
- * @param mixed $table A string or model class representing the table to be truncated
- * @param boolean $reset true for resetting the sequence, false to leave it as is.
- * and if 1, sequences are not modified
- * @return boolean SQL TRUNCATE TABLE statement, false if not applicable.
- */
- public function truncate($table, $reset = false) {
- $table = $this->fullTableName($table, false, false);
- if (!isset($this->_sequenceMap[$table])) {
- $cache = $this->cacheSources;
- $this->cacheSources = false;
- $this->describe($table);
- $this->cacheSources = $cache;
- }
- if ($this->execute('DELETE FROM ' . $this->fullTableName($table))) {
- $schema = $this->config['schema'];
- if (isset($this->_sequenceMap[$table]) && $reset != true) {
- foreach ($this->_sequenceMap[$table] as $field => $sequence) {
- list($schema, $sequence) = explode('.', $sequence);
- $this->_execute("ALTER SEQUENCE \"{$schema}\".\"{$sequence}\" RESTART WITH 1");
- }
- }
- return true;
- }
- return false;
- }
-
-/**
- * Prepares field names to be quoted by parent
- *
- * @param string $data
- * @return string SQL field
- */
- public function name($data) {
- if (is_string($data)) {
- $data = str_replace('"__"', '__', $data);
- }
- return parent::name($data);
- }
-
-/**
- * Generates the fields list of an SQL query.
- *
- * @param Model $model
- * @param string $alias Alias table name
- * @param mixed $fields
- * @param boolean $quote
- * @return array
- */
- public function fields(Model $model, $alias = null, $fields = array(), $quote = true) {
- if (empty($alias)) {
- $alias = $model->alias;
- }
- $fields = parent::fields($model, $alias, $fields, false);
-
- if (!$quote) {
- return $fields;
- }
- $count = count($fields);
-
- if ($count >= 1 && !preg_match('/^\s*COUNT\(\*/', $fields[0])) {
- $result = array();
- for ($i = 0; $i < $count; $i++) {
- if (!preg_match('/^.+\\(.*\\)/', $fields[$i]) && !preg_match('/\s+AS\s+/', $fields[$i])) {
- if (substr($fields[$i], -1) == '*') {
- if (strpos($fields[$i], '.') !== false && $fields[$i] != $alias . '.*') {
- $build = explode('.', $fields[$i]);
- $AssociatedModel = $model->{$build[0]};
- } else {
- $AssociatedModel = $model;
- }
-
- $_fields = $this->fields($AssociatedModel, $AssociatedModel->alias, array_keys($AssociatedModel->schema()));
- $result = array_merge($result, $_fields);
- continue;
- }
-
- $prepend = '';
- if (strpos($fields[$i], 'DISTINCT') !== false) {
- $prepend = 'DISTINCT ';
- $fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i]));
- }
-
- if (strrpos($fields[$i], '.') === false) {
- $fields[$i] = $prepend . $this->name($alias) . '.' . $this->name($fields[$i]) . ' AS ' . $this->name($alias . '__' . $fields[$i]);
- } else {
- $build = explode('.', $fields[$i]);
- $fields[$i] = $prepend . $this->name($build[0]) . '.' . $this->name($build[1]) . ' AS ' . $this->name($build[0] . '__' . $build[1]);
- }
- } else {
- $fields[$i] = preg_replace_callback('/\(([\s\.\w]+)\)/', array(&$this, '_quoteFunctionField'), $fields[$i]);
- }
- $result[] = $fields[$i];
- }
- return $result;
- }
- return $fields;
- }
-
-/**
- * Auxiliary function to quote matched `(Model.fields)` from a preg_replace_callback call
- * Quotes the fields in a function call.
- *
- * @param string $match matched string
- * @return string quoted string
- */
- protected function _quoteFunctionField($match) {
- $prepend = '';
- if (strpos($match[1], 'DISTINCT') !== false) {
- $prepend = 'DISTINCT ';
- $match[1] = trim(str_replace('DISTINCT', '', $match[1]));
- }
- $constant = preg_match('/^\d+|NULL|FALSE|TRUE$/i', $match[1]);
-
- if (!$constant && strpos($match[1], '.') === false) {
- $match[1] = $this->name($match[1]);
- } elseif (!$constant) {
- $parts = explode('.', $match[1]);
- if (!Set::numeric($parts)) {
- $match[1] = $this->name($match[1]);
- }
- }
- return '(' . $prepend . $match[1] . ')';
- }
-
-/**
- * Returns an array of the indexes in given datasource name.
- *
- * @param string $model Name of model to inspect
- * @return array Fields in table. Keys are column and unique
- */
- public function index($model) {
- $index = array();
- $table = $this->fullTableName($model, false, false);
- if ($table) {
- $indexes = $this->query("SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, i.indisvalid, pg_catalog.pg_get_indexdef(i.indexrelid, 0, true) as statement, c2.reltablespace
- FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i
- WHERE c.oid = (
- SELECT c.oid
- FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
- WHERE c.relname ~ '^(" . $table . ")$'
- AND pg_catalog.pg_table_is_visible(c.oid)
- AND n.nspname ~ '^(" . $this->config['schema'] . ")$'
- )
- AND c.oid = i.indrelid AND i.indexrelid = c2.oid
- ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname", false);
- foreach ($indexes as $i => $info) {
- $key = array_pop($info);
- if ($key['indisprimary']) {
- $key['relname'] = 'PRIMARY';
- }
- preg_match('/\(([^\)]+)\)/', $key['statement'], $indexColumns);
- $parsedColumn = $indexColumns[1];
- if (strpos($indexColumns[1], ',') !== false) {
- $parsedColumn = explode(', ', $indexColumns[1]);
- }
- $index[$key['relname']]['unique'] = $key['indisunique'];
- $index[$key['relname']]['column'] = $parsedColumn;
- }
- }
- return $index;
- }
-
-/**
- * Alter the Schema of a table.
- *
- * @param array $compare Results of CakeSchema::compare()
- * @param string $table name of the table
- * @return array
- */
- public function alterSchema($compare, $table = null) {
- if (!is_array($compare)) {
- return false;
- }
- $out = '';
- $colList = array();
- foreach ($compare as $curTable => $types) {
- $indexes = $colList = array();
- if (!$table || $table == $curTable) {
- $out .= 'ALTER TABLE ' . $this->fullTableName($curTable) . " \n";
- foreach ($types as $type => $column) {
- if (isset($column['indexes'])) {
- $indexes[$type] = $column['indexes'];
- unset($column['indexes']);
- }
- switch ($type) {
- case 'add':
- foreach ($column as $field => $col) {
- $col['name'] = $field;
- $colList[] = 'ADD COLUMN ' . $this->buildColumn($col);
- }
- break;
- case 'drop':
- foreach ($column as $field => $col) {
- $col['name'] = $field;
- $colList[] = 'DROP COLUMN ' . $this->name($field);
- }
- break;
- case 'change':
- foreach ($column as $field => $col) {
- if (!isset($col['name'])) {
- $col['name'] = $field;
- }
- $fieldName = $this->name($field);
-
- $default = isset($col['default']) ? $col['default'] : null;
- $nullable = isset($col['null']) ? $col['null'] : null;
- unset($col['default'], $col['null']);
- $colList[] = 'ALTER COLUMN ' . $fieldName . ' TYPE ' . str_replace(array($fieldName, 'NOT NULL'), '', $this->buildColumn($col));
- if (isset($nullable)) {
- $nullable = ($nullable) ? 'DROP NOT NULL' : 'SET NOT NULL';
- $colList[] = 'ALTER COLUMN ' . $fieldName . ' ' . $nullable;
- }
-
- if (isset($default)) {
- $colList[] = 'ALTER COLUMN ' . $fieldName . ' SET DEFAULT ' . $this->value($default, $col['type']);
- } else {
- $colList[] = 'ALTER COLUMN ' . $fieldName . ' DROP DEFAULT';
- }
-
- }
- break;
- }
- }
- if (isset($indexes['drop']['PRIMARY'])) {
- $colList[] = 'DROP CONSTRAINT ' . $curTable . '_pkey';
- }
- if (isset($indexes['add']['PRIMARY'])) {
- $cols = $indexes['add']['PRIMARY']['column'];
- if (is_array($cols)) {
- $cols = implode(', ', $cols);
- }
- $colList[] = 'ADD PRIMARY KEY (' . $cols . ')';
- }
-
- if (!empty($colList)) {
- $out .= "\t" . implode(",\n\t", $colList) . ";\n\n";
- } else {
- $out = '';
- }
- $out .= implode(";\n\t", $this->_alterIndexes($curTable, $indexes));
- }
- }
- return $out;
- }
-
-/**
- * Generate PostgreSQL index alteration statements for a table.
- *
- * @param string $table Table to alter indexes for
- * @param array $indexes Indexes to add and drop
- * @return array Index alteration statements
- */
- protected function _alterIndexes($table, $indexes) {
- $alter = array();
- if (isset($indexes['drop'])) {
- foreach ($indexes['drop'] as $name => $value) {
- $out = 'DROP ';
- if ($name == 'PRIMARY') {
- continue;
- } else {
- $out .= 'INDEX ' . $name;
- }
- $alter[] = $out;
- }
- }
- if (isset($indexes['add'])) {
- foreach ($indexes['add'] as $name => $value) {
- $out = 'CREATE ';
- if ($name == 'PRIMARY') {
- continue;
- } else {
- if (!empty($value['unique'])) {
- $out .= 'UNIQUE ';
- }
- $out .= 'INDEX ';
- }
- if (is_array($value['column'])) {
- $out .= $name . ' ON ' . $table . ' (' . implode(', ', array_map(array(&$this, 'name'), $value['column'])) . ')';
- } else {
- $out .= $name . ' ON ' . $table . ' (' . $this->name($value['column']) . ')';
- }
- $alter[] = $out;
- }
- }
- return $alter;
- }
-
-/**
- * Returns a limit statement in the correct format for the particular database.
- *
- * @param integer $limit Limit of results returned
- * @param integer $offset Offset from which to start results
- * @return string SQL limit/offset statement
- */
- public function limit($limit, $offset = null) {
- if ($limit) {
- $rt = '';
- if (!strpos(strtolower($limit), 'limit') || strpos(strtolower($limit), 'limit') === 0) {
- $rt = ' LIMIT';
- }
-
- $rt .= ' ' . $limit;
- if ($offset) {
- $rt .= ' OFFSET ' . $offset;
- }
-
- return $rt;
- }
- return null;
- }
-
-/**
- * Converts database-layer column types to basic types
- *
- * @param string $real Real database-layer column type (i.e. "varchar(255)")
- * @return string Abstract column type (i.e. "string")
- */
- public function column($real) {
- if (is_array($real)) {
- $col = $real['name'];
- if (isset($real['limit'])) {
- $col .= '(' . $real['limit'] . ')';
- }
- return $col;
- }
-
- $col = str_replace(')', '', $real);
- $limit = null;
-
- if (strpos($col, '(') !== false) {
- list($col, $limit) = explode('(', $col);
- }
-
- $floats = array(
- 'float', 'float4', 'float8', 'double', 'double precision', 'decimal', 'real', 'numeric'
- );
-
- switch (true) {
- case (in_array($col, array('date', 'time', 'inet', 'boolean'))):
- return $col;
- case (strpos($col, 'timestamp') !== false):
- return 'datetime';
- case (strpos($col, 'time') === 0):
- return 'time';
- case (strpos($col, 'int') !== false && $col != 'interval'):
- return 'integer';
- case (strpos($col, 'char') !== false || $col == 'uuid'):
- return 'string';
- case (strpos($col, 'text') !== false):
- return 'text';
- case (strpos($col, 'bytea') !== false):
- return 'binary';
- case (in_array($col, $floats)):
- return 'float';
- default:
- return 'text';
- break;
- }
- }
-
-/**
- * Gets the length of a database-native column description, or null if no length
- *
- * @param string $real Real database-layer column type (i.e. "varchar(255)")
- * @return integer An integer representing the length of the column
- */
- public function length($real) {
- $col = str_replace(array(')', 'unsigned'), '', $real);
- $limit = null;
-
- if (strpos($col, '(') !== false) {
- list($col, $limit) = explode('(', $col);
- }
- if ($col == 'uuid') {
- return 36;
- }
- if ($limit != null) {
- return intval($limit);
- }
- return null;
- }
-
-/**
- * resultSet method
- *
- * @param array $results
- * @return void
- */
- public function resultSet(&$results) {
- $this->map = array();
- $numFields = $results->columnCount();
- $index = 0;
- $j = 0;
-
- while ($j < $numFields) {
- $column = $results->getColumnMeta($j);
- if (strpos($column['name'], '__')) {
- list($table, $name) = explode('__', $column['name']);
- $this->map[$index++] = array($table, $name, $column['native_type']);
- } else {
- $this->map[$index++] = array(0, $column['name'], $column['native_type']);
- }
- $j++;
- }
- }
-
-/**
- * Fetches the next row from the current result set
- *
- * @return array
- */
- public function fetchResult() {
- if ($row = $this->_result->fetch(PDO::FETCH_NUM)) {
- $resultRow = array();
-
- foreach ($this->map as $index => $meta) {
- list($table, $column, $type) = $meta;
-
- switch ($type) {
- case 'bool':
- $resultRow[$table][$column] = is_null($row[$index]) ? null : $this->boolean($row[$index]);
- break;
- case 'binary':
- case 'bytea':
- $resultRow[$table][$column] = is_null($row[$index]) ? null : stream_get_contents($row[$index]);
- break;
- default:
- $resultRow[$table][$column] = $row[$index];
- break;
- }
- }
- return $resultRow;
- } else {
- $this->_result->closeCursor();
- return false;
- }
- }
-
-/**
- * Translates between PHP boolean values and PostgreSQL boolean values
- *
- * @param mixed $data Value to be translated
- * @param boolean $quote true to quote a boolean to be used in a query, false to return the boolean value
- * @return boolean Converted boolean value
- */
- public function boolean($data, $quote = false) {
- switch (true) {
- case ($data === true || $data === false):
- $result = $data;
- break;
- case ($data === 't' || $data === 'f'):
- $result = ($data === 't');
- break;
- case ($data === 'true' || $data === 'false'):
- $result = ($data === 'true');
- break;
- case ($data === 'TRUE' || $data === 'FALSE'):
- $result = ($data === 'TRUE');
- break;
- default:
- $result = (bool)$data;
- break;
- }
-
- if ($quote) {
- return ($result) ? 'TRUE' : 'FALSE';
- }
- return (bool)$result;
- }
-
-/**
- * Sets the database encoding
- *
- * @param mixed $enc Database encoding
- * @return boolean True on success, false on failure
- */
- public function setEncoding($enc) {
- return $this->_execute('SET NAMES ' . $this->value($enc)) !== false;
- }
-
-/**
- * Gets the database encoding
- *
- * @return string The database encoding
- */
- public function getEncoding() {
- $result = $this->_execute('SHOW client_encoding')->fetch();
- if ($result === false) {
- return false;
- }
- return (isset($result['client_encoding'])) ? $result['client_encoding'] : false;
- }
-
-/**
- * Generate a Postgres-native column schema string
- *
- * @param array $column An array structured like the following:
- * array('name'=>'value', 'type'=>'value'[, options]),
- * where options can be 'default', 'length', or 'key'.
- * @return string
- */
- public function buildColumn($column) {
- $col = $this->columns[$column['type']];
- if (!isset($col['length']) && !isset($col['limit'])) {
- unset($column['length']);
- }
- $out = preg_replace('/integer\([0-9]+\)/', 'integer', parent::buildColumn($column));
- $out = str_replace('integer serial', 'serial', $out);
- if (strpos($out, 'timestamp DEFAULT')) {
- if (isset($column['null']) && $column['null']) {
- $out = str_replace('DEFAULT NULL', '', $out);
- } else {
- $out = str_replace('DEFAULT NOT NULL', '', $out);
- }
- }
- if (strpos($out, 'DEFAULT DEFAULT')) {
- if (isset($column['null']) && $column['null']) {
- $out = str_replace('DEFAULT DEFAULT', 'DEFAULT NULL', $out);
- } elseif (in_array($column['type'], array('integer', 'float'))) {
- $out = str_replace('DEFAULT DEFAULT', 'DEFAULT 0', $out);
- } elseif ($column['type'] == 'boolean') {
- $out = str_replace('DEFAULT DEFAULT', 'DEFAULT FALSE', $out);
- }
- }
- return $out;
- }
-
-/**
- * Format indexes for create table
- *
- * @param array $indexes
- * @param string $table
- * @return string
- */
- public function buildIndex($indexes, $table = null) {
- $join = array();
- if (!is_array($indexes)) {
- return array();
- }
- foreach ($indexes as $name => $value) {
- if ($name == 'PRIMARY') {
- $out = 'PRIMARY KEY (' . $this->name($value['column']) . ')';
- } else {
- $out = 'CREATE ';
- if (!empty($value['unique'])) {
- $out .= 'UNIQUE ';
- }
- if (is_array($value['column'])) {
- $value['column'] = implode(', ', array_map(array(&$this, 'name'), $value['column']));
- } else {
- $value['column'] = $this->name($value['column']);
- }
- $out .= "INDEX {$name} ON {$table}({$value['column']});";
- }
- $join[] = $out;
- }
- return $join;
- }
-
-/**
- * Overrides DboSource::renderStatement to handle schema generation with Postgres-style indexes
- *
- * @param string $type
- * @param array $data
- * @return string
- */
- public function renderStatement($type, $data) {
- switch (strtolower($type)) {
- case 'schema':
- extract($data);
-
- foreach ($indexes as $i => $index) {
- if (preg_match('/PRIMARY KEY/', $index)) {
- unset($indexes[$i]);
- $columns[] = $index;
- break;
- }
- }
- $join = array('columns' => ",\n\t", 'indexes' => "\n");
-
- foreach (array('columns', 'indexes') as $var) {
- if (is_array(${$var})) {
- ${$var} = implode($join[$var], array_filter(${$var}));
- }
- }
- return "CREATE TABLE {$table} (\n\t{$columns}\n);\n{$indexes}";
- break;
- default:
- return parent::renderStatement($type, $data);
- break;
- }
- }
-
-/**
- * Gets the schema name
- *
- * @return string The schema name
- */
- public function getSchemaName() {
- return $this->config['schema'];
- }
-
-}
diff --git a/lib/Cake/Model/Datasource/Database/Sqlite.php b/lib/Cake/Model/Datasource/Database/Sqlite.php
deleted file mode 100644
index 59db71dcf48..00000000000
--- a/lib/Cake/Model/Datasource/Database/Sqlite.php
+++ /dev/null
@@ -1,562 +0,0 @@
- false,
- 'database' => null
- );
-
-/**
- * SQLite3 column definition
- *
- * @var array
- */
- public $columns = array(
- 'primary_key' => array('name' => 'integer primary key autoincrement'),
- 'string' => array('name' => 'varchar', 'limit' => '255'),
- 'text' => array('name' => 'text'),
- 'integer' => array('name' => 'integer', 'limit' => null, 'formatter' => 'intval'),
- 'float' => array('name' => 'float', 'formatter' => 'floatval'),
- 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
- 'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
- 'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
- 'date' => array('name' => 'date', 'format' => 'Y-m-d', 'formatter' => 'date'),
- 'binary' => array('name' => 'blob'),
- 'boolean' => array('name' => 'boolean')
- );
-
-/**
- * List of engine specific additional field parameters used on table creating
- *
- * @var array
- */
- public $fieldParameters = array(
- 'collate' => array(
- 'value' => 'COLLATE',
- 'quote' => false,
- 'join' => ' ',
- 'column' => 'Collate',
- 'position' => 'afterDefault',
- 'options' => array(
- 'BINARY', 'NOCASE', 'RTRIM'
- )
- ),
- );
-
-/**
- * Connects to the database using config['database'] as a filename.
- *
- * @return boolean
- * @throws MissingConnectionException
- */
- public function connect() {
- $config = $this->config;
- $flags = array(
- PDO::ATTR_PERSISTENT => $config['persistent'],
- PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
- );
- try {
- $this->_connection = new PDO('sqlite:' . $config['database'], null, null, $flags);
- $this->connected = true;
- } catch(PDOException $e) {
- throw new MissingConnectionException(array('class' => $e->getMessage()));
- }
- return $this->connected;
- }
-
-/**
- * Check whether the SQLite extension is installed/loaded
- *
- * @return boolean
- */
- public function enabled() {
- return in_array('sqlite', PDO::getAvailableDrivers());
- }
-
-/**
- * Returns an array of tables in the database. If there are no tables, an error is raised and the application exits.
- *
- * @param mixed $data
- * @return array Array of table names in the database
- */
- public function listSources($data = null) {
- $cache = parent::listSources();
- if ($cache != null) {
- return $cache;
- }
-
- $result = $this->fetchAll("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;", false);
-
- if (!$result || empty($result)) {
- return array();
- } else {
- $tables = array();
- foreach ($result as $table) {
- $tables[] = $table[0]['name'];
- }
- parent::listSources($tables);
- return $tables;
- }
- }
-
-/**
- * Returns an array of the fields in given table name.
- *
- * @param Model|string $model Either the model or table name you want described.
- * @return array Fields in table. Keys are name and type
- */
- public function describe($model) {
- $table = $this->fullTableName($model, false, false);
- $cache = parent::describe($table);
- if ($cache != null) {
- return $cache;
- }
- $fields = array();
- $result = $this->_execute(
- 'PRAGMA table_info(' . $this->value($table, 'string') . ')'
- );
-
- foreach ($result as $column) {
- $column = (array)$column;
- $default = ($column['dflt_value'] === 'NULL') ? null : trim($column['dflt_value'], "'");
-
- $fields[$column['name']] = array(
- 'type' => $this->column($column['type']),
- 'null' => !$column['notnull'],
- 'default' => $default,
- 'length' => $this->length($column['type'])
- );
- if ($column['pk'] == 1) {
- $fields[$column['name']]['key'] = $this->index['PRI'];
- $fields[$column['name']]['null'] = false;
- if (empty($fields[$column['name']]['length'])) {
- $fields[$column['name']]['length'] = 11;
- }
- }
- }
-
- $result->closeCursor();
- $this->_cacheDescription($table, $fields);
- return $fields;
- }
-
-/**
- * Generates and executes an SQL UPDATE statement for given model, fields, and values.
- *
- * @param Model $model
- * @param array $fields
- * @param array $values
- * @param mixed $conditions
- * @return array
- */
- public function update(Model $model, $fields = array(), $values = null, $conditions = null) {
- if (empty($values) && !empty($fields)) {
- foreach ($fields as $field => $value) {
- if (strpos($field, $model->alias . '.') !== false) {
- unset($fields[$field]);
- $field = str_replace($model->alias . '.', "", $field);
- $field = str_replace($model->alias . '.', "", $field);
- $fields[$field] = $value;
- }
- }
- }
- return parent::update($model, $fields, $values, $conditions);
- }
-
-/**
- * Deletes all the records in a table and resets the count of the auto-incrementing
- * primary key, where applicable.
- *
- * @param mixed $table A string or model class representing the table to be truncated
- * @return boolean SQL TRUNCATE TABLE statement, false if not applicable.
- */
- public function truncate($table) {
- $this->_execute('DELETE FROM sqlite_sequence where name=' . $this->startQuote . $this->fullTableName($table, false, false) . $this->endQuote);
- return $this->execute('DELETE FROM ' . $this->fullTableName($table));
- }
-
-/**
- * Converts database-layer column types to basic types
- *
- * @param string $real Real database-layer column type (i.e. "varchar(255)")
- * @return string Abstract column type (i.e. "string")
- */
- public function column($real) {
- if (is_array($real)) {
- $col = $real['name'];
- if (isset($real['limit'])) {
- $col .= '(' . $real['limit'] . ')';
- }
- return $col;
- }
-
- $col = strtolower(str_replace(')', '', $real));
- $limit = null;
- @list($col, $limit) = explode('(', $col);
-
- if (in_array($col, array('text', 'integer', 'float', 'boolean', 'timestamp', 'date', 'datetime', 'time'))) {
- return $col;
- }
- if (strpos($col, 'char') !== false) {
- return 'string';
- }
- if (in_array($col, array('blob', 'clob'))) {
- return 'binary';
- }
- if (strpos($col, 'numeric') !== false || strpos($col, 'decimal') !== false) {
- return 'float';
- }
- return 'text';
- }
-
-/**
- * Generate ResultSet
- *
- * @param mixed $results
- * @return void
- */
- public function resultSet($results) {
- $this->results = $results;
- $this->map = array();
- $numFields = $results->columnCount();
- $index = 0;
- $j = 0;
-
- //PDO::getColumnMeta is experimental and does not work with sqlite3,
- // so try to figure it out based on the querystring
- $querystring = $results->queryString;
- if (stripos($querystring, 'SELECT') === 0) {
- $last = strripos($querystring, 'FROM');
- if ($last !== false) {
- $selectpart = substr($querystring, 7, $last - 8);
- $selects = String::tokenize($selectpart, ',', '(', ')');
- }
- } elseif (strpos($querystring, 'PRAGMA table_info') === 0) {
- $selects = array('cid', 'name', 'type', 'notnull', 'dflt_value', 'pk');
- } elseif (strpos($querystring, 'PRAGMA index_list') === 0) {
- $selects = array('seq', 'name', 'unique');
- } elseif (strpos($querystring, 'PRAGMA index_info') === 0) {
- $selects = array('seqno', 'cid', 'name');
- }
- while ($j < $numFields) {
- if (!isset($selects[$j])) {
- $j++;
- continue;
- }
- if (preg_match('/\bAS\s+(.*)/i', $selects[$j], $matches)) {
- $columnName = trim($matches[1], '"');
- } else {
- $columnName = trim(str_replace('"', '', $selects[$j]));
- }
-
- if (strpos($selects[$j], 'DISTINCT') === 0) {
- $columnName = str_ireplace('DISTINCT', '', $columnName);
- }
-
- $metaType = false;
- try {
- $metaData = (array)$results->getColumnMeta($j);
- if (!empty($metaData['sqlite:decl_type'])) {
- $metaType = trim($metaData['sqlite:decl_type']);
- }
- } catch (Exception $e) {
- }
-
- if (strpos($columnName, '.')) {
- $parts = explode('.', $columnName);
- $this->map[$index++] = array(trim($parts[0]), trim($parts[1]), $metaType);
- } else {
- $this->map[$index++] = array(0, $columnName, $metaType);
- }
- $j++;
- }
- }
-
-/**
- * Fetches the next row from the current result set
- *
- * @return mixed array with results fetched and mapped to column names or false if there is no results left to fetch
- */
- public function fetchResult() {
- if ($row = $this->_result->fetch(PDO::FETCH_NUM)) {
- $resultRow = array();
- foreach ($this->map as $col => $meta) {
- list($table, $column, $type) = $meta;
- $resultRow[$table][$column] = $row[$col];
- if ($type == 'boolean' && !is_null($row[$col])) {
- $resultRow[$table][$column] = $this->boolean($resultRow[$table][$column]);
- }
- }
- return $resultRow;
- } else {
- $this->_result->closeCursor();
- return false;
- }
- }
-
-/**
- * Returns a limit statement in the correct format for the particular database.
- *
- * @param integer $limit Limit of results returned
- * @param integer $offset Offset from which to start results
- * @return string SQL limit/offset statement
- */
- public function limit($limit, $offset = null) {
- if ($limit) {
- $rt = '';
- if (!strpos(strtolower($limit), 'limit') || strpos(strtolower($limit), 'limit') === 0) {
- $rt = ' LIMIT';
- }
- $rt .= ' ' . $limit;
- if ($offset) {
- $rt .= ' OFFSET ' . $offset;
- }
- return $rt;
- }
- return null;
- }
-
-/**
- * Generate a database-native column schema string
- *
- * @param array $column An array structured like the following: array('name'=>'value', 'type'=>'value'[, options]),
- * where options can be 'default', 'length', or 'key'.
- * @return string
- */
- public function buildColumn($column) {
- $name = $type = null;
- $column = array_merge(array('null' => true), $column);
- extract($column);
-
- if (empty($name) || empty($type)) {
- trigger_error(__d('cake_dev', 'Column name or type not defined in schema'), E_USER_WARNING);
- return null;
- }
-
- if (!isset($this->columns[$type])) {
- trigger_error(__d('cake_dev', 'Column type %s does not exist', $type), E_USER_WARNING);
- return null;
- }
-
- if (isset($column['key']) && $column['key'] == 'primary' && $type == 'integer') {
- return $this->name($name) . ' ' . $this->columns['primary_key']['name'];
- }
- return parent::buildColumn($column);
- }
-
-/**
- * Sets the database encoding
- *
- * @param string $enc Database encoding
- * @return boolean
- */
- public function setEncoding($enc) {
- if (!in_array($enc, array("UTF-8", "UTF-16", "UTF-16le", "UTF-16be"))) {
- return false;
- }
- return $this->_execute("PRAGMA encoding = \"{$enc}\"") !== false;
- }
-
-/**
- * Gets the database encoding
- *
- * @return string The database encoding
- */
- public function getEncoding() {
- return $this->fetchRow('PRAGMA encoding');
- }
-
-/**
- * Removes redundant primary key indexes, as they are handled in the column def of the key.
- *
- * @param array $indexes
- * @param string $table
- * @return string
- */
- public function buildIndex($indexes, $table = null) {
- $join = array();
-
- $table = str_replace('"', '', $table);
- list($dbname, $table) = explode('.', $table);
- $dbname = $this->name($dbname);
-
- foreach ($indexes as $name => $value) {
-
- if ($name == 'PRIMARY') {
- continue;
- }
- $out = 'CREATE ';
-
- if (!empty($value['unique'])) {
- $out .= 'UNIQUE ';
- }
- if (is_array($value['column'])) {
- $value['column'] = join(', ', array_map(array(&$this, 'name'), $value['column']));
- } else {
- $value['column'] = $this->name($value['column']);
- }
- $t = trim($table, '"');
- $indexname = $this->name($t . '_' . $name);
- $table = $this->name($table);
- $out .= "INDEX {$dbname}.{$indexname} ON {$table}({$value['column']});";
- $join[] = $out;
- }
- return $join;
- }
-
-/**
- * Overrides DboSource::index to handle SQLite index introspection
- * Returns an array of the indexes in given table name.
- *
- * @param string $model Name of model to inspect
- * @return array Fields in table. Keys are column and unique
- */
- public function index($model) {
- $index = array();
- $table = $this->fullTableName($model, false, false);
- if ($table) {
- $indexes = $this->query('PRAGMA index_list(' . $table . ')');
-
- if (is_bool($indexes)) {
- return array();
- }
- foreach ($indexes as $i => $info) {
- $key = array_pop($info);
- $keyInfo = $this->query('PRAGMA index_info("' . $key['name'] . '")');
- foreach ($keyInfo as $keyCol) {
- if (!isset($index[$key['name']])) {
- $col = array();
- if (preg_match('/autoindex/', $key['name'])) {
- $key['name'] = 'PRIMARY';
- }
- $index[$key['name']]['column'] = $keyCol[0]['name'];
- $index[$key['name']]['unique'] = intval($key['unique'] == 1);
- } else {
- if (!is_array($index[$key['name']]['column'])) {
- $col[] = $index[$key['name']]['column'];
- }
- $col[] = $keyCol[0]['name'];
- $index[$key['name']]['column'] = $col;
- }
- }
- }
- }
- return $index;
- }
-
-/**
- * Overrides DboSource::renderStatement to handle schema generation with SQLite-style indexes
- *
- * @param string $type
- * @param array $data
- * @return string
- */
- public function renderStatement($type, $data) {
- switch (strtolower($type)) {
- case 'schema':
- extract($data);
- if (is_array($columns)) {
- $columns = "\t" . join(",\n\t", array_filter($columns));
- }
- if (is_array($indexes)) {
- $indexes = "\t" . join("\n\t", array_filter($indexes));
- }
- return "CREATE TABLE {$table} (\n{$columns});\n{$indexes}";
- break;
- default:
- return parent::renderStatement($type, $data);
- break;
- }
- }
-
-/**
- * PDO deals in objects, not resources, so overload accordingly.
- *
- * @return boolean
- */
- public function hasResult() {
- return is_object($this->_result);
- }
-
-/**
- * Generate a "drop table" statement for the given Schema object
- *
- * @param CakeSchema $schema An instance of a subclass of CakeSchema
- * @param string $table Optional. If specified only the table name given will be generated.
- * Otherwise, all tables defined in the schema are generated.
- * @return string
- */
- public function dropSchema(CakeSchema $schema, $table = null) {
- $out = '';
- foreach ($schema->tables as $curTable => $columns) {
- if (!$table || $table == $curTable) {
- $out .= 'DROP TABLE IF EXISTS ' . $this->fullTableName($curTable) . ";\n";
- }
- }
- return $out;
- }
-
-/**
- * Gets the schema name
- *
- * @return string The schema name
- */
- public function getSchemaName() {
- return "main"; // Sqlite Datasource does not support multidb
- }
-
-}
diff --git a/lib/Cake/Model/Datasource/Database/Sqlserver.php b/lib/Cake/Model/Datasource/Database/Sqlserver.php
deleted file mode 100644
index a72373fb38d..00000000000
--- a/lib/Cake/Model/Datasource/Database/Sqlserver.php
+++ /dev/null
@@ -1,800 +0,0 @@
- true,
- 'host' => 'localhost\SQLEXPRESS',
- 'login' => '',
- 'password' => '',
- 'database' => 'cake',
- 'schema' => '',
- );
-
-/**
- * MS SQL column definition
- *
- * @var array
- */
- public $columns = array(
- 'primary_key' => array('name' => 'IDENTITY (1, 1) NOT NULL'),
- 'string' => array('name' => 'nvarchar', 'limit' => '255'),
- 'text' => array('name' => 'nvarchar', 'limit' => 'MAX'),
- 'integer' => array('name' => 'int', 'formatter' => 'intval'),
- 'float' => array('name' => 'numeric', 'formatter' => 'floatval'),
- 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
- 'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
- 'time' => array('name' => 'datetime', 'format' => 'H:i:s', 'formatter' => 'date'),
- 'date' => array('name' => 'datetime', 'format' => 'Y-m-d', 'formatter' => 'date'),
- 'binary' => array('name' => 'varbinary'),
- 'boolean' => array('name' => 'bit')
- );
-
-/**
- * Index of basic SQL commands
- *
- * @var array
- */
- protected $_commands = array(
- 'begin' => 'BEGIN TRANSACTION',
- 'commit' => 'COMMIT',
- 'rollback' => 'ROLLBACK'
- );
-
-/**
- * Magic column name used to provide pagination support for SQLServer 2008
- * which lacks proper limit/offset support.
- */
- const ROW_COUNTER = '_cake_page_rownum_';
-
-/**
- * The version of SQLServer being used. If greater than 11
- * Normal limit offset statements will be used
- *
- * @var string
- */
- protected $_version;
-
-/**
- * Connects to the database using options in the given configuration array.
- *
- * @return boolean True if the database could be connected, else false
- * @throws MissingConnectionException
- */
- public function connect() {
- $config = $this->config;
- $this->connected = false;
- try {
- $flags = array(
- PDO::ATTR_PERSISTENT => $config['persistent'],
- PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
- );
- if (!empty($config['encoding'])) {
- $flags[PDO::SQLSRV_ATTR_ENCODING] = $config['encoding'];
- }
- $this->_connection = new PDO(
- "sqlsrv:server={$config['host']};Database={$config['database']}",
- $config['login'],
- $config['password'],
- $flags
- );
- $this->connected = true;
- } catch (PDOException $e) {
- throw new MissingConnectionException(array('class' => $e->getMessage()));
- }
-
- $this->_version = $this->_connection->getAttribute(PDO::ATTR_SERVER_VERSION);
- return $this->connected;
- }
-
-/**
- * Check that PDO SQL Server is installed/loaded
- *
- * @return boolean
- */
- public function enabled() {
- return in_array('sqlsrv', PDO::getAvailableDrivers());
- }
-
-/**
- * Returns an array of sources (tables) in the database.
- *
- * @param mixed $data
- * @return array Array of table names in the database
- */
- public function listSources($data = null) {
- $cache = parent::listSources();
- if ($cache !== null) {
- return $cache;
- }
- $result = $this->_execute("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES");
-
- if (!$result) {
- $result->closeCursor();
- return array();
- } else {
- $tables = array();
-
- while ($line = $result->fetch(PDO::FETCH_NUM)) {
- $tables[] = $line[0];
- }
-
- $result->closeCursor();
- parent::listSources($tables);
- return $tables;
- }
- }
-
-/**
- * Returns an array of the fields in given table name.
- *
- * @param Model|string $model Model object to describe, or a string table name.
- * @return array Fields in table. Keys are name and type
- * @throws CakeException
- */
- public function describe($model) {
- $table = $this->fullTableName($model, false);
- $cache = parent::describe($table);
- if ($cache != null) {
- return $cache;
- }
- $fields = array();
- $table = $this->fullTableName($model, false);
- $cols = $this->_execute(
- "SELECT
- COLUMN_NAME as Field,
- DATA_TYPE as Type,
- COL_LENGTH('" . $table . "', COLUMN_NAME) as Length,
- IS_NULLABLE As [Null],
- COLUMN_DEFAULT as [Default],
- COLUMNPROPERTY(OBJECT_ID('" . $table . "'), COLUMN_NAME, 'IsIdentity') as [Key],
- NUMERIC_SCALE as Size
- FROM INFORMATION_SCHEMA.COLUMNS
- WHERE TABLE_NAME = '" . $table . "'"
- );
- if (!$cols) {
- throw new CakeException(__d('cake_dev', 'Could not describe table for %s', $table));
- }
-
- while ($column = $cols->fetch(PDO::FETCH_OBJ)) {
- $field = $column->Field;
- $fields[$field] = array(
- 'type' => $this->column($column),
- 'null' => ($column->Null === 'YES' ? true : false),
- 'default' => preg_replace("/^[(]{1,2}'?([^')]*)?'?[)]{1,2}$/", "$1", $column->Default),
- 'length' => $this->length($column),
- 'key' => ($column->Key == '1') ? 'primary' : false
- );
-
- if ($fields[$field]['default'] === 'null') {
- $fields[$field]['default'] = null;
- } else {
- $this->value($fields[$field]['default'], $fields[$field]['type']);
- }
-
- if ($fields[$field]['key'] !== false && $fields[$field]['type'] == 'integer') {
- $fields[$field]['length'] = 11;
- } elseif ($fields[$field]['key'] === false) {
- unset($fields[$field]['key']);
- }
- if (in_array($fields[$field]['type'], array('date', 'time', 'datetime', 'timestamp'))) {
- $fields[$field]['length'] = null;
- }
- if ($fields[$field]['type'] == 'float' && !empty($column->Size)) {
- $fields[$field]['length'] = $fields[$field]['length'] . ',' . $column->Size;
- }
- }
- $this->_cacheDescription($table, $fields);
- $cols->closeCursor();
- return $fields;
- }
-
-/**
- * Generates the fields list of an SQL query.
- *
- * @param Model $model
- * @param string $alias Alias table name
- * @param array $fields
- * @param boolean $quote
- * @return array
- */
- public function fields(Model $model, $alias = null, $fields = array(), $quote = true) {
- if (empty($alias)) {
- $alias = $model->alias;
- }
- $fields = parent::fields($model, $alias, $fields, false);
- $count = count($fields);
-
- if ($count >= 1 && strpos($fields[0], 'COUNT(*)') === false) {
- $result = array();
- for ($i = 0; $i < $count; $i++) {
- $prepend = '';
-
- if (strpos($fields[$i], 'DISTINCT') !== false) {
- $prepend = 'DISTINCT ';
- $fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i]));
- }
-
- if (!preg_match('/\s+AS\s+/i', $fields[$i])) {
- if (substr($fields[$i], -1) == '*') {
- if (strpos($fields[$i], '.') !== false && $fields[$i] != $alias . '.*') {
- $build = explode('.', $fields[$i]);
- $AssociatedModel = $model->{$build[0]};
- } else {
- $AssociatedModel = $model;
- }
-
- $_fields = $this->fields($AssociatedModel, $AssociatedModel->alias, array_keys($AssociatedModel->schema()));
- $result = array_merge($result, $_fields);
- continue;
- }
-
- if (strpos($fields[$i], '.') === false) {
- $this->_fieldMappings[$alias . '__' . $fields[$i]] = $alias . '.' . $fields[$i];
- $fieldName = $this->name($alias . '.' . $fields[$i]);
- $fieldAlias = $this->name($alias . '__' . $fields[$i]);
- } else {
- $build = explode('.', $fields[$i]);
- $this->_fieldMappings[$build[0] . '__' . $build[1]] = $fields[$i];
- $fieldName = $this->name($build[0] . '.' . $build[1]);
- $fieldAlias = $this->name(preg_replace("/^\[(.+)\]$/", "$1", $build[0]) . '__' . $build[1]);
- }
- if ($model->getColumnType($fields[$i]) == 'datetime') {
- $fieldName = "CONVERT(VARCHAR(20), {$fieldName}, 20)";
- }
- $fields[$i] = "{$fieldName} AS {$fieldAlias}";
- }
- $result[] = $prepend . $fields[$i];
- }
- return $result;
- } else {
- return $fields;
- }
- }
-
-/**
- * Generates and executes an SQL INSERT statement for given model, fields, and values.
- * Removes Identity (primary key) column from update data before returning to parent, if
- * value is empty.
- *
- * @param Model $model
- * @param array $fields
- * @param array $values
- * @return array
- */
- public function create(Model $model, $fields = null, $values = null) {
- if (!empty($values)) {
- $fields = array_combine($fields, $values);
- }
- $primaryKey = $this->_getPrimaryKey($model);
-
- if (array_key_exists($primaryKey, $fields)) {
- if (empty($fields[$primaryKey])) {
- unset($fields[$primaryKey]);
- } else {
- $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($model) . ' ON');
- }
- }
- $result = parent::create($model, array_keys($fields), array_values($fields));
- if (array_key_exists($primaryKey, $fields) && !empty($fields[$primaryKey])) {
- $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($model) . ' OFF');
- }
- return $result;
- }
-
-/**
- * Generates and executes an SQL UPDATE statement for given model, fields, and values.
- * Removes Identity (primary key) column from update data before returning to parent.
- *
- * @param Model $model
- * @param array $fields
- * @param array $values
- * @param mixed $conditions
- * @return array
- */
- public function update(Model $model, $fields = array(), $values = null, $conditions = null) {
- if (!empty($values)) {
- $fields = array_combine($fields, $values);
- }
- if (isset($fields[$model->primaryKey])) {
- unset($fields[$model->primaryKey]);
- }
- if (empty($fields)) {
- return true;
- }
- return parent::update($model, array_keys($fields), array_values($fields), $conditions);
- }
-
-/**
- * Returns a limit statement in the correct format for the particular database.
- *
- * @param integer $limit Limit of results returned
- * @param integer $offset Offset from which to start results
- * @return string SQL limit/offset statement
- */
- public function limit($limit, $offset = null) {
- if ($limit) {
- $rt = '';
- if (!strpos(strtolower($limit), 'top') || strpos(strtolower($limit), 'top') === 0) {
- $rt = ' TOP';
- }
- $rt .= ' ' . $limit;
- if (is_int($offset) && $offset > 0) {
- $rt = ' OFFSET ' . intval($offset) . ' ROWS FETCH FIRST ' . intval($limit) . ' ROWS ONLY';
- }
- return $rt;
- }
- return null;
- }
-
-/**
- * Converts database-layer column types to basic types
- *
- * @param mixed $real Either the string value of the fields type.
- * or the Result object from Sqlserver::describe()
- * @return string Abstract column type (i.e. "string")
- */
- public function column($real) {
- $limit = null;
- $col = $real;
- if (is_object($real) && isset($real->Field)) {
- $limit = $real->Length;
- $col = $real->Type;
- }
-
- if ($col == 'datetime2') {
- return 'datetime';
- }
- if (in_array($col, array('date', 'time', 'datetime', 'timestamp'))) {
- return $col;
- }
- if ($col == 'bit') {
- return 'boolean';
- }
- if (strpos($col, 'int') !== false) {
- return 'integer';
- }
- if (strpos($col, 'char') !== false && $limit == -1) {
- return 'text';
- }
- if (strpos($col, 'char') !== false) {
- return 'string';
- }
- if (strpos($col, 'text') !== false) {
- return 'text';
- }
- if (strpos($col, 'binary') !== false || $col == 'image') {
- return 'binary';
- }
- if (in_array($col, array('float', 'real', 'decimal', 'numeric'))) {
- return 'float';
- }
- return 'text';
- }
-
-/**
- * Handle SQLServer specific length properties.
- * SQLServer handles text types as nvarchar/varchar with a length of -1.
- *
- * @param mixed $length Either the length as a string, or a Column descriptor object.
- * @return mixed null|integer with length of column.
- */
- public function length($length) {
- if (is_object($length) && isset($length->Length)) {
- if ($length->Length == -1 && strpos($length->Type, 'char') !== false) {
- return null;
- }
- if (in_array($length->Type, array('nchar', 'nvarchar'))) {
- return floor($length->Length / 2);
- }
- return $length->Length;
- }
- return parent::length($length);
- }
-
-/**
- * Builds a map of the columns contained in a result
- *
- * @param PDOStatement $results
- * @return void
- */
- public function resultSet($results) {
- $this->map = array();
- $numFields = $results->columnCount();
- $index = 0;
-
- while ($numFields-- > 0) {
- $column = $results->getColumnMeta($index);
- $name = $column['name'];
-
- if (strpos($name, '__')) {
- if (isset($this->_fieldMappings[$name]) && strpos($this->_fieldMappings[$name], '.')) {
- $map = explode('.', $this->_fieldMappings[$name]);
- } elseif (isset($this->_fieldMappings[$name])) {
- $map = array(0, $this->_fieldMappings[$name]);
- } else {
- $map = array(0, $name);
- }
- } else {
- $map = array(0, $name);
- }
- $map[] = ($column['sqlsrv:decl_type'] == 'bit') ? 'boolean' : $column['native_type'];
- $this->map[$index++] = $map;
- }
- }
-
-/**
- * Builds final SQL statement
- *
- * @param string $type Query type
- * @param array $data Query data
- * @return string
- */
- public function renderStatement($type, $data) {
- switch (strtolower($type)) {
- case 'select':
- extract($data);
- $fields = trim($fields);
-
- if (strpos($limit, 'TOP') !== false && strpos($fields, 'DISTINCT ') === 0) {
- $limit = 'DISTINCT ' . trim($limit);
- $fields = substr($fields, 9);
- }
-
- // hack order as SQLServer requires an order if there is a limit.
- if ($limit && !$order) {
- $order = 'ORDER BY (SELECT NULL)';
- }
-
- // For older versions use the subquery version of pagination.
- if (version_compare($this->_version, '11', '<') && preg_match('/FETCH\sFIRST\s+([0-9]+)/i', $limit, $offset)) {
- preg_match('/OFFSET\s*(\d+)\s*.*?(\d+)\s*ROWS/', $limit, $limitOffset);
-
- $limit = 'TOP ' . intval($limitOffset[2]);
- $page = intval($limitOffset[1] / $limitOffset[2]);
- $offset = intval($limitOffset[2] * $page);
-
- $rowCounter = self::ROW_COUNTER;
- return "
- SELECT {$limit} * FROM (
- SELECT {$fields}, ROW_NUMBER() OVER ({$order}) AS {$rowCounter}
- FROM {$table} {$alias} {$joins} {$conditions} {$group}
- ) AS _cake_paging_
- WHERE _cake_paging_.{$rowCounter} > {$offset}
- ORDER BY _cake_paging_.{$rowCounter}
- ";
- } elseif (strpos($limit, 'FETCH') !== false) {
- return "SELECT {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order} {$limit}";
- } else {
- return "SELECT {$limit} {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order}";
- }
- break;
- case "schema":
- extract($data);
-
- foreach ($indexes as $i => $index) {
- if (preg_match('/PRIMARY KEY/', $index)) {
- unset($indexes[$i]);
- break;
- }
- }
-
- foreach (array('columns', 'indexes') as $var) {
- if (is_array(${$var})) {
- ${$var} = "\t" . implode(",\n\t", array_filter(${$var}));
- }
- }
- return "CREATE TABLE {$table} (\n{$columns});\n{$indexes}";
- break;
- default:
- return parent::renderStatement($type, $data);
- break;
- }
- }
-
-/**
- * Returns a quoted and escaped string of $data for use in an SQL statement.
- *
- * @param string $data String to be prepared for use in an SQL statement
- * @param string $column The column into which this data will be inserted
- * @return string Quoted and escaped data
- */
- public function value($data, $column = null) {
- if (is_array($data) || is_object($data)) {
- return parent::value($data, $column);
- } elseif (in_array($data, array('{$__cakeID__$}', '{$__cakeForeignKey__$}'), true)) {
- return $data;
- }
-
- if (empty($column)) {
- $column = $this->introspectType($data);
- }
-
- switch ($column) {
- case 'string':
- case 'text':
- return 'N' . $this->_connection->quote($data, PDO::PARAM_STR);
- default:
- return parent::value($data, $column);
- }
- }
-
-/**
- * Returns an array of all result rows for a given SQL query.
- * Returns false if no rows matched.
- *
- * @param Model $model
- * @param array $queryData
- * @param integer $recursive
- * @return array Array of resultset rows, or false if no rows matched
- */
- public function read(Model $model, $queryData = array(), $recursive = null) {
- $results = parent::read($model, $queryData, $recursive);
- $this->_fieldMappings = array();
- return $results;
- }
-
-/**
- * Fetches the next row from the current result set.
- * Eats the magic ROW_COUNTER variable.
- *
- * @return mixed
- */
- public function fetchResult() {
- if ($row = $this->_result->fetch(PDO::FETCH_NUM)) {
- $resultRow = array();
- foreach ($this->map as $col => $meta) {
- list($table, $column, $type) = $meta;
- if ($table === 0 && $column === self::ROW_COUNTER) {
- continue;
- }
- $resultRow[$table][$column] = $row[$col];
- if ($type === 'boolean' && !is_null($row[$col])) {
- $resultRow[$table][$column] = $this->boolean($resultRow[$table][$column]);
- }
- }
- return $resultRow;
- }
- $this->_result->closeCursor();
- return false;
- }
-
-/**
- * Inserts multiple values into a table
- *
- * @param string $table
- * @param string $fields
- * @param array $values
- * @return void
- */
- public function insertMulti($table, $fields, $values) {
- $primaryKey = $this->_getPrimaryKey($table);
- $hasPrimaryKey = $primaryKey != null && (
- (is_array($fields) && in_array($primaryKey, $fields)
- || (is_string($fields) && strpos($fields, $this->startQuote . $primaryKey . $this->endQuote) !== false))
- );
-
- if ($hasPrimaryKey) {
- $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' ON');
- }
-
- parent::insertMulti($table, $fields, $values);
-
- if ($hasPrimaryKey) {
- $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' OFF');
- }
- }
-
-/**
- * Generate a database-native column schema string
- *
- * @param array $column An array structured like the following: array('name'=>'value', 'type'=>'value'[, options]),
- * where options can be 'default', 'length', or 'key'.
- * @return string
- */
- public function buildColumn($column) {
- $result = preg_replace('/(int|integer)\([0-9]+\)/i', '$1', parent::buildColumn($column));
- if (strpos($result, 'DEFAULT NULL') !== false) {
- if (isset($column['default']) && $column['default'] === '') {
- $result = str_replace('DEFAULT NULL', "DEFAULT ''", $result);
- } else {
- $result = str_replace('DEFAULT NULL', 'NULL', $result);
- }
- } elseif (array_keys($column) == array('type', 'name')) {
- $result .= ' NULL';
- } elseif (strpos($result, "DEFAULT N'")) {
- $result = str_replace("DEFAULT N'", "DEFAULT '", $result);
- }
- return $result;
- }
-
-/**
- * Format indexes for create table
- *
- * @param array $indexes
- * @param string $table
- * @return string
- */
- public function buildIndex($indexes, $table = null) {
- $join = array();
-
- foreach ($indexes as $name => $value) {
- if ($name == 'PRIMARY') {
- $join[] = 'PRIMARY KEY (' . $this->name($value['column']) . ')';
- } elseif (isset($value['unique']) && $value['unique']) {
- $out = "ALTER TABLE {$table} ADD CONSTRAINT {$name} UNIQUE";
-
- if (is_array($value['column'])) {
- $value['column'] = implode(', ', array_map(array(&$this, 'name'), $value['column']));
- } else {
- $value['column'] = $this->name($value['column']);
- }
- $out .= "({$value['column']});";
- $join[] = $out;
- }
- }
- return $join;
- }
-
-/**
- * Makes sure it will return the primary key
- *
- * @param mixed $model Model instance of table name
- * @return string
- */
- protected function _getPrimaryKey($model) {
- $schema = $this->describe($model);
- foreach ($schema as $field => $props) {
- if (isset($props['key']) && $props['key'] == 'primary') {
- return $field;
- }
- }
- return null;
- }
-
-/**
- * Returns number of affected rows in previous database operation. If no previous operation exists,
- * this returns false.
- *
- * @param mixed $source
- * @return integer Number of affected rows
- */
- public function lastAffected($source = null) {
- $affected = parent::lastAffected();
- if ($affected === null && $this->_lastAffected !== false) {
- return $this->_lastAffected;
- }
- return $affected;
- }
-
-/**
- * Executes given SQL statement.
- *
- * @param string $sql SQL statement
- * @param array $params list of params to be bound to query (supported only in select)
- * @param array $prepareOptions Options to be used in the prepare statement
- * @return mixed PDOStatement if query executes with no problem, true as the result of a successful, false on error
- * query returning no rows, such as a CREATE statement, false otherwise
- * @throws PDOException
- */
- protected function _execute($sql, $params = array(), $prepareOptions = array()) {
- $this->_lastAffected = false;
- if (strncasecmp($sql, 'SELECT', 6) == 0 || preg_match('/^EXEC(?:UTE)?\s/mi', $sql) > 0) {
- $prepareOptions += array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL);
- return parent::_execute($sql, $params, $prepareOptions);
- }
- try {
- $this->_lastAffected = $this->_connection->exec($sql);
- if ($this->_lastAffected === false) {
- $this->_results = null;
- $error = $this->_connection->errorInfo();
- $this->error = $error[2];
- return false;
- }
- return true;
- } catch (PDOException $e) {
- if (isset($query->queryString)) {
- $e->queryString = $query->queryString;
- } else {
- $e->queryString = $sql;
- }
- throw $e;
- }
- }
-
-/**
- * Generate a "drop table" statement for the given Schema object
- *
- * @param CakeSchema $schema An instance of a subclass of CakeSchema
- * @param string $table Optional. If specified only the table name given will be generated.
- * Otherwise, all tables defined in the schema are generated.
- * @return string
- */
- public function dropSchema(CakeSchema $schema, $table = null) {
- $out = '';
- foreach ($schema->tables as $curTable => $columns) {
- if (!$table || $table == $curTable) {
- $out .= "IF OBJECT_ID('" . $this->fullTableName($curTable, false) . "', 'U') IS NOT NULL DROP TABLE " . $this->fullTableName($curTable) . ";\n";
- }
- }
- return $out;
- }
-
-/**
- * Gets the schema name
- *
- * @return string The schema name
- */
- public function getSchemaName() {
- return $this->config['schema'];
- }
-
-}
diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php
deleted file mode 100644
index d6eef163266..00000000000
--- a/lib/Cake/Model/Datasource/DboSource.php
+++ /dev/null
@@ -1,3155 +0,0 @@
- 'primary', 'MUL' => 'index', 'UNI' => 'unique');
-
-/**
- * Database keyword used to assign aliases to identifiers.
- *
- * @var string
- */
- public $alias = 'AS ';
-
-/**
- * Caches result from query parsing operations. Cached results for both DboSource::name() and
- * DboSource::conditions() will be stored here. Method caching uses `crc32()` which is
- * fast but can collisions more easily than other hashing algorithms. If you have problems
- * with collisions, set DboSource::$cacheMethods to false.
- *
- * @var array
- */
- public static $methodCache = array();
-
-/**
- * Whether or not to cache the results of DboSource::name() and DboSource::conditions()
- * into the memory cache. Set to false to disable the use of the memory cache.
- *
- * @var boolean.
- */
- public $cacheMethods = true;
-
-/**
- * Print full query debug info?
- *
- * @var boolean
- */
- public $fullDebug = false;
-
-/**
- * String to hold how many rows were affected by the last SQL operation.
- *
- * @var string
- */
- public $affected = null;
-
-/**
- * Number of rows in current resultset
- *
- * @var integer
- */
- public $numRows = null;
-
-/**
- * Time the last query took
- *
- * @var integer
- */
- public $took = null;
-
-/**
- * Result
- *
- * @var array
- */
- protected $_result = null;
-
-/**
- * Queries count.
- *
- * @var integer
- */
- protected $_queriesCnt = 0;
-
-/**
- * Total duration of all queries.
- *
- * @var integer
- */
- protected $_queriesTime = null;
-
-/**
- * Log of queries executed by this DataSource
- *
- * @var array
- */
- protected $_queriesLog = array();
-
-/**
- * Maximum number of items in query log
- *
- * This is to prevent query log taking over too much memory.
- *
- * @var integer Maximum number of queries in the queries log.
- */
- protected $_queriesLogMax = 200;
-
-/**
- * Caches serialized results of executed queries
- *
- * @var array Maximum number of queries in the queries log.
- */
- protected $_queryCache = array();
-
-/**
- * A reference to the physical connection of this DataSource
- *
- * @var array
- */
- protected $_connection = null;
-
-/**
- * The DataSource configuration key name
- *
- * @var string
- */
- public $configKeyName = null;
-
-/**
- * The starting character that this DataSource uses for quoted identifiers.
- *
- * @var string
- */
- public $startQuote = null;
-
-/**
- * The ending character that this DataSource uses for quoted identifiers.
- *
- * @var string
- */
- public $endQuote = null;
-
-/**
- * The set of valid SQL operations usable in a WHERE statement
- *
- * @var array
- */
- protected $_sqlOps = array('like', 'ilike', 'or', 'not', 'in', 'between', 'regexp', 'similar to');
-
-/**
- * Indicates the level of nested transactions
- *
- * @var integer
- */
- protected $_transactionNesting = 0;
-
-/**
- * Index of basic SQL commands
- *
- * @var array
- */
- protected $_commands = array(
- 'begin' => 'BEGIN',
- 'commit' => 'COMMIT',
- 'rollback' => 'ROLLBACK'
- );
-
-/**
- * Separator string for virtualField composition
- *
- * @var string
- */
- public $virtualFieldSeparator = '__';
-
-/**
- * List of table engine specific parameters used on table creating
- *
- * @var array
- */
- public $tableParameters = array();
-
-/**
- * List of engine specific additional field parameters used on table creating
- *
- * @var array
- */
- public $fieldParameters = array();
-
-/**
- * Indicates whether there was a change on the cached results on the methods of this class
- * This will be used for storing in a more persistent cache
- *
- * @var boolean
- */
- protected $_methodCacheChange = false;
-
-/**
- * Constructor
- *
- * @param array $config Array of configuration information for the Datasource.
- * @param boolean $autoConnect Whether or not the datasource should automatically connect.
- * @throws MissingConnectionException when a connection cannot be made.
- */
- public function __construct($config = null, $autoConnect = true) {
- if (!isset($config['prefix'])) {
- $config['prefix'] = '';
- }
- parent::__construct($config);
- $this->fullDebug = Configure::read('debug') > 1;
- if (!$this->enabled()) {
- throw new MissingConnectionException(array(
- 'class' => get_class($this)
- ));
- }
- if ($autoConnect) {
- $this->connect();
- }
- }
-
-/**
- * Reconnects to database server with optional new settings
- *
- * @param array $config An array defining the new configuration settings
- * @return boolean True on success, false on failure
- */
- public function reconnect($config = array()) {
- $this->disconnect();
- $this->setConfig($config);
- $this->_sources = null;
-
- return $this->connect();
- }
-
-/**
- * Disconnects from database.
- *
- * @return boolean True if the database could be disconnected, else false
- */
- public function disconnect() {
- if ($this->_result instanceof PDOStatement) {
- $this->_result->closeCursor();
- }
- unset($this->_connection);
- $this->connected = false;
- return true;
- }
-
-/**
- * Get the underlying connection object.
- *
- * @return PDOConnection
- */
- public function getConnection() {
- return $this->_connection;
- }
-
-/**
- * Returns a quoted and escaped string of $data for use in an SQL statement.
- *
- * @param string $data String to be prepared for use in an SQL statement
- * @param string $column The column into which this data will be inserted
- * @return string Quoted and escaped data
- */
- public function value($data, $column = null) {
- if (is_array($data) && !empty($data)) {
- return array_map(
- array(&$this, 'value'),
- $data, array_fill(0, count($data), $column)
- );
- } elseif (is_object($data) && isset($data->type, $data->value)) {
- if ($data->type == 'identifier') {
- return $this->name($data->value);
- } elseif ($data->type == 'expression') {
- return $data->value;
- }
- } elseif (in_array($data, array('{$__cakeID__$}', '{$__cakeForeignKey__$}'), true)) {
- return $data;
- }
-
- if ($data === null || (is_array($data) && empty($data))) {
- return 'NULL';
- }
-
- if (empty($column)) {
- $column = $this->introspectType($data);
- }
-
- switch ($column) {
- case 'binary':
- return $this->_connection->quote($data, PDO::PARAM_LOB);
- break;
- case 'boolean':
- return $this->_connection->quote($this->boolean($data, true), PDO::PARAM_BOOL);
- break;
- case 'string':
- case 'text':
- return $this->_connection->quote($data, PDO::PARAM_STR);
- default:
- if ($data === '') {
- return 'NULL';
- }
- if (is_float($data)) {
- return str_replace(',', '.', strval($data));
- }
- if ((is_int($data) || $data === '0') || (
- is_numeric($data) && strpos($data, ',') === false &&
- $data[0] != '0' && strpos($data, 'e') === false)
- ) {
- return $data;
- }
- return $this->_connection->quote($data);
- break;
- }
- }
-
-/**
- * Returns an object to represent a database identifier in a query. Expression objects
- * are not sanitized or escaped.
- *
- * @param string $identifier A SQL expression to be used as an identifier
- * @return stdClass An object representing a database identifier to be used in a query
- */
- public function identifier($identifier) {
- $obj = new stdClass();
- $obj->type = 'identifier';
- $obj->value = $identifier;
- return $obj;
- }
-
-/**
- * Returns an object to represent a database expression in a query. Expression objects
- * are not sanitized or escaped.
- *
- * @param string $expression An arbitrary SQL expression to be inserted into a query.
- * @return stdClass An object representing a database expression to be used in a query
- */
- public function expression($expression) {
- $obj = new stdClass();
- $obj->type = 'expression';
- $obj->value = $expression;
- return $obj;
- }
-
-/**
- * Executes given SQL statement.
- *
- * @param string $sql SQL statement
- * @param array $params Additional options for the query.
- * @return boolean
- */
- public function rawQuery($sql, $params = array()) {
- $this->took = $this->numRows = false;
- return $this->execute($sql, $params);
- }
-
-/**
- * Queries the database with given SQL statement, and obtains some metadata about the result
- * (rows affected, timing, any errors, number of rows in resultset). The query is also logged.
- * If Configure::read('debug') is set, the log is shown all the time, else it is only shown on errors.
- *
- * ### Options
- *
- * - log - Whether or not the query should be logged to the memory log.
- *
- * @param string $sql SQL statement
- * @param array $options
- * @param array $params values to be bound to the query
- * @return mixed Resource or object representing the result set, or false on failure
- */
- public function execute($sql, $options = array(), $params = array()) {
- $options += array('log' => $this->fullDebug);
-
- $t = microtime(true);
- $this->_result = $this->_execute($sql, $params);
-
- if ($options['log']) {
- $this->took = round((microtime(true) - $t) * 1000, 0);
- $this->numRows = $this->affected = $this->lastAffected();
- $this->logQuery($sql, $params);
- }
-
- return $this->_result;
- }
-
-/**
- * Executes given SQL statement.
- *
- * @param string $sql SQL statement
- * @param array $params list of params to be bound to query
- * @param array $prepareOptions Options to be used in the prepare statement
- * @return mixed PDOStatement if query executes with no problem, true as the result of a successful, false on error
- * query returning no rows, such as a CREATE statement, false otherwise
- * @throws PDOException
- */
- protected function _execute($sql, $params = array(), $prepareOptions = array()) {
- $sql = trim($sql);
- if (preg_match('/^(?:CREATE|ALTER|DROP)/i', $sql)) {
- $statements = array_filter(explode(';', $sql));
- if (count($statements) > 1) {
- $result = array_map(array($this, '_execute'), $statements);
- return array_search(false, $result) === false;
- }
- }
-
- try {
- $query = $this->_connection->prepare($sql, $prepareOptions);
- $query->setFetchMode(PDO::FETCH_LAZY);
- if (!$query->execute($params)) {
- $this->_results = $query;
- $query->closeCursor();
- return false;
- }
- if (!$query->columnCount()) {
- $query->closeCursor();
- if (!$query->rowCount()) {
- return true;
- }
- }
- return $query;
- } catch (PDOException $e) {
- if (isset($query->queryString)) {
- $e->queryString = $query->queryString;
- } else {
- $e->queryString = $sql;
- }
- throw $e;
- }
- }
-
-/**
- * Returns a formatted error message from previous database operation.
- *
- * @param PDOStatement $query the query to extract the error from if any
- * @return string Error message with error number
- */
- public function lastError(PDOStatement $query = null) {
- if ($query) {
- $error = $query->errorInfo();
- } else {
- $error = $this->_connection->errorInfo();
- }
- if (empty($error[2])) {
- return null;
- }
- return $error[1] . ': ' . $error[2];
- }
-
-/**
- * Returns number of affected rows in previous database operation. If no previous operation exists,
- * this returns false.
- *
- * @param mixed $source
- * @return integer Number of affected rows
- */
- public function lastAffected($source = null) {
- if ($this->hasResult()) {
- return $this->_result->rowCount();
- }
- return 0;
- }
-
-/**
- * Returns number of rows in previous resultset. If no previous resultset exists,
- * this returns false.
- *
- * @param mixed $source Not used
- * @return integer Number of rows in resultset
- */
- public function lastNumRows($source = null) {
- return $this->lastAffected();
- }
-
-/**
- * DataSource Query abstraction
- *
- * @return resource Result resource identifier.
- */
- public function query() {
- $args = func_get_args();
- $fields = null;
- $order = null;
- $limit = null;
- $page = null;
- $recursive = null;
-
- if (count($args) === 1) {
- return $this->fetchAll($args[0]);
- } elseif (count($args) > 1 && (strpos($args[0], 'findBy') === 0 || strpos($args[0], 'findAllBy') === 0)) {
- $params = $args[1];
-
- if (substr($args[0], 0, 6) === 'findBy') {
- $all = false;
- $field = Inflector::underscore(substr($args[0], 6));
- } else {
- $all = true;
- $field = Inflector::underscore(substr($args[0], 9));
- }
-
- $or = (strpos($field, '_or_') !== false);
- if ($or) {
- $field = explode('_or_', $field);
- } else {
- $field = explode('_and_', $field);
- }
- $off = count($field) - 1;
-
- if (isset($params[1 + $off])) {
- $fields = $params[1 + $off];
- }
-
- if (isset($params[2 + $off])) {
- $order = $params[2 + $off];
- }
-
- if (!array_key_exists(0, $params)) {
- return false;
- }
-
- $c = 0;
- $conditions = array();
-
- foreach ($field as $f) {
- $conditions[$args[2]->alias . '.' . $f] = $params[$c++];
- }
-
- if ($or) {
- $conditions = array('OR' => $conditions);
- }
-
- if ($all) {
- if (isset($params[3 + $off])) {
- $limit = $params[3 + $off];
- }
-
- if (isset($params[4 + $off])) {
- $page = $params[4 + $off];
- }
-
- if (isset($params[5 + $off])) {
- $recursive = $params[5 + $off];
- }
- return $args[2]->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive'));
- } else {
- if (isset($params[3 + $off])) {
- $recursive = $params[3 + $off];
- }
- return $args[2]->find('first', compact('conditions', 'fields', 'order', 'recursive'));
- }
- } else {
- if (isset($args[1]) && $args[1] === true) {
- return $this->fetchAll($args[0], true);
- } elseif (isset($args[1]) && !is_array($args[1]) ) {
- return $this->fetchAll($args[0], false);
- } elseif (isset($args[1]) && is_array($args[1])) {
- if (isset($args[2])) {
- $cache = $args[2];
- } else {
- $cache = true;
- }
- return $this->fetchAll($args[0], $args[1], array('cache' => $cache));
- }
- }
- }
-
-/**
- * Returns a row from current resultset as an array
- *
- * @param string $sql Some SQL to be executed.
- * @return array The fetched row as an array
- */
- public function fetchRow($sql = null) {
- if (is_string($sql) && strlen($sql) > 5 && !$this->execute($sql)) {
- return null;
- }
-
- if ($this->hasResult()) {
- $this->resultSet($this->_result);
- $resultRow = $this->fetchResult();
- if (isset($resultRow[0])) {
- $this->fetchVirtualField($resultRow);
- }
- return $resultRow;
- } else {
- return null;
- }
- }
-
-/**
- * Returns an array of all result rows for a given SQL query.
- * Returns false if no rows matched.
- *
- *
- * ### Options
- *
- * - `cache` - Returns the cached version of the query, if exists and stores the result in cache.
- * This is a non-persistent cache, and only lasts for a single request. This option
- * defaults to true. If you are directly calling this method, you can disable caching
- * by setting $options to `false`
- *
- * @param string $sql SQL statement
- * @param array $params parameters to be bound as values for the SQL statement
- * @param array $options additional options for the query.
- * @return array Array of resultset rows, or false if no rows matched
- */
- public function fetchAll($sql, $params = array(), $options = array()) {
- if (is_string($options)) {
- $options = array('modelName' => $options);
- }
- if (is_bool($params)) {
- $options['cache'] = $params;
- $params = array();
- }
- $options += array('cache' => true);
- $cache = $options['cache'];
- if ($cache && ($cached = $this->getQueryCache($sql, $params)) !== false) {
- return $cached;
- }
- if ($result = $this->execute($sql, array(), $params)) {
- $out = array();
-
- if ($this->hasResult()) {
- $first = $this->fetchRow();
- if ($first != null) {
- $out[] = $first;
- }
- while ($item = $this->fetchResult()) {
- if (isset($item[0])) {
- $this->fetchVirtualField($item);
- }
- $out[] = $item;
- }
- }
-
- if (!is_bool($result) && $cache) {
- $this->_writeQueryCache($sql, $out, $params);
- }
-
- if (empty($out) && is_bool($this->_result)) {
- return $this->_result;
- }
- return $out;
- }
- return false;
- }
-
-/**
- * Fetches the next row from the current result set
- *
- * @return boolean
- */
- public function fetchResult() {
- return false;
- }
-
-/**
- * Modifies $result array to place virtual fields in model entry where they belongs to
- *
- * @param array $result Reference to the fetched row
- * @return void
- */
- public function fetchVirtualField(&$result) {
- if (isset($result[0]) && is_array($result[0])) {
- foreach ($result[0] as $field => $value) {
- if (strpos($field, $this->virtualFieldSeparator) === false) {
- continue;
- }
- list($alias, $virtual) = explode($this->virtualFieldSeparator, $field);
-
- if (!ClassRegistry::isKeySet($alias)) {
- return;
- }
- $model = ClassRegistry::getObject($alias);
- if ($model->isVirtualField($virtual)) {
- $result[$alias][$virtual] = $value;
- unset($result[0][$field]);
- }
- }
- if (empty($result[0])) {
- unset($result[0]);
- }
- }
- }
-
-/**
- * Returns a single field of the first of query results for a given SQL query, or false if empty.
- *
- * @param string $name Name of the field
- * @param string $sql SQL query
- * @return mixed Value of field read.
- */
- public function field($name, $sql) {
- $data = $this->fetchRow($sql);
- if (empty($data[$name])) {
- return false;
- }
- return $data[$name];
- }
-
-/**
- * Empties the method caches.
- * These caches are used by DboSource::name() and DboSource::conditions()
- *
- * @return void
- */
- public function flushMethodCache() {
- $this->_methodCacheChange = true;
- self::$methodCache = array();
- }
-
-/**
- * Cache a value into the methodCaches. Will respect the value of DboSource::$cacheMethods.
- * Will retrieve a value from the cache if $value is null.
- *
- * If caching is disabled and a write is attempted, the $value will be returned.
- * A read will either return the value or null.
- *
- * @param string $method Name of the method being cached.
- * @param string $key The key name for the cache operation.
- * @param mixed $value The value to cache into memory.
- * @return mixed Either null on failure, or the value if its set.
- */
- public function cacheMethod($method, $key, $value = null) {
- if ($this->cacheMethods === false) {
- return $value;
- }
- if (empty(self::$methodCache)) {
- self::$methodCache = Cache::read('method_cache', '_cake_core_');
- }
- if ($value === null) {
- return (isset(self::$methodCache[$method][$key])) ? self::$methodCache[$method][$key] : null;
- }
- $this->_methodCacheChange = true;
- return self::$methodCache[$method][$key] = $value;
- }
-
-/**
- * Returns a quoted name of $data for use in an SQL statement.
- * Strips fields out of SQL functions before quoting.
- *
- * Results of this method are stored in a memory cache. This improves performance, but
- * because the method uses a simple hashing algorithm it can infrequently have collisions.
- * Setting DboSource::$cacheMethods to false will disable the memory cache.
- *
- * @param mixed $data Either a string with a column to quote. An array of columns to quote or an
- * object from DboSource::expression() or DboSource::identifier()
- * @return string SQL field
- */
- public function name($data) {
- if (is_object($data) && isset($data->type)) {
- return $data->value;
- }
- if ($data === '*') {
- return '*';
- }
- if (is_array($data)) {
- foreach ($data as $i => $dataItem) {
- $data[$i] = $this->name($dataItem);
- }
- return $data;
- }
- $cacheKey = crc32($this->startQuote . $data . $this->endQuote);
- if ($return = $this->cacheMethod(__FUNCTION__, $cacheKey)) {
- return $return;
- }
- $data = trim($data);
- if (preg_match('/^[\w-]+(?:\.[^ \*]*)*$/', $data)) { // string, string.string
- if (strpos($data, '.') === false) { // string
- return $this->cacheMethod(__FUNCTION__, $cacheKey, $this->startQuote . $data . $this->endQuote);
- }
- $items = explode('.', $data);
- return $this->cacheMethod(__FUNCTION__, $cacheKey,
- $this->startQuote . implode($this->endQuote . '.' . $this->startQuote, $items) . $this->endQuote
- );
- }
- if (preg_match('/^[\w-]+\.\*$/', $data)) { // string.*
- return $this->cacheMethod(__FUNCTION__, $cacheKey,
- $this->startQuote . str_replace('.*', $this->endQuote . '.*', $data)
- );
- }
- if (preg_match('/^([\w-]+)\((.*)\)$/', $data, $matches)) { // Functions
- return $this->cacheMethod(__FUNCTION__, $cacheKey,
- $matches[1] . '(' . $this->name($matches[2]) . ')'
- );
- }
- if (
- preg_match('/^([\w-]+(\.[\w-]+|\(.*\))*)\s+' . preg_quote($this->alias) . '\s*([\w-]+)$/i', $data, $matches
- )) {
- return $this->cacheMethod(
- __FUNCTION__, $cacheKey,
- preg_replace(
- '/\s{2,}/', ' ', $this->name($matches[1]) . ' ' . $this->alias . ' ' . $this->name($matches[3])
- )
- );
- }
- if (preg_match('/^[\w-_\s]*[\w-_]+/', $data)) {
- return $this->cacheMethod(__FUNCTION__, $cacheKey, $this->startQuote . $data . $this->endQuote);
- }
- return $this->cacheMethod(__FUNCTION__, $cacheKey, $data);
- }
-
-/**
- * Checks if the source is connected to the database.
- *
- * @return boolean True if the database is connected, else false
- */
- public function isConnected() {
- return $this->connected;
- }
-
-/**
- * Checks if the result is valid
- *
- * @return boolean True if the result is valid else false
- */
- public function hasResult() {
- return is_a($this->_result, 'PDOStatement');
- }
-
-/**
- * Get the query log as an array.
- *
- * @param boolean $sorted Get the queries sorted by time taken, defaults to false.
- * @param boolean $clear If True the existing log will cleared.
- * @return array Array of queries run as an array
- */
- public function getLog($sorted = false, $clear = true) {
- if ($sorted) {
- $log = sortByKey($this->_queriesLog, 'took', 'desc', SORT_NUMERIC);
- } else {
- $log = $this->_queriesLog;
- }
- if ($clear) {
- $this->_queriesLog = array();
- }
- return array('log' => $log, 'count' => $this->_queriesCnt, 'time' => $this->_queriesTime);
- }
-
-/**
- * Outputs the contents of the queries log. If in a non-CLI environment the sql_log element
- * will be rendered and output. If in a CLI environment, a plain text log is generated.
- *
- * @param boolean $sorted Get the queries sorted by time taken, defaults to false.
- * @return void
- */
- public function showLog($sorted = false) {
- $log = $this->getLog($sorted, false);
- if (empty($log['log'])) {
- return;
- }
- if (PHP_SAPI != 'cli') {
- $controller = null;
- $View = new View($controller, false);
- $View->set('logs', array($this->configKeyName => $log));
- echo $View->element('sql_dump', array('_forced_from_dbo_' => true));
- } else {
- foreach ($log['log'] as $k => $i) {
- print (($k + 1) . ". {$i['query']}\n");
- }
- }
- }
-
-/**
- * Log given SQL query.
- *
- * @param string $sql SQL statement
- * @param array $params Values binded to the query (prepared statements)
- * @return void
- */
- public function logQuery($sql, $params = array()) {
- $this->_queriesCnt++;
- $this->_queriesTime += $this->took;
- $this->_queriesLog[] = array(
- 'query' => $sql,
- 'params' => $params,
- 'affected' => $this->affected,
- 'numRows' => $this->numRows,
- 'took' => $this->took
- );
- if (count($this->_queriesLog) > $this->_queriesLogMax) {
- array_pop($this->_queriesLog);
- }
- }
-
-/**
- * Gets full table name including prefix
- *
- * @param mixed $model Either a Model object or a string table name.
- * @param boolean $quote Whether you want the table name quoted.
- * @param boolean $schema Whether you want the schema name included.
- * @return string Full quoted table name
- */
- public function fullTableName($model, $quote = true, $schema = true) {
- if (is_object($model)) {
- $schemaName = $model->schemaName;
- $table = $model->tablePrefix . $model->table;
- } elseif (!empty($this->config['prefix']) && strpos($model, $this->config['prefix']) === false) {
- $table = $this->config['prefix'] . strval($model);
- } else {
- $table = strval($model);
- }
- if ($schema && !isset($schemaName)) {
- $schemaName = $this->getSchemaName();
- }
-
- if ($quote) {
- if ($schema && !empty($schemaName)) {
- if (false == strstr($table, '.')) {
- return $this->name($schemaName) . '.' . $this->name($table);
- }
- }
- return $this->name($table);
- }
- if ($schema && !empty($schemaName)) {
- if (false == strstr($table, '.')) {
- return $schemaName . '.' . $table;
- }
- }
- return $table;
- }
-
-/**
- * The "C" in CRUD
- *
- * Creates new records in the database.
- *
- * @param Model $model Model object that the record is for.
- * @param array $fields An array of field names to insert. If null, $model->data will be
- * used to generate field names.
- * @param array $values An array of values with keys matching the fields. If null, $model->data will
- * be used to generate values.
- * @return boolean Success
- */
- public function create(Model $model, $fields = null, $values = null) {
- $id = null;
-
- if ($fields == null) {
- unset($fields, $values);
- $fields = array_keys($model->data);
- $values = array_values($model->data);
- }
- $count = count($fields);
-
- for ($i = 0; $i < $count; $i++) {
- $valueInsert[] = $this->value($values[$i], $model->getColumnType($fields[$i]));
- $fieldInsert[] = $this->name($fields[$i]);
- if ($fields[$i] == $model->primaryKey) {
- $id = $values[$i];
- }
- }
- $query = array(
- 'table' => $this->fullTableName($model),
- 'fields' => implode(', ', $fieldInsert),
- 'values' => implode(', ', $valueInsert)
- );
-
- if ($this->execute($this->renderStatement('create', $query))) {
- if (empty($id)) {
- $id = $this->lastInsertId($this->fullTableName($model, false, false), $model->primaryKey);
- }
- $model->setInsertID($id);
- $model->id = $id;
- return true;
- }
- $model->onError();
- return false;
- }
-
-/**
- * The "R" in CRUD
- *
- * Reads record(s) from the database.
- *
- * @param Model $model A Model object that the query is for.
- * @param array $queryData An array of queryData information containing keys similar to Model::find()
- * @param integer $recursive Number of levels of association
- * @return mixed boolean false on error/failure. An array of results on success.
- */
- public function read(Model $model, $queryData = array(), $recursive = null) {
- $queryData = $this->_scrubQueryData($queryData);
-
- $null = null;
- $array = array('callbacks' => $queryData['callbacks']);
- $linkedModels = array();
- $bypass = false;
-
- if ($recursive === null && isset($queryData['recursive'])) {
- $recursive = $queryData['recursive'];
- }
-
- if (!is_null($recursive)) {
- $_recursive = $model->recursive;
- $model->recursive = $recursive;
- }
-
- if (!empty($queryData['fields'])) {
- $bypass = true;
- $queryData['fields'] = $this->fields($model, null, $queryData['fields']);
- } else {
- $queryData['fields'] = $this->fields($model);
- }
-
- $_associations = $model->associations();
-
- if ($model->recursive == -1) {
- $_associations = array();
- } elseif ($model->recursive == 0) {
- unset($_associations[2], $_associations[3]);
- }
-
- foreach ($_associations as $type) {
- foreach ($model->{$type} as $assoc => $assocData) {
- $linkModel = $model->{$assoc};
- $external = isset($assocData['external']);
-
- $linkModel->getDataSource();
- if ($model->useDbConfig === $linkModel->useDbConfig) {
- if ($bypass) {
- $assocData['fields'] = false;
- }
- if (true === $this->generateAssociationQuery($model, $linkModel, $type, $assoc, $assocData, $queryData, $external, $null)) {
- $linkedModels[$type . '/' . $assoc] = true;
- }
- }
- }
- }
-
- $query = trim($this->generateAssociationQuery($model, null, null, null, null, $queryData, false, $null));
-
- $resultSet = $this->fetchAll($query, $model->cacheQueries);
- if ($resultSet === false) {
- $model->onError();
- return false;
- }
-
- $filtered = array();
-
- if ($queryData['callbacks'] === true || $queryData['callbacks'] === 'after') {
- $filtered = $this->_filterResults($resultSet, $model);
- }
-
- if ($model->recursive > -1) {
- foreach ($_associations as $type) {
- foreach ($model->{$type} as $assoc => $assocData) {
- $linkModel = $model->{$assoc};
-
- if (!isset($linkedModels[$type . '/' . $assoc])) {
- if ($model->useDbConfig === $linkModel->useDbConfig) {
- $db = $this;
- } else {
- $db = ConnectionManager::getDataSource($linkModel->useDbConfig);
- }
- } elseif ($model->recursive > 1 && ($type === 'belongsTo' || $type === 'hasOne')) {
- $db = $this;
- }
-
- if (isset($db) && method_exists($db, 'queryAssociation')) {
- $stack = array($assoc);
- $db->queryAssociation($model, $linkModel, $type, $assoc, $assocData, $array, true, $resultSet, $model->recursive - 1, $stack);
- unset($db);
-
- if ($type === 'hasMany') {
- $filtered[] = $assoc;
- }
- }
- }
- }
- if ($queryData['callbacks'] === true || $queryData['callbacks'] === 'after') {
- $this->_filterResults($resultSet, $model, $filtered);
- }
- }
-
- if (!is_null($recursive)) {
- $model->recursive = $_recursive;
- }
- return $resultSet;
- }
-
-/**
- * Passes association results thru afterFind filters of corresponding model
- *
- * @param array $results Reference of resultset to be filtered
- * @param Model $model Instance of model to operate against
- * @param array $filtered List of classes already filtered, to be skipped
- * @return array Array of results that have been filtered through $model->afterFind
- */
- protected function _filterResults(&$results, Model $model, $filtered = array()) {
- $current = current($results);
- if (!is_array($current)) {
- return array();
- }
- $keys = array_diff(array_keys($current), $filtered, array($model->alias));
- $filtering = array();
- foreach ($keys as $className) {
- if (!isset($model->{$className}) || !is_object($model->{$className})) {
- continue;
- }
- $linkedModel = $model->{$className};
- $filtering[] = $className;
- foreach ($results as &$result) {
- $data = $linkedModel->afterFind(array(array($className => $result[$className])), false);
- if (isset($data[0][$className])) {
- $result[$className] = $data[0][$className];
- }
- }
- }
- return $filtering;
- }
-
-/**
- * Queries associations. Used to fetch results on recursive models.
- *
- * @param Model $model Primary Model object
- * @param Model $linkModel Linked model that
- * @param string $type Association type, one of the model association types ie. hasMany
- * @param string $association
- * @param array $assocData
- * @param array $queryData
- * @param boolean $external Whether or not the association query is on an external datasource.
- * @param array $resultSet Existing results
- * @param integer $recursive Number of levels of association
- * @param array $stack
- * @return mixed
- * @throws CakeException when results cannot be created.
- */
- public function queryAssociation(Model $model, &$linkModel, $type, $association, $assocData, &$queryData, $external = false, &$resultSet, $recursive, $stack) {
- if ($query = $this->generateAssociationQuery($model, $linkModel, $type, $association, $assocData, $queryData, $external, $resultSet)) {
- if (!is_array($resultSet)) {
- throw new CakeException(__d('cake_dev', 'Error in Model %s', get_class($model)));
- }
- if ($type === 'hasMany' && empty($assocData['limit']) && !empty($assocData['foreignKey'])) {
- $ins = $fetch = array();
- foreach ($resultSet as &$result) {
- if ($in = $this->insertQueryData('{$__cakeID__$}', $result, $association, $assocData, $model, $linkModel, $stack)) {
- $ins[] = $in;
- }
- }
-
- if (!empty($ins)) {
- $ins = array_unique($ins);
- $fetch = $this->fetchAssociated($model, $query, $ins);
- }
-
- if (!empty($fetch) && is_array($fetch)) {
- if ($recursive > 0) {
- foreach ($linkModel->associations() as $type1) {
- foreach ($linkModel->{$type1} as $assoc1 => $assocData1) {
- $deepModel = $linkModel->{$assoc1};
- $tmpStack = $stack;
- $tmpStack[] = $assoc1;
-
- if ($linkModel->useDbConfig === $deepModel->useDbConfig) {
- $db = $this;
- } else {
- $db = ConnectionManager::getDataSource($deepModel->useDbConfig);
- }
- $db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack);
- }
- }
- }
- }
- if ($queryData['callbacks'] === true || $queryData['callbacks'] === 'after') {
- $this->_filterResults($fetch, $model);
- }
- return $this->_mergeHasMany($resultSet, $fetch, $association, $model, $linkModel);
- } elseif ($type === 'hasAndBelongsToMany') {
- $ins = $fetch = array();
- foreach ($resultSet as &$result) {
- if ($in = $this->insertQueryData('{$__cakeID__$}', $result, $association, $assocData, $model, $linkModel, $stack)) {
- $ins[] = $in;
- }
- }
- if (!empty($ins)) {
- $ins = array_unique($ins);
- if (count($ins) > 1) {
- $query = str_replace('{$__cakeID__$}', '(' . implode(', ', $ins) . ')', $query);
- $query = str_replace('= (', 'IN (', $query);
- } else {
- $query = str_replace('{$__cakeID__$}', $ins[0], $query);
- }
- $query = str_replace(' WHERE 1 = 1', '', $query);
- }
-
- $foreignKey = $model->hasAndBelongsToMany[$association]['foreignKey'];
- $joinKeys = array($foreignKey, $model->hasAndBelongsToMany[$association]['associationForeignKey']);
- list($with, $habtmFields) = $model->joinModel($model->hasAndBelongsToMany[$association]['with'], $joinKeys);
- $habtmFieldsCount = count($habtmFields);
- $q = $this->insertQueryData($query, null, $association, $assocData, $model, $linkModel, $stack);
-
- if ($q !== false) {
- $fetch = $this->fetchAll($q, $model->cacheQueries);
- } else {
- $fetch = null;
- }
- }
-
- $modelAlias = $model->alias;
- $modelPK = $model->primaryKey;
- foreach ($resultSet as &$row) {
- if ($type !== 'hasAndBelongsToMany') {
- $q = $this->insertQueryData($query, $row, $association, $assocData, $model, $linkModel, $stack);
- if ($q !== false) {
- $fetch = $this->fetchAll($q, $model->cacheQueries);
- } else {
- $fetch = null;
- }
- }
- $selfJoin = $linkModel->name === $model->name;
-
- if (!empty($fetch) && is_array($fetch)) {
- if ($recursive > 0) {
- foreach ($linkModel->associations() as $type1) {
- foreach ($linkModel->{$type1} as $assoc1 => $assocData1) {
- $deepModel = $linkModel->{$assoc1};
-
- if ($type1 === 'belongsTo' || ($deepModel->alias === $modelAlias && $type === 'belongsTo') || ($deepModel->alias !== $modelAlias)) {
- $tmpStack = $stack;
- $tmpStack[] = $assoc1;
- if ($linkModel->useDbConfig == $deepModel->useDbConfig) {
- $db = $this;
- } else {
- $db = ConnectionManager::getDataSource($deepModel->useDbConfig);
- }
- $db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack);
- }
- }
- }
- }
- if ($type === 'hasAndBelongsToMany') {
- $uniqueIds = $merge = array();
-
- foreach ($fetch as $j => $data) {
- if (isset($data[$with]) && $data[$with][$foreignKey] === $row[$modelAlias][$modelPK]) {
- if ($habtmFieldsCount <= 2) {
- unset($data[$with]);
- }
- $merge[] = $data;
- }
- }
- if (empty($merge) && !isset($row[$association])) {
- $row[$association] = $merge;
- } else {
- $this->_mergeAssociation($row, $merge, $association, $type);
- }
- } else {
- $this->_mergeAssociation($row, $fetch, $association, $type, $selfJoin);
- }
- if (isset($row[$association])) {
- $row[$association] = $linkModel->afterFind($row[$association], false);
- }
- } else {
- $tempArray[0][$association] = false;
- $this->_mergeAssociation($row, $tempArray, $association, $type, $selfJoin);
- }
- }
- }
- }
-
-/**
- * A more efficient way to fetch associations. Woohoo!
- *
- * @param Model $model Primary model object
- * @param string $query Association query
- * @param array $ids Array of IDs of associated records
- * @return array Association results
- */
- public function fetchAssociated(Model $model, $query, $ids) {
- $query = str_replace('{$__cakeID__$}', implode(', ', $ids), $query);
- if (count($ids) > 1) {
- $query = str_replace('= (', 'IN (', $query);
- }
- return $this->fetchAll($query, $model->cacheQueries);
- }
-
-/**
- * mergeHasMany - Merge the results of hasMany relations.
- *
- *
- * @param array $resultSet Data to merge into
- * @param array $merge Data to merge
- * @param string $association Name of Model being Merged
- * @param Model $model Model being merged onto
- * @param Model $linkModel Model being merged
- * @return void
- */
- protected function _mergeHasMany(&$resultSet, $merge, $association, $model, $linkModel) {
- $modelAlias = $model->alias;
- $modelPK = $model->primaryKey;
- $modelFK = $model->hasMany[$association]['foreignKey'];
- foreach ($resultSet as &$result) {
- if (!isset($result[$modelAlias])) {
- continue;
- }
- $merged = array();
- foreach ($merge as $data) {
- if ($result[$modelAlias][$modelPK] === $data[$association][$modelFK]) {
- if (count($data) > 1) {
- $data = array_merge($data[$association], $data);
- unset($data[$association]);
- foreach ($data as $key => $name) {
- if (is_numeric($key)) {
- $data[$association][] = $name;
- unset($data[$key]);
- }
- }
- $merged[] = $data;
- } else {
- $merged[] = $data[$association];
- }
- }
- }
- $result = Set::pushDiff($result, array($association => $merged));
- }
- }
-
-/**
- * Merge association of merge into data
- *
- * @param array $data
- * @param array $merge
- * @param string $association
- * @param string $type
- * @param boolean $selfJoin
- * @return void
- */
- protected function _mergeAssociation(&$data, &$merge, $association, $type, $selfJoin = false) {
- if (isset($merge[0]) && !isset($merge[0][$association])) {
- $association = Inflector::pluralize($association);
- }
-
- if ($type === 'belongsTo' || $type === 'hasOne') {
- if (isset($merge[$association])) {
- $data[$association] = $merge[$association][0];
- } else {
- if (count($merge[0][$association]) > 1) {
- foreach ($merge[0] as $assoc => $data2) {
- if ($assoc !== $association) {
- $merge[0][$association][$assoc] = $data2;
- }
- }
- }
- if (!isset($data[$association])) {
- if ($merge[0][$association] != null) {
- $data[$association] = $merge[0][$association];
- } else {
- $data[$association] = array();
- }
- } else {
- if (is_array($merge[0][$association])) {
- foreach ($data[$association] as $k => $v) {
- if (!is_array($v)) {
- $dataAssocTmp[$k] = $v;
- }
- }
-
- foreach ($merge[0][$association] as $k => $v) {
- if (!is_array($v)) {
- $mergeAssocTmp[$k] = $v;
- }
- }
- $dataKeys = array_keys($data);
- $mergeKeys = array_keys($merge[0]);
-
- if ($mergeKeys[0] === $dataKeys[0] || $mergeKeys === $dataKeys) {
- $data[$association][$association] = $merge[0][$association];
- } else {
- $diff = Set::diff($dataAssocTmp, $mergeAssocTmp);
- $data[$association] = array_merge($merge[0][$association], $diff);
- }
- } elseif ($selfJoin && array_key_exists($association, $merge[0])) {
- $data[$association] = array_merge($data[$association], array($association => array()));
- }
- }
- }
- } else {
- if (isset($merge[0][$association]) && $merge[0][$association] === false) {
- if (!isset($data[$association])) {
- $data[$association] = array();
- }
- } else {
- foreach ($merge as $i => $row) {
- $insert = array();
- if (count($row) === 1) {
- $insert = $row[$association];
- } elseif (isset($row[$association])) {
- $insert = array_merge($row[$association], $row);
- unset($insert[$association]);
- }
-
- if (empty($data[$association]) || (isset($data[$association]) && !in_array($insert, $data[$association], true))) {
- $data[$association][] = $insert;
- }
- }
- }
- }
- }
-
-/**
- * Generates an array representing a query or part of a query from a single model or two associated models
- *
- * @param Model $model
- * @param Model $linkModel
- * @param string $type
- * @param string $association
- * @param array $assocData
- * @param array $queryData
- * @param boolean $external
- * @param array $resultSet
- * @return mixed
- */
- public function generateAssociationQuery(Model $model, $linkModel, $type, $association = null, $assocData = array(), &$queryData, $external = false, &$resultSet) {
- $queryData = $this->_scrubQueryData($queryData);
- $assocData = $this->_scrubQueryData($assocData);
- $modelAlias = $model->alias;
-
- if (empty($queryData['fields'])) {
- $queryData['fields'] = $this->fields($model, $modelAlias);
- } elseif (!empty($model->hasMany) && $model->recursive > -1) {
- $assocFields = $this->fields($model, $modelAlias, array("{$modelAlias}.{$model->primaryKey}"));
- $passedFields = $queryData['fields'];
- if (count($passedFields) === 1) {
- if (strpos($passedFields[0], $assocFields[0]) === false && !preg_match('/^[a-z]+\(/i', $passedFields[0])) {
- $queryData['fields'] = array_merge($passedFields, $assocFields);
- } else {
- $queryData['fields'] = $passedFields;
- }
- } else {
- $queryData['fields'] = array_merge($passedFields, $assocFields);
- }
- unset($assocFields, $passedFields);
- }
-
- if ($linkModel === null) {
- return $this->buildStatement(
- array(
- 'fields' => array_unique($queryData['fields']),
- 'table' => $this->fullTableName($model),
- 'alias' => $modelAlias,
- 'limit' => $queryData['limit'],
- 'offset' => $queryData['offset'],
- 'joins' => $queryData['joins'],
- 'conditions' => $queryData['conditions'],
- 'order' => $queryData['order'],
- 'group' => $queryData['group']
- ),
- $model
- );
- }
- if ($external && !empty($assocData['finderQuery'])) {
- return $assocData['finderQuery'];
- }
-
- $self = $model->name === $linkModel->name;
- $fields = array();
-
- if ($external || (in_array($type, array('hasOne', 'belongsTo')) && $assocData['fields'] !== false)) {
- $fields = $this->fields($linkModel, $association, $assocData['fields']);
- }
- if (empty($assocData['offset']) && !empty($assocData['page'])) {
- $assocData['offset'] = ($assocData['page'] - 1) * $assocData['limit'];
- }
- $assocData['limit'] = $this->limit($assocData['limit'], $assocData['offset']);
-
- switch ($type) {
- case 'hasOne':
- case 'belongsTo':
- $conditions = $this->_mergeConditions(
- $assocData['conditions'],
- $this->getConstraint($type, $model, $linkModel, $association, array_merge($assocData, compact('external', 'self')))
- );
-
- if (!$self && $external) {
- foreach ($conditions as $key => $condition) {
- if (is_numeric($key) && strpos($condition, $modelAlias . '.') !== false) {
- unset($conditions[$key]);
- }
- }
- }
-
- if ($external) {
- $query = array_merge($assocData, array(
- 'conditions' => $conditions,
- 'table' => $this->fullTableName($linkModel),
- 'fields' => $fields,
- 'alias' => $association,
- 'group' => null
- ));
- $query += array('order' => $assocData['order'], 'limit' => $assocData['limit']);
- } else {
- $join = array(
- 'table' => $linkModel,
- 'alias' => $association,
- 'type' => isset($assocData['type']) ? $assocData['type'] : 'LEFT',
- 'conditions' => trim($this->conditions($conditions, true, false, $model))
- );
- $queryData['fields'] = array_merge($queryData['fields'], $fields);
-
- if (!empty($assocData['order'])) {
- $queryData['order'][] = $assocData['order'];
- }
- if (!in_array($join, $queryData['joins'])) {
- $queryData['joins'][] = $join;
- }
- return true;
- }
- break;
- case 'hasMany':
- $assocData['fields'] = $this->fields($linkModel, $association, $assocData['fields']);
- if (!empty($assocData['foreignKey'])) {
- $assocData['fields'] = array_merge($assocData['fields'], $this->fields($linkModel, $association, array("{$association}.{$assocData['foreignKey']}")));
- }
- $query = array(
- 'conditions' => $this->_mergeConditions($this->getConstraint('hasMany', $model, $linkModel, $association, $assocData), $assocData['conditions']),
- 'fields' => array_unique($assocData['fields']),
- 'table' => $this->fullTableName($linkModel),
- 'alias' => $association,
- 'order' => $assocData['order'],
- 'limit' => $assocData['limit'],
- 'group' => null
- );
- break;
- case 'hasAndBelongsToMany':
- $joinFields = array();
- $joinAssoc = null;
-
- if (isset($assocData['with']) && !empty($assocData['with'])) {
- $joinKeys = array($assocData['foreignKey'], $assocData['associationForeignKey']);
- list($with, $joinFields) = $model->joinModel($assocData['with'], $joinKeys);
-
- $joinTbl = $model->{$with};
- $joinAlias = $joinTbl;
-
- if (is_array($joinFields) && !empty($joinFields)) {
- $joinAssoc = $joinAlias = $model->{$with}->alias;
- $joinFields = $this->fields($model->{$with}, $joinAlias, $joinFields);
- } else {
- $joinFields = array();
- }
- } else {
- $joinTbl = $assocData['joinTable'];
- $joinAlias = $this->fullTableName($assocData['joinTable']);
- }
- $query = array(
- 'conditions' => $assocData['conditions'],
- 'limit' => $assocData['limit'],
- 'table' => $this->fullTableName($linkModel),
- 'alias' => $association,
- 'fields' => array_merge($this->fields($linkModel, $association, $assocData['fields']), $joinFields),
- 'order' => $assocData['order'],
- 'group' => null,
- 'joins' => array(array(
- 'table' => $joinTbl,
- 'alias' => $joinAssoc,
- 'conditions' => $this->getConstraint('hasAndBelongsToMany', $model, $linkModel, $joinAlias, $assocData, $association)
- ))
- );
- break;
- }
- if (isset($query)) {
- return $this->buildStatement($query, $model);
- }
- return null;
- }
-
-/**
- * Returns a conditions array for the constraint between two models
- *
- * @param string $type Association type
- * @param Model $model Model object
- * @param string $linkModel
- * @param string $alias
- * @param array $assoc
- * @param string $alias2
- * @return array Conditions array defining the constraint between $model and $association
- */
- public function getConstraint($type, $model, $linkModel, $alias, $assoc, $alias2 = null) {
- $assoc += array('external' => false, 'self' => false);
-
- if (empty($assoc['foreignKey'])) {
- return array();
- }
-
- switch (true) {
- case ($assoc['external'] && $type === 'hasOne'):
- return array("{$alias}.{$assoc['foreignKey']}" => '{$__cakeID__$}');
- case ($assoc['external'] && $type === 'belongsTo'):
- return array("{$alias}.{$linkModel->primaryKey}" => '{$__cakeForeignKey__$}');
- case (!$assoc['external'] && $type === 'hasOne'):
- return array("{$alias}.{$assoc['foreignKey']}" => $this->identifier("{$model->alias}.{$model->primaryKey}"));
- case (!$assoc['external'] && $type === 'belongsTo'):
- return array("{$model->alias}.{$assoc['foreignKey']}" => $this->identifier("{$alias}.{$linkModel->primaryKey}"));
- case ($type === 'hasMany'):
- return array("{$alias}.{$assoc['foreignKey']}" => array('{$__cakeID__$}'));
- case ($type === 'hasAndBelongsToMany'):
- return array(
- array("{$alias}.{$assoc['foreignKey']}" => '{$__cakeID__$}'),
- array("{$alias}.{$assoc['associationForeignKey']}" => $this->identifier("{$alias2}.{$linkModel->primaryKey}"))
- );
- }
- return array();
- }
-
-/**
- * Builds and generates a JOIN statement from an array. Handles final clean-up before conversion.
- *
- * @param array $join An array defining a JOIN statement in a query
- * @return string An SQL JOIN statement to be used in a query
- * @see DboSource::renderJoinStatement()
- * @see DboSource::buildStatement()
- */
- public function buildJoinStatement($join) {
- $data = array_merge(array(
- 'type' => null,
- 'alias' => null,
- 'table' => 'join_table',
- 'conditions' => array()
- ), $join);
-
- if (!empty($data['alias'])) {
- $data['alias'] = $this->alias . $this->name($data['alias']);
- }
- if (!empty($data['conditions'])) {
- $data['conditions'] = trim($this->conditions($data['conditions'], true, false));
- }
- if (!empty($data['table'])) {
- $data['table'] = $this->fullTableName($data['table']);
- }
- return $this->renderJoinStatement($data);
- }
-
-/**
- * Builds and generates an SQL statement from an array. Handles final clean-up before conversion.
- *
- * @param array $query An array defining an SQL query
- * @param Model $model The model object which initiated the query
- * @return string An executable SQL statement
- * @see DboSource::renderStatement()
- */
- public function buildStatement($query, $model) {
- $query = array_merge(array('offset' => null, 'joins' => array()), $query);
- if (!empty($query['joins'])) {
- $count = count($query['joins']);
- for ($i = 0; $i < $count; $i++) {
- if (is_array($query['joins'][$i])) {
- $query['joins'][$i] = $this->buildJoinStatement($query['joins'][$i]);
- }
- }
- }
- return $this->renderStatement('select', array(
- 'conditions' => $this->conditions($query['conditions'], true, true, $model),
- 'fields' => implode(', ', $query['fields']),
- 'table' => $query['table'],
- 'alias' => $this->alias . $this->name($query['alias']),
- 'order' => $this->order($query['order'], 'ASC', $model),
- 'limit' => $this->limit($query['limit'], $query['offset']),
- 'joins' => implode(' ', $query['joins']),
- 'group' => $this->group($query['group'], $model)
- ));
- }
-
-/**
- * Renders a final SQL JOIN statement
- *
- * @param array $data
- * @return string
- */
- public function renderJoinStatement($data) {
- extract($data);
- return trim("{$type} JOIN {$table} {$alias} ON ({$conditions})");
- }
-
-/**
- * Renders a final SQL statement by putting together the component parts in the correct order
- *
- * @param string $type type of query being run. e.g select, create, update, delete, schema, alter.
- * @param array $data Array of data to insert into the query.
- * @return string Rendered SQL expression to be run.
- */
- public function renderStatement($type, $data) {
- extract($data);
- $aliases = null;
-
- switch (strtolower($type)) {
- case 'select':
- return "SELECT {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order} {$limit}";
- case 'create':
- return "INSERT INTO {$table} ({$fields}) VALUES ({$values})";
- case 'update':
- if (!empty($alias)) {
- $aliases = "{$this->alias}{$alias} {$joins} ";
- }
- return "UPDATE {$table} {$aliases}SET {$fields} {$conditions}";
- case 'delete':
- if (!empty($alias)) {
- $aliases = "{$this->alias}{$alias} {$joins} ";
- }
- return "DELETE {$alias} FROM {$table} {$aliases}{$conditions}";
- case 'schema':
- foreach (array('columns', 'indexes', 'tableParameters') as $var) {
- if (is_array(${$var})) {
- ${$var} = "\t" . join(",\n\t", array_filter(${$var}));
- } else {
- ${$var} = '';
- }
- }
- if (trim($indexes) !== '') {
- $columns .= ',';
- }
- return "CREATE TABLE {$table} (\n{$columns}{$indexes}) {$tableParameters};";
- case 'alter':
- return;
- }
- }
-
-/**
- * Merges a mixed set of string/array conditions
- *
- * @param mixed $query
- * @param mixed $assoc
- * @return array
- */
- protected function _mergeConditions($query, $assoc) {
- if (empty($assoc)) {
- return $query;
- }
-
- if (is_array($query)) {
- return array_merge((array)$assoc, $query);
- }
-
- if (!empty($query)) {
- $query = array($query);
- if (is_array($assoc)) {
- $query = array_merge($query, $assoc);
- } else {
- $query[] = $assoc;
- }
- return $query;
- }
-
- return $assoc;
- }
-
-/**
- * Generates and executes an SQL UPDATE statement for given model, fields, and values.
- * For databases that do not support aliases in UPDATE queries.
- *
- * @param Model $model
- * @param array $fields
- * @param array $values
- * @param mixed $conditions
- * @return boolean Success
- */
- public function update(Model $model, $fields = array(), $values = null, $conditions = null) {
- if ($values == null) {
- $combined = $fields;
- } else {
- $combined = array_combine($fields, $values);
- }
-
- $fields = implode(', ', $this->_prepareUpdateFields($model, $combined, empty($conditions)));
-
- $alias = $joins = null;
- $table = $this->fullTableName($model);
- $conditions = $this->_matchRecords($model, $conditions);
-
- if ($conditions === false) {
- return false;
- }
- $query = compact('table', 'alias', 'joins', 'fields', 'conditions');
-
- if (!$this->execute($this->renderStatement('update', $query))) {
- $model->onError();
- return false;
- }
- return true;
- }
-
-/**
- * Quotes and prepares fields and values for an SQL UPDATE statement
- *
- * @param Model $model
- * @param array $fields
- * @param boolean $quoteValues If values should be quoted, or treated as SQL snippets
- * @param boolean $alias Include the model alias in the field name
- * @return array Fields and values, quoted and prepared
- */
- protected function _prepareUpdateFields(Model $model, $fields, $quoteValues = true, $alias = false) {
- $quotedAlias = $this->startQuote . $model->alias . $this->endQuote;
-
- $updates = array();
- foreach ($fields as $field => $value) {
- if ($alias && strpos($field, '.') === false) {
- $quoted = $model->escapeField($field);
- } elseif (!$alias && strpos($field, '.') !== false) {
- $quoted = $this->name(str_replace($quotedAlias . '.', '', str_replace(
- $model->alias . '.', '', $field
- )));
- } else {
- $quoted = $this->name($field);
- }
-
- if ($value === null) {
- $updates[] = $quoted . ' = NULL';
- continue;
- }
- $update = $quoted . ' = ';
-
- if ($quoteValues) {
- $update .= $this->value($value, $model->getColumnType($field));
- } elseif ($model->getColumnType($field) == 'boolean' && (is_int($value) || is_bool($value))) {
- $update .= $this->boolean($value, true);
- } elseif (!$alias) {
- $update .= str_replace($quotedAlias . '.', '', str_replace(
- $model->alias . '.', '', $value
- ));
- } else {
- $update .= $value;
- }
- $updates[] = $update;
- }
- return $updates;
- }
-
-/**
- * Generates and executes an SQL DELETE statement.
- * For databases that do not support aliases in UPDATE queries.
- *
- * @param Model $model
- * @param mixed $conditions
- * @return boolean Success
- */
- public function delete(Model $model, $conditions = null) {
- $alias = $joins = null;
- $table = $this->fullTableName($model);
- $conditions = $this->_matchRecords($model, $conditions);
-
- if ($conditions === false) {
- return false;
- }
-
- if ($this->execute($this->renderStatement('delete', compact('alias', 'table', 'joins', 'conditions'))) === false) {
- $model->onError();
- return false;
- }
- return true;
- }
-
-/**
- * Gets a list of record IDs for the given conditions. Used for multi-record updates and deletes
- * in databases that do not support aliases in UPDATE/DELETE queries.
- *
- * @param Model $model
- * @param mixed $conditions
- * @return array List of record IDs
- */
- protected function _matchRecords(Model $model, $conditions = null) {
- if ($conditions === true) {
- $conditions = $this->conditions(true);
- } elseif ($conditions === null) {
- $conditions = $this->conditions($this->defaultConditions($model, $conditions, false), true, true, $model);
- } else {
- $noJoin = true;
- foreach ($conditions as $field => $value) {
- $originalField = $field;
- if (strpos($field, '.') !== false) {
- list($alias, $field) = explode('.', $field);
- $field = ltrim($field, $this->startQuote);
- $field = rtrim($field, $this->endQuote);
- }
- if (!$model->hasField($field)) {
- $noJoin = false;
- break;
- }
- if ($field !== $originalField) {
- $conditions[$field] = $value;
- unset($conditions[$originalField]);
- }
- }
- if ($noJoin === true) {
- return $this->conditions($conditions);
- }
- $idList = $model->find('all', array(
- 'fields' => "{$model->alias}.{$model->primaryKey}",
- 'conditions' => $conditions
- ));
-
- if (empty($idList)) {
- return false;
- }
- $conditions = $this->conditions(array(
- $model->primaryKey => Set::extract($idList, "{n}.{$model->alias}.{$model->primaryKey}")
- ));
- }
- return $conditions;
- }
-
-/**
- * Returns an array of SQL JOIN fragments from a model's associations
- *
- * @param Model $model
- * @return array
- */
- protected function _getJoins(Model $model) {
- $join = array();
- $joins = array_merge($model->getAssociated('hasOne'), $model->getAssociated('belongsTo'));
-
- foreach ($joins as $assoc) {
- if (isset($model->{$assoc}) && $model->useDbConfig == $model->{$assoc}->useDbConfig && $model->{$assoc}->getDataSource()) {
- $assocData = $model->getAssociated($assoc);
- $join[] = $this->buildJoinStatement(array(
- 'table' => $model->{$assoc},
- 'alias' => $assoc,
- 'type' => isset($assocData['type']) ? $assocData['type'] : 'LEFT',
- 'conditions' => trim($this->conditions(
- $this->_mergeConditions($assocData['conditions'], $this->getConstraint($assocData['association'], $model, $model->{$assoc}, $assoc, $assocData)),
- true, false, $model
- ))
- ));
- }
- }
- return $join;
- }
-
-/**
- * Returns an SQL calculation, i.e. COUNT() or MAX()
- *
- * @param Model $model
- * @param string $func Lowercase name of SQL function, i.e. 'count' or 'max'
- * @param array $params Function parameters (any values must be quoted manually)
- * @return string An SQL calculation function
- */
- public function calculate(Model $model, $func, $params = array()) {
- $params = (array)$params;
-
- switch (strtolower($func)) {
- case 'count':
- if (!isset($params[0])) {
- $params[0] = '*';
- }
- if (!isset($params[1])) {
- $params[1] = 'count';
- }
- if (is_object($model) && $model->isVirtualField($params[0])) {
- $arg = $this->_quoteFields($model->getVirtualField($params[0]));
- } else {
- $arg = $this->name($params[0]);
- }
- return 'COUNT(' . $arg . ') AS ' . $this->name($params[1]);
- case 'max':
- case 'min':
- if (!isset($params[1])) {
- $params[1] = $params[0];
- }
- if (is_object($model) && $model->isVirtualField($params[0])) {
- $arg = $this->_quoteFields($model->getVirtualField($params[0]));
- } else {
- $arg = $this->name($params[0]);
- }
- return strtoupper($func) . '(' . $arg . ') AS ' . $this->name($params[1]);
- break;
- }
- }
-
-/**
- * Deletes all the records in a table and resets the count of the auto-incrementing
- * primary key, where applicable.
- *
- * @param mixed $table A string or model class representing the table to be truncated
- * @return boolean SQL TRUNCATE TABLE statement, false if not applicable.
- */
- public function truncate($table) {
- return $this->execute('TRUNCATE TABLE ' . $this->fullTableName($table));
- }
-
-/**
- * Begin a transaction
- *
- * @return boolean True on success, false on fail
- * (i.e. if the database/model does not support transactions,
- * or a transaction has not started).
- */
- public function begin() {
- if ($this->_transactionStarted || $this->_connection->beginTransaction()) {
- if ($this->fullDebug && empty($this->_transactionNesting)) {
- $this->logQuery('BEGIN');
- }
- $this->_transactionStarted = true;
- $this->_transactionNesting++;
- return true;
- }
- return false;
- }
-
-/**
- * Commit a transaction
- *
- * @return boolean True on success, false on fail
- * (i.e. if the database/model does not support transactions,
- * or a transaction has not started).
- */
- public function commit() {
- if ($this->_transactionStarted) {
- $this->_transactionNesting--;
- if ($this->_transactionNesting <= 0) {
- $this->_transactionStarted = false;
- $this->_transactionNesting = 0;
- if ($this->fullDebug) {
- $this->logQuery('COMMIT');
- }
- return $this->_connection->commit();
- }
- return true;
- }
- return false;
- }
-
-/**
- * Rollback a transaction
- *
- * @return boolean True on success, false on fail
- * (i.e. if the database/model does not support transactions,
- * or a transaction has not started).
- */
- public function rollback() {
- if ($this->_transactionStarted && $this->_connection->rollBack()) {
- if ($this->fullDebug) {
- $this->logQuery('ROLLBACK');
- }
- $this->_transactionStarted = false;
- $this->_transactionNesting = 0;
- return true;
- }
- return false;
- }
-
-/**
- * Returns the ID generated from the previous INSERT operation.
- *
- * @param mixed $source
- * @return mixed
- */
- public function lastInsertId($source = null) {
- return $this->_connection->lastInsertId();
- }
-
-/**
- * Creates a default set of conditions from the model if $conditions is null/empty.
- * If conditions are supplied then they will be returned. If a model doesn't exist and no conditions
- * were provided either null or false will be returned based on what was input.
- *
- * @param Model $model
- * @param mixed $conditions Array of conditions, conditions string, null or false. If an array of conditions,
- * or string conditions those conditions will be returned. With other values the model's existence will be checked.
- * If the model doesn't exist a null or false will be returned depending on the input value.
- * @param boolean $useAlias Use model aliases rather than table names when generating conditions
- * @return mixed Either null, false, $conditions or an array of default conditions to use.
- * @see DboSource::update()
- * @see DboSource::conditions()
- */
- public function defaultConditions(Model $model, $conditions, $useAlias = true) {
- if (!empty($conditions)) {
- return $conditions;
- }
- $exists = $model->exists();
- if (!$exists && $conditions !== null) {
- return false;
- } elseif (!$exists) {
- return null;
- }
- $alias = $model->alias;
-
- if (!$useAlias) {
- $alias = $this->fullTableName($model, false);
- }
- return array("{$alias}.{$model->primaryKey}" => $model->getID());
- }
-
-/**
- * Returns a key formatted like a string Model.fieldname(i.e. Post.title, or Country.name)
- *
- * @param Model $model
- * @param string $key
- * @param string $assoc
- * @return string
- */
- public function resolveKey(Model $model, $key, $assoc = null) {
- if (strpos('.', $key) !== false) {
- return $this->name($model->alias) . '.' . $this->name($key);
- }
- return $key;
- }
-
-/**
- * Private helper method to remove query metadata in given data array.
- *
- * @param array $data
- * @return array
- */
- protected function _scrubQueryData($data) {
- static $base = null;
- if ($base === null) {
- $base = array_fill_keys(array('conditions', 'fields', 'joins', 'order', 'limit', 'offset', 'group'), array());
- $base['callbacks'] = null;
- }
- return (array)$data + $base;
- }
-
-/**
- * Converts model virtual fields into sql expressions to be fetched later
- *
- * @param Model $model
- * @param string $alias Alias table name
- * @param mixed $fields virtual fields to be used on query
- * @return array
- */
- protected function _constructVirtualFields(Model $model, $alias, $fields) {
- $virtual = array();
- foreach ($fields as $field) {
- $virtualField = $this->name($alias . $this->virtualFieldSeparator . $field);
- $expression = $this->_quoteFields($model->getVirtualField($field));
- $virtual[] = '(' . $expression . ") {$this->alias} {$virtualField}";
- }
- return $virtual;
- }
-
-/**
- * Generates the fields list of an SQL query.
- *
- * @param Model $model
- * @param string $alias Alias table name
- * @param mixed $fields
- * @param boolean $quote If false, returns fields array unquoted
- * @return array
- */
- public function fields(Model $model, $alias = null, $fields = array(), $quote = true) {
- if (empty($alias)) {
- $alias = $model->alias;
- }
- $virtualFields = $model->getVirtualField();
- $cacheKey = array(
- $alias,
- get_class($model),
- $model->alias,
- $virtualFields,
- $fields,
- $quote
- );
- $cacheKey = md5(serialize($cacheKey));
- if ($return = $this->cacheMethod(__FUNCTION__, $cacheKey)) {
- return $return;
- }
- $allFields = empty($fields);
- if ($allFields) {
- $fields = array_keys($model->schema());
- } elseif (!is_array($fields)) {
- $fields = String::tokenize($fields);
- }
- $fields = array_values(array_filter($fields));
- $allFields = $allFields || in_array('*', $fields) || in_array($model->alias . '.*', $fields);
-
- $virtual = array();
- if (!empty($virtualFields)) {
- $virtualKeys = array_keys($virtualFields);
- foreach ($virtualKeys as $field) {
- $virtualKeys[] = $model->alias . '.' . $field;
- }
- $virtual = ($allFields) ? $virtualKeys : array_intersect($virtualKeys, $fields);
- foreach ($virtual as $i => $field) {
- if (strpos($field, '.') !== false) {
- $virtual[$i] = str_replace($model->alias . '.', '', $field);
- }
- $fields = array_diff($fields, array($field));
- }
- $fields = array_values($fields);
- }
-
- if (!$quote) {
- if (!empty($virtual)) {
- $fields = array_merge($fields, $this->_constructVirtualFields($model, $alias, $virtual));
- }
- return $fields;
- }
- $count = count($fields);
-
- if ($count >= 1 && !in_array($fields[0], array('*', 'COUNT(*)'))) {
- for ($i = 0; $i < $count; $i++) {
- if (is_string($fields[$i]) && in_array($fields[$i], $virtual)) {
- unset($fields[$i]);
- continue;
- }
- if (is_object($fields[$i]) && isset($fields[$i]->type) && $fields[$i]->type === 'expression') {
- $fields[$i] = $fields[$i]->value;
- } elseif (preg_match('/^\(.*\)\s' . $this->alias . '.*/i', $fields[$i])) {
- continue;
- } elseif (!preg_match('/^.+\\(.*\\)/', $fields[$i])) {
- $prepend = '';
-
- if (strpos($fields[$i], 'DISTINCT') !== false) {
- $prepend = 'DISTINCT ';
- $fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i]));
- }
- $dot = strpos($fields[$i], '.');
-
- if ($dot === false) {
- $prefix = !(
- strpos($fields[$i], ' ') !== false ||
- strpos($fields[$i], '(') !== false
- );
- $fields[$i] = $this->name(($prefix ? $alias . '.' : '') . $fields[$i]);
- } else {
- if (strpos($fields[$i], ',') === false) {
- $build = explode('.', $fields[$i]);
- if (!Set::numeric($build)) {
- $fields[$i] = $this->name(implode('.', $build));
- }
- }
- }
- $fields[$i] = $prepend . $fields[$i];
- } elseif (preg_match('/\(([\.\w]+)\)/', $fields[$i], $field)) {
- if (isset($field[1])) {
- if (strpos($field[1], '.') === false) {
- $field[1] = $this->name($alias . '.' . $field[1]);
- } else {
- $field[0] = explode('.', $field[1]);
- if (!Set::numeric($field[0])) {
- $field[0] = implode('.', array_map(array(&$this, 'name'), $field[0]));
- $fields[$i] = preg_replace('/\(' . $field[1] . '\)/', '(' . $field[0] . ')', $fields[$i], 1);
- }
- }
- }
- }
- }
- }
- if (!empty($virtual)) {
- $fields = array_merge($fields, $this->_constructVirtualFields($model, $alias, $virtual));
- }
- return $this->cacheMethod(__FUNCTION__, $cacheKey, array_unique($fields));
- }
-
-/**
- * Creates a WHERE clause by parsing given conditions data. If an array or string
- * conditions are provided those conditions will be parsed and quoted. If a boolean
- * is given it will be integer cast as condition. Null will return 1 = 1.
- *
- * Results of this method are stored in a memory cache. This improves performance, but
- * because the method uses a simple hashing algorithm it can infrequently have collisions.
- * Setting DboSource::$cacheMethods to false will disable the memory cache.
- *
- * @param mixed $conditions Array or string of conditions, or any value.
- * @param boolean $quoteValues If true, values should be quoted
- * @param boolean $where If true, "WHERE " will be prepended to the return value
- * @param Model $model A reference to the Model instance making the query
- * @return string SQL fragment
- */
- public function conditions($conditions, $quoteValues = true, $where = true, $model = null) {
- $clause = $out = '';
-
- if ($where) {
- $clause = ' WHERE ';
- }
-
- if (is_array($conditions) && !empty($conditions)) {
- $out = $this->conditionKeysToString($conditions, $quoteValues, $model);
-
- if (empty($out)) {
- return $clause . ' 1 = 1';
- }
- return $clause . implode(' AND ', $out);
- }
- if (is_bool($conditions)) {
- return $clause . (int)$conditions . ' = 1';
- }
-
- if (empty($conditions) || trim($conditions) === '') {
- return $clause . '1 = 1';
- }
- $clauses = '/^WHERE\\x20|^GROUP\\x20BY\\x20|^HAVING\\x20|^ORDER\\x20BY\\x20/i';
-
- if (preg_match($clauses, $conditions, $match)) {
- $clause = '';
- }
- $conditions = $this->_quoteFields($conditions);
- return $clause . $conditions;
- }
-
-/**
- * Creates a WHERE clause by parsing given conditions array. Used by DboSource::conditions().
- *
- * @param array $conditions Array or string of conditions
- * @param boolean $quoteValues If true, values should be quoted
- * @param Model $model A reference to the Model instance making the query
- * @return string SQL fragment
- */
- public function conditionKeysToString($conditions, $quoteValues = true, $model = null) {
- $out = array();
- $data = $columnType = null;
- $bool = array('and', 'or', 'not', 'and not', 'or not', 'xor', '||', '&&');
-
- foreach ($conditions as $key => $value) {
- $join = ' AND ';
- $not = null;
-
- if (is_array($value)) {
- $valueInsert = (
- !empty($value) &&
- (substr_count($key, '?') === count($value) || substr_count($key, ':') === count($value))
- );
- }
-
- if (is_numeric($key) && empty($value)) {
- continue;
- } elseif (is_numeric($key) && is_string($value)) {
- $out[] = $not . $this->_quoteFields($value);
- } elseif ((is_numeric($key) && is_array($value)) || in_array(strtolower(trim($key)), $bool)) {
- if (in_array(strtolower(trim($key)), $bool)) {
- $join = ' ' . strtoupper($key) . ' ';
- } else {
- $key = $join;
- }
- $value = $this->conditionKeysToString($value, $quoteValues, $model);
-
- if (strpos($join, 'NOT') !== false) {
- if (strtoupper(trim($key)) === 'NOT') {
- $key = 'AND ' . trim($key);
- }
- $not = 'NOT ';
- }
-
- if (empty($value[1])) {
- if ($not) {
- $out[] = $not . '(' . $value[0] . ')';
- } else {
- $out[] = $value[0];
- }
- } else {
- $out[] = '(' . $not . '(' . implode(') ' . strtoupper($key) . ' (', $value) . '))';
- }
- } else {
- if (is_object($value) && isset($value->type)) {
- if ($value->type === 'identifier') {
- $data .= $this->name($key) . ' = ' . $this->name($value->value);
- } elseif ($value->type === 'expression') {
- if (is_numeric($key)) {
- $data .= $value->value;
- } else {
- $data .= $this->name($key) . ' = ' . $value->value;
- }
- }
- } elseif (is_array($value) && !empty($value) && !$valueInsert) {
- $keys = array_keys($value);
- if ($keys === array_values($keys)) {
- $count = count($value);
- if ($count === 1 && !preg_match("/\s+NOT$/", $key)) {
- $data = $this->_quoteFields($key) . ' = (';
- } else {
- $data = $this->_quoteFields($key) . ' IN (';
- }
- if ($quoteValues) {
- if (is_object($model)) {
- $columnType = $model->getColumnType($key);
- }
- $data .= implode(', ', $this->value($value, $columnType));
- }
- $data .= ')';
- } else {
- $ret = $this->conditionKeysToString($value, $quoteValues, $model);
- if (count($ret) > 1) {
- $data = '(' . implode(') AND (', $ret) . ')';
- } elseif (isset($ret[0])) {
- $data = $ret[0];
- }
- }
- } elseif (is_numeric($key) && !empty($value)) {
- $data = $this->_quoteFields($value);
- } else {
- $data = $this->_parseKey($model, trim($key), $value);
- }
-
- if ($data != null) {
- $out[] = $data;
- $data = null;
- }
- }
- }
- return $out;
- }
-
-/**
- * Extracts a Model.field identifier and an SQL condition operator from a string, formats
- * and inserts values, and composes them into an SQL snippet.
- *
- * @param Model $model Model object initiating the query
- * @param string $key An SQL key snippet containing a field and optional SQL operator
- * @param mixed $value The value(s) to be inserted in the string
- * @return string
- */
- protected function _parseKey($model, $key, $value) {
- $operatorMatch = '/^(((' . implode(')|(', $this->_sqlOps);
- $operatorMatch .= ')\\x20?)|<[>=]?(?![^>]+>)\\x20?|[>=!]{1,3}(?!<)\\x20?)/is';
- $bound = (strpos($key, '?') !== false || (is_array($value) && strpos($key, ':') !== false));
-
- if (strpos($key, ' ') === false) {
- $operator = '=';
- } else {
- list($key, $operator) = explode(' ', trim($key), 2);
-
- if (!preg_match($operatorMatch, trim($operator)) && strpos($operator, ' ') !== false) {
- $key = $key . ' ' . $operator;
- $split = strrpos($key, ' ');
- $operator = substr($key, $split);
- $key = substr($key, 0, $split);
- }
- }
-
- $virtual = false;
- if (is_object($model) && $model->isVirtualField($key)) {
- $key = $this->_quoteFields($model->getVirtualField($key));
- $virtual = true;
- }
-
- $type = is_object($model) ? $model->getColumnType($key) : null;
- $null = $value === null || (is_array($value) && empty($value));
-
- if (strtolower($operator) === 'not') {
- $data = $this->conditionKeysToString(
- array($operator => array($key => $value)), true, $model
- );
- return $data[0];
- }
-
- $value = $this->value($value, $type);
-
- if (!$virtual && $key !== '?') {
- $isKey = (strpos($key, '(') !== false || strpos($key, ')') !== false);
- $key = $isKey ? $this->_quoteFields($key) : $this->name($key);
- }
-
- if ($bound) {
- return String::insert($key . ' ' . trim($operator), $value);
- }
-
- if (!preg_match($operatorMatch, trim($operator))) {
- $operator .= ' =';
- }
- $operator = trim($operator);
-
- if (is_array($value)) {
- $value = implode(', ', $value);
-
- switch ($operator) {
- case '=':
- $operator = 'IN';
- break;
- case '!=':
- case '<>':
- $operator = 'NOT IN';
- break;
- }
- $value = "({$value})";
- } elseif ($null || $value === 'NULL') {
- switch ($operator) {
- case '=':
- $operator = 'IS';
- break;
- case '!=':
- case '<>':
- $operator = 'IS NOT';
- break;
- }
- }
- if ($virtual) {
- return "({$key}) {$operator} {$value}";
- }
- return "{$key} {$operator} {$value}";
- }
-
-/**
- * Quotes Model.fields
- *
- * @param string $conditions
- * @return string or false if no match
- */
- protected function _quoteFields($conditions) {
- $start = $end = null;
- $original = $conditions;
-
- if (!empty($this->startQuote)) {
- $start = preg_quote($this->startQuote);
- }
- if (!empty($this->endQuote)) {
- $end = preg_quote($this->endQuote);
- }
- $conditions = str_replace(array($start, $end), '', $conditions);
- $conditions = preg_replace_callback('/(?:[\'\"][^\'\"\\\]*(?:\\\.[^\'\"\\\]*)*[\'\"])|([a-z0-9_' . $start . $end . ']*\\.[a-z0-9_' . $start . $end . ']*)/i', array(&$this, '_quoteMatchedField'), $conditions);
-
- if ($conditions !== null) {
- return $conditions;
- }
- return $original;
- }
-
-/**
- * Auxiliary function to quote matches `Model.fields` from a preg_replace_callback call
- *
- * @param string $match matched string
- * @return string quoted string
- */
- protected function _quoteMatchedField($match) {
- if (is_numeric($match[0])) {
- return $match[0];
- }
- return $this->name($match[0]);
- }
-
-/**
- * Returns a limit statement in the correct format for the particular database.
- *
- * @param integer $limit Limit of results returned
- * @param integer $offset Offset from which to start results
- * @return string SQL limit/offset statement
- */
- public function limit($limit, $offset = null) {
- if ($limit) {
- $rt = '';
- if (!strpos(strtolower($limit), 'limit')) {
- $rt = ' LIMIT';
- }
-
- if ($offset) {
- $rt .= ' ' . $offset . ',';
- }
-
- $rt .= ' ' . $limit;
- return $rt;
- }
- return null;
- }
-
-/**
- * Returns an ORDER BY clause as a string.
- *
- * @param array|string $keys Field reference, as a key (i.e. Post.title)
- * @param string $direction Direction (ASC or DESC)
- * @param Model $model model reference (used to look for virtual field)
- * @return string ORDER BY clause
- */
- public function order($keys, $direction = 'ASC', $model = null) {
- if (!is_array($keys)) {
- $keys = array($keys);
- }
- $keys = array_filter($keys);
- $result = array();
- while (!empty($keys)) {
- list($key, $dir) = each($keys);
- array_shift($keys);
-
- if (is_numeric($key)) {
- $key = $dir;
- $dir = $direction;
- }
-
- if (is_string($key) && strpos($key, ',') !== false && !preg_match('/\(.+\,.+\)/', $key)) {
- $key = array_map('trim', explode(',', $key));
- }
- if (is_array($key)) {
- //Flatten the array
- $key = array_reverse($key, true);
- foreach ($key as $k => $v) {
- if (is_numeric($k)) {
- array_unshift($keys, $v);
- } else {
- $keys = array($k => $v) + $keys;
- }
- }
- continue;
- } elseif (is_object($key) && isset($key->type) && $key->type === 'expression') {
- $result[] = $key->value;
- continue;
- }
-
- if (preg_match('/\\x20(ASC|DESC).*/i', $key, $_dir)) {
- $dir = $_dir[0];
- $key = preg_replace('/\\x20(ASC|DESC).*/i', '', $key);
- }
-
- $key = trim($key);
-
- if (is_object($model) && $model->isVirtualField($key)) {
- $key = '(' . $this->_quoteFields($model->getVirtualField($key)) . ')';
- }
- list($alias, $field) = pluginSplit($key);
- if (is_object($model) && $alias !== $model->alias && is_object($model->{$alias}) && $model->{$alias}->isVirtualField($key)) {
- $key = '(' . $this->_quoteFields($model->{$alias}->getVirtualField($key)) . ')';
- }
-
- if (strpos($key, '.')) {
- $key = preg_replace_callback('/([a-zA-Z0-9_-]{1,})\\.([a-zA-Z0-9_-]{1,})/', array(&$this, '_quoteMatchedField'), $key);
- }
- if (!preg_match('/\s/', $key) && strpos($key, '.') === false) {
- $key = $this->name($key);
- }
- $key .= ' ' . trim($dir);
- $result[] = $key;
- }
- if (!empty($result)) {
- return ' ORDER BY ' . implode(', ', $result);
- }
- return '';
- }
-
-/**
- * Create a GROUP BY SQL clause
- *
- * @param string $group Group By Condition
- * @param Model $model
- * @return string string condition or null
- */
- public function group($group, $model = null) {
- if ($group) {
- if (!is_array($group)) {
- $group = array($group);
- }
- foreach ($group as $index => $key) {
- if (is_object($model) && $model->isVirtualField($key)) {
- $group[$index] = '(' . $model->getVirtualField($key) . ')';
- }
- }
- $group = implode(', ', $group);
- return ' GROUP BY ' . $this->_quoteFields($group);
- }
- return null;
- }
-
-/**
- * Disconnects database, kills the connection and says the connection is closed.
- *
- * @return void
- */
- public function close() {
- $this->disconnect();
- }
-
-/**
- * Checks if the specified table contains any record matching specified SQL
- *
- * @param Model $Model Model to search
- * @param string $sql SQL WHERE clause (condition only, not the "WHERE" part)
- * @return boolean True if the table has a matching record, else false
- */
- public function hasAny(Model $Model, $sql) {
- $sql = $this->conditions($sql);
- $table = $this->fullTableName($Model);
- $alias = $this->alias . $this->name($Model->alias);
- $where = $sql ? "{$sql}" : ' WHERE 1 = 1';
- $id = $Model->escapeField();
-
- $out = $this->fetchRow("SELECT COUNT({$id}) {$this->alias}count FROM {$table} {$alias}{$where}");
-
- if (is_array($out)) {
- return $out[0]['count'];
- }
- return false;
- }
-
-/**
- * Gets the length of a database-native column description, or null if no length
- *
- * @param string $real Real database-layer column type (i.e. "varchar(255)")
- * @return mixed An integer or string representing the length of the column, or null for unknown length.
- */
- public function length($real) {
- if (!preg_match_all('/([\w\s]+)(?:\((\d+)(?:,(\d+))?\))?(\sunsigned)?(\szerofill)?/', $real, $result)) {
- $col = str_replace(array(')', 'unsigned'), '', $real);
- $limit = null;
-
- if (strpos($col, '(') !== false) {
- list($col, $limit) = explode('(', $col);
- }
- if ($limit !== null) {
- return intval($limit);
- }
- return null;
- }
-
- $types = array(
- 'int' => 1, 'tinyint' => 1, 'smallint' => 1, 'mediumint' => 1, 'integer' => 1, 'bigint' => 1
- );
-
- list($real, $type, $length, $offset, $sign, $zerofill) = $result;
- $typeArr = $type;
- $type = $type[0];
- $length = $length[0];
- $offset = $offset[0];
-
- $isFloat = in_array($type, array('dec', 'decimal', 'float', 'numeric', 'double'));
- if ($isFloat && $offset) {
- return $length . ',' . $offset;
- }
-
- if (($real[0] == $type) && (count($real) === 1)) {
- return null;
- }
-
- if (isset($types[$type])) {
- $length += $types[$type];
- if (!empty($sign)) {
- $length--;
- }
- } elseif (in_array($type, array('enum', 'set'))) {
- $length = 0;
- foreach ($typeArr as $key => $enumValue) {
- if ($key === 0) {
- continue;
- }
- $tmpLength = strlen($enumValue);
- if ($tmpLength > $length) {
- $length = $tmpLength;
- }
- }
- }
- return intval($length);
- }
-
-/**
- * Translates between PHP boolean values and Database (faked) boolean values
- *
- * @param mixed $data Value to be translated
- * @param boolean $quote
- * @return string|boolean Converted boolean value
- */
- public function boolean($data, $quote = false) {
- if ($quote) {
- return !empty($data) ? '1' : '0';
- }
- return !empty($data);
- }
-
-/**
- * Inserts multiple values into a table
- *
- * @param string $table The table being inserted into.
- * @param array $fields The array of field/column names being inserted.
- * @param array $values The array of values to insert. The values should
- * be an array of rows. Each row should have values keyed by the column name.
- * Each row must have the values in the same order as $fields.
- * @return boolean
- */
- public function insertMulti($table, $fields, $values) {
- $table = $this->fullTableName($table);
- $holder = implode(',', array_fill(0, count($fields), '?'));
- $fields = implode(', ', array_map(array(&$this, 'name'), $fields));
-
- $pdoMap = array(
- 'integer' => PDO::PARAM_INT,
- 'float' => PDO::PARAM_STR,
- 'boolean' => PDO::PARAM_BOOL,
- 'string' => PDO::PARAM_STR,
- 'text' => PDO::PARAM_STR
- );
- $columnMap = array();
-
- $sql = "INSERT INTO {$table} ({$fields}) VALUES ({$holder})";
- $statement = $this->_connection->prepare($sql);
- $this->begin();
-
- foreach ($values[key($values)] as $key => $val) {
- $type = $this->introspectType($val);
- $columnMap[$key] = $pdoMap[$type];
- }
-
- foreach ($values as $row => $value) {
- $i = 1;
- foreach ($value as $col => $val) {
- $statement->bindValue($i, $val, $columnMap[$col]);
- $i += 1;
- }
- $statement->execute();
- $statement->closeCursor();
- }
- return $this->commit();
- }
-
-/**
- * Returns an array of the indexes in given datasource name.
- *
- * @param string $model Name of model to inspect
- * @return array Fields in table. Keys are column and unique
- */
- public function index($model) {
- return false;
- }
-
-/**
- * Generate a database-native schema for the given Schema object
- *
- * @param Model $schema An instance of a subclass of CakeSchema
- * @param string $tableName Optional. If specified only the table name given will be generated.
- * Otherwise, all tables defined in the schema are generated.
- * @return string
- */
- public function createSchema($schema, $tableName = null) {
- if (!is_a($schema, 'CakeSchema')) {
- trigger_error(__d('cake_dev', 'Invalid schema object'), E_USER_WARNING);
- return null;
- }
- $out = '';
-
- foreach ($schema->tables as $curTable => $columns) {
- if (!$tableName || $tableName == $curTable) {
- $cols = $colList = $indexes = $tableParameters = array();
- $primary = null;
- $table = $this->fullTableName($curTable);
-
- foreach ($columns as $name => $col) {
- if (is_string($col)) {
- $col = array('type' => $col);
- }
- if (isset($col['key']) && $col['key'] === 'primary') {
- $primary = $name;
- }
- if ($name !== 'indexes' && $name !== 'tableParameters') {
- $col['name'] = $name;
- if (!isset($col['type'])) {
- $col['type'] = 'string';
- }
- $cols[] = $this->buildColumn($col);
- } elseif ($name === 'indexes') {
- $indexes = array_merge($indexes, $this->buildIndex($col, $table));
- } elseif ($name === 'tableParameters') {
- $tableParameters = array_merge($tableParameters, $this->buildTableParameters($col, $table));
- }
- }
- if (empty($indexes) && !empty($primary)) {
- $col = array('PRIMARY' => array('column' => $primary, 'unique' => 1));
- $indexes = array_merge($indexes, $this->buildIndex($col, $table));
- }
- $columns = $cols;
- $out .= $this->renderStatement('schema', compact('table', 'columns', 'indexes', 'tableParameters')) . "\n\n";
- }
- }
- return $out;
- }
-
-/**
- * Generate a alter syntax from CakeSchema::compare()
- *
- * @param mixed $compare
- * @param string $table
- * @return boolean
- */
- public function alterSchema($compare, $table = null) {
- return false;
- }
-
-/**
- * Generate a "drop table" statement for the given Schema object
- *
- * @param CakeSchema $schema An instance of a subclass of CakeSchema
- * @param string $table Optional. If specified only the table name given will be generated.
- * Otherwise, all tables defined in the schema are generated.
- * @return string
- */
- public function dropSchema(CakeSchema $schema, $table = null) {
- $out = '';
-
- foreach ($schema->tables as $curTable => $columns) {
- if (!$table || $table == $curTable) {
- $out .= 'DROP TABLE ' . $this->fullTableName($curTable) . ";\n";
- }
- }
- return $out;
- }
-
-/**
- * Generate a database-native column schema string
- *
- * @param array $column An array structured like the following: array('name' => 'value', 'type' => 'value'[, options]),
- * where options can be 'default', 'length', or 'key'.
- * @return string
- */
- public function buildColumn($column) {
- $name = $type = null;
- extract(array_merge(array('null' => true), $column));
-
- if (empty($name) || empty($type)) {
- trigger_error(__d('cake_dev', 'Column name or type not defined in schema'), E_USER_WARNING);
- return null;
- }
-
- if (!isset($this->columns[$type])) {
- trigger_error(__d('cake_dev', 'Column type %s does not exist', $type), E_USER_WARNING);
- return null;
- }
-
- $real = $this->columns[$type];
- $out = $this->name($name) . ' ' . $real['name'];
-
- if (isset($column['length'])) {
- $length = $column['length'];
- } elseif (isset($column['limit'])) {
- $length = $column['limit'];
- } elseif (isset($real['length'])) {
- $length = $real['length'];
- } elseif (isset($real['limit'])) {
- $length = $real['limit'];
- }
- if (isset($length)) {
- $out .= '(' . $length . ')';
- }
-
- if (($column['type'] === 'integer' || $column['type'] === 'float') && isset($column['default']) && $column['default'] === '') {
- $column['default'] = null;
- }
- $out = $this->_buildFieldParameters($out, $column, 'beforeDefault');
-
- if (isset($column['key']) && $column['key'] === 'primary' && $type === 'integer') {
- $out .= ' ' . $this->columns['primary_key']['name'];
- } elseif (isset($column['key']) && $column['key'] === 'primary') {
- $out .= ' NOT NULL';
- } elseif (isset($column['default']) && isset($column['null']) && $column['null'] === false) {
- $out .= ' DEFAULT ' . $this->value($column['default'], $type) . ' NOT NULL';
- } elseif (isset($column['default'])) {
- $out .= ' DEFAULT ' . $this->value($column['default'], $type);
- } elseif ($type !== 'timestamp' && !empty($column['null'])) {
- $out .= ' DEFAULT NULL';
- } elseif ($type === 'timestamp' && !empty($column['null'])) {
- $out .= ' NULL';
- } elseif (isset($column['null']) && $column['null'] === false) {
- $out .= ' NOT NULL';
- }
- if ($type === 'timestamp' && isset($column['default']) && strtolower($column['default']) === 'current_timestamp') {
- $out = str_replace(array("'CURRENT_TIMESTAMP'", "'current_timestamp'"), 'CURRENT_TIMESTAMP', $out);
- }
- return $this->_buildFieldParameters($out, $column, 'afterDefault');
- }
-
-/**
- * Build the field parameters, in a position
- *
- * @param string $columnString The partially built column string
- * @param array $columnData The array of column data.
- * @param string $position The position type to use. 'beforeDefault' or 'afterDefault' are common
- * @return string a built column with the field parameters added.
- */
- protected function _buildFieldParameters($columnString, $columnData, $position) {
- foreach ($this->fieldParameters as $paramName => $value) {
- if (isset($columnData[$paramName]) && $value['position'] == $position) {
- if (isset($value['options']) && !in_array($columnData[$paramName], $value['options'])) {
- continue;
- }
- $val = $columnData[$paramName];
- if ($value['quote']) {
- $val = $this->value($val);
- }
- $columnString .= ' ' . $value['value'] . $value['join'] . $val;
- }
- }
- return $columnString;
- }
-
-/**
- * Format indexes for create table
- *
- * @param array $indexes
- * @param string $table
- * @return array
- */
- public function buildIndex($indexes, $table = null) {
- $join = array();
- foreach ($indexes as $name => $value) {
- $out = '';
- if ($name === 'PRIMARY') {
- $out .= 'PRIMARY ';
- $name = null;
- } else {
- if (!empty($value['unique'])) {
- $out .= 'UNIQUE ';
- }
- $name = $this->startQuote . $name . $this->endQuote;
- }
- if (is_array($value['column'])) {
- $out .= 'KEY ' . $name . ' (' . implode(', ', array_map(array(&$this, 'name'), $value['column'])) . ')';
- } else {
- $out .= 'KEY ' . $name . ' (' . $this->name($value['column']) . ')';
- }
- $join[] = $out;
- }
- return $join;
- }
-
-/**
- * Read additional table parameters
- *
- * @param string $name
- * @return array
- */
- public function readTableParameters($name) {
- $parameters = array();
- if (method_exists($this, 'listDetailedSources')) {
- $currentTableDetails = $this->listDetailedSources($name);
- foreach ($this->tableParameters as $paramName => $parameter) {
- if (!empty($parameter['column']) && !empty($currentTableDetails[$parameter['column']])) {
- $parameters[$paramName] = $currentTableDetails[$parameter['column']];
- }
- }
- }
- return $parameters;
- }
-
-/**
- * Format parameters for create table
- *
- * @param array $parameters
- * @param string $table
- * @return array
- */
- public function buildTableParameters($parameters, $table = null) {
- $result = array();
- foreach ($parameters as $name => $value) {
- if (isset($this->tableParameters[$name])) {
- if ($this->tableParameters[$name]['quote']) {
- $value = $this->value($value);
- }
- $result[] = $this->tableParameters[$name]['value'] . $this->tableParameters[$name]['join'] . $value;
- }
- }
- return $result;
- }
-
-/**
- * Guesses the data type of an array
- *
- * @param string $value
- * @return void
- */
- public function introspectType($value) {
- if (!is_array($value)) {
- if (is_bool($value)) {
- return 'boolean';
- }
- if (is_float($value) && floatval($value) === $value) {
- return 'float';
- }
- if (is_int($value) && intval($value) === $value) {
- return 'integer';
- }
- if (is_string($value) && strlen($value) > 255) {
- return 'text';
- }
- return 'string';
- }
-
- $isAllFloat = $isAllInt = true;
- $containsFloat = $containsInt = $containsString = false;
- foreach ($value as $key => $valElement) {
- $valElement = trim($valElement);
- if (!is_float($valElement) && !preg_match('/^[\d]+\.[\d]+$/', $valElement)) {
- $isAllFloat = false;
- } else {
- $containsFloat = true;
- continue;
- }
- if (!is_int($valElement) && !preg_match('/^[\d]+$/', $valElement)) {
- $isAllInt = false;
- } else {
- $containsInt = true;
- continue;
- }
- $containsString = true;
- }
-
- if ($isAllFloat) {
- return 'float';
- }
- if ($isAllInt) {
- return 'integer';
- }
-
- if ($containsInt && !$containsString) {
- return 'integer';
- }
- return 'string';
- }
-
-/**
- * Writes a new key for the in memory sql query cache
- *
- * @param string $sql SQL query
- * @param mixed $data result of $sql query
- * @param array $params query params bound as values
- * @return void
- */
- protected function _writeQueryCache($sql, $data, $params = array()) {
- if (preg_match('/^\s*select/i', $sql)) {
- $this->_queryCache[$sql][serialize($params)] = $data;
- }
- }
-
-/**
- * Returns the result for a sql query if it is already cached
- *
- * @param string $sql SQL query
- * @param array $params query params bound as values
- * @return mixed results for query if it is cached, false otherwise
- */
- public function getQueryCache($sql, $params = array()) {
- if (isset($this->_queryCache[$sql]) && preg_match('/^\s*select/i', $sql)) {
- $serialized = serialize($params);
- if (isset($this->_queryCache[$sql][$serialized])) {
- return $this->_queryCache[$sql][$serialized];
- }
- }
- return false;
- }
-
-/**
- * Used for storing in cache the results of the in-memory methodCache
- *
- */
- public function __destruct() {
- if ($this->_methodCacheChange) {
- Cache::write('method_cache', self::$methodCache, '_cake_core_');
- }
- }
-
-}
diff --git a/lib/Cake/Model/Datasource/Session/CacheSession.php b/lib/Cake/Model/Datasource/Session/CacheSession.php
deleted file mode 100644
index 711b01bab71..00000000000
--- a/lib/Cake/Model/Datasource/Session/CacheSession.php
+++ /dev/null
@@ -1,103 +0,0 @@
- 'Session',
- 'alias' => 'Session',
- 'table' => 'cake_sessions',
- );
- } else {
- $settings = array(
- 'class' => $modelName,
- 'alias' => 'Session',
- );
- }
- $this->_model = ClassRegistry::init($settings);
- $this->_timeout = Configure::read('Session.timeout') * 60;
- }
-
-/**
- * Method called on open of a database session.
- *
- * @return boolean Success
- */
- public function open() {
- return true;
- }
-
-/**
- * Method called on close of a database session.
- *
- * @return boolean Success
- */
- public function close() {
- $probability = mt_rand(1, 150);
- if ($probability <= 3) {
- $this->gc();
- }
- return true;
- }
-
-/**
- * Method used to read from a database session.
- *
- * @param mixed $id The key of the value to read
- * @return mixed The value of the key or false if it does not exist
- */
- public function read($id) {
- $row = $this->_model->find('first', array(
- 'conditions' => array($this->_model->primaryKey => $id)
- ));
-
- if (empty($row[$this->_model->alias]['data'])) {
- return false;
- }
-
- return $row[$this->_model->alias]['data'];
- }
-
-/**
- * Helper function called on write for database sessions.
- *
- * @param integer $id ID that uniquely identifies session in database
- * @param mixed $data The value of the data to be saved.
- * @return boolean True for successful write, false otherwise.
- */
- public function write($id, $data) {
- if (!$id) {
- return false;
- }
- $expires = time() + $this->_timeout;
- $record = compact('id', 'data', 'expires');
- $record[$this->_model->primaryKey] = $id;
- return $this->_model->save($record);
- }
-
-/**
- * Method called on the destruction of a database session.
- *
- * @param integer $id ID that uniquely identifies session in database
- * @return boolean True for successful delete, false otherwise.
- */
- public function destroy($id) {
- return $this->_model->delete($id);
- }
-
-/**
- * Helper function called on gc for database sessions.
- *
- * @param integer $expires Timestamp (defaults to current time)
- * @return boolean Success
- */
- public function gc($expires = null) {
- if (!$expires) {
- $expires = time();
- }
- return $this->_model->deleteAll(array($this->_model->alias . ".expires <" => $expires), false, false);
- }
-
-/**
- * Closes the session before the objects handling it become unavailable
- *
- * @return void
- */
- public function __destruct() {
- try {
- session_write_close();
- } catch (Exception $e) {
- }
- }
-
-}
diff --git a/lib/Cake/Model/I18nModel.php b/lib/Cake/Model/I18nModel.php
deleted file mode 100644
index 9b185064b18..00000000000
--- a/lib/Cake/Model/I18nModel.php
+++ /dev/null
@@ -1,44 +0,0 @@
- table 'users'; class 'Man' => table 'men')
- * The table is required to have at least 'id auto_increment' primary key.
- *
- * @package Cake.Model
- * @link http://book.cakephp.org/2.0/en/models.html
- */
-class Model extends Object implements CakeEventListener {
-
-/**
- * The name of the DataSource connection that this Model uses
- *
- * The value must be an attribute name that you defined in `app/Config/database.php`
- * or created using `ConnectionManager::create()`.
- *
- * @var string
- * @link http://book.cakephp.org/2.0/en/models/model-attributes.html#usedbconfig
- */
- public $useDbConfig = 'default';
-
-/**
- * Custom database table name, or null/false if no table association is desired.
- *
- * @var string
- * @link http://book.cakephp.org/2.0/en/models/model-attributes.html#useTable
- */
- public $useTable = null;
-
-/**
- * Custom display field name. Display fields are used by Scaffold, in SELECT boxes' OPTION elements.
- *
- * This field is also used in `find('list')` when called with no extra parameters in the fields list
- *
- * @var string
- * @link http://book.cakephp.org/2.0/en/models/model-attributes.html#displayField
- */
- public $displayField = null;
-
-/**
- * Value of the primary key ID of the record that this model is currently pointing to.
- * Automatically set after database insertions.
- *
- * @var mixed
- */
- public $id = false;
-
-/**
- * Container for the data that this model gets from persistent storage (usually, a database).
- *
- * @var array
- * @link http://book.cakephp.org/2.0/en/models/model-attributes.html#data
- */
- public $data = array();
-
-/**
- * Holds physical schema/database name for this model. Automatically set during Model creation.
- *
- * @var string
- * @access public
- */
- public $schemaName = null;
-
-/**
- * Table name for this Model.
- *
- * @var string
- */
- public $table = false;
-
-/**
- * The name of the primary key field for this model.
- *
- * @var string
- * @link http://book.cakephp.org/2.0/en/models/model-attributes.html#primaryKey
- */
- public $primaryKey = null;
-
-/**
- * Field-by-field table metadata.
- *
- * @var array
- */
- protected $_schema = null;
-
-/**
- * List of validation rules. It must be an array with the field name as key and using
- * as value one of the following possibilities
- *
- * ### Validating using regular expressions
- *
- * {{{
- * public $validate = array(
- * 'name' => '/^[a-z].+$/i'
- * );
- * }}}
- *
- * ### Validating using methods (no parameters)
- *
- * {{{
- * public $validate = array(
- * 'name' => 'notEmpty'
- * );
- * }}}
- *
- * ### Validating using methods (with parameters)
- *
- * {{{
- * public $validate = array(
- * 'age' => array(
- * 'rule' => array('between', 5, 25)
- * )
- * );
- * }}}
- *
- * ### Validating using custom method
- *
- * {{{
- * public $validate = array(
- * 'password' => array(
- * 'rule' => array('customValidation')
- * )
- * );
- * public function customValidation($data) {
- * // $data will contain array('password' => 'value')
- * if (isset($this->data[$this->alias]['password2'])) {
- * return $this->data[$this->alias]['password2'] === current($data);
- * }
- * return true;
- * }
- * }}}
- *
- * ### Validations with messages
- *
- * The messages will be used in Model::$validationErrors and can be used in the FormHelper
- *
- * {{{
- * public $validate = array(
- * 'age' => array(
- * 'rule' => array('between', 5, 25),
- * 'message' => array('The age must be between %d and %d.')
- * )
- * );
- * }}}
- *
- * ### Multiple validations to the same field
- *
- * {{{
- * public $validate = array(
- * 'login' => array(
- * array(
- * 'rule' => 'alphaNumeric',
- * 'message' => 'Only alphabets and numbers allowed',
- * 'last' => true
- * ),
- * array(
- * 'rule' => array('minLength', 8),
- * 'message' => array('Minimum length of %d characters')
- * )
- * )
- * );
- * }}}
- *
- * ### Valid keys in validations
- *
- * - `rule`: String with method name, regular expression (started by slash) or array with method and parameters
- * - `message`: String with the message or array if have multiple parameters. See http://php.net/sprintf
- * - `last`: Boolean value to indicate if continue validating the others rules if the current fail [Default: true]
- * - `required`: Boolean value to indicate if the field must be present on save
- * - `allowEmpty`: Boolean value to indicate if the field can be empty
- * - `on`: Possible values: `update`, `create`. Indicate to apply this rule only on update or create
- *
- * @var array
- * @link http://book.cakephp.org/2.0/en/models/model-attributes.html#validate
- * @link http://book.cakephp.org/2.0/en/models/data-validation.html
- */
- public $validate = array();
-
-/**
- * List of validation errors.
- *
- * @var array
- */
- public $validationErrors = array();
-
-/**
- * Name of the validation string domain to use when translating validation errors.
- *
- * @var string
- */
- public $validationDomain = null;
-
-/**
- * Database table prefix for tables in model.
- *
- * @var string
- * @link http://book.cakephp.org/2.0/en/models/model-attributes.html#tableprefix
- */
- public $tablePrefix = null;
-
-/**
- * Name of the model.
- *
- * @var string
- * @link http://book.cakephp.org/2.0/en/models/model-attributes.html#name
- */
- public $name = null;
-
-/**
- * Alias name for model.
- *
- * @var string
- */
- public $alias = null;
-
-/**
- * List of table names included in the model description. Used for associations.
- *
- * @var array
- */
- public $tableToModel = array();
-
-/**
- * Whether or not to cache queries for this model. This enables in-memory
- * caching only, the results are not stored beyond the current request.
- *
- * @var boolean
- * @link http://book.cakephp.org/2.0/en/models/model-attributes.html#cacheQueries
- */
- public $cacheQueries = false;
-
-/**
- * Detailed list of belongsTo associations.
- *
- * ### Basic usage
- *
- * `public $belongsTo = array('Group', 'Department');`
- *
- * ### Detailed configuration
- *
- * {{{
- * public $belongsTo = array(
- * 'Group',
- * 'Department' => array(
- * 'className' => 'Department',
- * 'foreignKey' => 'department_id'
- * )
- * );
- * }}}
- *
- * ### Possible keys in association
- *
- * - `className`: the classname of the model being associated to the current model.
- * If you're defining a 'Profile belongsTo User' relationship, the className key should equal 'User.'
- * - `foreignKey`: the name of the foreign key found in the current model. This is
- * especially handy if you need to define multiple belongsTo relationships. The default
- * value for this key is the underscored, singular name of the other model, suffixed with '_id'.
- * - `conditions`: An SQL fragment used to filter related model records. It's good
- * practice to use model names in SQL fragments: 'User.active = 1' is always
- * better than just 'active = 1.'
- * - `type`: the type of the join to use in the SQL query, default is LEFT which
- * may not fit your needs in all situations, INNER may be helpful when you want
- * everything from your main and associated models or nothing at all!(effective
- * when used with some conditions of course). (NB: type value is in lower case - i.e. left, inner)
- * - `fields`: A list of fields to be retrieved when the associated model data is
- * fetched. Returns all fields by default.
- * - `order`: An SQL fragment that defines the sorting order for the returned associated rows.
- * - `counterCache`: If set to true the associated Model will automatically increase or
- * decrease the "[singular_model_name]_count" field in the foreign table whenever you do
- * a save() or delete(). If its a string then its the field name to use. The value in the
- * counter field represents the number of related rows.
- * - `counterScope`: Optional conditions array to use for updating counter cache field.
- *
- * @var array
- * @link http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#belongsto
- */
- public $belongsTo = array();
-
-/**
- * Detailed list of hasOne associations.
- *
- * ### Basic usage
- *
- * `public $hasOne = array('Profile', 'Address');`
- *
- * ### Detailed configuration
- *
- * {{{
- * public $hasOne = array(
- * 'Profile',
- * 'Address' => array(
- * 'className' => 'Address',
- * 'foreignKey' => 'user_id'
- * )
- * );
- * }}}
- *
- * ### Possible keys in association
- *
- * - `className`: the classname of the model being associated to the current model.
- * If you're defining a 'User hasOne Profile' relationship, the className key should equal 'Profile.'
- * - `foreignKey`: the name of the foreign key found in the other model. This is
- * especially handy if you need to define multiple hasOne relationships.
- * The default value for this key is the underscored, singular name of the
- * current model, suffixed with '_id'. In the example above it would default to 'user_id'.
- * - `conditions`: An SQL fragment used to filter related model records. It's good
- * practice to use model names in SQL fragments: "Profile.approved = 1" is
- * always better than just "approved = 1."
- * - `fields`: A list of fields to be retrieved when the associated model data is
- * fetched. Returns all fields by default.
- * - `order`: An SQL fragment that defines the sorting order for the returned associated rows.
- * - `dependent`: When the dependent key is set to true, and the model's delete()
- * method is called with the cascade parameter set to true, associated model
- * records are also deleted. In this case we set it true so that deleting a
- * User will also delete her associated Profile.
- *
- * @var array
- * @link http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasone
- */
- public $hasOne = array();
-
-/**
- * Detailed list of hasMany associations.
- *
- * ### Basic usage
- *
- * `public $hasMany = array('Comment', 'Task');`
- *
- * ### Detailed configuration
- *
- * {{{
- * public $hasMany = array(
- * 'Comment',
- * 'Task' => array(
- * 'className' => 'Task',
- * 'foreignKey' => 'user_id'
- * )
- * );
- * }}}
- *
- * ### Possible keys in association
- *
- * - `className`: the classname of the model being associated to the current model.
- * If you're defining a 'User hasMany Comment' relationship, the className key should equal 'Comment.'
- * - `foreignKey`: the name of the foreign key found in the other model. This is
- * especially handy if you need to define multiple hasMany relationships. The default
- * value for this key is the underscored, singular name of the actual model, suffixed with '_id'.
- * - `conditions`: An SQL fragment used to filter related model records. It's good
- * practice to use model names in SQL fragments: "Comment.status = 1" is always
- * better than just "status = 1."
- * - `fields`: A list of fields to be retrieved when the associated model data is
- * fetched. Returns all fields by default.
- * - `order`: An SQL fragment that defines the sorting order for the returned associated rows.
- * - `limit`: The maximum number of associated rows you want returned.
- * - `offset`: The number of associated rows to skip over (given the current
- * conditions and order) before fetching and associating.
- * - `dependent`: When dependent is set to true, recursive model deletion is
- * possible. In this example, Comment records will be deleted when their
- * associated User record has been deleted.
- * - `exclusive`: When exclusive is set to true, recursive model deletion does
- * the delete with a deleteAll() call, instead of deleting each entity separately.
- * This greatly improves performance, but may not be ideal for all circumstances.
- * - `finderQuery`: A complete SQL query CakePHP can use to fetch associated model
- * records. This should be used in situations that require very custom results.
- *
- * @var array
- * @link http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasmany
- */
- public $hasMany = array();
-
-/**
- * Detailed list of hasAndBelongsToMany associations.
- *
- * ### Basic usage
- *
- * `public $hasAndBelongsToMany = array('Role', 'Address');`
- *
- * ### Detailed configuration
- *
- * {{{
- * public $hasAndBelongsToMany = array(
- * 'Role',
- * 'Address' => array(
- * 'className' => 'Address',
- * 'foreignKey' => 'user_id',
- * 'associationForeignKey' => 'address_id',
- * 'joinTable' => 'addresses_users'
- * )
- * );
- * }}}
- *
- * ### Possible keys in association
- *
- * - `className`: the classname of the model being associated to the current model.
- * If you're defining a 'Recipe HABTM Tag' relationship, the className key should equal 'Tag.'
- * - `joinTable`: The name of the join table used in this association (if the
- * current table doesn't adhere to the naming convention for HABTM join tables).
- * - `with`: Defines the name of the model for the join table. By default CakePHP
- * will auto-create a model for you. Using the example above it would be called
- * RecipesTag. By using this key you can override this default name. The join
- * table model can be used just like any "regular" model to access the join table directly.
- * - `foreignKey`: the name of the foreign key found in the current model.
- * This is especially handy if you need to define multiple HABTM relationships.
- * The default value for this key is the underscored, singular name of the
- * current model, suffixed with '_id'.
- * - `associationForeignKey`: the name of the foreign key found in the other model.
- * This is especially handy if you need to define multiple HABTM relationships.
- * The default value for this key is the underscored, singular name of the other
- * model, suffixed with '_id'.
- * - `unique`: If true (default value) cake will first delete existing relationship
- * records in the foreign keys table before inserting new ones, when updating a
- * record. So existing associations need to be passed again when updating.
- * To prevent deletion of existing relationship records, set this key to a string 'keepExisting'.
- * - `conditions`: An SQL fragment used to filter related model records. It's good
- * practice to use model names in SQL fragments: "Comment.status = 1" is always
- * better than just "status = 1."
- * - `fields`: A list of fields to be retrieved when the associated model data is
- * fetched. Returns all fields by default.
- * - `order`: An SQL fragment that defines the sorting order for the returned associated rows.
- * - `limit`: The maximum number of associated rows you want returned.
- * - `offset`: The number of associated rows to skip over (given the current
- * conditions and order) before fetching and associating.
- * - `finderQuery`, `deleteQuery`, `insertQuery`: A complete SQL query CakePHP
- * can use to fetch, delete, or create new associated model records. This should
- * be used in situations that require very custom results.
- *
- * @var array
- * @link http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasandbelongstomany-habtm
- */
- public $hasAndBelongsToMany = array();
-
-/**
- * List of behaviors to load when the model object is initialized. Settings can be
- * passed to behaviors by using the behavior name as index. Eg:
- *
- * public $actsAs = array('Translate', 'MyBehavior' => array('setting1' => 'value1'))
- *
- * @var array
- * @link http://book.cakephp.org/2.0/en/models/behaviors.html#using-behaviors
- */
- public $actsAs = null;
-
-/**
- * Holds the Behavior objects currently bound to this model.
- *
- * @var BehaviorCollection
- */
- public $Behaviors = null;
-
-/**
- * Whitelist of fields allowed to be saved.
- *
- * @var array
- */
- public $whitelist = array();
-
-/**
- * Whether or not to cache sources for this model.
- *
- * @var boolean
- */
- public $cacheSources = true;
-
-/**
- * Type of find query currently executing.
- *
- * @var string
- */
- public $findQueryType = null;
-
-/**
- * Number of associations to recurse through during find calls. Fetches only
- * the first level by default.
- *
- * @var integer
- * @link http://book.cakephp.org/2.0/en/models/model-attributes.html#recursive
- */
- public $recursive = 1;
-
-/**
- * The column name(s) and direction(s) to order find results by default.
- *
- * public $order = "Post.created DESC";
- * public $order = array("Post.view_count DESC", "Post.rating DESC");
- *
- * @var string
- * @link http://book.cakephp.org/2.0/en/models/model-attributes.html#order
- */
- public $order = null;
-
-/**
- * Array of virtual fields this model has. Virtual fields are aliased
- * SQL expressions. Fields added to this property will be read as other fields in a model
- * but will not be saveable.
- *
- * `public $virtualFields = array('two' => '1 + 1');`
- *
- * Is a simplistic example of how to set virtualFields
- *
- * @var array
- * @link http://book.cakephp.org/2.0/en/models/model-attributes.html#virtualfields
- */
- public $virtualFields = array();
-
-/**
- * Default list of association keys.
- *
- * @var array
- */
- protected $_associationKeys = array(
- 'belongsTo' => array('className', 'foreignKey', 'conditions', 'fields', 'order', 'counterCache'),
- 'hasOne' => array('className', 'foreignKey', 'conditions', 'fields', 'order', 'dependent'),
- 'hasMany' => array('className', 'foreignKey', 'conditions', 'fields', 'order', 'limit', 'offset', 'dependent', 'exclusive', 'finderQuery', 'counterQuery'),
- 'hasAndBelongsToMany' => array('className', 'joinTable', 'with', 'foreignKey', 'associationForeignKey', 'conditions', 'fields', 'order', 'limit', 'offset', 'unique', 'finderQuery', 'deleteQuery', 'insertQuery')
- );
-
-/**
- * Holds provided/generated association key names and other data for all associations.
- *
- * @var array
- */
- protected $_associations = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
-
-/**
- * Holds model associations temporarily to allow for dynamic (un)binding.
- *
- * @var array
- */
- public $__backAssociation = array();
-
-/**
- * Back inner association
- *
- * @var array
- */
- public $__backInnerAssociation = array();
-
-/**
- * Back original association
- *
- * @var array
- */
- public $__backOriginalAssociation = array();
-
-/**
- * Back containable association
- *
- * @var array
- */
- public $__backContainableAssociation = array();
-
-/**
- * The ID of the model record that was last inserted.
- *
- * @var integer
- */
- protected $_insertID = null;
-
-/**
- * Has the datasource been configured.
- *
- * @var boolean
- * @see Model::getDataSource
- */
- protected $_sourceConfigured = false;
-
-/**
- * List of valid finder method options, supplied as the first parameter to find().
- *
- * @var array
- */
- public $findMethods = array(
- 'all' => true, 'first' => true, 'count' => true,
- 'neighbors' => true, 'list' => true, 'threaded' => true
- );
-
-/**
- * Instance of the CakeEventManager this model is using
- * to dispatch inner events.
- *
- * @var CakeEventManager
- */
- protected $_eventManager = null;
-
-/**
- * Constructor. Binds the model's database table to the object.
- *
- * If `$id` is an array it can be used to pass several options into the model.
- *
- * - id - The id to start the model on.
- * - table - The table to use for this model.
- * - ds - The connection name this model is connected to.
- * - name - The name of the model eg. Post.
- * - alias - The alias of the model, this is used for registering the instance in the `ClassRegistry`.
- * eg. `ParentThread`
- *
- * ### Overriding Model's __construct method.
- *
- * When overriding Model::__construct() be careful to include and pass in all 3 of the
- * arguments to `parent::__construct($id, $table, $ds);`
- *
- * ### Dynamically creating models
- *
- * You can dynamically create model instances using the $id array syntax.
- *
- * {{{
- * $Post = new Model(array('table' => 'posts', 'name' => 'Post', 'ds' => 'connection2'));
- * }}}
- *
- * Would create a model attached to the posts table on connection2. Dynamic model creation is useful
- * when you want a model object that contains no associations or attached behaviors.
- *
- * @param mixed $id Set this ID for this model on startup, can also be an array of options, see above.
- * @param string $table Name of database table to use.
- * @param string $ds DataSource connection name.
- */
- public function __construct($id = false, $table = null, $ds = null) {
- parent::__construct();
-
- if (is_array($id)) {
- extract(array_merge(
- array(
- 'id' => $this->id, 'table' => $this->useTable, 'ds' => $this->useDbConfig,
- 'name' => $this->name, 'alias' => $this->alias
- ),
- $id
- ));
- }
-
- if ($this->name === null) {
- $this->name = (isset($name) ? $name : get_class($this));
- }
-
- if ($this->alias === null) {
- $this->alias = (isset($alias) ? $alias : $this->name);
- }
-
- if ($this->primaryKey === null) {
- $this->primaryKey = 'id';
- }
-
- ClassRegistry::addObject($this->alias, $this);
-
- $this->id = $id;
- unset($id);
-
- if ($table === false) {
- $this->useTable = false;
- } elseif ($table) {
- $this->useTable = $table;
- }
-
- if ($ds !== null) {
- $this->useDbConfig = $ds;
- }
-
- if (is_subclass_of($this, 'AppModel')) {
- $merge = array('actsAs', 'findMethods');
- $parentClass = get_parent_class($this);
- if ($parentClass !== 'AppModel') {
- $this->_mergeVars($merge, $parentClass);
- }
- $this->_mergeVars($merge, 'AppModel');
- }
- $this->_mergeVars(array('findMethods'), 'Model');
-
- $this->Behaviors = new BehaviorCollection();
-
- if ($this->useTable !== false) {
-
- if ($this->useTable === null) {
- $this->useTable = Inflector::tableize($this->name);
- }
-
- if ($this->displayField == null) {
- unset($this->displayField);
- }
- $this->table = $this->useTable;
- $this->tableToModel[$this->table] = $this->alias;
- } elseif ($this->table === false) {
- $this->table = Inflector::tableize($this->name);
- }
-
- if ($this->tablePrefix === null) {
- unset($this->tablePrefix);
- }
-
- $this->_createLinks();
- $this->Behaviors->init($this->alias, $this->actsAs);
- }
-
-/**
- * Returns a list of all events that will fire in the model during it's lifecycle.
- * You can override this function to add you own listener callbacks
- *
- * @return array
- */
- public function implementedEvents() {
- return array(
- 'Model.beforeFind' => array('callable' => 'beforeFind', 'passParams' => true),
- 'Model.afterFind' => array('callable' => 'afterFind', 'passParams' => true),
- 'Model.beforeValidate' => array('callable' => 'beforeValidate', 'passParams' => true),
- 'Model.beforeSave' => array('callable' => 'beforeSave', 'passParams' => true),
- 'Model.afterSave' => array('callable' => 'afterSave', 'passParams' => true),
- 'Model.beforeDelete' => array('callable' => 'beforeDelete', 'passParams' => true),
- 'Model.afterDelete' => array('callable' => 'afterDelete'),
- );
- }
-
-/**
- * Returns the CakeEventManager manager instance that is handling any callbacks.
- * You can use this instance to register any new listeners or callbacks to the
- * model events, or create your own events and trigger them at will.
- *
- * @return CakeEventManager
- */
- public function getEventManager() {
- if (empty($this->_eventManager)) {
- $this->_eventManager = new CakeEventManager();
- $this->_eventManager->attach($this->Behaviors);
- $this->_eventManager->attach($this);
- }
- return $this->_eventManager;
- }
-
-/**
- * Handles custom method calls, like findBy for DB models,
- * and custom RPC calls for remote data sources.
- *
- * @param string $method Name of method to call.
- * @param array $params Parameters for the method.
- * @return mixed Whatever is returned by called method
- */
- public function __call($method, $params) {
- $result = $this->Behaviors->dispatchMethod($this, $method, $params);
- if ($result !== array('unhandled')) {
- return $result;
- }
- $return = $this->getDataSource()->query($method, $params, $this);
- return $return;
- }
-
-/**
- * Handles the lazy loading of model associations by looking in the association arrays for the requested variable
- *
- * @param string $name variable tested for existence in class
- * @return boolean true if the variable exists (if is a not loaded model association it will be created), false otherwise
- */
- public function __isset($name) {
- $className = false;
-
- foreach ($this->_associations as $type) {
- if (isset($name, $this->{$type}[$name])) {
- $className = empty($this->{$type}[$name]['className']) ? $name : $this->{$type}[$name]['className'];
- break;
- } elseif (isset($name, $this->__backAssociation[$type][$name])) {
- $className = empty($this->__backAssociation[$type][$name]['className']) ?
- $name : $this->__backAssociation[$type][$name]['className'];
- break;
- } elseif ($type == 'hasAndBelongsToMany') {
- foreach ($this->{$type} as $k => $relation) {
- if (empty($relation['with'])) {
- continue;
- }
- if (is_array($relation['with'])) {
- if (key($relation['with']) === $name) {
- $className = $name;
- }
- } else {
- list($plugin, $class) = pluginSplit($relation['with']);
- if ($class === $name) {
- $className = $relation['with'];
- }
- }
- if ($className) {
- $assocKey = $k;
- $dynamic = !empty($relation['dynamicWith']);
- break(2);
- }
- }
- }
- }
-
- if (!$className) {
- return false;
- }
-
- list($plugin, $className) = pluginSplit($className);
-
- if (!ClassRegistry::isKeySet($className) && !empty($dynamic)) {
- $this->{$className} = new AppModel(array(
- 'name' => $className,
- 'table' => $this->hasAndBelongsToMany[$assocKey]['joinTable'],
- 'ds' => $this->useDbConfig
- ));
- } else {
- $this->_constructLinkedModel($name, $className, $plugin);
- }
-
- if (!empty($assocKey)) {
- $this->hasAndBelongsToMany[$assocKey]['joinTable'] = $this->{$name}->table;
- if (count($this->{$name}->schema()) <= 2 && $this->{$name}->primaryKey !== false) {
- $this->{$name}->primaryKey = $this->hasAndBelongsToMany[$assocKey]['foreignKey'];
- }
- }
-
- return true;
- }
-
-/**
- * Returns the value of the requested variable if it can be set by __isset()
- *
- * @param string $name variable requested for it's value or reference
- * @return mixed value of requested variable if it is set
- */
- public function __get($name) {
- if ($name === 'displayField') {
- return $this->displayField = $this->hasField(array('title', 'name', $this->primaryKey));
- }
- if ($name === 'tablePrefix') {
- $this->setDataSource();
- if (property_exists($this, 'tablePrefix') && !empty($this->tablePrefix)) {
- return $this->tablePrefix;
- }
- return $this->tablePrefix = null;
- }
- if (isset($this->{$name})) {
- return $this->{$name};
- }
- }
-
-/**
- * Bind model associations on the fly.
- *
- * If `$reset` is false, association will not be reset
- * to the originals defined in the model
- *
- * Example: Add a new hasOne binding to the Profile model not
- * defined in the model source code:
- *
- * `$this->User->bindModel( array('hasOne' => array('Profile')) );`
- *
- * Bindings that are not made permanent will be reset by the next Model::find() call on this
- * model.
- *
- * @param array $params Set of bindings (indexed by binding type)
- * @param boolean $reset Set to false to make the binding permanent
- * @return boolean Success
- * @link http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#creating-and-destroying-associations-on-the-fly
- */
- public function bindModel($params, $reset = true) {
- foreach ($params as $assoc => $model) {
- if ($reset === true && !isset($this->__backAssociation[$assoc])) {
- $this->__backAssociation[$assoc] = $this->{$assoc};
- }
- foreach ($model as $key => $value) {
- $assocName = $key;
-
- if (is_numeric($key)) {
- $assocName = $value;
- $value = array();
- }
- $this->{$assoc}[$assocName] = $value;
- if (property_exists($this, $assocName)) {
- unset($this->{$assocName});
- }
- if ($reset === false && isset($this->__backAssociation[$assoc])) {
- $this->__backAssociation[$assoc][$assocName] = $value;
- }
- }
- }
- $this->_createLinks();
- return true;
- }
-
-/**
- * Turn off associations on the fly.
- *
- * If $reset is false, association will not be reset
- * to the originals defined in the model
- *
- * Example: Turn off the associated Model Support request,
- * to temporarily lighten the User model:
- *
- * `$this->User->unbindModel( array('hasMany' => array('Supportrequest')) );`
- *
- * unbound models that are not made permanent will reset with the next call to Model::find()
- *
- * @param array $params Set of bindings to unbind (indexed by binding type)
- * @param boolean $reset Set to false to make the unbinding permanent
- * @return boolean Success
- * @link http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#creating-and-destroying-associations-on-the-fly
- */
- public function unbindModel($params, $reset = true) {
- foreach ($params as $assoc => $models) {
- if ($reset === true && !isset($this->__backAssociation[$assoc])) {
- $this->__backAssociation[$assoc] = $this->{$assoc};
- }
- foreach ($models as $model) {
- if ($reset === false && isset($this->__backAssociation[$assoc][$model])) {
- unset($this->__backAssociation[$assoc][$model]);
- }
- unset($this->{$assoc}[$model]);
- }
- }
- return true;
- }
-
-/**
- * Create a set of associations.
- *
- * @return void
- */
- protected function _createLinks() {
- foreach ($this->_associations as $type) {
- if (!is_array($this->{$type})) {
- $this->{$type} = explode(',', $this->{$type});
-
- foreach ($this->{$type} as $i => $className) {
- $className = trim($className);
- unset ($this->{$type}[$i]);
- $this->{$type}[$className] = array();
- }
- }
-
- if (!empty($this->{$type})) {
- foreach ($this->{$type} as $assoc => $value) {
- $plugin = null;
-
- if (is_numeric($assoc)) {
- unset ($this->{$type}[$assoc]);
- $assoc = $value;
- $value = array();
-
- if (strpos($assoc, '.') !== false) {
- list($plugin, $assoc) = pluginSplit($assoc);
- $this->{$type}[$assoc] = array('className' => $plugin . '.' . $assoc);
- } else {
- $this->{$type}[$assoc] = $value;
- }
- }
- $this->_generateAssociation($type, $assoc);
- }
- }
- }
- }
-
-/**
- * Protected helper method to create associated models of a given class.
- *
- * @param string $assoc Association name
- * @param string $className Class name
- * @param string $plugin name of the plugin where $className is located
- * examples: public $hasMany = array('Assoc' => array('className' => 'ModelName'));
- * usage: $this->Assoc->modelMethods();
- *
- * public $hasMany = array('ModelName');
- * usage: $this->ModelName->modelMethods();
- * @return void
- */
- protected function _constructLinkedModel($assoc, $className = null, $plugin = null) {
- if (empty($className)) {
- $className = $assoc;
- }
-
- if (!isset($this->{$assoc}) || $this->{$assoc}->name !== $className) {
- if ($plugin) {
- $plugin .= '.';
- }
- $model = array('class' => $plugin . $className, 'alias' => $assoc);
- $this->{$assoc} = ClassRegistry::init($model);
- if ($plugin) {
- ClassRegistry::addObject($plugin . $className, $this->{$assoc});
- }
- if ($assoc) {
- $this->tableToModel[$this->{$assoc}->table] = $assoc;
- }
- }
- }
-
-/**
- * Build an array-based association from string.
- *
- * @param string $type 'belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany'
- * @param string $assocKey
- * @return void
- */
- protected function _generateAssociation($type, $assocKey) {
- $class = $assocKey;
- $dynamicWith = false;
-
- foreach ($this->_associationKeys[$type] as $key) {
-
- if (!isset($this->{$type}[$assocKey][$key]) || $this->{$type}[$assocKey][$key] === null) {
- $data = '';
-
- switch ($key) {
- case 'fields':
- $data = '';
- break;
-
- case 'foreignKey':
- $data = (($type == 'belongsTo') ? Inflector::underscore($assocKey) : Inflector::singularize($this->table)) . '_id';
- break;
-
- case 'associationForeignKey':
- $data = Inflector::singularize($this->{$class}->table) . '_id';
- break;
-
- case 'with':
- $data = Inflector::camelize(Inflector::singularize($this->{$type}[$assocKey]['joinTable']));
- $dynamicWith = true;
- break;
-
- case 'joinTable':
- $tables = array($this->table, $this->{$class}->table);
- sort ($tables);
- $data = $tables[0] . '_' . $tables[1];
- break;
-
- case 'className':
- $data = $class;
- break;
-
- case 'unique':
- $data = true;
- break;
- }
- $this->{$type}[$assocKey][$key] = $data;
- }
-
- if ($dynamicWith) {
- $this->{$type}[$assocKey]['dynamicWith'] = true;
- }
-
- }
- }
-
-/**
- * Sets a custom table for your controller class. Used by your controller to select a database table.
- *
- * @param string $tableName Name of the custom table
- * @throws MissingTableException when database table $tableName is not found on data source
- * @return void
- */
- public function setSource($tableName) {
- $this->setDataSource($this->useDbConfig);
- $db = ConnectionManager::getDataSource($this->useDbConfig);
- $db->cacheSources = ($this->cacheSources && $db->cacheSources);
-
- if (method_exists($db, 'listSources')) {
- $sources = $db->listSources();
- if (is_array($sources) && !in_array(strtolower($this->tablePrefix . $tableName), array_map('strtolower', $sources))) {
- throw new MissingTableException(array(
- 'table' => $this->tablePrefix . $tableName,
- 'class' => $this->alias,
- 'ds' => $this->useDbConfig,
- ));
- }
- $this->_schema = null;
- }
- $this->table = $this->useTable = $tableName;
- $this->tableToModel[$this->table] = $this->alias;
- }
-
-/**
- * This function does two things:
- *
- * 1. it scans the array $one for the primary key,
- * and if that's found, it sets the current id to the value of $one[id].
- * For all other keys than 'id' the keys and values of $one are copied to the 'data' property of this object.
- * 2. Returns an array with all of $one's keys and values.
- * (Alternative indata: two strings, which are mangled to
- * a one-item, two-dimensional array using $one for a key and $two as its value.)
- *
- * @param mixed $one Array or string of data
- * @param string $two Value string for the alternative indata method
- * @return array Data with all of $one's keys and values
- * @link http://book.cakephp.org/2.0/en/models/saving-your-data.html
- */
- public function set($one, $two = null) {
- if (!$one) {
- return;
- }
- if (is_object($one)) {
- if ($one instanceof SimpleXMLElement || $one instanceof DOMNode) {
- $one = $this->_normalizeXmlData(Xml::toArray($one));
- } else {
- $one = Set::reverse($one);
- }
- }
-
- if (is_array($one)) {
- $data = $one;
- if (empty($one[$this->alias])) {
- if ($this->getAssociated(key($one)) === null) {
- $data = array($this->alias => $one);
- }
- }
- } else {
- $data = array($this->alias => array($one => $two));
- }
-
- foreach ($data as $modelName => $fieldSet) {
- if (is_array($fieldSet)) {
-
- foreach ($fieldSet as $fieldName => $fieldValue) {
- if (isset($this->validationErrors[$fieldName])) {
- unset ($this->validationErrors[$fieldName]);
- }
-
- if ($modelName === $this->alias) {
- if ($fieldName === $this->primaryKey) {
- $this->id = $fieldValue;
- }
- }
- if (is_array($fieldValue) || is_object($fieldValue)) {
- $fieldValue = $this->deconstruct($fieldName, $fieldValue);
- }
- $this->data[$modelName][$fieldName] = $fieldValue;
- }
- }
- }
- return $data;
- }
-
-/**
- * Normalize Xml::toArray() to use in Model::save()
- *
- * @param array $xml XML as array
- * @return array
- */
- protected function _normalizeXmlData(array $xml) {
- $return = array();
- foreach ($xml as $key => $value) {
- if (is_array($value)) {
- $return[Inflector::camelize($key)] = $this->_normalizeXmlData($value);
- } elseif ($key[0] === '@') {
- $return[substr($key, 1)] = $value;
- } else {
- $return[$key] = $value;
- }
- }
- return $return;
- }
-
-/**
- * Deconstructs a complex data type (array or object) into a single field value.
- *
- * @param string $field The name of the field to be deconstructed
- * @param mixed $data An array or object to be deconstructed into a field
- * @return mixed The resulting data that should be assigned to a field
- */
- public function deconstruct($field, $data) {
- if (!is_array($data)) {
- return $data;
- }
-
- $type = $this->getColumnType($field);
-
- if (in_array($type, array('datetime', 'timestamp', 'date', 'time'))) {
- $useNewDate = (isset($data['year']) || isset($data['month']) ||
- isset($data['day']) || isset($data['hour']) || isset($data['minute']));
-
- $dateFields = array('Y' => 'year', 'm' => 'month', 'd' => 'day', 'H' => 'hour', 'i' => 'min', 's' => 'sec');
- $timeFields = array('H' => 'hour', 'i' => 'min', 's' => 'sec');
- $date = array();
-
- if (isset($data['meridian']) && empty($data['meridian'])) {
- return null;
- }
-
- if (
- isset($data['hour']) &&
- isset($data['meridian']) &&
- !empty($data['hour']) &&
- $data['hour'] != 12 &&
- 'pm' == $data['meridian']
- ) {
- $data['hour'] = $data['hour'] + 12;
- }
- if (isset($data['hour']) && isset($data['meridian']) && $data['hour'] == 12 && 'am' == $data['meridian']) {
- $data['hour'] = '00';
- }
- if ($type == 'time') {
- foreach ($timeFields as $key => $val) {
- if (!isset($data[$val]) || $data[$val] === '0' || $data[$val] === '00') {
- $data[$val] = '00';
- } elseif ($data[$val] !== '') {
- $data[$val] = sprintf('%02d', $data[$val]);
- }
- if (!empty($data[$val])) {
- $date[$key] = $data[$val];
- } else {
- return null;
- }
- }
- }
-
- if ($type == 'datetime' || $type == 'timestamp' || $type == 'date') {
- foreach ($dateFields as $key => $val) {
- if ($val == 'hour' || $val == 'min' || $val == 'sec') {
- if (!isset($data[$val]) || $data[$val] === '0' || $data[$val] === '00') {
- $data[$val] = '00';
- } else {
- $data[$val] = sprintf('%02d', $data[$val]);
- }
- }
- if (!isset($data[$val]) || isset($data[$val]) && (empty($data[$val]) || $data[$val][0] === '-')) {
- return null;
- }
- if (isset($data[$val]) && !empty($data[$val])) {
- $date[$key] = $data[$val];
- }
- }
- }
-
- if ($useNewDate && !empty($date)) {
- $format = $this->getDataSource()->columns[$type]['format'];
- foreach (array('m', 'd', 'H', 'i', 's') as $index) {
- if (isset($date[$index])) {
- $date[$index] = sprintf('%02d', $date[$index]);
- }
- }
- return str_replace(array_keys($date), array_values($date), $format);
- }
- }
- return $data;
- }
-
-/**
- * Returns an array of table metadata (column names and types) from the database.
- * $field => keys(type, null, default, key, length, extra)
- *
- * @param mixed $field Set to true to reload schema, or a string to return a specific field
- * @return array Array of table metadata
- */
- public function schema($field = false) {
- if ($this->useTable !== false && (!is_array($this->_schema) || $field === true)) {
- $db = $this->getDataSource();
- $db->cacheSources = ($this->cacheSources && $db->cacheSources);
- if (method_exists($db, 'describe') && $this->useTable !== false) {
- $this->_schema = $db->describe($this);
- } elseif ($this->useTable === false) {
- $this->_schema = array();
- }
- }
- if (is_string($field)) {
- if (isset($this->_schema[$field])) {
- return $this->_schema[$field];
- } else {
- return null;
- }
- }
- return $this->_schema;
- }
-
-/**
- * Returns an associative array of field names and column types.
- *
- * @return array Field types indexed by field name
- */
- public function getColumnTypes() {
- $columns = $this->schema();
- if (empty($columns)) {
- trigger_error(__d('cake_dev', '(Model::getColumnTypes) Unable to build model field data. If you are using a model without a database table, try implementing schema()'), E_USER_WARNING);
- }
- $cols = array();
- foreach ($columns as $field => $values) {
- $cols[$field] = $values['type'];
- }
- return $cols;
- }
-
-/**
- * Returns the column type of a column in the model.
- *
- * @param string $column The name of the model column
- * @return string Column type
- */
- public function getColumnType($column) {
- $db = $this->getDataSource();
- $cols = $this->schema();
- $model = null;
-
- $column = str_replace(array($db->startQuote, $db->endQuote), '', $column);
-
- if (strpos($column, '.')) {
- list($model, $column) = explode('.', $column);
- }
- if ($model != $this->alias && isset($this->{$model})) {
- return $this->{$model}->getColumnType($column);
- }
- if (isset($cols[$column]) && isset($cols[$column]['type'])) {
- return $cols[$column]['type'];
- }
- return null;
- }
-
-/**
- * Returns true if the supplied field exists in the model's database table.
- *
- * @param mixed $name Name of field to look for, or an array of names
- * @param boolean $checkVirtual checks if the field is declared as virtual
- * @return mixed If $name is a string, returns a boolean indicating whether the field exists.
- * If $name is an array of field names, returns the first field that exists,
- * or false if none exist.
- */
- public function hasField($name, $checkVirtual = false) {
- if (is_array($name)) {
- foreach ($name as $n) {
- if ($this->hasField($n, $checkVirtual)) {
- return $n;
- }
- }
- return false;
- }
-
- if ($checkVirtual && !empty($this->virtualFields)) {
- if ($this->isVirtualField($name)) {
- return true;
- }
- }
-
- if (empty($this->_schema)) {
- $this->schema();
- }
-
- if ($this->_schema != null) {
- return isset($this->_schema[$name]);
- }
- return false;
- }
-
-/**
- * Check that a method is callable on a model. This will check both the model's own methods, its
- * inherited methods and methods that could be callable through behaviors.
- *
- * @param string $method The method to be called.
- * @return boolean True on method being callable.
- */
- public function hasMethod($method) {
- if (method_exists($this, $method)) {
- return true;
- }
- if ($this->Behaviors->hasMethod($method)) {
- return true;
- }
- return false;
- }
-
-/**
- * Returns true if the supplied field is a model Virtual Field
- *
- * @param string $field Name of field to look for
- * @return boolean indicating whether the field exists as a model virtual field.
- */
- public function isVirtualField($field) {
- if (empty($this->virtualFields) || !is_string($field)) {
- return false;
- }
- if (isset($this->virtualFields[$field])) {
- return true;
- }
- if (strpos($field, '.') !== false) {
- list($model, $field) = explode('.', $field);
- if ($model == $this->alias && isset($this->virtualFields[$field])) {
- return true;
- }
- }
- return false;
- }
-
-/**
- * Returns the expression for a model virtual field
- *
- * @param string $field Name of field to look for
- * @return mixed If $field is string expression bound to virtual field $field
- * If $field is null, returns an array of all model virtual fields
- * or false if none $field exist.
- */
- public function getVirtualField($field = null) {
- if ($field == null) {
- return empty($this->virtualFields) ? false : $this->virtualFields;
- }
- if ($this->isVirtualField($field)) {
- if (strpos($field, '.') !== false) {
- list($model, $field) = explode('.', $field);
- }
- return $this->virtualFields[$field];
- }
- return false;
- }
-
-/**
- * Initializes the model for writing a new record, loading the default values
- * for those fields that are not defined in $data, and clearing previous validation errors.
- * Especially helpful for saving data in loops.
- *
- * @param mixed $data Optional data array to assign to the model after it is created. If null or false,
- * schema data defaults are not merged.
- * @param boolean $filterKey If true, overwrites any primary key input with an empty value
- * @return array The current Model::data; after merging $data and/or defaults from database
- * @link http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-create-array-data-array
- */
- public function create($data = array(), $filterKey = false) {
- $defaults = array();
- $this->id = false;
- $this->data = array();
- $this->validationErrors = array();
-
- if ($data !== null && $data !== false) {
- foreach ($this->schema() as $field => $properties) {
- if ($this->primaryKey !== $field && isset($properties['default']) && $properties['default'] !== '') {
- $defaults[$field] = $properties['default'];
- }
- }
- $this->set($defaults);
- $this->set($data);
- }
- if ($filterKey) {
- $this->set($this->primaryKey, false);
- }
- return $this->data;
- }
-
-/**
- * Returns a list of fields from the database, and sets the current model
- * data (Model::$data) with the record found.
- *
- * @param mixed $fields String of single field name, or an array of field names.
- * @param mixed $id The ID of the record to read
- * @return array Array of database fields, or false if not found
- * @link http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#model-read
- */
- public function read($fields = null, $id = null) {
- $this->validationErrors = array();
-
- if ($id != null) {
- $this->id = $id;
- }
-
- $id = $this->id;
-
- if (is_array($this->id)) {
- $id = $this->id[0];
- }
-
- if ($id !== null && $id !== false) {
- $this->data = $this->find('first', array(
- 'conditions' => array($this->alias . '.' . $this->primaryKey => $id),
- 'fields' => $fields
- ));
- return $this->data;
- } else {
- return false;
- }
- }
-
-/**
- * Returns the contents of a single field given the supplied conditions, in the
- * supplied order.
- *
- * @param string $name Name of field to get
- * @param array $conditions SQL conditions (defaults to NULL)
- * @param string $order SQL ORDER BY fragment
- * @return string field contents, or false if not found
- * @link http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#model-field
- */
- public function field($name, $conditions = null, $order = null) {
- if ($conditions === null && $this->id !== false) {
- $conditions = array($this->alias . '.' . $this->primaryKey => $this->id);
- }
- if ($this->recursive >= 1) {
- $recursive = -1;
- } else {
- $recursive = $this->recursive;
- }
- $fields = $name;
- if ($data = $this->find('first', compact('conditions', 'fields', 'order', 'recursive'))) {
- if (strpos($name, '.') === false) {
- if (isset($data[$this->alias][$name])) {
- return $data[$this->alias][$name];
- }
- } else {
- $name = explode('.', $name);
- if (isset($data[$name[0]][$name[1]])) {
- return $data[$name[0]][$name[1]];
- }
- }
- if (isset($data[0]) && count($data[0]) > 0) {
- return array_shift($data[0]);
- }
- } else {
- return false;
- }
- }
-
-/**
- * Saves the value of a single field to the database, based on the current
- * model ID.
- *
- * @param string $name Name of the table field
- * @param mixed $value Value of the field
- * @param array $validate See $options param in Model::save(). Does not respect 'fieldList' key if passed
- * @return boolean See Model::save()
- * @see Model::save()
- * @link http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-savefield-string-fieldname-string-fieldvalue-validate-false
- */
- public function saveField($name, $value, $validate = false) {
- $id = $this->id;
- $this->create(false);
-
- if (is_array($validate)) {
- $options = array_merge(array('validate' => false, 'fieldList' => array($name)), $validate);
- } else {
- $options = array('validate' => $validate, 'fieldList' => array($name));
- }
- return $this->save(array($this->alias => array($this->primaryKey => $id, $name => $value)), $options);
- }
-
-/**
- * Saves model data (based on white-list, if supplied) to the database. By
- * default, validation occurs before save.
- *
- * @param array $data Data to save.
- * @param mixed $validate Either a boolean, or an array.
- * If a boolean, indicates whether or not to validate before saving.
- * If an array, allows control of validate, callbacks, and fieldList
- * @param array $fieldList List of fields to allow to be written
- * @return mixed On success Model::$data if its not empty or true, false on failure
- * @link http://book.cakephp.org/2.0/en/models/saving-your-data.html
- */
- public function save($data = null, $validate = true, $fieldList = array()) {
- $defaults = array('validate' => true, 'fieldList' => array(), 'callbacks' => true);
- $_whitelist = $this->whitelist;
- $fields = array();
-
- if (!is_array($validate)) {
- $options = array_merge($defaults, compact('validate', 'fieldList', 'callbacks'));
- } else {
- $options = array_merge($defaults, $validate);
- }
-
- if (!empty($options['fieldList'])) {
- if (!empty($options['fieldList'][$this->alias]) && is_array($options['fieldList'][$this->alias])) {
- $this->whitelist = $options['fieldList'][$this->alias];
- } else {
- $this->whitelist = $options['fieldList'];
- }
- } elseif ($options['fieldList'] === null) {
- $this->whitelist = array();
- }
- $this->set($data);
-
- if (empty($this->data) && !$this->hasField(array('created', 'updated', 'modified'))) {
- return false;
- }
-
- foreach (array('created', 'updated', 'modified') as $field) {
- $keyPresentAndEmpty = (
- isset($this->data[$this->alias]) &&
- array_key_exists($field, $this->data[$this->alias]) &&
- $this->data[$this->alias][$field] === null
- );
- if ($keyPresentAndEmpty) {
- unset($this->data[$this->alias][$field]);
- }
- }
-
- $exists = $this->exists();
- $dateFields = array('modified', 'updated');
-
- if (!$exists) {
- $dateFields[] = 'created';
- }
- if (isset($this->data[$this->alias])) {
- $fields = array_keys($this->data[$this->alias]);
- }
- if ($options['validate'] && !$this->validates($options)) {
- $this->whitelist = $_whitelist;
- return false;
- }
-
- $db = $this->getDataSource();
-
- foreach ($dateFields as $updateCol) {
- if ($this->hasField($updateCol) && !in_array($updateCol, $fields)) {
- $default = array('formatter' => 'date');
- $colType = array_merge($default, $db->columns[$this->getColumnType($updateCol)]);
- if (!array_key_exists('format', $colType)) {
- $time = strtotime('now');
- } else {
- $time = $colType['formatter']($colType['format']);
- }
- if (!empty($this->whitelist)) {
- $this->whitelist[] = $updateCol;
- }
- $this->set($updateCol, $time);
- }
- }
-
- if ($options['callbacks'] === true || $options['callbacks'] === 'before') {
- $event = new CakeEvent('Model.beforeSave', $this, array($options));
- list($event->break, $event->breakOn) = array(true, array(false, null));
- $this->getEventManager()->dispatch($event);
- if (!$event->result) {
- $this->whitelist = $_whitelist;
- return false;
- }
- }
-
- if (empty($this->data[$this->alias][$this->primaryKey])) {
- unset($this->data[$this->alias][$this->primaryKey]);
- }
- $fields = $values = array();
-
- foreach ($this->data as $n => $v) {
- if (isset($this->hasAndBelongsToMany[$n])) {
- if (isset($v[$n])) {
- $v = $v[$n];
- }
- $joined[$n] = $v;
- } else {
- if ($n === $this->alias) {
- foreach (array('created', 'updated', 'modified') as $field) {
- if (array_key_exists($field, $v) && empty($v[$field])) {
- unset($v[$field]);
- }
- }
-
- foreach ($v as $x => $y) {
- if ($this->hasField($x) && (empty($this->whitelist) || in_array($x, $this->whitelist))) {
- list($fields[], $values[]) = array($x, $y);
- }
- }
- }
- }
- }
- $count = count($fields);
-
- if (!$exists && $count > 0) {
- $this->id = false;
- }
- $success = true;
- $created = false;
-
- if ($count > 0) {
- $cache = $this->_prepareUpdateFields(array_combine($fields, $values));
-
- if (!empty($this->id)) {
- $success = (bool)$db->update($this, $fields, $values);
- } else {
- $fInfo = $this->schema($this->primaryKey);
- $isUUID = ($fInfo['length'] == 36 &&
- ($fInfo['type'] === 'string' || $fInfo['type'] === 'binary')
- );
- if (empty($this->data[$this->alias][$this->primaryKey]) && $isUUID) {
- if (array_key_exists($this->primaryKey, $this->data[$this->alias])) {
- $j = array_search($this->primaryKey, $fields);
- $values[$j] = String::uuid();
- } else {
- list($fields[], $values[]) = array($this->primaryKey, String::uuid());
- }
- }
-
- if (!$db->create($this, $fields, $values)) {
- $success = $created = false;
- } else {
- $created = true;
- }
- }
-
- if ($success && !empty($this->belongsTo)) {
- $this->updateCounterCache($cache, $created);
- }
- }
-
- if (!empty($joined) && $success === true) {
- $this->_saveMulti($joined, $this->id, $db);
- }
-
- if ($success && $count > 0) {
- if (!empty($this->data)) {
- $success = $this->data;
- if ($created) {
- $this->data[$this->alias][$this->primaryKey] = $this->id;
- }
- }
- if ($options['callbacks'] === true || $options['callbacks'] === 'after') {
- $event = new CakeEvent('Model.afterSave', $this, array($created, $options));
- $this->getEventManager()->dispatch($event);
- }
- if (!empty($this->data)) {
- $success = Set::merge($success, $this->data);
- }
- $this->data = false;
- $this->_clearCache();
- $this->validationErrors = array();
- }
- $this->whitelist = $_whitelist;
- return $success;
- }
-
-/**
- * Saves model hasAndBelongsToMany data to the database.
- *
- * @param array $joined Data to save
- * @param mixed $id ID of record in this model
- * @param DataSource $db
- * @return void
- */
- protected function _saveMulti($joined, $id, $db) {
- foreach ($joined as $assoc => $data) {
-
- if (isset($this->hasAndBelongsToMany[$assoc])) {
- list($join) = $this->joinModel($this->hasAndBelongsToMany[$assoc]['with']);
-
- $keyInfo = $this->{$join}->schema($this->{$join}->primaryKey);
- if ($with = $this->hasAndBelongsToMany[$assoc]['with']) {
- $withModel = is_array($with) ? key($with) : $with;
- list($pluginName, $withModel) = pluginSplit($withModel);
- $dbMulti = $this->{$withModel}->getDataSource();
- } else {
- $dbMulti = $db;
- }
-
- $isUUID = !empty($this->{$join}->primaryKey) && (
- $keyInfo['length'] == 36 && (
- $keyInfo['type'] === 'string' ||
- $keyInfo['type'] === 'binary'
- )
- );
-
- $newData = $newValues = $newJoins = array();
- $primaryAdded = false;
-
- $fields = array(
- $dbMulti->name($this->hasAndBelongsToMany[$assoc]['foreignKey']),
- $dbMulti->name($this->hasAndBelongsToMany[$assoc]['associationForeignKey'])
- );
-
- $idField = $db->name($this->{$join}->primaryKey);
- if ($isUUID && !in_array($idField, $fields)) {
- $fields[] = $idField;
- $primaryAdded = true;
- }
-
- foreach ((array)$data as $row) {
- if ((is_string($row) && (strlen($row) == 36 || strlen($row) == 16)) || is_numeric($row)) {
- $newJoins[] = $row;
- $values = array($id, $row);
- if ($isUUID && $primaryAdded) {
- $values[] = String::uuid();
- }
- $newValues[$row] = $values;
- unset($values);
- } elseif (isset($row[$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) {
- if (!empty($row[$this->{$join}->primaryKey])) {
- $newJoins[] = $row[$this->hasAndBelongsToMany[$assoc]['associationForeignKey']];
- }
- $newData[] = $row;
- } elseif (isset($row[$join]) && isset($row[$join][$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) {
- if (!empty($row[$join][$this->{$join}->primaryKey])) {
- $newJoins[] = $row[$join][$this->hasAndBelongsToMany[$assoc]['associationForeignKey']];
- }
- $newData[] = $row[$join];
- }
- }
-
- $keepExisting = $this->hasAndBelongsToMany[$assoc]['unique'] === 'keepExisting';
- if ($this->hasAndBelongsToMany[$assoc]['unique']) {
- $conditions = array(
- $join . '.' . $this->hasAndBelongsToMany[$assoc]['foreignKey'] => $id
- );
- if (!empty($this->hasAndBelongsToMany[$assoc]['conditions'])) {
- $conditions = array_merge($conditions, (array)$this->hasAndBelongsToMany[$assoc]['conditions']);
- }
- $associationForeignKey = $this->{$join}->alias . '.' . $this->hasAndBelongsToMany[$assoc]['associationForeignKey'];
- $links = $this->{$join}->find('all', array(
- 'conditions' => $conditions,
- 'recursive' => empty($this->hasAndBelongsToMany[$assoc]['conditions']) ? -1 : 0,
- 'fields' => $associationForeignKey,
- ));
-
- $oldLinks = Set::extract($links, "{n}.{$associationForeignKey}");
- if (!empty($oldLinks)) {
- if ($keepExisting && !empty($newJoins)) {
- $conditions[$associationForeignKey] = array_diff($oldLinks, $newJoins);
- } else {
- $conditions[$associationForeignKey] = $oldLinks;
- }
- $dbMulti->delete($this->{$join}, $conditions);
- }
- }
-
- if (!empty($newData)) {
- foreach ($newData as $data) {
- $data[$this->hasAndBelongsToMany[$assoc]['foreignKey']] = $id;
- if (empty($data[$this->{$join}->primaryKey])) {
- $this->{$join}->create();
- }
- $this->{$join}->save($data);
- }
- }
-
- if (!empty($newValues)) {
- if ($keepExisting && !empty($links)) {
- foreach ($links as $link) {
- $oldJoin = $link[$join][$this->hasAndBelongsToMany[$assoc]['associationForeignKey']];
- if (! in_array($oldJoin, $newJoins) ) {
- $conditions[$associationForeignKey] = $oldJoin;
- $db->delete($this->{$join}, $conditions);
- } else {
- unset($newValues[$oldJoin]);
- }
- }
- $newValues = array_values($newValues);
- }
- if (!empty($newValues)) {
- $dbMulti->insertMulti($this->{$join}, $fields, $newValues);
- }
- }
- }
- }
- }
-
-/**
- * Updates the counter cache of belongsTo associations after a save or delete operation
- *
- * @param array $keys Optional foreign key data, defaults to the information $this->data
- * @param boolean $created True if a new record was created, otherwise only associations with
- * 'counterScope' defined get updated
- * @return void
- */
- public function updateCounterCache($keys = array(), $created = false) {
- $keys = empty($keys) ? $this->data[$this->alias] : $keys;
- $keys['old'] = isset($keys['old']) ? $keys['old'] : array();
-
- foreach ($this->belongsTo as $parent => $assoc) {
- if (!empty($assoc['counterCache'])) {
- if (!is_array($assoc['counterCache'])) {
- if (isset($assoc['counterScope'])) {
- $assoc['counterCache'] = array($assoc['counterCache'] => $assoc['counterScope']);
- } else {
- $assoc['counterCache'] = array($assoc['counterCache'] => array());
- }
- }
-
- $foreignKey = $assoc['foreignKey'];
- $fkQuoted = $this->escapeField($assoc['foreignKey']);
-
- foreach ($assoc['counterCache'] as $field => $conditions) {
- if (!is_string($field)) {
- $field = Inflector::underscore($this->alias) . '_count';
- }
- if (!$this->{$parent}->hasField($field)) {
- continue;
- }
- if ($conditions === true) {
- $conditions = array();
- } else {
- $conditions = (array)$conditions;
- }
-
- if (!array_key_exists($foreignKey, $keys)) {
- $keys[$foreignKey] = $this->field($foreignKey);
- }
- $recursive = (empty($conditions) ? -1 : 0);
-
- if (isset($keys['old'][$foreignKey])) {
- if ($keys['old'][$foreignKey] != $keys[$foreignKey]) {
- $conditions[$fkQuoted] = $keys['old'][$foreignKey];
- $count = intval($this->find('count', compact('conditions', 'recursive')));
-
- $this->{$parent}->updateAll(
- array($field => $count),
- array($this->{$parent}->escapeField() => $keys['old'][$foreignKey])
- );
- }
- }
- $conditions[$fkQuoted] = $keys[$foreignKey];
-
- if ($recursive === 0) {
- $conditions = array_merge($conditions, (array)$conditions);
- }
- $count = intval($this->find('count', compact('conditions', 'recursive')));
-
- $this->{$parent}->updateAll(
- array($field => $count),
- array($this->{$parent}->escapeField() => $keys[$foreignKey])
- );
- }
- }
- }
- }
-
-/**
- * Helper method for Model::updateCounterCache(). Checks the fields to be updated for
- *
- * @param array $data The fields of the record that will be updated
- * @return array Returns updated foreign key values, along with an 'old' key containing the old
- * values, or empty if no foreign keys are updated.
- */
- protected function _prepareUpdateFields($data) {
- $foreignKeys = array();
- foreach ($this->belongsTo as $assoc => $info) {
- if ($info['counterCache']) {
- $foreignKeys[$assoc] = $info['foreignKey'];
- }
- }
- $included = array_intersect($foreignKeys, array_keys($data));
-
- if (empty($included) || empty($this->id)) {
- return array();
- }
- $old = $this->find('first', array(
- 'conditions' => array($this->alias . '.' . $this->primaryKey => $this->id),
- 'fields' => array_values($included),
- 'recursive' => -1
- ));
- return array_merge($data, array('old' => $old[$this->alias]));
- }
-
-/**
- * Backwards compatible passthrough method for:
- * saveMany(), validateMany(), saveAssociated() and validateAssociated()
- *
- * Saves multiple individual records for a single model; Also works with a single record, as well as
- * all its associated records.
- *
- * #### Options
- *
- * - validate: Set to false to disable validation, true to validate each record before saving,
- * 'first' to validate *all* records before any are saved (default),
- * or 'only' to only validate the records, but not save them.
- * - atomic: If true (default), will attempt to save all records in a single transaction.
- * Should be set to false if database/table does not support transactions.
- * - fieldList: Equivalent to the $fieldList parameter in Model::save().
- * It should be an associate array with model name as key and array of fields as value. Eg.
- * {{{
- * array(
- * 'SomeModel' => array('field'),
- * 'AssociatedModel' => array('field', 'otherfield')
- * )
- * }}}
- * - deep: see saveMany/saveAssociated
- *
- * @param array $data Record data to save. This can be either a numerically-indexed array (for saving multiple
- * records of the same type), or an array indexed by association name.
- * @param array $options Options to use when saving record data, See $options above.
- * @return mixed If atomic: True on success, or false on failure.
- * Otherwise: array similar to the $data array passed, but values are set to true/false
- * depending on whether each record saved successfully.
- * @link http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-saveassociated-array-data-null-array-options-array
- * @link http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-saveall-array-data-null-array-options-array
- */
- public function saveAll($data = null, $options = array()) {
- $options = array_merge(array('validate' => 'first'), $options);
- if (Set::numeric(array_keys($data))) {
- if ($options['validate'] === 'only') {
- return $this->validateMany($data, $options);
- }
- return $this->saveMany($data, $options);
- }
- if ($options['validate'] === 'only') {
- return $this->validateAssociated($data, $options);
- }
- return $this->saveAssociated($data, $options);
- }
-
-/**
- * Saves multiple individual records for a single model
- *
- * #### Options
- *
- * - validate: Set to false to disable validation, true to validate each record before saving,
- * 'first' to validate *all* records before any are saved (default),
- * - atomic: If true (default), will attempt to save all records in a single transaction.
- * Should be set to false if database/table does not support transactions.
- * - fieldList: Equivalent to the $fieldList parameter in Model::save()
- * - deep: If set to true, all associated data will be saved as well.
- *
- * @param array $data Record data to save. This should be a numerically-indexed array
- * @param array $options Options to use when saving record data, See $options above.
- * @return mixed If atomic: True on success, or false on failure.
- * Otherwise: array similar to the $data array passed, but values are set to true/false
- * depending on whether each record saved successfully.
- * @link http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-savemany-array-data-null-array-options-array
- */
- public function saveMany($data = null, $options = array()) {
- if (empty($data)) {
- $data = $this->data;
- }
-
- $options = array_merge(array('validate' => 'first', 'atomic' => true, 'deep' => false), $options);
- $this->validationErrors = $validationErrors = array();
-
- if (empty($data) && $options['validate'] !== false) {
- $result = $this->save($data, $options);
- return !empty($result);
- }
-
- if ($options['validate'] === 'first') {
- $validates = $this->validateMany($data, $options);
- if ((!$validates && $options['atomic']) || (!$options['atomic'] && in_array(false, $validates, true))) {
- return $validates;
- }
- $options['validate'] = true;
- }
-
- if ($options['atomic']) {
- $db = $this->getDataSource();
- $transactionBegun = $db->begin();
- }
- $return = array();
- foreach ($data as $key => $record) {
- $validates = $this->create(null) !== null;
- $saved = false;
- if ($validates) {
- if ($options['deep']) {
- $saved = $this->saveAssociated($record, array_merge($options, array('atomic' => false)));
- } else {
- $saved = $this->save($record, $options);
- }
- }
- $validates = ($validates && ($saved === true || (is_array($saved) && !in_array(false, $saved, true))));
- if (!$validates) {
- $validationErrors[$key] = $this->validationErrors;
- }
- if (!$options['atomic']) {
- $return[$key] = $validates;
- } elseif (!$validates) {
- break;
- }
- }
- $this->validationErrors = $validationErrors;
-
- if (!$options['atomic']) {
- return $return;
- }
- if ($validates) {
- if ($transactionBegun) {
- return $db->commit() !== false;
- } else {
- return true;
- }
- }
- $db->rollback();
- return false;
- }
-
-/**
- * Validates multiple individual records for a single model
- *
- * #### Options
- *
- * - atomic: If true (default), returns boolean. If false returns array.
- * - fieldList: Equivalent to the $fieldList parameter in Model::save()
- * - deep: If set to true, all associated data will be validated as well.
- *
- * @param array $data Record data to validate. This should be a numerically-indexed array
- * @param array $options Options to use when validating record data (see above), See also $options of validates().
- * @return boolean True on success, or false on failure.
- * @return mixed If atomic: True on success, or false on failure.
- * Otherwise: array similar to the $data array passed, but values are set to true/false
- * depending on whether each record validated successfully.
- */
- public function validateMany($data, $options = array()) {
- $options = array_merge(array('atomic' => true, 'deep' => false), $options);
- $this->validationErrors = $validationErrors = $return = array();
- foreach ($data as $key => $record) {
- if ($options['deep']) {
- $validates = $this->validateAssociated($record, $options);
- } else {
- $validates = $this->create($record) && $this->validates($options);
- }
- if ($validates === false || (is_array($validates) && in_array(false, $validates, true))) {
- $validationErrors[$key] = $this->validationErrors;
- $validates = false;
- } else {
- $validates = true;
- }
- $return[$key] = $validates;
- }
- $this->validationErrors = $validationErrors;
- if (!$options['atomic']) {
- return $return;
- }
- if (empty($this->validationErrors)) {
- return true;
- }
- return false;
- }
-
-/**
- * Saves a single record, as well as all its directly associated records.
- *
- * #### Options
- *
- * - `validate` Set to `false` to disable validation, `true` to validate each record before saving,
- * 'first' to validate *all* records before any are saved(default),
- * - `atomic` If true (default), will attempt to save all records in a single transaction.
- * Should be set to false if database/table does not support transactions.
- * - fieldList: Equivalent to the $fieldList parameter in Model::save().
- * It should be an associate array with model name as key and array of fields as value. Eg.
- * {{{
- * array(
- * 'SomeModel' => array('field'),
- * 'AssociatedModel' => array('field', 'otherfield')
- * )
- * }}}
- * - deep: If set to true, not only directly associated data is saved, but deeper nested associated data as well.
- *
- * @param array $data Record data to save. This should be an array indexed by association name.
- * @param array $options Options to use when saving record data, See $options above.
- * @return mixed If atomic: True on success, or false on failure.
- * Otherwise: array similar to the $data array passed, but values are set to true/false
- * depending on whether each record saved successfully.
- * @link http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-saveassociated-array-data-null-array-options-array
- */
- public function saveAssociated($data = null, $options = array()) {
- if (empty($data)) {
- $data = $this->data;
- }
-
- $options = array_merge(array('validate' => 'first', 'atomic' => true, 'deep' => false), $options);
- $this->validationErrors = $validationErrors = array();
-
- if (empty($data) && $options['validate'] !== false) {
- $result = $this->save($data, $options);
- return !empty($result);
- }
-
- if ($options['validate'] === 'first') {
- $validates = $this->validateAssociated($data, $options);
- if ((!$validates && $options['atomic']) || (!$options['atomic'] && in_array(false, $validates, true))) {
- return $validates;
- }
- $options['validate'] = true;
- }
- if ($options['atomic']) {
- $db = $this->getDataSource();
- $transactionBegun = $db->begin();
- }
- $associations = $this->getAssociated();
- $return = array();
- $validates = true;
- foreach ($data as $association => $values) {
- if (isset($associations[$association]) && $associations[$association] === 'belongsTo') {
- $validates = $this->{$association}->create(null) !== null;
- $saved = false;
- if ($validates) {
- if ($options['deep']) {
- $saved = $this->{$association}->saveAssociated($values, array_merge($options, array('atomic' => false)));
- } else {
- $saved = $this->{$association}->save($values, array_merge($options, array('atomic' => false)));
- }
- $validates = ($saved === true || (is_array($saved) && !in_array(false, $saved, true)));
- }
- if ($validates) {
- $key = $this->belongsTo[$association]['foreignKey'];
- if (isset($data[$this->alias])) {
- $data[$this->alias][$key] = $this->{$association}->id;
- } else {
- $data = array_merge(array($key => $this->{$association}->id), $data, array($key => $this->{$association}->id));
- }
- } else {
- $validationErrors[$association] = $this->{$association}->validationErrors;
- }
- $return[$association] = $validates;
- }
- }
- if ($validates && !($this->create(null) !== null && $this->save($data, $options))) {
- $validationErrors[$this->alias] = $this->validationErrors;
- $validates = false;
- }
- $return[$this->alias] = $validates;
-
- foreach ($data as $association => $values) {
- if (!$validates) {
- break;
- }
- if (isset($associations[$association])) {
- $type = $associations[$association];
- $key = $this->{$type}[$association]['foreignKey'];
- switch ($type) {
- case 'hasOne':
- if (isset($values[$association])) {
- $values[$association][$key] = $this->id;
- } else {
- $values = array_merge(array($key => $this->id), $values, array($key => $this->id));
- }
- $validates = $this->{$association}->create(null) !== null;
- $saved = false;
- if ($validates) {
- if ($options['deep']) {
- $saved = $this->{$association}->saveAssociated($values, array_merge($options, array('atomic' => false)));
- } else {
- $saved = $this->{$association}->save($values, $options);
- }
- }
- $validates = ($validates && ($saved === true || (is_array($saved) && !in_array(false, $saved, true))));
- if (!$validates) {
- $validationErrors[$association] = $this->{$association}->validationErrors;
- }
- $return[$association] = $validates;
- break;
- case 'hasMany':
- foreach ($values as $i => $value) {
- if (isset($values[$i][$association])) {
- $values[$i][$association][$key] = $this->id;
- } else {
- $values[$i] = array_merge(array($key => $this->id), $value, array($key => $this->id));
- }
- }
- $_return = $this->{$association}->saveMany($values, array_merge($options, array('atomic' => false)));
- if (in_array(false, $_return, true)) {
- $validationErrors[$association] = $this->{$association}->validationErrors;
- $validates = false;
- }
- $return[$association] = $_return;
- break;
- }
- }
- }
- $this->validationErrors = $validationErrors;
-
- if (isset($validationErrors[$this->alias])) {
- $this->validationErrors = $validationErrors[$this->alias];
- }
-
- if (!$options['atomic']) {
- return $return;
- }
- if ($validates) {
- if ($transactionBegun) {
- return $db->commit() !== false;
- } else {
- return true;
- }
- }
- $db->rollback();
- return false;
- }
-
-/**
- * Validates a single record, as well as all its directly associated records.
- *
- * #### Options
- *
- * - atomic: If true (default), returns boolean. If false returns array.
- * - fieldList: Equivalent to the $fieldList parameter in Model::save()
- * - deep: If set to true, not only directly associated data , but deeper nested associated data is validated as well.
- *
- * @param array $data Record data to validate. This should be an array indexed by association name.
- * @param array $options Options to use when validating record data (see above), See also $options of validates().
- * @return array|boolean If atomic: True on success, or false on failure.
- * Otherwise: array similar to the $data array passed, but values are set to true/false
- * depending on whether each record validated successfully.
- */
- public function validateAssociated($data, $options = array()) {
- $options = array_merge(array('atomic' => true, 'deep' => false), $options);
- $this->validationErrors = $validationErrors = $return = array();
- if (!($this->create($data) && $this->validates($options))) {
- $validationErrors[$this->alias] = $this->validationErrors;
- $return[$this->alias] = false;
- } else {
- $return[$this->alias] = true;
- }
- $associations = $this->getAssociated();
- foreach ($data as $association => $values) {
- $validates = true;
- if (isset($associations[$association])) {
- if (in_array($associations[$association], array('belongsTo', 'hasOne'))) {
- if ($options['deep']) {
- $validates = $this->{$association}->validateAssociated($values, $options);
- } else {
- $validates = $this->{$association}->create($values) !== null && $this->{$association}->validates($options);
- }
- if (is_array($validates)) {
- if (in_array(false, $validates, true)) {
- $validates = false;
- } else {
- $validates = true;
- }
- }
- $return[$association] = $validates;
- } elseif ($associations[$association] === 'hasMany') {
- $validates = $this->{$association}->validateMany($values, $options);
- $return[$association] = $validates;
- }
- if (!$validates || (is_array($validates) && in_array(false, $validates, true))) {
- $validationErrors[$association] = $this->{$association}->validationErrors;
- }
- }
- }
-
- $this->validationErrors = $validationErrors;
- if (isset($validationErrors[$this->alias])) {
- $this->validationErrors = $validationErrors[$this->alias];
- }
- if (!$options['atomic']) {
- return $return;
- }
- if ($return[$this->alias] === false || !empty($this->validationErrors)) {
- return false;
- }
- return true;
- }
-
-/**
- * Updates multiple model records based on a set of conditions.
- *
- * @param array $fields Set of fields and values, indexed by fields.
- * Fields are treated as SQL snippets, to insert literal values manually escape your data.
- * @param mixed $conditions Conditions to match, true for all records
- * @return boolean True on success, false on failure
- * @link http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-updateall-array-fields-array-conditions
- */
- public function updateAll($fields, $conditions = true) {
- return $this->getDataSource()->update($this, $fields, null, $conditions);
- }
-
-/**
- * Removes record for given ID. If no ID is given, the current ID is used. Returns true on success.
- *
- * @param mixed $id ID of record to delete
- * @param boolean $cascade Set to true to delete records that depend on this record
- * @return boolean True on success
- * @link http://book.cakephp.org/2.0/en/models/deleting-data.html
- */
- public function delete($id = null, $cascade = true) {
- if (!empty($id)) {
- $this->id = $id;
- }
- $id = $this->id;
-
- $event = new CakeEvent('Model.beforeDelete', $this, array($cascade));
- list($event->break, $event->breakOn) = array(true, array(false, null));
- $this->getEventManager()->dispatch($event);
- if (!$event->isStopped()) {
- if (!$this->exists()) {
- return false;
- }
- $db = $this->getDataSource();
-
- $this->_deleteDependent($id, $cascade);
- $this->_deleteLinks($id);
- $this->id = $id;
-
- $updateCounterCache = false;
- if (!empty($this->belongsTo)) {
- foreach ($this->belongsTo as $parent => $assoc) {
- if (!empty($assoc['counterCache'])) {
- $updateCounterCache = true;
- break;
- }
- }
-
- $keys = $this->find('first', array(
- 'fields' => $this->_collectForeignKeys(),
- 'conditions' => array($this->alias . '.' . $this->primaryKey => $id),
- 'recursive' => -1,
- 'callbacks' => false
- ));
- }
-
- if ($db->delete($this, array($this->alias . '.' . $this->primaryKey => $id))) {
- if ($updateCounterCache) {
- $this->updateCounterCache($keys[$this->alias]);
- }
- $this->getEventManager()->dispatch(new CakeEvent('Model.afterDelete', $this));
- $this->_clearCache();
- $this->id = false;
- return true;
- }
- }
- return false;
- }
-
-/**
- * Cascades model deletes through associated hasMany and hasOne child records.
- *
- * @param string $id ID of record that was deleted
- * @param boolean $cascade Set to true to delete records that depend on this record
- * @return void
- */
- protected function _deleteDependent($id, $cascade) {
- if (!empty($this->__backAssociation)) {
- $savedAssociatons = $this->__backAssociation;
- $this->__backAssociation = array();
- }
- if ($cascade === true) {
- foreach (array_merge($this->hasMany, $this->hasOne) as $assoc => $data) {
- if ($data['dependent'] === true) {
-
- $model = $this->{$assoc};
-
- if ($data['foreignKey'] === false && $data['conditions'] && in_array($this->name, $model->getAssociated('belongsTo'))) {
- $model->recursive = 0;
- $conditions = array($this->escapeField(null, $this->name) => $id);
- } else {
- $model->recursive = -1;
- $conditions = array($model->escapeField($data['foreignKey']) => $id);
- if ($data['conditions']) {
- $conditions = array_merge((array)$data['conditions'], $conditions);
- }
- }
-
- if (isset($data['exclusive']) && $data['exclusive']) {
- $model->deleteAll($conditions);
- } else {
- $records = $model->find('all', array(
- 'conditions' => $conditions, 'fields' => $model->primaryKey
- ));
-
- if (!empty($records)) {
- foreach ($records as $record) {
- $model->delete($record[$model->alias][$model->primaryKey]);
- }
- }
- }
- }
- }
- }
- if (isset($savedAssociatons)) {
- $this->__backAssociation = $savedAssociatons;
- }
- }
-
-/**
- * Cascades model deletes through HABTM join keys.
- *
- * @param string $id ID of record that was deleted
- * @return void
- */
- protected function _deleteLinks($id) {
- foreach ($this->hasAndBelongsToMany as $assoc => $data) {
- list($plugin, $joinModel) = pluginSplit($data['with']);
- $records = $this->{$joinModel}->find('all', array(
- 'conditions' => array($this->{$joinModel}->escapeField($data['foreignKey']) => $id),
- 'fields' => $this->{$joinModel}->primaryKey,
- 'recursive' => -1,
- 'callbacks' => false
- ));
- if (!empty($records)) {
- foreach ($records as $record) {
- $this->{$joinModel}->delete($record[$this->{$joinModel}->alias][$this->{$joinModel}->primaryKey]);
- }
- }
- }
- }
-
-/**
- * Deletes multiple model records based on a set of conditions.
- *
- * @param mixed $conditions Conditions to match
- * @param boolean $cascade Set to true to delete records that depend on this record
- * @param boolean $callbacks Run callbacks
- * @return boolean True on success, false on failure
- * @link http://book.cakephp.org/2.0/en/models/deleting-data.html#deleteall
- */
- public function deleteAll($conditions, $cascade = true, $callbacks = false) {
- if (empty($conditions)) {
- return false;
- }
- $db = $this->getDataSource();
-
- if (!$cascade && !$callbacks) {
- return $db->delete($this, $conditions);
- } else {
- $ids = $this->find('all', array_merge(array(
- 'fields' => "{$this->alias}.{$this->primaryKey}",
- 'recursive' => 0), compact('conditions'))
- );
- if ($ids === false) {
- return false;
- }
-
- $ids = Set::extract($ids, "{n}.{$this->alias}.{$this->primaryKey}");
- if (empty($ids)) {
- return true;
- }
-
- if ($callbacks) {
- $_id = $this->id;
- $result = true;
- foreach ($ids as $id) {
- $result = ($result && $this->delete($id, $cascade));
- }
- $this->id = $_id;
- return $result;
- } else {
- foreach ($ids as $id) {
- $this->_deleteLinks($id);
- if ($cascade) {
- $this->_deleteDependent($id, $cascade);
- }
- }
- return $db->delete($this, array($this->alias . '.' . $this->primaryKey => $ids));
- }
- }
- }
-
-/**
- * Collects foreign keys from associations.
- *
- * @param string $type
- * @return array
- */
- protected function _collectForeignKeys($type = 'belongsTo') {
- $result = array();
-
- foreach ($this->{$type} as $assoc => $data) {
- if (isset($data['foreignKey']) && is_string($data['foreignKey'])) {
- $result[$assoc] = $data['foreignKey'];
- }
- }
- return $result;
- }
-
-/**
- * Returns true if a record with particular ID exists.
- *
- * If $id is not passed it calls Model::getID() to obtain the current record ID,
- * and then performs a Model::find('count') on the currently configured datasource
- * to ascertain the existence of the record in persistent storage.
- *
- * @param mixed $id ID of record to check for existence
- * @return boolean True if such a record exists
- */
- public function exists($id = null) {
- if ($id === null) {
- $id = $this->getID();
- }
- if ($id === false) {
- return false;
- }
- $conditions = array($this->alias . '.' . $this->primaryKey => $id);
- $query = array('conditions' => $conditions, 'recursive' => -1, 'callbacks' => false);
- return ($this->find('count', $query) > 0);
- }
-
-/**
- * Returns true if a record that meets given conditions exists.
- *
- * @param array $conditions SQL conditions array
- * @return boolean True if such a record exists
- */
- public function hasAny($conditions = null) {
- return ($this->find('count', array('conditions' => $conditions, 'recursive' => -1)) != false);
- }
-
-/**
- * Queries the datasource and returns a result set array.
- *
- * Also used to perform notation finds, where the first argument is type of find operation to perform
- * (all / first / count / neighbors / list / threaded),
- * second parameter options for finding ( indexed array, including: 'conditions', 'limit',
- * 'recursive', 'page', 'fields', 'offset', 'order')
- *
- * Eg:
- * {{{
- * find('all', array(
- * 'conditions' => array('name' => 'Thomas Anderson'),
- * 'fields' => array('name', 'email'),
- * 'order' => 'field3 DESC',
- * 'recursive' => 2,
- * 'group' => 'type'
- * ));
- * }}}
- *
- * In addition to the standard query keys above, you can provide Datasource, and behavior specific
- * keys. For example, when using a SQL based datasource you can use the joins key to specify additional
- * joins that should be part of the query.
- *
- * {{{
- * find('all', array(
- * 'conditions' => array('name' => 'Thomas Anderson'),
- * 'joins' => array(
- * array(
- * 'alias' => 'Thought',
- * 'table' => 'thoughts',
- * 'type' => 'LEFT',
- * 'conditions' => '`Thought`.`person_id` = `Person`.`id`'
- * )
- * )
- * ));
- * }}}
- *
- * Behaviors and find types can also define custom finder keys which are passed into find().
- *
- * Specifying 'fields' for notation 'list':
- *
- * - If no fields are specified, then 'id' is used for key and 'model->displayField' is used for value.
- * - If a single field is specified, 'id' is used for key and specified field is used for value.
- * - If three fields are specified, they are used (in order) for key, value and group.
- * - Otherwise, first and second fields are used for key and value.
- *
- * Note: find(list) + database views have issues with MySQL 5.0. Try upgrading to MySQL 5.1 if you
- * have issues with database views.
- * @param string $type Type of find operation (all / first / count / neighbors / list / threaded)
- * @param array $query Option fields (conditions / fields / joins / limit / offset / order / page / group / callbacks)
- * @return array Array of records
- * @link http://book.cakephp.org/2.0/en/models/deleting-data.html#deleteall
- */
- public function find($type = 'first', $query = array()) {
- $this->findQueryType = $type;
- $this->id = $this->getID();
-
- $query = $this->buildQuery($type, $query);
- if (is_null($query)) {
- return null;
- }
-
- $results = $this->getDataSource()->read($this, $query);
- $this->resetAssociations();
-
- if ($query['callbacks'] === true || $query['callbacks'] === 'after') {
- $results = $this->_filterResults($results);
- }
-
- $this->findQueryType = null;
-
- if ($type === 'all') {
- return $results;
- } else {
- if ($this->findMethods[$type] === true) {
- return $this->{'_find' . ucfirst($type)}('after', $query, $results);
- }
- }
- }
-
-/**
- * Builds the query array that is used by the data source to generate the query to fetch the data.
- *
- * @param string $type Type of find operation (all / first / count / neighbors / list / threaded)
- * @param array $query Option fields (conditions / fields / joins / limit / offset / order / page / group / callbacks)
- * @return array Query array or null if it could not be build for some reasons
- * @see Model::find()
- */
- public function buildQuery($type = 'first', $query = array()) {
- $query = array_merge(
- array(
- 'conditions' => null, 'fields' => null, 'joins' => array(), 'limit' => null,
- 'offset' => null, 'order' => null, 'page' => 1, 'group' => null, 'callbacks' => true,
- ),
- (array)$query
- );
-
- if ($type !== 'all') {
- if ($this->findMethods[$type] === true) {
- $query = $this->{'_find' . ucfirst($type)}('before', $query);
- }
- }
-
- if (!is_numeric($query['page']) || intval($query['page']) < 1) {
- $query['page'] = 1;
- }
- if ($query['page'] > 1 && !empty($query['limit'])) {
- $query['offset'] = ($query['page'] - 1) * $query['limit'];
- }
- if ($query['order'] === null && $this->order !== null) {
- $query['order'] = $this->order;
- }
- $query['order'] = array($query['order']);
-
- if ($query['callbacks'] === true || $query['callbacks'] === 'before') {
- $event = new CakeEvent('Model.beforeFind', $this, array($query));
- list($event->break, $event->breakOn, $event->modParams) = array(true, array(false, null), 0);
- $this->getEventManager()->dispatch($event);
- if ($event->isStopped()) {
- return null;
- }
- $query = $event->result === true ? $event->data[0] : $event->result;
- }
-
- return $query;
- }
-
-/**
- * Handles the before/after filter logic for find('first') operations. Only called by Model::find().
- *
- * @param string $state Either "before" or "after"
- * @param array $query
- * @param array $results
- * @return array
- * @see Model::find()
- */
- protected function _findFirst($state, $query, $results = array()) {
- if ($state === 'before') {
- $query['limit'] = 1;
- return $query;
- } elseif ($state === 'after') {
- if (empty($results[0])) {
- return false;
- }
- return $results[0];
- }
- }
-
-/**
- * Handles the before/after filter logic for find('count') operations. Only called by Model::find().
- *
- * @param string $state Either "before" or "after"
- * @param array $query
- * @param array $results
- * @return integer The number of records found, or false
- * @see Model::find()
- */
- protected function _findCount($state, $query, $results = array()) {
- if ($state === 'before') {
- $db = $this->getDataSource();
- $query['order'] = false;
- if (!method_exists($db, 'calculate') || !method_exists($db, 'expression')) {
- return $query;
- }
- if (empty($query['fields'])) {
- $query['fields'] = $db->calculate($this, 'count');
- } elseif (is_string($query['fields']) && !preg_match('/count/i', $query['fields'])) {
- $query['fields'] = $db->calculate($this, 'count', array(
- $db->expression($query['fields']), 'count'
- ));
- }
- return $query;
- } elseif ($state === 'after') {
- foreach (array(0, $this->alias) as $key) {
- if (isset($results[0][$key]['count'])) {
- if (($count = count($results)) > 1) {
- return $count;
- } else {
- return intval($results[0][$key]['count']);
- }
- }
- }
- return false;
- }
- }
-
-/**
- * Handles the before/after filter logic for find('list') operations. Only called by Model::find().
- *
- * @param string $state Either "before" or "after"
- * @param array $query
- * @param array $results
- * @return array Key/value pairs of primary keys/display field values of all records found
- * @see Model::find()
- */
- protected function _findList($state, $query, $results = array()) {
- if ($state === 'before') {
- if (empty($query['fields'])) {
- $query['fields'] = array("{$this->alias}.{$this->primaryKey}", "{$this->alias}.{$this->displayField}");
- $list = array("{n}.{$this->alias}.{$this->primaryKey}", "{n}.{$this->alias}.{$this->displayField}", null);
- } else {
- if (!is_array($query['fields'])) {
- $query['fields'] = String::tokenize($query['fields']);
- }
-
- if (count($query['fields']) === 1) {
- if (strpos($query['fields'][0], '.') === false) {
- $query['fields'][0] = $this->alias . '.' . $query['fields'][0];
- }
-
- $list = array("{n}.{$this->alias}.{$this->primaryKey}", '{n}.' . $query['fields'][0], null);
- $query['fields'] = array("{$this->alias}.{$this->primaryKey}", $query['fields'][0]);
- } elseif (count($query['fields']) === 3) {
- for ($i = 0; $i < 3; $i++) {
- if (strpos($query['fields'][$i], '.') === false) {
- $query['fields'][$i] = $this->alias . '.' . $query['fields'][$i];
- }
- }
-
- $list = array('{n}.' . $query['fields'][0], '{n}.' . $query['fields'][1], '{n}.' . $query['fields'][2]);
- } else {
- for ($i = 0; $i < 2; $i++) {
- if (strpos($query['fields'][$i], '.') === false) {
- $query['fields'][$i] = $this->alias . '.' . $query['fields'][$i];
- }
- }
-
- $list = array('{n}.' . $query['fields'][0], '{n}.' . $query['fields'][1], null);
- }
- }
- if (!isset($query['recursive']) || $query['recursive'] === null) {
- $query['recursive'] = -1;
- }
- list($query['list']['keyPath'], $query['list']['valuePath'], $query['list']['groupPath']) = $list;
- return $query;
- } elseif ($state === 'after') {
- if (empty($results)) {
- return array();
- }
- $lst = $query['list'];
- return Set::combine($results, $lst['keyPath'], $lst['valuePath'], $lst['groupPath']);
- }
- }
-
-/**
- * Detects the previous field's value, then uses logic to find the 'wrapping'
- * rows and return them.
- *
- * @param string $state Either "before" or "after"
- * @param mixed $query
- * @param array $results
- * @return array
- */
- protected function _findNeighbors($state, $query, $results = array()) {
- if ($state === 'before') {
- extract($query);
- $conditions = (array)$conditions;
- if (isset($field) && isset($value)) {
- if (strpos($field, '.') === false) {
- $field = $this->alias . '.' . $field;
- }
- } else {
- $field = $this->alias . '.' . $this->primaryKey;
- $value = $this->id;
- }
- $query['conditions'] = array_merge($conditions, array($field . ' <' => $value));
- $query['order'] = $field . ' DESC';
- $query['limit'] = 1;
- $query['field'] = $field;
- $query['value'] = $value;
- return $query;
- } elseif ($state === 'after') {
- extract($query);
- unset($query['conditions'][$field . ' <']);
- $return = array();
- if (isset($results[0])) {
- $prevVal = Set::extract('/' . str_replace('.', '/', $field), $results[0]);
- $query['conditions'][$field . ' >='] = $prevVal[0];
- $query['conditions'][$field . ' !='] = $value;
- $query['limit'] = 2;
- } else {
- $return['prev'] = null;
- $query['conditions'][$field . ' >'] = $value;
- $query['limit'] = 1;
- }
- $query['order'] = $field . ' ASC';
- $return2 = $this->find('all', $query);
- if (!array_key_exists('prev', $return)) {
- $return['prev'] = $return2[0];
- }
- if (count($return2) === 2) {
- $return['next'] = $return2[1];
- } elseif (count($return2) === 1 && !$return['prev']) {
- $return['next'] = $return2[0];
- } else {
- $return['next'] = null;
- }
- return $return;
- }
- }
-
-/**
- * In the event of ambiguous results returned (multiple top level results, with different parent_ids)
- * top level results with different parent_ids to the first result will be dropped
- *
- * @param mixed $state
- * @param mixed $query
- * @param array $results
- * @return array Threaded results
- */
- protected function _findThreaded($state, $query, $results = array()) {
- if ($state === 'before') {
- return $query;
- } elseif ($state === 'after') {
- $parent = 'parent_id';
- if (isset($query['parent'])) {
- $parent = $query['parent'];
- }
- return Set::nest($results, array(
- 'idPath' => '/' . $this->alias . '/' . $this->primaryKey,
- 'parentPath' => '/' . $this->alias . '/' . $parent
- ));
- }
- }
-
-/**
- * Passes query results through model and behavior afterFilter() methods.
- *
- * @param array $results Results to filter
- * @param boolean $primary If this is the primary model results (results from model where the find operation was performed)
- * @return array Set of filtered results
- */
- protected function _filterResults($results, $primary = true) {
- $event = new CakeEvent('Model.afterFind', $this, array($results, $primary));
- $event->modParams = 0;
- $this->getEventManager()->dispatch($event);
- return $event->result;
- }
-
-/**
- * This resets the association arrays for the model back
- * to those originally defined in the model. Normally called at the end
- * of each call to Model::find()
- *
- * @return boolean Success
- */
- public function resetAssociations() {
- if (!empty($this->__backAssociation)) {
- foreach ($this->_associations as $type) {
- if (isset($this->__backAssociation[$type])) {
- $this->{$type} = $this->__backAssociation[$type];
- }
- }
- $this->__backAssociation = array();
- }
-
- foreach ($this->_associations as $type) {
- foreach ($this->{$type} as $key => $name) {
- if (property_exists($this, $key) && !empty($this->{$key}->__backAssociation)) {
- $this->{$key}->resetAssociations();
- }
- }
- }
- $this->__backAssociation = array();
- return true;
- }
-
-/**
- * Returns false if any fields passed match any (by default, all if $or = false) of their matching values.
- *
- * @param array $fields Field/value pairs to search (if no values specified, they are pulled from $this->data)
- * @param boolean $or If false, all fields specified must match in order for a false return value
- * @return boolean False if any records matching any fields are found
- */
- public function isUnique($fields, $or = true) {
- if (!is_array($fields)) {
- $fields = func_get_args();
- if (is_bool($fields[count($fields) - 1])) {
- $or = $fields[count($fields) - 1];
- unset($fields[count($fields) - 1]);
- }
- }
-
- foreach ($fields as $field => $value) {
- if (is_numeric($field)) {
- unset($fields[$field]);
-
- $field = $value;
- if (isset($this->data[$this->alias][$field])) {
- $value = $this->data[$this->alias][$field];
- } else {
- $value = null;
- }
- }
-
- if (strpos($field, '.') === false) {
- unset($fields[$field]);
- $fields[$this->alias . '.' . $field] = $value;
- }
- }
- if ($or) {
- $fields = array('or' => $fields);
- }
- if (!empty($this->id)) {
- $fields[$this->alias . '.' . $this->primaryKey . ' !='] = $this->id;
- }
- return ($this->find('count', array('conditions' => $fields, 'recursive' => -1)) == 0);
- }
-
-/**
- * Returns a resultset for a given SQL statement. Custom SQL queries should be performed with this method.
- *
- * @param string $sql,... SQL statement
- * @return array Resultset
- * @link http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#model-query
- */
- public function query($sql) {
- $params = func_get_args();
- $db = $this->getDataSource();
- return call_user_func_array(array(&$db, 'query'), $params);
- }
-
-/**
- * Returns true if all fields pass validation. Will validate hasAndBelongsToMany associations
- * that use the 'with' key as well. Since _saveMulti is incapable of exiting a save operation.
- *
- * Will validate the currently set data. Use Model::set() or Model::create() to set the active data.
- *
- * @param array $options An optional array of custom options to be made available in the beforeValidate callback
- * @return boolean True if there are no errors
- */
- public function validates($options = array()) {
- $errors = $this->invalidFields($options);
- if (empty($errors) && $errors !== false) {
- $errors = $this->_validateWithModels($options);
- }
- if (is_array($errors)) {
- return count($errors) === 0;
- }
- return $errors;
- }
-
-/**
- * Returns an array of fields that have failed validation. On the current model.
- *
- * @param string $options An optional array of custom options to be made available in the beforeValidate callback
- * @return array Array of invalid fields
- * @see Model::validates()
- */
- public function invalidFields($options = array()) {
- $event = new CakeEvent('Model.beforeValidate', $this, array($options));
- list($event->break, $event->breakOn) = array(true, false);
- $this->getEventManager()->dispatch($event);
- if ($event->isStopped()) {
- return false;
- }
-
- if (!isset($this->validate) || empty($this->validate)) {
- return $this->validationErrors;
- }
-
- $data = $this->data;
- $methods = array_map('strtolower', get_class_methods($this));
- $behaviorMethods = array_keys($this->Behaviors->methods());
-
- if (isset($data[$this->alias])) {
- $data = $data[$this->alias];
- } elseif (!is_array($data)) {
- $data = array();
- }
-
- $exists = null;
-
- $_validate = $this->validate;
- $whitelist = $this->whitelist;
-
- if (!empty($options['fieldList'])) {
- if (!empty($options['fieldList'][$this->alias]) && is_array($options['fieldList'][$this->alias])) {
- $whitelist = $options['fieldList'][$this->alias];
- } else {
- $whitelist = $options['fieldList'];
- }
- }
-
- if (!empty($whitelist)) {
- $validate = array();
- foreach ((array)$whitelist as $f) {
- if (!empty($this->validate[$f])) {
- $validate[$f] = $this->validate[$f];
- }
- }
- $this->validate = $validate;
- }
-
- $validationDomain = $this->validationDomain;
- if (empty($validationDomain)) {
- $validationDomain = 'default';
- }
-
- foreach ($this->validate as $fieldName => $ruleSet) {
- if (!is_array($ruleSet) || (is_array($ruleSet) && isset($ruleSet['rule']))) {
- $ruleSet = array($ruleSet);
- }
- $default = array(
- 'allowEmpty' => null,
- 'required' => null,
- 'rule' => 'blank',
- 'last' => true,
- 'on' => null
- );
-
- foreach ($ruleSet as $index => $validator) {
- if (!is_array($validator)) {
- $validator = array('rule' => $validator);
- }
- $validator = array_merge($default, $validator);
-
- if (!empty($validator['on']) || in_array($validator['required'], array('create', 'update'), true)) {
- if ($exists === null) {
- $exists = $this->exists();
- }
- if ($validator['on'] == 'create' && $exists || $validator['on'] == 'update' && !$exists) {
- continue;
- }
- if ($validator['required'] === 'create' && !$exists || $validator['required'] === 'update' && $exists) {
- $validator['required'] = true;
- }
- }
-
- $valid = true;
- $requiredFail = (
- (!isset($data[$fieldName]) && $validator['required'] === true) ||
- (
- isset($data[$fieldName]) && (empty($data[$fieldName]) &&
- !is_numeric($data[$fieldName])) && $validator['allowEmpty'] === false
- )
- );
-
- if (!$requiredFail && array_key_exists($fieldName, $data)) {
- if (empty($data[$fieldName]) && $data[$fieldName] != '0' && $validator['allowEmpty'] === true) {
- break;
- }
- if (is_array($validator['rule'])) {
- $rule = $validator['rule'][0];
- unset($validator['rule'][0]);
- $ruleParams = array_merge(array($data[$fieldName]), array_values($validator['rule']));
- } else {
- $rule = $validator['rule'];
- $ruleParams = array($data[$fieldName]);
- }
-
- if (in_array(strtolower($rule), $methods)) {
- $ruleParams[] = $validator;
- $ruleParams[0] = array($fieldName => $ruleParams[0]);
- $valid = $this->dispatchMethod($rule, $ruleParams);
- } elseif (in_array($rule, $behaviorMethods) || in_array(strtolower($rule), $behaviorMethods)) {
- $ruleParams[] = $validator;
- $ruleParams[0] = array($fieldName => $ruleParams[0]);
- $valid = $this->Behaviors->dispatchMethod($this, $rule, $ruleParams);
- } elseif (method_exists('Validation', $rule)) {
- $valid = call_user_func_array(array('Validation', $rule), $ruleParams);
- } elseif (!is_array($validator['rule'])) {
- $valid = preg_match($rule, $data[$fieldName]);
- } elseif (Configure::read('debug') > 0) {
- trigger_error(__d('cake_dev', 'Could not find validation handler %s for %s', $rule, $fieldName), E_USER_WARNING);
- }
- }
-
- if ($requiredFail || !$valid || (is_string($valid) && strlen($valid) > 0)) {
- if (is_string($valid)) {
- $message = $valid;
- } elseif (isset($validator['message'])) {
- $args = null;
- if (is_array($validator['message'])) {
- $message = $validator['message'][0];
- $args = array_slice($validator['message'], 1);
- } else {
- $message = $validator['message'];
- }
- if (is_array($validator['rule']) && $args === null) {
- $args = array_slice($ruleSet[$index]['rule'], 1);
- }
- $message = __d($validationDomain, $message, $args);
- } elseif (is_string($index)) {
- if (is_array($validator['rule'])) {
- $args = array_slice($ruleSet[$index]['rule'], 1);
- $message = __d($validationDomain, $index, $args);
- } else {
- $message = __d($validationDomain, $index);
- }
- } elseif (!$requiredFail && is_numeric($index) && count($ruleSet) > 1) {
- $message = $index + 1;
- } else {
- $message = __d('cake_dev', 'This field cannot be left blank');
- }
-
- $this->invalidate($fieldName, $message);
- if ($validator['last']) {
- break;
- }
- }
- }
- }
- $this->validate = $_validate;
- return $this->validationErrors;
- }
-
-/**
- * Runs validation for hasAndBelongsToMany associations that have 'with' keys
- * set. And data in the set() data set.
- *
- * @param array $options Array of options to use on Validation of with models
- * @return boolean Failure of validation on with models.
- * @see Model::validates()
- */
- protected function _validateWithModels($options) {
- $valid = true;
- foreach ($this->hasAndBelongsToMany as $assoc => $association) {
- if (empty($association['with']) || !isset($this->data[$assoc])) {
- continue;
- }
- list($join) = $this->joinModel($this->hasAndBelongsToMany[$assoc]['with']);
- $data = $this->data[$assoc];
-
- $newData = array();
- foreach ((array)$data as $row) {
- if (isset($row[$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) {
- $newData[] = $row;
- } elseif (isset($row[$join]) && isset($row[$join][$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) {
- $newData[] = $row[$join];
- }
- }
- if (empty($newData)) {
- continue;
- }
- foreach ($newData as $data) {
- $data[$this->hasAndBelongsToMany[$assoc]['foreignKey']] = $this->id;
- $this->{$join}->create($data);
- $valid = ($valid && $this->{$join}->validates($options));
- }
- }
- return $valid;
- }
-
-/**
- * Marks a field as invalid, optionally setting the name of validation
- * rule (in case of multiple validation for field) that was broken.
- *
- * @param string $field The name of the field to invalidate
- * @param mixed $value Name of validation rule that was not failed, or validation message to
- * be returned. If no validation key is provided, defaults to true.
- * @return void
- */
- public function invalidate($field, $value = true) {
- if (!is_array($this->validationErrors)) {
- $this->validationErrors = array();
- }
- $this->validationErrors[$field][] = $value;
- }
-
-/**
- * Returns true if given field name is a foreign key in this model.
- *
- * @param string $field Returns true if the input string ends in "_id"
- * @return boolean True if the field is a foreign key listed in the belongsTo array.
- */
- public function isForeignKey($field) {
- $foreignKeys = array();
- if (!empty($this->belongsTo)) {
- foreach ($this->belongsTo as $assoc => $data) {
- $foreignKeys[] = $data['foreignKey'];
- }
- }
- return in_array($field, $foreignKeys);
- }
-
-/**
- * Escapes the field name and prepends the model name. Escaping is done according to the
- * current database driver's rules.
- *
- * @param string $field Field to escape (e.g: id)
- * @param string $alias Alias for the model (e.g: Post)
- * @return string The name of the escaped field for this Model (i.e. id becomes `Post`.`id`).
- */
- public function escapeField($field = null, $alias = null) {
- if (empty($alias)) {
- $alias = $this->alias;
- }
- if (empty($field)) {
- $field = $this->primaryKey;
- }
- $db = $this->getDataSource();
- if (strpos($field, $db->name($alias) . '.') === 0) {
- return $field;
- }
- return $db->name($alias . '.' . $field);
- }
-
-/**
- * Returns the current record's ID
- *
- * @param integer $list Index on which the composed ID is located
- * @return mixed The ID of the current record, false if no ID
- */
- public function getID($list = 0) {
- if (empty($this->id) || (is_array($this->id) && isset($this->id[0]) && empty($this->id[0]))) {
- return false;
- }
-
- if (!is_array($this->id)) {
- return $this->id;
- }
-
- if (isset($this->id[$list]) && !empty($this->id[$list])) {
- return $this->id[$list];
- } elseif (isset($this->id[$list])) {
- return false;
- }
-
- return current($this->id);
- }
-
-/**
- * Returns the ID of the last record this model inserted.
- *
- * @return mixed Last inserted ID
- */
- public function getLastInsertID() {
- return $this->getInsertID();
- }
-
-/**
- * Returns the ID of the last record this model inserted.
- *
- * @return mixed Last inserted ID
- */
- public function getInsertID() {
- return $this->_insertID;
- }
-
-/**
- * Sets the ID of the last record this model inserted
- *
- * @param mixed $id Last inserted ID
- * @return void
- */
- public function setInsertID($id) {
- $this->_insertID = $id;
- }
-
-/**
- * Returns the number of rows returned from the last query.
- *
- * @return integer Number of rows
- */
- public function getNumRows() {
- return $this->getDataSource()->lastNumRows();
- }
-
-/**
- * Returns the number of rows affected by the last query.
- *
- * @return integer Number of rows
- */
- public function getAffectedRows() {
- return $this->getDataSource()->lastAffected();
- }
-
-/**
- * Sets the DataSource to which this model is bound.
- *
- * @param string $dataSource The name of the DataSource, as defined in app/Config/database.php
- * @return boolean True on success
- * @throws MissingConnectionException
- */
- public function setDataSource($dataSource = null) {
- $oldConfig = $this->useDbConfig;
-
- if ($dataSource != null) {
- $this->useDbConfig = $dataSource;
- }
- $db = ConnectionManager::getDataSource($this->useDbConfig);
- if (!empty($oldConfig) && isset($db->config['prefix'])) {
- $oldDb = ConnectionManager::getDataSource($oldConfig);
-
- if (!isset($this->tablePrefix) || (!isset($oldDb->config['prefix']) || $this->tablePrefix == $oldDb->config['prefix'])) {
- $this->tablePrefix = $db->config['prefix'];
- }
- } elseif (isset($db->config['prefix'])) {
- $this->tablePrefix = $db->config['prefix'];
- }
-
- $this->schemaName = $db->getSchemaName();
-
- if (empty($db) || !is_object($db)) {
- throw new MissingConnectionException(array('class' => $this->name));
- }
- }
-
-/**
- * Gets the DataSource to which this model is bound.
- *
- * @return DataSource A DataSource object
- */
- public function getDataSource() {
- if (!$this->_sourceConfigured && $this->useTable !== false) {
- $this->_sourceConfigured = true;
- $this->setSource($this->useTable);
- }
- return ConnectionManager::getDataSource($this->useDbConfig);
- }
-
-/**
- * Get associations
- *
- * @return array
- */
- public function associations() {
- return $this->_associations;
- }
-
-/**
- * Gets all the models with which this model is associated.
- *
- * @param string $type Only result associations of this type
- * @return array Associations
- */
- public function getAssociated($type = null) {
- if ($type == null) {
- $associated = array();
- foreach ($this->_associations as $assoc) {
- if (!empty($this->{$assoc})) {
- $models = array_keys($this->{$assoc});
- foreach ($models as $m) {
- $associated[$m] = $assoc;
- }
- }
- }
- return $associated;
- } elseif (in_array($type, $this->_associations)) {
- if (empty($this->{$type})) {
- return array();
- }
- return array_keys($this->{$type});
- } else {
- $assoc = array_merge(
- $this->hasOne,
- $this->hasMany,
- $this->belongsTo,
- $this->hasAndBelongsToMany
- );
- if (array_key_exists($type, $assoc)) {
- foreach ($this->_associations as $a) {
- if (isset($this->{$a}[$type])) {
- $assoc[$type]['association'] = $a;
- break;
- }
- }
- return $assoc[$type];
- }
- return null;
- }
- }
-
-/**
- * Gets the name and fields to be used by a join model. This allows specifying join fields
- * in the association definition.
- *
- * @param string|array $assoc The model to be joined
- * @param array $keys Any join keys which must be merged with the keys queried
- * @return array
- */
- public function joinModel($assoc, $keys = array()) {
- if (is_string($assoc)) {
- list(, $assoc) = pluginSplit($assoc);
- return array($assoc, array_keys($this->{$assoc}->schema()));
- } elseif (is_array($assoc)) {
- $with = key($assoc);
- return array($with, array_unique(array_merge($assoc[$with], $keys)));
- }
- trigger_error(
- __d('cake_dev', 'Invalid join model settings in %s', $model->alias),
- E_USER_WARNING
- );
- }
-
-/**
- * Called before each find operation. Return false if you want to halt the find
- * call, otherwise return the (modified) query data.
- *
- * @param array $queryData Data used to execute this query, i.e. conditions, order, etc.
- * @return mixed true if the operation should continue, false if it should abort; or, modified
- * $queryData to continue with new $queryData
- * @link http://book.cakephp.org/view/1048/Callback-Methods#beforeFind-1049
- */
- public function beforeFind($queryData) {
- return true;
- }
-
-/**
- * Called after each find operation. Can be used to modify any results returned by find().
- * Return value should be the (modified) results.
- *
- * @param mixed $results The results of the find operation
- * @param boolean $primary Whether this model is being queried directly (vs. being queried as an association)
- * @return mixed Result of the find operation
- * @link http://book.cakephp.org/view/1048/Callback-Methods#afterFind-1050
- */
- public function afterFind($results, $primary = false) {
- return $results;
- }
-
-/**
- * Called before each save operation, after validation. Return a non-true result
- * to halt the save.
- *
- * @param array $options
- * @return boolean True if the operation should continue, false if it should abort
- * @link http://book.cakephp.org/view/1048/Callback-Methods#beforeSave-1052
- */
- public function beforeSave($options = array()) {
- return true;
- }
-
-/**
- * Called after each successful save operation.
- *
- * @param boolean $created True if this save created a new record
- * @return void
- * @link http://book.cakephp.org/view/1048/Callback-Methods#afterSave-1053
- */
- public function afterSave($created) {
- }
-
-/**
- * Called before every deletion operation.
- *
- * @param boolean $cascade If true records that depend on this record will also be deleted
- * @return boolean True if the operation should continue, false if it should abort
- * @link http://book.cakephp.org/view/1048/Callback-Methods#beforeDelete-1054
- */
- public function beforeDelete($cascade = true) {
- return true;
- }
-
-/**
- * Called after every deletion operation.
- *
- * @return void
- * @link http://book.cakephp.org/view/1048/Callback-Methods#afterDelete-1055
- */
- public function afterDelete() {
- }
-
-/**
- * Called during validation operations, before validation. Please note that custom
- * validation rules can be defined in $validate.
- *
- * @param array $options Options passed from model::save(), see $options of model::save().
- * @return boolean True if validate operation should continue, false to abort
- * @link http://book.cakephp.org/view/1048/Callback-Methods#beforeValidate-1051
- */
- public function beforeValidate($options = array()) {
- return true;
- }
-
-/**
- * Called when a DataSource-level error occurs.
- *
- * @return void
- * @link http://book.cakephp.org/view/1048/Callback-Methods#onError-1056
- */
- public function onError() {
- }
-
-/**
- * Clears cache for this model.
- *
- * @param string $type If null this deletes cached views if Cache.check is true
- * Will be used to allow deleting query cache also
- * @return boolean true on delete
- */
- protected function _clearCache($type = null) {
- if ($type === null) {
- if (Configure::read('Cache.check') === true) {
- $assoc[] = strtolower(Inflector::pluralize($this->alias));
- $assoc[] = strtolower(Inflector::underscore(Inflector::pluralize($this->alias)));
- foreach ($this->_associations as $key => $association) {
- foreach ($this->$association as $key => $className) {
- $check = strtolower(Inflector::pluralize($className['className']));
- if (!in_array($check, $assoc)) {
- $assoc[] = strtolower(Inflector::pluralize($className['className']));
- $assoc[] = strtolower(Inflector::underscore(Inflector::pluralize($className['className'])));
- }
- }
- }
- clearCache($assoc);
- return true;
- }
- } else {
- //Will use for query cache deleting
- }
- }
-
-}
diff --git a/lib/Cake/Model/ModelBehavior.php b/lib/Cake/Model/ModelBehavior.php
deleted file mode 100644
index 0ad9a4da9d4..00000000000
--- a/lib/Cake/Model/ModelBehavior.php
+++ /dev/null
@@ -1,225 +0,0 @@
-Model->doSomething($arg1, $arg2);`.
- *
- * ### Mapped methods
- *
- * Behaviors can also define mapped methods. Mapped methods use pattern matching for method invocation. This
- * allows you to create methods similar to Model::findAllByXXX methods on your behaviors. Mapped methods need to
- * be declared in your behaviors `$mapMethods` array. The method signature for a mapped method is slightly different
- * than a normal behavior mixin method.
- *
- * {{{
- * public $mapMethods = array('/do(\w+)/' => 'doSomething');
- *
- * function doSomething(Model $model, $method, $arg1, $arg2) {
- * //do something
- * }
- * }}}
- *
- * The above will map every doXXX() method call to the behavior. As you can see, the model is
- * still the first parameter, but the called method name will be the 2nd parameter. This allows
- * you to munge the method name for additional information, much like Model::findAllByXX.
- *
- * @package Cake.Model
- * @see Model::$actsAs
- * @see BehaviorCollection::load()
- */
-class ModelBehavior extends Object {
-
-/**
- * Contains configuration settings for use with individual model objects. This
- * is used because if multiple models use this Behavior, each will use the same
- * object instance. Individual model settings should be stored as an
- * associative array, keyed off of the model name.
- *
- * @var array
- * @see Model::$alias
- */
- public $settings = array();
-
-/**
- * Allows the mapping of preg-compatible regular expressions to public or
- * private methods in this class, where the array key is a /-delimited regular
- * expression, and the value is a class method. Similar to the functionality of
- * the findBy* / findAllBy* magic methods.
- *
- * @var array
- */
- public $mapMethods = array();
-
-/**
- * Setup this behavior with the specified configuration settings.
- *
- * @param Model $model Model using this behavior
- * @param array $config Configuration settings for $model
- * @return void
- */
- public function setup(Model $model, $config = array()) {
- }
-
-/**
- * Clean up any initialization this behavior has done on a model. Called when a behavior is dynamically
- * detached from a model using Model::detach().
- *
- * @param Model $model Model using this behavior
- * @return void
- * @see BehaviorCollection::detach()
- */
- public function cleanup(Model $model) {
- if (isset($this->settings[$model->alias])) {
- unset($this->settings[$model->alias]);
- }
- }
-
-/**
- * beforeFind can be used to cancel find operations, or modify the query that will be executed.
- * By returning null/false you can abort a find. By returning an array you can modify/replace the query
- * that is going to be run.
- *
- * @param Model $model Model using this behavior
- * @param array $query Data used to execute this query, i.e. conditions, order, etc.
- * @return boolean|array False or null will abort the operation. You can return an array to replace the
- * $query that will be eventually run.
- */
- public function beforeFind(Model $model, $query) {
- return true;
- }
-
-/**
- * After find callback. Can be used to modify any results returned by find.
- *
- * @param Model $model Model using this behavior
- * @param mixed $results The results of the find operation
- * @param boolean $primary Whether this model is being queried directly (vs. being queried as an association)
- * @return mixed An array value will replace the value of $results - any other value will be ignored.
- */
- public function afterFind(Model $model, $results, $primary) {
- }
-
-/**
- * beforeValidate is called before a model is validated, you can use this callback to
- * add behavior validation rules into a models validate array. Returning false
- * will allow you to make the validation fail.
- *
- * @param Model $model Model using this behavior
- * @return mixed False or null will abort the operation. Any other result will continue.
- */
- public function beforeValidate(Model $model) {
- return true;
- }
-
-/**
- * beforeSave is called before a model is saved. Returning false from a beforeSave callback
- * will abort the save operation.
- *
- * @param Model $model Model using this behavior
- * @return mixed False if the operation should abort. Any other result will continue.
- */
- public function beforeSave(Model $model) {
- return true;
- }
-
-/**
- * afterSave is called after a model is saved.
- *
- * @param Model $model Model using this behavior
- * @param boolean $created True if this save created a new record
- * @return boolean
- */
- public function afterSave(Model $model, $created) {
- return true;
- }
-
-/**
- * Before delete is called before any delete occurs on the attached model, but after the model's
- * beforeDelete is called. Returning false from a beforeDelete will abort the delete.
- *
- * @param Model $model Model using this behavior
- * @param boolean $cascade If true records that depend on this record will also be deleted
- * @return mixed False if the operation should abort. Any other result will continue.
- */
- public function beforeDelete(Model $model, $cascade = true) {
- return true;
- }
-
-/**
- * After delete is called after any delete occurs on the attached model.
- *
- * @param Model $model Model using this behavior
- * @return void
- */
- public function afterDelete(Model $model) {
- }
-
-/**
- * DataSource error callback
- *
- * @param Model $model Model using this behavior
- * @param string $error Error generated in DataSource
- * @return void
- */
- public function onError(Model $model, $error) {
- }
-
-/**
- * If $model's whitelist property is non-empty, $field will be added to it.
- * Note: this method should *only* be used in beforeValidate or beforeSave to ensure
- * that it only modifies the whitelist for the current save operation. Also make sure
- * you explicitly set the value of the field which you are allowing.
- *
- * @param Model $model Model using this behavior
- * @param string $field Field to be added to $model's whitelist
- * @return void
- */
- protected function _addToWhitelist(Model $model, $field) {
- if (is_array($field)) {
- foreach ($field as $f) {
- $this->_addToWhitelist($model, $f);
- }
- return;
- }
- if (!empty($model->whitelist) && !in_array($field, $model->whitelist)) {
- $model->whitelist[] = $field;
- }
- }
-
-}
-
diff --git a/lib/Cake/Model/Permission.php b/lib/Cake/Model/Permission.php
deleted file mode 100644
index 86f1f02ff0d..00000000000
--- a/lib/Cake/Model/Permission.php
+++ /dev/null
@@ -1,75 +0,0 @@
-useDbConfig = $config;
- }
- parent::__construct();
- }
-
-}
diff --git a/lib/Cake/Network/CakeRequest.php b/lib/Cake/Network/CakeRequest.php
deleted file mode 100644
index 911a15a1bbe..00000000000
--- a/lib/Cake/Network/CakeRequest.php
+++ /dev/null
@@ -1,852 +0,0 @@
-controller`.
- *
- * @package Cake.Network
- */
-class CakeRequest implements ArrayAccess {
-
-/**
- * Array of parameters parsed from the url.
- *
- * @var array
- */
- public $params = array(
- 'plugin' => null,
- 'controller' => null,
- 'action' => null,
- );
-
-/**
- * Array of POST data. Will contain form data as well as uploaded files.
- * Inputs prefixed with 'data' will have the data prefix removed. If there is
- * overlap between an input prefixed with data and one without, the 'data' prefixed
- * value will take precedence.
- *
- * @var array
- */
- public $data = array();
-
-/**
- * Array of querystring arguments
- *
- * @var array
- */
- public $query = array();
-
-/**
- * The url string used for the request.
- *
- * @var string
- */
- public $url;
-
-/**
- * Base url path.
- *
- * @var string
- */
- public $base = false;
-
-/**
- * webroot path segment for the request.
- *
- * @var string
- */
- public $webroot = '/';
-
-/**
- * The full address to the current request
- *
- * @var string
- */
- public $here = null;
-
-/**
- * The built in detectors used with `is()` can be modified with `addDetector()`.
- *
- * There are several ways to specify a detector, see CakeRequest::addDetector() for the
- * various formats and ways to define detectors.
- *
- * @var array
- */
- protected $_detectors = array(
- 'get' => array('env' => 'REQUEST_METHOD', 'value' => 'GET'),
- 'post' => array('env' => 'REQUEST_METHOD', 'value' => 'POST'),
- 'put' => array('env' => 'REQUEST_METHOD', 'value' => 'PUT'),
- 'delete' => array('env' => 'REQUEST_METHOD', 'value' => 'DELETE'),
- 'head' => array('env' => 'REQUEST_METHOD', 'value' => 'HEAD'),
- 'options' => array('env' => 'REQUEST_METHOD', 'value' => 'OPTIONS'),
- 'ssl' => array('env' => 'HTTPS', 'value' => 1),
- 'ajax' => array('env' => 'HTTP_X_REQUESTED_WITH', 'value' => 'XMLHttpRequest'),
- 'flash' => array('env' => 'HTTP_USER_AGENT', 'pattern' => '/^(Shockwave|Adobe) Flash/'),
- 'mobile' => array('env' => 'HTTP_USER_AGENT', 'options' => array(
- 'Android', 'AvantGo', 'BlackBerry', 'DoCoMo', 'Fennec', 'iPod', 'iPhone', 'iPad',
- 'J2ME', 'MIDP', 'NetFront', 'Nokia', 'Opera Mini', 'Opera Mobi', 'PalmOS', 'PalmSource',
- 'portalmmm', 'Plucker', 'ReqwirelessWeb', 'SonyEricsson', 'Symbian', 'UP\\.Browser',
- 'webOS', 'Windows CE', 'Windows Phone OS', 'Xiino'
- )),
- 'requested' => array('param' => 'requested', 'value' => 1)
- );
-
-/**
- * Copy of php://input. Since this stream can only be read once in most SAPI's
- * keep a copy of it so users don't need to know about that detail.
- *
- * @var string
- */
- protected $_input = '';
-
-/**
- * Constructor
- *
- * @param string $url Trimmed url string to use. Should not contain the application base path.
- * @param boolean $parseEnvironment Set to false to not auto parse the environment. ie. GET, POST and FILES.
- */
- public function __construct($url = null, $parseEnvironment = true) {
- $this->_base();
- if (empty($url)) {
- $url = $this->_url();
- }
- if ($url[0] == '/') {
- $url = substr($url, 1);
- }
- $this->url = $url;
-
- if ($parseEnvironment) {
- $this->_processPost();
- $this->_processGet();
- $this->_processFiles();
- }
- $this->here = $this->base . '/' . $this->url;
- }
-
-/**
- * process the post data and set what is there into the object.
- * processed data is available at `$this->data`
- *
- * Will merge POST vars prefixed with `data`, and ones without
- * into a single array. Variables prefixed with `data` will overwrite those without.
- *
- * If you have mixed POST values be careful not to make any top level keys numeric
- * containing arrays. Set::merge() is used to merge data, and it has possibly
- * unexpected behavior in this situation.
- *
- * @return void
- */
- protected function _processPost() {
- $this->data = $_POST;
- if (ini_get('magic_quotes_gpc') === '1') {
- $this->data = stripslashes_deep($this->data);
- }
- if (env('HTTP_X_HTTP_METHOD_OVERRIDE')) {
- $this->data['_method'] = env('HTTP_X_HTTP_METHOD_OVERRIDE');
- }
- if (isset($this->data['_method'])) {
- if (!empty($_SERVER)) {
- $_SERVER['REQUEST_METHOD'] = $this->data['_method'];
- } else {
- $_ENV['REQUEST_METHOD'] = $this->data['_method'];
- }
- unset($this->data['_method']);
- }
-
- if (isset($this->data['data'])) {
- $data = $this->data['data'];
- if (count($this->data) <= 1) {
- $this->data = $data;
- } else {
- unset($this->data['data']);
- $this->data = Set::merge($this->data, $data);
- }
- }
- }
-
-/**
- * Process the GET parameters and move things into the object.
- *
- * @return void
- */
- protected function _processGet() {
- if (ini_get('magic_quotes_gpc') === '1') {
- $query = stripslashes_deep($_GET);
- } else {
- $query = $_GET;
- }
-
- unset($query['/' . str_replace('.', '_', urldecode($this->url))]);
- if (strpos($this->url, '?') !== false) {
- list(, $querystr) = explode('?', $this->url);
- parse_str($querystr, $queryArgs);
- $query += $queryArgs;
- }
- if (isset($this->params['url'])) {
- $query = array_merge($this->params['url'], $query);
- }
- $this->query = $query;
- }
-
-/**
- * Get the request uri. Looks in PATH_INFO first, as this is the exact value we need prepared
- * by PHP. Following that, REQUEST_URI, PHP_SELF, HTTP_X_REWRITE_URL and argv are checked in that order.
- * Each of these server variables have the base path, and query strings stripped off
- *
- * @return string URI The CakePHP request path that is being accessed.
- */
- protected function _url() {
- if (!empty($_SERVER['PATH_INFO'])) {
- return $_SERVER['PATH_INFO'];
- } elseif (isset($_SERVER['REQUEST_URI'])) {
- $uri = $_SERVER['REQUEST_URI'];
- } elseif (isset($_SERVER['PHP_SELF']) && isset($_SERVER['SCRIPT_NAME'])) {
- $uri = str_replace($_SERVER['SCRIPT_NAME'], '', $_SERVER['PHP_SELF']);
- } elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) {
- $uri = $_SERVER['HTTP_X_REWRITE_URL'];
- } elseif ($var = env('argv')) {
- $uri = $var[0];
- }
-
- $base = $this->base;
-
- if (strlen($base) > 0 && strpos($uri, $base) === 0) {
- $uri = substr($uri, strlen($base));
- }
- if (strpos($uri, '?') !== false) {
- list($uri) = explode('?', $uri, 2);
- }
- if (empty($uri) || $uri == '/' || $uri == '//') {
- return '/';
- }
- return $uri;
- }
-
-/**
- * Returns a base URL and sets the proper webroot
- *
- * @return string Base URL
- */
- protected function _base() {
- $dir = $webroot = null;
- $config = Configure::read('App');
- extract($config);
-
- if (!isset($base)) {
- $base = $this->base;
- }
- if ($base !== false) {
- $this->webroot = $base . '/';
- return $this->base = $base;
- }
-
- if (!$baseUrl) {
- $base = dirname(env('PHP_SELF'));
-
- if ($webroot === 'webroot' && $webroot === basename($base)) {
- $base = dirname($base);
- }
- if ($dir === 'app' && $dir === basename($base)) {
- $base = dirname($base);
- }
-
- if ($base === DS || $base === '.') {
- $base = '';
- }
-
- $this->webroot = $base . '/';
- return $this->base = $base;
- }
-
- $file = '/' . basename($baseUrl);
- $base = dirname($baseUrl);
-
- if ($base === DS || $base === '.') {
- $base = '';
- }
- $this->webroot = $base . '/';
-
- $docRoot = env('DOCUMENT_ROOT');
- $docRootContainsWebroot = strpos($docRoot, $dir . '/' . $webroot);
-
- if (!empty($base) || !$docRootContainsWebroot) {
- if (strpos($this->webroot, '/' . $dir . '/') === false) {
- $this->webroot .= $dir . '/';
- }
- if (strpos($this->webroot, '/' . $webroot . '/') === false) {
- $this->webroot .= $webroot . '/';
- }
- }
- return $this->base = $base . $file;
- }
-
-/**
- * Process $_FILES and move things into the object.
- *
- * @return void
- */
- protected function _processFiles() {
- if (isset($_FILES) && is_array($_FILES)) {
- foreach ($_FILES as $name => $data) {
- if ($name != 'data') {
- $this->params['form'][$name] = $data;
- }
- }
- }
-
- if (isset($_FILES['data'])) {
- foreach ($_FILES['data'] as $key => $data) {
- foreach ($data as $model => $fields) {
- if (is_array($fields)) {
- foreach ($fields as $field => $value) {
- if (is_array($value)) {
- foreach ($value as $k => $v) {
- $this->data[$model][$field][$k][$key] = $v;
- }
- } else {
- $this->data[$model][$field][$key] = $value;
- }
- }
- } else {
- $this->data[$model][$key] = $fields;
- }
- }
- }
- }
- }
-
-/**
- * Get the IP the client is using, or says they are using.
- *
- * @param boolean $safe Use safe = false when you think the user might manipulate their HTTP_CLIENT_IP
- * header. Setting $safe = false will will also look at HTTP_X_FORWARDED_FOR
- * @return string The client IP.
- */
- public function clientIp($safe = true) {
- if (!$safe && env('HTTP_X_FORWARDED_FOR') != null) {
- $ipaddr = preg_replace('/(?:,.*)/', '', env('HTTP_X_FORWARDED_FOR'));
- } else {
- if (env('HTTP_CLIENT_IP') != null) {
- $ipaddr = env('HTTP_CLIENT_IP');
- } else {
- $ipaddr = env('REMOTE_ADDR');
- }
- }
-
- if (env('HTTP_CLIENTADDRESS') != null) {
- $tmpipaddr = env('HTTP_CLIENTADDRESS');
-
- if (!empty($tmpipaddr)) {
- $ipaddr = preg_replace('/(?:,.*)/', '', $tmpipaddr);
- }
- }
- return trim($ipaddr);
- }
-
-/**
- * Returns the referer that referred this request.
- *
- * @param boolean $local Attempt to return a local address. Local addresses do not contain hostnames.
- * @return string The referring address for this request.
- */
- public function referer($local = false) {
- $ref = env('HTTP_REFERER');
- $forwarded = env('HTTP_X_FORWARDED_HOST');
- if ($forwarded) {
- $ref = $forwarded;
- }
-
- $base = '';
- if (defined('FULL_BASE_URL')) {
- $base = FULL_BASE_URL . $this->webroot;
- }
- if (!empty($ref) && !empty($base)) {
- if ($local && strpos($ref, $base) === 0) {
- $ref = substr($ref, strlen($base));
- if ($ref[0] != '/') {
- $ref = '/' . $ref;
- }
- return $ref;
- } elseif (!$local) {
- return $ref;
- }
- }
- return '/';
- }
-
-/**
- * Missing method handler, handles wrapping older style isAjax() type methods
- *
- * @param string $name The method called
- * @param array $params Array of parameters for the method call
- * @return mixed
- * @throws CakeException when an invalid method is called.
- */
- public function __call($name, $params) {
- if (strpos($name, 'is') === 0) {
- $type = strtolower(substr($name, 2));
- return $this->is($type);
- }
- throw new CakeException(__d('cake_dev', 'Method %s does not exist', $name));
- }
-
-/**
- * Magic get method allows access to parsed routing parameters directly on the object.
- *
- * Allows access to `$this->params['controller']` via `$this->controller`
- *
- * @param string $name The property being accessed.
- * @return mixed Either the value of the parameter or null.
- */
- public function __get($name) {
- if (isset($this->params[$name])) {
- return $this->params[$name];
- }
- return null;
- }
-
-/**
- * Magic isset method allows isset/empty checks
- * on routing parameters.
- *
- * @param string $name The property being accessed.
- * @return bool Existence
- */
- public function __isset($name) {
- return isset($this->params[$name]);
- }
-
-/**
- * Check whether or not a Request is a certain type. Uses the built in detection rules
- * as well as additional rules defined with CakeRequest::addDetector(). Any detector can be called
- * as `is($type)` or `is$Type()`.
- *
- * @param string $type The type of request you want to check.
- * @return boolean Whether or not the request is the type you are checking.
- */
- public function is($type) {
- $type = strtolower($type);
- if (!isset($this->_detectors[$type])) {
- return false;
- }
- $detect = $this->_detectors[$type];
- if (isset($detect['env'])) {
- if (isset($detect['value'])) {
- return env($detect['env']) == $detect['value'];
- }
- if (isset($detect['pattern'])) {
- return (bool)preg_match($detect['pattern'], env($detect['env']));
- }
- if (isset($detect['options'])) {
- $pattern = '/' . implode('|', $detect['options']) . '/i';
- return (bool)preg_match($pattern, env($detect['env']));
- }
- }
- if (isset($detect['param'])) {
- $key = $detect['param'];
- $value = $detect['value'];
- return isset($this->params[$key]) ? $this->params[$key] == $value : false;
- }
- if (isset($detect['callback']) && is_callable($detect['callback'])) {
- return call_user_func($detect['callback'], $this);
- }
- return false;
- }
-
-/**
- * Add a new detector to the list of detectors that a request can use.
- * There are several different formats and types of detectors that can be set.
- *
- * ### Environment value comparison
- *
- * An environment value comparison, compares a value fetched from `env()` to a known value
- * the environment value is equality checked against the provided value.
- *
- * e.g `addDetector('post', array('env' => 'REQUEST_METHOD', 'value' => 'POST'))`
- *
- * ### Pattern value comparison
- *
- * Pattern value comparison allows you to compare a value fetched from `env()` to a regular expression.
- *
- * e.g `addDetector('iphone', array('env' => 'HTTP_USER_AGENT', 'pattern' => '/iPhone/i'));`
- *
- * ### Option based comparison
- *
- * Option based comparisons use a list of options to create a regular expression. Subsequent calls
- * to add an already defined options detector will merge the options.
- *
- * e.g `addDetector('mobile', array('env' => 'HTTP_USER_AGENT', 'options' => array('Fennec')));`
- *
- * ### Callback detectors
- *
- * Callback detectors allow you to provide a 'callback' type to handle the check. The callback will
- * receive the request object as its only parameter.
- *
- * e.g `addDetector('custom', array('callback' => array('SomeClass', 'somemethod')));`
- *
- * ### Request parameter detectors
- *
- * Allows for custom detectors on the request parameters.
- *
- * e.g `addDetector('post', array('param' => 'requested', 'value' => 1)`
- *
- * @param string $name The name of the detector.
- * @param array $options The options for the detector definition. See above.
- * @return void
- */
- public function addDetector($name, $options) {
- $name = strtolower($name);
- if (isset($this->_detectors[$name]) && isset($options['options'])) {
- $options = Set::merge($this->_detectors[$name], $options);
- }
- $this->_detectors[$name] = $options;
- }
-
-/**
- * Add parameters to the request's parsed parameter set. This will overwrite any existing parameters.
- * This modifies the parameters available through `$request->params`.
- *
- * @param array $params Array of parameters to merge in
- * @return The current object, you can chain this method.
- */
- public function addParams($params) {
- $this->params = array_merge($this->params, (array)$params);
- return $this;
- }
-
-/**
- * Add paths to the requests' paths vars. This will overwrite any existing paths.
- * Provides an easy way to modify, here, webroot and base.
- *
- * @param array $paths Array of paths to merge in
- * @return CakeRequest the current object, you can chain this method.
- */
- public function addPaths($paths) {
- foreach (array('webroot', 'here', 'base') as $element) {
- if (isset($paths[$element])) {
- $this->{$element} = $paths[$element];
- }
- }
- return $this;
- }
-
-/**
- * Get the value of the current requests url. Will include named parameters and querystring arguments.
- *
- * @param boolean $base Include the base path, set to false to trim the base path off.
- * @return string the current request url including query string args.
- */
- public function here($base = true) {
- $url = $this->here;
- if (!empty($this->query)) {
- $url .= '?' . http_build_query($this->query, null, '&');
- }
- if (!$base) {
- $url = preg_replace('/^' . preg_quote($this->base, '/') . '/', '', $url, 1);
- }
- return $url;
- }
-
-/**
- * Read an HTTP header from the Request information.
- *
- * @param string $name Name of the header you want.
- * @return mixed Either false on no header being set or the value of the header.
- */
- public static function header($name) {
- $name = 'HTTP_' . strtoupper(str_replace('-', '_', $name));
- if (!empty($_SERVER[$name])) {
- return $_SERVER[$name];
- }
- return false;
- }
-
-/**
- * Get the HTTP method used for this request.
- * There are a few ways to specify a method.
- *
- * - If your client supports it you can use native HTTP methods.
- * - You can set the HTTP-X-Method-Override header.
- * - You can submit an input with the name `_method`
- *
- * Any of these 3 approaches can be used to set the HTTP method used
- * by CakePHP internally, and will effect the result of this method.
- *
- * @return string The name of the HTTP method used.
- */
- public function method() {
- return env('REQUEST_METHOD');
- }
-
-/**
- * Get the host that the request was handled on.
- *
- * @return void
- */
- public function host() {
- return env('HTTP_HOST');
- }
-
-/**
- * Get the domain name and include $tldLength segments of the tld.
- *
- * @param integer $tldLength Number of segments your tld contains. For example: `example.com` contains 1 tld.
- * While `example.co.uk` contains 2.
- * @return string Domain name without subdomains.
- */
- public function domain($tldLength = 1) {
- $segments = explode('.', $this->host());
- $domain = array_slice($segments, -1 * ($tldLength + 1));
- return implode('.', $domain);
- }
-
-/**
- * Get the subdomains for a host.
- *
- * @param integer $tldLength Number of segments your tld contains. For example: `example.com` contains 1 tld.
- * While `example.co.uk` contains 2.
- * @return array of subdomains.
- */
- public function subdomains($tldLength = 1) {
- $segments = explode('.', $this->host());
- return array_slice($segments, 0, -1 * ($tldLength + 1));
- }
-
-/**
- * Find out which content types the client accepts or check if they accept a
- * particular type of content.
- *
- * #### Get all types:
- *
- * `$this->request->accepts();`
- *
- * #### Check for a single type:
- *
- * `$this->request->accepts('json');`
- *
- * This method will order the returned content types by the preference values indicated
- * by the client.
- *
- * @param string $type The content type to check for. Leave null to get all types a client accepts.
- * @return mixed Either an array of all the types the client accepts or a boolean if they accept the
- * provided type.
- */
- public function accepts($type = null) {
- $raw = $this->parseAccept();
- $accept = array();
- foreach ($raw as $value => $types) {
- $accept = array_merge($accept, $types);
- }
- if ($type === null) {
- return $accept;
- }
- return in_array($type, $accept);
- }
-
-/**
- * Parse the HTTP_ACCEPT header and return a sorted array with content types
- * as the keys, and pref values as the values.
- *
- * Generally you want to use CakeRequest::accept() to get a simple list
- * of the accepted content types.
- *
- * @return array An array of prefValue => array(content/types)
- */
- public function parseAccept() {
- $accept = array();
- $header = explode(',', $this->header('accept'));
- foreach (array_filter($header) as $value) {
- $prefPos = strpos($value, ';');
- if ($prefPos !== false) {
- $prefValue = substr($value, strpos($value, '=') + 1);
- $value = trim(substr($value, 0, $prefPos));
- } else {
- $prefValue = '1.0';
- $value = trim($value);
- }
- if (!isset($accept[$prefValue])) {
- $accept[$prefValue] = array();
- }
- if ($prefValue) {
- $accept[$prefValue][] = $value;
- }
- }
- krsort($accept);
- return $accept;
- }
-
-/**
- * Get the languages accepted by the client, or check if a specific language is accepted.
- *
- * Get the list of accepted languages:
- *
- * {{{ CakeRequest::acceptLanguage(); }}}
- *
- * Check if a specific language is accepted:
- *
- * {{{ CakeRequest::acceptLanguage('es-es'); }}}
- *
- * @param string $language The language to test.
- * @return If a $language is provided, a boolean. Otherwise the array of accepted languages.
- */
- public static function acceptLanguage($language = null) {
- $accepts = preg_split('/[;,]/', self::header('Accept-Language'));
- foreach ($accepts as &$accept) {
- $accept = strtolower($accept);
- if (strpos($accept, '_') !== false) {
- $accept = str_replace('_', '-', $accept);
- }
- }
- if ($language === null) {
- return $accepts;
- }
- return in_array($language, $accepts);
- }
-
-/**
- * Provides a read/write accessor for `$this->data`. Allows you
- * to use a syntax similar to `CakeSession` for reading post data.
- *
- * ## Reading values.
- *
- * `$request->data('Post.title');`
- *
- * When reading values you will get `null` for keys/values that do not exist.
- *
- * ## Writing values
- *
- * `$request->data('Post.title', 'New post!');`
- *
- * You can write to any value, even paths/keys that do not exist, and the arrays
- * will be created for you.
- *
- * @param string $name,... Dot separated name of the value to read/write
- * @return mixed Either the value being read, or this so you can chain consecutive writes.
- */
- public function data($name) {
- $args = func_get_args();
- if (count($args) == 2) {
- $this->data = Set::insert($this->data, $name, $args[1]);
- return $this;
- }
- return Set::classicExtract($this->data, $name);
- }
-
-/**
- * Read data from `php://input`. Useful when interacting with XML or JSON
- * request body content.
- *
- * Getting input with a decoding function:
- *
- * `$this->request->input('json_decode');`
- *
- * Getting input using a decoding function, and additional params:
- *
- * `$this->request->input('Xml::build', array('return' => 'DOMDocument'));`
- *
- * Any additional parameters are applied to the callback in the order they are given.
- *
- * @param string $callback A decoding callback that will convert the string data to another
- * representation. Leave empty to access the raw input data. You can also
- * supply additional parameters for the decoding callback using var args, see above.
- * @return The decoded/processed request data.
- */
- public function input($callback = null) {
- $input = $this->_readInput();
- $args = func_get_args();
- if (!empty($args)) {
- $callback = array_shift($args);
- array_unshift($args, $input);
- return call_user_func_array($callback, $args);
- }
- return $input;
- }
-
-/**
- * Read data from php://input, mocked in tests.
- *
- * @return string contents of php://input
- */
- protected function _readInput() {
- if (empty($this->_input)) {
- $fh = fopen('php://input', 'r');
- $content = stream_get_contents($fh);
- fclose($fh);
- $this->_input = $content;
- }
- return $this->_input;
- }
-
-/**
- * Array access read implementation
- *
- * @param string $name Name of the key being accessed.
- * @return mixed
- */
- public function offsetGet($name) {
- if (isset($this->params[$name])) {
- return $this->params[$name];
- }
- if ($name == 'url') {
- return $this->query;
- }
- if ($name == 'data') {
- return $this->data;
- }
- return null;
- }
-
-/**
- * Array access write implementation
- *
- * @param string $name Name of the key being written
- * @param mixed $value The value being written.
- * @return void
- */
- public function offsetSet($name, $value) {
- $this->params[$name] = $value;
- }
-
-/**
- * Array access isset() implementation
- *
- * @param string $name thing to check.
- * @return boolean
- */
- public function offsetExists($name) {
- return isset($this->params[$name]);
- }
-
-/**
- * Array access unset() implementation
- *
- * @param string $name Name to unset.
- * @return void
- */
- public function offsetUnset($name) {
- unset($this->params[$name]);
- }
-
-}
diff --git a/lib/Cake/Network/CakeResponse.php b/lib/Cake/Network/CakeResponse.php
deleted file mode 100644
index 591ae64214c..00000000000
--- a/lib/Cake/Network/CakeResponse.php
+++ /dev/null
@@ -1,1154 +0,0 @@
- 'Continue',
- 101 => 'Switching Protocols',
- 200 => 'OK',
- 201 => 'Created',
- 202 => 'Accepted',
- 203 => 'Non-Authoritative Information',
- 204 => 'No Content',
- 205 => 'Reset Content',
- 206 => 'Partial Content',
- 300 => 'Multiple Choices',
- 301 => 'Moved Permanently',
- 302 => 'Found',
- 303 => 'See Other',
- 304 => 'Not Modified',
- 305 => 'Use Proxy',
- 307 => 'Temporary 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 Large',
- 415 => 'Unsupported Media Type',
- 416 => 'Requested range not satisfiable',
- 417 => 'Expectation Failed',
- 500 => 'Internal Server Error',
- 501 => 'Not Implemented',
- 502 => 'Bad Gateway',
- 503 => 'Service Unavailable',
- 504 => 'Gateway Time-out'
- );
-
-/**
- * Holds known mime type mappings
- *
- * @var array
- */
- protected $_mimeTypes = array(
- 'ai' => 'application/postscript',
- 'bcpio' => 'application/x-bcpio',
- 'bin' => 'application/octet-stream',
- 'ccad' => 'application/clariscad',
- 'cdf' => 'application/x-netcdf',
- 'class' => 'application/octet-stream',
- 'cpio' => 'application/x-cpio',
- 'cpt' => 'application/mac-compactpro',
- 'csh' => 'application/x-csh',
- 'csv' => array('text/csv', 'application/vnd.ms-excel', 'text/plain'),
- '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',
- 'eot' => 'application/vnd.ms-fontobject',
- 'eps' => 'application/postscript',
- 'exe' => 'application/octet-stream',
- 'ez' => 'application/andrew-inset',
- 'flv' => 'video/x-flv',
- 'gtar' => 'application/x-gtar',
- 'gz' => 'application/x-gzip',
- 'bz2' => 'application/x-bzip',
- '7z' => 'application/x-7z-compressed',
- 'hdf' => 'application/x-hdf',
- 'hqx' => 'application/mac-binhex40',
- 'ico' => 'image/vnd.microsoft.icon',
- 'ips' => 'application/x-ipscript',
- 'ipx' => 'application/x-ipix',
- 'js' => 'text/javascript',
- 'latex' => 'application/x-latex',
- 'lha' => 'application/octet-stream',
- 'lsp' => 'application/x-lisp',
- 'lzh' => 'application/octet-stream',
- 'man' => 'application/x-troff-man',
- 'me' => 'application/x-troff-me',
- 'mif' => 'application/vnd.mif',
- 'ms' => 'application/x-troff-ms',
- 'nc' => 'application/x-netcdf',
- 'oda' => 'application/oda',
- 'otf' => 'font/otf',
- 'pdf' => 'application/pdf',
- 'pgn' => 'application/x-chess-pgn',
- 'pot' => 'application/mspowerpoint',
- 'pps' => 'application/mspowerpoint',
- 'ppt' => 'application/mspowerpoint',
- 'ppz' => 'application/mspowerpoint',
- 'pre' => 'application/x-freelance',
- 'prt' => 'application/pro_eng',
- 'ps' => 'application/postscript',
- 'roff' => 'application/x-troff',
- 'scm' => 'application/x-lotusscreencam',
- 'set' => 'application/set',
- 'sh' => 'application/x-sh',
- 'shar' => 'application/x-shar',
- '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',
- 'sol' => 'application/solids',
- 'spl' => 'application/x-futuresplash',
- 'src' => 'application/x-wais-source',
- 'step' => 'application/STEP',
- 'stl' => 'application/SLA',
- 'stp' => 'application/STEP',
- 'sv4cpio' => 'application/x-sv4cpio',
- 'sv4crc' => 'application/x-sv4crc',
- 'svg' => 'image/svg+xml',
- 'svgz' => 'image/svg+xml',
- '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',
- 'tr' => 'application/x-troff',
- 'tsp' => 'application/dsptype',
- 'ttf' => 'font/ttf',
- 'unv' => 'application/i-deas',
- 'ustar' => 'application/x-ustar',
- 'vcd' => 'application/x-cdlink',
- 'vda' => 'application/vda',
- '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',
- 'zip' => 'application/zip',
- 'aif' => 'audio/x-aiff',
- 'aifc' => 'audio/x-aiff',
- 'aiff' => 'audio/x-aiff',
- 'au' => 'audio/basic',
- 'kar' => 'audio/midi',
- 'mid' => 'audio/midi',
- 'midi' => 'audio/midi',
- 'mp2' => 'audio/mpeg',
- 'mp3' => 'audio/mpeg',
- 'mpga' => 'audio/mpeg',
- 'ogg' => 'audio/ogg',
- 'oga' => 'audio/ogg',
- 'spx' => 'audio/ogg',
- 'ra' => 'audio/x-realaudio',
- 'ram' => 'audio/x-pn-realaudio',
- 'rm' => 'audio/x-pn-realaudio',
- 'rpm' => 'audio/x-pn-realaudio-plugin',
- 'snd' => 'audio/basic',
- 'tsi' => 'audio/TSP-audio',
- 'wav' => 'audio/x-wav',
- 'aac' => 'audio/aac',
- 'asc' => 'text/plain',
- 'c' => 'text/plain',
- 'cc' => 'text/plain',
- 'css' => 'text/css',
- 'etx' => 'text/x-setext',
- 'f' => 'text/plain',
- 'f90' => 'text/plain',
- 'h' => 'text/plain',
- 'hh' => 'text/plain',
- 'html' => array('text/html', '*/*'),
- 'htm' => array('text/html', '*/*'),
- 'ics' => 'text/calendar',
- 'm' => 'text/plain',
- 'rtf' => 'text/rtf',
- 'rtx' => 'text/richtext',
- 'sgm' => 'text/sgml',
- 'sgml' => 'text/sgml',
- 'tsv' => 'text/tab-separated-values',
- 'tpl' => 'text/template',
- 'txt' => 'text/plain',
- 'text' => 'text/plain',
- 'xml' => array('application/xml', 'text/xml'),
- 'avi' => 'video/x-msvideo',
- 'fli' => 'video/x-fli',
- 'mov' => 'video/quicktime',
- 'movie' => 'video/x-sgi-movie',
- 'mpe' => 'video/mpeg',
- 'mpeg' => 'video/mpeg',
- 'mpg' => 'video/mpeg',
- 'qt' => 'video/quicktime',
- 'viv' => 'video/vnd.vivo',
- 'vivo' => 'video/vnd.vivo',
- 'ogv' => 'video/ogg',
- 'webm' => 'video/webm',
- 'mp4' => 'video/mp4',
- 'gif' => 'image/gif',
- 'ief' => 'image/ief',
- 'jpe' => 'image/jpeg',
- 'jpeg' => 'image/jpeg',
- 'jpg' => 'image/jpeg',
- 'pbm' => 'image/x-portable-bitmap',
- 'pgm' => 'image/x-portable-graymap',
- 'png' => 'image/png',
- 'pnm' => 'image/x-portable-anymap',
- 'ppm' => 'image/x-portable-pixmap',
- 'ras' => 'image/cmu-raster',
- 'rgb' => 'image/x-rgb',
- 'tif' => 'image/tiff',
- 'tiff' => 'image/tiff',
- 'xbm' => 'image/x-xbitmap',
- 'xpm' => 'image/x-xpixmap',
- 'xwd' => 'image/x-xwindowdump',
- 'ice' => 'x-conference/x-cooltalk',
- 'iges' => 'model/iges',
- 'igs' => 'model/iges',
- 'mesh' => 'model/mesh',
- 'msh' => 'model/mesh',
- 'silo' => 'model/mesh',
- 'vrml' => 'model/vrml',
- 'wrl' => 'model/vrml',
- 'mime' => 'www/mime',
- 'pdb' => 'chemical/x-pdb',
- 'xyz' => 'chemical/x-pdb',
- 'javascript' => 'text/javascript',
- 'json' => 'application/json',
- 'form' => 'application/x-www-form-urlencoded',
- 'file' => 'multipart/form-data',
- 'xhtml' => array('application/xhtml+xml', 'application/xhtml', 'text/xhtml'),
- 'xhtml-mobile' => 'application/vnd.wap.xhtml+xml',
- 'rss' => 'application/rss+xml',
- 'atom' => 'application/atom+xml',
- 'amf' => 'application/x-amf',
- 'wap' => array('text/vnd.wap.wml', 'text/vnd.wap.wmlscript', 'image/vnd.wap.wbmp'),
- 'wml' => 'text/vnd.wap.wml',
- 'wmlscript' => 'text/vnd.wap.wmlscript',
- 'wbmp' => 'image/vnd.wap.wbmp',
- );
-
-/**
- * Protocol header to send to the client
- *
- * @var string
- */
- protected $_protocol = 'HTTP/1.1';
-
-/**
- * Status code to send to the client
- *
- * @var integer
- */
- protected $_status = 200;
-
-/**
- * Content type to send. This can be an 'extension' that will be transformed using the $_mimetypes array
- * or a complete mime-type
- *
- * @var integer
- */
- protected $_contentType = 'text/html';
-
-/**
- * Buffer list of headers
- *
- * @var array
- */
- protected $_headers = array();
-
-/**
- * Buffer string for response message
- *
- * @var string
- */
- protected $_body = null;
-
-/**
- * The charset the response body is encoded with
- *
- * @var string
- */
- protected $_charset = 'UTF-8';
-
-/**
- * Holds all the cache directives that will be converted
- * into headers when sending the request
- *
- * @var string
- */
- protected $_cacheDirectives = array();
-
-/**
- * Holds cookies to be sent to the client
- *
- * @var array
- */
- protected $_cookies = array();
-
-/**
- * Class constructor
- *
- * @param array $options list of parameters to setup the response. Possible values are:
- * - body: the response text that should be sent to the client
- * - status: the HTTP status code to respond with
- * - type: a complete mime-type string or an extension mapped in this class
- * - charset: the charset for the response body
- */
- public function __construct(array $options = array()) {
- if (isset($options['body'])) {
- $this->body($options['body']);
- }
- if (isset($options['status'])) {
- $this->statusCode($options['status']);
- }
- if (isset($options['type'])) {
- $this->type($options['type']);
- }
- if (isset($options['charset'])) {
- $this->charset($options['charset']);
- }
- }
-
-/**
- * Sends the complete response to the client including headers and message body.
- * Will echo out the content in the response body.
- *
- * @return void
- */
- public function send() {
- if (isset($this->_headers['Location']) && $this->_status === 200) {
- $this->statusCode(302);
- }
-
- $codeMessage = $this->_statusCodes[$this->_status];
- $this->_setCookies();
- $this->_sendHeader("{$this->_protocol} {$this->_status} {$codeMessage}");
- $this->_setContent();
- $this->_setContentLength();
- $this->_setContentType();
- foreach ($this->_headers as $header => $value) {
- $this->_sendHeader($header, $value);
- }
- $this->_sendContent($this->_body);
- }
-
-/**
- * Sets the cookies that have been added via static method CakeResponse::addCookie()
- * before any other output is sent to the client.
- * Will set the cookies in the order they have been set.
- *
- * @return void
- */
- protected function _setCookies() {
- foreach ($this->_cookies as $name => $c) {
- setcookie(
- $name, $c['value'], $c['expire'], $c['path'],
- $c['domain'], $c['secure'], $c['httpOnly']
- );
- }
- }
-
-/**
- * Formats the Content-Type header based on the configured contentType and charset
- * the charset will only be set in the header if the response is of type text/*
- *
- * @return void
- */
- protected function _setContentType() {
- if (in_array($this->_status, array(304, 204))) {
- return;
- }
- if (strpos($this->_contentType, 'text/') === 0) {
- $this->header('Content-Type', "{$this->_contentType}; charset={$this->_charset}");
- } else {
- $this->header('Content-Type', "{$this->_contentType}");
- }
- }
-
-/**
- * Sets the response body to an empty text if the status code is 204 or 304
- *
- * @return void
- */
- protected function _setContent() {
- if (in_array($this->_status, array(304, 204))) {
- $this->body('');
- }
- }
-
-/**
- * Calculates the correct Content-Length and sets it as a header in the response
- * Will not set the value if already set or if the output is compressed.
- *
- * @return void
- */
- protected function _setContentLength() {
- $shouldSetLength = !isset($this->_headers['Content-Length']) && !in_array($this->_status, range(301, 307));
- if (isset($this->_headers['Content-Length']) && $this->_headers['Content-Length'] === false) {
- unset($this->_headers['Content-Length']);
- return;
- }
- if ($shouldSetLength && !$this->outputCompressed()) {
- $offset = ob_get_level() ? ob_get_length() : 0;
- if (ini_get('mbstring.func_overload') & 2 && function_exists('mb_strlen')) {
- $this->length($offset + mb_strlen($this->_body, '8bit'));
- } else {
- $this->length($this->_headers['Content-Length'] = $offset + strlen($this->_body));
- }
- }
- }
-
-/**
- * Sends a header to the client.
- *
- * @param string $name the header name
- * @param string $value the header value
- * @return void
- */
- protected function _sendHeader($name, $value = null) {
- if (!headers_sent()) {
- if (is_null($value)) {
- header($name);
- } else {
- header("{$name}: {$value}");
- }
- }
- }
-
-/**
- * Sends a content string to the client.
- *
- * @param string $content string to send as response body
- * @return void
- */
- protected function _sendContent($content) {
- echo $content;
- }
-
-/**
- * Buffers a header string to be sent
- * Returns the complete list of buffered headers
- *
- * ### Single header
- * e.g `header('Location', 'http://example.com');`
- *
- * ### Multiple headers
- * e.g `header(array('Location' => 'http://example.com', 'X-Extra' => 'My header'));`
- *
- * ### String header
- * e.g `header('WWW-Authenticate: Negotiate');`
- *
- * ### Array of string headers
- * e.g `header(array('WWW-Authenticate: Negotiate', 'Content-type: application/pdf'));`
- *
- * Multiple calls for setting the same header name will have the same effect as setting the header once
- * with the last value sent for it
- * e.g `header('WWW-Authenticate: Negotiate'); header('WWW-Authenticate: Not-Negotiate');`
- * will have the same effect as only doing `header('WWW-Authenticate: Not-Negotiate');`
- *
- * @param mixed $header. An array of header strings or a single header string
- * - an associative array of "header name" => "header value" is also accepted
- * - an array of string headers is also accepted
- * @param mixed $value. The header value.
- * @return array list of headers to be sent
- */
- public function header($header = null, $value = null) {
- if (is_null($header)) {
- return $this->_headers;
- }
- if (is_array($header)) {
- foreach ($header as $h => $v) {
- if (is_numeric($h)) {
- $this->header($v);
- continue;
- }
- $this->_headers[$h] = trim($v);
- }
- return $this->_headers;
- }
-
- if (!is_null($value)) {
- $this->_headers[$header] = $value;
- return $this->_headers;
- }
-
- list($header, $value) = explode(':', $header, 2);
- $this->_headers[$header] = trim($value);
- return $this->_headers;
- }
-
-/**
- * Buffers the response message to be sent
- * if $content is null the current buffer is returned
- *
- * @param string $content the string message to be sent
- * @return string current message buffer if $content param is passed as null
- */
- public function body($content = null) {
- if (is_null($content)) {
- return $this->_body;
- }
- return $this->_body = $content;
- }
-
-/**
- * Sets the HTTP status code to be sent
- * if $code is null the current code is returned
- *
- * @param integer $code
- * @return integer current status code
- * @throws CakeException When an unknown status code is reached.
- */
- public function statusCode($code = null) {
- if (is_null($code)) {
- return $this->_status;
- }
- if (!isset($this->_statusCodes[$code])) {
- throw new CakeException(__d('cake_dev', 'Unknown status code'));
- }
- return $this->_status = $code;
- }
-
-/**
- * Queries & sets valid HTTP response codes & messages.
- *
- * @param mixed $code If $code is an integer, then the corresponding code/message is
- * returned if it exists, null if it does not exist. If $code is an array,
- * then the 'code' and 'message' keys of each nested array are added to the default
- * HTTP codes. Example:
- *
- * httpCodes(404); // returns array(404 => 'Not Found')
- *
- * httpCodes(array(
- * 701 => 'Unicorn Moved',
- * 800 => 'Unexpected Minotaur'
- * )); // sets these new values, and returns true
- *
- * @return mixed associative array of the HTTP codes as keys, and the message
- * strings as values, or null of the given $code does not exist.
- */
- public function httpCodes($code = null) {
- if (empty($code)) {
- return $this->_statusCodes;
- }
-
- if (is_array($code)) {
- $this->_statusCodes = $code + $this->_statusCodes;
- return true;
- }
-
- if (!isset($this->_statusCodes[$code])) {
- return null;
- }
- return array($code => $this->_statusCodes[$code]);
- }
-
-/**
- * Sets the response content type. It can be either a file extension
- * which will be mapped internally to a mime-type or a string representing a mime-type
- * if $contentType is null the current content type is returned
- * if $contentType is an associative array, it will be stored as a content type definition
- *
- * ### Setting the content type
- *
- * e.g `type('jpg');`
- *
- * ### Returning the current content type
- *
- * e.g `type();`
- *
- * ### Storing a content type definition
- *
- * e.g `type(array('keynote' => 'application/keynote'));`
- *
- * ### Replacing a content type definition
- *
- * e.g `type(array('jpg' => 'text/plain'));`
- *
- * @param string $contentType
- * @return mixed current content type or false if supplied an invalid content type
- */
- public function type($contentType = null) {
- if (is_null($contentType)) {
- return $this->_contentType;
- }
- if (is_array($contentType)) {
- $type = key($contentType);
- $defitition = current($contentType);
- $this->_mimeTypes[$type] = $defitition;
- return $this->_contentType;
- }
- if (isset($this->_mimeTypes[$contentType])) {
- $contentType = $this->_mimeTypes[$contentType];
- $contentType = is_array($contentType) ? current($contentType) : $contentType;
- }
- if (strpos($contentType, '/') === false) {
- return false;
- }
- return $this->_contentType = $contentType;
- }
-
-/**
- * Returns the mime type definition for an alias
- *
- * e.g `getMimeType('pdf'); // returns 'application/pdf'`
- *
- * @param string $alias the content type alias to map
- * @return mixed string mapped mime type or false if $alias is not mapped
- */
- public function getMimeType($alias) {
- if (isset($this->_mimeTypes[$alias])) {
- return $this->_mimeTypes[$alias];
- }
- return false;
- }
-
-/**
- * Maps a content-type back to an alias
- *
- * e.g `mapType('application/pdf'); // returns 'pdf'`
- *
- * @param mixed $ctype Either a string content type to map, or an array of types.
- * @return mixed Aliases for the types provided.
- */
- public function mapType($ctype) {
- if (is_array($ctype)) {
- return array_map(array($this, 'mapType'), $ctype);
- }
-
- foreach ($this->_mimeTypes as $alias => $types) {
- if (is_array($types) && in_array($ctype, $types)) {
- return $alias;
- } elseif (is_string($types) && $types == $ctype) {
- return $alias;
- }
- }
- return null;
- }
-
-/**
- * Sets the response charset
- * if $charset is null the current charset is returned
- *
- * @param string $charset
- * @return string current charset
- */
- public function charset($charset = null) {
- if (is_null($charset)) {
- return $this->_charset;
- }
- return $this->_charset = $charset;
- }
-
-/**
- * Sets the correct headers to instruct the client to not cache the response
- *
- * @return void
- */
- public function disableCache() {
- $this->header(array(
- 'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
- 'Last-Modified' => gmdate("D, d M Y H:i:s") . " GMT",
- 'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'
- ));
- }
-
-/**
- * Sets the correct headers to instruct the client to cache the response.
- *
- * @param string $since a valid time since the response text has not been modified
- * @param string $time a valid time for cache expiry
- * @return void
- */
- public function cache($since, $time = '+1 day') {
- if (!is_integer($time)) {
- $time = strtotime($time);
- }
- $this->header(array(
- 'Date' => gmdate("D, j M Y G:i:s ", time()) . 'GMT'
- ));
- $this->modified($since);
- $this->expires($time);
- $this->sharable(true);
- $this->maxAge($time - time());
- }
-
-/**
- * Sets whether a response is eligible to be cached by intermediate proxies
- * This method controls the `public` or `private` directive in the Cache-Control
- * header
- *
- * @param boolean $public if set to true, the Cache-Control header will be set as public
- * if set to false, the response will be set to private
- * if no value is provided, it will return whether the response is sharable or not
- * @param int $time time in seconds after which the response should no longer be considered fresh
- * @return boolean
- */
- public function sharable($public = null, $time = null) {
- if ($public === null) {
- $public = array_key_exists('public', $this->_cacheDirectives);
- $private = array_key_exists('private', $this->_cacheDirectives);
- $noCache = array_key_exists('no-cache', $this->_cacheDirectives);
- if (!$public && !$private && !$noCache) {
- return null;
- }
- $sharable = $public || ! ($private || $noCache);
- return $sharable;
- }
- if ($public) {
- $this->_cacheDirectives['public'] = true;
- unset($this->_cacheDirectives['private']);
- $this->sharedMaxAge($time);
- } else {
- $this->_cacheDirectives['private'] = true;
- unset($this->_cacheDirectives['public']);
- $this->maxAge($time);
- }
- if ($time == null) {
- $this->_setCacheControl();
- }
- return (bool)$public;
- }
-
-/**
- * Sets the Cache-Control s-maxage directive.
- * The max-age is the number of seconds after which the response should no longer be considered
- * a good candidate to be fetched from a shared cache (like in a proxy server).
- * If called with no parameters, this function will return the current max-age value if any
- *
- * @param int $seconds if null, the method will return the current s-maxage value
- * @return int
- */
- public function sharedMaxAge($seconds = null) {
- if ($seconds !== null) {
- $this->_cacheDirectives['s-maxage'] = $seconds;
- $this->_setCacheControl();
- }
- if (isset($this->_cacheDirectives['s-maxage'])) {
- return $this->_cacheDirectives['s-maxage'];
- }
- return null;
- }
-
-/**
- * Sets the Cache-Control max-age directive.
- * The max-age is the number of seconds after which the response should no longer be considered
- * a good candidate to be fetched from the local (client) cache.
- * If called with no parameters, this function will return the current max-age value if any
- *
- * @param int $seconds if null, the method will return the current max-age value
- * @return int
- */
- public function maxAge($seconds = null) {
- if ($seconds !== null) {
- $this->_cacheDirectives['max-age'] = $seconds;
- $this->_setCacheControl();
- }
- if (isset($this->_cacheDirectives['max-age'])) {
- return $this->_cacheDirectives['max-age'];
- }
- return null;
- }
-
-/**
- * Sets the Cache-Control must-revalidate directive.
- * must-revalidate indicates that the response should not be served
- * stale by a cache under any cirumstance without first revalidating
- * with the origin.
- * If called with no parameters, this function will return wheter must-revalidate is present.
- *
- * @param int $seconds if null, the method will return the current
- * must-revalidate value
- * @return boolean
- */
- public function mustRevalidate($enable = null) {
- if ($enable !== null) {
- if ($enable) {
- $this->_cacheDirectives['must-revalidate'] = true;
- } else {
- unset($this->_cacheDirectives['must-revalidate']);
- }
- $this->_setCacheControl();
- }
- return array_key_exists('must-revalidate', $this->_cacheDirectives);
- }
-
-/**
- * Helper method to generate a valid Cache-Control header from the options set
- * in other methods
- *
- * @return void
- */
- protected function _setCacheControl() {
- $control = '';
- foreach ($this->_cacheDirectives as $key => $val) {
- $control .= $val === true ? $key : sprintf('%s=%s', $key, $val);
- $control .= ', ';
- }
- $control = rtrim($control, ', ');
- $this->header('Cache-Control', $control);
- }
-
-/**
- * Sets the Expires header for the response by taking an expiration time
- * If called with no parameters it will return the current Expires value
- *
- * ## Examples:
- *
- * `$response->expires('now')` Will Expire the response cache now
- * `$response->expires(new DateTime('+1 day'))` Will set the expiration in next 24 hours
- * `$response->expires()` Will return the current expiration header value
- *
- * @param string|DateTime $time
- * @return string
- */
- public function expires($time = null) {
- if ($time !== null) {
- $date = $this->_getUTCDate($time);
- $this->_headers['Expires'] = $date->format('D, j M Y H:i:s') . ' GMT';
- }
- if (isset($this->_headers['Expires'])) {
- return $this->_headers['Expires'];
- }
- return null;
- }
-
-/**
- * Sets the Last-Modified header for the response by taking an modification time
- * If called with no parameters it will return the current Last-Modified value
- *
- * ## Examples:
- *
- * `$response->modified('now')` Will set the Last-Modified to the current time
- * `$response->modified(new DateTime('+1 day'))` Will set the modification date in the past 24 hours
- * `$response->modified()` Will return the current Last-Modified header value
- *
- * @param string|DateTime $time
- * @return string
- */
- public function modified($time = null) {
- if ($time !== null) {
- $date = $this->_getUTCDate($time);
- $this->_headers['Last-Modified'] = $date->format('D, j M Y H:i:s') . ' GMT';
- }
- if (isset($this->_headers['Last-Modified'])) {
- return $this->_headers['Last-Modified'];
- }
- return null;
- }
-
-/**
- * Sets the response as Not Modified by removing any body contents
- * setting the status code to "304 Not Modified" and removing all
- * conflicting headers
- *
- * @return void
- **/
- public function notModified() {
- $this->statusCode(304);
- $this->body('');
- $remove = array(
- 'Allow',
- 'Content-Encoding',
- 'Content-Language',
- 'Content-Length',
- 'Content-MD5',
- 'Content-Type',
- 'Last-Modified'
- );
- foreach ($remove as $header) {
- unset($this->_headers[$header]);
- }
- }
-
-/**
- * Sets the Vary header for the response, if an array is passed,
- * values will be imploded into a comma separated string. If no
- * parameters are passed, then an array with the current Vary header
- * value is returned
- *
- * @param string|array $cacheVariances a single Vary string or a array
- * containig the list for variances.
- * @return array
- **/
- public function vary($cacheVariances = null) {
- if ($cacheVariances !== null) {
- $cacheVariances = (array)$cacheVariances;
- $this->_headers['Vary'] = implode(', ', $cacheVariances);
- }
- if (isset($this->_headers['Vary'])) {
- return explode(', ', $this->_headers['Vary']);
- }
- return null;
- }
-
-/**
- * Sets the response Etag, Etags are a strong indicative that a response
- * can be cached by a HTTP client. A bad way of generaing Etags is
- * creating a hash of the response output, instead generate a unique
- * hash of the unique components that identifies a request, such as a
- * modification time, a resource Id, and anything else you consider it
- * makes it unique.
- *
- * Second parameter is used to instuct clients that the content has
- * changed, but sematicallly, it can be used as the same thing. Think
- * for instance of a page with a hit counter, two different page views
- * are equivalent, but they differ by a few bytes. This leaves off to
- * the Client the decision of using or not the cached page.
- *
- * If no parameters are passed, current Etag header is returned.
- *
- * @param string $hash the unique has that identifies this resposnse
- * @param boolean $weak whether the response is semantically the same as
- * other with th same hash or not
- * @return string
- **/
- public function etag($tag = null, $weak = false) {
- if ($tag !== null) {
- $this->_headers['Etag'] = sprintf('%s"%s"', ($weak) ? 'W/' : null, $tag);
- }
- if (isset($this->_headers['Etag'])) {
- return $this->_headers['Etag'];
- }
- return null;
- }
-
-/**
- * Returns a DateTime object initialized at the $time param and using UTC
- * as timezone
- *
- * @param string|int|DateTime $time
- * @return DateTime
- */
- protected function _getUTCDate($time = null) {
- if ($time instanceof DateTime) {
- $result = clone $time;
- } elseif (is_integer($time)) {
- $result = new DateTime(date('Y-m-d H:i:s', $time));
- } else {
- $result = new DateTime($time);
- }
- $result->setTimeZone(new DateTimeZone('UTC'));
- return $result;
- }
-
-/**
- * Sets the correct output buffering handler to send a compressed response. Responses will
- * be compressed with zlib, if the extension is available.
- *
- * @return boolean false if client does not accept compressed responses or no handler is available, true otherwise
- */
- public function compress() {
- $compressionEnabled = ini_get("zlib.output_compression") !== '1' &&
- extension_loaded("zlib") &&
- (strpos(env('HTTP_ACCEPT_ENCODING'), 'gzip') !== false);
- return $compressionEnabled && ob_start('ob_gzhandler');
- }
-
-/**
- * Returns whether the resulting output will be compressed by PHP
- *
- * @return boolean
- */
- public function outputCompressed() {
- return strpos(env('HTTP_ACCEPT_ENCODING'), 'gzip') !== false
- && (ini_get("zlib.output_compression") === '1' || in_array('ob_gzhandler', ob_list_handlers()));
- }
-
-/**
- * Sets the correct headers to instruct the browser to download the response as a file.
- *
- * @param string $filename the name of the file as the browser will download the response
- * @return void
- */
- public function download($filename) {
- $this->header('Content-Disposition', 'attachment; filename="' . $filename . '"');
- }
-
-/**
- * Sets the protocol to be used when sending the response. Defaults to HTTP/1.1
- * If called with no arguments, it will return the current configured protocol
- *
- * @return string protocol to be used for sending response
- */
- public function protocol($protocol = null) {
- if ($protocol !== null) {
- $this->_protocol = $protocol;
- }
- return $this->_protocol;
- }
-
-/**
- * Sets the Content-Length header for the response
- * If called with no arguments returns the last Content-Length set
- *
- * @return int
- */
- public function length($bytes = null) {
- if ($bytes !== null ) {
- $this->_headers['Content-Length'] = $bytes;
- }
- if (isset($this->_headers['Content-Length'])) {
- return $this->_headers['Content-Length'];
- }
- return null;
- }
-
-/**
- * Checks whether a response has not been modified according to the 'If-None-Match'
- * (Etags) and 'If-Modified-Since' (last modification date) request
- * headers headers. If the response is detected to be not modified, it
- * is marked as so accordingly so the client can be informed of that.
- *
- * In order to mark a response as not modified, you need to set at least
- * the Last-Modified response header or a response etag to be compared
- * with the request itself
- *
- * @return boolean whether the response was marked as not modified or
- * not
- **/
- public function checkNotModified(CakeRequest $request) {
- $etags = preg_split('/\s*,\s*/', $request->header('If-None-Match'), null, PREG_SPLIT_NO_EMPTY);
- $modifiedSince = $request->header('If-Modified-Since');
- if ($responseTag = $this->etag()) {
- $etagMatches = in_array('*', $etags) || in_array($responseTag, $etags);
- }
- if ($modifiedSince) {
- $timeMatches = strtotime($this->modified()) == strtotime($modifiedSince);
- }
- $checks = compact('etagMatches', 'timeMatches');
- if (empty($checks)) {
- return false;
- }
- $notModified = !in_array(false, $checks, true);
- if ($notModified) {
- $this->notModified();
- }
- return $notModified;
- }
-
-/**
- * String conversion. Fetches the response body as a string.
- * Does *not* send headers.
- *
- * @return string
- */
- public function __toString() {
- return (string)$this->_body;
- }
-
-/**
- * Getter/Setter for cookie configs
- *
- * This method acts as a setter/getter depending on the type of the argument.
- * If the method is called with no arguments, it returns all configurations.
- *
- * If the method is called with a string as argument, it returns either the
- * given configuration if it is set, or null, if it's not set.
- *
- * If the method is called with an array as argument, it will set the cookie
- * configuration to the cookie container.
- *
- * @param $options Either null to get all cookies, string for a specific cookie
- * or array to set cookie.
- *
- * ### Options (when setting a configuration)
- * - name: The Cookie name
- * - value: Value of the cookie
- * - expire: Time the cookie expires in
- * - path: Path the cookie applies to
- * - domain: Domain the cookie is for.
- * - secure: Is the cookie https?
- * - httpOnly: Is the cookie available in the client?
- *
- * ## Examples
- *
- * ### Getting all cookies
- *
- * `$this->cookie()`
- *
- * ### Getting a certain cookie configuration
- *
- * `$this->cookie('MyCookie')`
- *
- * ### Setting a cookie configuration
- *
- * `$this->cookie((array) $options)`
- *
- * @return mixed
- */
- public function cookie($options = null) {
- if ($options === null) {
- return $this->_cookies;
- }
-
- if (is_string($options)) {
- if (!isset($this->_cookies[$options])) {
- return null;
- }
- return $this->_cookies[$options];
- }
-
- $defaults = array(
- 'name' => 'CakeCookie[default]',
- 'value' => '',
- 'expire' => 0,
- 'path' => '/',
- 'domain' => '',
- 'secure' => false,
- 'httpOnly' => false
- );
- $options += $defaults;
-
- $this->_cookies[$options['name']] = $options;
- }
-
-}
diff --git a/lib/Cake/Network/CakeSocket.php b/lib/Cake/Network/CakeSocket.php
deleted file mode 100644
index aa0eb4fbd43..00000000000
--- a/lib/Cake/Network/CakeSocket.php
+++ /dev/null
@@ -1,280 +0,0 @@
- false,
- 'host' => 'localhost',
- 'protocol' => 'tcp',
- 'port' => 80,
- 'timeout' => 30
- );
-
-/**
- * Configuration settings for the socket connection
- *
- * @var array
- */
- public $config = array();
-
-/**
- * Reference to socket connection resource
- *
- * @var resource
- */
- public $connection = null;
-
-/**
- * This boolean contains the current state of the CakeSocket class
- *
- * @var boolean
- */
- public $connected = false;
-
-/**
- * This variable contains an array with the last error number (num) and string (str)
- *
- * @var array
- */
- public $lastError = array();
-
-/**
- * Constructor.
- *
- * @param array $config Socket configuration, which will be merged with the base configuration
- * @see CakeSocket::$_baseConfig
- */
- public function __construct($config = array()) {
- $this->config = array_merge($this->_baseConfig, $config);
- if (!is_numeric($this->config['protocol'])) {
- $this->config['protocol'] = getprotobyname($this->config['protocol']);
- }
- }
-
-/**
- * Connect the socket to the given host and port.
- *
- * @return boolean Success
- * @throws SocketException
- */
- public function connect() {
- if ($this->connection != null) {
- $this->disconnect();
- }
-
- $scheme = null;
- if (isset($this->config['request']) && $this->config['request']['uri']['scheme'] == 'https') {
- $scheme = 'ssl://';
- }
-
- if ($this->config['persistent'] == true) {
- $this->connection = @pfsockopen($scheme . $this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']);
- } else {
- $this->connection = @fsockopen($scheme . $this->config['host'], $this->config['port'], $errNum, $errStr, $this->config['timeout']);
- }
-
- if (!empty($errNum) || !empty($errStr)) {
- $this->setLastError($errNum, $errStr);
- throw new SocketException($errStr, $errNum);
- }
-
- $this->connected = is_resource($this->connection);
- if ($this->connected) {
- stream_set_timeout($this->connection, $this->config['timeout']);
- }
- return $this->connected;
- }
-
-/**
- * Get the host name of the current connection.
- *
- * @return string Host name
- */
- public function host() {
- if (Validation::ip($this->config['host'])) {
- return gethostbyaddr($this->config['host']);
- }
- return gethostbyaddr($this->address());
- }
-
-/**
- * Get the IP address of the current connection.
- *
- * @return string IP address
- */
- public function address() {
- if (Validation::ip($this->config['host'])) {
- return $this->config['host'];
- }
- return gethostbyname($this->config['host']);
- }
-
-/**
- * Get all IP addresses associated with the current connection.
- *
- * @return array IP addresses
- */
- public function addresses() {
- if (Validation::ip($this->config['host'])) {
- return array($this->config['host']);
- }
- return gethostbynamel($this->config['host']);
- }
-
-/**
- * Get the last error as a string.
- *
- * @return string Last error
- */
- public function lastError() {
- if (!empty($this->lastError)) {
- return $this->lastError['num'] . ': ' . $this->lastError['str'];
- }
- return null;
- }
-
-/**
- * Set the last error.
- *
- * @param integer $errNum Error code
- * @param string $errStr Error string
- * @return void
- */
- public function setLastError($errNum, $errStr) {
- $this->lastError = array('num' => $errNum, 'str' => $errStr);
- }
-
-/**
- * Write data to the socket.
- *
- * @param string $data The data to write to the socket
- * @return boolean Success
- */
- public function write($data) {
- if (!$this->connected) {
- if (!$this->connect()) {
- return false;
- }
- }
- $totalBytes = strlen($data);
- for ($written = 0, $rv = 0; $written < $totalBytes; $written += $rv) {
- $rv = fwrite($this->connection, substr($data, $written));
- if ($rv === false || $rv === 0) {
- return $written;
- }
- }
- return $written;
- }
-
-/**
- * Read data from the socket. Returns false if no data is available or no connection could be
- * established.
- *
- * @param integer $length Optional buffer length to read; defaults to 1024
- * @return mixed Socket data
- */
- public function read($length = 1024) {
- if (!$this->connected) {
- if (!$this->connect()) {
- return false;
- }
- }
-
- if (!feof($this->connection)) {
- $buffer = fread($this->connection, $length);
- $info = stream_get_meta_data($this->connection);
- if ($info['timed_out']) {
- $this->setLastError(E_WARNING, __d('cake_dev', 'Connection timed out'));
- return false;
- }
- return $buffer;
- }
- return false;
- }
-
-/**
- * Disconnect the socket from the current connection.
- *
- * @return boolean Success
- */
- public function disconnect() {
- if (!is_resource($this->connection)) {
- $this->connected = false;
- return true;
- }
- $this->connected = !fclose($this->connection);
-
- if (!$this->connected) {
- $this->connection = null;
- }
- return !$this->connected;
- }
-
-/**
- * Destructor, used to disconnect from current connection.
- *
- */
- public function __destruct() {
- $this->disconnect();
- }
-
-/**
- * Resets the state of this Socket instance to it's initial state (before Object::__construct got executed)
- *
- * @param array $state Array with key and values to reset
- * @return boolean True on success
- */
- public function reset($state = null) {
- if (empty($state)) {
- static $initalState = array();
- if (empty($initalState)) {
- $initalState = get_class_vars(__CLASS__);
- }
- $state = $initalState;
- }
-
- foreach ($state as $property => $value) {
- $this->{$property} = $value;
- }
- return true;
- }
-
-}
diff --git a/lib/Cake/Network/Email/AbstractTransport.php b/lib/Cake/Network/Email/AbstractTransport.php
deleted file mode 100644
index 401d51152eb..00000000000
--- a/lib/Cake/Network/Email/AbstractTransport.php
+++ /dev/null
@@ -1,76 +0,0 @@
-_config = $config;
- }
- return $this->_config;
- }
-
-/**
- * Help to convert headers in string
- *
- * @param array $headers Headers in format key => value
- * @param string $eol
- * @return string
- */
- protected function _headersToString($headers, $eol = "\r\n") {
- $out = '';
- foreach ($headers as $key => $value) {
- if ($value === false || $value === null || $value === '') {
- continue;
- }
- $out .= $key . ': ' . $value . $eol;
- }
- if (!empty($out)) {
- $out = substr($out, 0, -1 * strlen($eol));
- }
- return $out;
- }
-
-}
diff --git a/lib/Cake/Network/Email/CakeEmail.php b/lib/Cake/Network/Email/CakeEmail.php
deleted file mode 100644
index be21205ad2c..00000000000
--- a/lib/Cake/Network/Email/CakeEmail.php
+++ /dev/null
@@ -1,1478 +0,0 @@
-_appCharset = Configure::read('App.encoding');
- if ($this->_appCharset !== null) {
- $this->charset = $this->_appCharset;
- }
- if ($config) {
- $this->config($config);
- }
- if (empty($this->headerCharset)) {
- $this->headerCharset = $this->charset;
- }
- }
-
-/**
- * From
- *
- * @param mixed $email
- * @param string $name
- * @return mixed
- * @throws SocketException
- */
- public function from($email = null, $name = null) {
- if ($email === null) {
- return $this->_from;
- }
- return $this->_setEmailSingle('_from', $email, $name, __d('cake_dev', 'From requires only 1 email address.'));
- }
-
-/**
- * Sender
- *
- * @param mixed $email
- * @param string $name
- * @return mixed
- * @throws SocketException
- */
- public function sender($email = null, $name = null) {
- if ($email === null) {
- return $this->_sender;
- }
- return $this->_setEmailSingle('_sender', $email, $name, __d('cake_dev', 'Sender requires only 1 email address.'));
- }
-
-/**
- * Reply-To
- *
- * @param mixed $email
- * @param string $name
- * @return mixed
- * @throws SocketException
- */
- public function replyTo($email = null, $name = null) {
- if ($email === null) {
- return $this->_replyTo;
- }
- return $this->_setEmailSingle('_replyTo', $email, $name, __d('cake_dev', 'Reply-To requires only 1 email address.'));
- }
-
-/**
- * Read Receipt (Disposition-Notification-To header)
- *
- * @param mixed $email
- * @param string $name
- * @return mixed
- * @throws SocketException
- */
- public function readReceipt($email = null, $name = null) {
- if ($email === null) {
- return $this->_readReceipt;
- }
- return $this->_setEmailSingle('_readReceipt', $email, $name, __d('cake_dev', 'Disposition-Notification-To requires only 1 email address.'));
- }
-
-/**
- * Return Path
- *
- * @param mixed $email
- * @param string $name
- * @return mixed
- * @throws SocketException
- */
- public function returnPath($email = null, $name = null) {
- if ($email === null) {
- return $this->_returnPath;
- }
- return $this->_setEmailSingle('_returnPath', $email, $name, __d('cake_dev', 'Return-Path requires only 1 email address.'));
- }
-
-/**
- * To
- *
- * @param mixed $email Null to get, String with email, Array with email as key, name as value or email as value (without name)
- * @param string $name
- * @return mixed
- */
- public function to($email = null, $name = null) {
- if ($email === null) {
- return $this->_to;
- }
- return $this->_setEmail('_to', $email, $name);
- }
-
-/**
- * Add To
- *
- * @param mixed $email String with email, Array with email as key, name as value or email as value (without name)
- * @param string $name
- * @return CakeEmail $this
- */
- public function addTo($email, $name = null) {
- return $this->_addEmail('_to', $email, $name);
- }
-
-/**
- * Cc
- *
- * @param mixed $email String with email, Array with email as key, name as value or email as value (without name)
- * @param string $name
- * @return mixed
- */
- public function cc($email = null, $name = null) {
- if ($email === null) {
- return $this->_cc;
- }
- return $this->_setEmail('_cc', $email, $name);
- }
-
-/**
- * Add Cc
- *
- * @param mixed $email String with email, Array with email as key, name as value or email as value (without name)
- * @param string $name
- * @return CakeEmail $this
- */
- public function addCc($email, $name = null) {
- return $this->_addEmail('_cc', $email, $name);
- }
-
-/**
- * Bcc
- *
- * @param mixed $email String with email, Array with email as key, name as value or email as value (without name)
- * @param string $name
- * @return mixed
- */
- public function bcc($email = null, $name = null) {
- if ($email === null) {
- return $this->_bcc;
- }
- return $this->_setEmail('_bcc', $email, $name);
- }
-
-/**
- * Add Bcc
- *
- * @param mixed $email String with email, Array with email as key, name as value or email as value (without name)
- * @param string $name
- * @return CakeEmail $this
- */
- public function addBcc($email, $name = null) {
- return $this->_addEmail('_bcc', $email, $name);
- }
-
-/**
- * Set email
- *
- * @param string $varName
- * @param mixed $email
- * @param mixed $name
- * @return CakeEmail $this
- * @throws SocketException
- */
- protected function _setEmail($varName, $email, $name) {
- if (!is_array($email)) {
- if (!Validation::email($email)) {
- throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $email));
- }
- if ($name === null) {
- $name = $email;
- }
- $this->{$varName} = array($email => $name);
- return $this;
- }
- $list = array();
- foreach ($email as $key => $value) {
- if (is_int($key)) {
- $key = $value;
- }
- if (!Validation::email($key)) {
- throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $key));
- }
- $list[$key] = $value;
- }
- $this->{$varName} = $list;
- return $this;
- }
-
-/**
- * Set only 1 email
- *
- * @param string $varName
- * @param mixed $email
- * @param string $name
- * @param string $throwMessage
- * @return CakeEmail $this
- * @throws SocketException
- */
- protected function _setEmailSingle($varName, $email, $name, $throwMessage) {
- $current = $this->{$varName};
- $this->_setEmail($varName, $email, $name);
- if (count($this->{$varName}) !== 1) {
- $this->{$varName} = $current;
- throw new SocketException($throwMessage);
- }
- return $this;
- }
-
-/**
- * Add email
- *
- * @param string $varName
- * @param mixed $email
- * @param mixed $name
- * @return CakeEmail $this
- * @throws SocketException
- */
- protected function _addEmail($varName, $email, $name) {
- if (!is_array($email)) {
- if (!Validation::email($email)) {
- throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $email));
- }
- if ($name === null) {
- $name = $email;
- }
- $this->{$varName}[$email] = $name;
- return $this;
- }
- $list = array();
- foreach ($email as $key => $value) {
- if (is_int($key)) {
- $key = $value;
- }
- if (!Validation::email($key)) {
- throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $key));
- }
- $list[$key] = $value;
- }
- $this->{$varName} = array_merge($this->{$varName}, $list);
- return $this;
- }
-
-/**
- * Get/Set Subject.
- *
- * @param null|string $subject
- * @return mixed
- */
- public function subject($subject = null) {
- if ($subject === null) {
- return $this->_subject;
- }
- $this->_subject = $this->_encode((string)$subject);
- return $this;
- }
-
-/**
- * Sets headers for the message
- *
- * @param array $headers Associative array containing headers to be set.
- * @return CakeEmail $this
- * @throws SocketException
- */
- public function setHeaders($headers) {
- if (!is_array($headers)) {
- throw new SocketException(__d('cake_dev', '$headers should be an array.'));
- }
- $this->_headers = $headers;
- return $this;
- }
-
-/**
- * Add header for the message
- *
- * @param array $headers
- * @return object $this
- * @throws SocketException
- */
- public function addHeaders($headers) {
- if (!is_array($headers)) {
- throw new SocketException(__d('cake_dev', '$headers should be an array.'));
- }
- $this->_headers = array_merge($this->_headers, $headers);
- return $this;
- }
-
-/**
- * Get list of headers
- *
- * ### Includes:
- *
- * - `from`
- * - `replyTo`
- * - `readReceipt`
- * - `returnPath`
- * - `to`
- * - `cc`
- * - `bcc`
- * - `subject`
- *
- * @param array $include
- * @return array
- */
- public function getHeaders($include = array()) {
- if ($include == array_values($include)) {
- $include = array_fill_keys($include, true);
- }
- $defaults = array_fill_keys(array('from', 'sender', 'replyTo', 'readReceipt', 'returnPath', 'to', 'cc', 'bcc', 'subject'), false);
- $include += $defaults;
-
- $headers = array();
- $relation = array(
- 'from' => 'From',
- 'replyTo' => 'Reply-To',
- 'readReceipt' => 'Disposition-Notification-To',
- 'returnPath' => 'Return-Path'
- );
- foreach ($relation as $var => $header) {
- if ($include[$var]) {
- $var = '_' . $var;
- $headers[$header] = current($this->_formatAddress($this->{$var}));
- }
- }
- if ($include['sender']) {
- if (key($this->_sender) === key($this->_from)) {
- $headers['Sender'] = '';
- } else {
- $headers['Sender'] = current($this->_formatAddress($this->_sender));
- }
- }
-
- foreach (array('to', 'cc', 'bcc') as $var) {
- if ($include[$var]) {
- $classVar = '_' . $var;
- $headers[ucfirst($var)] = implode(', ', $this->_formatAddress($this->{$classVar}));
- }
- }
-
- $headers += $this->_headers;
- if (!isset($headers['X-Mailer'])) {
- $headers['X-Mailer'] = self::EMAIL_CLIENT;
- }
- if (!isset($headers['Date'])) {
- $headers['Date'] = date(DATE_RFC2822);
- }
- if ($this->_messageId !== false) {
- if ($this->_messageId === true) {
- $headers['Message-ID'] = '<' . str_replace('-', '', String::UUID()) . '@' . env('HTTP_HOST') . '>';
- } else {
- $headers['Message-ID'] = $this->_messageId;
- }
- }
-
- if ($include['subject']) {
- $headers['Subject'] = $this->_subject;
- }
-
- $headers['MIME-Version'] = '1.0';
- if (!empty($this->_attachments) || $this->_emailFormat === 'both') {
- $headers['Content-Type'] = 'multipart/mixed; boundary="' . $this->_boundary . '"';
- } elseif ($this->_emailFormat === 'text') {
- $headers['Content-Type'] = 'text/plain; charset=' . $this->charset;
- } elseif ($this->_emailFormat === 'html') {
- $headers['Content-Type'] = 'text/html; charset=' . $this->charset;
- }
- $headers['Content-Transfer-Encoding'] = $this->_getContentTransferEncoding();
-
- return $headers;
- }
-
-/**
- * Format addresses
- *
- * @param array $address
- * @return array
- */
- protected function _formatAddress($address) {
- $return = array();
- foreach ($address as $email => $alias) {
- if ($email === $alias) {
- $return[] = $email;
- } else {
- if (strpos($alias, ',') !== false) {
- $alias = '"' . $alias . '"';
- }
- $return[] = sprintf('%s <%s>', $this->_encode($alias), $email);
- }
- }
- return $return;
- }
-
-/**
- * Template and layout
- *
- * @param mixed $template Template name or null to not use
- * @param mixed $layout Layout name or null to not use
- * @return mixed
- */
- public function template($template = false, $layout = false) {
- if ($template === false) {
- return array(
- 'template' => $this->_template,
- 'layout' => $this->_layout
- );
- }
- $this->_template = $template;
- if ($layout !== false) {
- $this->_layout = $layout;
- }
- return $this;
- }
-
-/**
- * View class for render
- *
- * @param string $viewClass
- * @return mixed
- */
- public function viewRender($viewClass = null) {
- if ($viewClass === null) {
- return $this->_viewRender;
- }
- $this->_viewRender = $viewClass;
- return $this;
- }
-
-/**
- * Variables to be set on render
- *
- * @param array $viewVars
- * @return mixed
- */
- public function viewVars($viewVars = null) {
- if ($viewVars === null) {
- return $this->_viewVars;
- }
- $this->_viewVars = array_merge($this->_viewVars, (array)$viewVars);
- return $this;
- }
-
-/**
- * Helpers to be used in render
- *
- * @param array $helpers
- * @return mixed
- */
- public function helpers($helpers = null) {
- if ($helpers === null) {
- return $this->_helpers;
- }
- $this->_helpers = (array)$helpers;
- return $this;
- }
-
-/**
- * Email format
- *
- * @param string $format
- * @return mixed
- * @throws SocketException
- */
- public function emailFormat($format = null) {
- if ($format === null) {
- return $this->_emailFormat;
- }
- if (!in_array($format, $this->_emailFormatAvailable)) {
- throw new SocketException(__d('cake_dev', 'Format not available.'));
- }
- $this->_emailFormat = $format;
- return $this;
- }
-
-/**
- * Transport name
- *
- * @param string $name
- * @return mixed
- */
- public function transport($name = null) {
- if ($name === null) {
- return $this->_transportName;
- }
- $this->_transportName = (string)$name;
- $this->_transportClass = null;
- return $this;
- }
-
-/**
- * Return the transport class
- *
- * @return CakeEmail
- * @throws SocketException
- */
- public function transportClass() {
- if ($this->_transportClass) {
- return $this->_transportClass;
- }
- list($plugin, $transportClassname) = pluginSplit($this->_transportName, true);
- $transportClassname .= 'Transport';
- App::uses($transportClassname, $plugin . 'Network/Email');
- if (!class_exists($transportClassname)) {
- throw new SocketException(__d('cake_dev', 'Class "%s" not found.', $transportClassname));
- } elseif (!method_exists($transportClassname, 'send')) {
- throw new SocketException(__d('cake_dev', 'The "%s" do not have send method.', $transportClassname));
- }
-
- return $this->_transportClass = new $transportClassname();
- }
-
-/**
- * Message-ID
- *
- * @param mixed $message True to generate a new Message-ID, False to ignore (not send in email), String to set as Message-ID
- * @return mixed
- * @throws SocketException
- */
- public function messageId($message = null) {
- if ($message === null) {
- return $this->_messageId;
- }
- if (is_bool($message)) {
- $this->_messageId = $message;
- } else {
- if (!preg_match('/^\<.+@.+\>$/', $message)) {
- throw new SocketException(__d('cake_dev', 'Invalid format for Message-ID. The text should be something like ""'));
- }
- $this->_messageId = $message;
- }
- return $this;
- }
-
-/**
- * Add attachments to the email message
- *
- * Attachments can be defined in a few forms depending on how much control you need:
- *
- * Attach a single file:
- *
- * {{{
- * $email->attachments('path/to/file');
- * }}}
- *
- * Attach a file with a different filename:
- *
- * {{{
- * $email->attachments(array('custom_name.txt' => 'path/to/file.txt'));
- * }}}
- *
- * Attach a file and specify additional properties:
- *
- * {{{
- * $email->attachments(array('custom_name.png' => array(
- * 'file' => 'path/to/file',
- * 'mimetype' => 'image/png',
- * 'contentId' => 'abc123'
- * ));
- * }}}
- *
- * The `contentId` key allows you to specify an inline attachment. In your email text, you
- * can use ` ` to display the image inline.
- *
- * @param mixed $attachments String with the filename or array with filenames
- * @return mixed Either the array of attachments when getting or $this when setting.
- * @throws SocketException
- */
- public function attachments($attachments = null) {
- if ($attachments === null) {
- return $this->_attachments;
- }
- $attach = array();
- foreach ((array)$attachments as $name => $fileInfo) {
- if (!is_array($fileInfo)) {
- $fileInfo = array('file' => $fileInfo);
- }
- if (!isset($fileInfo['file'])) {
- throw new SocketException(__d('cake_dev', 'File not specified.'));
- }
- $fileInfo['file'] = realpath($fileInfo['file']);
- if ($fileInfo['file'] === false || !file_exists($fileInfo['file'])) {
- throw new SocketException(__d('cake_dev', 'File not found: "%s"', $fileInfo['file']));
- }
- if (is_int($name)) {
- $name = basename($fileInfo['file']);
- }
- if (!isset($fileInfo['mimetype'])) {
- $fileInfo['mimetype'] = 'application/octet-stream';
- }
- $attach[$name] = $fileInfo;
- }
- $this->_attachments = $attach;
- return $this;
- }
-
-/**
- * Add attachments
- *
- * @param mixed $attachments String with the filename or array with filenames
- * @return CakeEmail $this
- * @throws SocketException
- */
- public function addAttachments($attachments) {
- $current = $this->_attachments;
- $this->attachments($attachments);
- $this->_attachments = array_merge($current, $this->_attachments);
- return $this;
- }
-
-/**
- * Get generated message (used by transport classes)
- *
- * @param mixed $type Use MESSAGE_* constants or null to return the full message as array
- * @return mixed String if have type, array if type is null
- */
- public function message($type = null) {
- switch ($type) {
- case self::MESSAGE_HTML:
- return $this->_htmlMessage;
- case self::MESSAGE_TEXT:
- return $this->_textMessage;
- }
- return $this->_message;
- }
-
-/**
- * Configuration to use when send email
- *
- * @param mixed $config String with configuration name (from email.php), array with config or null to return current config
- * @return mixed
- */
- public function config($config = null) {
- if ($config === null) {
- return $this->_config;
- }
- if (!is_array($config)) {
- $config = (string)$config;
- }
-
- $this->_applyConfig($config);
- return $this;
- }
-
-/**
- * Send an email using the specified content, template and layout
- *
- * @param mixed $content String with message or array with messages
- * @return array
- * @throws SocketException
- */
- public function send($content = null) {
- if (empty($this->_from)) {
- throw new SocketException(__d('cake_dev', 'From is not specified.'));
- }
- if (empty($this->_to) && empty($this->_cc) && empty($this->_bcc)) {
- throw new SocketException(__d('cake_dev', 'You need to specify at least one destination for to, cc or bcc.'));
- }
-
- if (is_array($content)) {
- $content = implode("\n", $content) . "\n";
- }
-
- $this->_textMessage = $this->_htmlMessage = '';
- $this->_createBoundary();
- $this->_message = $this->_render($this->_wrap($content));
-
- $contents = $this->transportClass()->send($this);
- if (!empty($this->_config['log'])) {
- $level = LOG_DEBUG;
- if ($this->_config['log'] !== true) {
- $level = $this->_config['log'];
- }
- CakeLog::write($level, PHP_EOL . $contents['headers'] . PHP_EOL . $contents['message']);
- }
- return $contents;
- }
-
-/**
- * Static method to fast create an instance of CakeEmail
- *
- * @param mixed $to Address to send (see CakeEmail::to()). If null, will try to use 'to' from transport config
- * @param mixed $subject String of subject or null to use 'subject' from transport config
- * @param mixed $message String with message or array with variables to be used in render
- * @param mixed $transportConfig String to use config from EmailConfig or array with configs
- * @param boolean $send Send the email or just return the instance pre-configured
- * @return CakeEmail Instance of CakeEmail
- * @throws SocketException
- */
- public static function deliver($to = null, $subject = null, $message = null, $transportConfig = 'fast', $send = true) {
- $class = __CLASS__;
- $instance = new $class($transportConfig);
- if ($to !== null) {
- $instance->to($to);
- }
- if ($subject !== null) {
- $instance->subject($subject);
- }
- if (is_array($message)) {
- $instance->viewVars($message);
- $message = null;
- } elseif ($message === null && array_key_exists('message', $config = $instance->config())) {
- $message = $config['message'];
- }
-
- if ($send === true) {
- $instance->send($message);
- }
-
- return $instance;
- }
-
-/**
- * Apply the config to an instance
- *
- * @param CakeEmail $obj CakeEmail
- * @param array $config
- * @return void
- * @throws ConfigureException When configuration file cannot be found, or is missing
- * the named config.
- */
- protected function _applyConfig($config) {
- if (is_string($config)) {
- if (!class_exists('EmailConfig') && !config('email')) {
- throw new ConfigureException(__d('cake_dev', '%s not found.', APP . 'Config' . DS . 'email.php'));
- }
- $configs = new EmailConfig();
- if (!isset($configs->{$config})) {
- throw new ConfigureException(__d('cake_dev', 'Unknown email configuration "%s".', $config));
- }
- $config = $configs->{$config};
- }
- $this->_config += $config;
- if (!empty($config['charset'])) {
- $this->charset = $config['charset'];
- }
- if (!empty($config['headerCharset'])) {
- $this->headerCharset = $config['headerCharset'];
- }
- if (empty($this->headerCharset)) {
- $this->headerCharset = $this->charset;
- }
- $simpleMethods = array(
- 'from', 'sender', 'to', 'replyTo', 'readReceipt', 'returnPath', 'cc', 'bcc',
- 'messageId', 'subject', 'viewRender', 'viewVars', 'attachments',
- 'transport', 'emailFormat'
- );
- foreach ($simpleMethods as $method) {
- if (isset($config[$method])) {
- $this->$method($config[$method]);
- unset($config[$method]);
- }
- }
- if (isset($config['headers'])) {
- $this->setHeaders($config['headers']);
- unset($config['headers']);
- }
- if (array_key_exists('template', $config)) {
- $layout = false;
- if (array_key_exists('layout', $config)) {
- $layout = $config['layout'];
- unset($config['layout']);
- }
- $this->template($config['template'], $layout);
- unset($config['template']);
- }
- $this->transportClass()->config($config);
- }
-
-/**
- * Reset all EmailComponent internal variables to be able to send out a new email.
- *
- * @return CakeEmail $this
- */
- public function reset() {
- $this->_to = array();
- $this->_from = array();
- $this->_sender = array();
- $this->_replyTo = array();
- $this->_readReceipt = array();
- $this->_returnPath = array();
- $this->_cc = array();
- $this->_bcc = array();
- $this->_messageId = true;
- $this->_subject = '';
- $this->_headers = array();
- $this->_layout = 'default';
- $this->_template = '';
- $this->_viewRender = 'View';
- $this->_viewVars = array();
- $this->_helpers = array('Html');
- $this->_textMessage = '';
- $this->_htmlMessage = '';
- $this->_message = '';
- $this->_emailFormat = 'text';
- $this->_transportName = 'Mail';
- $this->_transportClass = null;
- $this->_attachments = array();
- $this->_config = array();
- return $this;
- }
-
-/**
- * Encode the specified string using the current charset
- *
- * @param string $text String to encode
- * @return string Encoded string
- */
- protected function _encode($text) {
- $internalEncoding = function_exists('mb_internal_encoding');
- if ($internalEncoding) {
- $restore = mb_internal_encoding();
- mb_internal_encoding($this->_appCharset);
- }
- $return = mb_encode_mimeheader($text, $this->headerCharset, 'B');
- if ($internalEncoding) {
- mb_internal_encoding($restore);
- }
- return $return;
- }
-
-/**
- * Translates a string for one charset to another if the App.encoding value
- * differs and the mb_convert_encoding function exists
- *
- * @param string $text The text to be converted
- * @param string $charset the target encoding
- * @return string
- */
- protected function _encodeString($text, $charset) {
- if ($this->_appCharset === $charset || !function_exists('mb_convert_encoding')) {
- return $text;
- }
- return mb_convert_encoding($text, $charset, $this->_appCharset);
- }
-
-/**
- * Wrap the message to follow the RFC 2822 - 2.1.1
- *
- * @param string $message Message to wrap
- * @return array Wrapped message
- */
- protected function _wrap($message) {
- $message = str_replace(array("\r\n", "\r"), "\n", $message);
- $lines = explode("\n", $message);
- $formatted = array();
-
- foreach ($lines as $line) {
- if (empty($line)) {
- $formatted[] = '';
- continue;
- }
- if ($line[0] === '.') {
- $line = '.' . $line;
- }
- if (!preg_match('/\<[a-z]/i', $line)) {
- $formatted = array_merge($formatted, explode("\n", wordwrap($line, self::LINE_LENGTH_SHOULD, "\n")));
- continue;
- }
-
- $tagOpen = false;
- $tmpLine = $tag = '';
- $tmpLineLength = 0;
- for ($i = 0, $count = strlen($line); $i < $count; $i++) {
- $char = $line[$i];
- if ($tagOpen) {
- $tag .= $char;
- if ($char === '>') {
- $tagLength = strlen($tag);
- if ($tagLength + $tmpLineLength < self::LINE_LENGTH_SHOULD) {
- $tmpLine .= $tag;
- $tmpLineLength += $tagLength;
- } else {
- if ($tmpLineLength > 0) {
- $formatted[] = trim($tmpLine);
- $tmpLine = '';
- $tmpLineLength = 0;
- }
- if ($tagLength > self::LINE_LENGTH_SHOULD) {
- $formatted[] = $tag;
- } else {
- $tmpLine = $tag;
- $tmpLineLength = $tagLength;
- }
- }
- $tag = '';
- $tagOpen = false;
- }
- continue;
- }
- if ($char === '<') {
- $tagOpen = true;
- $tag = '<';
- continue;
- }
- if ($char === ' ' && $tmpLineLength >= self::LINE_LENGTH_SHOULD) {
- $formatted[] = $tmpLine;
- $tmpLineLength = 0;
- continue;
- }
- $tmpLine .= $char;
- $tmpLineLength++;
- if ($tmpLineLength === self::LINE_LENGTH_SHOULD) {
- $nextChar = $line[$i + 1];
- if ($nextChar === ' ' || $nextChar === '<') {
- $formatted[] = trim($tmpLine);
- $tmpLine = '';
- $tmpLineLength = 0;
- if ($nextChar === ' ') {
- $i++;
- }
- } else {
- $lastSpace = strrpos($tmpLine, ' ');
- if ($lastSpace === false) {
- continue;
- }
- $formatted[] = trim(substr($tmpLine, 0, $lastSpace));
- $tmpLine = substr($tmpLine, $lastSpace + 1);
-
- $tmpLineLength = strlen($tmpLine);
- }
- }
- }
- if (!empty($tmpLine)) {
- $formatted[] = $tmpLine;
- }
- }
- $formatted[] = '';
- return $formatted;
- }
-
-/**
- * Create unique boundary identifier
- *
- * @return void
- */
- protected function _createBoundary() {
- if (!empty($this->_attachments) || $this->_emailFormat === 'both') {
- $this->_boundary = md5(uniqid(time()));
- }
- }
-
-/**
- * Attach non-embedded files by adding file contents inside boundaries.
- *
- * @param string $boundary Boundary to use. If null, will default to $this->_boundary
- * @return array An array of lines to add to the message
- */
- protected function _attachFiles($boundary = null) {
- if ($boundary === null) {
- $boundary = $this->_boundary;
- }
-
- $msg = array();
- foreach ($this->_attachments as $filename => $fileInfo) {
- if (!empty($fileInfo['contentId'])) {
- continue;
- }
- $data = $this->_readFile($fileInfo['file']);
-
- $msg[] = '--' . $boundary;
- $msg[] = 'Content-Type: ' . $fileInfo['mimetype'];
- $msg[] = 'Content-Transfer-Encoding: base64';
- $msg[] = 'Content-Disposition: attachment; filename="' . $filename . '"';
- $msg[] = '';
- $msg[] = $data;
- $msg[] = '';
- }
- return $msg;
- }
-
-/**
- * Read the file contents and return a base64 version of the file contents.
- *
- * @param string $file The file to read.
- * @return string File contents in base64 encoding
- */
- protected function _readFile($file) {
- $handle = fopen($file, 'rb');
- $data = fread($handle, filesize($file));
- $data = chunk_split(base64_encode($data));
- fclose($handle);
- return $data;
- }
-
-/**
- * Attach inline/embedded files to the message.
- *
- * @param string $boundary Boundary to use. If null, will default to $this->_boundary
- * @return array An array of lines to add to the message
- */
- protected function _attachInlineFiles($boundary = null) {
- if ($boundary === null) {
- $boundary = $this->_boundary;
- }
-
- $msg = array();
- foreach ($this->_attachments as $filename => $fileInfo) {
- if (empty($fileInfo['contentId'])) {
- continue;
- }
- $data = $this->_readFile($fileInfo['file']);
-
- $msg[] = '--' . $boundary;
- $msg[] = 'Content-Type: ' . $fileInfo['mimetype'];
- $msg[] = 'Content-Transfer-Encoding: base64';
- $msg[] = 'Content-ID: <' . $fileInfo['contentId'] . '>';
- $msg[] = 'Content-Disposition: inline; filename="' . $filename . '"';
- $msg[] = '';
- $msg[] = $data;
- $msg[] = '';
- }
- return $msg;
- }
-
-/**
- * Render the body of the email.
- *
- * @param string $content Content to render
- * @return array Email body ready to be sent
- */
- protected function _render($content) {
- $content = implode("\n", $content);
- $rendered = $this->_renderTemplates($content);
-
- $msg = array();
-
- $contentIds = array_filter((array)Set::classicExtract($this->_attachments, '{s}.contentId'));
- $hasInlineAttachments = count($contentIds) > 0;
- $hasAttachments = !empty($this->_attachments);
- $hasMultipleTypes = count($rendered) > 1;
-
- $boundary = $relBoundary = $textBoundary = $this->_boundary;
-
- if ($hasInlineAttachments) {
- $msg[] = '--' . $boundary;
- $msg[] = 'Content-Type: multipart/related; boundary="rel-' . $boundary . '"';
- $msg[] = '';
- $relBoundary = $textBoundary = 'rel-' . $boundary;
- }
-
- if ($hasMultipleTypes) {
- $msg[] = '--' . $relBoundary;
- $msg[] = 'Content-Type: multipart/alternative; boundary="alt-' . $boundary . '"';
- $msg[] = '';
- $textBoundary = 'alt-' . $boundary;
- }
-
- if (isset($rendered['text'])) {
- if ($textBoundary !== $boundary || $hasAttachments) {
- $msg[] = '--' . $textBoundary;
- $msg[] = 'Content-Type: text/plain; charset=' . $this->charset;
- $msg[] = 'Content-Transfer-Encoding: ' . $this->_getContentTransferEncoding();
- $msg[] = '';
- }
- $this->_textMessage = $rendered['text'];
- $content = explode("\n", $this->_textMessage);
- $msg = array_merge($msg, $content);
- $msg[] = '';
- }
-
- if (isset($rendered['html'])) {
- if ($textBoundary !== $boundary || $hasAttachments) {
- $msg[] = '--' . $textBoundary;
- $msg[] = 'Content-Type: text/html; charset=' . $this->charset;
- $msg[] = 'Content-Transfer-Encoding: ' . $this->_getContentTransferEncoding();
- $msg[] = '';
- }
- $this->_htmlMessage = $rendered['html'];
- $content = explode("\n", $this->_htmlMessage);
- $msg = array_merge($msg, $content);
- $msg[] = '';
- }
-
- if ($hasMultipleTypes) {
- $msg[] = '--' . $textBoundary . '--';
- $msg[] = '';
- }
-
- if ($hasInlineAttachments) {
- $attachments = $this->_attachInlineFiles($relBoundary);
- $msg = array_merge($msg, $attachments);
- $msg[] = '';
- $msg[] = '--' . $relBoundary . '--';
- $msg[] = '';
- }
-
- if ($hasAttachments) {
- $attachments = $this->_attachFiles($boundary);
- $msg = array_merge($msg, $attachments);
- }
- if ($hasAttachments || $hasMultipleTypes) {
- $msg[] = '';
- $msg[] = '--' . $boundary . '--';
- $msg[] = '';
- }
- return $msg;
- }
-
-/**
- * Gets the text body types that are in this email message
- *
- * @return array Array of types. Valid types are 'text' and 'html'
- */
- protected function _getTypes() {
- $types = array($this->_emailFormat);
- if ($this->_emailFormat == 'both') {
- $types = array('html', 'text');
- }
- return $types;
- }
-
-/**
- * Build and set all the view properties needed to render the templated emails.
- * If there is no template set, the $content will be returned in a hash
- * of the text content types for the email.
- *
- * @param string $content The content passed in from send() in most cases.
- * @return array The rendered content with html and text keys.
- */
- protected function _renderTemplates($content) {
- $types = $this->_getTypes();
- $rendered = array();
- if (empty($this->_template)) {
- foreach ($types as $type) {
- $rendered[$type] = $this->_encodeString($content, $this->charset);
- }
- return $rendered;
- }
- $viewClass = $this->_viewRender;
- if ($viewClass !== 'View') {
- list($plugin, $viewClass) = pluginSplit($viewClass, true);
- $viewClass .= 'View';
- App::uses($viewClass, $plugin . 'View');
- }
-
- $View = new $viewClass(null);
- $View->viewVars = $this->_viewVars;
- $View->helpers = $this->_helpers;
-
- list($templatePlugin, $template) = pluginSplit($this->_template);
- list($layoutPlugin, $layout) = pluginSplit($this->_layout);
- if ($templatePlugin) {
- $View->plugin = $templatePlugin;
- } elseif ($layoutPlugin) {
- $View->plugin = $layoutPlugin;
- }
-
- foreach ($types as $type) {
- $View->set('content', $content);
- $View->hasRendered = false;
- $View->viewPath = $View->layoutPath = 'Emails' . DS . $type;
-
- $render = $View->render($template, $layout);
- $render = str_replace(array("\r\n", "\r"), "\n", $render);
- $rendered[$type] = $this->_encodeString($render, $this->charset);
- }
- return $rendered;
- }
-
-/**
- * Return the Content-Transfer Encoding value based on the set charset
- *
- * @return void
- */
- protected function _getContentTransferEncoding() {
- $charset = strtoupper($this->charset);
- if (in_array($charset, $this->_charset8bit)) {
- return '8bit';
- }
- return '7bit';
- }
-
-}
diff --git a/lib/Cake/Network/Email/DebugTransport.php b/lib/Cake/Network/Email/DebugTransport.php
deleted file mode 100644
index e1f31f1454e..00000000000
--- a/lib/Cake/Network/Email/DebugTransport.php
+++ /dev/null
@@ -1,41 +0,0 @@
-getHeaders(array('from', 'sender', 'replyTo', 'readReceipt', 'returnPath', 'to', 'cc', 'subject'));
- $headers = $this->_headersToString($headers);
- $message = implode("\r\n", (array)$email->message());
- return array('headers' => $headers, 'message' => $message);
- }
-
-}
diff --git a/lib/Cake/Network/Email/MailTransport.php b/lib/Cake/Network/Email/MailTransport.php
deleted file mode 100644
index ae63b7612ff..00000000000
--- a/lib/Cake/Network/Email/MailTransport.php
+++ /dev/null
@@ -1,54 +0,0 @@
-_config['eol'])) {
- $eol = $this->_config['eol'];
- }
- $headers = $email->getHeaders(array('from', 'sender', 'replyTo', 'readReceipt', 'returnPath', 'to', 'cc', 'bcc'));
- $to = $headers['To'];
- unset($headers['To']);
- $headers = $this->_headersToString($headers, $eol);
- $message = implode($eol, $email->message());
- if (ini_get('safe_mode') || !isset($this->_config['additionalParameters'])) {
- if (!@mail($to, $email->subject(), $message, $headers)) {
- throw new SocketException(__d('cake_dev', 'Could not send email.'));
- }
- } elseif (!@mail($to, $email->subject(), $message, $headers, $this->_config['additionalParameters'])) {
- throw new SocketException(__d('cake_dev', 'Could not send email.'));
- }
- return array('headers' => $headers, 'message' => $message);
- }
-
-}
diff --git a/lib/Cake/Network/Email/SmtpTransport.php b/lib/Cake/Network/Email/SmtpTransport.php
deleted file mode 100644
index e89b21557fd..00000000000
--- a/lib/Cake/Network/Email/SmtpTransport.php
+++ /dev/null
@@ -1,231 +0,0 @@
-_cakeEmail = $email;
-
- $this->_connect();
- $this->_auth();
- $this->_sendRcpt();
- $this->_sendData();
- $this->_disconnect();
-
- return $this->_content;
- }
-
-/**
- * Set the configuration
- *
- * @param array $config
- * @return void
- */
- public function config($config = array()) {
- $default = array(
- 'host' => 'localhost',
- 'port' => 25,
- 'timeout' => 30,
- 'username' => null,
- 'password' => null,
- 'client' => null
- );
- $this->_config = $config + $default;
- }
-
-/**
- * Connect to SMTP Server
- *
- * @return void
- * @throws SocketException
- */
- protected function _connect() {
- $this->_generateSocket();
- if (!$this->_socket->connect()) {
- throw new SocketException(__d('cake_dev', 'Unable to connect to SMTP server.'));
- }
- $this->_smtpSend(null, '220');
-
- if (isset($this->_config['client'])) {
- $host = $this->_config['client'];
- } elseif ($httpHost = env('HTTP_HOST')) {
- list($host) = explode(':', $httpHost);
- } else {
- $host = 'localhost';
- }
-
- try {
- $this->_smtpSend("EHLO {$host}", '250');
- } catch (SocketException $e) {
- try {
- $this->_smtpSend("HELO {$host}", '250');
- } catch (SocketException $e2) {
- throw new SocketException(__d('cake_dev', 'SMTP server did not accept the connection.'));
- }
- }
- }
-
-/**
- * Send authentication
- *
- * @return void
- * @throws SocketException
- */
- protected function _auth() {
- if (isset($this->_config['username']) && isset($this->_config['password'])) {
- $authRequired = $this->_smtpSend('AUTH LOGIN', '334|503');
- if ($authRequired == '334') {
- if (!$this->_smtpSend(base64_encode($this->_config['username']), '334')) {
- throw new SocketException(__d('cake_dev', 'SMTP server did not accept the username.'));
- }
- if (!$this->_smtpSend(base64_encode($this->_config['password']), '235')) {
- throw new SocketException(__d('cake_dev', 'SMTP server did not accept the password.'));
- }
- } elseif ($authRequired != '503') {
- throw new SocketException(__d('cake_dev', 'SMTP does not require authentication.'));
- }
- }
- }
-
-/**
- * Send emails
- *
- * @return void
- * @throws SocketException
- */
- protected function _sendRcpt() {
- $from = $this->_cakeEmail->from();
- $this->_smtpSend('MAIL FROM:<' . key($from) . '>');
-
- $to = $this->_cakeEmail->to();
- $cc = $this->_cakeEmail->cc();
- $bcc = $this->_cakeEmail->bcc();
- $emails = array_merge(array_keys($to), array_keys($cc), array_keys($bcc));
- foreach ($emails as $email) {
- $this->_smtpSend('RCPT TO:<' . $email . '>');
- }
- }
-
-/**
- * Send Data
- *
- * @return void
- * @throws SocketException
- */
- protected function _sendData() {
- $this->_smtpSend('DATA', '354');
-
- $headers = $this->_cakeEmail->getHeaders(array('from', 'sender', 'replyTo', 'readReceipt', 'returnPath', 'to', 'cc', 'subject'));
- $headers = $this->_headersToString($headers);
- $message = implode("\r\n", $this->_cakeEmail->message());
- $this->_smtpSend($headers . "\r\n\r\n" . $message . "\r\n\r\n\r\n.");
- $this->_content = array('headers' => $headers, 'message' => $message);
- }
-
-/**
- * Disconnect
- *
- * @return void
- * @throws SocketException
- */
- protected function _disconnect() {
- $this->_smtpSend('QUIT', false);
- $this->_socket->disconnect();
- }
-
-/**
- * Helper method to generate socket
- *
- * @return void
- * @throws SocketException
- */
- protected function _generateSocket() {
- $this->_socket = new CakeSocket($this->_config);
- }
-
-/**
- * Protected method for sending data to SMTP connection
- *
- * @param string $data data to be sent to SMTP server
- * @param mixed $checkCode code to check for in server response, false to skip
- * @return void
- * @throws SocketException
- */
- protected function _smtpSend($data, $checkCode = '250') {
- if (!is_null($data)) {
- $this->_socket->write($data . "\r\n");
- }
- while ($checkCode !== false) {
- $response = '';
- $startTime = time();
- while (substr($response, -2) !== "\r\n" && ((time() - $startTime) < $this->_config['timeout'])) {
- $response .= $this->_socket->read();
- }
- if (substr($response, -2) !== "\r\n") {
- throw new SocketException(__d('cake_dev', 'SMTP timeout.'));
- }
- $responseLines = explode("\r\n", rtrim($response, "\r\n"));
- $response = end($responseLines);
-
- if (preg_match('/^(' . $checkCode . ')(.)/', $response, $code)) {
- if ($code[2] === '-') {
- continue;
- }
- return $code[1];
- }
- throw new SocketException(__d('cake_dev', 'SMTP Error: %s', $response));
- }
- }
-
-}
diff --git a/lib/Cake/Network/Http/BasicAuthentication.php b/lib/Cake/Network/Http/BasicAuthentication.php
deleted file mode 100644
index c39b2eea52f..00000000000
--- a/lib/Cake/Network/Http/BasicAuthentication.php
+++ /dev/null
@@ -1,66 +0,0 @@
-request['header']['Authorization'] = self::_generateHeader($authInfo['user'], $authInfo['pass']);
- }
- }
-
-/**
- * Proxy Authentication
- *
- * @param HttpSocket $http
- * @param array $proxyInfo
- * @return void
- * @see http://www.ietf.org/rfc/rfc2617.txt
- */
- public static function proxyAuthentication(HttpSocket $http, &$proxyInfo) {
- if (isset($proxyInfo['user'], $proxyInfo['pass'])) {
- $http->request['header']['Proxy-Authorization'] = self::_generateHeader($proxyInfo['user'], $proxyInfo['pass']);
- }
- }
-
-/**
- * Generate basic [proxy] authentication header
- *
- * @param string $user
- * @param string $pass
- * @return string
- */
- protected static function _generateHeader($user, $pass) {
- return 'Basic ' . base64_encode($user . ':' . $pass);
- }
-
-}
diff --git a/lib/Cake/Network/Http/DigestAuthentication.php b/lib/Cake/Network/Http/DigestAuthentication.php
deleted file mode 100644
index 5518ce94837..00000000000
--- a/lib/Cake/Network/Http/DigestAuthentication.php
+++ /dev/null
@@ -1,105 +0,0 @@
-request['header']['Authorization'] = self::_generateHeader($http, $authInfo);
- }
- }
-
-/**
- * Retrieve information about the authentication
- *
- * @param HttpSocket $http
- * @param array $authInfo
- * @return boolean
- */
- protected static function _getServerInformation(HttpSocket $http, &$authInfo) {
- $originalRequest = $http->request;
- $http->configAuth(false);
- $http->request($http->request);
- $http->request = $originalRequest;
- $http->configAuth('Digest', $authInfo);
-
- if (empty($http->response['header']['WWW-Authenticate'])) {
- return false;
- }
- preg_match_all('@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@', $http->response['header']['WWW-Authenticate'], $matches, PREG_SET_ORDER);
- foreach ($matches as $match) {
- $authInfo[$match[1]] = $match[2];
- }
- if (!empty($authInfo['qop']) && empty($authInfo['nc'])) {
- $authInfo['nc'] = 1;
- }
- return true;
- }
-
-/**
- * Generate the header Authorization
- *
- * @param HttpSocket $http
- * @param array $authInfo
- * @return string
- */
- protected static function _generateHeader(HttpSocket $http, &$authInfo) {
- $a1 = md5($authInfo['user'] . ':' . $authInfo['realm'] . ':' . $authInfo['pass']);
- $a2 = md5($http->request['method'] . ':' . $http->request['uri']['path']);
-
- if (empty($authInfo['qop'])) {
- $response = md5($a1 . ':' . $authInfo['nonce'] . ':' . $a2);
- } else {
- $authInfo['cnonce'] = uniqid();
- $nc = sprintf('%08x', $authInfo['nc']++);
- $response = md5($a1 . ':' . $authInfo['nonce'] . ':' . $nc . ':' . $authInfo['cnonce'] . ':auth:' . $a2);
- }
-
- $authHeader = 'Digest ';
- $authHeader .= 'username="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $authInfo['user']) . '", ';
- $authHeader .= 'realm="' . $authInfo['realm'] . '", ';
- $authHeader .= 'nonce="' . $authInfo['nonce'] . '", ';
- $authHeader .= 'uri="' . $http->request['uri']['path'] . '", ';
- $authHeader .= 'response="' . $response . '"';
- if (!empty($authInfo['opaque'])) {
- $authHeader .= ', opaque="' . $authInfo['opaque'] . '"';
- }
- if (!empty($authInfo['qop'])) {
- $authHeader .= ', qop="auth", nc=' . $nc . ', cnonce="' . $authInfo['cnonce'] . '"';
- }
- return $authHeader;
- }
-
-}
diff --git a/lib/Cake/Network/Http/HttpResponse.php b/lib/Cake/Network/Http/HttpResponse.php
deleted file mode 100644
index 139e3cfc4fb..00000000000
--- a/lib/Cake/Network/Http/HttpResponse.php
+++ /dev/null
@@ -1,448 +0,0 @@
-parseResponse($message);
- }
- }
-
-/**
- * Body content
- *
- * @return string
- */
- public function body() {
- return (string)$this->body;
- }
-
-/**
- * Get header in case insensitive
- *
- * @param string $name Header name
- * @param array $headers
- * @return mixed String if header exists or null
- */
- public function getHeader($name, $headers = null) {
- if (!is_array($headers)) {
- $headers =& $this->headers;
- }
- if (isset($headers[$name])) {
- return $headers[$name];
- }
- foreach ($headers as $key => $value) {
- if (strcasecmp($key, $name) == 0) {
- return $value;
- }
- }
- return null;
- }
-
-/**
- * If return is 200 (OK)
- *
- * @return boolean
- */
- public function isOk() {
- return $this->code == 200;
- }
-
-/**
- * If return is a valid 3xx (Redirection)
- *
- * @return boolean
- */
- public function isRedirect() {
- return in_array($this->code, array(301, 302, 303, 307)) && !is_null($this->getHeader('Location'));
- }
-
-/**
- * Parses the given message and breaks it down in parts.
- *
- * @param string $message Message to parse
- * @return void
- * @throws SocketException
- */
- public function parseResponse($message) {
- if (!is_string($message)) {
- throw new SocketException(__d('cake_dev', 'Invalid response.'));
- }
-
- if (!preg_match("/^(.+\r\n)(.*)(?<=\r\n)\r\n/Us", $message, $match)) {
- throw new SocketException(__d('cake_dev', 'Invalid HTTP response.'));
- }
-
- list(, $statusLine, $header) = $match;
- $this->raw = $message;
- $this->body = (string)substr($message, strlen($match[0]));
-
- if (preg_match("/(.+) ([0-9]{3}) (.+)\r\n/DU", $statusLine, $match)) {
- $this->httpVersion = $match[1];
- $this->code = $match[2];
- $this->reasonPhrase = $match[3];
- }
-
- $this->headers = $this->_parseHeader($header);
- $transferEncoding = $this->getHeader('Transfer-Encoding');
- $decoded = $this->_decodeBody($this->body, $transferEncoding);
- $this->body = $decoded['body'];
-
- if (!empty($decoded['header'])) {
- $this->headers = $this->_parseHeader($this->_buildHeader($this->headers) . $this->_buildHeader($decoded['header']));
- }
-
- if (!empty($this->headers)) {
- $this->cookies = $this->parseCookies($this->headers);
- }
- }
-
-/**
- * Generic function to decode a $body with a given $encoding. Returns either an array with the keys
- * 'body' and 'header' or false on failure.
- *
- * @param string $body A string containing the body to decode.
- * @param mixed $encoding Can be false in case no encoding is being used, or a string representing the encoding.
- * @return mixed Array of response headers and body or false.
- */
- protected function _decodeBody($body, $encoding = 'chunked') {
- if (!is_string($body)) {
- return false;
- }
- if (empty($encoding)) {
- return array('body' => $body, 'header' => false);
- }
- $decodeMethod = '_decode' . Inflector::camelize(str_replace('-', '_', $encoding)) . 'Body';
-
- if (!is_callable(array(&$this, $decodeMethod))) {
- return array('body' => $body, 'header' => false);
- }
- return $this->{$decodeMethod}($body);
- }
-
-/**
- * Decodes a chunked message $body and returns either an array with the keys 'body' and 'header' or false as
- * a result.
- *
- * @param string $body A string containing the chunked body to decode.
- * @return mixed Array of response headers and body or false.
- * @throws SocketException
- */
- protected function _decodeChunkedBody($body) {
- if (!is_string($body)) {
- return false;
- }
-
- $decodedBody = null;
- $chunkLength = null;
-
- while ($chunkLength !== 0) {
- if (!preg_match('/^([0-9a-f]+) *(?:;(.+)=(.+))?(?:\r\n|\n)/iU', $body, $match)) {
- throw new SocketException(__d('cake_dev', 'HttpSocket::_decodeChunkedBody - Could not parse malformed chunk.'));
- }
-
- $chunkSize = 0;
- $hexLength = 0;
- $chunkExtensionName = '';
- $chunkExtensionValue = '';
- if (isset($match[0])) {
- $chunkSize = $match[0];
- }
- if (isset($match[1])) {
- $hexLength = $match[1];
- }
- if (isset($match[2])) {
- $chunkExtensionName = $match[2];
- }
- if (isset($match[3])) {
- $chunkExtensionValue = $match[3];
- }
-
- $body = substr($body, strlen($chunkSize));
- $chunkLength = hexdec($hexLength);
- $chunk = substr($body, 0, $chunkLength);
- if (!empty($chunkExtensionName)) {
- // @todo See if there are popular chunk extensions we should implement
- }
- $decodedBody .= $chunk;
- if ($chunkLength !== 0) {
- $body = substr($body, $chunkLength + strlen("\r\n"));
- }
- }
-
- $entityHeader = false;
- if (!empty($body)) {
- $entityHeader = $this->_parseHeader($body);
- }
- return array('body' => $decodedBody, 'header' => $entityHeader);
- }
-
-/**
- * Parses an array based header.
- *
- * @param array $header Header as an indexed array (field => value)
- * @return array Parsed header
- */
- protected function _parseHeader($header) {
- if (is_array($header)) {
- return $header;
- } elseif (!is_string($header)) {
- return false;
- }
-
- preg_match_all("/(.+):(.+)(?:(?_unescapeToken($field);
-
- if (!isset($header[$field])) {
- $header[$field] = $value;
- } else {
- $header[$field] = array_merge((array)$header[$field], (array)$value);
- }
- }
- return $header;
- }
-
-/**
- * Parses cookies in response headers.
- *
- * @param array $header Header array containing one ore more 'Set-Cookie' headers.
- * @return mixed Either false on no cookies, or an array of cookies received.
- * @todo Make this 100% RFC 2965 confirm
- */
- public function parseCookies($header) {
- $cookieHeader = $this->getHeader('Set-Cookie', $header);
- if (!$cookieHeader) {
- return false;
- }
-
- $cookies = array();
- foreach ((array)$cookieHeader as $cookie) {
- if (strpos($cookie, '";"') !== false) {
- $cookie = str_replace('";"', "{__cookie_replace__}", $cookie);
- $parts = str_replace("{__cookie_replace__}", '";"', explode(';', $cookie));
- } else {
- $parts = preg_split('/\;[ \t]*/', $cookie);
- }
-
- list($name, $value) = explode('=', array_shift($parts), 2);
- $cookies[$name] = compact('value');
-
- foreach ($parts as $part) {
- if (strpos($part, '=') !== false) {
- list($key, $value) = explode('=', $part);
- } else {
- $key = $part;
- $value = true;
- }
-
- $key = strtolower($key);
- if (!isset($cookies[$name][$key])) {
- $cookies[$name][$key] = $value;
- }
- }
- }
- return $cookies;
- }
-
-/**
- * Unescapes a given $token according to RFC 2616 (HTTP 1.1 specs)
- *
- * @param string $token Token to unescape
- * @param array $chars
- * @return string Unescaped token
- * @todo Test $chars parameter
- */
- protected function _unescapeToken($token, $chars = null) {
- $regex = '/"([' . implode('', $this->_tokenEscapeChars(true, $chars)) . '])"/';
- $token = preg_replace($regex, '\\1', $token);
- return $token;
- }
-
-/**
- * Gets escape chars according to RFC 2616 (HTTP 1.1 specs).
- *
- * @param boolean $hex true to get them as HEX values, false otherwise
- * @param array $chars
- * @return array Escape chars
- * @todo Test $chars parameter
- */
- protected function _tokenEscapeChars($hex = true, $chars = null) {
- if (!empty($chars)) {
- $escape = $chars;
- } else {
- $escape = array('"', "(", ")", "<", ">", "@", ",", ";", ":", "\\", "/", "[", "]", "?", "=", "{", "}", " ");
- for ($i = 0; $i <= 31; $i++) {
- $escape[] = chr($i);
- }
- $escape[] = chr(127);
- }
-
- if ($hex == false) {
- return $escape;
- }
- foreach ($escape as $key => $char) {
- $escape[$key] = '\\x' . str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT);
- }
- return $escape;
- }
-
-/**
- * ArrayAccess - Offset Exists
- *
- * @param mixed $offset
- * @return boolean
- */
- public function offsetExists($offset) {
- return in_array($offset, array('raw', 'status', 'header', 'body', 'cookies'));
- }
-
-/**
- * ArrayAccess - Offset Get
- *
- * @param mixed $offset
- * @return mixed
- */
- public function offsetGet($offset) {
- switch ($offset) {
- case 'raw':
- $firstLineLength = strpos($this->raw, "\r\n") + 2;
- if ($this->raw[$firstLineLength] === "\r") {
- $header = null;
- } else {
- $header = substr($this->raw, $firstLineLength, strpos($this->raw, "\r\n\r\n") - $firstLineLength) . "\r\n";
- }
- return array(
- 'status-line' => $this->httpVersion . ' ' . $this->code . ' ' . $this->reasonPhrase . "\r\n",
- 'header' => $header,
- 'body' => $this->body,
- 'response' => $this->raw
- );
- case 'status':
- return array(
- 'http-version' => $this->httpVersion,
- 'code' => $this->code,
- 'reason-phrase' => $this->reasonPhrase
- );
- case 'header':
- return $this->headers;
- case 'body':
- return $this->body;
- case 'cookies':
- return $this->cookies;
- }
- return null;
- }
-
-/**
- * ArrayAccess - Offset Set
- *
- * @param mixed $offset
- * @param mixed $value
- * @return void
- */
- public function offsetSet($offset, $value) {
- }
-
-/**
- * ArrayAccess - Offset Unset
- *
- * @param mixed $offset
- * @return void
- */
- public function offsetUnset($offset) {
- }
-
-/**
- * Instance as string
- *
- * @return string
- */
- public function __toString() {
- return $this->body();
- }
-
-}
diff --git a/lib/Cake/Network/Http/HttpSocket.php b/lib/Cake/Network/Http/HttpSocket.php
deleted file mode 100644
index 9ff65977f3f..00000000000
--- a/lib/Cake/Network/Http/HttpSocket.php
+++ /dev/null
@@ -1,981 +0,0 @@
- 'GET',
- 'uri' => array(
- 'scheme' => 'http',
- 'host' => null,
- 'port' => 80,
- 'user' => null,
- 'pass' => null,
- 'path' => null,
- 'query' => null,
- 'fragment' => null
- ),
- 'version' => '1.1',
- 'body' => '',
- 'line' => null,
- 'header' => array(
- 'Connection' => 'close',
- 'User-Agent' => 'CakePHP'
- ),
- 'raw' => null,
- 'redirect' => false,
- 'cookies' => array()
- );
-
-/**
- * Contain information about the last response (read only)
- *
- * @var array
- */
- public $response = null;
-
-/**
- * Response classname
- *
- * @var string
- */
- public $responseClass = 'HttpResponse';
-
-/**
- * Configuration settings for the HttpSocket and the requests
- *
- * @var array
- */
- public $config = array(
- 'persistent' => false,
- 'host' => 'localhost',
- 'protocol' => 'tcp',
- 'port' => 80,
- 'timeout' => 30,
- 'request' => array(
- 'uri' => array(
- 'scheme' => array('http', 'https'),
- 'host' => 'localhost',
- 'port' => array(80, 443)
- ),
- 'redirect' => false,
- 'cookies' => array()
- )
- );
-
-/**
- * Authentication settings
- *
- * @var array
- */
- protected $_auth = array();
-
-/**
- * Proxy settings
- *
- * @var array
- */
- protected $_proxy = array();
-
-/**
- * Resource to receive the content of request
- *
- * @var mixed
- */
- protected $_contentResource = null;
-
-/**
- * Build an HTTP Socket using the specified configuration.
- *
- * You can use a url string to set the url and use default configurations for
- * all other options:
- *
- * `$http = new HttpSocket('http://cakephp.org/');`
- *
- * Or use an array to configure multiple options:
- *
- * {{{
- * $http = new HttpSocket(array(
- * 'host' => 'cakephp.org',
- * 'timeout' => 20
- * ));
- * }}}
- *
- * See HttpSocket::$config for options that can be used.
- *
- * @param mixed $config Configuration information, either a string url or an array of options.
- */
- public function __construct($config = array()) {
- if (is_string($config)) {
- $this->_configUri($config);
- } elseif (is_array($config)) {
- if (isset($config['request']['uri']) && is_string($config['request']['uri'])) {
- $this->_configUri($config['request']['uri']);
- unset($config['request']['uri']);
- }
- $this->config = Set::merge($this->config, $config);
- }
- parent::__construct($this->config);
- }
-
-/**
- * Set authentication settings.
- *
- * Accepts two forms of parameters. If all you need is a username + password, as with
- * Basic authentication you can do the following:
- *
- * {{{
- * $http->configAuth('Basic', 'mark', 'secret');
- * }}}
- *
- * If you are using an authentication strategy that requires more inputs, like Digest authentication
- * you can call `configAuth()` with an array of user information.
- *
- * {{{
- * $http->configAuth('Digest', array(
- * 'user' => 'mark',
- * 'pass' => 'secret',
- * 'realm' => 'my-realm',
- * 'nonce' => 1235
- * ));
- * }}}
- *
- * To remove any set authentication strategy, call `configAuth()` with no parameters:
- *
- * `$http->configAuth();`
- *
- * @param string $method Authentication method (ie. Basic, Digest). If empty, disable authentication
- * @param mixed $user Username for authentication. Can be an array with settings to authentication class
- * @param string $pass Password for authentication
- * @return void
- */
- public function configAuth($method, $user = null, $pass = null) {
- if (empty($method)) {
- $this->_auth = array();
- return;
- }
- if (is_array($user)) {
- $this->_auth = array($method => $user);
- return;
- }
- $this->_auth = array($method => compact('user', 'pass'));
- }
-
-/**
- * Set proxy settings
- *
- * @param mixed $host Proxy host. Can be an array with settings to authentication class
- * @param integer $port Port. Default 3128.
- * @param string $method Proxy method (ie, Basic, Digest). If empty, disable proxy authentication
- * @param string $user Username if your proxy need authentication
- * @param string $pass Password to proxy authentication
- * @return void
- */
- public function configProxy($host, $port = 3128, $method = null, $user = null, $pass = null) {
- if (empty($host)) {
- $this->_proxy = array();
- return;
- }
- if (is_array($host)) {
- $this->_proxy = $host + array('host' => null);
- return;
- }
- $this->_proxy = compact('host', 'port', 'method', 'user', 'pass');
- }
-
-/**
- * Set the resource to receive the request content. This resource must support fwrite.
- *
- * @param mixed $resource Resource or false to disable the resource use
- * @return void
- * @throws SocketException
- */
- public function setContentResource($resource) {
- if ($resource === false) {
- $this->_contentResource = null;
- return;
- }
- if (!is_resource($resource)) {
- throw new SocketException(__d('cake_dev', 'Invalid resource.'));
- }
- $this->_contentResource = $resource;
- }
-
-/**
- * Issue the specified request. HttpSocket::get() and HttpSocket::post() wrap this
- * method and provide a more granular interface.
- *
- * @param mixed $request Either an URI string, or an array defining host/uri
- * @return mixed false on error, HttpResponse on success
- * @throws SocketException
- */
- public function request($request = array()) {
- $this->reset(false);
-
- if (is_string($request)) {
- $request = array('uri' => $request);
- } elseif (!is_array($request)) {
- return false;
- }
-
- if (!isset($request['uri'])) {
- $request['uri'] = null;
- }
- $uri = $this->_parseUri($request['uri']);
- if (!isset($uri['host'])) {
- $host = $this->config['host'];
- }
- if (isset($request['host'])) {
- $host = $request['host'];
- unset($request['host']);
- }
- $request['uri'] = $this->url($request['uri']);
- $request['uri'] = $this->_parseUri($request['uri'], true);
- $this->request = Set::merge($this->request, array_diff_key($this->config['request'], array('cookies' => true)), $request);
-
- $this->_configUri($this->request['uri']);
-
- $Host = $this->request['uri']['host'];
- if (!empty($this->config['request']['cookies'][$Host])) {
- if (!isset($this->request['cookies'])) {
- $this->request['cookies'] = array();
- }
- if (!isset($request['cookies'])) {
- $request['cookies'] = array();
- }
- $this->request['cookies'] = array_merge($this->request['cookies'], $this->config['request']['cookies'][$Host], $request['cookies']);
- }
-
- if (isset($host)) {
- $this->config['host'] = $host;
- }
- $this->_setProxy();
- $this->request['proxy'] = $this->_proxy;
-
- $cookies = null;
-
- if (is_array($this->request['header'])) {
- if (!empty($this->request['cookies'])) {
- $cookies = $this->buildCookies($this->request['cookies']);
- }
- $scheme = '';
- $port = 0;
- if (isset($this->request['uri']['scheme'])) {
- $scheme = $this->request['uri']['scheme'];
- }
- if (isset($this->request['uri']['port'])) {
- $port = $this->request['uri']['port'];
- }
- if (
- ($scheme === 'http' && $port != 80) ||
- ($scheme === 'https' && $port != 443) ||
- ($port != 80 && $port != 443)
- ) {
- $Host .= ':' . $port;
- }
- $this->request['header'] = array_merge(compact('Host'), $this->request['header']);
- }
-
- if (isset($this->request['uri']['user'], $this->request['uri']['pass'])) {
- $this->configAuth('Basic', $this->request['uri']['user'], $this->request['uri']['pass']);
- }
- $this->_setAuth();
- $this->request['auth'] = $this->_auth;
-
- if (is_array($this->request['body'])) {
- $this->request['body'] = http_build_query($this->request['body']);
- }
-
- if (!empty($this->request['body']) && !isset($this->request['header']['Content-Type'])) {
- $this->request['header']['Content-Type'] = 'application/x-www-form-urlencoded';
- }
-
- if (!empty($this->request['body']) && !isset($this->request['header']['Content-Length'])) {
- $this->request['header']['Content-Length'] = strlen($this->request['body']);
- }
-
- $connectionType = null;
- if (isset($this->request['header']['Connection'])) {
- $connectionType = $this->request['header']['Connection'];
- }
- $this->request['header'] = $this->_buildHeader($this->request['header']) . $cookies;
-
- if (empty($this->request['line'])) {
- $this->request['line'] = $this->_buildRequestLine($this->request);
- }
-
- if ($this->quirksMode === false && $this->request['line'] === false) {
- return false;
- }
-
- $this->request['raw'] = '';
- if ($this->request['line'] !== false) {
- $this->request['raw'] = $this->request['line'];
- }
-
- if ($this->request['header'] !== false) {
- $this->request['raw'] .= $this->request['header'];
- }
-
- $this->request['raw'] .= "\r\n";
- $this->request['raw'] .= $this->request['body'];
- $this->write($this->request['raw']);
-
- $response = null;
- $inHeader = true;
- while ($data = $this->read()) {
- if ($this->_contentResource) {
- if ($inHeader) {
- $response .= $data;
- $pos = strpos($response, "\r\n\r\n");
- if ($pos !== false) {
- $pos += 4;
- $data = substr($response, $pos);
- fwrite($this->_contentResource, $data);
-
- $response = substr($response, 0, $pos);
- $inHeader = false;
- }
- } else {
- fwrite($this->_contentResource, $data);
- fflush($this->_contentResource);
- }
- } else {
- $response .= $data;
- }
- }
-
- if ($connectionType === 'close') {
- $this->disconnect();
- }
-
- list($plugin, $responseClass) = pluginSplit($this->responseClass, true);
- App::uses($this->responseClass, $plugin . 'Network/Http');
- if (!class_exists($responseClass)) {
- throw new SocketException(__d('cake_dev', 'Class %s not found.', $this->responseClass));
- }
- $responseClass = $this->responseClass;
- $this->response = new $responseClass($response);
- if (!empty($this->response->cookies)) {
- if (!isset($this->config['request']['cookies'][$Host])) {
- $this->config['request']['cookies'][$Host] = array();
- }
- $this->config['request']['cookies'][$Host] = array_merge($this->config['request']['cookies'][$Host], $this->response->cookies);
- }
-
- if ($this->request['redirect'] && $this->response->isRedirect()) {
- $request['uri'] = $this->response->getHeader('Location');
- $request['redirect'] = is_int($this->request['redirect']) ? $this->request['redirect'] - 1 : $this->request['redirect'];
- $this->response = $this->request($request);
- }
-
- return $this->response;
- }
-
-/**
- * Issues a GET request to the specified URI, query, and request.
- *
- * Using a string uri and an array of query string parameters:
- *
- * `$response = $http->get('http://google.com/search', array('q' => 'cakephp', 'client' => 'safari'));`
- *
- * Would do a GET request to `http://google.com/search?q=cakephp&client=safari`
- *
- * You could express the same thing using a uri array and query string parameters:
- *
- * {{{
- * $response = $http->get(
- * array('host' => 'google.com', 'path' => '/search'),
- * array('q' => 'cakephp', 'client' => 'safari')
- * );
- * }}}
- *
- * @param mixed $uri URI to request. Either a string uri, or a uri array, see HttpSocket::_parseUri()
- * @param array $query Querystring parameters to append to URI
- * @param array $request An indexed array with indexes such as 'method' or uri
- * @return mixed Result of request, either false on failure or the response to the request.
- */
- public function get($uri = null, $query = array(), $request = array()) {
- if (!empty($query)) {
- $uri = $this->_parseUri($uri, $this->config['request']['uri']);
- if (isset($uri['query'])) {
- $uri['query'] = array_merge($uri['query'], $query);
- } else {
- $uri['query'] = $query;
- }
- $uri = $this->_buildUri($uri);
- }
-
- $request = Set::merge(array('method' => 'GET', 'uri' => $uri), $request);
- return $this->request($request);
- }
-
-/**
- * Issues a POST request to the specified URI, query, and request.
- *
- * `post()` can be used to post simple data arrays to a url:
- *
- * {{{
- * $response = $http->post('http://example.com', array(
- * 'username' => 'batman',
- * 'password' => 'bruce_w4yne'
- * ));
- * }}}
- *
- * @param mixed $uri URI to request. See HttpSocket::_parseUri()
- * @param array $data Array of POST data keys and values.
- * @param array $request An indexed array with indexes such as 'method' or uri
- * @return mixed Result of request, either false on failure or the response to the request.
- */
- public function post($uri = null, $data = array(), $request = array()) {
- $request = Set::merge(array('method' => 'POST', 'uri' => $uri, 'body' => $data), $request);
- return $this->request($request);
- }
-
-/**
- * Issues a PUT request to the specified URI, query, and request.
- *
- * @param mixed $uri URI to request, See HttpSocket::_parseUri()
- * @param array $data Array of PUT data keys and values.
- * @param array $request An indexed array with indexes such as 'method' or uri
- * @return mixed Result of request
- */
- public function put($uri = null, $data = array(), $request = array()) {
- $request = Set::merge(array('method' => 'PUT', 'uri' => $uri, 'body' => $data), $request);
- return $this->request($request);
- }
-
-/**
- * Issues a DELETE request to the specified URI, query, and request.
- *
- * @param mixed $uri URI to request (see {@link _parseUri()})
- * @param array $data Query to append to URI
- * @param array $request An indexed array with indexes such as 'method' or uri
- * @return mixed Result of request
- */
- public function delete($uri = null, $data = array(), $request = array()) {
- $request = Set::merge(array('method' => 'DELETE', 'uri' => $uri, 'body' => $data), $request);
- return $this->request($request);
- }
-
-/**
- * Normalizes urls into a $uriTemplate. If no template is provided
- * a default one will be used. Will generate the url using the
- * current config information.
- *
- * ### Usage:
- *
- * After configuring part of the request parameters, you can use url() to generate
- * urls.
- *
- * {{{
- * $http = new HttpSocket('http://www.cakephp.org');
- * $url = $http->url('/search?q=bar');
- * }}}
- *
- * Would return `http://www.cakephp.org/search?q=bar`
- *
- * url() can also be used with custom templates:
- *
- * `$url = $http->url('http://www.cakephp/search?q=socket', '/%path?%query');`
- *
- * Would return `/search?q=socket`.
- *
- * @param mixed $url Either a string or array of url options to create a url with.
- * @param string $uriTemplate A template string to use for url formatting.
- * @return mixed Either false on failure or a string containing the composed url.
- */
- public function url($url = null, $uriTemplate = null) {
- if (is_null($url)) {
- $url = '/';
- }
- if (is_string($url)) {
- $scheme = $this->config['request']['uri']['scheme'];
- if (is_array($scheme)) {
- $scheme = $scheme[0];
- }
- $port = $this->config['request']['uri']['port'];
- if (is_array($port)) {
- $port = $port[0];
- }
- if ($url{0} == '/') {
- $url = $this->config['request']['uri']['host'] . ':' . $port . $url;
- }
- if (!preg_match('/^.+:\/\/|\*|^\//', $url)) {
- $url = $scheme . '://' . $url;
- }
- } elseif (!is_array($url) && !empty($url)) {
- return false;
- }
-
- $base = array_merge($this->config['request']['uri'], array('scheme' => array('http', 'https'), 'port' => array(80, 443)));
- $url = $this->_parseUri($url, $base);
-
- if (empty($url)) {
- $url = $this->config['request']['uri'];
- }
-
- if (!empty($uriTemplate)) {
- return $this->_buildUri($url, $uriTemplate);
- }
- return $this->_buildUri($url);
- }
-
-/**
- * Set authentication in request
- *
- * @return void
- * @throws SocketException
- */
- protected function _setAuth() {
- if (empty($this->_auth)) {
- return;
- }
- $method = key($this->_auth);
- list($plugin, $authClass) = pluginSplit($method, true);
- $authClass = Inflector::camelize($authClass) . 'Authentication';
- App::uses($authClass, $plugin . 'Network/Http');
-
- if (!class_exists($authClass)) {
- throw new SocketException(__d('cake_dev', 'Unknown authentication method.'));
- }
- if (!method_exists($authClass, 'authentication')) {
- throw new SocketException(sprintf(__d('cake_dev', 'The %s do not support authentication.'), $authClass));
- }
- call_user_func_array("$authClass::authentication", array($this, &$this->_auth[$method]));
- }
-
-/**
- * Set the proxy configuration and authentication
- *
- * @return void
- * @throws SocketException
- */
- protected function _setProxy() {
- if (empty($this->_proxy) || !isset($this->_proxy['host'], $this->_proxy['port'])) {
- return;
- }
- $this->config['host'] = $this->_proxy['host'];
- $this->config['port'] = $this->_proxy['port'];
-
- if (empty($this->_proxy['method']) || !isset($this->_proxy['user'], $this->_proxy['pass'])) {
- return;
- }
- list($plugin, $authClass) = pluginSplit($this->_proxy['method'], true);
- $authClass = Inflector::camelize($authClass) . 'Authentication';
- App::uses($authClass, $plugin . 'Network/Http');
-
- if (!class_exists($authClass)) {
- throw new SocketException(__d('cake_dev', 'Unknown authentication method for proxy.'));
- }
- if (!method_exists($authClass, 'proxyAuthentication')) {
- throw new SocketException(sprintf(__d('cake_dev', 'The %s do not support proxy authentication.'), $authClass));
- }
- call_user_func_array("$authClass::proxyAuthentication", array($this, &$this->_proxy));
- }
-
-/**
- * Parses and sets the specified URI into current request configuration.
- *
- * @param mixed $uri URI, See HttpSocket::_parseUri()
- * @return boolean If uri has merged in config
- */
- protected function _configUri($uri = null) {
- if (empty($uri)) {
- return false;
- }
-
- if (is_array($uri)) {
- $uri = $this->_parseUri($uri);
- } else {
- $uri = $this->_parseUri($uri, true);
- }
-
- if (!isset($uri['host'])) {
- return false;
- }
- $config = array(
- 'request' => array(
- 'uri' => array_intersect_key($uri, $this->config['request']['uri'])
- )
- );
- $this->config = Set::merge($this->config, $config);
- $this->config = Set::merge($this->config, array_intersect_key($this->config['request']['uri'], $this->config));
- return true;
- }
-
-/**
- * Takes a $uri array and turns it into a fully qualified URL string
- *
- * @param mixed $uri Either A $uri array, or a request string. Will use $this->config if left empty.
- * @param string $uriTemplate The Uri template/format to use.
- * @return mixed A fully qualified URL formatted according to $uriTemplate, or false on failure
- */
- protected function _buildUri($uri = array(), $uriTemplate = '%scheme://%user:%pass@%host:%port/%path?%query#%fragment') {
- if (is_string($uri)) {
- $uri = array('host' => $uri);
- }
- $uri = $this->_parseUri($uri, true);
-
- if (!is_array($uri) || empty($uri)) {
- return false;
- }
-
- $uri['path'] = preg_replace('/^\//', null, $uri['path']);
- $uri['query'] = http_build_query($uri['query']);
- $uri['query'] = rtrim($uri['query'], '=');
- $stripIfEmpty = array(
- 'query' => '?%query',
- 'fragment' => '#%fragment',
- 'user' => '%user:%pass@',
- 'host' => '%host:%port/'
- );
-
- foreach ($stripIfEmpty as $key => $strip) {
- if (empty($uri[$key])) {
- $uriTemplate = str_replace($strip, null, $uriTemplate);
- }
- }
-
- $defaultPorts = array('http' => 80, 'https' => 443);
- if (array_key_exists($uri['scheme'], $defaultPorts) && $defaultPorts[$uri['scheme']] == $uri['port']) {
- $uriTemplate = str_replace(':%port', null, $uriTemplate);
- }
- foreach ($uri as $property => $value) {
- $uriTemplate = str_replace('%' . $property, $value, $uriTemplate);
- }
-
- if ($uriTemplate === '/*') {
- $uriTemplate = '*';
- }
- return $uriTemplate;
- }
-
-/**
- * Parses the given URI and breaks it down into pieces as an indexed array with elements
- * such as 'scheme', 'port', 'query'.
- *
- * @param string $uri URI to parse
- * @param mixed $base If true use default URI config, otherwise indexed array to set 'scheme', 'host', 'port', etc.
- * @return array Parsed URI
- */
- protected function _parseUri($uri = null, $base = array()) {
- $uriBase = array(
- 'scheme' => array('http', 'https'),
- 'host' => null,
- 'port' => array(80, 443),
- 'user' => null,
- 'pass' => null,
- 'path' => '/',
- 'query' => null,
- 'fragment' => null
- );
-
- if (is_string($uri)) {
- $uri = parse_url($uri);
- }
- if (!is_array($uri) || empty($uri)) {
- return false;
- }
- if ($base === true) {
- $base = $uriBase;
- }
-
- if (isset($base['port'], $base['scheme']) && is_array($base['port']) && is_array($base['scheme'])) {
- if (isset($uri['scheme']) && !isset($uri['port'])) {
- $base['port'] = $base['port'][array_search($uri['scheme'], $base['scheme'])];
- } elseif (isset($uri['port']) && !isset($uri['scheme'])) {
- $base['scheme'] = $base['scheme'][array_search($uri['port'], $base['port'])];
- }
- }
-
- if (is_array($base) && !empty($base)) {
- $uri = array_merge($base, $uri);
- }
-
- if (isset($uri['scheme']) && is_array($uri['scheme'])) {
- $uri['scheme'] = array_shift($uri['scheme']);
- }
- if (isset($uri['port']) && is_array($uri['port'])) {
- $uri['port'] = array_shift($uri['port']);
- }
-
- if (array_key_exists('query', $uri)) {
- $uri['query'] = $this->_parseQuery($uri['query']);
- }
-
- if (!array_intersect_key($uriBase, $uri)) {
- return false;
- }
- return $uri;
- }
-
-/**
- * This function can be thought of as a reverse to PHP5's http_build_query(). It takes a given query string and turns it into an array and
- * supports nesting by using the php bracket syntax. So this means you can parse queries like:
- *
- * - ?key[subKey]=value
- * - ?key[]=value1&key[]=value2
- *
- * A leading '?' mark in $query is optional and does not effect the outcome of this function.
- * For the complete capabilities of this implementation take a look at HttpSocketTest::testparseQuery()
- *
- * @param mixed $query A query string to parse into an array or an array to return directly "as is"
- * @return array The $query parsed into a possibly multi-level array. If an empty $query is
- * given, an empty array is returned.
- */
- protected function _parseQuery($query) {
- if (is_array($query)) {
- return $query;
- }
-
- if (is_array($query)) {
- return $query;
- }
- $parsedQuery = array();
-
- if (is_string($query) && !empty($query)) {
- $query = preg_replace('/^\?/', '', $query);
- $items = explode('&', $query);
-
- foreach ($items as $item) {
- if (strpos($item, '=') !== false) {
- list($key, $value) = explode('=', $item, 2);
- } else {
- $key = $item;
- $value = null;
- }
-
- $key = urldecode($key);
- $value = urldecode($value);
-
- if (preg_match_all('/\[([^\[\]]*)\]/iUs', $key, $matches)) {
- $subKeys = $matches[1];
- $rootKey = substr($key, 0, strpos($key, '['));
- if (!empty($rootKey)) {
- array_unshift($subKeys, $rootKey);
- }
- $queryNode =& $parsedQuery;
-
- foreach ($subKeys as $subKey) {
- if (!is_array($queryNode)) {
- $queryNode = array();
- }
-
- if ($subKey === '') {
- $queryNode[] = array();
- end($queryNode);
- $subKey = key($queryNode);
- }
- $queryNode =& $queryNode[$subKey];
- }
- $queryNode = $value;
- continue;
- }
- if (!isset($parsedQuery[$key])) {
- $parsedQuery[$key] = $value;
- } else {
- $parsedQuery[$key] = (array)$parsedQuery[$key];
- $parsedQuery[$key][] = $value;
- }
- }
- }
- return $parsedQuery;
- }
-
-/**
- * Builds a request line according to HTTP/1.1 specs. Activate quirks mode to work outside specs.
- *
- * @param array $request Needs to contain a 'uri' key. Should also contain a 'method' key, otherwise defaults to GET.
- * @param string $versionToken The version token to use, defaults to HTTP/1.1
- * @return string Request line
- * @throws SocketException
- */
- protected function _buildRequestLine($request = array(), $versionToken = 'HTTP/1.1') {
- $asteriskMethods = array('OPTIONS');
-
- if (is_string($request)) {
- $isValid = preg_match("/(.+) (.+) (.+)\r\n/U", $request, $match);
- if (!$this->quirksMode && (!$isValid || ($match[2] == '*' && !in_array($match[3], $asteriskMethods)))) {
- throw new SocketException(__d('cake_dev', 'HttpSocket::_buildRequestLine - Passed an invalid request line string. Activate quirks mode to do this.'));
- }
- return $request;
- } elseif (!is_array($request)) {
- return false;
- } elseif (!array_key_exists('uri', $request)) {
- return false;
- }
-
- $request['uri'] = $this->_parseUri($request['uri']);
- $request = array_merge(array('method' => 'GET'), $request);
- if (!empty($this->_proxy['host'])) {
- $request['uri'] = $this->_buildUri($request['uri'], '%scheme://%host:%port/%path?%query');
- } else {
- $request['uri'] = $this->_buildUri($request['uri'], '/%path?%query');
- }
-
- if (!$this->quirksMode && $request['uri'] === '*' && !in_array($request['method'], $asteriskMethods)) {
- throw new SocketException(__d('cake_dev', 'HttpSocket::_buildRequestLine - The "*" asterisk character is only allowed for the following methods: %s. Activate quirks mode to work outside of HTTP/1.1 specs.', implode(',', $asteriskMethods)));
- }
- return $request['method'] . ' ' . $request['uri'] . ' ' . $versionToken . "\r\n";
- }
-
-/**
- * Builds the header.
- *
- * @param array $header Header to build
- * @param string $mode
- * @return string Header built from array
- */
- protected function _buildHeader($header, $mode = 'standard') {
- if (is_string($header)) {
- return $header;
- } elseif (!is_array($header)) {
- return false;
- }
-
- $fieldsInHeader = array();
- foreach ($header as $key => $value) {
- $lowKey = strtolower($key);
- if (array_key_exists($lowKey, $fieldsInHeader)) {
- $header[$fieldsInHeader[$lowKey]] = $value;
- unset($header[$key]);
- } else {
- $fieldsInHeader[$lowKey] = $key;
- }
- }
-
- $returnHeader = '';
- foreach ($header as $field => $contents) {
- if (is_array($contents) && $mode == 'standard') {
- $contents = implode(',', $contents);
- }
- foreach ((array)$contents as $content) {
- $contents = preg_replace("/\r\n(?![\t ])/", "\r\n ", $content);
- $field = $this->_escapeToken($field);
-
- $returnHeader .= $field . ': ' . $contents . "\r\n";
- }
- }
- return $returnHeader;
- }
-
-/**
- * Builds cookie headers for a request.
- *
- * @param array $cookies Array of cookies to send with the request.
- * @return string Cookie header string to be sent with the request.
- * @todo Refactor token escape mechanism to be configurable
- */
- public function buildCookies($cookies) {
- $header = array();
- foreach ($cookies as $name => $cookie) {
- $header[] = $name . '=' . $this->_escapeToken($cookie['value'], array(';'));
- }
- return $this->_buildHeader(array('Cookie' => implode('; ', $header)), 'pragmatic');
- }
-
-/**
- * Escapes a given $token according to RFC 2616 (HTTP 1.1 specs)
- *
- * @param string $token Token to escape
- * @param array $chars
- * @return string Escaped token
- * @todo Test $chars parameter
- */
- protected function _escapeToken($token, $chars = null) {
- $regex = '/([' . implode('', $this->_tokenEscapeChars(true, $chars)) . '])/';
- $token = preg_replace($regex, '"\\1"', $token);
- return $token;
- }
-
-/**
- * Gets escape chars according to RFC 2616 (HTTP 1.1 specs).
- *
- * @param boolean $hex true to get them as HEX values, false otherwise
- * @param array $chars
- * @return array Escape chars
- * @todo Test $chars parameter
- */
- protected function _tokenEscapeChars($hex = true, $chars = null) {
- if (!empty($chars)) {
- $escape = $chars;
- } else {
- $escape = array('"', "(", ")", "<", ">", "@", ",", ";", ":", "\\", "/", "[", "]", "?", "=", "{", "}", " ");
- for ($i = 0; $i <= 31; $i++) {
- $escape[] = chr($i);
- }
- $escape[] = chr(127);
- }
-
- if ($hex == false) {
- return $escape;
- }
- foreach ($escape as $key => $char) {
- $escape[$key] = '\\x' . str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT);
- }
- return $escape;
- }
-
-/**
- * Resets the state of this HttpSocket instance to it's initial state (before Object::__construct got executed) or does
- * the same thing partially for the request and the response property only.
- *
- * @param boolean $full If set to false only HttpSocket::response and HttpSocket::request are reseted
- * @return boolean True on success
- */
- public function reset($full = true) {
- static $initalState = array();
- if (empty($initalState)) {
- $initalState = get_class_vars(__CLASS__);
- }
- if (!$full) {
- $this->request = $initalState['request'];
- $this->response = $initalState['response'];
- return true;
- }
- parent::reset($initalState);
- return true;
- }
-
-}
diff --git a/lib/Cake/Routing/Dispatcher.php b/lib/Cake/Routing/Dispatcher.php
deleted file mode 100644
index cab5675ac1e..00000000000
--- a/lib/Cake/Routing/Dispatcher.php
+++ /dev/null
@@ -1,328 +0,0 @@
-asset($request->url, $response) || $this->cached($request->here())) {
- return;
- }
-
- Router::setRequestInfo($request);
- $request = $this->parseParams($request, $additionalParams);
- $controller = $this->_getController($request, $response);
-
- if (!($controller instanceof Controller)) {
- throw new MissingControllerException(array(
- 'class' => Inflector::camelize($request->params['controller']) . 'Controller',
- 'plugin' => empty($request->params['plugin']) ? null : Inflector::camelize($request->params['plugin'])
- ));
- }
-
- return $this->_invoke($controller, $request, $response);
- }
-
-/**
- * Initializes the components and models a controller will be using.
- * Triggers the controller action, and invokes the rendering if Controller::$autoRender is true and echo's the output.
- * Otherwise the return value of the controller action are returned.
- *
- * @param Controller $controller Controller to invoke
- * @param CakeRequest $request The request object to invoke the controller for.
- * @param CakeResponse $response The response object to receive the output
- * @return void
- */
- protected function _invoke(Controller $controller, CakeRequest $request, CakeResponse $response) {
- $controller->constructClasses();
- $controller->startupProcess();
-
- $render = true;
- $result = $controller->invokeAction($request);
- if ($result instanceof CakeResponse) {
- $render = false;
- $response = $result;
- }
-
- if ($render && $controller->autoRender) {
- $response = $controller->render();
- } elseif ($response->body() === null) {
- $response->body($result);
- }
- $controller->shutdownProcess();
-
- if (isset($request->params['return'])) {
- return $response->body();
- }
- $response->send();
- }
-
-/**
- * Applies Routing and additionalParameters to the request to be dispatched.
- * If Routes have not been loaded they will be loaded, and app/Config/routes.php will be run.
- *
- * @param CakeRequest $request CakeRequest object to mine for parameter information.
- * @param array $additionalParams An array of additional parameters to set to the request.
- * Useful when Object::requestAction() is involved
- * @return CakeRequest The request object with routing params set.
- */
- public function parseParams(CakeRequest $request, $additionalParams = array()) {
- if (count(Router::$routes) == 0) {
- $namedExpressions = Router::getNamedExpressions();
- extract($namedExpressions);
- $this->_loadRoutes();
- }
-
- $params = Router::parse($request->url);
- $request->addParams($params);
-
- if (!empty($additionalParams)) {
- $request->addParams($additionalParams);
- }
- return $request;
- }
-
-/**
- * Get controller to use, either plugin controller or application controller
- *
- * @param CakeRequest $request Request object
- * @param CakeResponse $response Response for the controller.
- * @return mixed name of controller if not loaded, or object if loaded
- */
- protected function _getController($request, $response) {
- $ctrlClass = $this->_loadController($request);
- if (!$ctrlClass) {
- return false;
- }
- $reflection = new ReflectionClass($ctrlClass);
- if ($reflection->isAbstract() || $reflection->isInterface()) {
- return false;
- }
- return $reflection->newInstance($request, $response);
- }
-
-/**
- * Load controller and return controller classname
- *
- * @param CakeRequest $request
- * @return string|bool Name of controller class name
- */
- protected function _loadController($request) {
- $pluginName = $pluginPath = $controller = null;
- if (!empty($request->params['plugin'])) {
- $pluginName = $controller = Inflector::camelize($request->params['plugin']);
- $pluginPath = $pluginName . '.';
- }
- if (!empty($request->params['controller'])) {
- $controller = Inflector::camelize($request->params['controller']);
- }
- if ($pluginPath . $controller) {
- $class = $controller . 'Controller';
- App::uses('AppController', 'Controller');
- App::uses($pluginName . 'AppController', $pluginPath . 'Controller');
- App::uses($class, $pluginPath . 'Controller');
- if (class_exists($class)) {
- return $class;
- }
- }
- return false;
- }
-
-/**
- * Loads route configuration
- *
- * @return void
- */
- protected function _loadRoutes() {
- include APP . 'Config' . DS . 'routes.php';
- }
-
-/**
- * Outputs cached dispatch view cache
- *
- * @param string $path Requested URL path with any query string parameters
- * @return string|boolean False if is not cached or output
- */
- public function cached($path) {
- if (Configure::read('Cache.check') === true) {
- if ($path == '/') {
- $path = 'home';
- }
- $path = strtolower(Inflector::slug($path));
-
- $filename = CACHE . 'views' . DS . $path . '.php';
-
- if (!file_exists($filename)) {
- $filename = CACHE . 'views' . DS . $path . '_index.php';
- }
- if (file_exists($filename)) {
- $controller = null;
- $view = new View($controller);
- return $view->renderCache($filename, microtime(true));
- }
- }
- return false;
- }
-
-/**
- * Checks if a requested asset exists and sends it to the browser
- *
- * @param string $url Requested URL
- * @param CakeResponse $response The response object to put the file contents in.
- * @return boolean True on success if the asset file was found and sent
- */
- public function asset($url, CakeResponse $response) {
- if (strpos($url, '..') !== false || strpos($url, '.') === false) {
- return false;
- }
- $filters = Configure::read('Asset.filter');
- $isCss = (
- strpos($url, 'ccss/') === 0 ||
- preg_match('#^(theme/([^/]+)/ccss/)|(([^/]+)(?statusCode(404);
- $response->send();
- return true;
- } elseif ($isCss) {
- include WWW_ROOT . DS . $filters['css'];
- return true;
- } elseif ($isJs) {
- include WWW_ROOT . DS . $filters['js'];
- return true;
- }
- $pathSegments = explode('.', $url);
- $ext = array_pop($pathSegments);
- $parts = explode('/', $url);
- $assetFile = null;
-
- if ($parts[0] === 'theme') {
- $themeName = $parts[1];
- unset($parts[0], $parts[1]);
- $fileFragment = urldecode(implode(DS, $parts));
- $path = App::themePath($themeName) . 'webroot' . DS;
- if (file_exists($path . $fileFragment)) {
- $assetFile = $path . $fileFragment;
- }
- } else {
- $plugin = Inflector::camelize($parts[0]);
- if (CakePlugin::loaded($plugin)) {
- unset($parts[0]);
- $fileFragment = urldecode(implode(DS, $parts));
- $pluginWebroot = CakePlugin::path($plugin) . 'webroot' . DS;
- if (file_exists($pluginWebroot . $fileFragment)) {
- $assetFile = $pluginWebroot . $fileFragment;
- }
- }
- }
-
- if ($assetFile !== null) {
- $this->_deliverAsset($response, $assetFile, $ext);
- return true;
- }
- return false;
- }
-
-/**
- * Sends an asset file to the client
- *
- * @param CakeResponse $response The response object to use.
- * @param string $assetFile Path to the asset file in the file system
- * @param string $ext The extension of the file to determine its mime type
- * @return void
- */
- protected function _deliverAsset(CakeResponse $response, $assetFile, $ext) {
- ob_start();
- $compressionEnabled = Configure::read('Asset.compress') && $response->compress();
- if ($response->type($ext) == $ext) {
- $contentType = 'application/octet-stream';
- $agent = env('HTTP_USER_AGENT');
- if (preg_match('%Opera(/| )([0-9].[0-9]{1,2})%', $agent) || preg_match('/MSIE ([0-9].[0-9]{1,2})/', $agent)) {
- $contentType = 'application/octetstream';
- }
- $response->type($contentType);
- }
- if (!$compressionEnabled) {
- $response->header('Content-Length', filesize($assetFile));
- }
- $response->cache(filemtime($assetFile));
- $response->send();
- ob_clean();
- if ($ext === 'css' || $ext === 'js') {
- include $assetFile;
- } else {
- readfile($assetFile);
- }
-
- if ($compressionEnabled) {
- ob_end_flush();
- }
- }
-
-}
diff --git a/lib/Cake/Routing/Route/CakeRoute.php b/lib/Cake/Routing/Route/CakeRoute.php
deleted file mode 100644
index 2c2343b71a3..00000000000
--- a/lib/Cake/Routing/Route/CakeRoute.php
+++ /dev/null
@@ -1,529 +0,0 @@
- 'content_type',
- 'method' => 'request_method',
- 'server' => 'server_name'
- );
-
-/**
- * Constructor for a Route
- *
- * @param string $template Template string with parameter placeholders
- * @param array $defaults Array of defaults for the route.
- * @param array $options Array of additional options for the Route
- */
- public function __construct($template, $defaults = array(), $options = array()) {
- $this->template = $template;
- $this->defaults = (array)$defaults;
- $this->options = (array)$options;
- }
-
-/**
- * Check if a Route has been compiled into a regular expression.
- *
- * @return boolean
- */
- public function compiled() {
- return !empty($this->_compiledRoute);
- }
-
-/**
- * Compiles the route's regular expression. Modifies defaults property so all necessary keys are set
- * and populates $this->names with the named routing elements.
- *
- * @return array Returns a string regular expression of the compiled route.
- */
- public function compile() {
- if ($this->compiled()) {
- return $this->_compiledRoute;
- }
- $this->_writeRoute();
- return $this->_compiledRoute;
- }
-
-/**
- * Builds a route regular expression. Uses the template, defaults and options
- * properties to compile a regular expression that can be used to parse request strings.
- *
- * @return void
- */
- protected function _writeRoute() {
- if (empty($this->template) || ($this->template === '/')) {
- $this->_compiledRoute = '#^/*$#';
- $this->keys = array();
- return;
- }
- $route = $this->template;
- $names = $routeParams = array();
- $parsed = preg_quote($this->template, '#');
-
- preg_match_all('#:([A-Za-z0-9_-]+[A-Z0-9a-z])#', $route, $namedElements);
- foreach ($namedElements[1] as $i => $name) {
- $search = '\\' . $namedElements[0][$i];
- if (isset($this->options[$name])) {
- $option = null;
- if ($name !== 'plugin' && array_key_exists($name, $this->defaults)) {
- $option = '?';
- }
- $slashParam = '/\\' . $namedElements[0][$i];
- if (strpos($parsed, $slashParam) !== false) {
- $routeParams[$slashParam] = '(?:/(?P<' . $name . '>' . $this->options[$name] . ')' . $option . ')' . $option;
- } else {
- $routeParams[$search] = '(?:(?P<' . $name . '>' . $this->options[$name] . ')' . $option . ')' . $option;
- }
- } else {
- $routeParams[$search] = '(?:(?P<' . $name . '>[^/]+))';
- }
- $names[] = $name;
- }
- if (preg_match('#\/\*\*$#', $route)) {
- $parsed = preg_replace('#/\\\\\*\\\\\*$#', '(?:/(?P<_trailing_>.*))?', $parsed);
- $this->_greedy = true;
- } elseif (preg_match('#\/\*$#', $route)) {
- $parsed = preg_replace('#/\\\\\*$#', '(?:/(?P<_args_>.*))?', $parsed);
- $this->_greedy = true;
- }
- krsort($routeParams);
- $parsed = str_replace(array_keys($routeParams), array_values($routeParams), $parsed);
- $this->_compiledRoute = '#^' . $parsed . '[/]*$#';
- $this->keys = $names;
-
- //remove defaults that are also keys. They can cause match failures
- foreach ($this->keys as $key) {
- unset($this->defaults[$key]);
- }
- }
-
-/**
- * Checks to see if the given URL can be parsed by this route.
- * If the route can be parsed an array of parameters will be returned; if not
- * false will be returned. String urls are parsed if they match a routes regular expression.
- *
- * @param string $url The url to attempt to parse.
- * @return mixed Boolean false on failure, otherwise an array or parameters
- */
- public function parse($url) {
- if (!$this->compiled()) {
- $this->compile();
- }
- if (!preg_match($this->_compiledRoute, $url, $route)) {
- return false;
- }
- foreach ($this->defaults as $key => $val) {
- $key = (string)$key;
- if ($key[0] === '[' && preg_match('/^\[(\w+)\]$/', $key, $header)) {
- if (isset($this->_headerMap[$header[1]])) {
- $header = $this->_headerMap[$header[1]];
- } else {
- $header = 'http_' . $header[1];
- }
- $header = strtoupper($header);
-
- $val = (array)$val;
- $h = false;
-
- foreach ($val as $v) {
- if (env($header) === $v) {
- $h = true;
- }
- }
- if (!$h) {
- return false;
- }
- }
- }
- array_shift($route);
- $count = count($this->keys);
- for ($i = 0; $i <= $count; $i++) {
- unset($route[$i]);
- }
- $route['pass'] = $route['named'] = array();
-
- // Assign defaults, set passed args to pass
- foreach ($this->defaults as $key => $value) {
- if (isset($route[$key])) {
- continue;
- }
- if (is_integer($key)) {
- $route['pass'][] = $value;
- continue;
- }
- $route[$key] = $value;
- }
-
- foreach ($this->keys as $key) {
- if (isset($route[$key])) {
- $route[$key] = rawurldecode($route[$key]);
- }
- }
-
- if (isset($route['_args_'])) {
- list($pass, $named) = $this->_parseArgs($route['_args_'], $route);
- $route['pass'] = array_merge($route['pass'], $pass);
- $route['named'] = $named;
- unset($route['_args_']);
- }
-
- if (isset($route['_trailing_'])) {
- $route['pass'][] = rawurldecode($route['_trailing_']);
- unset($route['_trailing_']);
- }
-
- // restructure 'pass' key route params
- if (isset($this->options['pass'])) {
- $j = count($this->options['pass']);
- while ($j--) {
- if (isset($route[$this->options['pass'][$j]])) {
- array_unshift($route['pass'], $route[$this->options['pass'][$j]]);
- }
- }
- }
- return $route;
- }
-
-/**
- * Parse passed and Named parameters into a list of passed args, and a hash of named parameters.
- * The local and global configuration for named parameters will be used.
- *
- * @param string $args A string with the passed & named params. eg. /1/page:2
- * @param string $context The current route context, which should contain controller/action keys.
- * @return array Array of ($pass, $named)
- */
- protected function _parseArgs($args, $context) {
- $pass = $named = array();
- $args = explode('/', $args);
-
- $namedConfig = Router::namedConfig();
- $greedy = $namedConfig['greedyNamed'];
- $rules = $namedConfig['rules'];
- if (!empty($this->options['named'])) {
- $greedy = isset($this->options['greedyNamed']) && $this->options['greedyNamed'] === true;
- foreach ((array)$this->options['named'] as $key => $val) {
- if (is_numeric($key)) {
- $rules[$val] = true;
- continue;
- }
- $rules[$key] = $val;
- }
- }
-
- foreach ($args as $param) {
- if (empty($param) && $param !== '0' && $param !== 0) {
- continue;
- }
-
- $separatorIsPresent = strpos($param, $namedConfig['separator']) !== false;
- if ((!isset($this->options['named']) || !empty($this->options['named'])) && $separatorIsPresent) {
- list($key, $val) = explode($namedConfig['separator'], $param, 2);
- $key = rawurldecode($key);
- $val = rawurldecode($val);
- $hasRule = isset($rules[$key]);
- $passIt = (!$hasRule && !$greedy) || ($hasRule && !$this->_matchNamed($val, $rules[$key], $context));
- if ($passIt) {
- $pass[] = rawurldecode($param);
- } else {
- if (preg_match_all('/\[([A-Za-z0-9_-]+)?\]/', $key, $matches, PREG_SET_ORDER)) {
- $matches = array_reverse($matches);
- $parts = explode('[', $key);
- $key = array_shift($parts);
- $arr = $val;
- foreach ($matches as $match) {
- if (empty($match[1])) {
- $arr = array($arr);
- } else {
- $arr = array(
- $match[1] => $arr
- );
- }
- }
- $val = $arr;
- }
- $named = array_merge_recursive($named, array($key => $val));
- }
- } else {
- $pass[] = rawurldecode($param);
- }
- }
- return array($pass, $named);
- }
-
-/**
- * Return true if a given named $param's $val matches a given $rule depending on $context. Currently implemented
- * rule types are controller, action and match that can be combined with each other.
- *
- * @param string $val The value of the named parameter
- * @param array $rule The rule(s) to apply, can also be a match string
- * @param string $context An array with additional context information (controller / action)
- * @return boolean
- */
- protected function _matchNamed($val, $rule, $context) {
- if ($rule === true || $rule === false) {
- return $rule;
- }
- if (is_string($rule)) {
- $rule = array('match' => $rule);
- }
- if (!is_array($rule)) {
- return false;
- }
-
- $controllerMatches = (
- !isset($rule['controller'], $context['controller']) ||
- in_array($context['controller'], (array)$rule['controller'])
- );
- if (!$controllerMatches) {
- return false;
- }
- $actionMatches = (
- !isset($rule['action'], $context['action']) ||
- in_array($context['action'], (array)$rule['action'])
- );
- if (!$actionMatches) {
- return false;
- }
- return (!isset($rule['match']) || preg_match('/' . $rule['match'] . '/', $val));
- }
-
-/**
- * Apply persistent parameters to a url array. Persistent parameters are a special
- * key used during route creation to force route parameters to persist when omitted from
- * a url array.
- *
- * @param array $url The array to apply persistent parameters to.
- * @param array $params An array of persistent values to replace persistent ones.
- * @return array An array with persistent parameters applied.
- */
- public function persistParams($url, $params) {
- foreach ($this->options['persist'] as $persistKey) {
- if (array_key_exists($persistKey, $params) && !isset($url[$persistKey])) {
- $url[$persistKey] = $params[$persistKey];
- }
- }
- return $url;
- }
-
-/**
- * Attempt to match a url array. If the url matches the route parameters and settings, then
- * return a generated string url. If the url doesn't match the route parameters, false will be returned.
- * This method handles the reverse routing or conversion of url arrays into string urls.
- *
- * @param array $url An array of parameters to check matching with.
- * @return mixed Either a string url for the parameters if they match or false.
- */
- public function match($url) {
- if (!$this->compiled()) {
- $this->compile();
- }
- $defaults = $this->defaults;
-
- if (isset($defaults['prefix'])) {
- $url['prefix'] = $defaults['prefix'];
- }
-
- //check that all the key names are in the url
- $keyNames = array_flip($this->keys);
- if (array_intersect_key($keyNames, $url) !== $keyNames) {
- return false;
- }
-
- // Missing defaults is a fail.
- if (array_diff_key($defaults, $url) !== array()) {
- return false;
- }
-
- $namedConfig = Router::namedConfig();
- $prefixes = Router::prefixes();
- $greedyNamed = $namedConfig['greedyNamed'];
- $allowedNamedParams = $namedConfig['rules'];
-
- $named = $pass = array();
-
- foreach ($url as $key => $value) {
-
- // keys that exist in the defaults and have different values is a match failure.
- $defaultExists = array_key_exists($key, $defaults);
- if ($defaultExists && $defaults[$key] != $value) {
- return false;
- } elseif ($defaultExists) {
- continue;
- }
-
- // If the key is a routed key, its not different yet.
- if (array_key_exists($key, $keyNames)) {
- continue;
- }
-
- // pull out passed args
- $numeric = is_numeric($key);
- if ($numeric && isset($defaults[$key]) && $defaults[$key] == $value) {
- continue;
- } elseif ($numeric) {
- $pass[] = $value;
- unset($url[$key]);
- continue;
- }
-
- // pull out named params if named params are greedy or a rule exists.
- if (
- ($greedyNamed || isset($allowedNamedParams[$key])) &&
- ($value !== false && $value !== null) &&
- (!in_array($key, $prefixes))
- ) {
- $named[$key] = $value;
- continue;
- }
-
- // keys that don't exist are different.
- if (!$defaultExists && !empty($value)) {
- return false;
- }
- }
-
- //if a not a greedy route, no extra params are allowed.
- if (!$this->_greedy && (!empty($pass) || !empty($named))) {
- return false;
- }
-
- //check patterns for routed params
- if (!empty($this->options)) {
- foreach ($this->options as $key => $pattern) {
- if (array_key_exists($key, $url) && !preg_match('#^' . $pattern . '$#', $url[$key])) {
- return false;
- }
- }
- }
- return $this->_writeUrl(array_merge($url, compact('pass', 'named')));
- }
-
-/**
- * Converts a matching route array into a url string. Composes the string url using the template
- * used to create the route.
- *
- * @param array $params The params to convert to a string url.
- * @return string Composed route string.
- */
- protected function _writeUrl($params) {
- if (isset($params['prefix'], $params['action'])) {
- $params['action'] = str_replace($params['prefix'] . '_', '', $params['action']);
- unset($params['prefix']);
- }
-
- if (is_array($params['pass'])) {
- $params['pass'] = implode('/', array_map('rawurlencode', $params['pass']));
- }
-
- $namedConfig = Router::namedConfig();
- $separator = $namedConfig['separator'];
-
- if (!empty($params['named']) && is_array($params['named'])) {
- $named = array();
- foreach ($params['named'] as $key => $value) {
- if (is_array($value)) {
- $flat = Set::flatten($value, '][');
- foreach ($flat as $namedKey => $namedValue) {
- $named[] = $key . "[$namedKey]" . $separator . rawurlencode($namedValue);
- }
- } else {
- $named[] = $key . $separator . rawurlencode($value);
- }
- }
- $params['pass'] = $params['pass'] . '/' . implode('/', $named);
- }
- $out = $this->template;
-
- $search = $replace = array();
- foreach ($this->keys as $key) {
- $string = null;
- if (isset($params[$key])) {
- $string = $params[$key];
- } elseif (strpos($out, $key) != strlen($out) - strlen($key)) {
- $key .= '/';
- }
- $search[] = ':' . $key;
- $replace[] = $string;
- }
- $out = str_replace($search, $replace, $out);
-
- if (strpos($this->template, '*')) {
- $out = str_replace('*', $params['pass'], $out);
- }
- $out = str_replace('//', '/', $out);
- return $out;
- }
-
-}
diff --git a/lib/Cake/Routing/Route/PluginShortRoute.php b/lib/Cake/Routing/Route/PluginShortRoute.php
deleted file mode 100644
index 2edd944e4ed..00000000000
--- a/lib/Cake/Routing/Route/PluginShortRoute.php
+++ /dev/null
@@ -1,58 +0,0 @@
-defaults['controller'] = $url['controller'];
- $result = parent::match($url);
- unset($this->defaults['controller']);
- return $result;
- }
-
-}
diff --git a/lib/Cake/Routing/Route/RedirectRoute.php b/lib/Cake/Routing/Route/RedirectRoute.php
deleted file mode 100644
index bfb0f06c380..00000000000
--- a/lib/Cake/Routing/Route/RedirectRoute.php
+++ /dev/null
@@ -1,117 +0,0 @@
-redirect = (array)$defaults;
- }
-
-/**
- * Parses a string url into an array. Parsed urls will result in an automatic
- * redirection
- *
- * @param string $url The url to parse
- * @return boolean False on failure
- */
- public function parse($url) {
- $params = parent::parse($url);
- if (!$params) {
- return false;
- }
- if (!$this->response) {
- $this->response = new CakeResponse();
- }
- $redirect = $this->redirect;
- if (count($this->redirect) == 1 && !isset($this->redirect['controller'])) {
- $redirect = $this->redirect[0];
- }
- if (isset($this->options['persist']) && is_array($redirect)) {
- $redirect += array('named' => $params['named'], 'pass' => $params['pass'], 'url' => array());
- $redirect = Router::reverse($redirect);
- }
- $status = 301;
- if (isset($this->options['status']) && ($this->options['status'] >= 300 && $this->options['status'] < 400)) {
- $status = $this->options['status'];
- }
- $this->response->header(array('Location' => Router::url($redirect, true)));
- $this->response->statusCode($status);
- $this->response->send();
- $this->_stop();
- }
-
-/**
- * There is no reverse routing redirection routes
- *
- * @param array $url Array of parameters to convert to a string.
- * @return mixed either false or a string url.
- */
- public function match($url) {
- return false;
- }
-
-/**
- * Stop execution of the current script. Wraps exit() making
- * testing easier.
- *
- * @param integer|string $status see http://php.net/exit for values
- * @return void
- */
- protected function _stop($code = 0) {
- if ($this->stop) {
- exit($code);
- }
- }
-
-}
diff --git a/lib/Cake/Routing/Router.php b/lib/Cake/Routing/Router.php
deleted file mode 100644
index a7bad556366..00000000000
--- a/lib/Cake/Routing/Router.php
+++ /dev/null
@@ -1,1112 +0,0 @@
- Router::ACTION,
- 'Year' => Router::YEAR,
- 'Month' => Router::MONTH,
- 'Day' => Router::DAY,
- 'ID' => Router::ID,
- 'UUID' => Router::UUID
- );
-
-/**
- * Stores all information necessary to decide what named arguments are parsed under what conditions.
- *
- * @var string
- */
- protected static $_namedConfig = array(
- 'default' => array('page', 'fields', 'order', 'limit', 'recursive', 'sort', 'direction', 'step'),
- 'greedyNamed' => true,
- 'separator' => ':',
- 'rules' => false,
- );
-
-/**
- * The route matching the URL of the current request
- *
- * @var array
- */
- protected static $_currentRoute = array();
-
-/**
- * Default HTTP request method => controller action map.
- *
- * @var array
- */
- protected static $_resourceMap = array(
- array('action' => 'index', 'method' => 'GET', 'id' => false),
- array('action' => 'view', 'method' => 'GET', 'id' => true),
- array('action' => 'add', 'method' => 'POST', 'id' => false),
- array('action' => 'edit', 'method' => 'PUT', 'id' => true),
- array('action' => 'delete', 'method' => 'DELETE', 'id' => true),
- array('action' => 'edit', 'method' => 'POST', 'id' => true)
- );
-
-/**
- * List of resource-mapped controllers
- *
- * @var array
- */
- protected static $_resourceMapped = array();
-
-/**
- * Maintains the request object stack for the current request.
- * This will contain more than one request object when requestAction is used.
- *
- * @var array
- */
- protected static $_requests = array();
-
-/**
- * Initial state is populated the first time reload() is called which is at the bottom
- * of this file. This is a cheat as get_class_vars() returns the value of static vars even if they
- * have changed.
- *
- * @var array
- */
- protected static $_initialState = array();
-
-/**
- * Default route class to use
- *
- * @var string
- */
- protected static $_routeClass = 'CakeRoute';
-
-/**
- * Set the default route class to use or return the current one
- *
- * @param string $routeClass to set as default
- * @return mixed void|string
- * @throws RouterException
- */
- public static function defaultRouteClass($routeClass = null) {
- if (is_null($routeClass)) {
- return self::$_routeClass;
- }
-
- self::$_routeClass = self::_validateRouteClass($routeClass);
- }
-
-/**
- * Validates that the passed route class exists and is a subclass of CakeRoute
- *
- * @param $routeClass
- * @return string
- * @throws RouterException
- */
- protected static function _validateRouteClass($routeClass) {
- if (!class_exists($routeClass) || !is_subclass_of($routeClass, 'CakeRoute')) {
- throw new RouterException(__d('cake_dev', 'Route classes must extend CakeRoute'));
- }
- return $routeClass;
- }
-
-/**
- * Sets the Routing prefixes.
- *
- * @return void
- */
- protected static function _setPrefixes() {
- $routing = Configure::read('Routing');
- if (!empty($routing['prefixes'])) {
- self::$_prefixes = array_merge(self::$_prefixes, (array)$routing['prefixes']);
- }
- }
-
-/**
- * Gets the named route elements for use in app/Config/routes.php
- *
- * @return array Named route elements
- * @see Router::$_namedExpressions
- */
- public static function getNamedExpressions() {
- return self::$_namedExpressions;
- }
-
-/**
- * Resource map getter & setter.
- *
- * @param array $resourceMap Resource map
- * @return mixed
- * @see Router::$_resourceMap
- */
- public static function resourceMap($resourceMap = null) {
- if ($resourceMap === null) {
- return self::$_resourceMap;
- }
- self::$_resourceMap = $resourceMap;
- }
-
-/**
- * Connects a new Route in the router.
- *
- * Routes are a way of connecting request urls to objects in your application. At their core routes
- * are a set or regular expressions that are used to match requests to destinations.
- *
- * Examples:
- *
- * `Router::connect('/:controller/:action/*');`
- *
- * The first parameter will be used as a controller name while the second is used as the action name.
- * the '/*' syntax makes this route greedy in that it will match requests like `/posts/index` as well as requests
- * like `/posts/edit/1/foo/bar`.
- *
- * `Router::connect('/home-page', array('controller' => 'pages', 'action' => 'display', 'home'));`
- *
- * The above shows the use of route parameter defaults. And providing routing parameters for a static route.
- *
- * {{{
- * Router::connect(
- * '/:lang/:controller/:action/:id',
- * array(),
- * array('id' => '[0-9]+', 'lang' => '[a-z]{3}')
- * );
- * }}}
- *
- * Shows connecting a route with custom route parameters as well as providing patterns for those parameters.
- * Patterns for routing parameters do not need capturing groups, as one will be added for each route params.
- *
- * $options offers four 'special' keys. `pass`, `named`, `persist` and `routeClass`
- * have special meaning in the $options array.
- *
- * `pass` is used to define which of the routed parameters should be shifted into the pass array. Adding a
- * parameter to pass will remove it from the regular route array. Ex. `'pass' => array('slug')`
- *
- * `persist` is used to define which route parameters should be automatically included when generating
- * new urls. You can override persistent parameters by redefining them in a url or remove them by
- * setting the parameter to `false`. Ex. `'persist' => array('lang')`
- *
- * `routeClass` is used to extend and change how individual routes parse requests and handle reverse routing,
- * via a custom routing class. Ex. `'routeClass' => 'SlugRoute'`
- *
- * `named` is used to configure named parameters at the route level. This key uses the same options
- * as Router::connectNamed()
- *
- * @param string $route A string describing the template of the route
- * @param array $defaults An array describing the default route parameters. These parameters will be used by default
- * and can supply routing parameters that are not dynamic. See above.
- * @param array $options An array matching the named elements in the route to regular expressions which that
- * element should match. Also contains additional parameters such as which routed parameters should be
- * shifted into the passed arguments, supplying patterns for routing parameters and supplying the name of a
- * custom routing class.
- * @see routes
- * @return array Array of routes
- * @throws RouterException
- */
- public static function connect($route, $defaults = array(), $options = array()) {
- foreach (self::$_prefixes as $prefix) {
- if (isset($defaults[$prefix])) {
- if ($defaults[$prefix]) {
- $defaults['prefix'] = $prefix;
- } else {
- unset($defaults[$prefix]);
- }
- break;
- }
- }
- if (isset($defaults['prefix'])) {
- self::$_prefixes[] = $defaults['prefix'];
- self::$_prefixes = array_keys(array_flip(self::$_prefixes));
- }
- $defaults += array('plugin' => null);
- if (empty($options['action'])) {
- $defaults += array('action' => 'index');
- }
- $routeClass = self::$_routeClass;
- if (isset($options['routeClass'])) {
- $routeClass = self::_validateRouteClass($options['routeClass']);
- unset($options['routeClass']);
- }
- if ($routeClass == 'RedirectRoute' && isset($defaults['redirect'])) {
- $defaults = $defaults['redirect'];
- }
- self::$routes[] = new $routeClass($route, $defaults, $options);
- return self::$routes;
- }
-
-/**
- * Connects a new redirection Route in the router.
- *
- * Redirection routes are different from normal routes as they perform an actual
- * header redirection if a match is found. The redirection can occur within your
- * application or redirect to an outside location.
- *
- * Examples:
- *
- * `Router::redirect('/home/*', array('controller' => 'posts', 'action' => 'view', array('persist' => true));`
- *
- * Redirects /home/* to /posts/view and passes the parameters to /posts/view. Using an array as the
- * redirect destination allows you to use other routes to define where a url string should be redirected to.
- *
- * `Router::redirect('/posts/*', 'http://google.com', array('status' => 302));`
- *
- * Redirects /posts/* to http://google.com with a HTTP status of 302
- *
- * ### Options:
- *
- * - `status` Sets the HTTP status (default 301)
- * - `persist` Passes the params to the redirected route, if it can. This is useful with greedy routes,
- * routes that end in `*` are greedy. As you can remap urls and not loose any passed/named args.
- *
- * @param string $route A string describing the template of the route
- * @param array $url A url to redirect to. Can be a string or a Cake array-based url
- * @param array $options An array matching the named elements in the route to regular expressions which that
- * element should match. Also contains additional parameters such as which routed parameters should be
- * shifted into the passed arguments. As well as supplying patterns for routing parameters.
- * @see routes
- * @return array Array of routes
- */
- public static function redirect($route, $url, $options = array()) {
- App::uses('RedirectRoute', 'Routing/Route');
- $options['routeClass'] = 'RedirectRoute';
- if (is_string($url)) {
- $url = array('redirect' => $url);
- }
- return self::connect($route, $url, $options);
- }
-
-/**
- * Specifies what named parameters CakePHP should be parsing out of incoming urls. By default
- * CakePHP will parse every named parameter out of incoming URLs. However, if you want to take more
- * control over how named parameters are parsed you can use one of the following setups:
- *
- * Do not parse any named parameters:
- *
- * {{{ Router::connectNamed(false); }}}
- *
- * Parse only default parameters used for CakePHP's pagination:
- *
- * {{{ Router::connectNamed(false, array('default' => true)); }}}
- *
- * Parse only the page parameter if its value is a number:
- *
- * {{{ Router::connectNamed(array('page' => '[\d]+'), array('default' => false, 'greedy' => false)); }}}
- *
- * Parse only the page parameter no matter what.
- *
- * {{{ Router::connectNamed(array('page'), array('default' => false, 'greedy' => false)); }}}
- *
- * Parse only the page parameter if the current action is 'index'.
- *
- * {{{
- * Router::connectNamed(
- * array('page' => array('action' => 'index')),
- * array('default' => false, 'greedy' => false)
- * );
- * }}}
- *
- * Parse only the page parameter if the current action is 'index' and the controller is 'pages'.
- *
- * {{{
- * Router::connectNamed(
- * array('page' => array('action' => 'index', 'controller' => 'pages')),
- * array('default' => false, 'greedy' => false)
- * );
- * }}}
- *
- * ### Options
- *
- * - `greedy` Setting this to true will make Router parse all named params. Setting it to false will
- * parse only the connected named params.
- * - `default` Set this to true to merge in the default set of named parameters.
- * - `reset` Set to true to clear existing rules and start fresh.
- * - `separator` Change the string used to separate the key & value in a named parameter. Defaults to `:`
- *
- * @param array $named A list of named parameters. Key value pairs are accepted where values are
- * either regex strings to match, or arrays as seen above.
- * @param array $options Allows to control all settings: separator, greedy, reset, default
- * @return array
- */
- public static function connectNamed($named, $options = array()) {
- if (isset($options['separator'])) {
- self::$_namedConfig['separator'] = $options['separator'];
- unset($options['separator']);
- }
-
- if ($named === true || $named === false) {
- $options = array_merge(array('default' => $named, 'reset' => true, 'greedy' => $named), $options);
- $named = array();
- } else {
- $options = array_merge(array('default' => false, 'reset' => false, 'greedy' => true), $options);
- }
-
- if ($options['reset'] == true || self::$_namedConfig['rules'] === false) {
- self::$_namedConfig['rules'] = array();
- }
-
- if ($options['default']) {
- $named = array_merge($named, self::$_namedConfig['default']);
- }
-
- foreach ($named as $key => $val) {
- if (is_numeric($key)) {
- self::$_namedConfig['rules'][$val] = true;
- } else {
- self::$_namedConfig['rules'][$key] = $val;
- }
- }
- self::$_namedConfig['greedyNamed'] = $options['greedy'];
- return self::$_namedConfig;
- }
-
-/**
- * Gets the current named parameter configuration values.
- *
- * @return array
- * @see Router::$_namedConfig
- */
- public static function namedConfig() {
- return self::$_namedConfig;
- }
-
-/**
- * Creates REST resource routes for the given controller(s). When creating resource routes
- * for a plugin, by default the prefix will be changed to the lower_underscore version of the plugin
- * name. By providing a prefix you can override this behavior.
- *
- * ### Options:
- *
- * - 'id' - The regular expression fragment to use when matching IDs. By default, matches
- * integer values and UUIDs.
- * - 'prefix' - URL prefix to use for the generated routes. Defaults to '/'.
- *
- * @param mixed $controller A controller name or array of controller names (i.e. "Posts" or "ListItems")
- * @param array $options Options to use when generating REST routes
- * @return array Array of mapped resources
- */
- public static function mapResources($controller, $options = array()) {
- $hasPrefix = isset($options['prefix']);
- $options = array_merge(array(
- 'prefix' => '/',
- 'id' => self::ID . '|' . self::UUID
- ), $options);
-
- $prefix = $options['prefix'];
-
- foreach ((array)$controller as $name) {
- list($plugin, $name) = pluginSplit($name);
- $urlName = Inflector::underscore($name);
- $plugin = Inflector::underscore($plugin);
- if ($plugin && !$hasPrefix) {
- $prefix = '/' . $plugin . '/';
- }
-
- foreach (self::$_resourceMap as $params) {
- $url = $prefix . $urlName . (($params['id']) ? '/:id' : '');
-
- Router::connect($url,
- array(
- 'plugin' => $plugin,
- 'controller' => $urlName,
- 'action' => $params['action'],
- '[method]' => $params['method']
- ),
- array('id' => $options['id'], 'pass' => array('id'))
- );
- }
- self::$_resourceMapped[] = $urlName;
- }
- return self::$_resourceMapped;
- }
-
-/**
- * Returns the list of prefixes used in connected routes
- *
- * @return array A list of prefixes used in connected routes
- */
- public static function prefixes() {
- return self::$_prefixes;
- }
-
-/**
- * Parses given URL string. Returns 'routing' parameters for that url.
- *
- * @param string $url URL to be parsed
- * @return array Parsed elements from URL
- */
- public static function parse($url) {
- $ext = null;
- $out = array();
-
- if ($url && strpos($url, '/') !== 0) {
- $url = '/' . $url;
- }
- if (strpos($url, '?') !== false) {
- $url = substr($url, 0, strpos($url, '?'));
- }
-
- extract(self::_parseExtension($url));
-
- for ($i = 0, $len = count(self::$routes); $i < $len; $i++) {
- $route =& self::$routes[$i];
-
- if (($r = $route->parse($url)) !== false) {
- self::$_currentRoute[] =& $route;
- $out = $r;
- break;
- }
- }
- if (isset($out['prefix'])) {
- $out['action'] = $out['prefix'] . '_' . $out['action'];
- }
-
- if (!empty($ext) && !isset($out['ext'])) {
- $out['ext'] = $ext;
- }
- return $out;
- }
-
-/**
- * Parses a file extension out of a URL, if Router::parseExtensions() is enabled.
- *
- * @param string $url
- * @return array Returns an array containing the altered URL and the parsed extension.
- */
- protected static function _parseExtension($url) {
- $ext = null;
-
- if (self::$_parseExtensions) {
- if (preg_match('/\.[0-9a-zA-Z]*$/', $url, $match) === 1) {
- $match = substr($match[0], 1);
- if (empty(self::$_validExtensions)) {
- $url = substr($url, 0, strpos($url, '.' . $match));
- $ext = $match;
- } else {
- foreach (self::$_validExtensions as $name) {
- if (strcasecmp($name, $match) === 0) {
- $url = substr($url, 0, strpos($url, '.' . $name));
- $ext = $match;
- break;
- }
- }
- }
- }
- }
- return compact('ext', 'url');
- }
-
-/**
- * Takes parameter and path information back from the Dispatcher, sets these
- * parameters as the current request parameters that are merged with url arrays
- * created later in the request.
- *
- * Nested requests will create a stack of requests. You can remove requests using
- * Router::popRequest(). This is done automatically when using Object::requestAction().
- *
- * Will accept either a CakeRequest object or an array of arrays. Support for
- * accepting arrays may be removed in the future.
- *
- * @param CakeRequest|array $request Parameters and path information or a CakeRequest object.
- * @return void
- */
- public static function setRequestInfo($request) {
- if ($request instanceof CakeRequest) {
- self::$_requests[] = $request;
- } else {
- $requestObj = new CakeRequest();
- $request += array(array(), array());
- $request[0] += array('controller' => false, 'action' => false, 'plugin' => null);
- $requestObj->addParams($request[0])->addPaths($request[1]);
- self::$_requests[] = $requestObj;
- }
- }
-
-/**
- * Pops a request off of the request stack. Used when doing requestAction
- *
- * @return CakeRequest The request removed from the stack.
- * @see Router::setRequestInfo()
- * @see Object::requestAction()
- */
- public static function popRequest() {
- return array_pop(self::$_requests);
- }
-
-/**
- * Get the either the current request object, or the first one.
- *
- * @param boolean $current Whether you want the request from the top of the stack or the first one.
- * @return CakeRequest or null.
- */
- public static function getRequest($current = false) {
- if ($current) {
- return self::$_requests[count(self::$_requests) - 1];
- }
- return isset(self::$_requests[0]) ? self::$_requests[0] : null;
- }
-
-/**
- * Gets parameter information
- *
- * @param boolean $current Get current request parameter, useful when using requestAction
- * @return array Parameter information
- */
- public static function getParams($current = false) {
- if ($current) {
- return self::$_requests[count(self::$_requests) - 1]->params;
- }
- if (isset(self::$_requests[0])) {
- return self::$_requests[0]->params;
- }
- return array();
- }
-
-/**
- * Gets URL parameter by name
- *
- * @param string $name Parameter name
- * @param boolean $current Current parameter, useful when using requestAction
- * @return string Parameter value
- */
- public static function getParam($name = 'controller', $current = false) {
- $params = Router::getParams($current);
- if (isset($params[$name])) {
- return $params[$name];
- }
- return null;
- }
-
-/**
- * Gets path information
- *
- * @param boolean $current Current parameter, useful when using requestAction
- * @return array
- */
- public static function getPaths($current = false) {
- if ($current) {
- return self::$_requests[count(self::$_requests) - 1];
- }
- if (!isset(self::$_requests[0])) {
- return array('base' => null);
- }
- return array('base' => self::$_requests[0]->base);
- }
-
-/**
- * Reloads default Router settings. Resets all class variables and
- * removes all connected routes.
- *
- * @return void
- */
- public static function reload() {
- if (empty(self::$_initialState)) {
- self::$_initialState = get_class_vars('Router');
- self::_setPrefixes();
- return;
- }
- foreach (self::$_initialState as $key => $val) {
- if ($key != '_initialState') {
- self::${$key} = $val;
- }
- }
- self::_setPrefixes();
- }
-
-/**
- * Promote a route (by default, the last one added) to the beginning of the list
- *
- * @param integer $which A zero-based array index representing the route to move. For example,
- * if 3 routes have been added, the last route would be 2.
- * @return boolean Returns false if no route exists at the position specified by $which.
- */
- public static function promote($which = null) {
- if ($which === null) {
- $which = count(self::$routes) - 1;
- }
- if (!isset(self::$routes[$which])) {
- return false;
- }
- $route =& self::$routes[$which];
- unset(self::$routes[$which]);
- array_unshift(self::$routes, $route);
- return true;
- }
-
-/**
- * Finds URL for specified action.
- *
- * Returns an URL pointing to a combination of controller and action. Param
- * $url can be:
- *
- * - Empty - the method will find address to actual controller/action.
- * - '/' - the method will find base URL of application.
- * - A combination of controller/action - the method will find url for it.
- *
- * There are a few 'special' parameters that can change the final URL string that is generated
- *
- * - `base` - Set to false to remove the base path from the generated url. If your application
- * is not in the root directory, this can be used to generate urls that are 'cake relative'.
- * cake relative urls are required when using requestAction.
- * - `?` - Takes an array of query string parameters
- * - `#` - Allows you to set url hash fragments.
- * - `full_base` - If true the `FULL_BASE_URL` constant will be prepended to generated urls.
- *
- * @param mixed $url Cake-relative URL, like "/products/edit/92" or "/presidents/elect/4"
- * or an array specifying any of the following: 'controller', 'action',
- * and/or 'plugin', in addition to named arguments (keyed array elements),
- * and standard URL arguments (indexed array elements)
- * @param mixed $full If (bool) true, the full base URL will be prepended to the result.
- * If an array accepts the following keys
- * - escape - used when making urls embedded in html escapes query string '&'
- * - full - if true the full base URL will be prepended.
- * @return string Full translated URL with base path.
- */
- public static function url($url = null, $full = false) {
- $params = array('plugin' => null, 'controller' => null, 'action' => 'index');
-
- if (is_bool($full)) {
- $escape = false;
- } else {
- extract($full + array('escape' => false, 'full' => false));
- }
-
- $path = array('base' => null);
- if (!empty(self::$_requests)) {
- $request = self::$_requests[count(self::$_requests) - 1];
- $params = $request->params;
- $path = array('base' => $request->base, 'here' => $request->here);
- }
-
- $base = $path['base'];
- $extension = $output = $q = $frag = null;
-
- if (empty($url)) {
- $output = isset($path['here']) ? $path['here'] : '/';
- if ($full && defined('FULL_BASE_URL')) {
- $output = FULL_BASE_URL . $output;
- }
- return $output;
- } elseif (is_array($url)) {
- if (isset($url['base']) && $url['base'] === false) {
- $base = null;
- unset($url['base']);
- }
- if (isset($url['full_base']) && $url['full_base'] === true) {
- $full = true;
- unset($url['full_base']);
- }
- if (isset($url['?'])) {
- $q = $url['?'];
- unset($url['?']);
- }
- if (isset($url['#'])) {
- $frag = '#' . urlencode($url['#']);
- unset($url['#']);
- }
- if (isset($url['ext'])) {
- $extension = '.' . $url['ext'];
- unset($url['ext']);
- }
- if (empty($url['action'])) {
- if (empty($url['controller']) || $params['controller'] === $url['controller']) {
- $url['action'] = $params['action'];
- } else {
- $url['action'] = 'index';
- }
- }
-
- $prefixExists = (array_intersect_key($url, array_flip(self::$_prefixes)));
- foreach (self::$_prefixes as $prefix) {
- if (!empty($params[$prefix]) && !$prefixExists) {
- $url[$prefix] = true;
- } elseif (isset($url[$prefix]) && !$url[$prefix]) {
- unset($url[$prefix]);
- }
- if (isset($url[$prefix]) && strpos($url['action'], $prefix . '_') === 0) {
- $url['action'] = substr($url['action'], strlen($prefix) + 1);
- }
- }
-
- $url += array('controller' => $params['controller'], 'plugin' => $params['plugin']);
-
- $match = false;
-
- for ($i = 0, $len = count(self::$routes); $i < $len; $i++) {
- $originalUrl = $url;
-
- if (isset(self::$routes[$i]->options['persist'], $params)) {
- $url = self::$routes[$i]->persistParams($url, $params);
- }
-
- if ($match = self::$routes[$i]->match($url)) {
- $output = trim($match, '/');
- break;
- }
- $url = $originalUrl;
- }
- if ($match === false) {
- $output = self::_handleNoRoute($url);
- }
- } else {
- if (
- (strpos($url, '://') !== false ||
- (strpos($url, 'javascript:') === 0) ||
- (strpos($url, 'mailto:') === 0)) ||
- (!strncmp($url, '#', 1))
- ) {
- return $url;
- }
- if (substr($url, 0, 1) === '/') {
- $output = substr($url, 1);
- } else {
- foreach (self::$_prefixes as $prefix) {
- if (isset($params[$prefix])) {
- $output .= $prefix . '/';
- break;
- }
- }
- if (!empty($params['plugin']) && $params['plugin'] !== $params['controller']) {
- $output .= Inflector::underscore($params['plugin']) . '/';
- }
- $output .= Inflector::underscore($params['controller']) . '/' . $url;
- }
- }
- $protocol = preg_match('#^[a-z][a-z0-9+-.]*\://#i', $output);
- if ($protocol === 0) {
- $output = str_replace('//', '/', $base . '/' . $output);
-
- if ($full && defined('FULL_BASE_URL')) {
- $output = FULL_BASE_URL . $output;
- }
- if (!empty($extension)) {
- $output = rtrim($output, '/');
- }
- }
- return $output . $extension . self::queryString($q, array(), $escape) . $frag;
- }
-
-/**
- * A special fallback method that handles url arrays that cannot match
- * any defined routes.
- *
- * @param array $url A url that didn't match any routes
- * @return string A generated url for the array
- * @see Router::url()
- */
- protected static function _handleNoRoute($url) {
- $named = $args = array();
- $skip = array_merge(
- array('bare', 'action', 'controller', 'plugin', 'prefix'),
- self::$_prefixes
- );
-
- $keys = array_values(array_diff(array_keys($url), $skip));
- $count = count($keys);
-
- // Remove this once parsed URL parameters can be inserted into 'pass'
- for ($i = 0; $i < $count; $i++) {
- $key = $keys[$i];
- if (is_numeric($keys[$i])) {
- $args[] = $url[$key];
- } else {
- $named[$key] = $url[$key];
- }
- }
-
- list($args, $named) = array(Set::filter($args, true), Set::filter($named, true));
- foreach (self::$_prefixes as $prefix) {
- if (!empty($url[$prefix])) {
- $url['action'] = str_replace($prefix . '_', '', $url['action']);
- break;
- }
- }
-
- if (empty($named) && empty($args) && (!isset($url['action']) || $url['action'] === 'index')) {
- $url['action'] = null;
- }
-
- $urlOut = array_filter(array($url['controller'], $url['action']));
-
- if (isset($url['plugin'])) {
- array_unshift($urlOut, $url['plugin']);
- }
-
- foreach (self::$_prefixes as $prefix) {
- if (isset($url[$prefix])) {
- array_unshift($urlOut, $prefix);
- break;
- }
- }
- $output = implode('/', $urlOut);
-
- if (!empty($args)) {
- $output .= '/' . implode('/', array_map('rawurlencode', $args));
- }
-
- if (!empty($named)) {
- foreach ($named as $name => $value) {
- if (is_array($value)) {
- $flattend = Set::flatten($value, '][');
- foreach ($flattend as $namedKey => $namedValue) {
- $output .= '/' . $name . "[$namedKey]" . self::$_namedConfig['separator'] . rawurlencode($namedValue);
- }
- } else {
- $output .= '/' . $name . self::$_namedConfig['separator'] . rawurlencode($value);
- }
- }
- }
- return $output;
- }
-
-/**
- * Generates a well-formed querystring from $q
- *
- * @param string|array $q Query string Either a string of already compiled query string arguments or
- * an array of arguments to convert into a query string.
- * @param array $extra Extra querystring parameters.
- * @param boolean $escape Whether or not to use escaped &
- * @return array
- */
- public static function queryString($q, $extra = array(), $escape = false) {
- if (empty($q) && empty($extra)) {
- return null;
- }
- $join = '&';
- if ($escape === true) {
- $join = '&';
- }
- $out = '';
-
- if (is_array($q)) {
- $q = array_merge($extra, $q);
- } else {
- $out = $q;
- $q = $extra;
- }
- $out .= http_build_query($q, null, $join);
- if (isset($out[0]) && $out[0] != '?') {
- $out = '?' . $out;
- }
- return $out;
- }
-
-/**
- * Reverses a parsed parameter array into a string. Works similarly to Router::url(), but
- * Since parsed URL's contain additional 'pass' and 'named' as well as 'url.url' keys.
- * Those keys need to be specially handled in order to reverse a params array into a string url.
- *
- * This will strip out 'autoRender', 'bare', 'requested', and 'return' param names as those
- * are used for CakePHP internals and should not normally be part of an output url.
- *
- * @param CakeRequest|array $params The params array or CakeRequest object that needs to be reversed.
- * @param boolean $full Set to true to include the full url including the protocol when reversing
- * the url.
- * @return string The string that is the reversed result of the array
- */
- public static function reverse($params, $full = false) {
- if ($params instanceof CakeRequest) {
- $url = $params->query;
- $params = $params->params;
- } else {
- $url = $params['url'];
- }
- $pass = isset($params['pass']) ? $params['pass'] : array();
- $named = isset($params['named']) ? $params['named'] : array();
-
- unset(
- $params['pass'], $params['named'], $params['paging'], $params['models'], $params['url'], $url['url'],
- $params['autoRender'], $params['bare'], $params['requested'], $params['return'],
- $params['_Token']
- );
- $params = array_merge($params, $pass, $named);
- if (!empty($url)) {
- $params['?'] = $url;
- }
- return Router::url($params, $full);
- }
-
-/**
- * Normalizes a URL for purposes of comparison. Will strip the base path off
- * and replace any double /'s. It will not unify the casing and underscoring
- * of the input value.
- *
- * @param mixed $url URL to normalize Either an array or a string url.
- * @return string Normalized URL
- */
- public static function normalize($url = '/') {
- if (is_array($url)) {
- $url = Router::url($url);
- } elseif (preg_match('/^[a-z\-]+:\/\//', $url)) {
- return $url;
- }
- $request = Router::getRequest();
-
- if (!empty($request->base) && stristr($url, $request->base)) {
- $url = preg_replace('/^' . preg_quote($request->base, '/') . '/', '', $url, 1);
- }
- $url = '/' . $url;
-
- while (strpos($url, '//') !== false) {
- $url = str_replace('//', '/', $url);
- }
- $url = preg_replace('/(?:(\/$))/', '', $url);
-
- if (empty($url)) {
- return '/';
- }
- return $url;
- }
-
-/**
- * Returns the route matching the current request URL.
- *
- * @return CakeRoute Matching route object.
- */
- public static function &requestRoute() {
- return self::$_currentRoute[0];
- }
-
-/**
- * Returns the route matching the current request (useful for requestAction traces)
- *
- * @return CakeRoute Matching route object.
- */
- public static function ¤tRoute() {
- return self::$_currentRoute[count(self::$_currentRoute) - 1];
- }
-
-/**
- * Removes the plugin name from the base URL.
- *
- * @param string $base Base URL
- * @param string $plugin Plugin name
- * @return string base url with plugin name removed if present
- */
- public static function stripPlugin($base, $plugin = null) {
- if ($plugin != null) {
- $base = preg_replace('/(?:' . $plugin . ')/', '', $base);
- $base = str_replace('//', '', $base);
- $pos1 = strrpos($base, '/');
- $char = strlen($base) - 1;
-
- if ($pos1 === $char) {
- $base = substr($base, 0, $char);
- }
- }
- return $base;
- }
-
-/**
- * Instructs the router to parse out file extensions from the URL. For example,
- * http://example.com/posts.rss would yield an file extension of "rss".
- * The file extension itself is made available in the controller as
- * `$this->params['ext']`, and is used by the RequestHandler component to
- * automatically switch to alternate layouts and templates, and load helpers
- * corresponding to the given content, i.e. RssHelper. Switching layouts and helpers
- * requires that the chosen extension has a defined mime type in `CakeResponse`
- *
- * A list of valid extension can be passed to this method, i.e. Router::parseExtensions('rss', 'xml');
- * If no parameters are given, anything after the first . (dot) after the last / in the URL will be
- * parsed, excluding querystring parameters (i.e. ?q=...).
- *
- * @return void
- * @see RequestHandler::startup()
- */
- public static function parseExtensions() {
- self::$_parseExtensions = true;
- if (func_num_args() > 0) {
- self::$_validExtensions = func_get_args();
- }
- }
-
-/**
- * Get the list of extensions that can be parsed by Router. To add more
- * extensions use Router::parseExtensions()
- *
- * @return array Array of extensions Router is configured to parse.
- */
- public static function extensions() {
- return self::$_validExtensions;
- }
-
-}
-
-//Save the initial state
-Router::reload();
diff --git a/lib/Cake/Test/Case/AllBehaviorsTest.php b/lib/Cake/Test/Case/AllBehaviorsTest.php
deleted file mode 100644
index c2f30af55a5..00000000000
--- a/lib/Cake/Test/Case/AllBehaviorsTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-addTestFile(CORE_TEST_CASES . DS . 'Model' . DS . 'BehaviorCollectionTest.php');
-
- $suite->addTestDirectory($path);
- return $suite;
- }
-}
diff --git a/lib/Cake/Test/Case/AllCacheTest.php b/lib/Cake/Test/Case/AllCacheTest.php
deleted file mode 100644
index e9c8a3eb862..00000000000
--- a/lib/Cake/Test/Case/AllCacheTest.php
+++ /dev/null
@@ -1,40 +0,0 @@
-addTestDirectory(CORE_TEST_CASES . DS . 'Cache');
- $suite->addTestDirectory(CORE_TEST_CASES . DS . 'Cache' . DS . 'Engine');
- return $suite;
- }
-}
diff --git a/lib/Cake/Test/Case/AllComponentsTest.php b/lib/Cake/Test/Case/AllComponentsTest.php
deleted file mode 100644
index 25cf1703631..00000000000
--- a/lib/Cake/Test/Case/AllComponentsTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-addTestFile(CORE_TEST_CASES . DS . 'Controller' . DS . 'ComponentTest.php');
- $suite->addTestFile(CORE_TEST_CASES . DS . 'Controller' . DS . 'ComponentCollectionTest.php');
- $suite->addTestDirectoryRecursive(CORE_TEST_CASES . DS . 'Controller' . DS . 'Component');
- return $suite;
- }
-}
diff --git a/lib/Cake/Test/Case/AllConfigureTest.php b/lib/Cake/Test/Case/AllConfigureTest.php
deleted file mode 100644
index ff56ee6b98b..00000000000
--- a/lib/Cake/Test/Case/AllConfigureTest.php
+++ /dev/null
@@ -1,40 +0,0 @@
-addTestDirectory(CORE_TEST_CASES . DS . 'Configure');
- return $suite;
- }
-}
diff --git a/lib/Cake/Test/Case/AllConsoleTest.php b/lib/Cake/Test/Case/AllConsoleTest.php
deleted file mode 100644
index 820d622b2ce..00000000000
--- a/lib/Cake/Test/Case/AllConsoleTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-addTestFile($path . 'AllConsoleLibsTest.php');
- $suite->addTestFile($path . 'AllTasksTest.php');
- $suite->addTestFile($path . 'AllShellsTest.php');
- return $suite;
- }
-}
\ No newline at end of file
diff --git a/lib/Cake/Test/Case/AllControllerTest.php b/lib/Cake/Test/Case/AllControllerTest.php
deleted file mode 100644
index 0d3a316493c..00000000000
--- a/lib/Cake/Test/Case/AllControllerTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-addTestFile(CORE_TEST_CASES . DS . 'Controller' . DS . 'ControllerTest.php');
- $suite->addTestFile(CORE_TEST_CASES . DS . 'Controller' . DS . 'ScaffoldTest.php');
- $suite->addTestFile(CORE_TEST_CASES . DS . 'Controller' . DS . 'PagesControllerTest.php');
- $suite->addTestFile(CORE_TEST_CASES . DS . 'Controller' . DS . 'ComponentTest.php');
- $suite->addTestFile(CORE_TEST_CASES . DS . 'Controller' . DS . 'ControllerMergeVarsTest.php');
- return $suite;
- }
-}
\ No newline at end of file
diff --git a/lib/Cake/Test/Case/AllCoreTest.php b/lib/Cake/Test/Case/AllCoreTest.php
deleted file mode 100644
index 7964fe12fca..00000000000
--- a/lib/Cake/Test/Case/AllCoreTest.php
+++ /dev/null
@@ -1,41 +0,0 @@
-addTestDirectory(CORE_TEST_CASES . DS . 'Core');
- return $suite;
- }
-}
-
diff --git a/lib/Cake/Test/Case/AllDatabaseTest.php b/lib/Cake/Test/Case/AllDatabaseTest.php
deleted file mode 100644
index 6357ab9b1f7..00000000000
--- a/lib/Cake/Test/Case/AllDatabaseTest.php
+++ /dev/null
@@ -1,56 +0,0 @@
-addTestFile($path . $task . 'Test.php');
- }
- return $suite;
- }
-}
diff --git a/lib/Cake/Test/Case/AllErrorTest.php b/lib/Cake/Test/Case/AllErrorTest.php
deleted file mode 100644
index 0777ed50537..00000000000
--- a/lib/Cake/Test/Case/AllErrorTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-addTestDirectory($libs . 'Error');
- return $suite;
- }
-}
diff --git a/lib/Cake/Test/Case/AllEventTest.php b/lib/Cake/Test/Case/AllEventTest.php
deleted file mode 100644
index 9f8ab2941c9..00000000000
--- a/lib/Cake/Test/Case/AllEventTest.php
+++ /dev/null
@@ -1,40 +0,0 @@
-addTestDirectory(CORE_TEST_CASES . DS . 'Event');
- return $suite;
- }
-}
-
diff --git a/lib/Cake/Test/Case/AllHelpersTest.php b/lib/Cake/Test/Case/AllHelpersTest.php
deleted file mode 100644
index 9c40ad6f40f..00000000000
--- a/lib/Cake/Test/Case/AllHelpersTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-addTestFile(CORE_TEST_CASES . DS . 'View' . DS . 'HelperTest.php');
- $suite->addTestFile(CORE_TEST_CASES . DS . 'View' . DS . 'HelperCollectionTest.php');
- $suite->addTestDirectory(CORE_TEST_CASES . DS . 'View' . DS . 'Helper' . DS);
- return $suite;
- }
-}
diff --git a/lib/Cake/Test/Case/AllI18nTest.php b/lib/Cake/Test/Case/AllI18nTest.php
deleted file mode 100644
index b4bfb8b2756..00000000000
--- a/lib/Cake/Test/Case/AllI18nTest.php
+++ /dev/null
@@ -1,40 +0,0 @@
-addTestDirectory(CORE_TEST_CASES . DS . 'I18n');
- return $suite;
- }
-}
diff --git a/lib/Cake/Test/Case/AllLogTest.php b/lib/Cake/Test/Case/AllLogTest.php
deleted file mode 100644
index e6dca95b611..00000000000
--- a/lib/Cake/Test/Case/AllLogTest.php
+++ /dev/null
@@ -1,41 +0,0 @@
-addTestDirectory(CORE_TEST_CASES . DS . 'Log');
- $suite->addTestDirectory(CORE_TEST_CASES . DS . 'Log' . DS . 'Engine');
- return $suite;
- }
-}
-
diff --git a/lib/Cake/Test/Case/AllNetworkTest.php b/lib/Cake/Test/Case/AllNetworkTest.php
deleted file mode 100644
index 22809e067f1..00000000000
--- a/lib/Cake/Test/Case/AllNetworkTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-addTestDirectory(CORE_TEST_CASES . DS . 'Network');
- $suite->addTestDirectory(CORE_TEST_CASES . DS . 'Network' . DS . 'Email');
- $suite->addTestDirectory(CORE_TEST_CASES . DS . 'Network' . DS . 'Http');
- return $suite;
- }
-}
diff --git a/lib/Cake/Test/Case/AllRoutingTest.php b/lib/Cake/Test/Case/AllRoutingTest.php
deleted file mode 100644
index 0564439a5d6..00000000000
--- a/lib/Cake/Test/Case/AllRoutingTest.php
+++ /dev/null
@@ -1,43 +0,0 @@
-addTestDirectory($libs . 'Routing');
- $suite->addTestDirectory($libs . 'Routing' . DS . 'Route');
- return $suite;
- }
-}
diff --git a/lib/Cake/Test/Case/AllTestSuiteTest.php b/lib/Cake/Test/Case/AllTestSuiteTest.php
deleted file mode 100644
index 1ead825dd1a..00000000000
--- a/lib/Cake/Test/Case/AllTestSuiteTest.php
+++ /dev/null
@@ -1,40 +0,0 @@
-addTestDirectory(CORE_TEST_CASES . DS . 'TestSuite');
- return $suite;
- }
-}
\ No newline at end of file
diff --git a/lib/Cake/Test/Case/AllTestsTest.php b/lib/Cake/Test/Case/AllTestsTest.php
deleted file mode 100644
index 89903596d03..00000000000
--- a/lib/Cake/Test/Case/AllTestsTest.php
+++ /dev/null
@@ -1,60 +0,0 @@
-addTestFile($path . 'BasicsTest.php');
- $suite->addTestFile($path . 'AllConsoleTest.php');
- $suite->addTestFile($path . 'AllBehaviorsTest.php');
- $suite->addTestFile($path . 'AllCacheTest.php');
- $suite->addTestFile($path . 'AllComponentsTest.php');
- $suite->addTestFile($path . 'AllConfigureTest.php');
- $suite->addTestFile($path . 'AllCoreTest.php');
- $suite->addTestFile($path . 'AllControllerTest.php');
- $suite->addTestFile($path . 'AllDatabaseTest.php');
- $suite->addTestFile($path . 'AllErrorTest.php');
- $suite->addTestFile($path . 'AllEventTest.php');
- $suite->addTestFile($path . 'AllHelpersTest.php');
- $suite->addTestFile($path . 'AllLogTest.php');
- $suite->addTestFile($path . 'Model' . DS . 'ModelTest.php');
- $suite->addTestFile($path . 'AllRoutingTest.php');
- $suite->addTestFile($path . 'AllNetworkTest.php');
- $suite->addTestFile($path . 'AllTestSuiteTest.php');
- $suite->addTestFile($path . 'AllUtilityTest.php');
- $suite->addTestFile($path . 'AllViewTest.php');
- $suite->addTestFile($path . 'AllI18nTest.php');
- return $suite;
- }
-}
diff --git a/lib/Cake/Test/Case/AllUtilityTest.php b/lib/Cake/Test/Case/AllUtilityTest.php
deleted file mode 100644
index 8b41d8dae04..00000000000
--- a/lib/Cake/Test/Case/AllUtilityTest.php
+++ /dev/null
@@ -1,39 +0,0 @@
-addTestDirectory(CORE_TEST_CASES . DS . 'Utility');
- return $suite;
- }
-}
diff --git a/lib/Cake/Test/Case/AllViewTest.php b/lib/Cake/Test/Case/AllViewTest.php
deleted file mode 100644
index 3a9bcd3d0d2..00000000000
--- a/lib/Cake/Test/Case/AllViewTest.php
+++ /dev/null
@@ -1,40 +0,0 @@
-addTestDirectory(CORE_TEST_CASES . DS . 'View');
- return $suite;
- }
-}
diff --git a/lib/Cake/Test/Case/BasicsTest.php b/lib/Cake/Test/Case/BasicsTest.php
deleted file mode 100644
index fd2dbba6502..00000000000
--- a/lib/Cake/Test/Case/BasicsTest.php
+++ /dev/null
@@ -1,942 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case
- * @since CakePHP(tm) v 1.2.0.4206
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-require_once CAKE . 'basics.php';
-App::uses('Folder', 'Utility');
-App::uses('CakeResponse', 'Network');
-
-/**
- * BasicsTest class
- *
- * @package Cake.Test.Case
- */
-class BasicsTest extends CakeTestCase {
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- App::build(array(
- 'Locale' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Locale' . DS)
- ));
- $this->_language = Configure::read('Config.language');
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- App::build();
- Configure::write('Config.language', $this->_language);
- }
-
-/**
- * test the array_diff_key compatibility function.
- *
- * @return void
- */
- public function testArrayDiffKey() {
- $one = array('one' => 1, 'two' => 2, 'three' => 3);
- $two = array('one' => 'one', 'two' => 'two');
- $result = array_diff_key($one, $two);
- $expected = array('three' => 3);
- $this->assertEquals($expected, $result);
-
- $one = array('one' => array('value', 'value-two'), 'two' => 2, 'three' => 3);
- $two = array('two' => 'two');
- $result = array_diff_key($one, $two);
- $expected = array('one' => array('value', 'value-two'), 'three' => 3);
- $this->assertEquals($expected, $result);
-
- $one = array('one' => null, 'two' => 2, 'three' => '', 'four' => 0);
- $two = array('two' => 'two');
- $result = array_diff_key($one, $two);
- $expected = array('one' => null, 'three' => '', 'four' => 0);
- $this->assertEquals($expected, $result);
-
- $one = array('minYear' => null, 'maxYear' => null, 'separator' => '-', 'interval' => 1, 'monthNames' => true);
- $two = array('minYear' => null, 'maxYear' => null, 'separator' => '-', 'interval' => 1, 'monthNames' => true);
- $result = array_diff_key($one, $two);
- $this->assertEquals(array(), $result);
- }
-
-/**
- * testHttpBase method
- *
- * @return void
- */
- public function testEnv() {
- $this->skipIf(!function_exists('ini_get') || ini_get('safe_mode') === '1', 'Safe mode is on.');
-
- $server = $_SERVER;
- $env = $_ENV;
-
- $_SERVER['HTTP_HOST'] = 'localhost';
- $this->assertEquals(env('HTTP_BASE'), '.localhost');
-
- $_SERVER['HTTP_HOST'] = 'com.ar';
- $this->assertEquals(env('HTTP_BASE'), '.com.ar');
-
- $_SERVER['HTTP_HOST'] = 'example.ar';
- $this->assertEquals(env('HTTP_BASE'), '.example.ar');
-
- $_SERVER['HTTP_HOST'] = 'example.com';
- $this->assertEquals(env('HTTP_BASE'), '.example.com');
-
- $_SERVER['HTTP_HOST'] = 'www.example.com';
- $this->assertEquals(env('HTTP_BASE'), '.example.com');
-
- $_SERVER['HTTP_HOST'] = 'subdomain.example.com';
- $this->assertEquals(env('HTTP_BASE'), '.example.com');
-
- $_SERVER['HTTP_HOST'] = 'example.com.ar';
- $this->assertEquals(env('HTTP_BASE'), '.example.com.ar');
-
- $_SERVER['HTTP_HOST'] = 'www.example.com.ar';
- $this->assertEquals(env('HTTP_BASE'), '.example.com.ar');
-
- $_SERVER['HTTP_HOST'] = 'subdomain.example.com.ar';
- $this->assertEquals(env('HTTP_BASE'), '.example.com.ar');
-
- $_SERVER['HTTP_HOST'] = 'double.subdomain.example.com';
- $this->assertEquals(env('HTTP_BASE'), '.subdomain.example.com');
-
- $_SERVER['HTTP_HOST'] = 'double.subdomain.example.com.ar';
- $this->assertEquals(env('HTTP_BASE'), '.subdomain.example.com.ar');
-
- $_SERVER = $_ENV = array();
-
- $_SERVER['SCRIPT_NAME'] = '/a/test/test.php';
- $this->assertEquals(env('SCRIPT_NAME'), '/a/test/test.php');
-
- $_SERVER = $_ENV = array();
-
- $_ENV['CGI_MODE'] = 'BINARY';
- $_ENV['SCRIPT_URL'] = '/a/test/test.php';
- $this->assertEquals(env('SCRIPT_NAME'), '/a/test/test.php');
-
- $_SERVER = $_ENV = array();
-
- $this->assertFalse(env('HTTPS'));
-
- $_SERVER['HTTPS'] = 'on';
- $this->assertTrue(env('HTTPS'));
-
- $_SERVER['HTTPS'] = '1';
- $this->assertTrue(env('HTTPS'));
-
- $_SERVER['HTTPS'] = 'I am not empty';
- $this->assertTrue(env('HTTPS'));
-
- $_SERVER['HTTPS'] = 1;
- $this->assertTrue(env('HTTPS'));
-
- $_SERVER['HTTPS'] = 'off';
- $this->assertFalse(env('HTTPS'));
-
- $_SERVER['HTTPS'] = false;
- $this->assertFalse(env('HTTPS'));
-
- $_SERVER['HTTPS'] = '';
- $this->assertFalse(env('HTTPS'));
-
- $_SERVER = array();
-
- $_ENV['SCRIPT_URI'] = 'https://domain.test/a/test.php';
- $this->assertTrue(env('HTTPS'));
-
- $_ENV['SCRIPT_URI'] = 'http://domain.test/a/test.php';
- $this->assertFalse(env('HTTPS'));
-
- $_SERVER = $_ENV = array();
-
- $this->assertNull(env('TEST_ME'));
-
- $_ENV['TEST_ME'] = 'a';
- $this->assertEquals(env('TEST_ME'), 'a');
-
- $_SERVER['TEST_ME'] = 'b';
- $this->assertEquals(env('TEST_ME'), 'b');
-
- unset($_ENV['TEST_ME']);
- $this->assertEquals(env('TEST_ME'), 'b');
-
- $_SERVER = $server;
- $_ENV = $env;
- }
-
-/**
- * Test h()
- *
- * @return void
- */
- public function testH() {
- $string = '';
- $result = h($string);
- $this->assertEquals('<foo>', $result);
-
- $in = array('this & that', 'Which one
');
- $result = h($in);
- $expected = array('this & that', '<p>Which one</p>');
- $this->assertEquals($expected, $result);
-
- $string = ' & ';
- $result = h($string);
- $this->assertEquals('<foo> & ', $result);
-
- $string = ' & ';
- $result = h($string, false);
- $this->assertEquals('<foo> & ', $result);
-
- $string = ' & ';
- $result = h($string, 'UTF-8');
- $this->assertEquals('<foo> & ', $result);
-
- $arr = array('', ' ');
- $result = h($arr);
- $expected = array(
- '<foo>',
- ' '
- );
- $this->assertEquals($expected, $result);
-
- $arr = array('', ' ');
- $result = h($arr, false);
- $expected = array(
- '<foo>',
- ' '
- );
- $this->assertEquals($expected, $result);
-
- $arr = array('f' => '', 'n' => ' ');
- $result = h($arr, false);
- $expected = array(
- 'f' => '<foo>',
- 'n' => ' '
- );
- $this->assertEquals($expected, $result);
-
- $obj = new stdClass();
- $result = h($obj);
- $this->assertEquals('(object)stdClass', $result);
-
- $obj = new CakeResponse(array('body' => 'Body content'));
- $result = h($obj);
- $this->assertEquals('Body content', $result);
- }
-
-/**
- * Test am()
- *
- * @return void
- */
- public function testAm() {
- $result = am(array('one', 'two'), 2, 3, 4);
- $expected = array('one', 'two', 2, 3, 4);
- $this->assertEquals($expected, $result);
-
- $result = am(array('one' => array(2, 3), 'two' => array('foo')), array('one' => array(4, 5)));
- $expected = array('one' => array(4, 5), 'two' => array('foo'));
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test cache()
- *
- * @return void
- */
- public function testCache() {
- $_cacheDisable = Configure::read('Cache.disable');
- $this->skipIf($_cacheDisable, 'Cache is disabled, skipping cache() tests.');
-
- Configure::write('Cache.disable', true);
- $result = cache('basics_test', 'simple cache write');
- $this->assertNull($result);
-
- $result = cache('basics_test');
- $this->assertNull($result);
-
- Configure::write('Cache.disable', false);
- $result = cache('basics_test', 'simple cache write');
- $this->assertTrue((boolean)$result);
- $this->assertTrue(file_exists(CACHE . 'basics_test'));
-
- $result = cache('basics_test');
- $this->assertEquals('simple cache write', $result);
- @unlink(CACHE . 'basics_test');
-
- cache('basics_test', 'expired', '+1 second');
- sleep(2);
- $result = cache('basics_test', null, '+1 second');
- $this->assertNull($result);
-
- Configure::write('Cache.disable', $_cacheDisable);
- }
-
-/**
- * test clearCache()
- *
- * @return void
- */
- public function testClearCache() {
- $cacheOff = Configure::read('Cache.disable');
- $this->skipIf($cacheOff, 'Cache is disabled, skipping clearCache() tests.');
-
- cache('views' . DS . 'basics_test.cache', 'simple cache write');
- $this->assertTrue(file_exists(CACHE . 'views' . DS . 'basics_test.cache'));
-
- cache('views' . DS . 'basics_test_2.cache', 'simple cache write 2');
- $this->assertTrue(file_exists(CACHE . 'views' . DS . 'basics_test_2.cache'));
-
- cache('views' . DS . 'basics_test_3.cache', 'simple cache write 3');
- $this->assertTrue(file_exists(CACHE . 'views' . DS . 'basics_test_3.cache'));
-
- $result = clearCache(array('basics_test', 'basics_test_2'), 'views', '.cache');
- $this->assertTrue($result);
- $this->assertFalse(file_exists(CACHE . 'views' . DS . 'basics_test.cache'));
- $this->assertFalse(file_exists(CACHE . 'views' . DS . 'basics_test.cache'));
- $this->assertTrue(file_exists(CACHE . 'views' . DS . 'basics_test_3.cache'));
-
- $result = clearCache(null, 'views', '.cache');
- $this->assertTrue($result);
- $this->assertFalse(file_exists(CACHE . 'views' . DS . 'basics_test_3.cache'));
-
- // Different path from views and with prefix
- cache('models' . DS . 'basics_test.cache', 'simple cache write');
- $this->assertTrue(file_exists(CACHE . 'models' . DS . 'basics_test.cache'));
-
- cache('models' . DS . 'basics_test_2.cache', 'simple cache write 2');
- $this->assertTrue(file_exists(CACHE . 'models' . DS . 'basics_test_2.cache'));
-
- cache('models' . DS . 'basics_test_3.cache', 'simple cache write 3');
- $this->assertTrue(file_exists(CACHE . 'models' . DS . 'basics_test_3.cache'));
-
- $result = clearCache('basics', 'models', '.cache');
- $this->assertTrue($result);
- $this->assertFalse(file_exists(CACHE . 'models' . DS . 'basics_test.cache'));
- $this->assertFalse(file_exists(CACHE . 'models' . DS . 'basics_test_2.cache'));
- $this->assertFalse(file_exists(CACHE . 'models' . DS . 'basics_test_3.cache'));
-
- // checking if empty files were not removed
- $emptyExists = file_exists(CACHE . 'views' . DS . 'empty');
- if (!$emptyExists) {
- cache('views' . DS . 'empty', '');
- }
- cache('views' . DS . 'basics_test.php', 'simple cache write');
- $this->assertTrue(file_exists(CACHE . 'views' . DS . 'basics_test.php'));
- $this->assertTrue(file_exists(CACHE . 'views' . DS . 'empty'));
-
- $result = clearCache();
- $this->assertTrue($result);
- $this->assertTrue(file_exists(CACHE . 'views' . DS . 'empty'));
- $this->assertFalse(file_exists(CACHE . 'views' . DS . 'basics_test.php'));
- if (!$emptyExists) {
- unlink(CACHE . 'views' . DS . 'empty');
- }
- }
-
-/**
- * test __()
- *
- * @return void
- */
- public function testTranslate() {
- Configure::write('Config.language', 'rule_1_po');
-
- $result = __('Plural Rule 1');
- $expected = 'Plural Rule 1 (translated)';
- $this->assertEquals($expected, $result);
-
- $result = __('Plural Rule 1 (from core)');
- $expected = 'Plural Rule 1 (from core translated)';
- $this->assertEquals($expected, $result);
-
- $result = __('Some string with %s', 'arguments');
- $expected = 'Some string with arguments';
- $this->assertEquals($expected, $result);
-
- $result = __('Some string with %s %s', 'multiple', 'arguments');
- $expected = 'Some string with multiple arguments';
- $this->assertEquals($expected, $result);
-
- $result = __('Some string with %s %s', array('multiple', 'arguments'));
- $expected = 'Some string with multiple arguments';
- $this->assertEquals($expected, $result);
-
- $result = __('Testing %2$s %1$s', 'order', 'different');
- $expected = 'Testing different order';
- $this->assertEquals($expected, $result);
-
- $result = __('Testing %2$s %1$s', array('order', 'different'));
- $expected = 'Testing different order';
- $this->assertEquals($expected, $result);
-
- $result = __('Testing %.2f number', 1.2345);
- $expected = 'Testing 1.23 number';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test __n()
- *
- * @return void
- */
- public function testTranslatePlural() {
- Configure::write('Config.language', 'rule_1_po');
-
- $result = __n('%d = 1', '%d = 0 or > 1', 0);
- $expected = '%d = 0 or > 1 (translated)';
- $this->assertEquals($expected, $result);
-
- $result = __n('%d = 1', '%d = 0 or > 1', 1);
- $expected = '%d = 1 (translated)';
- $this->assertEquals($expected, $result);
-
- $result = __n('%d = 1 (from core)', '%d = 0 or > 1 (from core)', 2);
- $expected = '%d = 0 or > 1 (from core translated)';
- $this->assertEquals($expected, $result);
-
- $result = __n('%d item.', '%d items.', 1, 1);
- $expected = '1 item.';
- $this->assertEquals($expected, $result);
-
- $result = __n('%d item for id %s', '%d items for id %s', 2, 2, '1234');
- $expected = '2 items for id 1234';
- $this->assertEquals($expected, $result);
-
- $result = __n('%d item for id %s', '%d items for id %s', 2, array(2, '1234'));
- $expected = '2 items for id 1234';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test __d()
- *
- * @return void
- */
- public function testTranslateDomain() {
- Configure::write('Config.language', 'rule_1_po');
-
- $result = __d('default', 'Plural Rule 1');
- $expected = 'Plural Rule 1 (translated)';
- $this->assertEquals($expected, $result);
-
- $result = __d('core', 'Plural Rule 1');
- $expected = 'Plural Rule 1';
- $this->assertEquals($expected, $result);
-
- $result = __d('core', 'Plural Rule 1 (from core)');
- $expected = 'Plural Rule 1 (from core translated)';
- $this->assertEquals($expected, $result);
-
- $result = __d('core', 'Some string with %s', 'arguments');
- $expected = 'Some string with arguments';
- $this->assertEquals($expected, $result);
-
- $result = __d('core', 'Some string with %s %s', 'multiple', 'arguments');
- $expected = 'Some string with multiple arguments';
- $this->assertEquals($expected, $result);
-
- $result = __d('core', 'Some string with %s %s', array('multiple', 'arguments'));
- $expected = 'Some string with multiple arguments';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test __dn()
- *
- * @return void
- */
- public function testTranslateDomainPlural() {
- Configure::write('Config.language', 'rule_1_po');
-
- $result = __dn('default', '%d = 1', '%d = 0 or > 1', 0);
- $expected = '%d = 0 or > 1 (translated)';
- $this->assertEquals($expected, $result);
-
- $result = __dn('core', '%d = 1', '%d = 0 or > 1', 0);
- $expected = '%d = 0 or > 1';
- $this->assertEquals($expected, $result);
-
- $result = __dn('core', '%d = 1 (from core)', '%d = 0 or > 1 (from core)', 0);
- $expected = '%d = 0 or > 1 (from core translated)';
- $this->assertEquals($expected, $result);
-
- $result = __dn('default', '%d = 1', '%d = 0 or > 1', 1);
- $expected = '%d = 1 (translated)';
- $this->assertEquals($expected, $result);
-
- $result = __dn('core', '%d item.', '%d items.', 1, 1);
- $expected = '1 item.';
- $this->assertEquals($expected, $result);
-
- $result = __dn('core', '%d item for id %s', '%d items for id %s', 2, 2, '1234');
- $expected = '2 items for id 1234';
- $this->assertEquals($expected, $result);
-
- $result = __dn('core', '%d item for id %s', '%d items for id %s', 2, array(2, '1234'));
- $expected = '2 items for id 1234';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test __c()
- *
- * @return void
- */
- public function testTranslateCategory() {
- Configure::write('Config.language', 'rule_1_po');
-
- $result = __c('Plural Rule 1', 6);
- $expected = 'Plural Rule 1 (translated)';
- $this->assertEquals($expected, $result);
-
- $result = __c('Plural Rule 1 (from core)', 6);
- $expected = 'Plural Rule 1 (from core translated)';
- $this->assertEquals($expected, $result);
-
- $result = __c('Some string with %s', 6, 'arguments');
- $expected = 'Some string with arguments';
- $this->assertEquals($expected, $result);
-
- $result = __c('Some string with %s %s', 6, 'multiple', 'arguments');
- $expected = 'Some string with multiple arguments';
- $this->assertEquals($expected, $result);
-
- $result = __c('Some string with %s %s', 6, array('multiple', 'arguments'));
- $expected = 'Some string with multiple arguments';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test __dc()
- *
- * @return void
- */
- public function testTranslateDomainCategory() {
- Configure::write('Config.language', 'rule_1_po');
-
- $result = __dc('default', 'Plural Rule 1', 6);
- $expected = 'Plural Rule 1 (translated)';
- $this->assertEquals($expected, $result);
-
- $result = __dc('default', 'Plural Rule 1 (from core)', 6);
- $expected = 'Plural Rule 1 (from core translated)';
- $this->assertEquals($expected, $result);
-
- $result = __dc('core', 'Plural Rule 1', 6);
- $expected = 'Plural Rule 1';
- $this->assertEquals($expected, $result);
-
- $result = __dc('core', 'Plural Rule 1 (from core)', 6);
- $expected = 'Plural Rule 1 (from core translated)';
- $this->assertEquals($expected, $result);
-
- $result = __dc('core', 'Some string with %s', 6, 'arguments');
- $expected = 'Some string with arguments';
- $this->assertEquals($expected, $result);
-
- $result = __dc('core', 'Some string with %s %s', 6, 'multiple', 'arguments');
- $expected = 'Some string with multiple arguments';
- $this->assertEquals($expected, $result);
-
- $result = __dc('core', 'Some string with %s %s', 6, array('multiple', 'arguments'));
- $expected = 'Some string with multiple arguments';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test __dcn()
- *
- * @return void
- */
- public function testTranslateDomainCategoryPlural() {
- Configure::write('Config.language', 'rule_1_po');
-
- $result = __dcn('default', '%d = 1', '%d = 0 or > 1', 0, 6);
- $expected = '%d = 0 or > 1 (translated)';
- $this->assertEquals($expected, $result);
-
- $result = __dcn('default', '%d = 1 (from core)', '%d = 0 or > 1 (from core)', 1, 6);
- $expected = '%d = 1 (from core translated)';
- $this->assertEquals($expected, $result);
-
- $result = __dcn('core', '%d = 1', '%d = 0 or > 1', 0, 6);
- $expected = '%d = 0 or > 1';
- $this->assertEquals($expected, $result);
-
- $result = __dcn('core', '%d item.', '%d items.', 1, 6, 1);
- $expected = '1 item.';
- $this->assertEquals($expected, $result);
-
- $result = __dcn('core', '%d item for id %s', '%d items for id %s', 2, 6, 2, '1234');
- $expected = '2 items for id 1234';
- $this->assertEquals($expected, $result);
-
- $result = __dcn('core', '%d item for id %s', '%d items for id %s', 2, 6, array(2, '1234'));
- $expected = '2 items for id 1234';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test LogError()
- *
- * @return void
- */
- public function testLogError() {
- @unlink(LOGS . 'error.log');
-
- LogError('Testing LogError() basic function');
- LogError("Testing with\nmulti-line\nstring");
-
- $result = file_get_contents(LOGS . 'error.log');
- $this->assertRegExp('/Error: Testing LogError\(\) basic function/', $result);
- $this->assertNotRegExp("/Error: Testing with\nmulti-line\nstring/", $result);
- $this->assertRegExp('/Error: Testing with multi-line string/', $result);
- }
-
-/**
- * test fileExistsInPath()
- *
- * @return void
- */
- public function testFileExistsInPath() {
- if (!function_exists('ini_set')) {
- $this->markTestSkipped('%s ini_set function not available');
- }
-
- $_includePath = ini_get('include_path');
-
- $path = TMP . 'basics_test';
- $folder1 = $path . DS . 'folder1';
- $folder2 = $path . DS . 'folder2';
- $file1 = $path . DS . 'file1.php';
- $file2 = $folder1 . DS . 'file2.php';
- $file3 = $folder1 . DS . 'file3.php';
- $file4 = $folder2 . DS . 'file4.php';
-
- new Folder($path, true);
- new Folder($folder1, true);
- new Folder($folder2, true);
- touch($file1);
- touch($file2);
- touch($file3);
- touch($file4);
-
- ini_set('include_path', $path . PATH_SEPARATOR . $folder1);
-
- $this->assertEquals(fileExistsInPath('file1.php'), $file1);
- $this->assertEquals(fileExistsInPath('file2.php'), $file2);
- $this->assertEquals(fileExistsInPath('folder1' . DS . 'file2.php'), $file2);
- $this->assertEquals(fileExistsInPath($file2), $file2);
- $this->assertEquals(fileExistsInPath('file3.php'), $file3);
- $this->assertEquals(fileExistsInPath($file4), $file4);
-
- $this->assertFalse(fileExistsInPath('file1'));
- $this->assertFalse(fileExistsInPath('file4.php'));
-
- $Folder = new Folder($path);
- $Folder->delete();
-
- ini_set('include_path', $_includePath);
- }
-
-/**
- * test convertSlash()
- *
- * @return void
- */
- public function testConvertSlash() {
- $result = convertSlash('\path\to\location\\');
- $expected = '\path\to\location\\';
- $this->assertEquals($expected, $result);
-
- $result = convertSlash('/path/to/location/');
- $expected = 'path_to_location';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test debug()
- *
- * @return void
- */
- public function testDebug() {
- ob_start();
- debug('this-is-a-test', false);
- $result = ob_get_clean();
- $expectedText = <<assertEquals($expected, $result);
-
- ob_start();
- debug('this-is-a-test
', true);
- $result = ob_get_clean();
- $expectedHtml = <<
-%s (line %d )
-
-'<div>this-is-a-test</div>'
-
-
-EXPECTED;
- $expected = sprintf($expectedHtml, substr(__FILE__, strlen(ROOT)), __LINE__ - 10);
- $this->assertEquals($expected, $result);
-
- ob_start();
- debug('this-is-a-test
', true, true);
- $result = ob_get_clean();
- $expected = <<
-%s (line %d )
-
-'<div>this-is-a-test</div>'
-
-
-EXPECTED;
- $expected = sprintf($expected, substr(__FILE__, strlen(ROOT)), __LINE__ - 10);
- $this->assertEquals($expected, $result);
-
- ob_start();
- debug('this-is-a-test
', true, false);
- $result = ob_get_clean();
- $expected = <<
-
-
-'<div>this-is-a-test</div>'
-
-
-EXPECTED;
- $expected = sprintf($expected, substr(__FILE__, strlen(ROOT)), __LINE__ - 10);
- $this->assertEquals($expected, $result);
-
- ob_start();
- debug('this-is-a-test
', null);
- $result = ob_get_clean();
- $expectedHtml = <<
-%s (line %d )
-
-'<div>this-is-a-test</div>'
-
-
-EXPECTED;
- $expectedText = <<this-is-a-test'
-###########################
-EXPECTED;
- if (php_sapi_name() == 'cli') {
- $expected = sprintf($expectedText, substr(__FILE__, strlen(ROOT)), __LINE__ - 17);
- } else {
- $expected = sprintf($expectedHtml, substr(__FILE__, strlen(ROOT)), __LINE__ - 19);
- }
- $this->assertEquals($expected, $result);
-
- ob_start();
- debug('this-is-a-test
', null, false);
- $result = ob_get_clean();
- $expectedHtml = <<
-
-
-'<div>this-is-a-test</div>'
-
-
-EXPECTED;
- $expectedText = <<this-is-a-test'
-###########################
-EXPECTED;
- if (php_sapi_name() == 'cli') {
- $expected = sprintf($expectedText, substr(__FILE__, strlen(ROOT)), __LINE__ - 17);
- } else {
- $expected = sprintf($expectedHtml, substr(__FILE__, strlen(ROOT)), __LINE__ - 19);
- }
- $this->assertEquals($expected, $result);
-
- ob_start();
- debug('this-is-a-test
', false);
- $result = ob_get_clean();
- $expected = <<this-is-a-test'
-###########################
-EXPECTED;
- $expected = sprintf($expected, substr(__FILE__, strlen(ROOT)), __LINE__ - 8);
- $this->assertEquals($expected, $result);
-
- ob_start();
- debug('this-is-a-test
', false, true);
- $result = ob_get_clean();
- $expected = <<this-is-a-test'
-###########################
-EXPECTED;
- $expected = sprintf($expected, substr(__FILE__, strlen(ROOT)), __LINE__ - 8);
- $this->assertEquals($expected, $result);
-
- ob_start();
- debug('this-is-a-test
', false, false);
- $result = ob_get_clean();
- $expected = <<this-is-a-test'
-###########################
-EXPECTED;
- $expected = sprintf($expected, substr(__FILE__, strlen(ROOT)), __LINE__ - 8);
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test pr()
- *
- * @return void
- */
- public function testPr() {
- ob_start();
- pr('this is a test');
- $result = ob_get_clean();
- $expected = "this is a test ";
- $this->assertEquals($expected, $result);
-
- ob_start();
- pr(array('this' => 'is', 'a' => 'test'));
- $result = ob_get_clean();
- $expected = "Array\n(\n [this] => is\n [a] => test\n)\n ";
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test stripslashes_deep()
- *
- * @return void
- */
- public function testStripslashesDeep() {
- $this->skipIf(ini_get('magic_quotes_sybase') === '1', 'magic_quotes_sybase is on.');
-
- $this->assertEquals(stripslashes_deep("tes\'t"), "tes't");
- $this->assertEquals(stripslashes_deep('tes\\' . chr(0) . 't'), 'tes' . chr(0) . 't');
- $this->assertEquals(stripslashes_deep('tes\"t'), 'tes"t');
- $this->assertEquals(stripslashes_deep("tes\'t"), "tes't");
- $this->assertEquals(stripslashes_deep('te\\st'), 'test');
-
- $nested = array(
- 'a' => "tes\'t",
- 'b' => 'tes\\' . chr(0) . 't',
- 'c' => array(
- 'd' => 'tes\"t',
- 'e' => "te\'s\'t",
- array('f' => "tes\'t")
- ),
- 'g' => 'te\\st'
- );
- $expected = array(
- 'a' => "tes't",
- 'b' => 'tes' . chr(0) . 't',
- 'c' => array(
- 'd' => 'tes"t',
- 'e' => "te's't",
- array('f' => "tes't")
- ),
- 'g' => 'test'
- );
- $this->assertEquals($expected, stripslashes_deep($nested));
- }
-
-/**
- * test stripslashes_deep() with magic_quotes_sybase on
- *
- * @return void
- */
- public function testStripslashesDeepSybase() {
- if (!(ini_get('magic_quotes_sybase') === '1')) {
- $this->markTestSkipped('magic_quotes_sybase is off');
- }
-
- $this->assertEquals(stripslashes_deep("tes\'t"), "tes\'t");
-
- $nested = array(
- 'a' => "tes't",
- 'b' => "tes''t",
- 'c' => array(
- 'd' => "tes'''t",
- 'e' => "tes''''t",
- array('f' => "tes''t")
- ),
- 'g' => "te'''''st"
- );
- $expected = array(
- 'a' => "tes't",
- 'b' => "tes't",
- 'c' => array(
- 'd' => "tes''t",
- 'e' => "tes''t",
- array('f' => "tes't")
- ),
- 'g' => "te'''st"
- );
- $this->assertEquals($expected, stripslashes_deep($nested));
- }
-
-/**
- * test pluginSplit
- *
- * @return void
- */
- public function testPluginSplit() {
- $result = pluginSplit('Something.else');
- $this->assertEquals(array('Something', 'else'), $result);
-
- $result = pluginSplit('Something.else.more.dots');
- $this->assertEquals(array('Something', 'else.more.dots'), $result);
-
- $result = pluginSplit('Somethingelse');
- $this->assertEquals(array(null, 'Somethingelse'), $result);
-
- $result = pluginSplit('Something.else', true);
- $this->assertEquals(array('Something.', 'else'), $result);
-
- $result = pluginSplit('Something.else.more.dots', true);
- $this->assertEquals(array('Something.', 'else.more.dots'), $result);
-
- $result = pluginSplit('Post', false, 'Blog');
- $this->assertEquals(array('Blog', 'Post'), $result);
-
- $result = pluginSplit('Blog.Post', false, 'Ultimate');
- $this->assertEquals(array('Blog', 'Post'), $result);
- }
-}
diff --git a/lib/Cake/Test/Case/Cache/CacheTest.php b/lib/Cake/Test/Case/Cache/CacheTest.php
deleted file mode 100644
index a5360a4e2a6..00000000000
--- a/lib/Cake/Test/Case/Cache/CacheTest.php
+++ /dev/null
@@ -1,409 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Cache
- * @since CakePHP(tm) v 1.2.0.5432
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('Cache', 'Cache');
-
-/**
- * CacheTest class
- *
- * @package Cake.Test.Case.Cache
- */
-class CacheTest extends CakeTestCase {
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- $this->_cacheDisable = Configure::read('Cache.disable');
- Configure::write('Cache.disable', false);
-
- $this->_defaultCacheConfig = Cache::config('default');
- Cache::config('default', array('engine' => 'File', 'path' => TMP . 'tests'));
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- Configure::write('Cache.disable', $this->_cacheDisable);
- Cache::config('default', $this->_defaultCacheConfig['settings']);
- }
-
-/**
- * testConfig method
- *
- * @return void
- */
- public function testConfig() {
- $settings = array('engine' => 'File', 'path' => TMP . 'tests', 'prefix' => 'cake_test_');
- $results = Cache::config('new', $settings);
- $this->assertEquals(Cache::config('new'), $results);
- $this->assertTrue(isset($results['engine']));
- $this->assertTrue(isset($results['settings']));
- }
-
-/**
- * Check that no fatal errors are issued doing normal things when Cache.disable is true.
- *
- * @return void
- */
- public function testNonFatalErrorsWithCachedisable() {
- Configure::write('Cache.disable', true);
- Cache::config('test', array('engine' => 'File', 'path' => TMP, 'prefix' => 'error_test_'));
-
- Cache::write('no_save', 'Noooo!', 'test');
- Cache::read('no_save', 'test');
- Cache::delete('no_save', 'test');
- Cache::set('duration', '+10 minutes');
-
- Configure::write('Cache.disable', false);
- }
-
-/**
- * test configuring CacheEngines in App/libs
- *
- * @return void
- */
- public function testConfigWithLibAndPluginEngines() {
- App::build(array(
- 'Lib' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Lib' . DS),
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ), App::RESET);
- CakePlugin::load('TestPlugin');
-
- $settings = array('engine' => 'TestAppCache', 'path' => TMP, 'prefix' => 'cake_test_');
- $result = Cache::config('libEngine', $settings);
- $this->assertEquals(Cache::config('libEngine'), $result);
-
- $settings = array('engine' => 'TestPlugin.TestPluginCache', 'path' => TMP, 'prefix' => 'cake_test_');
- $result = Cache::config('pluginLibEngine', $settings);
- $this->assertEquals(Cache::config('pluginLibEngine'), $result);
-
- Cache::drop('libEngine');
- Cache::drop('pluginLibEngine');
-
- App::build();
- CakePlugin::unload();
- }
-
-/**
- * testInvalidConfig method
- *
- * Test that the cache class doesn't cause fatal errors with a partial path
- *
- * @expectedException PHPUnit_Framework_Error_Warning
- * @return void
- */
- public function testInvalidConfig() {
- Cache::config('invalid', array(
- 'engine' => 'File',
- 'duration' => '+1 year',
- 'prefix' => 'testing_invalid_',
- 'path' => 'data/',
- 'serialize' => true,
- 'random' => 'wii'
- ));
- $read = Cache::read('Test', 'invalid');
- }
-
-/**
- * Test reading from a config that is undefined.
- *
- * @return void
- */
- public function testReadNonExistingConfig() {
- $this->assertFalse(Cache::read('key', 'totally fake'));
- $this->assertFalse(Cache::write('key', 'value', 'totally fake'));
- $this->assertFalse(Cache::increment('key', 1, 'totally fake'));
- $this->assertFalse(Cache::decrement('key', 1, 'totally fake'));
- }
-
-/**
- * test that trying to configure classes that don't extend CacheEngine fail.
- *
- * @expectedException CacheException
- * @return void
- */
- public function testAttemptingToConfigureANonCacheEngineClass() {
- $this->getMock('StdClass', array(), array(), 'RubbishEngine');
- Cache::config('Garbage', array(
- 'engine' => 'Rubbish'
- ));
- }
-
-/**
- * testConfigChange method
- *
- * @return void
- */
- public function testConfigChange() {
- $_cacheConfigSessions = Cache::config('sessions');
- $_cacheConfigTests = Cache::config('tests');
-
- $result = Cache::config('sessions', array('engine' => 'File', 'path' => TMP . 'sessions'));
- $this->assertEquals(Cache::settings('sessions'), $result['settings']);
-
- $result = Cache::config('tests', array('engine' => 'File', 'path' => TMP . 'tests'));
- $this->assertEquals(Cache::settings('tests'), $result['settings']);
-
- Cache::config('sessions', $_cacheConfigSessions['settings']);
- Cache::config('tests', $_cacheConfigTests['settings']);
- }
-
-/**
- * test that calling config() sets the 'default' configuration up.
- *
- * @return void
- */
- public function testConfigSettingDefaultConfigKey() {
- Cache::config('test_name', array('engine' => 'File', 'prefix' => 'test_name_'));
-
- Cache::write('value_one', 'I am cached', 'test_name');
- $result = Cache::read('value_one', 'test_name');
- $this->assertEquals('I am cached', $result);
-
- $result = Cache::read('value_one');
- $this->assertEquals(null, $result);
-
- Cache::write('value_one', 'I am in default config!');
- $result = Cache::read('value_one');
- $this->assertEquals('I am in default config!', $result);
-
- $result = Cache::read('value_one', 'test_name');
- $this->assertEquals('I am cached', $result);
-
- Cache::delete('value_one', 'test_name');
- Cache::delete('value_one', 'default');
- }
-
-/**
- * testWritingWithConfig method
- *
- * @return void
- */
- public function testWritingWithConfig() {
- $_cacheConfigSessions = Cache::config('sessions');
-
- Cache::write('test_something', 'this is the test data', 'tests');
-
- $expected = array(
- 'path' => TMP . 'sessions' . DS,
- 'prefix' => 'cake_',
- 'lock' => true,
- 'serialize' => true,
- 'duration' => 3600,
- 'probability' => 100,
- 'engine' => 'File',
- 'isWindows' => DIRECTORY_SEPARATOR == '\\',
- 'mask' => 0664
- );
- $this->assertEquals($expected, Cache::settings('sessions'));
-
- Cache::config('sessions', $_cacheConfigSessions['settings']);
- }
-
-/**
- * test that configured returns an array of the currently configured cache
- * settings
- *
- * @return void
- */
- public function testConfigured() {
- $result = Cache::configured();
- $this->assertTrue(in_array('_cake_core_', $result));
- $this->assertTrue(in_array('default', $result));
- }
-
-/**
- * testInitSettings method
- *
- * @return void
- */
- public function testInitSettings() {
- $initial = Cache::settings();
- $override = array('engine' => 'File', 'path' => TMP . 'tests');
- Cache::config('for_test', $override);
-
- $settings = Cache::settings();
- $expecting = $override + $initial;
- $this->assertEquals($settings, $expecting);
- }
-
-/**
- * test that drop removes cache configs, and that further attempts to use that config
- * do not work.
- *
- * @return void
- */
- public function testDrop() {
- App::build(array(
- 'Lib' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Lib' . DS),
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ), App::RESET);
-
- $result = Cache::drop('some_config_that_does_not_exist');
- $this->assertFalse($result);
-
- $_testsConfig = Cache::config('tests');
- $result = Cache::drop('tests');
- $this->assertTrue($result);
-
- Cache::config('unconfigTest', array(
- 'engine' => 'TestAppCache'
- ));
- $this->assertTrue(Cache::isInitialized('unconfigTest'));
-
- $this->assertTrue(Cache::drop('unconfigTest'));
- $this->assertFalse(Cache::isInitialized('TestAppCache'));
-
- Cache::config('tests', $_testsConfig);
- App::build();
- }
-
-/**
- * testWriteEmptyValues method
- *
- * @return void
- */
- public function testWriteEmptyValues() {
- Cache::write('App.falseTest', false);
- $this->assertSame(Cache::read('App.falseTest'), false);
-
- Cache::write('App.trueTest', true);
- $this->assertSame(Cache::read('App.trueTest'), true);
-
- Cache::write('App.nullTest', null);
- $this->assertSame(Cache::read('App.nullTest'), null);
-
- Cache::write('App.zeroTest', 0);
- $this->assertSame(Cache::read('App.zeroTest'), 0);
-
- Cache::write('App.zeroTest2', '0');
- $this->assertSame(Cache::read('App.zeroTest2'), '0');
- }
-
-/**
- * Test that failed writes cause errors to be triggered.
- *
- * @return void
- */
- public function testWriteTriggerError() {
- App::build(array(
- 'Lib' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Lib' . DS),
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ), App::RESET);
-
- Cache::config('test_trigger', array('engine' => 'TestAppCache', 'prefix' => ''));
- try {
- Cache::write('fail', 'value', 'test_trigger');
- $this->fail('No exception thrown');
- } catch (PHPUnit_Framework_Error $e) {
- $this->assertTrue(true);
- }
- Cache::drop('test_trigger');
- App::build();
- }
-
-/**
- * testCacheDisable method
- *
- * Check that the "Cache.disable" configuration and a change to it
- * (even after a cache config has been setup) is taken into account.
- *
- * @return void
- */
- public function testCacheDisable() {
- Configure::write('Cache.disable', false);
- Cache::config('test_cache_disable_1', array('engine' => 'File', 'path' => TMP . 'tests'));
-
- $this->assertTrue(Cache::write('key_1', 'hello', 'test_cache_disable_1'));
- $this->assertSame(Cache::read('key_1', 'test_cache_disable_1'), 'hello');
-
- Configure::write('Cache.disable', true);
-
- $this->assertFalse(Cache::write('key_2', 'hello', 'test_cache_disable_1'));
- $this->assertFalse(Cache::read('key_2', 'test_cache_disable_1'));
-
- Configure::write('Cache.disable', false);
-
- $this->assertTrue(Cache::write('key_3', 'hello', 'test_cache_disable_1'));
- $this->assertSame(Cache::read('key_3', 'test_cache_disable_1'), 'hello');
-
- Configure::write('Cache.disable', true);
- Cache::config('test_cache_disable_2', array('engine' => 'File', 'path' => TMP . 'tests'));
-
- $this->assertFalse(Cache::write('key_4', 'hello', 'test_cache_disable_2'));
- $this->assertFalse(Cache::read('key_4', 'test_cache_disable_2'));
-
- Configure::write('Cache.disable', false);
-
- $this->assertTrue(Cache::write('key_5', 'hello', 'test_cache_disable_2'));
- $this->assertSame(Cache::read('key_5', 'test_cache_disable_2'), 'hello');
-
- Configure::write('Cache.disable', true);
-
- $this->assertFalse(Cache::write('key_6', 'hello', 'test_cache_disable_2'));
- $this->assertFalse(Cache::read('key_6', 'test_cache_disable_2'));
- }
-
-/**
- * testSet method
- *
- * @return void
- */
- public function testSet() {
- $_cacheSet = Cache::set();
-
- Cache::set(array('duration' => '+1 year'));
- $data = Cache::read('test_cache');
- $this->assertFalse($data);
-
- $data = 'this is just a simple test of the cache system';
- $write = Cache::write('test_cache', $data);
- $this->assertTrue($write);
-
- Cache::set(array('duration' => '+1 year'));
- $data = Cache::read('test_cache');
- $this->assertEquals('this is just a simple test of the cache system', $data);
-
- Cache::delete('test_cache');
-
- $global = Cache::settings();
-
- Cache::set($_cacheSet);
- }
-
-/**
- * test set() parameter handling for user cache configs.
- *
- * @return void
- */
- public function testSetOnAlternateConfigs() {
- Cache::config('file_config', array('engine' => 'File', 'prefix' => 'test_file_'));
- Cache::set(array('duration' => '+1 year'), 'file_config');
- $settings = Cache::settings('file_config');
-
- $this->assertEquals('test_file_', $settings['prefix']);
- $this->assertEquals(strtotime('+1 year') - time(), $settings['duration']);
- }
-}
diff --git a/lib/Cake/Test/Case/Cache/Engine/ApcEngineTest.php b/lib/Cake/Test/Case/Cache/Engine/ApcEngineTest.php
deleted file mode 100644
index 62ac9b69251..00000000000
--- a/lib/Cake/Test/Case/Cache/Engine/ApcEngineTest.php
+++ /dev/null
@@ -1,201 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Cache.Engine
- * @since CakePHP(tm) v 1.2.0.5434
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('Cache', 'Cache');
-
-/**
- * ApcEngineTest class
- *
- * @package Cake.Test.Case.Cache.Engine
- */
-class ApcEngineTest extends CakeTestCase {
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- $this->skipIf(!function_exists('apc_store'), 'Apc is not installed or configured properly.');
-
- $this->_cacheDisable = Configure::read('Cache.disable');
- Configure::write('Cache.disable', false);
- Cache::config('apc', array('engine' => 'Apc', 'prefix' => 'cake_'));
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- Configure::write('Cache.disable', $this->_cacheDisable);
- Cache::drop('apc');
- Cache::config('default');
- }
-
-/**
- * testReadAndWriteCache method
- *
- * @return void
- */
- public function testReadAndWriteCache() {
- Cache::set(array('duration' => 1), 'apc');
-
- $result = Cache::read('test', 'apc');
- $expecting = '';
- $this->assertEquals($expecting, $result);
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('test', $data, 'apc');
- $this->assertTrue($result);
-
- $result = Cache::read('test', 'apc');
- $expecting = $data;
- $this->assertEquals($expecting, $result);
-
- Cache::delete('test', 'apc');
- }
-
-/**
- * Writing cache entries with duration = 0 (forever) should work.
- *
- * @return void
- */
- public function testReadWriteDurationZero() {
- Cache::config('apc', array('engine' => 'Apc', 'duration' => 0, 'prefix' => 'cake_'));
- Cache::write('zero', 'Should save', 'apc');
- sleep(1);
-
- $result = Cache::read('zero', 'apc');
- $this->assertEquals('Should save', $result);
- }
-
-/**
- * testExpiry method
- *
- * @return void
- */
- public function testExpiry() {
- Cache::set(array('duration' => 1), 'apc');
-
- $result = Cache::read('test', 'apc');
- $this->assertFalse($result);
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('other_test', $data, 'apc');
- $this->assertTrue($result);
-
- sleep(2);
- $result = Cache::read('other_test', 'apc');
- $this->assertFalse($result);
-
- Cache::set(array('duration' => 1), 'apc');
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('other_test', $data, 'apc');
- $this->assertTrue($result);
-
- sleep(2);
- $result = Cache::read('other_test', 'apc');
- $this->assertFalse($result);
-
- sleep(2);
- $result = Cache::read('other_test', 'apc');
- $this->assertFalse($result);
- }
-
-/**
- * testDeleteCache method
- *
- * @return void
- */
- public function testDeleteCache() {
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('delete_test', $data, 'apc');
- $this->assertTrue($result);
-
- $result = Cache::delete('delete_test', 'apc');
- $this->assertTrue($result);
- }
-
-/**
- * testDecrement method
- *
- * @return void
- */
- public function testDecrement() {
- $this->skipIf(!function_exists('apc_dec'), 'No apc_dec() function, cannot test decrement().');
-
- $result = Cache::write('test_decrement', 5, 'apc');
- $this->assertTrue($result);
-
- $result = Cache::decrement('test_decrement', 1, 'apc');
- $this->assertEquals(4, $result);
-
- $result = Cache::read('test_decrement', 'apc');
- $this->assertEquals(4, $result);
-
- $result = Cache::decrement('test_decrement', 2, 'apc');
- $this->assertEquals(2, $result);
-
- $result = Cache::read('test_decrement', 'apc');
- $this->assertEquals(2, $result);
- }
-
-/**
- * testIncrement method
- *
- * @return void
- */
- public function testIncrement() {
- $this->skipIf(!function_exists('apc_inc'), 'No apc_inc() function, cannot test increment().');
-
- $result = Cache::write('test_increment', 5, 'apc');
- $this->assertTrue($result);
-
- $result = Cache::increment('test_increment', 1, 'apc');
- $this->assertEquals(6, $result);
-
- $result = Cache::read('test_increment', 'apc');
- $this->assertEquals(6, $result);
-
- $result = Cache::increment('test_increment', 2, 'apc');
- $this->assertEquals(8, $result);
-
- $result = Cache::read('test_increment', 'apc');
- $this->assertEquals(8, $result);
- }
-
-/**
- * test the clearing of cache keys
- *
- * @return void
- */
- public function testClear() {
- apc_store('not_cake', 'survive');
- Cache::write('some_value', 'value', 'apc');
-
- $result = Cache::clear(false, 'apc');
- $this->assertTrue($result);
- $this->assertFalse(Cache::read('some_value', 'apc'));
- $this->assertEquals('survive', apc_fetch('not_cake'));
- apc_delete('not_cake');
- }
-}
diff --git a/lib/Cake/Test/Case/Cache/Engine/FileEngineTest.php b/lib/Cake/Test/Case/Cache/Engine/FileEngineTest.php
deleted file mode 100644
index b59b3029ae9..00000000000
--- a/lib/Cake/Test/Case/Cache/Engine/FileEngineTest.php
+++ /dev/null
@@ -1,396 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Cache.Engine
- * @since CakePHP(tm) v 1.2.0.5434
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('Cache', 'Cache');
-
-/**
- * FileEngineTest class
- *
- * @package Cake.Test.Case.Cache.Engine
- */
-class FileEngineTest extends CakeTestCase {
-
-/**
- * config property
- *
- * @var array
- */
- public $config = array();
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- Configure::write('Cache.disable', false);
- Cache::config('file_test', array('engine' => 'File', 'path' => CACHE));
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- Cache::clear(false, 'file_test');
- Cache::drop('file_test');
- }
-
-/**
- * testCacheDirChange method
- *
- * @return void
- */
- public function testCacheDirChange() {
- $result = Cache::config('sessions', array('engine' => 'File', 'path' => TMP . 'sessions'));
- $this->assertEquals(Cache::settings('sessions'), $result['settings']);
-
- $result = Cache::config('sessions', array('engine' => 'File', 'path' => TMP . 'tests'));
- $this->assertEquals(Cache::settings('sessions'), $result['settings']);
- $this->assertNotEquals(Cache::settings('default'), $result['settings']);
- }
-
-/**
- * testReadAndWriteCache method
- *
- * @return void
- */
- public function testReadAndWriteCache() {
- Cache::config('default');
-
- $result = Cache::write(null, 'here', 'file_test');
- $this->assertFalse($result);
-
- Cache::set(array('duration' => 1), 'file_test');
-
- $result = Cache::read('test', 'file_test');
- $expecting = '';
- $this->assertEquals($expecting, $result);
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('test', $data, 'file_test');
- $this->assertTrue(file_exists(CACHE . 'cake_test'));
-
- $result = Cache::read('test', 'file_test');
- $expecting = $data;
- $this->assertEquals($expecting, $result);
-
- Cache::delete('test', 'file_test');
- }
-
-/**
- * Test read/write on the same cache key. Ensures file handles are re-wound.
- *
- * @return void
- */
- public function testConsecutiveReadWrite() {
- Cache::write('rw', 'first write', 'file_test');
- $result = Cache::read('rw', 'file_test');
-
- Cache::write('rw', 'second write', 'file_test');
- $result2 = Cache::read('rw', 'file_test');
-
- Cache::delete('rw', 'file_test');
- $this->assertEquals('first write', $result);
- $this->assertEquals('second write', $result2);
- }
-
-/**
- * testExpiry method
- *
- * @return void
- */
- public function testExpiry() {
- Cache::set(array('duration' => 1), 'file_test');
-
- $result = Cache::read('test', 'file_test');
- $this->assertFalse($result);
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('other_test', $data, 'file_test');
- $this->assertTrue($result);
-
- sleep(2);
- $result = Cache::read('other_test', 'file_test');
- $this->assertFalse($result);
-
- Cache::set(array('duration' => "+1 second"), 'file_test');
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('other_test', $data, 'file_test');
- $this->assertTrue($result);
-
- sleep(2);
- $result = Cache::read('other_test', 'file_test');
- $this->assertFalse($result);
- }
-
-/**
- * testDeleteCache method
- *
- * @return void
- */
- public function testDeleteCache() {
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('delete_test', $data, 'file_test');
- $this->assertTrue($result);
-
- $result = Cache::delete('delete_test', 'file_test');
- $this->assertTrue($result);
- $this->assertFalse(file_exists(TMP . 'tests' . DS . 'delete_test'));
-
- $result = Cache::delete('delete_test', 'file_test');
- $this->assertFalse($result);
- }
-
-/**
- * testSerialize method
- *
- * @return void
- */
- public function testSerialize() {
- Cache::config('file_test', array('engine' => 'File', 'serialize' => true));
- $data = 'this is a test of the emergency broadcasting system';
- $write = Cache::write('serialize_test', $data, 'file_test');
- $this->assertTrue($write);
-
- Cache::config('file_test', array('serialize' => false));
- $read = Cache::read('serialize_test', 'file_test');
-
- $newread = Cache::read('serialize_test', 'file_test');
-
- $delete = Cache::delete('serialize_test', 'file_test');
-
- $this->assertSame($read, serialize($data));
-
- $this->assertSame(unserialize($newread), $data);
- }
-
-/**
- * testClear method
- *
- * @return void
- */
- public function testClear() {
- Cache::config('file_test', array('engine' => 'File', 'duration' => 1));
-
- $data = 'this is a test of the emergency broadcasting system';
- $write = Cache::write('serialize_test1', $data, 'file_test');
- $write = Cache::write('serialize_test2', $data, 'file_test');
- $write = Cache::write('serialize_test3', $data, 'file_test');
- $this->assertTrue(file_exists(CACHE . 'cake_serialize_test1'));
- $this->assertTrue(file_exists(CACHE . 'cake_serialize_test2'));
- $this->assertTrue(file_exists(CACHE . 'cake_serialize_test3'));
- sleep(2);
- $result = Cache::clear(true, 'file_test');
- $this->assertTrue($result);
- $this->assertFalse(file_exists(CACHE . 'cake_serialize_test1'));
- $this->assertFalse(file_exists(CACHE . 'cake_serialize_test2'));
- $this->assertFalse(file_exists(CACHE . 'cake_serialize_test3'));
-
- $data = 'this is a test of the emergency broadcasting system';
- $write = Cache::write('serialize_test1', $data, 'file_test');
- $write = Cache::write('serialize_test2', $data, 'file_test');
- $write = Cache::write('serialize_test3', $data, 'file_test');
- $this->assertTrue(file_exists(CACHE . 'cake_serialize_test1'));
- $this->assertTrue(file_exists(CACHE . 'cake_serialize_test2'));
- $this->assertTrue(file_exists(CACHE . 'cake_serialize_test3'));
-
- $result = Cache::clear(false, 'file_test');
- $this->assertTrue($result);
- $this->assertFalse(file_exists(CACHE . 'cake_serialize_test1'));
- $this->assertFalse(file_exists(CACHE . 'cake_serialize_test2'));
- $this->assertFalse(file_exists(CACHE . 'cake_serialize_test3'));
- }
-
-/**
- * test that clear() doesn't wipe files not in the current engine's prefix.
- *
- * @return void
- */
- public function testClearWithPrefixes() {
- $FileOne = new FileEngine();
- $FileOne->init(array(
- 'prefix' => 'prefix_one_',
- 'duration' => DAY
- ));
- $FileTwo = new FileEngine();
- $FileTwo->init(array(
- 'prefix' => 'prefix_two_',
- 'duration' => DAY
- ));
-
- $data1 = $data2 = $expected = 'content to cache';
- $FileOne->write('prefix_one_key_one', $data1, DAY);
- $FileTwo->write('prefix_two_key_two', $data2, DAY);
-
- $this->assertEquals($expected, $FileOne->read('prefix_one_key_one'));
- $this->assertEquals($expected, $FileTwo->read('prefix_two_key_two'));
-
- $FileOne->clear(false);
- $this->assertEquals($expected, $FileTwo->read('prefix_two_key_two'), 'secondary config was cleared by accident.');
- $FileTwo->clear(false);
- }
-
-/**
- * testKeyPath method
- *
- * @return void
- */
- public function testKeyPath() {
- $result = Cache::write('views.countries.something', 'here', 'file_test');
- $this->assertTrue($result);
- $this->assertTrue(file_exists(CACHE . 'cake_views_countries_something'));
-
- $result = Cache::read('views.countries.something', 'file_test');
- $this->assertEquals('here', $result);
-
- $result = Cache::clear(false, 'file_test');
- $this->assertTrue($result);
- }
-
-/**
- * testRemoveWindowsSlashesFromCache method
- *
- * @return void
- */
- public function testRemoveWindowsSlashesFromCache() {
- Cache::config('windows_test', array('engine' => 'File', 'isWindows' => true, 'prefix' => null, 'path' => TMP));
-
- $expected = array(
- 'C:\dev\prj2\sites\cake\libs' => array(
- 0 => 'C:\dev\prj2\sites\cake\libs', 1 => 'C:\dev\prj2\sites\cake\libs\view',
- 2 => 'C:\dev\prj2\sites\cake\libs\view\scaffolds', 3 => 'C:\dev\prj2\sites\cake\libs\view\pages',
- 4 => 'C:\dev\prj2\sites\cake\libs\view\layouts', 5 => 'C:\dev\prj2\sites\cake\libs\view\layouts\xml',
- 6 => 'C:\dev\prj2\sites\cake\libs\view\layouts\rss', 7 => 'C:\dev\prj2\sites\cake\libs\view\layouts\js',
- 8 => 'C:\dev\prj2\sites\cake\libs\view\layouts\email', 9 => 'C:\dev\prj2\sites\cake\libs\view\layouts\email\text',
- 10 => 'C:\dev\prj2\sites\cake\libs\view\layouts\email\html', 11 => 'C:\dev\prj2\sites\cake\libs\view\helpers',
- 12 => 'C:\dev\prj2\sites\cake\libs\view\errors', 13 => 'C:\dev\prj2\sites\cake\libs\view\elements',
- 14 => 'C:\dev\prj2\sites\cake\libs\view\elements\email', 15 => 'C:\dev\prj2\sites\cake\libs\view\elements\email\text',
- 16 => 'C:\dev\prj2\sites\cake\libs\view\elements\email\html', 17 => 'C:\dev\prj2\sites\cake\libs\model',
- 18 => 'C:\dev\prj2\sites\cake\libs\model\datasources', 19 => 'C:\dev\prj2\sites\cake\libs\model\datasources\dbo',
- 20 => 'C:\dev\prj2\sites\cake\libs\model\behaviors', 21 => 'C:\dev\prj2\sites\cake\libs\controller',
- 22 => 'C:\dev\prj2\sites\cake\libs\controller\components', 23 => 'C:\dev\prj2\sites\cake\libs\cache'),
- 'C:\dev\prj2\sites\main_site\vendors' => array(
- 0 => 'C:\dev\prj2\sites\main_site\vendors', 1 => 'C:\dev\prj2\sites\main_site\vendors\shells',
- 2 => 'C:\dev\prj2\sites\main_site\vendors\shells\templates', 3 => 'C:\dev\prj2\sites\main_site\vendors\shells\templates\cdc_project',
- 4 => 'C:\dev\prj2\sites\main_site\vendors\shells\tasks', 5 => 'C:\dev\prj2\sites\main_site\vendors\js',
- 6 => 'C:\dev\prj2\sites\main_site\vendors\css'),
- 'C:\dev\prj2\sites\vendors' => array(
- 0 => 'C:\dev\prj2\sites\vendors', 1 => 'C:\dev\prj2\sites\vendors\simpletest',
- 2 => 'C:\dev\prj2\sites\vendors\simpletest\test', 3 => 'C:\dev\prj2\sites\vendors\simpletest\test\support',
- 4 => 'C:\dev\prj2\sites\vendors\simpletest\test\support\collector', 5 => 'C:\dev\prj2\sites\vendors\simpletest\extensions',
- 6 => 'C:\dev\prj2\sites\vendors\simpletest\extensions\testdox', 7 => 'C:\dev\prj2\sites\vendors\simpletest\docs',
- 8 => 'C:\dev\prj2\sites\vendors\simpletest\docs\fr', 9 => 'C:\dev\prj2\sites\vendors\simpletest\docs\en'),
- 'C:\dev\prj2\sites\main_site\views\helpers' => array(
- 0 => 'C:\dev\prj2\sites\main_site\views\helpers')
- );
-
- Cache::write('test_dir_map', $expected, 'windows_test');
- $data = Cache::read('test_dir_map', 'windows_test');
- Cache::delete('test_dir_map', 'windows_test');
- $this->assertEquals($expected, $data);
-
- Cache::drop('windows_test');
- }
-
-/**
- * testWriteQuotedString method
- *
- * @return void
- */
- public function testWriteQuotedString() {
- Cache::config('file_test', array('engine' => 'File', 'path' => TMP . 'tests'));
- Cache::write('App.doubleQuoteTest', '"this is a quoted string"', 'file_test');
- $this->assertSame(Cache::read('App.doubleQuoteTest', 'file_test'), '"this is a quoted string"');
- Cache::write('App.singleQuoteTest', "'this is a quoted string'", 'file_test');
- $this->assertSame(Cache::read('App.singleQuoteTest', 'file_test'), "'this is a quoted string'");
-
- Cache::config('file_test', array('isWindows' => true, 'path' => TMP . 'tests'));
- $this->assertSame(Cache::read('App.doubleQuoteTest', 'file_test'), '"this is a quoted string"');
- Cache::write('App.singleQuoteTest', "'this is a quoted string'", 'file_test');
- $this->assertSame(Cache::read('App.singleQuoteTest', 'file_test'), "'this is a quoted string'");
- Cache::delete('App.singleQuoteTest', 'file_test');
- Cache::delete('App.doubleQuoteTest', 'file_test');
- }
-
-/**
- * check that FileEngine generates an error when a configured Path does not exist.
- *
- * @expectedException PHPUnit_Framework_Error_Warning
- * @return void
- */
- public function testErrorWhenPathDoesNotExist() {
- $this->skipIf(is_dir(TMP . 'tests' . DS . 'file_failure'), 'Cannot run test directory exists.');
-
- Cache::config('failure', array(
- 'engine' => 'File',
- 'path' => TMP . 'tests' . DS . 'file_failure'
- ));
-
- Cache::drop('failure');
- }
-
-/**
- * Testing the mask setting in FileEngine
- *
- * @return void
- */
- public function testMaskSetting() {
- if (DS === '\\') {
- $this->markTestSkipped('File permission testing does not work on Windows.');
- }
- Cache::config('mask_test', array('engine' => 'File', 'path' => TMP . 'tests'));
- $data = 'This is some test content';
- $write = Cache::write('masking_test', $data, 'mask_test');
- $result = substr(sprintf('%o',fileperms(TMP . 'tests' . DS . 'cake_masking_test')), -4);
- $expected = '0664';
- $this->assertEquals($expected, $result);
- Cache::delete('masking_test', 'mask_test');
- Cache::drop('mask_test');
-
- Cache::config('mask_test', array('engine' => 'File', 'mask' => 0666, 'path' => TMP . 'tests'));
- $write = Cache::write('masking_test', $data, 'mask_test');
- $result = substr(sprintf('%o',fileperms(TMP . 'tests' . DS . 'cake_masking_test')), -4);
- $expected = '0666';
- $this->assertEquals($expected, $result);
- Cache::delete('masking_test', 'mask_test');
- Cache::drop('mask_test');
-
- Cache::config('mask_test', array('engine' => 'File', 'mask' => 0644, 'path' => TMP . 'tests'));
- $write = Cache::write('masking_test', $data, 'mask_test');
- $result = substr(sprintf('%o',fileperms(TMP . 'tests' . DS . 'cake_masking_test')), -4);
- $expected = '0644';
- $this->assertEquals($expected, $result);
- Cache::delete('masking_test', 'mask_test');
- Cache::drop('mask_test');
-
- Cache::config('mask_test', array('engine' => 'File', 'mask' => 0640, 'path' => TMP . 'tests'));
- $write = Cache::write('masking_test', $data, 'mask_test');
- $result = substr(sprintf('%o',fileperms(TMP . 'tests' . DS . 'cake_masking_test')), -4);
- $expected = '0640';
- $this->assertEquals($expected, $result);
- Cache::delete('masking_test', 'mask_test');
- Cache::drop('mask_test');
- }
-
-}
diff --git a/lib/Cake/Test/Case/Cache/Engine/MemcacheEngineTest.php b/lib/Cake/Test/Case/Cache/Engine/MemcacheEngineTest.php
deleted file mode 100644
index c0430bd0446..00000000000
--- a/lib/Cake/Test/Case/Cache/Engine/MemcacheEngineTest.php
+++ /dev/null
@@ -1,403 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Cache.Engine
- * @since CakePHP(tm) v 1.2.0.5434
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('Cache', 'Cache');
-App::uses('MemcacheEngine', 'Cache/Engine');
-
-class TestMemcacheEngine extends MemcacheEngine {
-
-/**
- * public accessor to _parseServerString
- *
- * @param string $server
- * @return array
- */
- public function parseServerString($server) {
- return $this->_parseServerString($server);
- }
-
- public function setMemcache($memcache) {
- $this->_Memcache = $memcache;
- }
-
-}
-
-/**
- * MemcacheEngineTest class
- *
- * @package Cake.Test.Case.Cache.Engine
- */
-class MemcacheEngineTest extends CakeTestCase {
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- $this->skipIf(!class_exists('Memcache'), 'Memcache is not installed or configured properly.');
-
- $this->_cacheDisable = Configure::read('Cache.disable');
- Configure::write('Cache.disable', false);
- Cache::config('memcache', array(
- 'engine' => 'Memcache',
- 'prefix' => 'cake_',
- 'duration' => 3600
- ));
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- Configure::write('Cache.disable', $this->_cacheDisable);
- Cache::drop('memcache');
- Cache::config('default');
- }
-
-/**
- * testSettings method
- *
- * @return void
- */
- public function testSettings() {
- $settings = Cache::settings('memcache');
- unset($settings['serialize'], $settings['path']);
- $expecting = array(
- 'prefix' => 'cake_',
- 'duration' => 3600,
- 'probability' => 100,
- 'servers' => array('127.0.0.1'),
- 'persistent' => true,
- 'compress' => false,
- 'engine' => 'Memcache',
- 'persistent' => true,
- );
- $this->assertEquals($expecting, $settings);
- }
-
-/**
- * testSettings method
- *
- * @return void
- */
- public function testMultipleServers() {
- $servers = array('127.0.0.1:11211', '127.0.0.1:11222');
- $available = true;
- $Memcache = new Memcache();
-
- foreach ($servers as $server) {
- list($host, $port) = explode(':', $server);
- if (!@$Memcache->connect($host, $port)) {
- $available = false;
- }
- }
-
- $this->skipIf(!$available, 'Need memcache servers at ' . implode(', ', $servers) . ' to run this test.');
-
- $Memcache = new MemcacheEngine();
- $Memcache->init(array('engine' => 'Memcache', 'servers' => $servers));
-
- $servers = array_keys($Memcache->__Memcache->getExtendedStats());
- $settings = $Memcache->settings();
- $this->assertEquals($settings['servers'], $servers);
- Cache::drop('dual_server');
- }
-
-/**
- * testConnect method
- *
- * @return void
- */
- public function testConnect() {
- $Memcache = new MemcacheEngine();
- $Memcache->init(Cache::settings('memcache'));
- $result = $Memcache->connect('127.0.0.1');
- $this->assertTrue($result);
- }
-
-/**
- * test connecting to an ipv6 server.
- *
- * @return void
- */
- public function testConnectIpv6() {
- $Memcache = new MemcacheEngine();
- $result = $Memcache->init(array(
- 'prefix' => 'cake_',
- 'duration' => 200,
- 'engine' => 'Memcache',
- 'servers' => array(
- '[::1]:11211'
- )
- ));
- $this->assertTrue($result);
- }
-
-/**
- * test non latin domains.
- *
- * @return void
- */
- public function testParseServerStringNonLatin() {
- $Memcache = new TestMemcacheEngine();
- $result = $Memcache->parseServerString('schülervz.net:13211');
- $this->assertEquals(array('schülervz.net', '13211'), $result);
-
- $result = $Memcache->parseServerString('sülül:1111');
- $this->assertEquals(array('sülül', '1111'), $result);
- }
-
-/**
- * test unix sockets.
- *
- * @return void
- */
- public function testParseServerStringUnix() {
- $Memcache = new TestMemcacheEngine();
- $result = $Memcache->parseServerString('unix:///path/to/memcached.sock');
- $this->assertEquals(array('unix:///path/to/memcached.sock', 0), $result);
- }
-
-/**
- * testReadAndWriteCache method
- *
- * @return void
- */
- public function testReadAndWriteCache() {
- Cache::set(array('duration' => 1), null, 'memcache');
-
- $result = Cache::read('test', 'memcache');
- $expecting = '';
- $this->assertEquals($expecting, $result);
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('test', $data, 'memcache');
- $this->assertTrue($result);
-
- $result = Cache::read('test', 'memcache');
- $expecting = $data;
- $this->assertEquals($expecting, $result);
-
- Cache::delete('test', 'memcache');
- }
-
-/**
- * testExpiry method
- *
- * @return void
- */
- public function testExpiry() {
- Cache::set(array('duration' => 1), 'memcache');
-
- $result = Cache::read('test', 'memcache');
- $this->assertFalse($result);
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('other_test', $data, 'memcache');
- $this->assertTrue($result);
-
- sleep(2);
- $result = Cache::read('other_test', 'memcache');
- $this->assertFalse($result);
-
- Cache::set(array('duration' => "+1 second"), 'memcache');
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('other_test', $data, 'memcache');
- $this->assertTrue($result);
-
- sleep(2);
- $result = Cache::read('other_test', 'memcache');
- $this->assertFalse($result);
-
- Cache::config('memcache', array('duration' => '+1 second'));
- sleep(2);
-
- $result = Cache::read('other_test', 'memcache');
- $this->assertFalse($result);
-
- Cache::config('memcache', array('duration' => '+29 days'));
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('long_expiry_test', $data, 'memcache');
- $this->assertTrue($result);
-
- sleep(2);
- $result = Cache::read('long_expiry_test', 'memcache');
- $expecting = $data;
- $this->assertEquals($expecting, $result);
-
- Cache::config('memcache', array('duration' => 3600));
- }
-
-/**
- * testDeleteCache method
- *
- * @return void
- */
- public function testDeleteCache() {
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('delete_test', $data, 'memcache');
- $this->assertTrue($result);
-
- $result = Cache::delete('delete_test', 'memcache');
- $this->assertTrue($result);
- }
-
-/**
- * testDecrement method
- *
- * @return void
- */
- public function testDecrement() {
- $result = Cache::write('test_decrement', 5, 'memcache');
- $this->assertTrue($result);
-
- $result = Cache::decrement('test_decrement', 1, 'memcache');
- $this->assertEquals(4, $result);
-
- $result = Cache::read('test_decrement', 'memcache');
- $this->assertEquals(4, $result);
-
- $result = Cache::decrement('test_decrement', 2, 'memcache');
- $this->assertEquals(2, $result);
-
- $result = Cache::read('test_decrement', 'memcache');
- $this->assertEquals(2, $result);
- }
-
-/**
- * testIncrement method
- *
- * @return void
- */
- public function testIncrement() {
- $result = Cache::write('test_increment', 5, 'memcache');
- $this->assertTrue($result);
-
- $result = Cache::increment('test_increment', 1, 'memcache');
- $this->assertEquals(6, $result);
-
- $result = Cache::read('test_increment', 'memcache');
- $this->assertEquals(6, $result);
-
- $result = Cache::increment('test_increment', 2, 'memcache');
- $this->assertEquals(8, $result);
-
- $result = Cache::read('test_increment', 'memcache');
- $this->assertEquals(8, $result);
- }
-
-/**
- * test that configurations don't conflict, when a file engine is declared after a memcache one.
- *
- * @return void
- */
- public function testConfigurationConflict() {
- Cache::config('long_memcache', array(
- 'engine' => 'Memcache',
- 'duration' => '+2 seconds',
- 'servers' => array('127.0.0.1:11211'),
- ));
- Cache::config('short_memcache', array(
- 'engine' => 'Memcache',
- 'duration' => '+1 seconds',
- 'servers' => array('127.0.0.1:11211'),
- ));
- Cache::config('some_file', array('engine' => 'File'));
-
- $this->assertTrue(Cache::write('duration_test', 'yay', 'long_memcache'));
- $this->assertTrue(Cache::write('short_duration_test', 'boo', 'short_memcache'));
-
- $this->assertEquals('yay', Cache::read('duration_test', 'long_memcache'), 'Value was not read %s');
- $this->assertEquals('boo', Cache::read('short_duration_test', 'short_memcache'), 'Value was not read %s');
-
- sleep(1);
- $this->assertEquals('yay', Cache::read('duration_test', 'long_memcache'), 'Value was not read %s');
-
- sleep(2);
- $this->assertFalse(Cache::read('short_duration_test', 'short_memcache'), 'Cache was not invalidated %s');
- $this->assertFalse(Cache::read('duration_test', 'long_memcache'), 'Value did not expire %s');
-
- Cache::delete('duration_test', 'long_memcache');
- Cache::delete('short_duration_test', 'short_memcache');
- }
-
-/**
- * test clearing memcache.
- *
- * @return void
- */
- public function testClear() {
- Cache::config('memcache2', array(
- 'engine' => 'Memcache',
- 'prefix' => 'cake2_',
- 'duration' => 3600
- ));
-
- Cache::write('some_value', 'cache1', 'memcache');
- $result = Cache::clear(true, 'memcache');
- $this->assertTrue($result);
- $this->assertEquals('cache1', Cache::read('some_value', 'memcache'));
-
- Cache::write('some_value', 'cache2', 'memcache2');
- $result = Cache::clear(false, 'memcache');
- $this->assertTrue($result);
- $this->assertFalse(Cache::read('some_value', 'memcache'));
- $this->assertEquals('cache2', Cache::read('some_value', 'memcache2'));
-
- Cache::clear(false, 'memcache2');
- }
-
-/**
- * test that a 0 duration can successfully write.
- *
- * @return void
- */
- public function testZeroDuration() {
- Cache::config('memcache', array('duration' => 0));
- $result = Cache::write('test_key', 'written!', 'memcache');
-
- $this->assertTrue('Could not write with duration 0', $result);
- $result = Cache::read('test_key', 'memcache');
- $this->assertEquals('written!', $result);
- }
-
-/**
- * test that durations greater than 30 days never expire
- *
- * @return void
- */
- public function testLongDurationEqualToZero() {
- $memcache = new TestMemcacheEngine();
- $memcache->settings['compress'] = false;
-
- $mock = $this->getMock('Memcache');
- $memcache->setMemcache($mock);
- $mock->expects($this->once())
- ->method('set')
- ->with('key', 'value', false, 0);
-
- $value = 'value';
- $memcache->write('key', $value, 50 * DAY);
- }
-
-}
diff --git a/lib/Cake/Test/Case/Cache/Engine/WincacheEngineTest.php b/lib/Cake/Test/Case/Cache/Engine/WincacheEngineTest.php
deleted file mode 100644
index c4da341fada..00000000000
--- a/lib/Cake/Test/Case/Cache/Engine/WincacheEngineTest.php
+++ /dev/null
@@ -1,191 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Cache.Engine
- * @since CakePHP(tm) v 1.2.0.5434
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('Cache', 'Cache');
-
-/**
- * WincacheEngineTest class
- *
- * @package Cake.Test.Case.Cache.Engine
- */
-class WincacheEngineTest extends CakeTestCase {
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- $this->skipIf(!function_exists('wincache_ucache_set'), 'Wincache is not installed or configured properly.');
- $this->_cacheDisable = Configure::read('Cache.disable');
- Configure::write('Cache.disable', false);
- Cache::config('wincache', array('engine' => 'Wincache', 'prefix' => 'cake_'));
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- Configure::write('Cache.disable', $this->_cacheDisable);
- Cache::drop('wincache');
- Cache::config('default');
- }
-
-/**
- * testReadAndWriteCache method
- *
- * @return void
- */
- public function testReadAndWriteCache() {
- Cache::set(array('duration' => 1), 'wincache');
-
- $result = Cache::read('test', 'wincache');
- $expecting = '';
- $this->assertEquals($expecting, $result);
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('test', $data, 'wincache');
- $this->assertTrue($result);
-
- $result = Cache::read('test', 'wincache');
- $expecting = $data;
- $this->assertEquals($expecting, $result);
-
- Cache::delete('test', 'wincache');
- }
-
-/**
- * testExpiry method
- *
- * @return void
- */
- public function testExpiry() {
- Cache::set(array('duration' => 1), 'wincache');
-
- $result = Cache::read('test', 'wincache');
- $this->assertFalse($result);
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('other_test', $data, 'wincache');
- $this->assertTrue($result);
-
- sleep(2);
- $result = Cache::read('other_test', 'wincache');
- $this->assertFalse($result);
-
- Cache::set(array('duration' => 1), 'wincache');
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('other_test', $data, 'wincache');
- $this->assertTrue($result);
-
- sleep(2);
- $result = Cache::read('other_test', 'wincache');
- $this->assertFalse($result);
-
- sleep(2);
- $result = Cache::read('other_test', 'wincache');
- $this->assertFalse($result);
- }
-
-/**
- * testDeleteCache method
- *
- * @return void
- */
- public function testDeleteCache() {
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('delete_test', $data, 'wincache');
- $this->assertTrue($result);
-
- $result = Cache::delete('delete_test', 'wincache');
- $this->assertTrue($result);
- }
-
-/**
- * testDecrement method
- *
- * @return void
- */
- public function testDecrement() {
- $this->skipIf(
- !function_exists('wincache_ucache_dec'),
- 'No wincache_ucache_dec() function, cannot test decrement().'
- );
-
- $result = Cache::write('test_decrement', 5, 'wincache');
- $this->assertTrue($result);
-
- $result = Cache::decrement('test_decrement', 1, 'wincache');
- $this->assertEquals(4, $result);
-
- $result = Cache::read('test_decrement', 'wincache');
- $this->assertEquals(4, $result);
-
- $result = Cache::decrement('test_decrement', 2, 'wincache');
- $this->assertEquals(2, $result);
-
- $result = Cache::read('test_decrement', 'wincache');
- $this->assertEquals(2, $result);
- }
-
-/**
- * testIncrement method
- *
- * @return void
- */
- public function testIncrement() {
- $this->skipIf(
- !function_exists('wincache_ucache_inc'),
- 'No wincache_inc() function, cannot test increment().'
- );
-
- $result = Cache::write('test_increment', 5, 'wincache');
- $this->assertTrue($result);
-
- $result = Cache::increment('test_increment', 1, 'wincache');
- $this->assertEquals(6, $result);
-
- $result = Cache::read('test_increment', 'wincache');
- $this->assertEquals(6, $result);
-
- $result = Cache::increment('test_increment', 2, 'wincache');
- $this->assertEquals(8, $result);
-
- $result = Cache::read('test_increment', 'wincache');
- $this->assertEquals(8, $result);
- }
-
-/**
- * test the clearing of cache keys
- *
- * @return void
- */
- public function testClear() {
- wincache_ucache_set('not_cake', 'safe');
- Cache::write('some_value', 'value', 'wincache');
-
- $result = Cache::clear(false, 'wincache');
- $this->assertTrue($result);
- $this->assertFalse(Cache::read('some_value', 'wincache'));
- $this->assertEquals('safe', wincache_ucache_get('not_cake'));
- }
-}
diff --git a/lib/Cake/Test/Case/Cache/Engine/XcacheEngineTest.php b/lib/Cake/Test/Case/Cache/Engine/XcacheEngineTest.php
deleted file mode 100644
index 9f6b091412a..00000000000
--- a/lib/Cake/Test/Case/Cache/Engine/XcacheEngineTest.php
+++ /dev/null
@@ -1,199 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Cache.Engine
- * @since CakePHP(tm) v 1.2.0.5434
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('Cache', 'Cache');
-
-/**
- * XcacheEngineTest class
- *
- * @package Cake.Test.Case.Cache.Engine
- */
-class XcacheEngineTest extends CakeTestCase {
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- if (!function_exists('xcache_set')) {
- $this->markTestSkipped('Xcache is not installed or configured properly');
- }
- $this->_cacheDisable = Configure::read('Cache.disable');
- Configure::write('Cache.disable', false);
- Cache::config('xcache', array('engine' => 'Xcache', 'prefix' => 'cake_'));
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- Configure::write('Cache.disable', $this->_cacheDisable);
- Cache::config('default');
- }
-
-/**
- * testSettings method
- *
- * @return void
- */
- public function testSettings() {
- $settings = Cache::settings();
- $expecting = array(
- 'prefix' => 'cake_',
- 'duration' => 3600,
- 'probability' => 100,
- 'engine' => 'Xcache',
- );
- $this->assertTrue(isset($settings['PHP_AUTH_USER']));
- $this->assertTrue(isset($settings['PHP_AUTH_PW']));
-
- unset($settings['PHP_AUTH_USER'], $settings['PHP_AUTH_PW']);
- $this->assertEquals($settings, $expecting);
- }
-
-/**
- * testReadAndWriteCache method
- *
- * @return void
- */
- public function testReadAndWriteCache() {
- Cache::set(array('duration' => 1));
-
- $result = Cache::read('test');
- $expecting = '';
- $this->assertEquals($expecting, $result);
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('test', $data);
- $this->assertTrue($result);
-
- $result = Cache::read('test');
- $expecting = $data;
- $this->assertEquals($expecting, $result);
-
- Cache::delete('test');
- }
-
-/**
- * testExpiry method
- *
- * @return void
- */
- public function testExpiry() {
- Cache::set(array('duration' => 1));
- $result = Cache::read('test');
- $this->assertFalse($result);
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('other_test', $data);
- $this->assertTrue($result);
-
- sleep(2);
- $result = Cache::read('other_test');
- $this->assertFalse($result);
-
- Cache::set(array('duration' => "+1 second"));
-
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('other_test', $data);
- $this->assertTrue($result);
-
- sleep(2);
- $result = Cache::read('other_test');
- $this->assertFalse($result);
- }
-
-/**
- * testDeleteCache method
- *
- * @return void
- */
- public function testDeleteCache() {
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('delete_test', $data);
- $this->assertTrue($result);
-
- $result = Cache::delete('delete_test');
- $this->assertTrue($result);
- }
-
-/**
- * testClearCache method
- *
- * @return void
- */
- public function testClearCache() {
- $data = 'this is a test of the emergency broadcasting system';
- $result = Cache::write('clear_test_1', $data);
- $this->assertTrue($result);
-
- $result = Cache::write('clear_test_2', $data);
- $this->assertTrue($result);
-
- $result = Cache::clear();
- $this->assertTrue($result);
- }
-
-/**
- * testDecrement method
- *
- * @return void
- */
- public function testDecrement() {
- $result = Cache::write('test_decrement', 5);
- $this->assertTrue($result);
-
- $result = Cache::decrement('test_decrement');
- $this->assertEquals(4, $result);
-
- $result = Cache::read('test_decrement');
- $this->assertEquals(4, $result);
-
- $result = Cache::decrement('test_decrement', 2);
- $this->assertEquals(2, $result);
-
- $result = Cache::read('test_decrement');
- $this->assertEquals(2, $result);
- }
-
-/**
- * testIncrement method
- *
- * @return void
- */
- public function testIncrement() {
- $result = Cache::write('test_increment', 5);
- $this->assertTrue($result);
-
- $result = Cache::increment('test_increment');
- $this->assertEquals(6, $result);
-
- $result = Cache::read('test_increment');
- $this->assertEquals(6, $result);
-
- $result = Cache::increment('test_increment', 2);
- $this->assertEquals(8, $result);
-
- $result = Cache::read('test_increment');
- $this->assertEquals(8, $result);
- }
-}
diff --git a/lib/Cake/Test/Case/Configure/IniReaderTest.php b/lib/Cake/Test/Case/Configure/IniReaderTest.php
deleted file mode 100644
index 43ad3ce7244..00000000000
--- a/lib/Cake/Test/Case/Configure/IniReaderTest.php
+++ /dev/null
@@ -1,128 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Configure
- * @since CakePHP(tm) v 2.0
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-App::uses('IniReader', 'Configure');
-
-class IniReaderTest extends CakeTestCase {
-
-/**
- * The test file that will be read.
- *
- * @var string
- */
- public $file;
-
-/**
- * setup
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- $this->path = CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS;
- }
-
-/**
- * test construct
- *
- * @return void
- */
- public function testConstruct() {
- $reader = new IniReader($this->path);
- $config = $reader->read('acl.ini.php');
-
- $this->assertTrue(isset($config['admin']));
- $this->assertTrue(isset($config['paul']['groups']));
- $this->assertEquals('ads', $config['admin']['deny']);
- }
-
-/**
- * no other sections should exist.
- *
- * @return void
- */
- public function testReadingOnlyOneSection() {
- $reader = new IniReader($this->path, 'admin');
- $config = $reader->read('acl.ini.php');
-
- $this->assertTrue(isset($config['groups']));
- $this->assertEquals('administrators', $config['groups']);
- }
-
-/**
- * test without section
- *
- * @return void
- */
- public function testReadingWithoutSection() {
- $reader = new IniReader($this->path);
- $config = $reader->read('no_section.ini');
-
- $expected = array(
- 'some_key' => 'some_value',
- 'bool_key' => true
- );
- $this->assertEquals($expected, $config);
- }
-
-/**
- * test that names with .'s get exploded into arrays.
- *
- * @return void
- */
- public function testReadingValuesWithDots() {
- $reader = new IniReader($this->path);
- $config = $reader->read('nested.ini');
-
- $this->assertTrue(isset($config['database']['db']['username']));
- $this->assertEquals('mark', $config['database']['db']['username']);
- $this->assertEquals(3, $config['nesting']['one']['two']['three']);
- }
-
-/**
- * test boolean reading
- *
- * @return void
- */
- public function testBooleanReading() {
- $reader = new IniReader($this->path);
- $config = $reader->read('nested.ini');
-
- $this->assertTrue($config['bools']['test_on']);
- $this->assertFalse($config['bools']['test_off']);
-
- $this->assertTrue($config['bools']['test_yes']);
- $this->assertFalse($config['bools']['test_no']);
-
- $this->assertTrue($config['bools']['test_true']);
- $this->assertFalse($config['bools']['test_false']);
-
- $this->assertFalse($config['bools']['test_null']);
- }
-
-/**
- * test read file without extension
- *
- * @return void
- */
- public function testReadingWithoutExtension() {
- $reader = new IniReader($this->path);
- $config = $reader->read('nested');
- $this->assertTrue($config['bools']['test_on']);
- }
-}
diff --git a/lib/Cake/Test/Case/Configure/PhpReaderTest.php b/lib/Cake/Test/Case/Configure/PhpReaderTest.php
deleted file mode 100644
index ea34d8b3e38..00000000000
--- a/lib/Cake/Test/Case/Configure/PhpReaderTest.php
+++ /dev/null
@@ -1,99 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Configure
- * @since CakePHP(tm) v 2.0
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-App::uses('PhpReader', 'Configure');
-
-class PhpReaderTest extends CakeTestCase {
-
-/**
- * setup
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- $this->path = CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS;
- }
-
-/**
- * test reading files
- *
- * @return void
- */
- public function testRead() {
- $reader = new PhpReader($this->path);
- $values = $reader->read('var_test');
- $this->assertEquals('value', $values['Read']);
- $this->assertEquals('buried', $values['Deep']['Deeper']['Deepest']);
-
- $values = $reader->read('var_test.php');
- $this->assertEquals('value', $values['Read']);
- }
-
-/**
- * Test an exception is thrown by reading files that don't exist.
- *
- * @expectedException ConfigureException
- * @return void
- */
- public function testReadWithNonExistantFile() {
- $reader = new PhpReader($this->path);
- $reader->read('fake_values');
- }
-
-/**
- * test reading an empty file.
- *
- * @expectedException RuntimeException
- * @return void
- */
- public function testReadEmptyFile() {
- $reader = new PhpReader($this->path);
- $reader->read('empty');
- }
-
-/**
- * test reading keys with ../ doesn't work
- *
- * @expectedException ConfigureException
- * @return void
- */
- public function testReadWithDots() {
- $reader = new PhpReader($this->path);
- $reader->read('../empty');
- }
-
-/**
- * test reading from plugins
- *
- * @return void
- */
- public function testReadPluginValue() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ), App::RESET);
- CakePlugin::load('TestPlugin');
- $reader = new PhpReader($this->path);
- $result = $reader->read('TestPlugin.load');
- $this->assertTrue(isset($result['plugin_load']));
-
- $result = $reader->read('TestPlugin.load.php');
- $this->assertTrue(isset($result['plugin_load']));
- CakePlugin::unload();
- }
-}
diff --git a/lib/Cake/Test/Case/Console/AllConsoleLibsTest.php b/lib/Cake/Test/Case/Console/AllConsoleLibsTest.php
deleted file mode 100644
index 4d13c5df1e0..00000000000
--- a/lib/Cake/Test/Case/Console/AllConsoleLibsTest.php
+++ /dev/null
@@ -1,45 +0,0 @@
-isFile() || strpos($file, 'All') === 0) {
- continue;
- }
- $suite->addTestFile($file->getRealPath());
- }
- return $suite;
- }
-}
\ No newline at end of file
diff --git a/lib/Cake/Test/Case/Console/AllConsoleTest.php b/lib/Cake/Test/Case/Console/AllConsoleTest.php
deleted file mode 100644
index e2844798d3b..00000000000
--- a/lib/Cake/Test/Case/Console/AllConsoleTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-addTestFile($path . 'AllConsoleLibsTest.php');
- $suite->addTestFile($path . 'AllTasksTest.php');
- $suite->addTestFile($path . 'AllShellsTest.php');
- return $suite;
- }
-}
diff --git a/lib/Cake/Test/Case/Console/AllShellsTest.php b/lib/Cake/Test/Case/Console/AllShellsTest.php
deleted file mode 100644
index 8842d61f5f9..00000000000
--- a/lib/Cake/Test/Case/Console/AllShellsTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-addTestDirectory($path);
- return $suite;
- }
-}
\ No newline at end of file
diff --git a/lib/Cake/Test/Case/Console/AllTasksTest.php b/lib/Cake/Test/Case/Console/AllTasksTest.php
deleted file mode 100644
index dcdce737b58..00000000000
--- a/lib/Cake/Test/Case/Console/AllTasksTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-addTestDirectory($path);
- return $suite;
- }
-}
-
diff --git a/lib/Cake/Test/Case/Console/Command/AclShellTest.php b/lib/Cake/Test/Case/Console/Command/AclShellTest.php
deleted file mode 100644
index 44361d86a24..00000000000
--- a/lib/Cake/Test/Case/Console/Command/AclShellTest.php
+++ /dev/null
@@ -1,309 +0,0 @@
-getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Task = $this->getMock(
- 'AclShell',
- array('in', 'out', 'hr', 'createFile', 'error', 'err', 'clear', 'dispatchShell'),
- array($out, $out, $in)
- );
- $collection = new ComponentCollection();
- $this->Task->Acl = new AclComponent($collection);
- $this->Task->params['datasource'] = 'test';
- }
-
-/**
- * test that model.foreign_key output works when looking at acl rows
- *
- * @return void
- */
- public function testViewWithModelForeignKeyOutput() {
- $this->Task->command = 'view';
- $this->Task->startup();
- $data = array(
- 'parent_id' => null,
- 'model' => 'MyModel',
- 'foreign_key' => 2,
- );
- $this->Task->Acl->Aro->create($data);
- $this->Task->Acl->Aro->save();
- $this->Task->args[0] = 'aro';
-
- $this->Task->expects($this->at(0))->method('out')->with('Aro tree:');
- $this->Task->expects($this->at(2))->method('out')
- ->with($this->stringContains('[1] ROOT'));
-
- $this->Task->expects($this->at(4))->method('out')
- ->with($this->stringContains('[3] Gandalf'));
-
- $this->Task->expects($this->at(6))->method('out')
- ->with($this->stringContains('[5] MyModel.2'));
-
- $this->Task->view();
- }
-
-/**
- * test view with an argument
- *
- * @return void
- */
- public function testViewWithArgument() {
- $this->Task->args = array('aro', 'admins');
-
- $this->Task->expects($this->at(0))->method('out')->with('Aro tree:');
- $this->Task->expects($this->at(2))->method('out')->with(' [2] admins');
- $this->Task->expects($this->at(3))->method('out')->with(' [3] Gandalf');
- $this->Task->expects($this->at(4))->method('out')->with(' [4] Elrond');
-
- $this->Task->view();
- }
-
-/**
- * test the method that splits model.foreign key. and that it returns an array.
- *
- * @return void
- */
- public function testParsingModelAndForeignKey() {
- $result = $this->Task->parseIdentifier('Model.foreignKey');
- $expected = array('model' => 'Model', 'foreign_key' => 'foreignKey');
-
- $result = $this->Task->parseIdentifier('mySuperUser');
- $this->assertEquals('mySuperUser', $result);
-
- $result = $this->Task->parseIdentifier('111234');
- $this->assertEquals('111234', $result);
- }
-
-/**
- * test creating aro/aco nodes
- *
- * @return void
- */
- public function testCreate() {
- $this->Task->args = array('aro', 'root', 'User.1');
- $this->Task->expects($this->at(0))->method('out')->with("New Aro 'User.1' created.", 2);
- $this->Task->expects($this->at(1))->method('out')->with("New Aro 'User.3' created.", 2);
- $this->Task->expects($this->at(2))->method('out')->with("New Aro 'somealias' created.", 2);
-
- $this->Task->create();
-
- $Aro = ClassRegistry::init('Aro');
- $Aro->cacheQueries = false;
- $result = $Aro->read();
- $this->assertEquals('User', $result['Aro']['model']);
- $this->assertEquals(1, $result['Aro']['foreign_key']);
- $this->assertEquals(null, $result['Aro']['parent_id']);
- $id = $result['Aro']['id'];
-
- $this->Task->args = array('aro', 'User.1', 'User.3');
- $this->Task->create();
-
- $Aro = ClassRegistry::init('Aro');
- $result = $Aro->read();
- $this->assertEquals('User', $result['Aro']['model']);
- $this->assertEquals(3, $result['Aro']['foreign_key']);
- $this->assertEquals($id, $result['Aro']['parent_id']);
-
- $this->Task->args = array('aro', 'root', 'somealias');
- $this->Task->create();
-
- $Aro = ClassRegistry::init('Aro');
- $result = $Aro->read();
- $this->assertEquals('somealias', $result['Aro']['alias']);
- $this->assertEquals(null, $result['Aro']['model']);
- $this->assertEquals(null, $result['Aro']['foreign_key']);
- $this->assertEquals(null, $result['Aro']['parent_id']);
- }
-
-/**
- * test the delete method with different node types.
- *
- * @return void
- */
- public function testDelete() {
- $this->Task->args = array('aro', 'AuthUser.1');
- $this->Task->expects($this->at(0))->method('out')
- ->with("Aro deleted. ", 2);
- $this->Task->delete();
-
- $Aro = ClassRegistry::init('Aro');
- $result = $Aro->findById(3);
- $this->assertFalse($result);
- }
-
-/**
- * test setParent method.
- *
- * @return void
- */
- public function testSetParent() {
- $this->Task->args = array('aro', 'AuthUser.2', 'root');
- $this->Task->setParent();
-
- $Aro = ClassRegistry::init('Aro');
- $result = $Aro->read(null, 4);
- $this->assertEquals(null, $result['Aro']['parent_id']);
- }
-
-/**
- * test grant
- *
- * @return void
- */
- public function testGrant() {
- $this->Task->args = array('AuthUser.2', 'ROOT/Controller1', 'create');
- $this->Task->expects($this->at(0))->method('out')
- ->with($this->matchesRegularExpression('/granted/'), true);
- $this->Task->grant();
- $node = $this->Task->Acl->Aro->node(array('model' => 'AuthUser', 'foreign_key' => 2));
- $node = $this->Task->Acl->Aro->read(null, $node[0]['Aro']['id']);
-
- $this->assertFalse(empty($node['Aco'][0]));
- $this->assertEquals(1, $node['Aco'][0]['Permission']['_create']);
- }
-
-/**
- * test deny
- *
- * @return void
- */
- public function testDeny() {
- $this->Task->args = array('AuthUser.2', 'ROOT/Controller1', 'create');
- $this->Task->expects($this->at(0))->method('out')
- ->with($this->stringContains('Permission denied'), true);
-
- $this->Task->deny();
-
- $node = $this->Task->Acl->Aro->node(array('model' => 'AuthUser', 'foreign_key' => 2));
- $node = $this->Task->Acl->Aro->read(null, $node[0]['Aro']['id']);
- $this->assertFalse(empty($node['Aco'][0]));
- $this->assertEquals(-1, $node['Aco'][0]['Permission']['_create']);
- }
-
-/**
- * test checking allowed and denied perms
- *
- * @return void
- */
- public function testCheck() {
- $this->Task->expects($this->at(0))->method('out')
- ->with($this->matchesRegularExpression('/not allowed/'), true);
- $this->Task->expects($this->at(1))->method('out')
- ->with($this->matchesRegularExpression('/granted/'), true);
- $this->Task->expects($this->at(2))->method('out')
- ->with($this->matchesRegularExpression('/is.*allowed/'), true);
- $this->Task->expects($this->at(3))->method('out')
- ->with($this->matchesRegularExpression('/not.*allowed/'), true);
-
- $this->Task->args = array('AuthUser.2', 'ROOT/Controller1', '*');
- $this->Task->check();
-
- $this->Task->args = array('AuthUser.2', 'ROOT/Controller1', 'create');
- $this->Task->grant();
-
- $this->Task->args = array('AuthUser.2', 'ROOT/Controller1', 'create');
- $this->Task->check();
-
- $this->Task->args = array('AuthUser.2', 'ROOT/Controller1', '*');
- $this->Task->check();
- }
-
-/**
- * test inherit and that it 0's the permission fields.
- *
- * @return void
- */
- public function testInherit() {
- $this->Task->expects($this->at(0))->method('out')
- ->with($this->matchesRegularExpression('/Permission .*granted/'), true);
- $this->Task->expects($this->at(1))->method('out')
- ->with($this->matchesRegularExpression('/Permission .*inherited/'), true);
-
- $this->Task->args = array('AuthUser.2', 'ROOT/Controller1', 'create');
- $this->Task->grant();
-
- $this->Task->args = array('AuthUser.2', 'ROOT/Controller1', 'all');
- $this->Task->inherit();
-
- $node = $this->Task->Acl->Aro->node(array('model' => 'AuthUser', 'foreign_key' => 2));
- $node = $this->Task->Acl->Aro->read(null, $node[0]['Aro']['id']);
- $this->assertFalse(empty($node['Aco'][0]));
- $this->assertEquals(0, $node['Aco'][0]['Permission']['_create']);
- }
-
-/**
- * test getting the path for an aro/aco
- *
- * @return void
- */
- public function testGetPath() {
- $this->Task->args = array('aro', 'AuthUser.2');
- $node = $this->Task->Acl->Aro->node(array('model' => 'AuthUser', 'foreign_key' => 2));
- $first = $node[0]['Aro']['id'];
- $second = $node[1]['Aro']['id'];
- $last = $node[2]['Aro']['id'];
- $this->Task->expects($this->at(2))->method('out')->with('[' . $last . '] ROOT');
- $this->Task->expects($this->at(3))->method('out')->with(' [' . $second . '] admins');
- $this->Task->expects($this->at(4))->method('out')->with(' [' . $first . '] Elrond');
- $this->Task->getPath();
- }
-
-/**
- * test that initdb makes the correct call.
- *
- * @return void
- */
- public function testInitDb() {
- $this->Task->expects($this->once())->method('dispatchShell')
- ->with('schema create DbAcl');
-
- $this->Task->initdb();
- }
-}
diff --git a/lib/Cake/Test/Case/Console/Command/ApiShellTest.php b/lib/Cake/Test/Case/Console/Command/ApiShellTest.php
deleted file mode 100644
index 3908a2a2c12..00000000000
--- a/lib/Cake/Test/Case/Console/Command/ApiShellTest.php
+++ /dev/null
@@ -1,94 +0,0 @@
-getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Shell = $this->getMock(
- 'ApiShell',
- array('in', 'out', 'createFile', 'hr', '_stop'),
- array( $out, $out, $in)
- );
- }
-
-/**
- * Test that method names are detected properly including those with no arguments.
- *
- * @return void
- */
- public function testMethodNameDetection() {
- $this->Shell->expects($this->any())->method('in')->will($this->returnValue('q'));
- $this->Shell->expects($this->at(0))->method('out')->with('Controller');
-
- $expected = array(
- '1. afterFilter()',
- '2. afterScaffoldSave($method)',
- '3. afterScaffoldSaveError($method)',
- '4. beforeFilter()',
- '5. beforeRedirect($url, $status = NULL, $exit = true)',
- '6. beforeRender()',
- '7. beforeScaffold($method)',
- '8. constructClasses()',
- '9. disableCache()',
- '10. flash($message, $url, $pause = 1, $layout = \'flash\')',
- '11. getEventManager()',
- '12. header($status)',
- '13. httpCodes($code = NULL)',
- '14. implementedEvents()',
- '15. invokeAction($request)',
- '16. loadModel($modelClass = NULL, $id = NULL)',
- '17. paginate($object = NULL, $scope = array (), $whitelist = array ())',
- '18. postConditions($data = array (), $op = NULL, $bool = \'AND\', $exclusive = false)',
- '19. redirect($url, $status = NULL, $exit = true)',
- '20. referer($default = NULL, $local = false)',
- '21. render($view = NULL, $layout = NULL)',
- '22. scaffoldError($method)',
- '23. set($one, $two = NULL)',
- '24. setAction($action)',
- '25. setRequest($request)',
- '26. shutdownProcess()',
- '27. startupProcess()',
- '28. validate()',
- '29. validateErrors()'
- );
- $this->Shell->expects($this->at(2))->method('out')->with($expected);
-
- $this->Shell->args = array('controller');
- $this->Shell->paths['controller'] = CAKE . 'Controller' . DS;
- $this->Shell->main();
- }
-}
diff --git a/lib/Cake/Test/Case/Console/Command/BakeShellTest.php b/lib/Cake/Test/Case/Console/Command/BakeShellTest.php
deleted file mode 100644
index fe52adb02e8..00000000000
--- a/lib/Cake/Test/Case/Console/Command/BakeShellTest.php
+++ /dev/null
@@ -1,122 +0,0 @@
-getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Shell = $this->getMock(
- 'BakeShell',
- array('in', 'out', 'hr', 'err', 'createFile', '_stop', '_checkUnitTest'),
- array($out, $out, $in)
- );
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- unset($this->Dispatch, $this->Shell);
- }
-
-/**
- * test bake all
- *
- * @return void
- */
- public function testAllWithModelName() {
- App::uses('User', 'Model');
- $userExists = class_exists('User');
- $this->skipIf($userExists, 'User class exists, cannot test `bake all [param]`.');
-
- $this->Shell->Model = $this->getMock('ModelTask', array(), array(&$this->Dispatcher));
- $this->Shell->Controller = $this->getMock('ControllerTask', array(), array(&$this->Dispatcher));
- $this->Shell->View = $this->getMock('ModelTask', array(), array(&$this->Dispatcher));
- $this->Shell->DbConfig = $this->getMock('DbConfigTask', array(), array(&$this->Dispatcher));
-
- $this->Shell->DbConfig->expects($this->once())
- ->method('getConfig')
- ->will($this->returnValue('test'));
-
- $this->Shell->Model->expects($this->never())
- ->method('getName');
-
- $this->Shell->Model->expects($this->once())
- ->method('bake')
- ->will($this->returnValue(true));
-
- $this->Shell->Controller->expects($this->once())
- ->method('bake')
- ->will($this->returnValue(true));
-
- $this->Shell->View->expects($this->once())
- ->method('execute');
-
- $this->Shell->expects($this->once())->method('_stop');
- $this->Shell->expects($this->at(0))
- ->method('out')
- ->with('Bake All');
-
- $this->Shell->expects($this->at(5))
- ->method('out')
- ->with('Bake All complete ');
-
- $this->Shell->connection = '';
- $this->Shell->params = array();
- $this->Shell->args = array('User');
- $this->Shell->all();
-
- $this->assertEquals('User', $this->Shell->View->args[0]);
- }
-}
diff --git a/lib/Cake/Test/Case/Console/Command/CommandListShellTest.php b/lib/Cake/Test/Case/Console/Command/CommandListShellTest.php
deleted file mode 100644
index f67712b840a..00000000000
--- a/lib/Cake/Test/Case/Console/Command/CommandListShellTest.php
+++ /dev/null
@@ -1,160 +0,0 @@
-output .= $message;
- }
-
-}
-
-class CommandListShellTest extends CakeTestCase {
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- App::build(array(
- 'Plugin' => array(
- CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS
- ),
- 'Console/Command' => array(
- CAKE . 'Test' . DS . 'test_app' . DS . 'Console' . DS . 'Command' . DS
- )
- ), App::RESET);
- CakePlugin::load(array('TestPlugin', 'TestPluginTwo'));
-
- $out = new TestStringOutput();
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Shell = $this->getMock(
- 'CommandListShell',
- array('in', '_stop', 'clear'),
- array($out, $out, $in)
- );
- }
-
-/**
- * tearDown
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- unset($this->Shell);
- CakePlugin::unload();
- }
-
-/**
- * test that main finds core shells.
- *
- * @return void
- */
- public function testMain() {
- $this->Shell->main();
- $output = $this->Shell->stdout->output;
-
- $expected = "/example \[.*TestPlugin, TestPluginTwo.*\]/";
- $this->assertRegExp($expected, $output);
-
- $expected = "/welcome \[.*TestPluginTwo.*\]/";
- $this->assertRegExp($expected, $output);
-
- $expected = "/acl \[.*CORE.*\]/";
- $this->assertRegExp($expected, $output);
-
- $expected = "/api \[.*CORE.*\]/";
- $this->assertRegExp($expected, $output);
-
- $expected = "/bake \[.*CORE.*\]/";
- $this->assertRegExp($expected, $output);
-
- $expected = "/console \[.*CORE.*\]/";
- $this->assertRegExp($expected, $output);
-
- $expected = "/i18n \[.*CORE.*\]/";
- $this->assertRegExp($expected, $output);
-
- $expected = "/schema \[.*CORE.*\]/";
- $this->assertRegExp($expected, $output);
-
- $expected = "/testsuite \[.*CORE.*\]/";
- $this->assertRegExp($expected, $output);
-
- $expected = "/sample \[.*app.*\]/";
- $this->assertRegExp($expected, $output);
- }
-
-/**
- * Test the sort param
- *
- * @return void
- */
- public function testSortPlugin() {
- $this->Shell->params['sort'] = true;
- $this->Shell->main();
-
- $output = $this->Shell->stdout->output;
-
- $expected = "/\[.*App.*\]\\v*[ ]+sample/";
- $this->assertRegExp($expected, $output);
-
- $expected = "/\[.*TestPluginTwo.*\]\\v*[ ]+example, welcome/";
- $this->assertRegExp($expected, $output);
-
- $expected = "/\[.*TestPlugin.*\]\\v*[ ]+example/";
- $this->assertRegExp($expected, $output);
-
- $expected = "/\[.*Core.*\]\\v*[ ]+acl, api, bake, command_list, console, i18n, schema, test, testsuite/";
- $this->assertRegExp($expected, $output);
- }
-
-/**
- * test xml output.
- *
- * @return void
- */
- public function testMainXml() {
- $this->Shell->params['xml'] = true;
- $this->Shell->main();
-
- $output = $this->Shell->stdout->output;
-
- $find = ' ';
- $this->assertContains($find, $output);
-
- $find = ' ';
- $this->assertContains($find, $output);
-
- $find = ' ';
- $this->assertContains($find, $output);
- }
-}
diff --git a/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php b/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php
deleted file mode 100644
index 6abd0cbd7cd..00000000000
--- a/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php
+++ /dev/null
@@ -1,492 +0,0 @@
- array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
- 'post_id' => array('type' => 'integer', 'null' => false, 'default' => 0),
- 'user_id' => array('type' => 'integer', 'null' => false),
- 'title' => array('type' => 'string', 'null' => false, 'length' => 100),
- 'comment' => array('type' => 'text', 'null' => false, 'default' => null),
- 'published' => array('type' => 'string', 'null' => true, 'default' => 'N', 'length' => 1),
- 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
- 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
- );
-
-/**
- * posts property
- *
- * @var array
- */
- public $articles = array(
- 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
- 'user_id' => array('type' => 'integer', 'null' => true, 'default' => ''),
- 'title' => array('type' => 'string', 'null' => false, 'default' => 'Title'),
- 'body' => array('type' => 'text', 'null' => true, 'default' => null),
- 'summary' => array('type' => 'text', 'null' => true),
- 'published' => array('type' => 'string', 'null' => true, 'default' => 'Y', 'length' => 1),
- 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
- 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
- );
-}
-
-/**
- * SchemaShellTest class
- *
- * @package Cake.Test.Case.Console.Command
- */
-class SchemaShellTest extends CakeTestCase {
-
-/**
- * Fixtures
- *
- * @var array
- */
- public $fixtures = array('core.article', 'core.user', 'core.post', 'core.auth_user', 'core.author',
- 'core.comment', 'core.test_plugin_comment'
- );
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
-
- $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Shell = $this->getMock(
- 'SchemaShell',
- array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop'),
- array($out, $out, $in)
- );
- }
-
-/**
- * endTest method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- if (!empty($this->file) && $this->file instanceof File) {
- $this->file->delete();
- unset($this->file);
- }
- }
-
-/**
- * test startup method
- *
- * @return void
- */
- public function testStartup() {
- $this->Shell->startup();
- $this->assertTrue(isset($this->Shell->Schema));
- $this->assertTrue(is_a($this->Shell->Schema, 'CakeSchema'));
- $this->assertEquals(strtolower(APP_DIR), strtolower($this->Shell->Schema->name));
- $this->assertEquals('schema.php', $this->Shell->Schema->file);
-
- $this->Shell->Schema = null;
- $this->Shell->params = array(
- 'name' => 'TestSchema'
- );
- $this->Shell->startup();
- $this->assertEquals('TestSchema', $this->Shell->Schema->name);
- $this->assertEquals('test_schema.php', $this->Shell->Schema->file);
- $this->assertEquals('default', $this->Shell->Schema->connection);
- $this->assertEquals(APP . 'Config' . DS . 'Schema', $this->Shell->Schema->path);
-
- $this->Shell->Schema = null;
- $this->Shell->params = array(
- 'file' => 'other_file.php',
- 'connection' => 'test',
- 'path' => '/test/path'
- );
- $this->Shell->startup();
- $this->assertEquals(strtolower(APP_DIR), strtolower($this->Shell->Schema->name));
- $this->assertEquals('other_file.php', $this->Shell->Schema->file);
- $this->assertEquals('test', $this->Shell->Schema->connection);
- $this->assertEquals('/test/path', $this->Shell->Schema->path);
- }
-
-/**
- * Test View - and that it dumps the schema file to stdout
- *
- * @return void
- */
- public function testView() {
- $this->Shell->startup();
- $this->Shell->Schema->path = APP . 'Config' . DS . 'Schema';
- $this->Shell->params['file'] = 'i18n.php';
- $this->Shell->expects($this->once())->method('_stop');
- $this->Shell->expects($this->once())->method('out');
- $this->Shell->view();
- }
-
-/**
- * test that view() can find plugin schema files.
- *
- * @return void
- */
- public function testViewWithPlugins() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ));
- CakePlugin::load('TestPlugin');
- $this->Shell->args = array('TestPlugin.schema');
- $this->Shell->startup();
- $this->Shell->expects($this->exactly(2))->method('_stop');
- $this->Shell->expects($this->atLeastOnce())->method('out');
- $this->Shell->view();
-
- $this->Shell->args = array();
- $this->Shell->params = array('plugin' => 'TestPlugin');
- $this->Shell->startup();
- $this->Shell->view();
-
- App::build();
- CakePlugin::unload();
- }
-
-/**
- * test dump() with sql file generation
- *
- * @return void
- */
- public function testDumpWithFileWriting() {
- $this->Shell->params = array(
- 'name' => 'i18n',
- 'connection' => 'test',
- 'write' => TMP . 'tests' . DS . 'i18n.sql'
- );
- $this->Shell->expects($this->once())->method('_stop');
- $this->Shell->startup();
- $this->Shell->dump();
-
- $this->file = new File(TMP . 'tests' . DS . 'i18n.sql');
- $contents = $this->file->read();
- $this->assertRegExp('/DROP TABLE/', $contents);
- $this->assertRegExp('/CREATE TABLE.*?i18n/', $contents);
- $this->assertRegExp('/id/', $contents);
- $this->assertRegExp('/model/', $contents);
- $this->assertRegExp('/field/', $contents);
- $this->assertRegExp('/locale/', $contents);
- $this->assertRegExp('/foreign_key/', $contents);
- $this->assertRegExp('/content/', $contents);
- }
-
-/**
- * test that dump() can find and work with plugin schema files.
- *
- * @return void
- */
- public function testDumpFileWritingWithPlugins() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ));
- CakePlugin::load('TestPlugin');
- $this->Shell->args = array('TestPlugin.TestPluginApp');
- $this->Shell->params = array(
- 'connection' => 'test',
- 'write' => TMP . 'tests' . DS . 'dump_test.sql'
- );
- $this->Shell->startup();
- $this->Shell->expects($this->once())->method('_stop');
- $this->Shell->dump();
-
- $this->file = new File(TMP . 'tests' . DS . 'dump_test.sql');
- $contents = $this->file->read();
-
- $this->assertRegExp('/CREATE TABLE.*?test_plugin_acos/', $contents);
- $this->assertRegExp('/id/', $contents);
- $this->assertRegExp('/model/', $contents);
-
- $this->file->delete();
- App::build();
- CakePlugin::unload();
- }
-
-/**
- * test generate with snapshot generation
- *
- * @return void
- */
- public function testGenerateSnapshot() {
- $this->Shell->path = TMP;
- $this->Shell->params['file'] = 'schema.php';
- $this->Shell->params['force'] = false;
- $this->Shell->args = array('snapshot');
- $this->Shell->Schema = $this->getMock('CakeSchema');
- $this->Shell->Schema->expects($this->at(0))->method('read')->will($this->returnValue(array('schema data')));
- $this->Shell->Schema->expects($this->at(0))->method('write')->will($this->returnValue(true));
-
- $this->Shell->Schema->expects($this->at(1))->method('read');
- $this->Shell->Schema->expects($this->at(1))->method('write')->with(array('schema data', 'file' => 'schema_0.php'));
-
- $this->Shell->generate();
- }
-
-/**
- * test generate without a snapshot.
- *
- * @return void
- */
- public function testGenerateNoOverwrite() {
- touch(TMP . 'schema.php');
- $this->Shell->params['file'] = 'schema.php';
- $this->Shell->params['force'] = false;
- $this->Shell->args = array();
-
- $this->Shell->expects($this->once())->method('in')->will($this->returnValue('q'));
- $this->Shell->Schema = $this->getMock('CakeSchema');
- $this->Shell->Schema->path = TMP;
- $this->Shell->Schema->expects($this->never())->method('read');
-
- $result = $this->Shell->generate();
- unlink(TMP . 'schema.php');
- }
-
-/**
- * test generate with overwriting of the schema files.
- *
- * @return void
- */
- public function testGenerateOverwrite() {
- touch(TMP . 'schema.php');
- $this->Shell->params['file'] = 'schema.php';
- $this->Shell->params['force'] = false;
- $this->Shell->args = array();
-
- $this->Shell->expects($this->once())->method('in')->will($this->returnValue('o'));
-
- $this->Shell->expects($this->at(2))->method('out')
- ->with(new PHPUnit_Framework_Constraint_PCREMatch('/Schema file:\s[a-z\.]+\sgenerated/'));
-
- $this->Shell->Schema = $this->getMock('CakeSchema');
- $this->Shell->Schema->path = TMP;
- $this->Shell->Schema->expects($this->once())->method('read')->will($this->returnValue(array('schema data')));
- $this->Shell->Schema->expects($this->once())->method('write')->will($this->returnValue(true));
-
- $this->Shell->Schema->expects($this->once())->method('read');
- $this->Shell->Schema->expects($this->once())->method('write')
- ->with(array('schema data', 'file' => 'schema.php'));
-
- $this->Shell->generate();
- unlink(TMP . 'schema.php');
- }
-
-/**
- * test that generate() can read plugin dirs and generate schema files for the models
- * in a plugin.
- *
- * @return void
- */
- public function testGenerateWithPlugins() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ), App::RESET);
- CakePlugin::load('TestPlugin');
-
- $this->db->cacheSources = false;
- $this->Shell->params = array(
- 'plugin' => 'TestPlugin',
- 'connection' => 'test',
- 'force' => false
- );
- $this->Shell->startup();
- $this->Shell->Schema->path = TMP . 'tests' . DS;
-
- $this->Shell->generate();
- $this->file = new File(TMP . 'tests' . DS . 'schema.php');
- $contents = $this->file->read();
-
- $this->assertRegExp('/class TestPluginSchema/', $contents);
- $this->assertRegExp('/public \$posts/', $contents);
- $this->assertRegExp('/public \$auth_users/', $contents);
- $this->assertRegExp('/public \$authors/', $contents);
- $this->assertRegExp('/public \$test_plugin_comments/', $contents);
- $this->assertNotRegExp('/public \$users/', $contents);
- $this->assertNotRegExp('/public \$articles/', $contents);
- CakePlugin::unload();
- }
-
-/**
- * Test schema run create with no table args.
- *
- * @return void
- */
- public function testCreateNoArgs() {
- $this->Shell->params = array(
- 'connection' => 'test'
- );
- $this->Shell->args = array('i18n');
- $this->Shell->startup();
- $this->Shell->expects($this->any())->method('in')->will($this->returnValue('y'));
- $this->Shell->create();
-
- $db = ConnectionManager::getDataSource('test');
-
- $db->cacheSources = false;
- $sources = $db->listSources();
- $this->assertTrue(in_array($db->config['prefix'] . 'i18n', $sources));
-
- $schema = new i18nSchema();
- $db->execute($db->dropSchema($schema));
- }
-
-/**
- * Test schema run create with no table args.
- *
- * @return void
- */
- public function testCreateWithTableArgs() {
- $db = ConnectionManager::getDataSource('test');
- $sources = $db->listSources();
- if (in_array('acos', $sources)) {
- $this->markTestSkipped('acos table already exists, cannot try to create it again.');
- }
- $this->Shell->params = array(
- 'connection' => 'test',
- 'name' => 'DbAcl',
- 'path' => APP . 'Config' . DS . 'Schema'
- );
- $this->Shell->args = array('DbAcl', 'acos');
- $this->Shell->startup();
- $this->Shell->expects($this->any())->method('in')->will($this->returnValue('y'));
- $this->Shell->create();
-
- $db = ConnectionManager::getDataSource('test');
- $db->cacheSources = false;
- $sources = $db->listSources();
- $this->assertTrue(in_array($db->config['prefix'] . 'acos', $sources), 'acos should be present.');
- $this->assertFalse(in_array($db->config['prefix'] . 'aros', $sources), 'aros should not be found.');
- $this->assertFalse(in_array('aros_acos', $sources), 'aros_acos should not be found.');
-
- $schema = new DbAclSchema();
- $db->execute($db->dropSchema($schema, 'acos'));
- }
-
-/**
- * test run update with a table arg.
- *
- * @return void
- */
- public function testUpdateWithTable() {
- $this->Shell = $this->getMock(
- 'SchemaShell',
- array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_run'),
- array(&$this->Dispatcher)
- );
-
- $this->Shell->params = array(
- 'connection' => 'test',
- 'force' => true
- );
- $this->Shell->args = array('SchemaShellTest', 'articles');
- $this->Shell->startup();
- $this->Shell->expects($this->any())->method('in')->will($this->returnValue('y'));
- $this->Shell->expects($this->once())->method('_run')
- ->with($this->arrayHasKey('articles'), 'update', $this->isInstanceOf('CakeSchema'));
-
- $this->Shell->update();
- }
-
-/**
- * test that the plugin param creates the correct path in the schema object.
- *
- * @return void
- */
- public function testPluginParam() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ));
- CakePlugin::load('TestPlugin');
- $this->Shell->params = array(
- 'plugin' => 'TestPlugin',
- 'connection' => 'test'
- );
- $this->Shell->startup();
- $expected = CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS . 'TestPlugin' . DS . 'Config' . DS . 'Schema';
- $this->assertEquals($expected, $this->Shell->Schema->path);
- CakePlugin::unload();
- }
-
-/**
- * test that using Plugin.name with write.
- *
- * @return void
- */
- public function testPluginDotSyntaxWithCreate() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ));
- CakePlugin::load('TestPlugin');
- $this->Shell->params = array(
- 'connection' => 'test'
- );
- $this->Shell->args = array('TestPlugin.TestPluginApp');
- $this->Shell->startup();
- $this->Shell->expects($this->any())->method('in')->will($this->returnValue('y'));
- $this->Shell->create();
-
- $db = ConnectionManager::getDataSource('test');
- $sources = $db->listSources();
- $this->assertTrue(in_array($db->config['prefix'] . 'test_plugin_acos', $sources));
-
- $schema = new TestPluginAppSchema();
- $db->execute($db->dropSchema($schema, 'test_plugin_acos'));
- CakePlugin::unload();
- }
-}
diff --git a/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php
deleted file mode 100644
index 6c4b4b1e73d..00000000000
--- a/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php
+++ /dev/null
@@ -1,650 +0,0 @@
-getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Task = $this->getMock('ControllerTask',
- array('in', 'out', 'err', 'hr', 'createFile', '_stop', '_checkUnitTest'),
- array($out, $out, $in)
- );
- $this->Task->name = 'Controller';
- $this->Task->Template = new TemplateTask($out, $out, $in);
- $this->Task->Template->params['theme'] = 'default';
-
- $this->Task->Model = $this->getMock('ModelTask',
- array('in', 'out', 'err', 'createFile', '_stop', '_checkUnitTest'),
- array($out, $out, $in)
- );
- $this->Task->Project = $this->getMock('ProjectTask',
- array('in', 'out', 'err', 'createFile', '_stop', '_checkUnitTest', 'getPrefix'),
- array($out, $out, $in)
- );
- $this->Task->Test = $this->getMock('TestTask', array(), array($out, $out, $in));
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- unset($this->Task);
- ClassRegistry::flush();
- App::build();
- parent::tearDown();
- }
-
-/**
- * test ListAll
- *
- * @return void
- */
- public function testListAll() {
- $count = count($this->Task->listAll('test'));
- if ($count != count($this->fixtures)) {
- $this->markTestSkipped('Additional tables detected.');
- }
-
- $this->Task->connection = 'test';
- $this->Task->interactive = true;
- $this->Task->expects($this->at(1))->method('out')->with('1. BakeArticles');
- $this->Task->expects($this->at(2))->method('out')->with('2. BakeArticlesBakeTags');
- $this->Task->expects($this->at(3))->method('out')->with('3. BakeComments');
- $this->Task->expects($this->at(4))->method('out')->with('4. BakeTags');
-
- $expected = array('BakeArticles', 'BakeArticlesBakeTags', 'BakeComments', 'BakeTags');
- $result = $this->Task->listAll('test');
- $this->assertEquals($expected, $result);
-
- $this->Task->interactive = false;
- $result = $this->Task->listAll();
-
- $expected = array('bake_articles', 'bake_articles_bake_tags', 'bake_comments', 'bake_tags');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * Test that getName interacts with the user and returns the controller name.
- *
- * @return void
- */
- public function testGetNameValidIndex() {
- $count = count($this->Task->listAll('test'));
- if ($count != count($this->fixtures)) {
- $this->markTestSkipped('Additional tables detected.');
- }
- $this->Task->interactive = true;
- $this->Task->expects($this->any())->method('in')->will(
- $this->onConsecutiveCalls(3, 1)
- );
-
- $result = $this->Task->getName('test');
- $expected = 'BakeComments';
- $this->assertEquals($expected, $result);
-
- $result = $this->Task->getName('test');
- $expected = 'BakeArticles';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test getting invalid indexes.
- *
- * @return void
- */
- public function testGetNameInvalidIndex() {
- $this->Task->interactive = true;
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls(50, 'q'));
-
- $this->Task->expects($this->once())->method('err');
- $this->Task->expects($this->once())->method('_stop');
-
- $this->Task->getName('test');
- }
-
-/**
- * test helper interactions
- *
- * @return void
- */
- public function testDoHelpersNo() {
- $this->Task->expects($this->any())->method('in')->will($this->returnValue('n'));
- $result = $this->Task->doHelpers();
- $this->assertEquals(array(), $result);
- }
-
-/**
- * test getting helper values
- *
- * @return void
- */
- public function testDoHelpersTrailingSpace() {
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y'));
- $this->Task->expects($this->at(1))->method('in')->will($this->returnValue(' Javascript, Ajax, CustomOne '));
- $result = $this->Task->doHelpers();
- $expected = array('Javascript', 'Ajax', 'CustomOne');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test doHelpers with extra commas
- *
- * @return void
- */
- public function testDoHelpersTrailingCommas() {
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y'));
- $this->Task->expects($this->at(1))->method('in')->will($this->returnValue(' Javascript, Ajax, CustomOne, , '));
- $result = $this->Task->doHelpers();
- $expected = array('Javascript', 'Ajax', 'CustomOne');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test component interactions
- *
- * @return void
- */
- public function testDoComponentsNo() {
- $this->Task->expects($this->any())->method('in')->will($this->returnValue('n'));
- $result = $this->Task->doComponents();
- $this->assertEquals(array(), $result);
- }
-
-/**
- * test components with spaces
- *
- * @return void
- */
- public function testDoComponentsTrailingSpaces() {
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y'));
- $this->Task->expects($this->at(1))->method('in')->will($this->returnValue(' RequestHandler, Security '));
-
- $result = $this->Task->doComponents();
- $expected = array('RequestHandler', 'Security');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test components with commas
- *
- * @return void
- */
- public function testDoComponentsTrailingCommas() {
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y'));
- $this->Task->expects($this->at(1))->method('in')->will($this->returnValue(' RequestHandler, Security, , '));
-
- $result = $this->Task->doComponents();
- $expected = array('RequestHandler', 'Security');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test Confirming controller user interaction
- *
- * @return void
- */
- public function testConfirmController() {
- $controller = 'Posts';
- $scaffold = false;
- $helpers = array('Ajax', 'Time');
- $components = array('Acl', 'Auth');
-
- $this->Task->expects($this->at(4))->method('out')->with("Controller Name:\n\t$controller");
- $this->Task->expects($this->at(5))->method('out')->with("Helpers:\n\tAjax, Time");
- $this->Task->expects($this->at(6))->method('out')->with("Components:\n\tAcl, Auth");
- $this->Task->confirmController($controller, $scaffold, $helpers, $components);
- }
-
-/**
- * test the bake method
- *
- * @return void
- */
- public function testBake() {
- $helpers = array('Ajax', 'Time');
- $components = array('Acl', 'Auth');
- $this->Task->expects($this->any())->method('createFile')->will($this->returnValue(true));
-
- $result = $this->Task->bake('Articles', '--actions--', $helpers, $components);
- $this->assertContains(' * @property Article $Article', $result);
- $this->assertContains(' * @property AclComponent $Acl', $result);
- $this->assertContains(' * @property AuthComponent $Auth', $result);
- $this->assertContains('class ArticlesController extends AppController', $result);
- $this->assertContains("public \$components = array('Acl', 'Auth')", $result);
- $this->assertContains("public \$helpers = array('Ajax', 'Time')", $result);
- $this->assertContains("--actions--", $result);
-
- $result = $this->Task->bake('Articles', 'scaffold', $helpers, $components);
- $this->assertContains("class ArticlesController extends AppController", $result);
- $this->assertContains("public \$scaffold", $result);
- $this->assertNotContains('@property', $result);
- $this->assertNotContains('helpers', $result);
- $this->assertNotContains('components', $result);
-
- $result = $this->Task->bake('Articles', '--actions--', array(), array());
- $this->assertContains('class ArticlesController extends AppController', $result);
- $this->assertSame(substr_count($result, '@property'), 1);
- $this->assertNotContains('components', $result);
- $this->assertNotContains('helpers', $result);
- $this->assertContains('--actions--', $result);
- }
-
-/**
- * test bake() with a -plugin param
- *
- * @return void
- */
- public function testBakeWithPlugin() {
- $this->Task->plugin = 'ControllerTest';
-
- //fake plugin path
- CakePlugin::load('ControllerTest', array('path' => APP . 'Plugin' . DS . 'ControllerTest' . DS));
- $path = APP . 'Plugin' . DS . 'ControllerTest' . DS . 'Controller' . DS . 'ArticlesController.php';
-
- $this->Task->expects($this->at(1))->method('createFile')->with(
- $path,
- new PHPUnit_Framework_Constraint_IsAnything()
- );
- $this->Task->expects($this->at(3))->method('createFile')->with(
- $path,
- $this->stringContains('ArticlesController extends ControllerTestAppController')
- )->will($this->returnValue(true));
-
- $this->Task->bake('Articles', '--actions--', array(), array(), array());
-
- $this->Task->plugin = 'ControllerTest';
- $path = APP . 'Plugin' . DS . 'ControllerTest' . DS . 'Controller' . DS . 'ArticlesController.php';
- $result = $this->Task->bake('Articles', '--actions--', array(), array(), array());
-
- $this->assertContains("App::uses('ControllerTestAppController', 'ControllerTest.Controller');", $result);
- $this->assertEquals('ControllerTest', $this->Task->Template->templateVars['plugin']);
- $this->assertEquals('ControllerTest.', $this->Task->Template->templateVars['pluginPath']);
-
- CakePlugin::unload();
- }
-
-/**
- * test that bakeActions is creating the correct controller Code. (Using sessions)
- *
- * @return void
- */
- public function testBakeActionsUsingSessions() {
- $this->skipIf(!defined('ARTICLE_MODEL_CREATED'), 'Testing bakeActions requires Article, Comment & Tag Model to be undefined.');
-
- $result = $this->Task->bakeActions('BakeArticles', null, true);
-
- $this->assertContains('function index() {', $result);
- $this->assertContains('$this->BakeArticle->recursive = 0;', $result);
- $this->assertContains("\$this->set('bakeArticles', \$this->paginate());", $result);
-
- $this->assertContains('function view($id = null)', $result);
- $this->assertContains("throw new NotFoundException(__('Invalid bake article'));", $result);
- $this->assertContains("\$this->set('bakeArticle', \$this->BakeArticle->read(null, \$id)", $result);
-
- $this->assertContains('function add()', $result);
- $this->assertContains("if (\$this->request->is('post'))", $result);
- $this->assertContains('if ($this->BakeArticle->save($this->request->data))', $result);
- $this->assertContains("\$this->Session->setFlash(__('The bake article has been saved'));", $result);
-
- $this->assertContains('function edit($id = null)', $result);
- $this->assertContains("\$this->Session->setFlash(__('The bake article could not be saved. Please, try again.'));", $result);
-
- $this->assertContains('function delete($id = null)', $result);
- $this->assertContains('if ($this->BakeArticle->delete())', $result);
- $this->assertContains("\$this->Session->setFlash(__('Bake article deleted'));", $result);
-
- $result = $this->Task->bakeActions('BakeArticles', 'admin_', true);
-
- $this->assertContains('function admin_index() {', $result);
- $this->assertContains('function admin_add()', $result);
- $this->assertContains('function admin_view($id = null)', $result);
- $this->assertContains('function admin_edit($id = null)', $result);
- $this->assertContains('function admin_delete($id = null)', $result);
- }
-
-/**
- * Test baking with Controller::flash() or no sessions.
- *
- * @return void
- */
- public function testBakeActionsWithNoSessions() {
- $this->skipIf(!defined('ARTICLE_MODEL_CREATED'), 'Testing bakeActions requires Article, Tag, Comment Models to be undefined.');
-
- $result = $this->Task->bakeActions('BakeArticles', null, false);
-
- $this->assertContains('function index() {', $result);
- $this->assertContains('$this->BakeArticle->recursive = 0;', $result);
- $this->assertContains("\$this->set('bakeArticles', \$this->paginate());", $result);
-
- $this->assertContains('function view($id = null)', $result);
- $this->assertContains("throw new NotFoundException(__('Invalid bake article'));", $result);
- $this->assertContains("\$this->set('bakeArticle', \$this->BakeArticle->read(null, \$id)", $result);
-
- $this->assertContains('function add()', $result);
- $this->assertContains("if (\$this->request->is('post'))", $result);
- $this->assertContains('if ($this->BakeArticle->save($this->request->data))', $result);
-
- $this->assertContains("\$this->flash(__('The bake article has been saved.'), array('action' => 'index'))", $result);
-
- $this->assertContains('function edit($id = null)', $result);
- $this->assertContains("\$this->BakeArticle->BakeTag->find('list')", $result);
- $this->assertContains("\$this->set(compact('bakeTags'))", $result);
-
- $this->assertContains('function delete($id = null)', $result);
- $this->assertContains('if ($this->BakeArticle->delete())', $result);
- $this->assertContains("\$this->flash(__('Bake article deleted'), array('action' => 'index'))", $result);
- }
-
-/**
- * test baking a test
- *
- * @return void
- */
- public function testBakeTest() {
- $this->Task->plugin = 'ControllerTest';
- $this->Task->connection = 'test';
- $this->Task->interactive = false;
-
- $this->Task->Test->expects($this->once())->method('bake')->with('Controller', 'BakeArticles');
- $this->Task->bakeTest('BakeArticles');
-
- $this->assertEquals($this->Task->plugin, $this->Task->Test->plugin);
- $this->assertEquals($this->Task->connection, $this->Task->Test->connection);
- $this->assertEquals($this->Task->interactive, $this->Task->Test->interactive);
- }
-
-/**
- * test Interactive mode.
- *
- * @return void
- */
- public function testInteractive() {
- $count = count($this->Task->listAll('test'));
- if ($count != count($this->fixtures)) {
- $this->markTestSkipped('Additional tables detected.');
- }
-
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
-
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls(
- '1',
- 'y', // build interactive
- 'n', // build no scaffolds
- 'y', // build normal methods
- 'n', // build admin methods
- 'n', // helpers?
- 'n', // components?
- 'y', // sessions ?
- 'y' // looks good?
- ));
-
- $filename = '/my/path/BakeArticlesController.php';
- $this->Task->expects($this->once())->method('createFile')->with(
- $filename,
- $this->stringContains('class BakeArticlesController')
- );
- $this->Task->execute();
- }
-
-/**
- * test Interactive mode.
- *
- * @return void
- */
- public function testInteractiveAdminMethodsNotInteractive() {
- $count = count($this->Task->listAll('test'));
- if ($count != count($this->fixtures)) {
- $this->markTestSkipped('Additional tables detected.');
- }
-
- $this->Task->connection = 'test';
- $this->Task->interactive = true;
- $this->Task->path = '/my/path/';
-
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls(
- '1',
- 'y', // build interactive
- 'n', // build no scaffolds
- 'y', // build normal methods
- 'y', // build admin methods
- 'n', // helpers?
- 'n', // components?
- 'y', // sessions ?
- 'y' // looks good?
- ));
-
- $this->Task->Project->expects($this->any())
- ->method('getPrefix')
- ->will($this->returnValue('admin_'));
-
- $filename = '/my/path/BakeArticlesController.php';
- $this->Task->expects($this->once())->method('createFile')->with(
- $filename,
- $this->stringContains('class BakeArticlesController')
- )->will($this->returnValue(true));
-
- $result = $this->Task->execute();
- $this->assertRegExp('/admin_index/', $result);
- }
-
-/**
- * test that execute runs all when the first arg == all
- *
- * @return void
- */
- public function testExecuteIntoAll() {
- $count = count($this->Task->listAll('test'));
- if ($count != count($this->fixtures)) {
- $this->markTestSkipped('Additional tables detected.');
- }
- if (!defined('ARTICLE_MODEL_CREATED')) {
- $this->markTestSkipped('Execute into all could not be run as an Article, Tag or Comment model was already loaded.');
- }
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('all');
-
- $this->Task->expects($this->any())->method('_checkUnitTest')->will($this->returnValue(true));
- $this->Task->Test->expects($this->once())->method('bake');
-
- $filename = '/my/path/BakeArticlesController.php';
- $this->Task->expects($this->once())->method('createFile')->with(
- $filename,
- $this->stringContains('class BakeArticlesController')
- )->will($this->returnValue(true));
-
- $this->Task->execute();
- }
-
-/**
- * test that `cake bake controller foos` works.
- *
- * @return void
- */
- public function testExecuteWithController() {
- if (!defined('ARTICLE_MODEL_CREATED')) {
- $this->markTestSkipped('Execute with scaffold param requires no Article, Tag or Comment model to be defined');
- }
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('BakeArticles');
-
- $filename = '/my/path/BakeArticlesController.php';
- $this->Task->expects($this->once())->method('createFile')->with(
- $filename,
- $this->stringContains('$scaffold')
- );
-
- $this->Task->execute();
- }
-
-/**
- * data provider for testExecuteWithControllerNameVariations
- *
- * @return void
- */
- public static function nameVariations() {
- return array(
- array('BakeArticles'), array('BakeArticle'), array('bake_article'), array('bake_articles')
- );
- }
-
-/**
- * test that both plural and singular forms work for controller baking.
- *
- * @dataProvider nameVariations
- * @return void
- */
- public function testExecuteWithControllerNameVariations($name) {
- if (!defined('ARTICLE_MODEL_CREATED')) {
- $this->markTestSkipped('Execute with scaffold param requires no Article, Tag or Comment model to be defined.');
- }
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array($name);
-
- $filename = '/my/path/BakeArticlesController.php';
- $this->Task->expects($this->once())->method('createFile')->with(
- $filename, $this->stringContains('$scaffold')
- );
- $this->Task->execute();
- }
-
-/**
- * test that `cake bake controller foo scaffold` works.
- *
- * @return void
- */
- public function testExecuteWithPublicParam() {
- if (!defined('ARTICLE_MODEL_CREATED')) {
- $this->markTestSkipped('Execute with public param requires no Article, Tag or Comment model to be defined.');
- }
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('BakeArticles');
- $this->Task->params = array('public' => true);
-
- $filename = '/my/path/BakeArticlesController.php';
- $expected = new PHPUnit_Framework_Constraint_Not($this->stringContains('$scaffold'));
- $this->Task->expects($this->once())->method('createFile')->with(
- $filename, $expected
- );
- $this->Task->execute();
- }
-
-/**
- * test that `cake bake controller foos both` works.
- *
- * @return void
- */
- public function testExecuteWithControllerAndBoth() {
- if (!defined('ARTICLE_MODEL_CREATED')) {
- $this->markTestSkipped('Execute with controller and both requires no Article, Tag or Comment model to be defined.');
- }
- $this->Task->Project->expects($this->any())->method('getPrefix')->will($this->returnValue('admin_'));
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('BakeArticles');
- $this->Task->params = array('public' => true, 'admin' => true);
-
- $filename = '/my/path/BakeArticlesController.php';
- $this->Task->expects($this->once())->method('createFile')->with(
- $filename, $this->stringContains('admin_index')
- );
- $this->Task->execute();
- }
-
-/**
- * test that `cake bake controller foos admin` works.
- *
- * @return void
- */
- public function testExecuteWithControllerAndAdmin() {
- if (!defined('ARTICLE_MODEL_CREATED')) {
- $this->markTestSkipped('Execute with controller and admin requires no Article, Tag or Comment model to be defined.');
- }
- $this->Task->Project->expects($this->any())->method('getPrefix')->will($this->returnValue('admin_'));
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('BakeArticles');
- $this->Task->params = array('admin' => true);
-
- $filename = '/my/path/BakeArticlesController.php';
- $this->Task->expects($this->once())->method('createFile')->with(
- $filename, $this->stringContains('admin_index')
- );
- $this->Task->execute();
- }
-}
diff --git a/lib/Cake/Test/Case/Console/Command/Task/DbConfigTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/DbConfigTaskTest.php
deleted file mode 100644
index 558dd3c3d4a..00000000000
--- a/lib/Cake/Test/Case/Console/Command/Task/DbConfigTaskTest.php
+++ /dev/null
@@ -1,133 +0,0 @@
-getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Task = $this->getMock('DbConfigTask',
- array('in', 'out', 'err', 'hr', 'createFile', '_stop', '_checkUnitTest', '_verify'),
- array($out, $out, $in)
- );
-
- $this->Task->path = APP . 'Config' . DS;
- }
-
-/**
- * endTest method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- unset($this->Task);
- }
-
-/**
- * Test the getConfig method.
- *
- * @return void
- */
- public function testGetConfig() {
- $this->Task->expects($this->any())
- ->method('in')
- ->will($this->returnValue('test'));
-
- $result = $this->Task->getConfig();
- $this->assertEquals('test', $result);
- }
-
-/**
- * test that initialize sets the path up.
- *
- * @return void
- */
- public function testInitialize() {
- $this->Task->initialize();
- $this->assertFalse(empty($this->Task->path));
- $this->assertEquals(APP . 'Config' . DS, $this->Task->path);
- }
-
-/**
- * test execute and by extension _interactive
- *
- * @return void
- */
- public function testExecuteIntoInteractive() {
- $this->Task->initialize();
-
- $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Task = $this->getMock(
- 'DbConfigTask',
- array('in', '_stop', 'createFile', 'bake'), array($out, $out, $in)
- );
-
- $this->Task->expects($this->once())->method('_stop');
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('default')); //name
- $this->Task->expects($this->at(1))->method('in')->will($this->returnValue('mysql')); //db type
- $this->Task->expects($this->at(2))->method('in')->will($this->returnValue('n')); //persistant
- $this->Task->expects($this->at(3))->method('in')->will($this->returnValue('localhost')); //server
- $this->Task->expects($this->at(4))->method('in')->will($this->returnValue('n')); //port
- $this->Task->expects($this->at(5))->method('in')->will($this->returnValue('root')); //user
- $this->Task->expects($this->at(6))->method('in')->will($this->returnValue('password')); //password
- $this->Task->expects($this->at(10))->method('in')->will($this->returnValue('cake_test')); //db
- $this->Task->expects($this->at(11))->method('in')->will($this->returnValue('n')); //prefix
- $this->Task->expects($this->at(12))->method('in')->will($this->returnValue('n')); //encoding
- $this->Task->expects($this->at(13))->method('in')->will($this->returnValue('y')); //looks good
- $this->Task->expects($this->at(14))->method('in')->will($this->returnValue('n')); //another
- $this->Task->expects($this->at(15))->method('bake')
- ->with(array(
- array(
- 'name' => 'default',
- 'datasource' => 'mysql',
- 'persistent' => 'false',
- 'host' => 'localhost',
- 'login' => 'root',
- 'password' => 'password',
- 'database' => 'cake_test',
- 'prefix' => null,
- 'encoding' => null,
- 'port' => '',
- 'schema' => null
- )
- ));
-
- $result = $this->Task->execute();
- }
-}
diff --git a/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php
deleted file mode 100644
index b144e37b99a..00000000000
--- a/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php
+++ /dev/null
@@ -1,402 +0,0 @@
-getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Task = $this->getMock(
- 'ExtractTask',
- array('in', 'out', 'err', '_stop'),
- array($out, $out, $in)
- );
- $this->path = TMP . 'tests' . DS . 'extract_task_test';
- $Folder = new Folder($this->path . DS . 'locale', true);
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- unset($this->Task);
-
- $Folder = new Folder($this->path);
- $Folder->delete();
- CakePlugin::unload();
- }
-
-/**
- * testExecute method
- *
- * @return void
- */
- public function testExecute() {
- $this->Task->interactive = false;
-
- $this->Task->params['paths'] = CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS . 'Pages';
- $this->Task->params['output'] = $this->path . DS;
- $this->Task->expects($this->never())->method('err');
- $this->Task->expects($this->any())->method('in')
- ->will($this->returnValue('y'));
- $this->Task->expects($this->never())->method('_stop');
-
- $this->Task->execute();
- $this->assertTrue(file_exists($this->path . DS . 'default.pot'));
- $result = file_get_contents($this->path . DS . 'default.pot');
-
- $pattern = '/"Content-Type\: text\/plain; charset\=utf-8/';
- $this->assertRegExp($pattern, $result);
- $pattern = '/"Content-Transfer-Encoding\: 8bit/';
- $this->assertRegExp($pattern, $result);
- $pattern = '/"Plural-Forms\: nplurals\=INTEGER; plural\=EXPRESSION;/';
- $this->assertRegExp($pattern, $result);
-
- // home.ctp
- $pattern = '/msgid "Your tmp directory is writable."\nmsgstr ""\n/';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '/msgid "Your tmp directory is NOT writable."\nmsgstr ""\n/';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '/msgid "The %s is being used for caching. To change the config edit ';
- $pattern .= 'APP\/config\/core.php "\nmsgstr ""\n/';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '/msgid "Your cache is NOT working. Please check ';
- $pattern .= 'the settings in APP\/config\/core.php"\nmsgstr ""\n/';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '/msgid "Your database configuration file is present."\nmsgstr ""\n/';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '/msgid "Your database configuration file is NOT present."\nmsgstr ""\n/';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '/msgid "Rename config\/database.php.default to ';
- $pattern .= 'config\/database.php"\nmsgstr ""\n/';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '/msgid "Cake is able to connect to the database."\nmsgstr ""\n/';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '/msgid "Cake is NOT able to connect to the database."\nmsgstr ""\n/';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '/msgid "Editing this Page"\nmsgstr ""\n/';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '/msgid "To change the content of this page, create: APP\/views\/pages\/home\.ctp/';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '/To change its layout, create: APP\/views\/layouts\/default\.ctp\./s';
- $this->assertRegExp($pattern, $result);
-
- // extract.ctp
- $pattern = '/\#: (\\\\|\/)extract\.ctp:15;6\n';
- $pattern .= 'msgid "You have %d new message."\nmsgid_plural "You have %d new messages."/';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '/msgid "You have %d new message."\nmsgstr ""/';
- $this->assertNotRegExp($pattern, $result, 'No duplicate msgid');
-
- $pattern = '/\#: (\\\\|\/)extract\.ctp:7\n';
- $pattern .= 'msgid "You deleted %d message."\nmsgid_plural "You deleted %d messages."/';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '/\#: (\\\\|\/)extract\.ctp:14\n';
- $pattern .= '\#: (\\\\|\/)home\.ctp:99\n';
- $pattern .= 'msgid "Editing this Page"\nmsgstr ""/';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '/\#: (\\\\|\/)extract\.ctp:18\nmsgid "';
- $pattern .= 'Hot features!';
- $pattern .= '\\\n - No Configuration: Set-up the database and let the magic begin';
- $pattern .= '\\\n - Extremely Simple: Just look at the name...It\'s Cake';
- $pattern .= '\\\n - Active, Friendly Community: Join us #cakephp on IRC. We\'d love to help you get started';
- $pattern .= '"\nmsgstr ""/';
- $this->assertRegExp($pattern, $result);
-
- // extract.ctp - reading the domain.pot
- $result = file_get_contents($this->path . DS . 'domain.pot');
-
- $pattern = '/msgid "You have %d new message."\nmsgid_plural "You have %d new messages."/';
- $this->assertNotRegExp($pattern, $result);
- $pattern = '/msgid "You deleted %d message."\nmsgid_plural "You deleted %d messages."/';
- $this->assertNotRegExp($pattern, $result);
-
- $pattern = '/msgid "You have %d new message \(domain\)."\nmsgid_plural "You have %d new messages \(domain\)."/';
- $this->assertRegExp($pattern, $result);
- $pattern = '/msgid "You deleted %d message \(domain\)."\nmsgid_plural "You deleted %d messages \(domain\)."/';
- $this->assertRegExp($pattern, $result);
- }
-
-/**
- * test exclusions
- *
- * @return void
- */
- public function testExtractWithExclude() {
- $this->Task->interactive = false;
-
- $this->Task->params['paths'] = CAKE . 'Test' . DS . 'test_app' . DS . 'View';
- $this->Task->params['output'] = $this->path . DS;
- $this->Task->params['exclude'] = 'Pages,Layouts';
-
- $this->Task->expects($this->any())->method('in')
- ->will($this->returnValue('y'));
-
- $this->Task->execute();
- $this->assertTrue(file_exists($this->path . DS . 'default.pot'));
- $result = file_get_contents($this->path . DS . 'default.pot');
-
- $pattern = '/\#: .*extract\.ctp:6\n/';
- $this->assertNotRegExp($pattern, $result);
-
- $pattern = '/\#: .*default\.ctp:26\n/';
- $this->assertNotRegExp($pattern, $result);
- }
-
-/**
- * test extract can read more than one path.
- *
- * @return void
- */
- public function testExtractMultiplePaths() {
- $this->Task->interactive = false;
-
- $this->Task->params['paths'] =
- CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS . 'Pages,' .
- CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS . 'Posts';
-
- $this->Task->params['output'] = $this->path . DS;
- $this->Task->expects($this->never())->method('err');
- $this->Task->expects($this->never())->method('_stop');
- $this->Task->execute();
-
- $result = file_get_contents($this->path . DS . 'default.pot');
-
- $pattern = '/msgid "Add User"/';
- $this->assertRegExp($pattern, $result);
- }
-
-/**
- * Tests that it is possible to exclude plugin paths by enabling the param option for the ExtractTask
- *
- * @return void
- */
- public function testExtractExcludePlugins() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ));
- $this->out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $this->in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Task = $this->getMock('ExtractTask',
- array('_isExtractingApp', '_extractValidationMessages', 'in', 'out', 'err', 'clear', '_stop'),
- array($this->out, $this->out, $this->in)
- );
- $this->Task->expects($this->exactly(2))->method('_isExtractingApp')->will($this->returnValue(true));
-
- $this->Task->params['paths'] = CAKE . 'Test' . DS . 'test_app' . DS;
- $this->Task->params['output'] = $this->path . DS;
- $this->Task->params['exclude-plugins'] = true;
-
- $this->Task->execute();
- $result = file_get_contents($this->path . DS . 'default.pot');
- $this->assertNotRegExp('#TestPlugin#', $result);
- }
-
-/**
- * Test that is possible to extract messages form a single plugin
- *
- * @return void
- */
- public function testExtractPlugin() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ));
-
- $this->out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $this->in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Task = $this->getMock('ExtractTask',
- array('_isExtractingApp', '_extractValidationMessages', 'in', 'out', 'err', 'clear', '_stop'),
- array($this->out, $this->out, $this->in)
- );
-
- $this->Task->params['output'] = $this->path . DS;
- $this->Task->params['plugin'] = 'TestPlugin';
-
- $this->Task->execute();
- $result = file_get_contents($this->path . DS . 'default.pot');
- $this->assertNotRegExp('#Pages#', $result);
- $this->assertContains('translate.ctp:1', $result);
- $this->assertContains('This is a translatable string', $result);
- }
-
-/**
- * Tests that the task will inspect application models and extract the validation messages from them
- *
- * @return void
- */
- public function testExtractModelValidation() {
- App::build(array(
- 'Model' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Model' . DS),
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ), App::RESET);
- $this->out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $this->in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Task = $this->getMock('ExtractTask',
- array('_isExtractingApp', 'in', 'out', 'err', 'clear', '_stop'),
- array($this->out, $this->out, $this->in)
- );
- $this->Task->expects($this->exactly(2))->method('_isExtractingApp')->will($this->returnValue(true));
-
- $this->Task->params['paths'] = CAKE . 'Test' . DS . 'test_app' . DS;
- $this->Task->params['output'] = $this->path . DS;
- $this->Task->params['exclude-plugins'] = true;
- $this->Task->params['ignore-model-validation'] = false;
-
- $this->Task->execute();
- $result = file_get_contents($this->path . DS . 'default.pot');
-
- $pattern = preg_quote('#Model' . DS . 'PersisterOne.php:validation for field title#', '\\');
- $this->assertRegExp($pattern, $result);
-
- $pattern = preg_quote('#Model' . DS . 'PersisterOne.php:validation for field body#', '\\');
- $this->assertRegExp($pattern, $result);
-
- $pattern = '#msgid "Post title is required"#';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '#msgid "You may enter up to %s chars \(minimum is %s chars\)"#';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '#msgid "Post body is required"#';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '#msgid "Post body is super required"#';
- $this->assertRegExp($pattern, $result);
- }
-
-/**
- * Tests that the task will inspect application models and extract the validation messages from them
- * while using a custom validation domain for the messages set on the model itself
- *
- * @return void
- */
- public function testExtractModelValidationWithDomainInModel() {
- App::build(array(
- 'Model' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS . 'TestPlugin' . DS . 'Model' . DS)
- ));
- $this->out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $this->in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Task = $this->getMock('ExtractTask',
- array('_isExtractingApp', 'in', 'out', 'err', 'clear', '_stop'),
- array($this->out, $this->out, $this->in)
- );
- $this->Task->expects($this->exactly(2))->method('_isExtractingApp')->will($this->returnValue(true));
-
- $this->Task->params['paths'] = CAKE . 'Test' . DS . 'test_app' . DS;
- $this->Task->params['output'] = $this->path . DS;
- $this->Task->params['exclude-plugins'] = true;
- $this->Task->params['ignore-model-validation'] = false;
-
- $this->Task->execute();
- $result = file_get_contents($this->path . DS . 'test_plugin.pot');
-
- $pattern = preg_quote('#Plugin' . DS . 'TestPlugin' . DS . 'Model' . DS . 'TestPluginPost.php:validation for field title#', '\\');
- $this->assertRegExp($pattern, $result);
-
- $pattern = preg_quote('#Plugin' . DS . 'TestPlugin' . DS . 'Model' . DS . 'TestPluginPost.php:validation for field body#', '\\');
- $this->assertRegExp($pattern, $result);
-
- $pattern = '#msgid "Post title is required"#';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '#msgid "Post body is required"#';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '#msgid "Post body is super required"#';
- $this->assertRegExp($pattern, $result);
- }
-
-/**
- * Test that the extract shell can obtain validation messages from models inside a specific plugin
- *
- * @return void
- */
- public function testExtractModelValidationInPlugin() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ));
- $this->out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $this->in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Task = $this->getMock('ExtractTask',
- array('_isExtractingApp', 'in', 'out', 'err', 'clear', '_stop'),
- array($this->out, $this->out, $this->in)
- );
-
- $this->Task->params['output'] = $this->path . DS;
- $this->Task->params['ignore-model-validation'] = false;
- $this->Task->params['plugin'] = 'TestPlugin';
-
- $this->Task->execute();
- $result = file_get_contents($this->path . DS . 'test_plugin.pot');
-
- $pattern = preg_quote('#Model' . DS . 'TestPluginPost.php:validation for field title#', '\\');
- $this->assertRegExp($pattern, $result);
-
- $pattern = preg_quote('#Model' . DS . 'TestPluginPost.php:validation for field body#', '\\');
- $this->assertRegExp($pattern, $result);
-
- $pattern = '#msgid "Post title is required"#';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '#msgid "Post body is required"#';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '#msgid "Post body is super required"#';
- $this->assertRegExp($pattern, $result);
-
- $pattern = '#Plugin/TestPlugin/Model/TestPluginPost.php:validation for field title#';
- $this->assertNotRegExp($pattern, $result);
- }
-}
diff --git a/lib/Cake/Test/Case/Console/Command/Task/FixtureTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/FixtureTaskTest.php
deleted file mode 100644
index 9f2cbd0bd17..00000000000
--- a/lib/Cake/Test/Case/Console/Command/Task/FixtureTaskTest.php
+++ /dev/null
@@ -1,388 +0,0 @@
-getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Task = $this->getMock('FixtureTask',
- array('in', 'err', 'createFile', '_stop', 'clear'),
- array($out, $out, $in)
- );
- $this->Task->Model = $this->getMock('ModelTask',
- array('in', 'out', 'err', 'createFile', 'getName', 'getTable', 'listAll'),
- array($out, $out, $in)
- );
- $this->Task->Template = new TemplateTask($out, $out, $in);
- $this->Task->DbConfig = $this->getMock('DbConfigTask', array(), array($out, $out, $in));
- $this->Task->Template->initialize();
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- unset($this->Task);
- }
-
-/**
- * test that initialize sets the path
- *
- * @return void
- */
- public function testConstruct() {
- $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $Task = new FixtureTask($out, $out, $in);
- $this->assertEquals(APP . 'Test' . DS . 'Fixture' . DS, $Task->path);
- }
-
-/**
- * test import option array generation
- *
- * @return void
- */
- public function testImportOptionsSchemaRecords() {
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y'));
- $this->Task->expects($this->at(1))->method('in')->will($this->returnValue('y'));
-
- $result = $this->Task->importOptions('Article');
- $expected = array('schema' => 'Article', 'records' => true);
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test importOptions choosing nothing.
- *
- * @return void
- */
- public function testImportOptionsNothing() {
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('n'));
- $this->Task->expects($this->at(1))->method('in')->will($this->returnValue('n'));
- $this->Task->expects($this->at(2))->method('in')->will($this->returnValue('n'));
-
- $result = $this->Task->importOptions('Article');
- $expected = array();
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test importOptions choosing from Table.
- *
- * @return void
- */
- public function testImportOptionsTable() {
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('n'));
- $this->Task->expects($this->at(1))->method('in')->will($this->returnValue('n'));
- $this->Task->expects($this->at(2))->method('in')->will($this->returnValue('y'));
- $result = $this->Task->importOptions('Article');
- $expected = array('fromTable' => true);
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test generating a fixture with database conditions.
- *
- * @return void
- */
- public function testImportRecordsFromDatabaseWithConditionsPoo() {
- $this->Task->interactive = true;
- $this->Task->expects($this->at(0))->method('in')
- ->will($this->returnValue('WHERE 1=1'));
-
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
-
- $result = $this->Task->bake('Article', false, array(
- 'fromTable' => true, 'schema' => 'Article', 'records' => false
- ));
-
- $this->assertContains('class ArticleFixture extends CakeTestFixture', $result);
- $this->assertContains('public $records', $result);
- $this->assertContains('public $import', $result);
- $this->assertContains("'title' => 'First Article'", $result, 'Missing import data %s');
- $this->assertContains('Second Article', $result, 'Missing import data %s');
- $this->assertContains('Third Article', $result, 'Missing import data %s');
- }
-
-/**
- * test that connection gets set to the import options when a different connection is used.
- *
- * @return void
- */
- public function testImportOptionsAlternateConnection() {
- $this->Task->connection = 'test';
- $result = $this->Task->bake('Article', false, array('schema' => 'Article'));
- $this->assertContains("'connection' => 'test'", $result);
- }
-
-/**
- * Ensure that fixture data doesn't get overly escaped.
- *
- * @return void
- */
- public function testImportRecordsNoEscaping() {
- $db = ConnectionManager::getDataSource('test');
- if ($db instanceof Sqlserver) {
- $this->markTestSkipped('This test does not run on SQLServer');
- }
-
- $Article = ClassRegistry::init('Article');
- $Article->updateAll(array('body' => "'Body \"value\"'"));
-
- $this->Task->interactive = true;
- $this->Task->expects($this->at(0))
- ->method('in')
- ->will($this->returnValue('WHERE 1=1 LIMIT 10'));
-
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $result = $this->Task->bake('Article', false, array(
- 'fromTable' => true,
- 'schema' => 'Article',
- 'records' => false
- ));
- $this->assertContains("'body' => 'Body \"value\"'", $result, 'Data has bad escaping');
- }
-
-/**
- * test that execute passes runs bake depending with named model.
- *
- *
- * @return void
- */
- public function testExecuteWithNamedModel() {
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('article');
- $filename = '/my/path/ArticleFixture.php';
-
- $this->Task->expects($this->at(0))->method('createFile')
- ->with($filename, $this->stringContains('class ArticleFixture'));
-
- $this->Task->execute();
- }
-
-/**
- * test that execute runs all() when args[0] = all
- *
- * @return void
- */
- public function testExecuteIntoAll() {
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('all');
- $this->Task->Model->expects($this->any())
- ->method('listAll')
- ->will($this->returnValue(array('articles', 'comments')));
-
- $filename = '/my/path/ArticleFixture.php';
- $this->Task->expects($this->at(0))
- ->method('createFile')
- ->with($filename, $this->stringContains('class ArticleFixture'));
-
- $filename = '/my/path/CommentFixture.php';
- $this->Task->expects($this->at(1))
- ->method('createFile')
- ->with($filename, $this->stringContains('class CommentFixture'));
-
- $this->Task->execute();
- }
-
-/**
- * test using all() with -count and -records
- *
- * @return void
- */
- public function testAllWithCountAndRecordsFlags() {
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('all');
- $this->Task->params = array('count' => 10, 'records' => true);
-
- $this->Task->Model->expects($this->any())->method('listAll')
- ->will($this->returnValue(array('Articles', 'comments')));
-
- $filename = '/my/path/ArticleFixture.php';
- $this->Task->expects($this->at(0))->method('createFile')
- ->with($filename, $this->stringContains("'title' => 'Third Article'"));
-
- $filename = '/my/path/CommentFixture.php';
- $this->Task->expects($this->at(1))->method('createFile')
- ->with($filename, $this->stringContains("'comment' => 'First Comment for First Article'"));
- $this->Task->expects($this->exactly(2))->method('createFile');
-
- $this->Task->all();
- }
-
-/**
- * test interactive mode of execute
- *
- * @return void
- */
- public function testExecuteInteractive() {
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
-
- $this->Task->expects($this->any())->method('in')->will($this->returnValue('y'));
- $this->Task->Model->expects($this->any())->method('getName')->will($this->returnValue('Article'));
- $this->Task->Model->expects($this->any())->method('getTable')
- ->with('Article')
- ->will($this->returnValue('articles'));
-
- $filename = '/my/path/ArticleFixture.php';
- $this->Task->expects($this->once())->method('createFile')
- ->with($filename, $this->stringContains('class ArticleFixture'));
-
- $this->Task->execute();
- }
-
-/**
- * Test that bake works
- *
- * @return void
- */
- public function testBake() {
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
-
- $result = $this->Task->bake('Article');
- $this->assertContains('class ArticleFixture extends CakeTestFixture', $result);
- $this->assertContains('public $fields', $result);
- $this->assertContains('public $records', $result);
- $this->assertNotContains('public $import', $result);
-
- $result = $this->Task->bake('Article', 'comments');
- $this->assertContains('class ArticleFixture extends CakeTestFixture', $result);
- $this->assertContains('public $table = \'comments\';', $result);
- $this->assertContains('public $fields = array(', $result);
-
- $result = $this->Task->bake('Article', 'comments', array('records' => true));
- $this->assertContains("public \$import = array('records' => true, 'connection' => 'test');", $result);
- $this->assertNotContains('public $records', $result);
-
- $result = $this->Task->bake('Article', 'comments', array('schema' => 'Article'));
- $this->assertContains("public \$import = array('model' => 'Article', 'connection' => 'test');", $result);
- $this->assertNotContains('public $fields', $result);
-
- $result = $this->Task->bake('Article', 'comments', array('schema' => 'Article', 'records' => true));
- $this->assertContains("public \$import = array('model' => 'Article', 'records' => true, 'connection' => 'test');", $result);
- $this->assertNotContains('public $fields', $result);
- $this->assertNotContains('public $records', $result);
- }
-
-/**
- * test record generation with float and binary types
- *
- * @return void
- */
- public function testRecordGenerationForBinaryAndFloat() {
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
-
- $result = $this->Task->bake('Article', 'datatypes');
- $this->assertContains("'float_field' => 1", $result);
- $this->assertContains("'bool' => 1", $result);
-
- $result = $this->Task->bake('Article', 'binary_tests');
- $this->assertContains("'data' => 'Lorem ipsum dolor sit amet'", $result);
- }
-
-/**
- * Test that file generation includes headers and correct path for plugins.
- *
- * @return void
- */
- public function testGenerateFixtureFile() {
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $filename = '/my/path/ArticleFixture.php';
-
- $this->Task->expects($this->at(0))->method('createFile')
- ->with($filename, $this->stringContains('ArticleFixture'));
-
- $this->Task->expects($this->at(1))->method('createFile')
- ->with($filename, $this->stringContains('Task->generateFixtureFile('Article', array());
-
- $result = $this->Task->generateFixtureFile('Article', array());
- }
-
-/**
- * test generating files into plugins.
- *
- * @return void
- */
- public function testGeneratePluginFixtureFile() {
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->plugin = 'TestFixture';
- $filename = APP . 'Plugin' . DS . 'TestFixture' . DS . 'Test' . DS . 'Fixture' . DS . 'ArticleFixture.php';
-
- //fake plugin path
- CakePlugin::load('TestFixture', array('path' => APP . 'Plugin' . DS . 'TestFixture' . DS));
- $this->Task->expects($this->at(0))->method('createFile')
- ->with($filename, $this->stringContains('class Article'));
-
- $result = $this->Task->generateFixtureFile('Article', array());
- CakePlugin::unload();
- }
-
-}
diff --git a/lib/Cake/Test/Case/Console/Command/Task/ModelTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ModelTaskTest.php
deleted file mode 100644
index b181848afc5..00000000000
--- a/lib/Cake/Test/Case/Console/Command/Task/ModelTaskTest.php
+++ /dev/null
@@ -1,1189 +0,0 @@
-getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Task = $this->getMock('ModelTask',
- array('in', 'err', 'createFile', '_stop', '_checkUnitTest'),
- array($out, $out, $in)
- );
- $this->_setupOtherMocks();
- }
-
-/**
- * Setup a mock that has out mocked. Normally this is not used as it makes $this->at() really tricky.
- *
- * @return void
- */
- protected function _useMockedOut() {
- $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Task = $this->getMock('ModelTask',
- array('in', 'out', 'err', 'hr', 'createFile', '_stop', '_checkUnitTest'),
- array($out, $out, $in)
- );
- $this->_setupOtherMocks();
- }
-
-/**
- * sets up the rest of the dependencies for Model Task
- *
- * @return void
- */
- protected function _setupOtherMocks() {
- $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Task->Fixture = $this->getMock('FixtureTask', array(), array($out, $out, $in));
- $this->Task->Test = $this->getMock('FixtureTask', array(), array($out, $out, $in));
- $this->Task->Template = new TemplateTask($out, $out, $in);
-
- $this->Task->name = 'Model';
- $this->Task->interactive = true;
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- unset($this->Task);
- }
-
-/**
- * Test that listAll scans the database connection and lists all the tables in it.s
- *
- * @return void
- */
- public function testListAllArgument() {
- $this->_useMockedOut();
-
- $result = $this->Task->listAll('test');
- $this->assertContains('bake_articles', $result);
- $this->assertContains('bake_articles_bake_tags', $result);
- $this->assertContains('bake_tags', $result);
- $this->assertContains('bake_comments', $result);
- $this->assertContains('category_threads', $result);
- }
-
-/**
- * Test that listAll uses the connection property
- *
- * @return void
- */
- public function testListAllConnection() {
- $this->_useMockedOut();
-
- $this->Task->connection = 'test';
- $result = $this->Task->listAll();
- $this->assertContains('bake_articles', $result);
- $this->assertContains('bake_articles_bake_tags', $result);
- $this->assertContains('bake_tags', $result);
- $this->assertContains('bake_comments', $result);
- $this->assertContains('category_threads', $result);
- }
-
-/**
- * Test that getName interacts with the user and returns the model name.
- *
- * @return void
- */
- public function testGetNameQuit() {
- $this->Task->expects($this->once())->method('in')->will($this->returnValue('q'));
- $this->Task->expects($this->once())->method('_stop');
- $this->Task->getName('test');
- }
-
-/**
- * test getName with a valid option.
- *
- * @return void
- */
- public function testGetNameValidOption() {
- $listing = $this->Task->listAll('test');
- $this->Task->expects($this->any())->method('in')->will($this->onConsecutiveCalls(1, 4));
-
- $result = $this->Task->getName('test');
- $this->assertEquals(Inflector::classify($listing[0]), $result);
-
- $result = $this->Task->getName('test');
- $this->assertEquals(Inflector::classify($listing[3]), $result);
- }
-
-/**
- * test that an out of bounds option causes an error.
- *
- * @return void
- */
- public function testGetNameWithOutOfBoundsOption() {
- $this->Task->expects($this->any())->method('in')->will($this->onConsecutiveCalls(99, 1));
- $this->Task->expects($this->once())->method('err');
-
- $result = $this->Task->getName('test');
- }
-
-/**
- * Test table name interactions
- *
- * @return void
- */
- public function testGetTableName() {
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y'));
- $result = $this->Task->getTable('BakeArticle', 'test');
- $expected = 'bake_articles';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test gettting a custom table name.
- *
- * @return void
- */
- public function testGetTableNameCustom() {
- $this->Task->expects($this->any())->method('in')->will($this->onConsecutiveCalls('n', 'my_table'));
- $result = $this->Task->getTable('BakeArticle', 'test');
- $expected = 'my_table';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test getTable with non-conventional tablenames
- *
- * @return void
- */
- public function testGetTableOddTableInteractive() {
- $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Task = $this->getMock('ModelTask',
- array('in', 'err', '_stop', '_checkUnitTest', 'getAllTables'),
- array($out, $out, $in)
- );
- $this->_setupOtherMocks();
-
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->interactive = true;
-
- $this->Task->expects($this->once())->method('getAllTables')->will($this->returnValue(array('articles', 'bake_odd')));
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls(
- 2 // bake_odd
- ));
-
- $result = $this->Task->getName();
- $expected = 'BakeOdd';
- $this->assertEquals($expected, $result);
-
- $result = $this->Task->getTable($result);
- $expected = 'bake_odd';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test getTable with non-conventional tablenames
- *
- * @return void
- */
- public function testGetTableOddTable() {
- $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Task = $this->getMock('ModelTask',
- array('in', 'err', '_stop', '_checkUnitTest', 'getAllTables'),
- array($out, $out, $in)
- );
- $this->_setupOtherMocks();
-
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->interactive = false;
- $this->Task->args = array('BakeOdd');
-
- $this->Task->expects($this->once())->method('getAllTables')->will($this->returnValue(array('articles', 'bake_odd')));
-
- $this->Task->listAll();
-
- $result = $this->Task->getTable('BakeOdd');
- $expected = 'bake_odd';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test that initializing the validations works.
- *
- * @return void
- */
- public function testInitValidations() {
- $result = $this->Task->initValidations();
- $this->assertTrue(in_array('notempty', $result));
- }
-
-/**
- * test that individual field validation works, with interactive = false
- * tests the guessing features of validation
- *
- * @return void
- */
- public function testFieldValidationGuessing() {
- $this->Task->interactive = false;
- $this->Task->initValidations();
-
- $result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
- $expected = array('notempty' => 'notempty');
- $this->assertEquals($expected, $result);
-
- $result = $this->Task->fieldValidation('text', array('type' => 'date', 'length' => 10, 'null' => false));
- $expected = array('date' => 'date');
- $this->assertEquals($expected, $result);
-
- $result = $this->Task->fieldValidation('text', array('type' => 'time', 'length' => 10, 'null' => false));
- $expected = array('time' => 'time');
- $this->assertEquals($expected, $result);
-
- $result = $this->Task->fieldValidation('email', array('type' => 'string', 'length' => 10, 'null' => false));
- $expected = array('email' => 'email');
- $this->assertEquals($expected, $result);
-
- $result = $this->Task->fieldValidation('test', array('type' => 'integer', 'length' => 10, 'null' => false));
- $expected = array('numeric' => 'numeric');
- $this->assertEquals($expected, $result);
-
- $result = $this->Task->fieldValidation('test', array('type' => 'boolean', 'length' => 10, 'null' => false));
- $expected = array('boolean' => 'boolean');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test that interactive field validation works and returns multiple validators.
- *
- * @return void
- */
- public function testInteractiveFieldValidation() {
- $this->Task->initValidations();
- $this->Task->interactive = true;
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls('21', 'y', '17', 'n'));
-
- $result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
- $expected = array('notempty' => 'notempty', 'maxlength' => 'maxlength');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test that a bogus response doesn't cause errors to bubble up.
- *
- * @return void
- */
- public function testInteractiveFieldValidationWithBogusResponse() {
- $this->_useMockedOut();
- $this->Task->initValidations();
- $this->Task->interactive = true;
-
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls('999999', '21', 'n'));
-
- $this->Task->expects($this->at(7))->method('out')
- ->with($this->stringContains('make a valid'));
-
- $result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
- $expected = array('notempty' => 'notempty');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test that a regular expression can be used for validation.
- *
- * @return void
- */
- public function testInteractiveFieldValidationWithRegexp() {
- $this->Task->initValidations();
- $this->Task->interactive = true;
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls('/^[a-z]{0,9}$/', 'n'));
-
- $result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
- $expected = array('a_z_0_9' => '/^[a-z]{0,9}$/');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test the validation Generation routine
- *
- * @return void
- */
- public function testNonInteractiveDoValidation() {
- $Model = $this->getMock('Model');
- $Model->primaryKey = 'id';
- $Model->expects($this->any())->method('schema')->will($this->returnValue(array(
- 'id' => array(
- 'type' => 'integer',
- 'length' => 11,
- 'null' => false,
- 'key' => 'primary',
- ),
- 'name' => array(
- 'type' => 'string',
- 'length' => 20,
- 'null' => false,
- ),
- 'email' => array(
- 'type' => 'string',
- 'length' => 255,
- 'null' => false,
- ),
- 'some_date' => array(
- 'type' => 'date',
- 'length' => '',
- 'null' => false,
- ),
- 'some_time' => array(
- 'type' => 'time',
- 'length' => '',
- 'null' => false,
- ),
- 'created' => array(
- 'type' => 'datetime',
- 'length' => '',
- 'null' => false,
- )
- )));
- $this->Task->interactive = false;
-
- $result = $this->Task->doValidation($Model);
- $expected = array(
- 'name' => array(
- 'notempty' => 'notempty'
- ),
- 'email' => array(
- 'email' => 'email',
- ),
- 'some_date' => array(
- 'date' => 'date'
- ),
- 'some_time' => array(
- 'time' => 'time'
- ),
- );
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test that finding primary key works
- *
- * @return void
- */
- public function testFindPrimaryKey() {
- $fields = array(
- 'one' => array(),
- 'two' => array(),
- 'key' => array('key' => 'primary')
- );
- $anything = new PHPUnit_Framework_Constraint_IsAnything();
- $this->Task->expects($this->once())->method('in')
- ->with($anything, null, 'key')
- ->will($this->returnValue('my_field'));
-
- $result = $this->Task->findPrimaryKey($fields);
- $expected = 'my_field';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test finding Display field
- *
- * @return void
- */
- public function testFindDisplayFieldNone() {
- $fields = array(
- 'id' => array(), 'tagname' => array(), 'body' => array(),
- 'created' => array(), 'modified' => array()
- );
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('n'));
- $result = $this->Task->findDisplayField($fields);
- $this->assertFalse($result);
- }
-
-/**
- * Test finding a displayname from user input
- *
- * @return void
- */
- public function testFindDisplayName() {
- $fields = array(
- 'id' => array(), 'tagname' => array(), 'body' => array(),
- 'created' => array(), 'modified' => array()
- );
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls('y', 2));
-
- $result = $this->Task->findDisplayField($fields);
- $this->assertEquals('tagname', $result);
- }
-
-/**
- * test that belongsTo generation works.
- *
- * @return void
- */
- public function testBelongsToGeneration() {
- $model = new Model(array('ds' => 'test', 'name' => 'BakeComment'));
- $result = $this->Task->findBelongsTo($model, array());
- $expected = array(
- 'belongsTo' => array(
- array(
- 'alias' => 'BakeArticle',
- 'className' => 'BakeArticle',
- 'foreignKey' => 'bake_article_id',
- ),
- array(
- 'alias' => 'BakeUser',
- 'className' => 'BakeUser',
- 'foreignKey' => 'bake_user_id',
- ),
- )
- );
- $this->assertEquals($expected, $result);
-
- $model = new Model(array('ds' => 'test', 'name' => 'CategoryThread'));
- $result = $this->Task->findBelongsTo($model, array());
- $expected = array(
- 'belongsTo' => array(
- array(
- 'alias' => 'ParentCategoryThread',
- 'className' => 'CategoryThread',
- 'foreignKey' => 'parent_id',
- ),
- )
- );
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test that hasOne and/or hasMany relations are generated properly.
- *
- * @return void
- */
- public function testHasManyHasOneGeneration() {
- $model = new Model(array('ds' => 'test', 'name' => 'BakeArticle'));
- $this->Task->connection = 'test';
- $this->Task->listAll();
- $result = $this->Task->findHasOneAndMany($model, array());
- $expected = array(
- 'hasMany' => array(
- array(
- 'alias' => 'BakeComment',
- 'className' => 'BakeComment',
- 'foreignKey' => 'bake_article_id',
- ),
- ),
- 'hasOne' => array(
- array(
- 'alias' => 'BakeComment',
- 'className' => 'BakeComment',
- 'foreignKey' => 'bake_article_id',
- ),
- ),
- );
- $this->assertEquals($expected, $result);
-
- $model = new Model(array('ds' => 'test', 'name' => 'CategoryThread'));
- $result = $this->Task->findHasOneAndMany($model, array());
- $expected = array(
- 'hasOne' => array(
- array(
- 'alias' => 'ChildCategoryThread',
- 'className' => 'CategoryThread',
- 'foreignKey' => 'parent_id',
- ),
- ),
- 'hasMany' => array(
- array(
- 'alias' => 'ChildCategoryThread',
- 'className' => 'CategoryThread',
- 'foreignKey' => 'parent_id',
- ),
- )
- );
- $this->assertEquals($expected, $result);
- }
-
-/**
- * Test that HABTM generation works
- *
- * @return void
- */
- public function testHasAndBelongsToManyGeneration() {
- $model = new Model(array('ds' => 'test', 'name' => 'BakeArticle'));
- $this->Task->connection = 'test';
- $this->Task->listAll();
- $result = $this->Task->findHasAndBelongsToMany($model, array());
- $expected = array(
- 'hasAndBelongsToMany' => array(
- array(
- 'alias' => 'BakeTag',
- 'className' => 'BakeTag',
- 'foreignKey' => 'bake_article_id',
- 'joinTable' => 'bake_articles_bake_tags',
- 'associationForeignKey' => 'bake_tag_id',
- ),
- ),
- );
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test non interactive doAssociations
- *
- * @return void
- */
- public function testDoAssociationsNonInteractive() {
- $this->Task->connection = 'test';
- $this->Task->interactive = false;
- $model = new Model(array('ds' => 'test', 'name' => 'BakeArticle'));
- $result = $this->Task->doAssociations($model);
- $expected = array(
- 'belongsTo' => array(
- array(
- 'alias' => 'BakeUser',
- 'className' => 'BakeUser',
- 'foreignKey' => 'bake_user_id',
- ),
- ),
- 'hasMany' => array(
- array(
- 'alias' => 'BakeComment',
- 'className' => 'BakeComment',
- 'foreignKey' => 'bake_article_id',
- ),
- ),
- 'hasAndBelongsToMany' => array(
- array(
- 'alias' => 'BakeTag',
- 'className' => 'BakeTag',
- 'foreignKey' => 'bake_article_id',
- 'joinTable' => 'bake_articles_bake_tags',
- 'associationForeignKey' => 'bake_tag_id',
- ),
- ),
- );
- $this->assertEquals($expected, $result);
- }
-
-/**
- * Ensure that the fixture object is correctly called.
- *
- * @return void
- */
- public function testBakeFixture() {
- $this->Task->plugin = 'TestPlugin';
- $this->Task->interactive = true;
- $this->Task->Fixture->expects($this->at(0))->method('bake')->with('BakeArticle', 'bake_articles');
- $this->Task->bakeFixture('BakeArticle', 'bake_articles');
-
- $this->assertEquals($this->Task->plugin, $this->Task->Fixture->plugin);
- $this->assertEquals($this->Task->connection, $this->Task->Fixture->connection);
- $this->assertEquals($this->Task->interactive, $this->Task->Fixture->interactive);
- }
-
-/**
- * Ensure that the test object is correctly called.
- *
- * @return void
- */
- public function testBakeTest() {
- $this->Task->plugin = 'TestPlugin';
- $this->Task->interactive = true;
- $this->Task->Test->expects($this->at(0))->method('bake')->with('Model', 'BakeArticle');
- $this->Task->bakeTest('BakeArticle');
-
- $this->assertEquals($this->Task->plugin, $this->Task->Test->plugin);
- $this->assertEquals($this->Task->connection, $this->Task->Test->connection);
- $this->assertEquals($this->Task->interactive, $this->Task->Test->interactive);
- }
-
-/**
- * test confirming of associations, and that when an association is hasMany
- * a question for the hasOne is also not asked.
- *
- * @return void
- */
- public function testConfirmAssociations() {
- $associations = array(
- 'hasOne' => array(
- array(
- 'alias' => 'ChildCategoryThread',
- 'className' => 'CategoryThread',
- 'foreignKey' => 'parent_id',
- ),
- ),
- 'hasMany' => array(
- array(
- 'alias' => 'ChildCategoryThread',
- 'className' => 'CategoryThread',
- 'foreignKey' => 'parent_id',
- ),
- ),
- 'belongsTo' => array(
- array(
- 'alias' => 'User',
- 'className' => 'User',
- 'foreignKey' => 'user_id',
- ),
- )
- );
- $model = new Model(array('ds' => 'test', 'name' => 'CategoryThread'));
-
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls('n', 'y', 'n', 'n', 'n'));
-
- $result = $this->Task->confirmAssociations($model, $associations);
- $this->assertTrue(empty($result['hasOne']));
-
- $result = $this->Task->confirmAssociations($model, $associations);
- $this->assertTrue(empty($result['hasMany']));
- $this->assertTrue(empty($result['hasOne']));
- }
-
-/**
- * test that inOptions generates questions and only accepts a valid answer
- *
- * @return void
- */
- public function testInOptions() {
- $this->_useMockedOut();
-
- $options = array('one', 'two', 'three');
- $this->Task->expects($this->at(0))->method('out')->with('1. one');
- $this->Task->expects($this->at(1))->method('out')->with('2. two');
- $this->Task->expects($this->at(2))->method('out')->with('3. three');
- $this->Task->expects($this->at(3))->method('in')->will($this->returnValue(10));
-
- $this->Task->expects($this->at(4))->method('out')->with('1. one');
- $this->Task->expects($this->at(5))->method('out')->with('2. two');
- $this->Task->expects($this->at(6))->method('out')->with('3. three');
- $this->Task->expects($this->at(7))->method('in')->will($this->returnValue(2));
- $result = $this->Task->inOptions($options, 'Pick a number');
- $this->assertEquals(1, $result);
- }
-
-/**
- * test baking validation
- *
- * @return void
- */
- public function testBakeValidation() {
- $validate = array(
- 'name' => array(
- 'notempty' => 'notempty'
- ),
- 'email' => array(
- 'email' => 'email',
- ),
- 'some_date' => array(
- 'date' => 'date'
- ),
- 'some_time' => array(
- 'time' => 'time'
- )
- );
- $result = $this->Task->bake('BakeArticle', compact('validate'));
- $this->assertRegExp('/class BakeArticle extends AppModel \{/', $result);
- $this->assertRegExp('/\$validate \= array\(/', $result);
- $expected = <<< STRINGEND
-array(
- 'notempty' => array(
- 'rule' => array('notempty'),
- //'message' => 'Your custom message here',
- //'allowEmpty' => false,
- //'required' => false,
- //'last' => false, // Stop validation after this rule
- //'on' => 'create', // Limit validation to 'create' or 'update' operations
- ),
-STRINGEND;
- $this->assertRegExp('/' . preg_quote(str_replace("\r\n", "\n", $expected), '/') . '/', $result);
- }
-
-/**
- * test baking relations
- *
- * @return void
- */
- public function testBakeRelations() {
- $associations = array(
- 'belongsTo' => array(
- array(
- 'alias' => 'SomethingElse',
- 'className' => 'SomethingElse',
- 'foreignKey' => 'something_else_id',
- ),
- array(
- 'alias' => 'BakeUser',
- 'className' => 'BakeUser',
- 'foreignKey' => 'bake_user_id',
- ),
- ),
- 'hasOne' => array(
- array(
- 'alias' => 'OtherModel',
- 'className' => 'OtherModel',
- 'foreignKey' => 'other_model_id',
- ),
- ),
- 'hasMany' => array(
- array(
- 'alias' => 'BakeComment',
- 'className' => 'BakeComment',
- 'foreignKey' => 'parent_id',
- ),
- ),
- 'hasAndBelongsToMany' => array(
- array(
- 'alias' => 'BakeTag',
- 'className' => 'BakeTag',
- 'foreignKey' => 'bake_article_id',
- 'joinTable' => 'bake_articles_bake_tags',
- 'associationForeignKey' => 'bake_tag_id',
- ),
- )
- );
- $result = $this->Task->bake('BakeArticle', compact('associations'));
- $this->assertContains(' * @property BakeUser $BakeUser', $result);
- $this->assertContains(' * @property OtherModel $OtherModel', $result);
- $this->assertContains(' * @property BakeComment $BakeComment', $result);
- $this->assertContains(' * @property BakeTag $BakeTag', $result);
- $this->assertRegExp('/\$hasAndBelongsToMany \= array\(/', $result);
- $this->assertRegExp('/\$hasMany \= array\(/', $result);
- $this->assertRegExp('/\$belongsTo \= array\(/', $result);
- $this->assertRegExp('/\$hasOne \= array\(/', $result);
- $this->assertRegExp('/BakeTag/', $result);
- $this->assertRegExp('/OtherModel/', $result);
- $this->assertRegExp('/SomethingElse/', $result);
- $this->assertRegExp('/BakeComment/', $result);
- }
-
-/**
- * test bake() with a -plugin param
- *
- * @return void
- */
- public function testBakeWithPlugin() {
- $this->Task->plugin = 'ControllerTest';
-
- //fake plugin path
- CakePlugin::load('ControllerTest', array('path' => APP . 'Plugin' . DS . 'ControllerTest' . DS));
- $path = APP . 'Plugin' . DS . 'ControllerTest' . DS . 'Model' . DS . 'BakeArticle.php';
- $this->Task->expects($this->once())->method('createFile')
- ->with($path, $this->stringContains('BakeArticle extends ControllerTestAppModel'));
-
- $result = $this->Task->bake('BakeArticle', array(), array());
- $this->assertContains("App::uses('ControllerTestAppModel', 'ControllerTest.Model');", $result);
-
- $this->assertEquals(count(ClassRegistry::keys()), 0);
- $this->assertEquals(count(ClassRegistry::mapKeys()), 0);
- }
-
-/**
- * test that execute passes runs bake depending with named model.
- *
- * @return void
- */
- public function testExecuteWithNamedModel() {
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('BakeArticle');
- $filename = '/my/path/BakeArticle.php';
-
- $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(1));
- $this->Task->expects($this->once())->method('createFile')
- ->with($filename, $this->stringContains('class BakeArticle extends AppModel'));
-
- $this->Task->execute();
-
- $this->assertEquals(count(ClassRegistry::keys()), 0);
- $this->assertEquals(count(ClassRegistry::mapKeys()), 0);
- }
-
-/**
- * data provider for testExecuteWithNamedModelVariations
- *
- * @return void
- */
- public static function nameVariations() {
- return array(
- array('BakeArticles'), array('BakeArticle'), array('bake_article'), array('bake_articles')
- );
- }
-
-/**
- * test that execute passes with different inflections of the same name.
- *
- * @dataProvider nameVariations
- * @return void
- */
- public function testExecuteWithNamedModelVariations($name) {
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(1));
-
- $this->Task->args = array($name);
- $filename = '/my/path/BakeArticle.php';
-
- $this->Task->expects($this->at(0))->method('createFile')
- ->with($filename, $this->stringContains('class BakeArticle extends AppModel'));
- $this->Task->execute();
- }
-
-/**
- * test that execute with a model name picks up hasMany associations.
- *
- * @return void
- */
- public function testExecuteWithNamedModelHasManyCreated() {
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('BakeArticle');
- $filename = '/my/path/BakeArticle.php';
-
- $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(1));
- $this->Task->expects($this->at(0))->method('createFile')
- ->with($filename, $this->stringContains("'BakeComment' => array("));
-
- $this->Task->execute();
- }
-
-/**
- * test that execute runs all() when args[0] = all
- *
- * @return void
- */
- public function testExecuteIntoAll() {
- $count = count($this->Task->listAll('test'));
- if ($count != count($this->fixtures)) {
- $this->markTestSkipped('Additional tables detected.');
- }
-
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('all');
- $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(true));
-
- $this->Task->Fixture->expects($this->exactly(5))->method('bake');
- $this->Task->Test->expects($this->exactly(5))->method('bake');
-
- $filename = '/my/path/BakeArticle.php';
- $this->Task->expects($this->at(1))->method('createFile')
- ->with($filename, $this->stringContains('class BakeArticle'));
-
- $filename = '/my/path/BakeArticlesBakeTag.php';
- $this->Task->expects($this->at(2))->method('createFile')
- ->with($filename, $this->stringContains('class BakeArticlesBakeTag'));
-
- $filename = '/my/path/BakeComment.php';
- $this->Task->expects($this->at(3))->method('createFile')
- ->with($filename, $this->stringContains('class BakeComment'));
-
- $filename = '/my/path/BakeComment.php';
- $this->Task->expects($this->at(3))->method('createFile')
- ->with($filename, $this->stringContains('public $primaryKey = \'otherid\';'));
-
- $filename = '/my/path/BakeTag.php';
- $this->Task->expects($this->at(4))->method('createFile')
- ->with($filename, $this->stringContains('class BakeTag'));
-
- $filename = '/my/path/BakeTag.php';
- $this->Task->expects($this->at(4))->method('createFile')
- ->with($filename, $this->logicalNot($this->stringContains('public $primaryKey')));
-
- $filename = '/my/path/CategoryThread.php';
- $this->Task->expects($this->at(5))->method('createFile')
- ->with($filename, $this->stringContains('class CategoryThread'));
-
- $this->Task->execute();
-
- $this->assertEquals(count(ClassRegistry::keys()), 0);
- $this->assertEquals(count(ClassRegistry::mapKeys()), 0);
- }
-
-/**
- * test that odd tablenames arent inflected back from modelname
- *
- * @return void
- */
- public function testExecuteIntoAllOddTables() {
- $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Task = $this->getMock('ModelTask',
- array('in', 'err', '_stop', '_checkUnitTest', 'getAllTables', '_getModelObject', 'bake', 'bakeFixture'),
- array($out, $out, $in)
- );
- $this->_setupOtherMocks();
-
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('all');
- $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(true));
- $this->Task->expects($this->once())->method('getAllTables')->will($this->returnValue(array('bake_odd')));
- $object = new Model(array('name' => 'BakeOdd', 'table' => 'bake_odd', 'ds' => 'test'));
- $this->Task->expects($this->once())->method('_getModelObject')->with('BakeOdd', 'bake_odd')->will($this->returnValue($object));
- $this->Task->expects($this->at(3))->method('bake')->with($object, false)->will($this->returnValue(true));
- $this->Task->expects($this->once())->method('bakeFixture')->with('BakeOdd', 'bake_odd');
-
- $this->Task->execute();
-
- $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Task = $this->getMock('ModelTask',
- array('in', 'err', '_stop', '_checkUnitTest', 'getAllTables', '_getModelObject', 'doAssociations', 'doValidation', 'createFile'),
- array($out, $out, $in)
- );
- $this->_setupOtherMocks();
-
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('all');
- $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(true));
- $this->Task->expects($this->once())->method('getAllTables')->will($this->returnValue(array('bake_odd')));
- $object = new Model(array('name' => 'BakeOdd', 'table' => 'bake_odd', 'ds' => 'test'));
- $this->Task->expects($this->once())->method('_getModelObject')->will($this->returnValue($object));
- $this->Task->expects($this->once())->method('doAssociations')->will($this->returnValue(array()));
- $this->Task->expects($this->once())->method('doValidation')->will($this->returnValue(array()));
-
- $filename = '/my/path/BakeOdd.php';
- $this->Task->expects($this->once())->method('createFile')
- ->with($filename, $this->stringContains('class BakeOdd'));
-
- $filename = '/my/path/BakeOdd.php';
- $this->Task->expects($this->once())->method('createFile')
- ->with($filename, $this->stringContains('public $useTable = \'bake_odd\''));
-
- $this->Task->execute();
- }
-
-/**
- * test that odd tablenames arent inflected back from modelname
- *
- * @return void
- */
- public function testExecuteIntoBakeOddTables() {
- $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Task = $this->getMock('ModelTask',
- array('in', 'err', '_stop', '_checkUnitTest', 'getAllTables', '_getModelObject', 'bake', 'bakeFixture'),
- array($out, $out, $in)
- );
- $this->_setupOtherMocks();
-
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('BakeOdd');
- $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(true));
- $this->Task->expects($this->once())->method('getAllTables')->will($this->returnValue(array('articles', 'bake_odd')));
- $object = new Model(array('name' => 'BakeOdd', 'table' => 'bake_odd', 'ds' => 'test'));
- $this->Task->expects($this->once())->method('_getModelObject')->with('BakeOdd', 'bake_odd')->will($this->returnValue($object));
- $this->Task->expects($this->once())->method('bake')->with($object, false)->will($this->returnValue(true));
- $this->Task->expects($this->once())->method('bakeFixture')->with('BakeOdd', 'bake_odd');
-
- $this->Task->execute();
-
- $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Task = $this->getMock('ModelTask',
- array('in', 'err', '_stop', '_checkUnitTest', 'getAllTables', '_getModelObject', 'doAssociations', 'doValidation', 'createFile'),
- array($out, $out, $in)
- );
- $this->_setupOtherMocks();
-
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('BakeOdd');
- $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(true));
- $this->Task->expects($this->once())->method('getAllTables')->will($this->returnValue(array('articles', 'bake_odd')));
- $object = new Model(array('name' => 'BakeOdd', 'table' => 'bake_odd', 'ds' => 'test'));
- $this->Task->expects($this->once())->method('_getModelObject')->will($this->returnValue($object));
- $this->Task->expects($this->once())->method('doAssociations')->will($this->returnValue(array()));
- $this->Task->expects($this->once())->method('doValidation')->will($this->returnValue(array()));
-
- $filename = '/my/path/BakeOdd.php';
- $this->Task->expects($this->once())->method('createFile')
- ->with($filename, $this->stringContains('class BakeOdd'));
-
- $filename = '/my/path/BakeOdd.php';
- $this->Task->expects($this->once())->method('createFile')
- ->with($filename, $this->stringContains('public $useTable = \'bake_odd\''));
-
- $this->Task->execute();
- }
-
-/**
- * test that skipTables changes how all() works.
- *
- * @return void
- */
- public function testSkipTablesAndAll() {
- $count = count($this->Task->listAll('test'));
- if ($count != count($this->fixtures)) {
- $this->markTestSkipped('Additional tables detected.');
- }
-
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->args = array('all');
- $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(true));
- $this->Task->skipTables = array('bake_tags');
-
- $this->Task->Fixture->expects($this->exactly(4))->method('bake');
- $this->Task->Test->expects($this->exactly(4))->method('bake');
-
- $filename = '/my/path/BakeArticle.php';
- $this->Task->expects($this->at(1))->method('createFile')
- ->with($filename, $this->stringContains('class BakeArticle'));
-
- $filename = '/my/path/BakeArticlesBakeTag.php';
- $this->Task->expects($this->at(2))->method('createFile')
- ->with($filename, $this->stringContains('class BakeArticlesBakeTag'));
-
- $filename = '/my/path/BakeComment.php';
- $this->Task->expects($this->at(3))->method('createFile')
- ->with($filename, $this->stringContains('class BakeComment'));
-
- $filename = '/my/path/CategoryThread.php';
- $this->Task->expects($this->at(4))->method('createFile')
- ->with($filename, $this->stringContains('class CategoryThread'));
-
- $this->Task->execute();
- }
-
-/**
- * test the interactive side of bake.
- *
- * @return void
- */
- public function testExecuteIntoInteractive() {
- $tables = $this->Task->listAll('test');
- $article = array_search('bake_articles', $tables) + 1;
-
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
- $this->Task->interactive = true;
-
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls(
- $article, // article
- 'n', // no validation
- 'y', // associations
- 'y', // comment relation
- 'y', // user relation
- 'y', // tag relation
- 'n', // additional assocs
- 'y' // looks good?
- ));
- $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(true));
-
- $this->Task->Test->expects($this->once())->method('bake');
- $this->Task->Fixture->expects($this->once())->method('bake');
-
- $filename = '/my/path/BakeArticle.php';
-
- $this->Task->expects($this->once())->method('createFile')
- ->with($filename, $this->stringContains('class BakeArticle'));
-
- $this->Task->execute();
-
- $this->assertEquals(count(ClassRegistry::keys()), 0);
- $this->assertEquals(count(ClassRegistry::mapKeys()), 0);
- }
-
-/**
- * test using bake interactively with a table that does not exist.
- *
- * @return void
- */
- public function testExecuteWithNonExistantTableName() {
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
-
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls(
- 'Foobar', // Or type in the name of the model
- 'y', // Do you want to use this table
- 'n' // Doesn't exist, continue anyway?
- ));
-
- $this->Task->execute();
- }
-
-/**
- * test using bake interactively with a table that does not exist.
- *
- * @return void
- */
- public function testForcedExecuteWithNonExistantTableName() {
- $this->Task->connection = 'test';
- $this->Task->path = '/my/path/';
-
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls(
- 'Foobar', // Or type in the name of the model
- 'y', // Do you want to use this table
- 'y', // Doesn't exist, continue anyway?
- 'id', // Primary key
- 'y' // Looks good?
- ));
-
- $this->Task->execute();
- }
-
-}
diff --git a/lib/Cake/Test/Case/Console/Command/Task/PluginTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/PluginTaskTest.php
deleted file mode 100644
index 3a02a04792d..00000000000
--- a/lib/Cake/Test/Case/Console/Command/Task/PluginTaskTest.php
+++ /dev/null
@@ -1,193 +0,0 @@
-out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $this->in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Task = $this->getMock('PluginTask',
- array('in', 'err', 'createFile', '_stop', 'clear'),
- array($this->out, $this->out, $this->in)
- );
- $this->Task->path = TMP . 'tests' . DS;
-
- $this->_paths = $paths = App::path('plugins');
- foreach ($paths as $i => $p) {
- if (!is_dir($p)) {
- array_splice($paths, $i, 1);
- }
- }
- $this->_testPath = array_push($paths, TMP . 'tests' . DS);
- App::build(array('plugins' => $paths));
- }
-
-/**
- * test bake()
- *
- * @return void
- */
- public function testBakeFoldersAndFiles() {
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue($this->_testPath));
- $this->Task->expects($this->at(1))->method('in')->will($this->returnValue('y'));
-
- $path = $this->Task->path . 'BakeTestPlugin';
-
- $file = $path . DS . 'Controller' . DS . 'BakeTestPluginAppController.php';
- $this->Task->expects($this->at(2))->method('createFile')
- ->with($file, new PHPUnit_Framework_Constraint_IsAnything());
-
- $file = $path . DS . 'Model' . DS . 'BakeTestPluginAppModel.php';
- $this->Task->expects($this->at(3))->method('createFile')
- ->with($file, new PHPUnit_Framework_Constraint_IsAnything());
-
- $this->Task->bake('BakeTestPlugin');
-
- $path = $this->Task->path . 'BakeTestPlugin';
- $this->assertTrue(is_dir($path), 'No plugin dir %s');
-
- $directories = array(
- 'Config' . DS . 'Schema',
- 'Model' . DS . 'Behavior',
- 'Model' . DS . 'Datasource',
- 'Console' . DS . 'Command' . DS . 'Task',
- 'Controller' . DS . 'Component',
- 'Lib',
- 'View' . DS . 'Helper',
- 'Test' . DS . 'Case' . DS . 'Controller' . DS . 'Component',
- 'Test' . DS . 'Case' . DS . 'View' . DS . 'Helper',
- 'Test' . DS . 'Case' . DS . 'Model' . DS . 'Behavior',
- 'Test' . DS . 'Fixture',
- 'Vendor',
- 'webroot'
- );
- foreach ($directories as $dir) {
- $this->assertTrue(is_dir($path . DS . $dir), 'Missing directory for ' . $dir);
- }
-
- $Folder = new Folder($this->Task->path . 'BakeTestPlugin');
- $Folder->delete();
- }
-
-/**
- * test execute with no args, flowing into interactive,
- *
- * @return void
- */
- public function testExecuteWithNoArgs() {
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('TestPlugin'));
- $this->Task->expects($this->at(1))->method('in')->will($this->returnValue($this->_testPath));
- $this->Task->expects($this->at(2))->method('in')->will($this->returnValue('y'));
-
- $path = $this->Task->path . 'TestPlugin';
- $file = $path . DS . 'Controller' . DS . 'TestPluginAppController.php';
-
- $this->Task->expects($this->at(3))->method('createFile')
- ->with($file, new PHPUnit_Framework_Constraint_IsAnything());
-
- $file = $path . DS . 'Model' . DS . 'TestPluginAppModel.php';
- $this->Task->expects($this->at(4))->method('createFile')
- ->with($file, new PHPUnit_Framework_Constraint_IsAnything());
-
- $this->Task->args = array();
- $this->Task->execute();
-
- $Folder = new Folder($path);
- $Folder->delete();
- }
-
-/**
- * Test Execute
- *
- * @return void
- */
- public function testExecuteWithOneArg() {
- $this->Task->expects($this->at(0))->method('in')
- ->will($this->returnValue($this->_testPath));
- $this->Task->expects($this->at(1))->method('in')
- ->will($this->returnValue('y'));
-
- $path = $this->Task->path . 'BakeTestPlugin';
- $file = $path . DS . 'Controller' . DS . 'BakeTestPluginAppController.php';
- $this->Task->expects($this->at(2))->method('createFile')
- ->with($file, new PHPUnit_Framework_Constraint_IsAnything());
-
- $path = $this->Task->path . 'BakeTestPlugin';
- $file = $path . DS . 'Model' . DS . 'BakeTestPluginAppModel.php';
- $this->Task->expects($this->at(3))->method('createFile')
- ->with($file, new PHPUnit_Framework_Constraint_IsAnything());
-
- $this->Task->args = array('BakeTestPlugin');
-
- $this->Task->execute();
-
- $Folder = new Folder($this->Task->path . 'BakeTestPlugin');
- $Folder->delete();
- }
-
-/**
- * Test that findPath ignores paths that don't exist.
- *
- * @return void
- */
- public function testFindPathNonExistant() {
- $paths = App::path('plugins');
- $last = count($paths);
- $paths[] = '/fake/path';
-
- $this->Task = $this->getMock('PluginTask',
- array('in', 'out', 'err', 'createFile', '_stop'),
- array($this->out, $this->out, $this->in)
- );
- $this->Task->path = TMP . 'tests' . DS;
-
- // Make sure the added path is filtered out.
- $this->Task->expects($this->exactly($last))
- ->method('out');
-
- $this->Task->expects($this->once())
- ->method('in')
- ->will($this->returnValue($last));
-
- $this->Task->findPath($paths);
- }
-}
diff --git a/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php
deleted file mode 100644
index 8fd1b33f081..00000000000
--- a/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php
+++ /dev/null
@@ -1,369 +0,0 @@
-getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Task = $this->getMock('ProjectTask',
- array('in', 'err', 'createFile', '_stop'),
- array($out, $out, $in)
- );
- $this->Task->path = TMP . 'tests' . DS;
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
-
- $Folder = new Folder($this->Task->path . 'bake_test_app');
- $Folder->delete();
- unset($this->Task);
- }
-
-/**
- * creates a test project that is used for testing project task.
- *
- * @return void
- */
- protected function _setupTestProject() {
- $skel = CAKE . 'Console' . DS . 'Templates' . DS . 'skel';
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y'));
- $this->Task->bake($this->Task->path . 'bake_test_app', $skel);
- }
-
-/**
- * test bake() method and directory creation.
- *
- * @return void
- */
- public function testBake() {
- $this->_setupTestProject();
- $path = $this->Task->path . 'bake_test_app';
-
- $this->assertTrue(is_dir($path), 'No project dir %s');
- $dirs = array(
- 'Config',
- 'Config' . DS . 'Schema',
- 'Console',
- 'Console' . DS . 'Command',
- 'Console' . DS . 'Templates',
- 'Console' . DS . 'Command' . DS . 'Task',
- 'Controller',
- 'Controller' . DS . 'Component',
- 'Locale',
- 'Model',
- 'Model' . DS . 'Behavior',
- 'Model' . DS . 'Datasource',
- 'Plugin',
- 'Test',
- 'Test' . DS . 'Case',
- 'Test' . DS . 'Case' . DS . 'Controller',
- 'Test' . DS . 'Case' . DS . 'Controller' . DS . 'Component',
- 'Test' . DS . 'Case' . DS . 'Model',
- 'Test' . DS . 'Case' . DS . 'Model' . DS . 'Behavior',
- 'Test' . DS . 'Fixture',
- 'Vendor',
- 'View',
- 'View' . DS . 'Helper',
- 'tmp',
- 'tmp' . DS . 'cache',
- 'tmp' . DS . 'cache' . DS . 'models',
- 'tmp' . DS . 'cache' . DS . 'persistent',
- 'tmp' . DS . 'cache' . DS . 'views',
- 'tmp' . DS . 'logs',
- 'tmp' . DS . 'sessions',
- 'tmp' . DS . 'tests',
- 'webroot',
- 'webroot' . DS . 'css',
- 'webroot' . DS . 'files',
- 'webroot' . DS . 'img',
- 'webroot' . DS . 'js',
-
- );
- foreach ($dirs as $dir) {
- $this->assertTrue(is_dir($path . DS . $dir), 'Missing ' . $dir);
- }
- }
-
-/**
- * test bake with an absolute path.
- *
- * @return void
- */
- public function testExecuteWithAbsolutePath() {
- $path = $this->Task->args[0] = TMP . 'tests' . DS . 'bake_test_app';
- $this->Task->params['skel'] = CAKE . 'Console' . DS . 'Templates' . DS . 'skel';
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y'));
- $this->Task->execute();
-
- $this->assertTrue(is_dir($this->Task->args[0]), 'No project dir');
- $File = new File($path . DS . 'webroot' . DS . 'index.php');
- $contents = $File->read();
- $this->assertRegExp('/define\(\'CAKE_CORE_INCLUDE_PATH\', .*?DS/', $contents);
- $File = new File($path . DS . 'webroot' . DS . 'test.php');
- $contents = $File->read();
- $this->assertRegExp('/define\(\'CAKE_CORE_INCLUDE_PATH\', .*?DS/', $contents);
- }
-
-/**
- * test bake with CakePHP on the include path. The constants should remain commented out.
- *
- * @return void
- */
- public function testExecuteWithCakeOnIncludePath() {
- if (!function_exists('ini_set')) {
- $this->markTestAsSkipped('Not access to ini_set, cannot proceed.');
- }
- $restore = ini_get('include_path');
- ini_set('include_path', CAKE_CORE_INCLUDE_PATH . PATH_SEPARATOR . $restore);
-
- $path = $this->Task->args[0] = TMP . 'tests' . DS . 'bake_test_app';
- $this->Task->params['skel'] = CAKE . 'Console' . DS . 'Templates' . DS . 'skel';
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y'));
- $this->Task->execute();
-
- $this->assertTrue(is_dir($this->Task->args[0]), 'No project dir');
- $contents = file_get_contents($path . DS . 'webroot' . DS . 'index.php');
- $this->assertRegExp('#//define\(\'CAKE_CORE_INCLUDE_PATH#', $contents);
-
- $contents = file_get_contents($path . DS . 'webroot' . DS . 'test.php');
- $this->assertRegExp('#//define\(\'CAKE_CORE_INCLUDE_PATH#', $contents);
-
- ini_set('include_path', $restore);
- }
-
-/**
- * test bake() method with -empty flag, directory creation and empty files.
- *
- * @return void
- */
- public function testBakeEmptyFlag() {
- $this->Task->params['empty'] = true;
- $this->_setupTestProject();
- $path = $this->Task->path . 'bake_test_app';
-
- $empty = array(
- 'Console' . DS . 'Command' . DS . 'Task' => 'empty',
- 'Controller' . DS . 'Component' => 'empty',
- 'Lib' => 'empty',
- 'Model' . DS . 'Behavior' => 'empty',
- 'Model' . DS . 'Datasource' => 'empty',
- 'Plugin' => 'empty',
- 'Test' . DS . 'Case' . DS . 'Model' . DS . 'Behavior' => 'empty',
- 'Test' . DS . 'Case' . DS . 'Controller' . DS . 'Component' => 'empty',
- 'Test' . DS . 'Case' . DS . 'View' . DS . 'Helper' => 'empty',
- 'Test' . DS . 'Fixture' => 'empty',
- 'Vendor' => 'empty',
- 'View' . DS . 'Elements' => 'empty',
- 'View' . DS . 'Scaffolds' => 'empty',
- 'tmp' . DS . 'cache' . DS . 'models' => 'empty',
- 'tmp' . DS . 'cache' . DS . 'persistent' => 'empty',
- 'tmp' . DS . 'cache' . DS . 'views' => 'empty',
- 'tmp' . DS . 'logs' => 'empty',
- 'tmp' . DS . 'sessions' => 'empty',
- 'tmp' . DS . 'tests' => 'empty',
- 'webroot' . DS . 'js' => 'empty',
- 'webroot' . DS . 'files' => 'empty'
- );
-
- foreach ($empty as $dir => $file) {
- $this->assertTrue(is_file($path . DS . $dir . DS . $file), sprintf('Missing %s file in %s', $file, $dir));
- }
- }
-
-/**
- * test generation of Security.salt
- *
- * @return void
- */
- public function testSecuritySaltGeneration() {
- $this->_setupTestProject();
-
- $path = $this->Task->path . 'bake_test_app' . DS;
- $result = $this->Task->securitySalt($path);
- $this->assertTrue($result);
-
- $File = new File($path . 'Config' . DS . 'core.php');
- $contents = $File->read();
- $this->assertNotRegExp('/DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi/', $contents, 'Default Salt left behind. %s');
- }
-
-/**
- * test generation of Security.cipherSeed
- *
- * @return void
- */
- public function testSecurityCipherSeedGeneration() {
- $this->_setupTestProject();
-
- $path = $this->Task->path . 'bake_test_app' . DS;
- $result = $this->Task->securityCipherSeed($path);
- $this->assertTrue($result);
-
- $File = new File($path . 'Config' . DS . 'core.php');
- $contents = $File->read();
- $this->assertNotRegExp('/76859309657453542496749683645/', $contents, 'Default CipherSeed left behind. %s');
- }
-
-/**
- * Test that index.php is generated correctly.
- *
- * @return void
- */
- public function testIndexPhpGeneration() {
- $this->_setupTestProject();
-
- $path = $this->Task->path . 'bake_test_app' . DS;
- $this->Task->corePath($path);
-
- $File = new File($path . 'webroot' . DS . 'index.php');
- $contents = $File->read();
- $this->assertNotRegExp('/define\(\'CAKE_CORE_INCLUDE_PATH\', ROOT/', $contents);
- $File = new File($path . 'webroot' . DS . 'test.php');
- $contents = $File->read();
- $this->assertNotRegExp('/define\(\'CAKE_CORE_INCLUDE_PATH\', ROOT/', $contents);
- }
-
-/**
- * test getPrefix method, and that it returns Routing.prefix or writes to config file.
- *
- * @return void
- */
- public function testGetPrefix() {
- Configure::write('Routing.prefixes', array('admin'));
- $result = $this->Task->getPrefix();
- $this->assertEquals('admin_', $result);
-
- Configure::write('Routing.prefixes', null);
- $this->_setupTestProject();
- $this->Task->configPath = $this->Task->path . 'bake_test_app' . DS . 'Config' . DS;
- $this->Task->expects($this->once())->method('in')->will($this->returnValue('super_duper_admin'));
-
- $result = $this->Task->getPrefix();
- $this->assertEquals('super_duper_admin_', $result);
-
- $File = new File($this->Task->configPath . 'core.php');
- $File->delete();
- }
-
-/**
- * test cakeAdmin() writing core.php
- *
- * @return void
- */
- public function testCakeAdmin() {
- $File = new File(APP . 'Config' . DS . 'core.php');
- $contents = $File->read();
- $File = new File(TMP . 'tests' . DS . 'core.php');
- $File->write($contents);
-
- Configure::write('Routing.prefixes', null);
- $this->Task->configPath = TMP . 'tests' . DS;
- $result = $this->Task->cakeAdmin('my_prefix');
- $this->assertTrue($result);
-
- $this->assertEquals(Configure::read('Routing.prefixes'), array('my_prefix'));
- $File->delete();
- }
-
-/**
- * test getting the prefix with more than one prefix setup
- *
- * @return void
- */
- public function testGetPrefixWithMultiplePrefixes() {
- Configure::write('Routing.prefixes', array('admin', 'ninja', 'shinobi'));
- $this->_setupTestProject();
- $this->Task->configPath = $this->Task->path . 'bake_test_app' . DS . 'Config' . DS;
- $this->Task->expects($this->once())->method('in')->will($this->returnValue(2));
-
- $result = $this->Task->getPrefix();
- $this->assertEquals('ninja_', $result);
- }
-
-/**
- * Test execute method with one param to destination folder.
- *
- * @return void
- */
- public function testExecute() {
- $this->Task->params['skel'] = CAKE . 'Console' . DS . 'Templates' . DS . 'skel';
- $this->Task->params['working'] = TMP . 'tests' . DS;
-
- $path = $this->Task->path . 'bake_test_app';
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue($path));
- $this->Task->expects($this->at(1))->method('in')->will($this->returnValue('y'));
-
- $this->Task->execute();
- $this->assertTrue(is_dir($path), 'No project dir');
- $this->assertTrue(is_dir($path . DS . 'Controller'), 'No controllers dir ');
- $this->assertTrue(is_dir($path . DS . 'Controller' . DS . 'Component'), 'No components dir ');
- $this->assertTrue(is_dir($path . DS . 'Model'), 'No models dir');
- $this->assertTrue(is_dir($path . DS . 'View'), 'No views dir');
- $this->assertTrue(is_dir($path . DS . 'View' . DS . 'Helper'), 'No helpers dir');
- $this->assertTrue(is_dir($path . DS . 'Test'), 'No tests dir');
- $this->assertTrue(is_dir($path . DS . 'Test' . DS . 'Case'), 'No cases dir');
- $this->assertTrue(is_dir($path . DS . 'Test' . DS . 'Fixture'), 'No fixtures dir');
- }
-
-/**
- * test console path
- *
- * @return void
- */
- public function testConsolePath() {
- $this->_setupTestProject();
-
- $path = $this->Task->path . 'bake_test_app' . DS;
- $result = $this->Task->consolePath($path);
- $this->assertTrue($result);
-
- $File = new File($path . 'Console' . DS . 'cake.php');
- $contents = $File->read();
- $this->assertNotRegExp('/__CAKE_PATH__/', $contents, 'Console path placeholder left behind.');
- }
-}
diff --git a/lib/Cake/Test/Case/Console/Command/Task/TemplateTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/TemplateTaskTest.php
deleted file mode 100644
index ad458936019..00000000000
--- a/lib/Cake/Test/Case/Console/Command/Task/TemplateTaskTest.php
+++ /dev/null
@@ -1,165 +0,0 @@
-getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Task = $this->getMock('TemplateTask',
- array('in', 'err', 'createFile', '_stop', 'clear'),
- array($out, $out, $in)
- );
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- unset($this->Task);
- }
-
-/**
- * test that set sets variables
- *
- * @return void
- */
- public function testSet() {
- $this->Task->set('one', 'two');
- $this->assertTrue(isset($this->Task->templateVars['one']));
- $this->assertEquals('two', $this->Task->templateVars['one']);
-
- $this->Task->set(array('one' => 'three', 'four' => 'five'));
- $this->assertTrue(isset($this->Task->templateVars['one']));
- $this->assertEquals('three', $this->Task->templateVars['one']);
- $this->assertTrue(isset($this->Task->templateVars['four']));
- $this->assertEquals('five', $this->Task->templateVars['four']);
-
- $this->Task->templateVars = array();
- $this->Task->set(array(3 => 'three', 4 => 'four'));
- $this->Task->set(array(1 => 'one', 2 => 'two'));
- $expected = array(3 => 'three', 4 => 'four', 1 => 'one', 2 => 'two');
- $this->assertEquals($expected, $this->Task->templateVars);
- }
-
-/**
- * test finding themes installed in
- *
- * @return void
- */
- public function testFindingInstalledThemesForBake() {
- $consoleLibs = CAKE . 'Console' . DS;
- $this->Task->initialize();
- $this->assertEquals($this->Task->templatePaths['default'], $consoleLibs . 'Templates' . DS . 'default' . DS);
- }
-
-/**
- * test getting the correct theme name. Ensure that with only one theme, or a theme param
- * that the user is not bugged. If there are more, find and return the correct theme name
- *
- * @return void
- */
- public function testGetThemePath() {
- $defaultTheme = CAKE . 'Console' . DS . 'Templates' . DS . 'default' . DS;
- $this->Task->templatePaths = array('default' => $defaultTheme);
-
- $this->Task->expects($this->exactly(1))->method('in')->will($this->returnValue('1'));
-
- $result = $this->Task->getThemePath();
- $this->assertEquals($defaultTheme, $result);
-
- $this->Task->templatePaths = array('default' => $defaultTheme, 'other' => '/some/path');
- $this->Task->params['theme'] = 'other';
- $result = $this->Task->getThemePath();
- $this->assertEquals('/some/path', $result);
-
- $this->Task->params = array();
- $result = $this->Task->getThemePath();
- $this->assertEquals($defaultTheme, $result);
- $this->assertEquals('default', $this->Task->params['theme']);
- }
-
-/**
- * test generate
- *
- * @return void
- */
- public function testGenerate() {
- App::build(array(
- 'Console' => array(
- CAKE . 'Test' . DS . 'test_app' . DS . 'Console' . DS
- )
- ));
- $this->Task->initialize();
- $this->Task->expects($this->any())->method('in')->will($this->returnValue(1));
-
- $result = $this->Task->generate('classes', 'test_object', array('test' => 'foo'));
- $expected = "I got rendered\nfoo";
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test generate with a missing template in the chosen theme.
- * ensure fallback to default works.
- *
- * @return void
- */
- public function testGenerateWithTemplateFallbacks() {
- App::build(array(
- 'Console' => array(
- CAKE . 'Test' . DS . 'test_app' . DS . 'Console' . DS,
- CAKE_CORE_INCLUDE_PATH . DS . 'console' . DS
- )
- ));
- $this->Task->initialize();
- $this->Task->params['theme'] = 'test';
- $this->Task->set(array(
- 'model' => 'Article',
- 'table' => 'articles',
- 'import' => false,
- 'records' => false,
- 'schema' => ''
- ));
- $result = $this->Task->generate('classes', 'fixture');
- $this->assertRegExp('/ArticleFixture extends CakeTestFixture/', $result);
- }
-}
diff --git a/lib/Cake/Test/Case/Console/Command/Task/TestTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/TestTaskTest.php
deleted file mode 100644
index 767fc4e3522..00000000000
--- a/lib/Cake/Test/Case/Console/Command/Task/TestTaskTest.php
+++ /dev/null
@@ -1,727 +0,0 @@
- array(
- 'className' => 'TestTask.TestTaskComment',
- 'foreignKey' => 'article_id',
- )
- );
-
-/**
- * Has and Belongs To Many Associations
- *
- * @var array
- */
- public $hasAndBelongsToMany = array(
- 'Tag' => array(
- 'className' => 'TestTaskTag',
- 'joinTable' => 'articles_tags',
- 'foreignKey' => 'article_id',
- 'associationForeignKey' => 'tag_id'
- )
- );
-
-/**
- * Example public method
- *
- * @return void
- */
- public function doSomething() {
- }
-
-/**
- * Example Secondary public method
- *
- * @return void
- */
- public function doSomethingElse() {
- }
-
-/**
- * Example protected method
- *
- * @return void
- */
- protected function _innerMethod() {
- }
-
-}
-
-/**
- * Tag Testing Model
- *
- * @package Cake.Test.Case.Console.Command.Task
- * @package Cake.Test.Case.Console.Command.Task
- */
-class TestTaskTag extends Model {
-
-/**
- * Model name
- *
- * @var string
- */
- public $name = 'TestTaskTag';
-
-/**
- * Table name
- *
- * @var string
- */
- public $useTable = 'tags';
-
-/**
- * Has and Belongs To Many Associations
- *
- * @var array
- */
- public $hasAndBelongsToMany = array(
- 'Article' => array(
- 'className' => 'TestTaskArticle',
- 'joinTable' => 'articles_tags',
- 'foreignKey' => 'tag_id',
- 'associationForeignKey' => 'article_id'
- )
- );
-}
-
-/**
- * Simulated plugin
- *
- * @package Cake.Test.Case.Console.Command.Task
- * @package Cake.Test.Case.Console.Command.Task
- */
-class TestTaskAppModel extends Model {
-}
-
-/**
- * Testing AppMode (TaskComment)
- *
- * @package Cake.Test.Case.Console.Command.Task
- * @package Cake.Test.Case.Console.Command.Task
- */
-class TestTaskComment extends TestTaskAppModel {
-
-/**
- * Model name
- *
- * @var string
- */
- public $name = 'TestTaskComment';
-
-/**
- * Table name
- *
- * @var string
- */
- public $useTable = 'comments';
-
-/**
- * Belongs To Associations
- *
- * @var array
- */
- public $belongsTo = array(
- 'Article' => array(
- 'className' => 'TestTaskArticle',
- 'foreignKey' => 'article_id',
- )
- );
-}
-
-/**
- * Test Task Comments Controller
- *
- * @package Cake.Test.Case.Console.Command.Task
- * @package Cake.Test.Case.Console.Command.Task
- */
-class TestTaskCommentsController extends Controller {
-
-/**
- * Controller Name
- *
- * @var string
- */
- public $name = 'TestTaskComments';
-
-/**
- * Models to use
- *
- * @var array
- */
- public $uses = array('TestTaskComment', 'TestTaskTag');
-}
-
-/**
- * TestTaskTest class
- *
- * @package Cake.Test.Case.Console.Command.Task
- */
-class TestTaskTest extends CakeTestCase {
-
-/**
- * Fixtures
- *
- * @var string
- */
- public $fixtures = array('core.article', 'core.comment', 'core.articles_tag', 'core.tag');
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Task = $this->getMock('TestTask',
- array('in', 'err', 'createFile', '_stop', 'isLoadableClass'),
- array($out, $out, $in)
- );
- $this->Task->name = 'Test';
- $this->Task->Template = new TemplateTask($out, $out, $in);
- }
-
-/**
- * endTest method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- unset($this->Task);
- CakePlugin::unload();
- }
-
-/**
- * Test that file path generation doesn't continuously append paths.
- *
- * @return void
- */
- public function testFilePathGenerationModelRepeated() {
- $this->Task->expects($this->never())->method('err');
- $this->Task->expects($this->never())->method('_stop');
-
- $file = TESTS . 'Case' . DS . 'Model' . DS . 'MyClassTest.php';
-
- $this->Task->expects($this->at(1))->method('createFile')
- ->with($file, $this->anything());
-
- $this->Task->expects($this->at(3))->method('createFile')
- ->with($file, $this->anything());
-
- $file = TESTS . 'Case' . DS . 'Controller' . DS . 'CommentsControllerTest.php';
- $this->Task->expects($this->at(5))->method('createFile')
- ->with($file, $this->anything());
-
- $this->Task->bake('Model', 'MyClass');
- $this->Task->bake('Model', 'MyClass');
- $this->Task->bake('Controller', 'Comments');
- }
-
-/**
- * Test that method introspection pulls all relevant non parent class
- * methods into the test case.
- *
- * @return void
- */
- public function testMethodIntrospection() {
- $result = $this->Task->getTestableMethods('TestTaskArticle');
- $expected = array('dosomething', 'dosomethingelse');
- $this->assertEquals($expected, array_map('strtolower', $result));
- }
-
-/**
- * test that the generation of fixtures works correctly.
- *
- * @return void
- */
- public function testFixtureArrayGenerationFromModel() {
- $subject = ClassRegistry::init('TestTaskArticle');
- $result = $this->Task->generateFixtureList($subject);
- $expected = array('plugin.test_task.test_task_comment', 'app.articles_tags',
- 'app.test_task_article', 'app.test_task_tag');
-
- $this->assertEquals(sort($expected), sort($result));
- }
-
-/**
- * test that the generation of fixtures works correctly.
- *
- * @return void
- */
- public function testFixtureArrayGenerationFromController() {
- $subject = new TestTaskCommentsController();
- $result = $this->Task->generateFixtureList($subject);
- $expected = array('plugin.test_task.test_task_comment', 'app.articles_tags',
- 'app.test_task_article', 'app.test_task_tag');
-
- $this->assertEquals(sort($expected), sort($result));
- }
-
-/**
- * test user interaction to get object type
- *
- * @return void
- */
- public function testGetObjectType() {
- $this->Task->expects($this->once())->method('_stop');
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('q'));
- $this->Task->expects($this->at(2))->method('in')->will($this->returnValue(2));
-
- $this->Task->getObjectType();
-
- $result = $this->Task->getObjectType();
- $this->assertEquals($this->Task->classTypes['Controller'], $result);
- }
-
-/**
- * creating test subjects should clear the registry so the registry is always fresh
- *
- * @return void
- */
- public function testRegistryClearWhenBuildingTestObjects() {
- ClassRegistry::flush();
- $model = ClassRegistry::init('TestTaskComment');
- $model->bindModel(array(
- 'belongsTo' => array(
- 'Random' => array(
- 'className' => 'TestTaskArticle',
- 'foreignKey' => 'article_id',
- )
- )
- ));
- $keys = ClassRegistry::keys();
- $this->assertTrue(in_array('test_task_comment', $keys));
- $object = $this->Task->buildTestSubject('Model', 'TestTaskComment');
-
- $keys = ClassRegistry::keys();
- $this->assertFalse(in_array('random', $keys));
- }
-
-/**
- * test that getClassName returns the user choice as a classname.
- *
- * @return void
- */
- public function testGetClassName() {
- $objects = App::objects('model');
- $this->skipIf(empty($objects), 'No models in app.');
-
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('MyCustomClass'));
- $this->Task->expects($this->at(1))->method('in')->will($this->returnValue(1));
-
- $result = $this->Task->getClassName('Model');
- $this->assertEquals('MyCustomClass', $result);
-
- $result = $this->Task->getClassName('Model');
- $options = App::objects('model');
- $this->assertEquals($options[0], $result);
- }
-
-/**
- * Test the user interaction for defining additional fixtures.
- *
- * @return void
- */
- public function testGetUserFixtures() {
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y'));
- $this->Task->expects($this->at(1))->method('in')
- ->will($this->returnValue('app.pizza, app.topping, app.side_dish'));
-
- $result = $this->Task->getUserFixtures();
- $expected = array('app.pizza', 'app.topping', 'app.side_dish');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test that resolving classnames works
- *
- * @return void
- */
- public function testGetRealClassname() {
- $result = $this->Task->getRealClassname('Model', 'Post');
- $this->assertEquals('Post', $result);
-
- $result = $this->Task->getRealClassname('Controller', 'Posts');
- $this->assertEquals('PostsController', $result);
-
- $result = $this->Task->getRealClassname('Controller', 'PostsController');
- $this->assertEquals('PostsController', $result);
-
- $result = $this->Task->getRealClassname('Controller', 'AlertTypes');
- $this->assertEquals('AlertTypesController', $result);
-
- $result = $this->Task->getRealClassname('Helper', 'Form');
- $this->assertEquals('FormHelper', $result);
-
- $result = $this->Task->getRealClassname('Helper', 'FormHelper');
- $this->assertEquals('FormHelper', $result);
-
- $result = $this->Task->getRealClassname('Behavior', 'Containable');
- $this->assertEquals('ContainableBehavior', $result);
-
- $result = $this->Task->getRealClassname('Behavior', 'ContainableBehavior');
- $this->assertEquals('ContainableBehavior', $result);
-
- $result = $this->Task->getRealClassname('Component', 'Auth');
- $this->assertEquals('AuthComponent', $result);
- }
-
-/**
- * test baking files. The conditionally run tests are known to fail in PHP4
- * as PHP4 classnames are all lower case, breaking the plugin path inflection.
- *
- * @return void
- */
- public function testBakeModelTest() {
- $this->Task->expects($this->once())->method('createFile')->will($this->returnValue(true));
- $this->Task->expects($this->once())->method('isLoadableClass')->will($this->returnValue(true));
-
- $result = $this->Task->bake('Model', 'TestTaskArticle');
-
- $this->assertContains("App::uses('TestTaskArticle', 'Model')", $result);
- $this->assertContains('class TestTaskArticleTestCase extends CakeTestCase', $result);
-
- $this->assertContains('function setUp()', $result);
- $this->assertContains("\$this->TestTaskArticle = ClassRegistry::init('TestTaskArticle')", $result);
-
- $this->assertContains('function tearDown()', $result);
- $this->assertContains('unset($this->TestTaskArticle)', $result);
-
- $this->assertContains('function testDoSomething()', $result);
- $this->assertContains('function testDoSomethingElse()', $result);
-
- $this->assertContains("'app.test_task_article'", $result);
- $this->assertContains("'plugin.test_task.test_task_comment'", $result);
- $this->assertContains("'app.test_task_tag'", $result);
- $this->assertContains("'app.articles_tag'", $result);
- }
-
-/**
- * test baking controller test files, ensure that the stub class is generated.
- * Conditional assertion is known to fail on PHP4 as classnames are all lower case
- * causing issues with inflection of path name from classname.
- *
- * @return void
- */
- public function testBakeControllerTest() {
- $this->Task->expects($this->once())->method('createFile')->will($this->returnValue(true));
- $this->Task->expects($this->once())->method('isLoadableClass')->will($this->returnValue(true));
-
- $result = $this->Task->bake('Controller', 'TestTaskComments');
-
- $this->assertContains("App::uses('TestTaskCommentsController', 'Controller')", $result);
- $this->assertContains('class TestTaskCommentsControllerTestCase extends CakeTestCase', $result);
-
- $this->assertContains('class TestTestTaskCommentsController extends TestTaskCommentsController', $result);
- $this->assertContains('public $autoRender = false', $result);
- $this->assertContains('function redirect($url, $status = null, $exit = true)', $result);
-
- $this->assertContains('function setUp()', $result);
- $this->assertContains("\$this->TestTaskComments = new TestTestTaskCommentsController()", $result);
- $this->assertContains("\$this->TestTaskComments->constructClasses()", $result);
-
- $this->assertContains('function tearDown()', $result);
- $this->assertContains('unset($this->TestTaskComments)', $result);
-
- $this->assertContains("'app.test_task_article'", $result);
- $this->assertContains("'plugin.test_task.test_task_comment'", $result);
- $this->assertContains("'app.test_task_tag'", $result);
- $this->assertContains("'app.articles_tag'", $result);
- }
-
-/**
- * test Constructor generation ensure that constructClasses is called for controllers
- *
- * @return void
- */
- public function testGenerateConstructor() {
- $result = $this->Task->generateConstructor('controller', 'PostsController');
- $expected = array('', "new TestPostsController();\n", "\$this->Posts->constructClasses();\n");
- $this->assertEquals($expected, $result);
-
- $result = $this->Task->generateConstructor('model', 'Post');
- $expected = array('', "ClassRegistry::init('Post');\n", '');
- $this->assertEquals($expected, $result);
-
- $result = $this->Task->generateConstructor('helper', 'FormHelper');
- $expected = array("\$View = new View();\n", "new FormHelper(\$View);\n", '');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * Test generateUses()
- */
- public function testGenerateUses() {
- $result = $this->Task->generateUses('model', 'Model', 'Post');
- $expected = array(
- array('Post', 'Model')
- );
- $this->assertEquals($expected, $result);
-
- $result = $this->Task->generateUses('controller', 'Controller', 'PostsController');
- $expected = array(
- array('PostsController', 'Controller')
- );
- $this->assertEquals($expected, $result);
-
- $result = $this->Task->generateUses('helper', 'View/Helper', 'FormHelper');
- $expected = array(
- array('View', 'View'),
- array('Helper', 'View'),
- array('FormHelper', 'View/Helper'),
- );
- $this->assertEquals($expected, $result);
-
- $result = $this->Task->generateUses('component', 'Controller/Component', 'AuthComponent');
- $expected = array(
- array('ComponentCollection', 'Controller'),
- array('Component', 'Controller'),
- array('AuthComponent', 'Controller/Component')
- );
- $this->assertEquals($expected, $result);
- }
-
-/**
- * Test that mock class generation works for the appropriate classes
- *
- * @return void
- */
- public function testMockClassGeneration() {
- $result = $this->Task->hasMockClass('controller');
- $this->assertTrue($result);
- }
-
-/**
- * test bake() with a -plugin param
- *
- * @return void
- */
- public function testBakeWithPlugin() {
- $this->Task->plugin = 'TestTest';
-
- //fake plugin path
- CakePlugin::load('TestTest', array('path' => APP . 'Plugin' . DS . 'TestTest' . DS));
- $path = APP . 'Plugin' . DS . 'TestTest' . DS . 'Test' . DS . 'Case' . DS . 'View' . DS . 'Helper' . DS . 'FormHelperTest.php';
- $this->Task->expects($this->once())->method('createFile')
- ->with($path, $this->anything());
-
- $this->Task->bake('Helper', 'Form');
- CakePlugin::unload();
- }
-
-/**
- * test interactive with plugins lists from the plugin
- *
- * @return void
- */
- public function testInteractiveWithPlugin() {
- $testApp = CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS;
- App::build(array(
- 'Plugin' => array($testApp)
- ), App::RESET);
- CakePlugin::load('TestPlugin');
-
- $this->Task->plugin = 'TestPlugin';
- $path = $testApp . 'TestPlugin' . DS . 'Test' . DS . 'Case' . DS . 'View' . DS . 'Helper' . DS . 'OtherHelperTest.php';
- $this->Task->expects($this->any())
- ->method('in')
- ->will($this->onConsecutiveCalls(
- 5, //helper
- 1 //OtherHelper
- ));
-
- $this->Task->expects($this->once())
- ->method('createFile')
- ->with($path, $this->anything());
-
- $this->Task->stdout->expects($this->at(21))
- ->method('write')
- ->with('1. OtherHelperHelper');
-
- $this->Task->execute();
- }
-
- public static function caseFileNameProvider() {
- return array(
- array('Model', 'Post', 'Case' . DS . 'Model' . DS . 'PostTest.php'),
- array('Helper', 'Form', 'Case' . DS . 'View' . DS . 'Helper' . DS . 'FormHelperTest.php'),
- array('Controller', 'Posts', 'Case' . DS . 'Controller' . DS . 'PostsControllerTest.php'),
- array('Behavior', 'Containable', 'Case' . DS . 'Model' . DS . 'Behavior' . DS . 'ContainableBehaviorTest.php'),
- array('Component', 'Auth', 'Case' . DS . 'Controller' . DS . 'Component' . DS . 'AuthComponentTest.php'),
- array('model', 'Post', 'Case' . DS . 'Model' . DS . 'PostTest.php'),
- array('helper', 'Form', 'Case' . DS . 'View' . DS . 'Helper' . DS . 'FormHelperTest.php'),
- array('controller', 'Posts', 'Case' . DS . 'Controller' . DS . 'PostsControllerTest.php'),
- array('behavior', 'Containable', 'Case' . DS . 'Model' . DS . 'Behavior' . DS . 'ContainableBehaviorTest.php'),
- array('component', 'Auth', 'Case' . DS . 'Controller' . DS . 'Component' . DS . 'AuthComponentTest.php'),
- );
- }
-
-/**
- * Test filename generation for each type + plugins
- *
- * @dataProvider caseFileNameProvider
- * @return void
- */
- public function testTestCaseFileName($type, $class, $expected) {
- $this->Task->path = DS . 'my' . DS . 'path' . DS . 'tests' . DS;
-
- $result = $this->Task->testCaseFileName($type, $class);
- $expected = $this->Task->path . $expected;
- $this->assertEquals($expected, $result);
- }
-
-/**
- * Test filename generation for plugins.
- *
- * @return void
- */
- public function testTestCaseFileNamePlugin() {
- $this->Task->path = DS . 'my' . DS . 'path' . DS . 'tests' . DS;
-
- CakePlugin::load('TestTest', array('path' => APP . 'Plugin' . DS . 'TestTest' . DS ));
- $this->Task->plugin = 'TestTest';
- $result = $this->Task->testCaseFileName('Model', 'Post');
- $expected = APP . 'Plugin' . DS . 'TestTest' . DS . 'Test' . DS . 'Case' . DS . 'Model' . DS . 'PostTest.php';
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test execute with a type defined
- *
- * @return void
- */
- public function testExecuteWithOneArg() {
- $this->Task->args[0] = 'Model';
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('TestTaskTag'));
- $this->Task->expects($this->once())->method('isLoadableClass')->will($this->returnValue(true));
- $this->Task->expects($this->once())->method('createFile')
- ->with(
- $this->anything(),
- $this->stringContains('class TestTaskTagTestCase extends CakeTestCase')
- );
- $this->Task->execute();
- }
-
-/**
- * test execute with type and class name defined
- *
- * @return void
- */
- public function testExecuteWithTwoArgs() {
- $this->Task->args = array('Model', 'TestTaskTag');
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('TestTaskTag'));
- $this->Task->expects($this->once())->method('createFile')
- ->with(
- $this->anything(),
- $this->stringContains('class TestTaskTagTestCase extends CakeTestCase')
- );
- $this->Task->expects($this->any())->method('isLoadableClass')->will($this->returnValue(true));
- $this->Task->execute();
- }
-
-/**
- * test execute with type and class name defined and lower case.
- *
- * @return void
- */
- public function testExecuteWithTwoArgsLowerCase() {
- $this->Task->args = array('model', 'TestTaskTag');
- $this->Task->expects($this->at(0))->method('in')->will($this->returnValue('TestTaskTag'));
- $this->Task->expects($this->once())->method('createFile')
- ->with(
- $this->anything(),
- $this->stringContains('class TestTaskTagTestCase extends CakeTestCase')
- );
- $this->Task->expects($this->any())->method('isLoadableClass')->will($this->returnValue(true));
- $this->Task->execute();
- }
-
-/**
- * Data provider for mapType() tests.
- *
- * @return array
- */
- public static function mapTypeProvider() {
- return array(
- array('controller', null, 'Controller'),
- array('Controller', null, 'Controller'),
- array('component', null, 'Controller/Component'),
- array('Component', null, 'Controller/Component'),
- array('model', null, 'Model'),
- array('Model', null, 'Model'),
- array('behavior', null, 'Model/Behavior'),
- array('Behavior', null, 'Model/Behavior'),
- array('helper', null, 'View/Helper'),
- array('Helper', null, 'View/Helper'),
- array('Helper', 'DebugKit', 'DebugKit.View/Helper'),
- );
- }
-
-/**
- * Test that mapType returns the correct package names.
- *
- * @dataProvider mapTypeProvider
- * @return void
- */
- public function testMapType($original, $plugin, $expected) {
- $this->assertEquals($expected, $this->Task->mapType($original, $plugin));
- }
-}
diff --git a/lib/Cake/Test/Case/Console/Command/Task/ViewTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ViewTaskTest.php
deleted file mode 100644
index 486544320d4..00000000000
--- a/lib/Cake/Test/Case/Console/Command/Task/ViewTaskTest.php
+++ /dev/null
@@ -1,731 +0,0 @@
- array(
- 'className' => 'TestTest.ViewTaskArticle',
- 'foreignKey' => 'article_id'
- )
- );
-}
-
-/**
- * Test View Task Article Model
- *
- * @package Cake.Test.Case.Console.Command.Task
- * @package Cake.Test.Case.Console.Command.Task
- */
-class ViewTaskArticle extends Model {
-
-/**
- * Model name
- *
- * @var string
- */
- public $name = 'ViewTaskArticle';
-
-/**
- * Table name
- *
- * @var string
- */
- public $useTable = 'articles';
-}
-
-/**
- * Test View Task Comments Controller
- *
- * @package Cake.Test.Case.Console.Command.Task
- * @package Cake.Test.Case.Console.Command.Task
- */
-class ViewTaskCommentsController extends Controller {
-
-/**
- * Controller name
- *
- * @var string
- */
- public $name = 'ViewTaskComments';
-
-/**
- * Testing public controller action
- *
- * @return void
- */
- public function index() {
- }
-
-/**
- * Testing public controller action
- *
- * @return void
- */
- public function add() {
- }
-
-}
-
-/**
- * Test View Task Articles Controller
- *
- * @package Cake.Test.Case.Console.Command.Task
- * @package Cake.Test.Case.Console.Command.Task
- */
-class ViewTaskArticlesController extends Controller {
-
-/**
- * Controller name
- *
- * @var string
- */
- public $name = 'ViewTaskArticles';
-
-/**
- * Test public controller action
- *
- * @return void
- */
- public function index() {
- }
-
-/**
- * Test public controller action
- *
- * @return void
- */
- public function add() {
- }
-
-/**
- * Test admin prefixed controller action
- *
- * @return void
- */
- public function admin_index() {
- }
-
-/**
- * Test admin prefixed controller action
- *
- * @return void
- */
- public function admin_add() {
- }
-
-/**
- * Test admin prefixed controller action
- *
- * @return void
- */
- public function admin_view() {
- }
-
-/**
- * Test admin prefixed controller action
- *
- * @return void
- */
- public function admin_edit() {
- }
-
-/**
- * Test admin prefixed controller action
- *
- * @return void
- */
- public function admin_delete() {
- }
-
-}
-
-/**
- * ViewTaskTest class
- *
- * @package Cake.Test.Case.Console.Command.Task
- */
-class ViewTaskTest extends CakeTestCase {
-
-/**
- * Fixtures
- *
- * @var array
- */
- public $fixtures = array('core.article', 'core.comment', 'core.articles_tag', 'core.tag');
-
-/**
- * setUp method
- *
- * Ensure that the default theme is used
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Task = $this->getMock('ViewTask',
- array('in', 'err', 'createFile', '_stop'),
- array($out, $out, $in)
- );
- $this->Task->Template = new TemplateTask($out, $out, $in);
- $this->Task->Controller = $this->getMock('ControllerTask', array(), array($out, $out, $in));
- $this->Task->Project = $this->getMock('ProjectTask', array(), array($out, $out, $in));
- $this->Task->DbConfig = $this->getMock('DbConfigTask', array(), array($out, $out, $in));
-
- $this->Task->path = TMP;
- $this->Task->Template->params['theme'] = 'default';
- $this->Task->Template->templatePaths = array('default' => CAKE . 'Console' . DS . 'Templates' . DS . 'default' . DS);
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- unset($this->Task, $this->Dispatch);
- }
-
-/**
- * Test getContent and parsing of Templates.
- *
- * @return void
- */
- public function testGetContent() {
- $vars = array(
- 'modelClass' => 'TestViewModel',
- 'schema' => array(),
- 'primaryKey' => 'id',
- 'displayField' => 'name',
- 'singularVar' => 'testViewModel',
- 'pluralVar' => 'testViewModels',
- 'singularHumanName' => 'Test View Model',
- 'pluralHumanName' => 'Test View Models',
- 'fields' => array('id', 'name', 'body'),
- 'associations' => array()
- );
- $result = $this->Task->getContent('view', $vars);
-
- $this->assertRegExp('/Delete Test View Model/', $result);
- $this->assertRegExp('/Edit Test View Model/', $result);
- $this->assertRegExp('/List Test View Models/', $result);
- $this->assertRegExp('/New Test View Model/', $result);
-
- $this->assertRegExp('/testViewModel\[\'TestViewModel\'\]\[\'id\'\]/', $result);
- $this->assertRegExp('/testViewModel\[\'TestViewModel\'\]\[\'name\'\]/', $result);
- $this->assertRegExp('/testViewModel\[\'TestViewModel\'\]\[\'body\'\]/', $result);
- }
-
-/**
- * test getContent() using an admin_prefixed action.
- *
- * @return void
- */
- public function testGetContentWithAdminAction() {
- $_back = Configure::read('Routing');
- Configure::write('Routing.prefixes', array('admin'));
- $vars = array(
- 'modelClass' => 'TestViewModel',
- 'schema' => array(),
- 'primaryKey' => 'id',
- 'displayField' => 'name',
- 'singularVar' => 'testViewModel',
- 'pluralVar' => 'testViewModels',
- 'singularHumanName' => 'Test View Model',
- 'pluralHumanName' => 'Test View Models',
- 'fields' => array('id', 'name', 'body'),
- 'associations' => array()
- );
- $result = $this->Task->getContent('admin_view', $vars);
-
- $this->assertRegExp('/Delete Test View Model/', $result);
- $this->assertRegExp('/Edit Test View Model/', $result);
- $this->assertRegExp('/List Test View Models/', $result);
- $this->assertRegExp('/New Test View Model/', $result);
-
- $this->assertRegExp('/testViewModel\[\'TestViewModel\'\]\[\'id\'\]/', $result);
- $this->assertRegExp('/testViewModel\[\'TestViewModel\'\]\[\'name\'\]/', $result);
- $this->assertRegExp('/testViewModel\[\'TestViewModel\'\]\[\'body\'\]/', $result);
-
- $result = $this->Task->getContent('admin_add', $vars);
- $this->assertRegExp("/input\('name'\)/", $result);
- $this->assertRegExp("/input\('body'\)/", $result);
- $this->assertRegExp('/List Test View Models/', $result);
-
- Configure::write('Routing', $_back);
- }
-
-/**
- * test Bake method
- *
- * @return void
- */
- public function testBakeView() {
- $this->Task->controllerName = 'ViewTaskComments';
-
- $this->Task->expects($this->at(0))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'view.ctp',
- $this->stringContains('View Task Articles')
- );
-
- $this->Task->bake('view', true);
- }
-
-/**
- * test baking an edit file
- *
- * @return void
- */
- public function testBakeEdit() {
- $this->Task->controllerName = 'ViewTaskComments';
-
- $this->Task->expects($this->at(0))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'edit.ctp',
- new PHPUnit_Framework_Constraint_IsAnything()
- );
- $this->Task->bake('edit', true);
- }
-
-/**
- * test baking an index
- *
- * @return void
- */
- public function testBakeIndex() {
- $this->Task->controllerName = 'ViewTaskComments';
-
- $this->Task->expects($this->at(0))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'index.ctp',
- $this->stringContains("\$viewTaskComment['Article']['title']")
- );
- $this->Task->bake('index', true);
- }
-
-/**
- * test that baking a view with no template doesn't make a file.
- *
- * @return void
- */
- public function testBakeWithNoTemplate() {
- $this->Task->controllerName = 'ViewTaskComments';
-
- $this->Task->expects($this->never())->method('createFile');
- $this->Task->bake('delete', true);
- }
-
-/**
- * test bake() with a -plugin param
- *
- * @return void
- */
- public function testBakeWithPlugin() {
- $this->Task->controllerName = 'ViewTaskComments';
- $this->Task->plugin = 'TestTest';
- $this->Task->name = 'View';
-
- //fake plugin path
- CakePlugin::load('TestTest', array('path' => APP . 'Plugin' . DS . 'TestTest' . DS));
- $path = APP . 'Plugin' . DS . 'TestTest' . DS . 'View' . DS . 'ViewTaskComments' . DS . 'view.ctp';
-
- $result = $this->Task->getContent('index');
- $this->assertNotContains('List Test Test.view Task Articles', $result);
-
- $this->Task->expects($this->once())
- ->method('createFile')
- ->with($path, $this->anything());
-
- $this->Task->bake('view', true);
- CakePlugin::unload();
- }
-
-/**
- * test bake actions baking multiple actions.
- *
- * @return void
- */
- public function testBakeActions() {
- $this->Task->controllerName = 'ViewTaskComments';
-
- $this->Task->expects($this->at(0))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'view.ctp',
- $this->stringContains('View Task Comments')
- );
- $this->Task->expects($this->at(1))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'edit.ctp',
- $this->stringContains('Edit View Task Comment')
- );
- $this->Task->expects($this->at(2))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'index.ctp',
- $this->stringContains('ViewTaskComment')
- );
-
- $this->Task->bakeActions(array('view', 'edit', 'index'), array());
- }
-
-/**
- * test baking a customAction (non crud)
- *
- * @return void
- */
- public function testCustomAction() {
- $this->Task->controllerName = 'ViewTaskComments';
-
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls('', 'my_action', 'y'));
-
- $this->Task->expects($this->once())->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'my_action.ctp',
- $this->anything()
- );
-
- $this->Task->customAction();
- }
-
-/**
- * Test all()
- *
- * @return void
- */
- public function testExecuteIntoAll() {
- $this->Task->args[0] = 'all';
-
- $this->Task->Controller->expects($this->once())->method('listAll')
- ->will($this->returnValue(array('view_task_comments')));
-
- $this->Task->expects($this->at(0))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'index.ctp',
- $this->anything()
- );
- $this->Task->expects($this->at(1))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'add.ctp',
- $this->anything()
- );
- $this->Task->expects($this->exactly(2))->method('createFile');
-
- $this->Task->execute();
- }
-
-/**
- * Test all() with action parameter
- *
- * @return void
- */
- public function testExecuteIntoAllWithActionName() {
- $this->Task->args = array('all', 'index');
-
- $this->Task->Controller->expects($this->once())->method('listAll')
- ->will($this->returnValue(array('view_task_comments')));
-
- $this->Task->expects($this->once())->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'index.ctp',
- $this->anything()
- );
-
- $this->Task->execute();
- }
-
-/**
- * test `cake bake view $controller view`
- *
- * @return void
- */
- public function testExecuteWithActionParam() {
- $this->Task->args[0] = 'ViewTaskComments';
- $this->Task->args[1] = 'view';
-
- $this->Task->expects($this->once())->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'view.ctp',
- $this->anything()
- );
- $this->Task->execute();
- }
-
-/**
- * test `cake bake view $controller`
- * Ensure that views are only baked for actions that exist in the controller.
- *
- * @return void
- */
- public function testExecuteWithController() {
- $this->Task->args[0] = 'ViewTaskComments';
-
- $this->Task->expects($this->at(0))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'index.ctp',
- $this->anything()
- );
- $this->Task->expects($this->at(1))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'add.ctp',
- $this->anything()
- );
- $this->Task->expects($this->exactly(2))->method('createFile');
-
- $this->Task->execute();
- }
-
-/**
- * static dataprovider for test cases
- *
- * @return void
- */
- public static function nameVariations() {
- return array(array('ViewTaskComments'), array('ViewTaskComment'), array('view_task_comment'));
- }
-
-/**
- * test that both plural and singular forms can be used for baking views.
- *
- * @dataProvider nameVariations
- * @return void
- */
- public function testExecuteWithControllerVariations($name) {
- $this->Task->args = array($name);
-
- $this->Task->expects($this->at(0))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'index.ctp',
- $this->anything()
- );
- $this->Task->expects($this->at(1))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'add.ctp',
- $this->anything()
- );
- $this->Task->execute();
- }
-
-/**
- * test `cake bake view $controller --admin`
- * Which only bakes admin methods, not non-admin methods.
- *
- * @return void
- */
- public function testExecuteWithControllerAndAdminFlag() {
- $_back = Configure::read('Routing');
- Configure::write('Routing.prefixes', array('admin'));
- $this->Task->args[0] = 'ViewTaskArticles';
- $this->Task->params['admin'] = 1;
-
- $this->Task->Project->expects($this->any())->method('getPrefix')->will($this->returnValue('admin_'));
-
- $this->Task->expects($this->exactly(4))->method('createFile');
-
- $views = array('admin_index.ctp', 'admin_add.ctp', 'admin_view.ctp', 'admin_edit.ctp');
- foreach ($views as $i => $view) {
- $this->Task->expects($this->at($i))->method('createFile')
- ->with(
- TMP . 'ViewTaskArticles' . DS . $view,
- $this->anything()
- );
- }
- $this->Task->execute();
- Configure::write('Routing', $_back);
- }
-
-/**
- * test execute into interactive.
- *
- * @return void
- */
- public function testExecuteInteractive() {
- $this->Task->connection = 'test';
- $this->Task->args = array();
- $this->Task->params = array();
-
- $this->Task->Controller->expects($this->once())->method('getName')
- ->will($this->returnValue('ViewTaskComments'));
-
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls('y', 'y', 'n'));
-
- $this->Task->expects($this->at(3))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'index.ctp',
- $this->stringContains('ViewTaskComment')
- );
-
- $this->Task->expects($this->at(4))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'view.ctp',
- $this->stringContains('ViewTaskComment')
- );
-
- $this->Task->expects($this->at(5))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'add.ctp',
- $this->stringContains('Add View Task Comment')
- );
-
- $this->Task->expects($this->at(6))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'edit.ctp',
- $this->stringContains('Edit View Task Comment')
- );
-
- $this->Task->expects($this->exactly(4))->method('createFile');
- $this->Task->execute();
- }
-
-/**
- * test `cake bake view posts index list`
- *
- * @return void
- */
- public function testExecuteWithAlternateTemplates() {
- $this->Task->connection = 'test';
- $this->Task->args = array('ViewTaskComments', 'index', 'list');
- $this->Task->params = array();
-
- $this->Task->expects($this->once())->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'list.ctp',
- $this->stringContains('ViewTaskComment')
- );
- $this->Task->execute();
- }
-
-/**
- * test execute into interactive() with admin methods.
- *
- * @return void
- */
- public function testExecuteInteractiveWithAdmin() {
- Configure::write('Routing.prefixes', array('admin'));
- $this->Task->connection = 'test';
- $this->Task->args = array();
-
- $this->Task->Controller->expects($this->once())->method('getName')
- ->will($this->returnValue('ViewTaskComments'));
-
- $this->Task->Project->expects($this->once())->method('getPrefix')
- ->will($this->returnValue('admin_'));
-
- $this->Task->expects($this->any())->method('in')
- ->will($this->onConsecutiveCalls('y', 'n', 'y'));
-
- $this->Task->expects($this->at(3))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'admin_index.ctp',
- $this->stringContains('ViewTaskComment')
- );
-
- $this->Task->expects($this->at(4))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'admin_view.ctp',
- $this->stringContains('ViewTaskComment')
- );
-
- $this->Task->expects($this->at(5))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'admin_add.ctp',
- $this->stringContains('Add View Task Comment')
- );
-
- $this->Task->expects($this->at(6))->method('createFile')
- ->with(
- TMP . 'ViewTaskComments' . DS . 'admin_edit.ctp',
- $this->stringContains('Edit View Task Comment')
- );
-
- $this->Task->expects($this->exactly(4))->method('createFile');
- $this->Task->execute();
- }
-
-/**
- * test getting templates, make sure noTemplateActions works and prefixed template is used before generic one.
- *
- * @return void
- */
- public function testGetTemplate() {
- $result = $this->Task->getTemplate('delete');
- $this->assertFalse($result);
-
- $result = $this->Task->getTemplate('add');
- $this->assertEquals('form', $result);
-
- Configure::write('Routing.prefixes', array('admin'));
-
- $result = $this->Task->getTemplate('admin_add');
- $this->assertEquals('form', $result);
-
- $this->Task->Template->templatePaths = array(
- 'test' => CAKE . 'Test' . DS . 'test_app' . DS . 'Console' . DS . 'Templates' . DS . 'test' . DS
- );
- $this->Task->Template->params['theme'] = 'test';
-
- $result = $this->Task->getTemplate('admin_edit');
- $this->assertEquals('admin_edit', $result);
- }
-
-}
diff --git a/lib/Cake/Test/Case/Console/Command/TestShellTest.php b/lib/Cake/Test/Case/Console/Command/TestShellTest.php
deleted file mode 100644
index 8fc619bde77..00000000000
--- a/lib/Cake/Test/Case/Console/Command/TestShellTest.php
+++ /dev/null
@@ -1,333 +0,0 @@
-_mapFileToCase($file, $category, $throwOnMissingFile);
- }
-
- public function mapFileToCategory($file) {
- return $this->_mapFileToCategory($file);
- }
-
-}
-
-class TestShellTest extends CakeTestCase {
-
-/**
- * setUp test case
- *
- * @return void
- */
- public function setUp() {
- $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
-
- $this->Shell = $this->getMock(
- 'TestTestShell',
- array('in', 'out', 'hr', 'help', 'error', 'err', '_stop', 'initialize', '_run', 'clear'),
- array($out, $out, $in)
- );
- $this->Shell->OptionParser = $this->getMock('ConsoleOptionParser', array(), array(null, false));
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- unset($this->Dispatch, $this->Shell);
- }
-
-/**
- * testMapCoreFileToCategory
- *
- * @return void
- */
- public function testMapCoreFileToCategory() {
- $this->Shell->startup();
-
- $return = $this->Shell->mapFileToCategory('lib/Cake/basics.php');
- $this->assertSame('core', $return);
-
- $return = $this->Shell->mapFileToCategory('lib/Cake/Core/App.php');
- $this->assertSame('core', $return);
-
- $return = $this->Shell->mapFileToCategory('lib/Cake/Some/Deeply/Nested/Structure.php');
- $this->assertSame('core', $return);
- }
-
-/**
- * testMapCoreFileToCase
- *
- * basics.php is a slightly special case - it's the only file in the core with a test that isn't Capitalized
- *
- * @return void
- */
- public function testMapCoreFileToCase() {
- $this->Shell->startup();
-
- $return = $this->Shell->mapFileToCase('lib/Cake/basics.php', 'core');
- $this->assertSame('Basics', $return);
-
- $return = $this->Shell->mapFileToCase('lib/Cake/Core/App.php', 'core');
- $this->assertSame('Core/App', $return);
-
- $return = $this->Shell->mapFileToCase('lib/Cake/Some/Deeply/Nested/Structure.php', 'core', false);
- $this->assertSame('Some/Deeply/Nested/Structure', $return);
- }
-
-/**
- * testMapAppFileToCategory
- *
- * @return void
- */
- public function testMapAppFileToCategory() {
- $this->Shell->startup();
-
- $return = $this->Shell->mapFileToCategory(APP . 'Controller/ExampleController.php');
- $this->assertSame('app', $return);
-
- $return = $this->Shell->mapFileToCategory(APP . 'My/File/Is/Here.php');
- $this->assertSame('app', $return);
- }
-
-/**
- * testMapAppFileToCase
- *
- * @return void
- */
- public function testMapAppFileToCase() {
- $this->Shell->startup();
-
- $return = $this->Shell->mapFileToCase(APP . 'Controller/ExampleController.php', 'app', false);
- $this->assertSame('Controller/ExampleController', $return);
-
- $return = $this->Shell->mapFileToCase(APP . 'My/File/Is/Here.php', 'app', false);
- $this->assertSame('My/File/Is/Here', $return);
- }
-
-/**
- * testMapPluginFileToCategory
- *
- * @return void
- */
- public function testMapPluginFileToCategory() {
- $this->Shell->startup();
-
- $return = $this->Shell->mapFileToCategory(APP . 'Plugin/awesome/Controller/ExampleController.php');
- $this->assertSame('awesome', $return);
-
- $return = $this->Shell->mapFileToCategory(dirname(CAKE) . 'plugins/awesome/Controller/ExampleController.php');
- $this->assertSame('awesome', $return);
- }
-
-/**
- * testMapPluginFileToCase
- *
- * @return void
- */
- public function testMapPluginFileToCase() {
- $this->Shell->startup();
-
- $return = $this->Shell->mapFileToCase(APP . 'Plugin/awesome/Controller/ExampleController.php', 'awesome', false);
- $this->assertSame('Controller/ExampleController', $return);
-
- $return = $this->Shell->mapFileToCase(dirname(CAKE) . 'plugins/awesome/Controller/ExampleController.php', 'awesome', false);
- $this->assertSame('Controller/ExampleController', $return);
- }
-
-/**
- * testMapCoreTestToCategory
- *
- * @return void
- */
- public function testMapCoreTestToCategory() {
- $this->Shell->startup();
-
- $return = $this->Shell->mapFileToCategory('lib/Cake/Test/Case/BasicsTest.php');
- $this->assertSame('core', $return);
-
- $return = $this->Shell->mapFileToCategory('lib/Cake/Test/Case/BasicsTest.php');
- $this->assertSame('core', $return);
-
- $return = $this->Shell->mapFileToCategory('lib/Cake/Test/Case/Some/Deeply/Nested/StructureTest.php');
- $this->assertSame('core', $return);
- }
-
-/**
- * testMapCoreTestToCase
- *
- * basics.php is a slightly special case - it's the only file in the core with a test that isn't Capitalized
- *
- * @return void
- */
- public function testMapCoreTestToCase() {
- $this->Shell->startup();
-
- $return = $this->Shell->mapFileToCase('lib/Cake/Test/Case/BasicsTest.php', 'core');
- $this->assertSame('Basics', $return);
-
- $return = $this->Shell->mapFileToCase('lib/Cake/Test/Case/Core/AppTest.php', 'core');
- $this->assertSame('Core/App', $return);
-
- $return = $this->Shell->mapFileToCase('lib/Cake/Test/Case/Some/Deeply/Nested/StructureTest.php', 'core', false);
- $this->assertSame('Some/Deeply/Nested/Structure', $return);
- }
-
-/**
- * testMapAppTestToCategory
- *
- * @return void
- */
- public function testMapAppTestToCategory() {
- $this->Shell->startup();
-
- $return = $this->Shell->mapFileToCategory(APP . 'Test/Case/Controller/ExampleControllerTest.php');
- $this->assertSame('app', $return);
-
- $return = $this->Shell->mapFileToCategory(APP . 'Test/Case/My/File/Is/HereTest.php');
- $this->assertSame('app', $return);
- }
-
-/**
- * testMapAppTestToCase
- *
- * @return void
- */
- public function testMapAppTestToCase() {
- $this->Shell->startup();
-
- $return = $this->Shell->mapFileToCase(APP . 'Test/Case/Controller/ExampleControllerTest.php', 'app', false);
- $this->assertSame('Controller/ExampleController', $return);
-
- $return = $this->Shell->mapFileToCase(APP . 'Test/Case/My/File/Is/HereTest.php', 'app', false);
- $this->assertSame('My/File/Is/Here', $return);
- }
-
-/**
- * testMapPluginTestToCategory
- *
- * @return void
- */
- public function testMapPluginTestToCategory() {
- $this->Shell->startup();
-
- $return = $this->Shell->mapFileToCategory(APP . 'Plugin/awesome/Test/Case/Controller/ExampleControllerTest.php');
- $this->assertSame('awesome', $return);
-
- $return = $this->Shell->mapFileToCategory(dirname(CAKE) . 'plugins/awesome/Test/Case/Controller/ExampleControllerTest.php');
- $this->assertSame('awesome', $return);
- }
-
-/**
- * testMapPluginTestToCase
- *
- * @return void
- */
- public function testMapPluginTestToCase() {
- $this->Shell->startup();
-
- $return = $this->Shell->mapFileToCase(APP . 'Plugin/awesome/Test/Case/Controller/ExampleControllerTest.php', 'awesome', false);
- $this->assertSame('Controller/ExampleController', $return);
-
- $return = $this->Shell->mapFileToCase(dirname(CAKE) . 'plugins/awesome/Test/Case/Controller/ExampleControllerTest.php', 'awesome', false);
- $this->assertSame('Controller/ExampleController', $return);
- }
-
-/**
- * testMapNotTestToNothing
- *
- * @return void
- */
- public function testMapNotTestToNothing() {
- $this->Shell->startup();
-
- $return = $this->Shell->mapFileToCategory(APP . 'Test/Case/NotATestFile.php');
- $this->assertSame('app', $return);
-
- $return = $this->Shell->mapFileToCase(APP . 'Test/Case/NotATestFile.php', false, false);
- $this->assertFalse($return);
-
- $return = $this->Shell->mapFileToCategory(APP . 'Test/Fixture/SomeTest.php');
- $this->assertSame('app', $return);
-
- $return = $this->Shell->mapFileToCase(APP . 'Test/Fixture/SomeTest.php', false, false);
- $this->assertFalse($return);
- }
-
-/**
- * test available list of test cases for an empty category
- *
- * @return void
- */
- public function testAvailableWithEmptyList() {
- $this->Shell->startup();
- $this->Shell->args = array('unexistant-category');
- $this->Shell->expects($this->at(0))->method('out')->with(__d('cake_console', "No test cases available \n\n"));
- $this->Shell->OptionParser->expects($this->once())->method('help');
- $this->Shell->available();
- }
-
-/**
- * test available list of test cases for core category
- *
- * @return void
- */
- public function testAvailableCoreCategory() {
- $this->Shell->startup();
- $this->Shell->args = array('core');
- $this->Shell->expects($this->at(0))->method('out')->with('Core Test Cases:');
- $this->Shell->expects($this->at(1))->method('out')
- ->with($this->stringContains('[1]'));
- $this->Shell->expects($this->at(2))->method('out')
- ->with($this->stringContains('[2]'));
-
- $this->Shell->expects($this->once())->method('in')
- ->with(__d('cake_console', 'What test case would you like to run?'), null, 'q')
- ->will($this->returnValue('1'));
-
- $this->Shell->expects($this->once())->method('_run');
- $this->Shell->available();
- $this->assertEquals(array('core', 'AllBehaviors'), $this->Shell->args);
- }
-
-/**
- * Tests that correct option for test runner are passed
- *
- * @return void
- */
- public function testRunnerOptions() {
- $this->Shell->startup();
- $this->Shell->args = array('core', 'Basics');
- $this->Shell->params = array('filter' => 'myFilter', 'colors' => true, 'verbose' => true);
-
- $this->Shell->expects($this->once())->method('_run')
- ->with(
- array('app' => false, 'plugin' => null, 'core' => true, 'output' => 'text', 'case' => 'Basics'),
- array('--filter', 'myFilter', '--colors', '--verbose')
- );
- $this->Shell->main();
- }
-}
diff --git a/lib/Cake/Test/Case/Console/ConsoleErrorHandlerTest.php b/lib/Cake/Test/Case/Console/ConsoleErrorHandlerTest.php
deleted file mode 100644
index ef24dcbcfce..00000000000
--- a/lib/Cake/Test/Case/Console/ConsoleErrorHandlerTest.php
+++ /dev/null
@@ -1,134 +0,0 @@
-Error = $this->getMock('ConsoleErrorHandler', array('_stop'));
- ConsoleErrorHandler::$stderr = $this->getMock('ConsoleOutput', array(), array(), '', false);
- }
-
-/**
- * tearDown
- *
- * @return void
- */
- public function tearDown() {
- unset($this->Error);
- parent::tearDown();
- }
-
-/**
- * test that the console error handler can deal with CakeExceptions.
- *
- * @return void
- */
- public function testHandleError() {
- $content = "Notice Error: This is a notice error in [/some/file, line 275]\n";
- ConsoleErrorHandler::$stderr->expects($this->once())->method('write')
- ->with($content);
-
- $this->Error->handleError(E_NOTICE, 'This is a notice error', '/some/file', 275);
- }
-
-/**
- * test that the console error handler can deal with CakeExceptions.
- *
- * @return void
- */
- public function testCakeErrors() {
- $exception = new MissingActionException('Missing action');
- ConsoleErrorHandler::$stderr->expects($this->once())->method('write')
- ->with($this->stringContains('Missing action'));
-
- $this->Error->expects($this->once())
- ->method('_stop')
- ->with(404);
-
- $this->Error->handleException($exception);
- }
-
-/**
- * test a non CakeException exception.
- *
- * @return void
- */
- public function testNonCakeExceptions() {
- $exception = new InvalidArgumentException('Too many parameters.');
-
- ConsoleErrorHandler::$stderr->expects($this->once())->method('write')
- ->with($this->stringContains('Too many parameters.'));
-
- $this->Error->expects($this->once())
- ->method('_stop')
- ->with(1);
-
- $this->Error->handleException($exception);
- }
-
-/**
- * test a Error404 exception.
- *
- * @return void
- */
- public function testError404Exception() {
- $exception = new NotFoundException('dont use me in cli.');
-
- ConsoleErrorHandler::$stderr->expects($this->once())->method('write')
- ->with($this->stringContains('dont use me in cli.'));
-
- $this->Error->expects($this->once())
- ->method('_stop')
- ->with(404);
-
- $this->Error->handleException($exception);
- }
-
-/**
- * test a Error500 exception.
- *
- * @return void
- */
- public function testError500Exception() {
- $exception = new InternalErrorException('dont use me in cli.');
-
- ConsoleErrorHandler::$stderr->expects($this->once())->method('write')
- ->with($this->stringContains('dont use me in cli.'));
-
- $this->Error->expects($this->once())
- ->method('_stop')
- ->with(500);
-
- $this->Error->handleException($exception);
- }
-
-}
diff --git a/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php b/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php
deleted file mode 100644
index a2787ffc2fb..00000000000
--- a/lib/Cake/Test/Case/Console/ConsoleOptionParserTest.php
+++ /dev/null
@@ -1,594 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc.
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc.
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Console
- * @since CakePHP(tm) v 2.0
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('ConsoleOptionParser', 'Console');
-
-class ConsoleOptionParserTest extends CakeTestCase {
-
-/**
- * test setting the console description
- *
- * @return void
- */
- public function testDescription() {
- $parser = new ConsoleOptionParser('test', false);
- $result = $parser->description('A test');
-
- $this->assertEquals($parser, $result, 'Setting description is not chainable');
- $this->assertEquals('A test', $parser->description(), 'getting value is wrong.');
-
- $result = $parser->description(array('A test', 'something'));
- $this->assertEquals("A test\nsomething", $parser->description(), 'getting value is wrong.');
- }
-
-/**
- * test setting the console epilog
- *
- * @return void
- */
- public function testEpilog() {
- $parser = new ConsoleOptionParser('test', false);
- $result = $parser->epilog('A test');
-
- $this->assertEquals($parser, $result, 'Setting epilog is not chainable');
- $this->assertEquals('A test', $parser->epilog(), 'getting value is wrong.');
-
- $result = $parser->epilog(array('A test', 'something'));
- $this->assertEquals("A test\nsomething", $parser->epilog(), 'getting value is wrong.');
- }
-
-/**
- * test adding an option returns self.
- *
- * @return void
- */
- public function testAddOptionReturnSelf() {
- $parser = new ConsoleOptionParser('test', false);
- $result = $parser->addOption('test');
- $this->assertEquals($parser, $result, 'Did not return $this from addOption');
- }
-
-/**
- * test adding an option and using the long value for parsing.
- *
- * @return void
- */
- public function testAddOptionLong() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('test', array(
- 'short' => 't'
- ));
- $result = $parser->parse(array('--test', 'value'));
- $this->assertEquals(array('test' => 'value', 'help' => false), $result[0], 'Long parameter did not parse out');
- }
-
-/**
- * test addOption with an object.
- *
- * @return void
- */
- public function testAddOptionObject() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption(new ConsoleInputOption('test', 't'));
- $result = $parser->parse(array('--test=value'));
- $this->assertEquals(array('test' => 'value', 'help' => false), $result[0], 'Long parameter did not parse out');
- }
-
-/**
- * test adding an option and using the long value for parsing.
- *
- * @return void
- */
- public function testAddOptionLongEquals() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('test', array(
- 'short' => 't'
- ));
- $result = $parser->parse(array('--test=value'));
- $this->assertEquals(array('test' => 'value', 'help' => false), $result[0], 'Long parameter did not parse out');
- }
-
-/**
- * test adding an option and using the default.
- *
- * @return void
- */
- public function testAddOptionDefault() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('test', array(
- 'default' => 'default value',
- ));
- $result = $parser->parse(array('--test'));
- $this->assertEquals(array('test' => 'default value', 'help' => false), $result[0], 'Default value did not parse out');
-
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('test', array(
- 'default' => 'default value',
- ));
- $result = $parser->parse(array());
- $this->assertEquals(array('test' => 'default value', 'help' => false), $result[0], 'Default value did not parse out');
- }
-
-/**
- * test adding an option and using the short value for parsing.
- *
- * @return void
- */
- public function testAddOptionShort() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('test', array(
- 'short' => 't'
- ));
- $result = $parser->parse(array('-t', 'value'));
- $this->assertEquals(array('test' => 'value', 'help' => false), $result[0], 'Short parameter did not parse out');
- }
-
-/**
- * Test that adding an option using a two letter short value causes an exception.
- * As they will not parse correctly.
- *
- * @expectedException ConsoleException
- * @return void
- */
- public function testAddOptionShortOneLetter() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('test', array('short' => 'te'));
- }
-
-/**
- * test adding and using boolean options.
- *
- * @return void
- */
- public function testAddOptionBoolean() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('test', array(
- 'boolean' => true,
- ));
-
- $result = $parser->parse(array('--test', 'value'));
- $expected = array(array('test' => true, 'help' => false), array('value'));
- $this->assertEquals($expected, $result);
-
- $result = $parser->parse(array('value'));
- $expected = array(array('test' => false, 'help' => false), array('value'));
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test adding an multiple shorts.
- *
- * @return void
- */
- public function testAddOptionMultipleShort() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('test', array('short' => 't', 'boolean' => true))
- ->addOption('file', array('short' => 'f', 'boolean' => true))
- ->addOption('output', array('short' => 'o', 'boolean' => true));
-
- $result = $parser->parse(array('-o', '-t', '-f'));
- $expected = array('file' => true, 'test' => true, 'output' => true, 'help' => false);
- $this->assertEquals($expected, $result[0], 'Short parameter did not parse out');
-
- $result = $parser->parse(array('-otf'));
- $this->assertEquals($expected, $result[0], 'Short parameter did not parse out');
- }
-
-/**
- * test multiple options at once.
- *
- * @return void
- */
- public function testMultipleOptions() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('test')
- ->addOption('connection')
- ->addOption('table', array('short' => 't', 'default' => true));
-
- $result = $parser->parse(array('--test', 'value', '-t', '--connection', 'postgres'));
- $expected = array('test' => 'value', 'table' => true, 'connection' => 'postgres', 'help' => false);
- $this->assertEquals($expected, $result[0], 'multiple options did not parse');
- }
-
-/**
- * Test adding multiple options.
- *
- * @return void
- */
- public function testAddOptions() {
- $parser = new ConsoleOptionParser('something', false);
- $result = $parser->addOptions(array(
- 'name' => array('help' => 'The name'),
- 'other' => array('help' => 'The other arg')
- ));
- $this->assertEquals($parser, $result, 'addOptions is not chainable.');
-
- $result = $parser->options();
- $this->assertEquals(3, count($result), 'Not enough options');
- }
-
-/**
- * test that boolean options work
- *
- * @return void
- */
- public function testOptionWithBooleanParam() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('no-commit', array('boolean' => true))
- ->addOption('table', array('short' => 't'));
-
- $result = $parser->parse(array('--table', 'posts', '--no-commit', 'arg1', 'arg2'));
- $expected = array(array('table' => 'posts', 'no-commit' => true, 'help' => false), array('arg1', 'arg2'));
- $this->assertEquals($expected, $result, 'Boolean option did not parse correctly.');
- }
-
-/**
- * test parsing options that do not exist.
- *
- * @expectedException ConsoleException
- */
- public function testOptionThatDoesNotExist() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('no-commit', array('boolean' => true));
-
- $result = $parser->parse(array('--fail', 'other'));
- }
-
-/**
- * test parsing short options that do not exist.
- *
- * @expectedException ConsoleException
- */
- public function testShortOptionThatDoesNotExist() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('no-commit', array('boolean' => true));
-
- $result = $parser->parse(array('-f'));
- }
-
-/**
- * test that options with choices enforce them.
- *
- * @expectedException ConsoleException
- * @return void
- */
- public function testOptionWithChoices() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('name', array('choices' => array('mark', 'jose')));
-
- $result = $parser->parse(array('--name', 'mark'));
- $expected = array('name' => 'mark', 'help' => false);
- $this->assertEquals($expected, $result[0], 'Got the correct value.');
-
- $result = $parser->parse(array('--name', 'jimmy'));
- }
-
-/**
- * Ensure that option values can start with -
- *
- * @return void
- */
- public function testOptionWithValueStartingWithMinus() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('name')
- ->addOption('age');
-
- $result = $parser->parse(array('--name', '-foo', '--age', 'old'));
- $expected = array('name' => '-foo', 'age' => 'old', 'help' => false);
- $this->assertEquals($expected, $result[0], 'Option values starting with "-" are broken.');
- }
-
-/**
- * test positional argument parsing.
- *
- * @return void
- */
- public function testPositionalArgument() {
- $parser = new ConsoleOptionParser('test', false);
- $result = $parser->addArgument('name', array('help' => 'An argument'));
- $this->assertEquals($parser, $result, 'Should return this');
- }
-
-/**
- * test addOption with an object.
- *
- * @return void
- */
- public function testAddArgumentObject() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addArgument(new ConsoleInputArgument('test'));
- $result = $parser->arguments();
- $this->assertEquals(1, count($result));
- $this->assertEquals('test', $result[0]->name());
- }
-
-/**
- * test overwriting positional arguments.
- *
- * @return void
- */
- public function testPositionalArgOverwrite() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addArgument('name', array('help' => 'An argument'))
- ->addArgument('other', array('index' => 0));
-
- $result = $parser->arguments();
- $this->assertEquals(1, count($result), 'Overwrite did not occur');
- }
-
-/**
- * test parsing arguments.
- *
- * @expectedException ConsoleException
- * @return void
- */
- public function testParseArgumentTooMany() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addArgument('name', array('help' => 'An argument'))
- ->addArgument('other');
-
- $expected = array('one', 'two');
- $result = $parser->parse($expected);
- $this->assertEquals($expected, $result[1], 'Arguments are not as expected');
-
- $result = $parser->parse(array('one', 'two', 'three'));
- }
-
-/**
- * test parsing arguments with 0 value.
- *
- * @return void
- */
- public function testParseArgumentZero() {
- $parser = new ConsoleOptionParser('test', false);
-
- $expected = array('one', 'two', 0, 'after', 'zero');
- $result = $parser->parse($expected);
- $this->assertEquals($expected, $result[1], 'Arguments are not as expected');
- }
-
-/**
- * test that when there are not enough arguments an exception is raised
- *
- * @expectedException ConsoleException
- * @return void
- */
- public function testPositionalArgNotEnough() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addArgument('name', array('required' => true))
- ->addArgument('other', array('required' => true));
-
- $parser->parse(array('one'));
- }
-
-/**
- * test that arguments with choices enforce them.
- *
- * @expectedException ConsoleException
- * @return void
- */
- public function testPositionalArgWithChoices() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addArgument('name', array('choices' => array('mark', 'jose')))
- ->addArgument('alias', array('choices' => array('cowboy', 'samurai')))
- ->addArgument('weapon', array('choices' => array('gun', 'sword')));
-
- $result = $parser->parse(array('mark', 'samurai', 'sword'));
- $expected = array('mark', 'samurai', 'sword');
- $this->assertEquals($expected, $result[1], 'Got the correct value.');
-
- $result = $parser->parse(array('jose', 'coder'));
- }
-
-/**
- * Test adding multiple arguments.
- *
- * @return void
- */
- public function testAddArguments() {
- $parser = new ConsoleOptionParser('test', false);
- $result = $parser->addArguments(array(
- 'name' => array('help' => 'The name'),
- 'other' => array('help' => 'The other arg')
- ));
- $this->assertEquals($parser, $result, 'addArguments is not chainable.');
-
- $result = $parser->arguments();
- $this->assertEquals(2, count($result), 'Not enough arguments');
- }
-
-/**
- * test setting a subcommand up.
- *
- * @return void
- */
- public function testSubcommand() {
- $parser = new ConsoleOptionParser('test', false);
- $result = $parser->addSubcommand('initdb', array(
- 'help' => 'Initialize the database'
- ));
- $this->assertEquals($parser, $result, 'Adding a subcommand is not chainable');
- }
-
-/**
- * test addSubcommand with an object.
- *
- * @return void
- */
- public function testAddSubcommandObject() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addSubcommand(new ConsoleInputSubcommand('test'));
- $result = $parser->subcommands();
- $this->assertEquals(1, count($result));
- $this->assertEquals('test', $result['test']->name());
- }
-
-/**
- * test adding multiple subcommands
- *
- * @return void
- */
- public function testAddSubcommands() {
- $parser = new ConsoleOptionParser('test', false);
- $result = $parser->addSubcommands(array(
- 'initdb' => array('help' => 'Initialize the database'),
- 'create' => array('help' => 'Create something')
- ));
- $this->assertEquals($parser, $result, 'Adding a subcommands is not chainable');
- $result = $parser->subcommands();
- $this->assertEquals(2, count($result), 'Not enough subcommands');
- }
-
-/**
- * test that no exception is triggered when help is being generated
- *
- * @return void
- */
- public function testHelpNoExceptionWhenGettingHelp() {
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser->addOption('test', array('help' => 'A test option.'))
- ->addArgument('model', array('help' => 'The model to make.', 'required' => true));
-
- $result = $parser->parse(array('--help'));
- $this->assertTrue($result[0]['help']);
- }
-
-/**
- * test that help() with a command param shows the help for a subcommand
- *
- * @return void
- */
- public function testHelpSubcommandHelp() {
- $subParser = new ConsoleOptionParser('method', false);
- $subParser->addOption('connection', array('help' => 'Db connection.'));
-
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser->addSubcommand('method', array(
- 'help' => 'This is another command',
- 'parser' => $subParser
- ))
- ->addOption('test', array('help' => 'A test option.'));
-
- $result = $parser->help('method');
- $expected = <<Usage:
-cake mycommand method [-h] [--connection]
-
-Options:
-
---help, -h Display this help.
---connection Db connection.
-
-TEXT;
- $this->assertEquals($expected, $result, 'Help is not correct.');
- }
-
-/**
- * test building a parser from an array.
- *
- * @return void
- */
- public function testBuildFromArray() {
- $spec = array(
- 'command' => 'test',
- 'arguments' => array(
- 'name' => array('help' => 'The name'),
- 'other' => array('help' => 'The other arg')
- ),
- 'options' => array(
- 'name' => array('help' => 'The name'),
- 'other' => array('help' => 'The other arg')
- ),
- 'subcommands' => array(
- 'initdb' => array('help' => 'make database')
- ),
- 'description' => 'description text',
- 'epilog' => 'epilog text'
- );
- $parser = ConsoleOptionParser::buildFromArray($spec);
-
- $this->assertEquals($spec['description'], $parser->description());
- $this->assertEquals($spec['epilog'], $parser->epilog());
-
- $options = $parser->options();
- $this->assertTrue(isset($options['name']));
- $this->assertTrue(isset($options['other']));
-
- $args = $parser->arguments();
- $this->assertEquals(2, count($args));
-
- $commands = $parser->subcommands();
- $this->assertEquals(1, count($commands));
- }
-
-/**
- * test that create() returns instances
- *
- * @return void
- */
- public function testCreateFactory() {
- $parser = ConsoleOptionParser::create('factory', false);
- $this->assertInstanceOf('ConsoleOptionParser', $parser);
- $this->assertEquals('factory', $parser->command());
- }
-
-/**
- * test that command() inflects the command name.
- *
- * @return void
- */
- public function testCommandInflection() {
- $parser = new ConsoleOptionParser('CommandLine');
- $this->assertEquals('command_line', $parser->command());
- }
-
-/**
- * test that parse() takes a subcommand argument, and that the subcommand parser
- * is used.
- *
- * @return void
- */
- public function testParsingWithSubParser() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->addOption('primary')
- ->addArgument('one', array('required' => true, 'choices' => array('a', 'b')))
- ->addArgument('two', array('required' => true))
- ->addSubcommand('sub', array(
- 'parser' => array(
- 'options' => array(
- 'secondary' => array('boolean' => true),
- 'fourth' => array('help' => 'fourth option')
- ),
- 'arguments' => array(
- 'sub_arg' => array('choices' => array('c', 'd'))
- )
- )
- ));
-
- $result = $parser->parse(array('--secondary', '--fourth', '4', 'c'), 'sub');
- $expected = array(array(
- 'secondary' => true,
- 'fourth' => '4',
- 'help' => false,
- 'verbose' => false,
- 'quiet' => false), array('c'));
- $this->assertEquals($expected, $result, 'Sub parser did not parse request.');
- }
-
-}
diff --git a/lib/Cake/Test/Case/Console/ConsoleOutputTest.php b/lib/Cake/Test/Case/Console/ConsoleOutputTest.php
deleted file mode 100644
index 0f7e106a3da..00000000000
--- a/lib/Cake/Test/Case/Console/ConsoleOutputTest.php
+++ /dev/null
@@ -1,241 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc.
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc.
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Console
- * @since CakePHP(tm) v 1.2.0.5432
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('ConsoleOutput', 'Console');
-
-class ConsoleOutputTest extends CakeTestCase {
-
-/**
- * setup
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- $this->output = $this->getMock('ConsoleOutput', array('_write'));
- $this->output->outputAs(ConsoleOutput::COLOR);
- }
-
-/**
- * tearDown
- *
- * @return void
- */
- public function tearDown() {
- unset($this->output);
- }
-
-/**
- * test writing with no new line
- *
- * @return void
- */
- public function testWriteNoNewLine() {
- $this->output->expects($this->once())->method('_write')
- ->with('Some output');
-
- $this->output->write('Some output', false);
- }
-
-/**
- * test writing with no new line
- *
- * @return void
- */
- public function testWriteNewLine() {
- $this->output->expects($this->once())->method('_write')
- ->with('Some output' . PHP_EOL);
-
- $this->output->write('Some output');
- }
-
-/**
- * test write() with multiple new lines
- *
- * @return void
- */
- public function testWriteMultipleNewLines() {
- $this->output->expects($this->once())->method('_write')
- ->with('Some output' . PHP_EOL . PHP_EOL . PHP_EOL . PHP_EOL);
-
- $this->output->write('Some output', 4);
- }
-
-/**
- * test writing an array of messages.
- *
- * @return void
- */
- public function testWriteArray() {
- $this->output->expects($this->once())->method('_write')
- ->with('Line' . PHP_EOL . 'Line' . PHP_EOL . 'Line' . PHP_EOL);
-
- $this->output->write(array('Line', 'Line', 'Line'));
- }
-
-/**
- * test getting a style.
- *
- * @return void
- */
- public function testStylesGet() {
- $result = $this->output->styles('error');
- $expected = array('text' => 'red', 'underline' => true);
- $this->assertEquals($expected, $result);
-
- $this->assertNull($this->output->styles('made_up_goop'));
-
- $result = $this->output->styles();
- $this->assertNotEmpty($result, 'error', 'Error is missing');
- $this->assertNotEmpty($result, 'warning', 'Warning is missing');
- }
-
-/**
- * test adding a style.
- *
- * @return void
- */
- public function testStylesAdding() {
- $this->output->styles('test', array('text' => 'red', 'background' => 'black'));
- $result = $this->output->styles('test');
- $expected = array('text' => 'red', 'background' => 'black');
- $this->assertEquals($expected, $result);
-
- $this->assertTrue($this->output->styles('test', false), 'Removing a style should return true.');
- $this->assertNull($this->output->styles('test'), 'Removed styles should be null.');
- }
-
-/**
- * test formatting text with styles.
- *
- * @return void
- */
- public function testFormattingSimple() {
- $this->output->expects($this->once())->method('_write')
- ->with("\033[31;4mError:\033[0m Something bad");
-
- $this->output->write('Error: Something bad', false);
- }
-
-/**
- * test that formatting doesn't eat tags it doesn't know about.
- *
- * @return void
- */
- public function testFormattingNotEatingTags() {
- $this->output->expects($this->once())->method('_write')
- ->with(" Something bad");
-
- $this->output->write(' Something bad', false);
- }
-
-/**
- * test formatting with custom styles.
- *
- * @return void
- */
- public function testFormattingCustom() {
- $this->output->styles('annoying', array(
- 'text' => 'magenta',
- 'background' => 'cyan',
- 'blink' => true,
- 'underline' => true
- ));
-
- $this->output->expects($this->once())->method('_write')
- ->with("\033[35;46;5;4mAnnoy:\033[0m Something bad");
-
- $this->output->write('Annoy: Something bad', false);
- }
-
-/**
- * test formatting text with missing styles.
- *
- * @return void
- */
- public function testFormattingMissingStyleName() {
- $this->output->expects($this->once())->method('_write')
- ->with("Error: Something bad");
-
- $this->output->write('Error: Something bad', false);
- }
-
-/**
- * test formatting text with multiple styles.
- *
- * @return void
- */
- public function testFormattingMultipleStylesName() {
- $this->output->expects($this->once())->method('_write')
- ->with("\033[31;4mBad\033[0m \033[33mWarning\033[0m Regular");
-
- $this->output->write('Bad Warning Regular', false);
- }
-
-/**
- * test that multiple tags of the same name work in one string.
- *
- * @return void
- */
- public function testFormattingMultipleSameTags() {
- $this->output->expects($this->once())->method('_write')
- ->with("\033[31;4mBad\033[0m \033[31;4mWarning\033[0m Regular");
-
- $this->output->write('Bad Warning Regular', false);
- }
-
-/**
- * test raw output not getting tags replaced.
- *
- * @return void
- */
- public function testOutputAsRaw() {
- $this->output->outputAs(ConsoleOutput::RAW);
- $this->output->expects($this->once())->method('_write')
- ->with('Bad Regular');
-
- $this->output->write('Bad Regular', false);
- }
-
-/**
- * test plain output.
- *
- * @return void
- */
- public function testOutputAsPlain() {
- $this->output->outputAs(ConsoleOutput::PLAIN);
- $this->output->expects($this->once())->method('_write')
- ->with('Bad Regular');
-
- $this->output->write('Bad Regular', false);
- }
-
-/**
- * test plain output only strips tags used for formatting.
- *
- * @return void
- */
- public function testOutputAsPlainSelectiveTagRemoval() {
- $this->output->outputAs(ConsoleOutput::PLAIN);
- $this->output->expects($this->once())->method('_write')
- ->with('Bad Regular Left behind ');
-
- $this->output->write('Bad Regular Left behind ', false);
- }
-}
diff --git a/lib/Cake/Test/Case/Console/HelpFormatterTest.php b/lib/Cake/Test/Case/Console/HelpFormatterTest.php
deleted file mode 100644
index 1b4d953171e..00000000000
--- a/lib/Cake/Test/Case/Console/HelpFormatterTest.php
+++ /dev/null
@@ -1,505 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc.
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc.
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Console
- * @since CakePHP(tm) v 2.0
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('ConsoleOptionParser', 'Console');
-App::uses('HelpFormatter', 'Console');
-
-class HelpFormatterTest extends CakeTestCase {
-
-/**
- * test that the console max width is respected when generating help.
- *
- * @return void
- */
- public function testWidthFormatting() {
- $parser = new ConsoleOptionParser('test', false);
- $parser->description('This is fifteen This is fifteen This is fifteen')
- ->addOption('four', array('help' => 'this is help text this is help text'))
- ->addArgument('four', array('help' => 'this is help text this is help text'))
- ->addSubcommand('four', array('help' => 'this is help text this is help text'));
-
- $formatter = new HelpFormatter($parser);
- $result = $formatter->text(30);
- $expected = <<Usage:
-cake test [subcommand] [-h] [--four] []
-
-Subcommands:
-
-four this is help text this
- is help text
-
-To see help on a subcommand use `cake test [subcommand] --help`
-
-Options:
-
---help, -h Display this help.
---four this is help text
- this is help text
-
-Arguments:
-
-four this is help text this
- is help text
- (optional)
-
-TEXT;
- $this->assertEquals($expected, $result, 'Generated help is too wide');
- }
-
-/**
- * test help() with options and arguments that have choices.
- *
- * @return void
- */
- public function testHelpWithChoices() {
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser->addOption('test', array('help' => 'A test option.', 'choices' => array('one', 'two')))
- ->addArgument('type', array(
- 'help' => 'Resource type.',
- 'choices' => array('aco', 'aro'),
- 'required' => true
- ))
- ->addArgument('other_longer', array('help' => 'Another argument.'));
-
- $formatter = new HelpFormatter($parser);
- $result = $formatter->text();
- $expected = <<Usage:
-cake mycommand [-h] [--test one|two] []
-
-Options:
-
---help, -h Display this help.
---test A test option. (choices: one|two)
-
-Arguments:
-
-type Resource type. (choices: aco|aro)
-other_longer Another argument. (optional)
-
-TEXT;
- $this->assertEquals($expected, $result, 'Help does not match');
- }
-
-/**
- * test description and epilog in the help
- *
- * @return void
- */
- public function testHelpDescriptionAndEpilog() {
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser->description('Description text')
- ->epilog('epilog text')
- ->addOption('test', array('help' => 'A test option.'))
- ->addArgument('model', array('help' => 'The model to make.', 'required' => true));
-
- $formatter = new HelpFormatter($parser);
- $result = $formatter->text();
- $expected = <<Usage:
-cake mycommand [-h] [--test]
-
-Options:
-
---help, -h Display this help.
---test A test option.
-
-Arguments:
-
-model The model to make.
-
-epilog text
-
-TEXT;
- $this->assertEquals($expected, $result, 'Help is wrong.');
- }
-
-/**
- * test that help() outputs subcommands.
- *
- * @return void
- */
- public function testHelpSubcommand() {
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser->addSubcommand('method', array('help' => 'This is another command'))
- ->addOption('test', array('help' => 'A test option.'));
-
- $formatter = new HelpFormatter($parser);
- $result = $formatter->text();
- $expected = <<Usage:
-cake mycommand [subcommand] [-h] [--test]
-
-Subcommands:
-
-method This is another command
-
-To see help on a subcommand use `cake mycommand [subcommand] --help`
-
-Options:
-
---help, -h Display this help.
---test A test option.
-
-TEXT;
- $this->assertEquals($expected, $result, 'Help is not correct.');
- }
-
-/**
- * test getting help with defined options.
- *
- * @return void
- */
- public function testHelpWithOptions() {
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser->addOption('test', array('help' => 'A test option.'))
- ->addOption('connection', array(
- 'short' => 'c', 'help' => 'The connection to use.', 'default' => 'default'
- ));
-
- $formatter = new HelpFormatter($parser);
- $result = $formatter->text();
- $expected = <<Usage:
-cake mycommand [-h] [--test] [-c default]
-
-Options:
-
---help, -h Display this help.
---test A test option.
---connection, -c The connection to use. (default:
- default)
-
-TEXT;
- $this->assertEquals($expected, $result, 'Help does not match');
- }
-
-/**
- * test getting help with defined options.
- *
- * @return void
- */
- public function testHelpWithOptionsAndArguments() {
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser->addOption('test', array('help' => 'A test option.'))
- ->addArgument('model', array('help' => 'The model to make.', 'required' => true))
- ->addArgument('other_longer', array('help' => 'Another argument.'));
-
- $formatter = new HelpFormatter($parser);
- $result = $formatter->text();
- $expected = <<Usage:
-cake mycommand [-h] [--test] []
-
-Options:
-
---help, -h Display this help.
---test A test option.
-
-Arguments:
-
-model The model to make.
-other_longer Another argument. (optional)
-
-TEXT;
- $this->assertEquals($expected, $result, 'Help does not match');
- }
-
-/**
- * Test that a long set of options doesn't make useless output.
- *
- * @return void
- */
- public function testHelpWithLotsOfOptions() {
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser
- ->addOption('test', array('help' => 'A test option.'))
- ->addOption('test2', array('help' => 'A test option.'))
- ->addOption('test3', array('help' => 'A test option.'))
- ->addOption('test4', array('help' => 'A test option.'))
- ->addOption('test5', array('help' => 'A test option.'))
- ->addOption('test6', array('help' => 'A test option.'))
- ->addOption('test7', array('help' => 'A test option.'))
- ->addArgument('model', array('help' => 'The model to make.', 'required' => true))
- ->addArgument('other_longer', array('help' => 'Another argument.'));
-
- $formatter = new HelpFormatter($parser);
- $result = $formatter->text();
- $expected = 'cake mycommand [options] []';
- $this->assertContains($expected, $result);
- }
-
-/**
- * Test that a long set of arguments doesn't make useless output.
- *
- * @return void
- */
- public function testHelpWithLotsOfArguments() {
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser
- ->addArgument('test', array('help' => 'A test option.'))
- ->addArgument('test2', array('help' => 'A test option.'))
- ->addArgument('test3', array('help' => 'A test option.'))
- ->addArgument('test4', array('help' => 'A test option.'))
- ->addArgument('test5', array('help' => 'A test option.'))
- ->addArgument('test6', array('help' => 'A test option.'))
- ->addArgument('test7', array('help' => 'A test option.'))
- ->addArgument('model', array('help' => 'The model to make.', 'required' => true))
- ->addArgument('other_longer', array('help' => 'Another argument.'));
-
- $formatter = new HelpFormatter($parser);
- $result = $formatter->text();
- $expected = 'cake mycommand [-h] [arguments]';
- $this->assertContains($expected, $result);
- }
-
-/**
- * test help() with options and arguments that have choices.
- *
- * @return void
- */
- public function testXmlHelpWithChoices() {
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser->addOption('test', array('help' => 'A test option.', 'choices' => array('one', 'two')))
- ->addArgument('type', array(
- 'help' => 'Resource type.',
- 'choices' => array('aco', 'aro'),
- 'required' => true
- ))
- ->addArgument('other_longer', array('help' => 'Another argument.'));
-
- $formatter = new HelpFormatter($parser);
- $result = $formatter->xml();
- $expected = <<
-
-mycommand
-Description text
-
-
-
-
-
-
-
-
-
- one
- two
-
-
-
-
-
-
- aco
- aro
-
-
-
-epilog text
-
-TEXT;
- $this->assertEquals(new DomDocument($expected), new DomDocument($result), 'Help does not match');
- }
-
-/**
- * test description and epilog in the help
- *
- * @return void
- */
- public function testXmlHelpDescriptionAndEpilog() {
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser->description('Description text')
- ->epilog('epilog text')
- ->addOption('test', array('help' => 'A test option.'))
- ->addArgument('model', array('help' => 'The model to make.', 'required' => true));
-
- $formatter = new HelpFormatter($parser);
- $result = $formatter->xml();
- $expected = <<
-
-mycommand
-Description text
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-epilog text
-
-TEXT;
- $this->assertEquals(new DomDocument($expected), new DomDocument($result), 'Help does not match');
- }
-
-/**
- * test that help() outputs subcommands.
- *
- * @return void
- */
- public function testXmlHelpSubcommand() {
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser->addSubcommand('method', array('help' => 'This is another command'))
- ->addOption('test', array('help' => 'A test option.'));
-
- $formatter = new HelpFormatter($parser);
- $result = $formatter->xml();
- $expected = <<
-
-mycommand
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-TEXT;
- $this->assertEquals(new DomDocument($expected), new DomDocument($result), 'Help does not match');
- }
-
-/**
- * test getting help with defined options.
- *
- * @return void
- */
- public function testXmlHelpWithOptions() {
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser->addOption('test', array('help' => 'A test option.'))
- ->addOption('connection', array(
- 'short' => 'c', 'help' => 'The connection to use.', 'default' => 'default'
- ));
-
- $formatter = new HelpFormatter($parser);
- $result = $formatter->xml();
- $expected = <<
-
-mycommand
-
-
-
-
-
-
-
-
-
-
-
-
- default
-
-
-
-
-
-
-TEXT;
- $this->assertEquals(new DomDocument($expected), new DomDocument($result), 'Help does not match');
- }
-
-/**
- * test getting help with defined options.
- *
- * @return void
- */
- public function testXmlHelpWithOptionsAndArguments() {
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser->addOption('test', array('help' => 'A test option.'))
- ->addArgument('model', array('help' => 'The model to make.', 'required' => true))
- ->addArgument('other_longer', array('help' => 'Another argument.'));
-
- $formatter = new HelpFormatter($parser);
- $result = $formatter->xml();
- $expected = <<
-
- mycommand
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-TEXT;
- $this->assertEquals(new DomDocument($expected), new DomDocument($result), 'Help does not match');
- }
-
-/**
- * Test xml help as object
- *
- * @return void
- */
- public function testXmlHelpAsObject() {
- $parser = new ConsoleOptionParser('mycommand', false);
- $parser->addOption('test', array('help' => 'A test option.'))
- ->addArgument('model', array('help' => 'The model to make.', 'required' => true))
- ->addArgument('other_longer', array('help' => 'Another argument.'));
-
- $formatter = new HelpFormatter($parser);
- $result = $formatter->xml(false);
- $this->assertInstanceOf('SimpleXmlElement', $result);
- }
-}
diff --git a/lib/Cake/Test/Case/Console/ShellDispatcherTest.php b/lib/Cake/Test/Case/Console/ShellDispatcherTest.php
deleted file mode 100644
index 1b3adfabd64..00000000000
--- a/lib/Cake/Test/Case/Console/ShellDispatcherTest.php
+++ /dev/null
@@ -1,576 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc.
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc.
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Console
- * @since CakePHP(tm) v 1.2.0.5432
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('ShellDispatcher', 'Console');
-
-/**
- * TestShellDispatcher class
- *
- * @package Cake.Test.Case.Console
- */
-class TestShellDispatcher extends ShellDispatcher {
-
-/**
- * params property
- *
- * @var array
- */
- public $params = array();
-
-/**
- * stopped property
- *
- * @var string
- */
- public $stopped = null;
-
-/**
- * TestShell
- *
- * @var mixed
- */
- public $TestShell;
-
-/**
- * _initEnvironment method
- *
- * @return void
- */
- protected function _initEnvironment() {
- }
-
-/**
- * clear method
- *
- * @return void
- */
- public function clear() {
- }
-
-/**
- * _stop method
- *
- * @return void
- */
- protected function _stop($status = 0) {
- $this->stopped = 'Stopped with status: ' . $status;
- return $status;
- }
-
-/**
- * getShell
- *
- * @param mixed $shell
- * @return mixed
- */
- public function getShell($shell) {
- return $this->_getShell($shell);
- }
-
-/**
- * _getShell
- *
- * @param mixed $plugin
- * @return mixed
- */
- protected function _getShell($shell) {
- if (isset($this->TestShell)) {
- return $this->TestShell;
- }
- return parent::_getShell($shell);
- }
-
-}
-
-/**
- * ShellDispatcherTest
- *
- * @package Cake.Test.Case.Console
- */
-class ShellDispatcherTest extends CakeTestCase {
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- App::build(array(
- 'Plugin' => array(
- CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS
- ),
- 'Console/Command' => array(
- CAKE . 'Test' . DS . 'test_app' . DS . 'Console' . DS . 'Command' . DS
- )
- ), App::RESET);
- CakePlugin::load('TestPlugin');
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- CakePlugin::unload();
- }
-
-/**
- * testParseParams method
- *
- * @return void
- */
- public function testParseParams() {
- $Dispatcher = new TestShellDispatcher();
-
- $params = array(
- '/cake/1.2.x.x/cake/console/cake.php',
- 'bake',
- '-app',
- 'new',
- '-working',
- '/var/www/htdocs'
- );
- $expected = array(
- 'app' => 'new',
- 'webroot' => 'webroot',
- 'working' => str_replace('/', DS, '/var/www/htdocs/new'),
- 'root' => str_replace('/', DS,'/var/www/htdocs')
- );
- $Dispatcher->parseParams($params);
- $this->assertEquals($expected, $Dispatcher->params);
-
- $params = array('cake.php');
- $expected = array(
- 'app' => 'app',
- 'webroot' => 'webroot',
- 'working' => str_replace('\\', DS, dirname(CAKE_CORE_INCLUDE_PATH) . DS . 'app'),
- 'root' => str_replace('\\', DS, dirname(CAKE_CORE_INCLUDE_PATH)),
- );
- $Dispatcher->params = $Dispatcher->args = array();
- $Dispatcher->parseParams($params);
- $this->assertEquals($expected, $Dispatcher->params);
-
- $params = array(
- 'cake.php',
- '-app',
- 'new',
- );
- $expected = array(
- 'app' => 'new',
- 'webroot' => 'webroot',
- 'working' => str_replace('\\', DS, dirname(CAKE_CORE_INCLUDE_PATH) . DS . 'new'),
- 'root' => str_replace('\\', DS, dirname(CAKE_CORE_INCLUDE_PATH))
- );
- $Dispatcher->params = $Dispatcher->args = array();
- $Dispatcher->parseParams($params);
- $this->assertEquals($expected, $Dispatcher->params);
-
- $params = array(
- './cake.php',
- 'bake',
- '-app',
- 'new',
- '-working',
- '/cake/1.2.x.x/cake/console'
- );
-
- $expected = array(
- 'app' => 'new',
- 'webroot' => 'webroot',
- 'working' => str_replace('\\', DS, dirname(CAKE_CORE_INCLUDE_PATH) . DS . 'new'),
- 'root' => str_replace('\\', DS, dirname(CAKE_CORE_INCLUDE_PATH))
- );
-
- $Dispatcher->params = $Dispatcher->args = array();
- $Dispatcher->parseParams($params);
- $this->assertEquals($expected, $Dispatcher->params);
-
- $params = array(
- './console/cake.php',
- 'bake',
- '-app',
- 'new',
- '-working',
- '/cake/1.2.x.x/cake'
- );
- $expected = array(
- 'app' => 'new',
- 'webroot' => 'webroot',
- 'working' => str_replace('\\', DS, dirname(CAKE_CORE_INCLUDE_PATH) . DS . 'new'),
- 'root' => str_replace('\\', DS, dirname(CAKE_CORE_INCLUDE_PATH))
- );
- $Dispatcher->params = $Dispatcher->args = array();
- $Dispatcher->parseParams($params);
- $this->assertEquals($expected, $Dispatcher->params);
-
- $params = array(
- './console/cake.php',
- 'bake',
- '-app',
- 'new',
- '-dry',
- '-working',
- '/cake/1.2.x.x/cake'
- );
- $expected = array(
- 'app' => 'new',
- 'working' => str_replace('\\', DS, dirname(CAKE_CORE_INCLUDE_PATH) . DS . 'new'),
- 'root' => str_replace('\\', DS, dirname(CAKE_CORE_INCLUDE_PATH)),
- 'webroot' => 'webroot'
- );
- $Dispatcher->params = $Dispatcher->args = array();
- $Dispatcher->parseParams($params);
- $this->assertEquals($expected, $Dispatcher->params);
-
- $params = array(
- './console/cake.php',
- '-working',
- '/cake/1.2.x.x/cake',
- 'schema',
- 'run',
- 'create',
- '-dry',
- '-f',
- '-name',
- 'DbAcl'
- );
- $expected = array(
- 'app' => 'app',
- 'webroot' => 'webroot',
- 'working' => str_replace('\\', DS, dirname(CAKE_CORE_INCLUDE_PATH) . DS . 'app'),
- 'root' => str_replace('\\', DS, dirname(CAKE_CORE_INCLUDE_PATH)),
- );
- $Dispatcher->params = $Dispatcher->args = array();
- $Dispatcher->parseParams($params);
- $this->assertEquals($expected, $Dispatcher->params);
-
- $expected = array(
- './console/cake.php', 'schema', 'run', 'create', '-dry', '-f', '-name', 'DbAcl'
- );
- $this->assertEquals($expected, $Dispatcher->args);
-
- $params = array(
- '/cake/1.2.x.x/cake/console/cake.php',
- '-working',
- '/cake/1.2.x.x/app',
- 'schema',
- 'run',
- 'create',
- '-dry',
- '-name',
- 'DbAcl'
- );
- $expected = array(
- 'app' => 'app',
- 'webroot' => 'webroot',
- 'working' => str_replace('/', DS, '/cake/1.2.x.x/app'),
- 'root' => str_replace('/', DS, '/cake/1.2.x.x'),
- );
- $Dispatcher->params = $Dispatcher->args = array();
- $Dispatcher->parseParams($params);
- $this->assertEquals($expected, $Dispatcher->params);
-
- $params = array(
- 'cake.php',
- '-working',
- 'C:/wamp/www/cake/app',
- 'bake',
- '-app',
- 'C:/wamp/www/apps/cake/app',
- );
- $expected = array(
- 'app' => 'app',
- 'webroot' => 'webroot',
- 'working' => 'C:\wamp\www\apps\cake\app',
- 'root' => 'C:\wamp\www\apps\cake'
- );
-
- $Dispatcher->params = $Dispatcher->args = array();
- $Dispatcher->parseParams($params);
- $this->assertEquals($expected, $Dispatcher->params);
-
- $params = array(
- 'cake.php',
- '-working',
- 'C:\wamp\www\cake\app',
- 'bake',
- '-app',
- 'C:\wamp\www\apps\cake\app',
- );
- $expected = array(
- 'app' => 'app',
- 'webroot' => 'webroot',
- 'working' => 'C:\wamp\www\apps\cake\app',
- 'root' => 'C:\wamp\www\apps\cake'
- );
- $Dispatcher->params = $Dispatcher->args = array();
- $Dispatcher->parseParams($params);
- $this->assertEquals($expected, $Dispatcher->params);
-
- $params = array(
- 'cake.php',
- '-working',
- 'C:\wamp\www\apps',
- 'bake',
- '-app',
- 'cake\app',
- '-url',
- 'http://example.com/some/url/with/a/path'
- );
- $expected = array(
- 'app' => 'app',
- 'webroot' => 'webroot',
- 'working' => 'C:\wamp\www\apps\cake\app',
- 'root' => 'C:\wamp\www\apps\cake',
- );
- $Dispatcher->params = $Dispatcher->args = array();
- $Dispatcher->parseParams($params);
- $this->assertEquals($expected, $Dispatcher->params);
-
- $params = array(
- '/home/amelo/dev/cake-common/cake/console/cake.php',
- '-root',
- '/home/amelo/dev/lsbu-vacancy',
- '-working',
- '/home/amelo/dev/lsbu-vacancy',
- '-app',
- 'app',
- );
- $expected = array(
- 'app' => 'app',
- 'webroot' => 'webroot',
- 'working' => '/home/amelo/dev/lsbu-vacancy/app',
- 'root' => '/home/amelo/dev/lsbu-vacancy',
- );
- $Dispatcher->params = $Dispatcher->args = array();
- $Dispatcher->parseParams($params);
- $this->assertEquals($expected, $Dispatcher->params);
-
- $params = array(
- '/cake/1.2.x.x/cake/console/cake.php',
- 'bake',
- '-app',
- 'new',
- '-app',
- 'old',
- '-working',
- '/var/www/htdocs'
- );
- $expected = array(
- 'app' => 'old',
- 'webroot' => 'webroot',
- 'working' => str_replace('/', DS, '/var/www/htdocs/old'),
- 'root' => str_replace('/', DS,'/var/www/htdocs')
- );
- $Dispatcher->parseParams($params);
- $this->assertEquals($expected, $Dispatcher->params);
-
- if (DS === '\\') {
- $params = array(
- 'cake.php',
- '-working',
- 'D:\www',
- 'bake',
- 'my_app',
- );
- $expected = array(
- 'working' => 'D:\\\\www',
- 'app' => 'www',
- 'root' => 'D:\\',
- 'webroot' => 'webroot'
- );
-
- $Dispatcher->params = $Dispatcher->args = array();
- $Dispatcher->parseParams($params);
- $this->assertEquals($expected, $Dispatcher->params);
- }
- }
-
-/**
- * Verify loading of (plugin-) shells
- *
- * @return void
- */
- public function testGetShell() {
- $this->skipIf(class_exists('SampleShell'), 'SampleShell Class already loaded.');
- $this->skipIf(class_exists('ExampleShell'), 'ExampleShell Class already loaded.');
-
- $Dispatcher = new TestShellDispatcher();
-
- $result = $Dispatcher->getShell('sample');
- $this->assertInstanceOf('SampleShell', $result);
-
- $Dispatcher = new TestShellDispatcher();
- $result = $Dispatcher->getShell('test_plugin.example');
- $this->assertInstanceOf('ExampleShell', $result);
- $this->assertEquals('TestPlugin', $result->plugin);
- $this->assertEquals('Example', $result->name);
-
- $Dispatcher = new TestShellDispatcher();
- $result = $Dispatcher->getShell('TestPlugin.example');
- $this->assertInstanceOf('ExampleShell', $result);
- }
-
-/**
- * Verify correct dispatch of Shell subclasses with a main method
- *
- * @return void
- */
- public function testDispatchShellWithMain() {
- $Dispatcher = new TestShellDispatcher();
- $Mock = $this->getMock('Shell', array(), array(&$Dispatcher), 'MockWithMainShell');
-
- $Mock->expects($this->once())->method('initialize');
- $Mock->expects($this->once())->method('loadTasks');
- $Mock->expects($this->once())->method('runCommand')
- ->with(null, array())
- ->will($this->returnValue(true));
-
- $Dispatcher->TestShell = $Mock;
-
- $Dispatcher->args = array('mock_with_main');
- $result = $Dispatcher->dispatch();
- $this->assertTrue($result);
- $this->assertEquals(array(), $Dispatcher->args);
- }
-
-/**
- * Verify correct dispatch of Shell subclasses without a main method
- *
- * @return void
- */
- public function testDispatchShellWithoutMain() {
- $Dispatcher = new TestShellDispatcher();
- $Shell = $this->getMock('Shell', array(), array(&$Dispatcher), 'MockWithoutMainShell');
-
- $Shell = new MockWithoutMainShell($Dispatcher);
- $this->mockObjects[] = $Shell;
-
- $Shell->expects($this->once())->method('initialize');
- $Shell->expects($this->once())->method('loadTasks');
- $Shell->expects($this->once())->method('runCommand')
- ->with('initdb', array('initdb'))
- ->will($this->returnValue(true));
-
- $Dispatcher->TestShell = $Shell;
-
- $Dispatcher->args = array('mock_without_main', 'initdb');
- $result = $Dispatcher->dispatch();
- $this->assertTrue($result);
- }
-
-/**
- * Verify correct dispatch of custom classes with a main method
- *
- * @return void
- */
- public function testDispatchNotAShellWithMain() {
- $Dispatcher = new TestShellDispatcher();
- $methods = get_class_methods('Object');
- array_push($methods, 'main', 'initdb', 'initialize', 'loadTasks', 'startup', '_secret');
- $Shell = $this->getMock('Object', $methods, array(), 'MockWithMainNotAShell');
-
- $Shell->expects($this->never())->method('initialize');
- $Shell->expects($this->never())->method('loadTasks');
- $Shell->expects($this->once())->method('startup');
- $Shell->expects($this->once())->method('main')->will($this->returnValue(true));
- $Dispatcher->TestShell = $Shell;
-
- $Dispatcher->args = array('mock_with_main_not_a');
- $result = $Dispatcher->dispatch();
- $this->assertTrue($result);
- $this->assertEquals(array(), $Dispatcher->args);
-
- $Shell = new MockWithMainNotAShell($Dispatcher);
- $this->mockObjects[] = $Shell;
- $Shell->expects($this->once())->method('initdb')->will($this->returnValue(true));
- $Shell->expects($this->once())->method('startup');
- $Dispatcher->TestShell = $Shell;
-
- $Dispatcher->args = array('mock_with_main_not_a', 'initdb');
- $result = $Dispatcher->dispatch();
- $this->assertTrue($result);
- }
-
-/**
- * Verify correct dispatch of custom classes without a main method
- *
- * @return void
- */
- public function testDispatchNotAShellWithoutMain() {
- $Dispatcher = new TestShellDispatcher();
- $methods = get_class_methods('Object');
- array_push($methods, 'main', 'initdb', 'initialize', 'loadTasks', 'startup', '_secret');
- $Shell = $this->getMock('Object', $methods, array(&$Dispatcher), 'MockWithoutMainNotAShell');
-
- $Shell->expects($this->never())->method('initialize');
- $Shell->expects($this->never())->method('loadTasks');
- $Shell->expects($this->once())->method('startup');
- $Shell->expects($this->once())->method('main')->will($this->returnValue(true));
- $Dispatcher->TestShell = $Shell;
-
- $Dispatcher->args = array('mock_without_main_not_a');
- $result = $Dispatcher->dispatch();
- $this->assertTrue($result);
- $this->assertEquals(array(), $Dispatcher->args);
-
- $Shell = new MockWithoutMainNotAShell($Dispatcher);
- $this->mockObjects[] = $Shell;
- $Shell->expects($this->once())->method('initdb')->will($this->returnValue(true));
- $Shell->expects($this->once())->method('startup');
- $Dispatcher->TestShell = $Shell;
-
- $Dispatcher->args = array('mock_without_main_not_a', 'initdb');
- $result = $Dispatcher->dispatch();
- $this->assertTrue($result);
- }
-
-/**
- * Verify shifting of arguments
- *
- * @return void
- */
- public function testShiftArgs() {
- $Dispatcher = new TestShellDispatcher();
-
- $Dispatcher->args = array('a', 'b', 'c');
- $this->assertEquals('a', $Dispatcher->shiftArgs());
- $this->assertSame($Dispatcher->args, array('b', 'c'));
-
- $Dispatcher->args = array('a' => 'b', 'c', 'd');
- $this->assertEquals('b', $Dispatcher->shiftArgs());
- $this->assertSame($Dispatcher->args, array('c', 'd'));
-
- $Dispatcher->args = array('a', 'b' => 'c', 'd');
- $this->assertEquals('a', $Dispatcher->shiftArgs());
- $this->assertSame($Dispatcher->args, array('b' => 'c', 'd'));
-
- $Dispatcher->args = array(0 => 'a', 2 => 'b', 30 => 'c');
- $this->assertEquals('a', $Dispatcher->shiftArgs());
- $this->assertSame($Dispatcher->args, array(0 => 'b', 1 => 'c'));
-
- $Dispatcher->args = array();
- $this->assertNull($Dispatcher->shiftArgs());
- $this->assertSame(array(), $Dispatcher->args);
- }
-
-}
diff --git a/lib/Cake/Test/Case/Console/ShellTest.php b/lib/Cake/Test/Case/Console/ShellTest.php
deleted file mode 100644
index 4e75b29b96d..00000000000
--- a/lib/Cake/Test/Case/Console/ShellTest.php
+++ /dev/null
@@ -1,871 +0,0 @@
-stopped = $status;
- }
-
- public function do_something() {
- }
-
- protected function _secret() {
- }
-
- protected function no_access() {
- }
-
- public function mergeVars($properties, $class, $normalize = true) {
- return $this->_mergeVars($properties, $class, $normalize);
- }
-
-}
-
-/**
- * Class for testing merging vars
- *
- * @package Cake.Test.Case.Console.Command
- */
-class TestMergeShell extends Shell {
-
- public $tasks = array('DbConfig', 'Fixture');
-
- public $uses = array('Comment');
-
-}
-
-/**
- * TestAppleTask class
- *
- * @package Cake.Test.Case.Console.Command
- */
-class TestAppleTask extends Shell {
-}
-
-/**
- * TestBananaTask class
- *
- * @package Cake.Test.Case.Console.Command
- */
-class TestBananaTask extends Shell {
-}
-
-/**
- * ShellTest class
- *
- * @package Cake.Test.Case.Console.Command
- */
-class ShellTest extends CakeTestCase {
-
-/**
- * Fixtures used in this test case
- *
- * @var array
- */
- public $fixtures = array(
- 'core.post', 'core.comment', 'core.article', 'core.user',
- 'core.tag', 'core.articles_tag', 'core.attachment'
- );
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
-
- $output = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $error = $this->getMock('ConsoleOutput', array(), array(), '', false);
- $in = $this->getMock('ConsoleInput', array(), array(), '', false);
- $this->Shell = new ShellTestShell($output, $error, $in);
-
- if (is_dir(TMP . 'shell_test')) {
- $Folder = new Folder(TMP . 'shell_test');
- $Folder->delete();
- }
- }
-
-/**
- * testConstruct method
- *
- * @return void
- */
- public function testConstruct() {
- $this->assertEquals('ShellTestShell', $this->Shell->name);
- $this->assertInstanceOf('ConsoleInput', $this->Shell->stdin);
- $this->assertInstanceOf('ConsoleOutput', $this->Shell->stdout);
- $this->assertInstanceOf('ConsoleOutput', $this->Shell->stderr);
- }
-
-/**
- * test merging vars
- *
- * @return void
- */
- public function testMergeVars() {
- $this->Shell->tasks = array('DbConfig' => array('one', 'two'));
- $this->Shell->uses = array('Posts');
- $this->Shell->mergeVars(array('tasks'), 'TestMergeShell');
- $this->Shell->mergeVars(array('uses'), 'TestMergeShell', false);
-
- $expected = array('DbConfig' => null, 'Fixture' => null, 'DbConfig' => array('one', 'two'));
- $this->assertEquals($expected, $this->Shell->tasks);
-
- $expected = array('Fixture' => null, 'DbConfig' => array('one', 'two'));
- $this->assertEquals($expected, Set::normalize($this->Shell->tasks), 'Normalized results are wrong.');
- $this->assertEquals(array('Comment', 'Posts'), $this->Shell->uses, 'Merged models are wrong.');
- }
-
-/**
- * testInitialize method
- *
- * @return void
- */
- public function testInitialize() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS),
- 'Model' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Model' . DS)
- ), App::RESET);
-
- CakePlugin::load('TestPlugin');
- $this->Shell->uses = array('TestPlugin.TestPluginPost');
- $this->Shell->initialize();
-
- $this->assertTrue(isset($this->Shell->TestPluginPost));
- $this->assertInstanceOf('TestPluginPost', $this->Shell->TestPluginPost);
- $this->assertEquals('TestPluginPost', $this->Shell->modelClass);
- CakePlugin::unload('TestPlugin');
-
- $this->Shell->uses = array('Comment');
- $this->Shell->initialize();
- $this->assertTrue(isset($this->Shell->Comment));
- $this->assertInstanceOf('Comment', $this->Shell->Comment);
- $this->assertEquals('Comment', $this->Shell->modelClass);
-
- App::build();
- }
-
-/**
- * testIn method
- *
- * @return void
- */
- public function testIn() {
- $this->Shell->stdin->expects($this->at(0))
- ->method('read')
- ->will($this->returnValue('n'));
-
- $this->Shell->stdin->expects($this->at(1))
- ->method('read')
- ->will($this->returnValue('Y'));
-
- $this->Shell->stdin->expects($this->at(2))
- ->method('read')
- ->will($this->returnValue('y'));
-
- $this->Shell->stdin->expects($this->at(3))
- ->method('read')
- ->will($this->returnValue('y'));
-
- $this->Shell->stdin->expects($this->at(4))
- ->method('read')
- ->will($this->returnValue('y'));
-
- $this->Shell->stdin->expects($this->at(5))
- ->method('read')
- ->will($this->returnValue('0'));
-
- $result = $this->Shell->in('Just a test?', array('y', 'n'), 'n');
- $this->assertEquals('n', $result);
-
- $result = $this->Shell->in('Just a test?', array('y', 'n'), 'n');
- $this->assertEquals('Y', $result);
-
- $result = $this->Shell->in('Just a test?', 'y,n', 'n');
- $this->assertEquals('y', $result);
-
- $result = $this->Shell->in('Just a test?', 'y/n', 'n');
- $this->assertEquals('y', $result);
-
- $result = $this->Shell->in('Just a test?', 'y', 'y');
- $this->assertEquals('y', $result);
-
- $result = $this->Shell->in('Just a test?', array(0, 1, 2), '0');
- $this->assertEquals('0', $result);
- }
-
-/**
- * Test in() when not interactive.
- *
- * @return void
- */
- public function testInNonInteractive() {
- $this->Shell->interactive = false;
-
- $result = $this->Shell->in('Just a test?', 'y/n', 'n');
- $this->assertEquals('n', $result);
- }
-
-/**
- * testOut method
- *
- * @return void
- */
- public function testOut() {
- $this->Shell->stdout->expects($this->at(0))
- ->method('write')
- ->with("Just a test", 1);
-
- $this->Shell->stdout->expects($this->at(1))
- ->method('write')
- ->with(array('Just', 'a', 'test'), 1);
-
- $this->Shell->stdout->expects($this->at(2))
- ->method('write')
- ->with(array('Just', 'a', 'test'), 2);
-
- $this->Shell->stdout->expects($this->at(3))
- ->method('write')
- ->with('', 1);
-
- $this->Shell->out('Just a test');
-
- $this->Shell->out(array('Just', 'a', 'test'));
-
- $this->Shell->out(array('Just', 'a', 'test'), 2);
-
- $this->Shell->out();
- }
-
-/**
- * test that verbose and quiet output levels work
- *
- * @return void
- */
- public function testVerboseOutput() {
- $this->Shell->stdout->expects($this->at(0))->method('write')
- ->with('Verbose', 1);
- $this->Shell->stdout->expects($this->at(1))->method('write')
- ->with('Normal', 1);
- $this->Shell->stdout->expects($this->at(2))->method('write')
- ->with('Quiet', 1);
-
- $this->Shell->params['verbose'] = true;
- $this->Shell->params['quiet'] = false;
-
- $this->Shell->out('Verbose', 1, Shell::VERBOSE);
- $this->Shell->out('Normal', 1, Shell::NORMAL);
- $this->Shell->out('Quiet', 1, Shell::QUIET);
- }
-
-/**
- * test that verbose and quiet output levels work
- *
- * @return void
- */
- public function testQuietOutput() {
- $this->Shell->stdout->expects($this->once())->method('write')
- ->with('Quiet', 1);
-
- $this->Shell->params['verbose'] = false;
- $this->Shell->params['quiet'] = true;
-
- $this->Shell->out('Verbose', 1, Shell::VERBOSE);
- $this->Shell->out('Normal', 1, Shell::NORMAL);
- $this->Shell->out('Quiet', 1, Shell::QUIET);
- }
-
-/**
- * testErr method
- *
- * @return void
- */
- public function testErr() {
- $this->Shell->stderr->expects($this->at(0))
- ->method('write')
- ->with("Just a test", 1);
-
- $this->Shell->stderr->expects($this->at(1))
- ->method('write')
- ->with(array('Just', 'a', 'test'), 1);
-
- $this->Shell->stderr->expects($this->at(2))
- ->method('write')
- ->with(array('Just', 'a', 'test'), 2);
-
- $this->Shell->stderr->expects($this->at(3))
- ->method('write')
- ->with('', 1);
-
- $this->Shell->err('Just a test');
-
- $this->Shell->err(array('Just', 'a', 'test'));
-
- $this->Shell->err(array('Just', 'a', 'test'), 2);
-
- $this->Shell->err();
- }
-
-/**
- * testNl
- *
- * @return void
- */
- public function testNl() {
- $newLine = "\n";
- if (DS === '\\') {
- $newLine = "\r\n";
- }
- $this->assertEquals($this->Shell->nl(), $newLine);
- $this->assertEquals($this->Shell->nl(true), $newLine);
- $this->assertEquals("", $this->Shell->nl(false));
- $this->assertEquals($this->Shell->nl(2), $newLine . $newLine);
- $this->assertEquals($this->Shell->nl(1), $newLine);
- }
-
-/**
- * testHr
- *
- * @return void
- */
- public function testHr() {
- $bar = '---------------------------------------------------------------';
-
- $this->Shell->stdout->expects($this->at(0))->method('write')->with('', 0);
- $this->Shell->stdout->expects($this->at(1))->method('write')->with($bar, 1);
- $this->Shell->stdout->expects($this->at(2))->method('write')->with('', 0);
-
- $this->Shell->stdout->expects($this->at(3))->method('write')->with("", true);
- $this->Shell->stdout->expects($this->at(4))->method('write')->with($bar, 1);
- $this->Shell->stdout->expects($this->at(5))->method('write')->with("", true);
-
- $this->Shell->stdout->expects($this->at(6))->method('write')->with("", 2);
- $this->Shell->stdout->expects($this->at(7))->method('write')->with($bar, 1);
- $this->Shell->stdout->expects($this->at(8))->method('write')->with("", 2);
-
- $this->Shell->hr();
-
- $this->Shell->hr(true);
-
- $this->Shell->hr(2);
- }
-
-/**
- * testError
- *
- * @return void
- */
- public function testError() {
- $this->Shell->stderr->expects($this->at(0))
- ->method('write')
- ->with("Error: Foo Not Found", 1);
-
- $this->Shell->stderr->expects($this->at(1))
- ->method('write')
- ->with("Error: Foo Not Found", 1);
-
- $this->Shell->stderr->expects($this->at(2))
- ->method('write')
- ->with("Searched all...", 1);
-
- $this->Shell->error('Foo Not Found');
- $this->assertSame($this->Shell->stopped, 1);
-
- $this->Shell->stopped = null;
-
- $this->Shell->error('Foo Not Found', 'Searched all...');
- $this->assertSame($this->Shell->stopped, 1);
- }
-
-/**
- * testLoadTasks method
- *
- * @return void
- */
- public function testLoadTasks() {
- $this->assertTrue($this->Shell->loadTasks());
-
- $this->Shell->tasks = null;
- $this->assertTrue($this->Shell->loadTasks());
-
- $this->Shell->tasks = false;
- $this->assertTrue($this->Shell->loadTasks());
-
- $this->Shell->tasks = true;
- $this->assertTrue($this->Shell->loadTasks());
-
- $this->Shell->tasks = array();
- $this->assertTrue($this->Shell->loadTasks());
-
- $this->Shell->tasks = array('TestApple');
- $this->assertTrue($this->Shell->loadTasks());
- $this->assertInstanceOf('TestAppleTask', $this->Shell->TestApple);
-
- $this->Shell->tasks = 'TestBanana';
- $this->assertTrue($this->Shell->loadTasks());
- $this->assertInstanceOf('TestAppleTask', $this->Shell->TestApple);
- $this->assertInstanceOf('TestBananaTask', $this->Shell->TestBanana);
-
- unset($this->Shell->ShellTestApple, $this->Shell->TestBanana);
-
- $this->Shell->tasks = array('TestApple', 'TestBanana');
- $this->assertTrue($this->Shell->loadTasks());
- $this->assertInstanceOf('TestAppleTask', $this->Shell->TestApple);
- $this->assertInstanceOf('TestBananaTask', $this->Shell->TestBanana);
- }
-
-/**
- * test that __get() makes args and params references
- *
- * @return void
- */
- public function testMagicGetArgAndParamReferences() {
- $this->Shell->tasks = array('TestApple');
- $this->Shell->args = array('one');
- $this->Shell->params = array('help' => false);
- $this->Shell->loadTasks();
- $result = $this->Shell->TestApple;
-
- $this->Shell->args = array('one', 'two');
-
- $this->assertSame($this->Shell->args, $result->args);
- $this->assertSame($this->Shell->params, $result->params);
- }
-
-/**
- * testShortPath method
- *
- * @return void
- */
- public function testShortPath() {
- $path = $expected = DS . 'tmp' . DS . 'ab' . DS . 'cd';
- $this->assertEquals($expected, $this->Shell->shortPath($path));
-
- $path = $expected = DS . 'tmp' . DS . 'ab' . DS . 'cd' . DS;
- $this->assertEquals($expected, $this->Shell->shortPath($path));
-
- $path = $expected = DS . 'tmp' . DS . 'ab' . DS . 'index.php';
- $this->assertEquals($expected, $this->Shell->shortPath($path));
-
- $path = DS . 'tmp' . DS . 'ab' . DS . DS . 'cd';
- $expected = DS . 'tmp' . DS . 'ab' . DS . 'cd';
- $this->assertEquals($expected, $this->Shell->shortPath($path));
-
- $path = 'tmp' . DS . 'ab';
- $expected = 'tmp' . DS . 'ab';
- $this->assertEquals($expected, $this->Shell->shortPath($path));
-
- $path = 'tmp' . DS . 'ab';
- $expected = 'tmp' . DS . 'ab';
- $this->assertEquals($expected, $this->Shell->shortPath($path));
-
- $path = APP;
- $expected = DS . basename(APP) . DS;
- $this->assertEquals($expected, $this->Shell->shortPath($path));
-
- $path = APP . 'index.php';
- $expected = DS . basename(APP) . DS . 'index.php';
- $this->assertEquals($expected, $this->Shell->shortPath($path));
- }
-
-/**
- * testCreateFile method
- *
- * @return void
- */
- public function testCreateFileNonInteractive() {
- $this->skipIf(DIRECTORY_SEPARATOR === '\\', 'Not supported on Windows.');
-
- $path = TMP . 'shell_test';
- $file = $path . DS . 'file1.php';
-
- $Folder = new Folder($path, true);
-
- $this->Shell->interactive = false;
-
- $contents = "Shell->createFile($file, $contents);
- $this->assertTrue($result);
- $this->assertTrue(file_exists($file));
- $this->assertEquals(file_get_contents($file), $contents);
-
- $contents = "Shell->createFile($file, $contents);
- $this->assertTrue($result);
- $this->assertTrue(file_exists($file));
- $this->assertEquals(file_get_contents($file), $contents);
- }
-
-/**
- * test createFile when the shell is interactive.
- *
- * @return void
- */
- public function testCreateFileInteractive() {
- $this->skipIf(DIRECTORY_SEPARATOR === '\\', 'Not supported on Windows.');
-
- $path = TMP . 'shell_test';
- $file = $path . DS . 'file1.php';
- $Folder = new Folder($path, true);
-
- $this->Shell->interactive = true;
-
- $this->Shell->stdin->expects($this->at(0))
- ->method('read')
- ->will($this->returnValue('n'));
-
- $this->Shell->stdin->expects($this->at(1))
- ->method('read')
- ->will($this->returnValue('y'));
-
- $contents = "Shell->createFile($file, $contents);
- $this->assertTrue($result);
- $this->assertTrue(file_exists($file));
- $this->assertEquals(file_get_contents($file), $contents);
-
- // no overwrite
- $contents = 'new contents';
- $result = $this->Shell->createFile($file, $contents);
- $this->assertFalse($result);
- $this->assertTrue(file_exists($file));
- $this->assertNotEquals($contents, file_get_contents($file));
-
- // overwrite
- $contents = 'more new contents';
- $result = $this->Shell->createFile($file, $contents);
- $this->assertTrue($result);
- $this->assertTrue(file_exists($file));
- $this->assertEquals($contents, file_get_contents($file));
- }
-
-/**
- * Test that you can't create files that aren't writable.
- *
- * @return void
- */
- public function testCreateFileNoPermissions() {
- $path = TMP . 'shell_test';
- $file = $path . DS . 'no_perms';
-
- mkdir($path);
- chmod($path, 0444);
-
- $this->Shell->createFile($file, 'testing');
- $this->assertFalse(file_exists($file));
-
- chmod($path, 0744);
- rmdir($path);
- }
-
-/**
- * testCreateFileWindows method
- *
- * @return void
- */
- public function testCreateFileWindowsNonInteractive() {
- $this->skipIf(DIRECTORY_SEPARATOR === '/', 'testCreateFileWindowsNonInteractive supported on Windows only.');
-
- $path = TMP . 'shell_test';
- $file = $path . DS . 'file1.php';
-
- $Folder = new Folder($path, true);
-
- $this->Shell->interactive = false;
-
- $contents = "Shell->createFile($file, $contents);
- $this->assertTrue($result);
- $this->assertTrue(file_exists($file));
- $this->assertEquals(file_get_contents($file), $contents);
-
- $contents = "Shell->createFile($file, $contents);
- $this->assertTrue($result);
- $this->assertTrue(file_exists($file));
- $this->assertEquals(file_get_contents($file), $contents);
-
- $Folder = new Folder($path);
- $Folder->delete();
- }
-
-/**
- * test createFile on windows with interactive on.
- *
- * @return void
- */
- public function testCreateFileWindowsInteractive() {
- $this->skipIf(DIRECTORY_SEPARATOR === '/', 'testCreateFileWindowsInteractive supported on Windows only.');
- $path = TMP . 'shell_test';
- $file = $path . DS . 'file1.php';
- $Folder = new Folder($path, true);
-
- $this->Shell->interactive = true;
-
- $this->Shell->stdin->expects($this->at(0))
- ->method('read')
- ->will($this->returnValue('n'));
-
- $this->Shell->stdin->expects($this->at(1))
- ->method('read')
- ->will($this->returnValue('y'));
-
- $contents = "Shell->createFile($file, $contents);
- $this->assertTrue($result);
- $this->assertTrue(file_exists($file));
- $this->assertEquals(file_get_contents($file), $contents);
-
- // no overwrite
- $contents = 'new contents';
- $result = $this->Shell->createFile($file, $contents);
- $this->assertFalse($result);
- $this->assertTrue(file_exists($file));
- $this->assertNotEquals($contents, file_get_contents($file));
-
- // overwrite
- $contents = 'more new contents';
- $result = $this->Shell->createFile($file, $contents);
- $this->assertTrue($result);
- $this->assertTrue(file_exists($file));
- $this->assertEquals($contents, file_get_contents($file));
-
- $Folder->delete();
- }
-
-/**
- * test hasTask method
- *
- * @return void
- */
- public function testHasTask() {
- $this->Shell->tasks = array('Extract', 'DbConfig');
- $this->Shell->loadTasks();
-
- $this->assertTrue($this->Shell->hasTask('extract'));
- $this->assertTrue($this->Shell->hasTask('Extract'));
- $this->assertFalse($this->Shell->hasTask('random'));
-
- $this->assertTrue($this->Shell->hasTask('db_config'));
- $this->assertTrue($this->Shell->hasTask('DbConfig'));
- }
-
-/**
- * test the hasMethod
- *
- * @return void
- */
- public function testHasMethod() {
- $this->assertTrue($this->Shell->hasMethod('do_something'));
- $this->assertFalse($this->Shell->hasMethod('hr'), 'hr is callable');
- $this->assertFalse($this->Shell->hasMethod('_secret'), '_secret is callable');
- $this->assertFalse($this->Shell->hasMethod('no_access'), 'no_access is callable');
- }
-
-/**
- * test run command calling main.
- *
- * @return void
- */
- public function testRunCommandMain() {
- $methods = get_class_methods('Shell');
- $Mock = $this->getMock('Shell', array('main', 'startup'), array(), '', false);
-
- $Mock->expects($this->once())->method('main')->will($this->returnValue(true));
- $result = $Mock->runCommand(null, array());
- $this->assertTrue($result);
- }
-
-/**
- * test run command calling a legit method.
- *
- * @return void
- */
- public function testRunCommandWithMethod() {
- $methods = get_class_methods('Shell');
- $Mock = $this->getMock('Shell', array('hit_me', 'startup'), array(), '', false);
-
- $Mock->expects($this->once())->method('hit_me')->will($this->returnValue(true));
- $result = $Mock->runCommand('hit_me', array());
- $this->assertTrue($result);
- }
-
-/**
- * test run command causing exception on Shell method.
- *
- * @return void
- */
- public function testRunCommandBaseclassMethod() {
- $Mock = $this->getMock('Shell', array('startup', 'getOptionParser', 'out'), array(), '', false);
- $Parser = $this->getMock('ConsoleOptionParser', array(), array(), '', false);
-
- $Parser->expects($this->once())->method('help');
- $Mock->expects($this->once())->method('getOptionParser')
- ->will($this->returnValue($Parser));
- $Mock->expects($this->never())->method('hr');
- $Mock->expects($this->once())->method('out');
-
- $result = $Mock->runCommand('hr', array());
- }
-
-/**
- * test run command causing exception on Shell method.
- *
- * @return void
- */
- public function testRunCommandMissingMethod() {
- $methods = get_class_methods('Shell');
- $Mock = $this->getMock('Shell', array('startup', 'getOptionParser', 'out'), array(), '', false);
- $Parser = $this->getMock('ConsoleOptionParser', array(), array(), '', false);
-
- $Parser->expects($this->once())->method('help');
- $Mock->expects($this->never())->method('idontexist');
- $Mock->expects($this->once())->method('getOptionParser')
- ->will($this->returnValue($Parser));
- $Mock->expects($this->once())->method('out');
-
- $result = $Mock->runCommand('idontexist', array());
- $this->assertFalse($result);
- }
-
-/**
- * test that a --help causes help to show.
- *
- * @return void
- */
- public function testRunCommandTriggeringHelp() {
- $Parser = $this->getMock('ConsoleOptionParser', array(), array(), '', false);
- $Parser->expects($this->once())->method('parse')
- ->with(array('--help'))
- ->will($this->returnValue(array(array('help' => true), array())));
- $Parser->expects($this->once())->method('help');
-
- $Shell = $this->getMock('Shell', array('getOptionParser', 'out', 'startup', '_welcome'), array(), '', false);
- $Shell->expects($this->once())->method('getOptionParser')
- ->will($this->returnValue($Parser));
- $Shell->expects($this->once())->method('out');
-
- $Shell->runCommand(null, array('--help'));
- }
-
-/**
- * test that runCommand will call runCommand on the task.
- *
- * @return void
- */
- public function testRunCommandHittingTask() {
- $Shell = $this->getMock('Shell', array('hasTask', 'startup'), array(), '', false);
- $task = $this->getMock('Shell', array('execute', 'runCommand'), array(), '', false);
- $task->expects($this->any())
- ->method('runCommand')
- ->with('execute', array('one', 'value'));
-
- $Shell->expects($this->once())->method('startup');
- $Shell->expects($this->any())
- ->method('hasTask')
- ->will($this->returnValue(true));
-
- $Shell->RunCommand = $task;
-
- $result = $Shell->runCommand('run_command', array('run_command', 'one', 'value'));
- }
-
-/**
- * test wrapBlock wrapping text.
- *
- * @return void
- */
- public function testWrapText() {
- $text = 'This is the song that never ends. This is the song that never ends. This is the song that never ends.';
- $result = $this->Shell->wrapText($text, 33);
- $expected = <<assertEquals($expected, $result, 'Text not wrapped.');
-
- $result = $this->Shell->wrapText($text, array('indent' => ' ', 'width' => 33));
- $expected = <<assertEquals($expected, $result, 'Text not wrapped.');
- }
-
-/**
- * Testing camel cased naming of tasks
- *
- * @return void
- */
- public function testShellNaming() {
- $this->Shell->tasks = array('TestApple');
- $this->Shell->loadTasks();
- $expected = 'TestApple';
- $this->assertEquals($expected, $this->Shell->TestApple->name);
- }
-
-/**
- * Test that option parsers are created with the correct name/command.
- *
- * @return void
- */
- public function testGetOptionParser() {
- $this->Shell->name = 'test';
- $this->Shell->plugin = 'plugin';
- $parser = $this->Shell->getOptionParser();
-
- $this->assertEquals('plugin.test', $parser->command());
- }
-
-}
diff --git a/lib/Cake/Test/Case/Console/TaskCollectionTest.php b/lib/Cake/Test/Case/Console/TaskCollectionTest.php
deleted file mode 100644
index a681b490b9d..00000000000
--- a/lib/Cake/Test/Case/Console/TaskCollectionTest.php
+++ /dev/null
@@ -1,124 +0,0 @@
-getMock('Shell', array(), array(), '', false);
- $dispatcher = $this->getMock('ShellDispatcher', array(), array(), '', false);
- $this->Tasks = new TaskCollection($shell, $dispatcher);
- }
-
-/**
- * tearDown
- *
- * @return void
- */
- public function tearDown() {
- unset($this->Tasks);
- parent::tearDown();
- }
-
-/**
- * test triggering callbacks on loaded tasks
- *
- * @return void
- */
- public function testLoad() {
- $result = $this->Tasks->load('DbConfig');
- $this->assertInstanceOf('DbConfigTask', $result);
- $this->assertInstanceOf('DbConfigTask', $this->Tasks->DbConfig);
-
- $result = $this->Tasks->attached();
- $this->assertEquals(array('DbConfig'), $result, 'attached() results are wrong.');
- }
-
-/**
- * test load and enable = false
- *
- * @return void
- */
- public function testLoadWithEnableFalse() {
- $result = $this->Tasks->load('DbConfig', array('enabled' => false));
- $this->assertInstanceOf('DbConfigTask', $result);
- $this->assertInstanceOf('DbConfigTask', $this->Tasks->DbConfig);
-
- $this->assertFalse($this->Tasks->enabled('DbConfig'), 'DbConfigTask should be disabled');
- }
-
-/**
- * test missingtask exception
- *
- * @expectedException MissingTaskException
- * @return void
- */
- public function testLoadMissingTask() {
- $result = $this->Tasks->load('ThisTaskShouldAlwaysBeMissing');
- }
-
-/**
- * test loading a plugin helper.
- *
- * @return void
- */
- public function testLoadPluginTask() {
- $dispatcher = $this->getMock('ShellDispatcher', array(), array(), '', false);
- $shell = $this->getMock('Shell', array(), array(), '', false);
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ));
- CakePlugin::load('TestPlugin');
- $this->Tasks = new TaskCollection($shell, $dispatcher);
-
- $result = $this->Tasks->load('TestPlugin.OtherTask');
- $this->assertInstanceOf('OtherTaskTask', $result, 'Task class is wrong.');
- $this->assertInstanceOf('OtherTaskTask', $this->Tasks->OtherTask, 'Class is wrong');
- CakePlugin::unload();
- }
-
-/**
- * test unload()
- *
- * @return void
- */
- public function testUnload() {
- $this->Tasks->load('Extract');
- $this->Tasks->load('DbConfig');
-
- $result = $this->Tasks->attached();
- $this->assertEquals(array('Extract', 'DbConfig'), $result, 'loaded tasks is wrong');
-
- $this->Tasks->unload('DbConfig');
- $this->assertFalse(isset($this->Tasks->DbConfig));
- $this->assertTrue(isset($this->Tasks->Extract));
-
- $result = $this->Tasks->attached();
- $this->assertEquals(array('Extract'), $result, 'loaded tasks is wrong');
- }
-
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/Acl/DbAclTest.php b/lib/Cake/Test/Case/Controller/Component/Acl/DbAclTest.php
deleted file mode 100644
index 4137e648da4..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/Acl/DbAclTest.php
+++ /dev/null
@@ -1,537 +0,0 @@
- array('with' => 'PermissionTwoTest'));
-}
-
-/**
- * AcoTwoTest class
- *
- * @package Cake.Test.Case.Controller.Component.Acl
- */
-class AcoTwoTest extends AclNodeTwoTestBase {
-
-/**
- * name property
- *
- * @var string 'AcoTwoTest'
- */
- public $name = 'AcoTwoTest';
-
-/**
- * useTable property
- *
- * @var string 'aco_twos'
- */
- public $useTable = 'aco_twos';
-
-/**
- * hasAndBelongsToMany property
- *
- * @var array
- */
- public $hasAndBelongsToMany = array('AroTwoTest' => array('with' => 'PermissionTwoTest'));
-}
-
-/**
- * PermissionTwoTest class
- *
- * @package Cake.Test.Case.Controller.Component.Acl
- */
-class PermissionTwoTest extends CakeTestModel {
-
-/**
- * name property
- *
- * @var string 'PermissionTwoTest'
- */
- public $name = 'PermissionTwoTest';
-
-/**
- * useTable property
- *
- * @var string 'aros_aco_twos'
- */
- public $useTable = 'aros_aco_twos';
-
-/**
- * cacheQueries property
- *
- * @var bool false
- */
- public $cacheQueries = false;
-
-/**
- * belongsTo property
- *
- * @var array
- */
- public $belongsTo = array('AroTwoTest' => array('foreignKey' => 'aro_id'), 'AcoTwoTest' => array('foreignKey' => 'aco_id'));
-
-/**
- * actsAs property
- *
- * @var mixed null
- */
- public $actsAs = null;
-}
-
-/**
- * DbAclTwoTest class
- *
- * @package Cake.Test.Case.Controller.Component.Acl
- */
-class DbAclTwoTest extends DbAcl {
-
-/**
- * construct method
- *
- * @return void
- */
- public function __construct() {
- $this->Aro = new AroTwoTest();
- $this->Aro->Permission = new PermissionTwoTest();
- $this->Aco = new AcoTwoTest();
- $this->Aro->Permission = new PermissionTwoTest();
- }
-
-}
-
-/**
- * Test case for AclComponent using the DbAcl implementation.
- *
- * @package Cake.Test.Case.Controller.Component.Acl
- */
-class DbAclTest extends CakeTestCase {
-
-/**
- * fixtures property
- *
- * @var array
- */
- public $fixtures = array('core.aro_two', 'core.aco_two', 'core.aros_aco_two');
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- Configure::write('Acl.classname', 'DbAclTwoTest');
- Configure::write('Acl.database', 'test');
- $Collection = new ComponentCollection();
- $this->Acl = new AclComponent($Collection);
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- unset($this->Acl);
- }
-
-/**
- * testAclCreate method
- *
- * @return void
- */
- public function testCreate() {
- $this->Acl->Aro->create(array('alias' => 'Chotchkey'));
- $this->assertTrue((bool)$this->Acl->Aro->save());
-
- $parent = $this->Acl->Aro->id;
-
- $this->Acl->Aro->create(array('parent_id' => $parent, 'alias' => 'Joanna'));
- $this->assertTrue((bool)$this->Acl->Aro->save());
-
- $this->Acl->Aro->create(array('parent_id' => $parent, 'alias' => 'Stapler'));
- $this->assertTrue((bool)$this->Acl->Aro->save());
-
- $root = $this->Acl->Aco->node('ROOT');
- $parent = $root[0]['AcoTwoTest']['id'];
-
- $this->Acl->Aco->create(array('parent_id' => $parent, 'alias' => 'Drinks'));
- $this->assertTrue((bool)$this->Acl->Aco->save());
-
- $this->Acl->Aco->create(array('parent_id' => $parent, 'alias' => 'PiecesOfFlair'));
- $this->assertTrue((bool)$this->Acl->Aco->save());
- }
-
-/**
- * testAclCreateWithParent method
- *
- * @return void
- */
- public function testCreateWithParent() {
- $parent = $this->Acl->Aro->findByAlias('Peter', null, null, -1);
- $this->Acl->Aro->create();
- $this->Acl->Aro->save(array(
- 'alias' => 'Subordinate',
- 'model' => 'User',
- 'foreign_key' => 7,
- 'parent_id' => $parent['AroTwoTest']['id']
- ));
- $result = $this->Acl->Aro->findByAlias('Subordinate', null, null, -1);
- $this->assertEquals(16, $result['AroTwoTest']['lft']);
- $this->assertEquals(17, $result['AroTwoTest']['rght']);
- }
-
-/**
- * testDbAclAllow method
- *
- * @expectedException PHPUnit_Framework_Error_Warning
- * @return void
- */
- public function testAllow() {
- $this->assertFalse($this->Acl->check('Micheal', 'tpsReports', 'read'));
- $this->assertTrue($this->Acl->allow('Micheal', 'tpsReports', array('read', 'delete', 'update')));
- $this->assertTrue($this->Acl->check('Micheal', 'tpsReports', 'update'));
- $this->assertTrue($this->Acl->check('Micheal', 'tpsReports', 'read'));
- $this->assertTrue($this->Acl->check('Micheal', 'tpsReports', 'delete'));
-
- $this->assertFalse($this->Acl->check('Micheal', 'tpsReports', 'create'));
- $this->assertTrue($this->Acl->allow('Micheal', 'ROOT/tpsReports', 'create'));
- $this->assertTrue($this->Acl->check('Micheal', 'tpsReports', 'create'));
- $this->assertTrue($this->Acl->check('Micheal', 'tpsReports', 'delete'));
- $this->assertTrue($this->Acl->allow('Micheal', 'printers', 'create'));
- // Michael no longer has his delete permission for tpsReports!
- $this->assertTrue($this->Acl->check('Micheal', 'tpsReports', 'delete'));
- $this->assertTrue($this->Acl->check('Micheal', 'printers', 'create'));
-
- $this->assertFalse($this->Acl->check('root/users/Samir', 'ROOT/tpsReports/view'));
- $this->assertTrue($this->Acl->allow('root/users/Samir', 'ROOT/tpsReports/view', '*'));
- $this->assertTrue($this->Acl->check('Samir', 'view', 'read'));
- $this->assertTrue($this->Acl->check('root/users/Samir', 'ROOT/tpsReports/view', 'update'));
-
- $this->assertFalse($this->Acl->check('root/users/Samir', 'ROOT/tpsReports/update','*'));
- $this->assertTrue($this->Acl->allow('root/users/Samir', 'ROOT/tpsReports/update', '*'));
- $this->assertTrue($this->Acl->check('Samir', 'update', 'read'));
- $this->assertTrue($this->Acl->check('root/users/Samir', 'ROOT/tpsReports/update', 'update'));
- // Samir should still have his tpsReports/view permissions, but does not
- $this->assertTrue($this->Acl->check('root/users/Samir', 'ROOT/tpsReports/view', 'update'));
-
- $this->assertFalse($this->Acl->allow('Lumbergh', 'ROOT/tpsReports/DoesNotExist', 'create'));
- }
-
-/**
- * testAllowInvalidNode method
- *
- * @expectedException PHPUnit_Framework_Error_Warning
- * @return void
- */
- public function testAllowInvalidNode() {
- $this->Acl->allow('Homer', 'tpsReports', 'create');
- }
-
-/**
- * testDbAclCheck method
- *
- * @return void
- */
- public function testCheck() {
- $this->assertTrue($this->Acl->check('Samir', 'print', 'read'));
- $this->assertTrue($this->Acl->check('Lumbergh', 'current', 'read'));
- $this->assertFalse($this->Acl->check('Milton', 'smash', 'read'));
- $this->assertFalse($this->Acl->check('Milton', 'current', 'update'));
-
- $this->assertFalse($this->Acl->check(null, 'printers', 'create'));
- $this->assertFalse($this->Acl->check('managers', null, 'read'));
-
- $this->assertTrue($this->Acl->check('Bobs', 'ROOT/tpsReports/view/current', 'read'));
- $this->assertFalse($this->Acl->check('Samir', 'ROOT/tpsReports/update', 'read'));
-
- $this->assertFalse($this->Acl->check('root/users/Milton', 'smash', 'delete'));
- }
-
-/**
- * testCheckInvalidNode method
- *
- * @expectedException PHPUnit_Framework_Error_Warning
- * @return void
- */
- public function testCheckInvalidNode() {
- $this->assertFalse($this->Acl->check('WRONG', 'tpsReports', 'read'));
- }
-
-/**
- * testCheckInvalidPermission method
- *
- * @expectedException PHPUnit_Framework_Error_Notice
- * @return void
- */
- public function testCheckInvalidPermission() {
- $this->Acl->check('Lumbergh', 'smash', 'foobar');
- }
-
-/**
- * testCheckMissingPermission method
- *
- * @expectedException PHPUnit_Framework_Error_Warning
- * @return void
- */
- public function testCheckMissingPermission() {
- $this->Acl->check('users', 'NonExistant', 'read');
- }
-
-/**
- * testDbAclCascadingDeny function
- *
- * Setup the acl permissions such that Bobs inherits from admin.
- * deny Admin delete access to a specific resource, check the permisssions are inherited.
- *
- * @return void
- */
- public function testAclCascadingDeny() {
- $this->Acl->inherit('Bobs', 'ROOT', '*');
- $this->assertTrue($this->Acl->check('admin', 'tpsReports', 'delete'));
- $this->assertTrue($this->Acl->check('Bobs', 'tpsReports', 'delete'));
- $this->Acl->deny('admin', 'tpsReports', 'delete');
- $this->assertFalse($this->Acl->check('admin', 'tpsReports', 'delete'));
- $this->assertFalse($this->Acl->check('Bobs', 'tpsReports', 'delete'));
- }
-
-/**
- * testDbAclDeny method
- *
- * @expectedException PHPUnit_Framework_Error_Warning
- * @return void
- */
- public function testDeny() {
- $this->assertTrue($this->Acl->check('Micheal', 'smash', 'delete'));
- $this->Acl->deny('Micheal', 'smash', 'delete');
- $this->assertFalse($this->Acl->check('Micheal', 'smash', 'delete'));
- $this->assertTrue($this->Acl->check('Micheal', 'smash', 'read'));
- $this->assertTrue($this->Acl->check('Micheal', 'smash', 'create'));
- $this->assertTrue($this->Acl->check('Micheal', 'smash', 'update'));
- $this->assertFalse($this->Acl->check('Micheal', 'smash', '*'));
-
- $this->assertTrue($this->Acl->check('Samir', 'refill', '*'));
- $this->Acl->deny('Samir', 'refill', '*');
- $this->assertFalse($this->Acl->check('Samir', 'refill', 'create'));
- $this->assertFalse($this->Acl->check('Samir', 'refill', 'update'));
- $this->assertFalse($this->Acl->check('Samir', 'refill', 'read'));
- $this->assertFalse($this->Acl->check('Samir', 'refill', 'delete'));
-
- $result = $this->Acl->Aro->Permission->find('all', array('conditions' => array('AroTwoTest.alias' => 'Samir')));
- $expected = '-1';
- $this->assertEquals($expected, $result[0]['PermissionTwoTest']['_delete']);
-
- $this->assertFalse($this->Acl->deny('Lumbergh', 'ROOT/tpsReports/DoesNotExist', 'create'));
- }
-
-/**
- * testAclNodeLookup method
- *
- * @return void
- */
- public function testAclNodeLookup() {
- $result = $this->Acl->Aro->node('root/users/Samir');
- $expected = array(
- array('AroTwoTest' => array('id' => '7', 'parent_id' => '4', 'model' => 'User', 'foreign_key' => 3, 'alias' => 'Samir')),
- array('AroTwoTest' => array('id' => '4', 'parent_id' => '1', 'model' => 'Group', 'foreign_key' => 3, 'alias' => 'users')),
- array('AroTwoTest' => array('id' => '1', 'parent_id' => null, 'model' => null, 'foreign_key' => null, 'alias' => 'root'))
- );
- $this->assertEquals($expected, $result);
-
- $result = $this->Acl->Aco->node('ROOT/tpsReports/view/current');
- $expected = array(
- array('AcoTwoTest' => array('id' => '4', 'parent_id' => '3', 'model' => null, 'foreign_key' => null, 'alias' => 'current')),
- array('AcoTwoTest' => array('id' => '3', 'parent_id' => '2', 'model' => null, 'foreign_key' => null, 'alias' => 'view')),
- array('AcoTwoTest' => array('id' => '2', 'parent_id' => '1', 'model' => null, 'foreign_key' => null, 'alias' => 'tpsReports')),
- array('AcoTwoTest' => array('id' => '1', 'parent_id' => null, 'model' => null, 'foreign_key' => null, 'alias' => 'ROOT')),
- );
- $this->assertEquals($expected, $result);
- }
-
-/**
- * testDbInherit method
- *
- * @return void
- */
- public function testInherit() {
- //parent doesn't have access inherit should still deny
- $this->assertFalse($this->Acl->check('Milton', 'smash', 'delete'));
- $this->Acl->inherit('Milton', 'smash', 'delete');
- $this->assertFalse($this->Acl->check('Milton', 'smash', 'delete'));
-
- //inherit parent
- $this->assertFalse($this->Acl->check('Milton', 'smash', 'read'));
- $this->Acl->inherit('Milton', 'smash', 'read');
- $this->assertTrue($this->Acl->check('Milton', 'smash', 'read'));
- }
-
-/**
- * testDbGrant method
- *
- * @expectedException PHPUnit_Framework_Error_Warning
- * @return void
- */
- public function testGrant() {
- $this->assertFalse($this->Acl->check('Samir', 'tpsReports', 'create'));
- $this->Acl->allow('Samir', 'tpsReports', 'create');
- $this->assertTrue($this->Acl->check('Samir', 'tpsReports', 'create'));
-
- $this->assertFalse($this->Acl->check('Micheal', 'view', 'read'));
- $this->Acl->allow('Micheal', 'view', array('read', 'create', 'update'));
- $this->assertTrue($this->Acl->check('Micheal', 'view', 'read'));
- $this->assertTrue($this->Acl->check('Micheal', 'view', 'create'));
- $this->assertTrue($this->Acl->check('Micheal', 'view', 'update'));
- $this->assertFalse($this->Acl->check('Micheal', 'view', 'delete'));
-
- $this->assertFalse($this->Acl->allow('Peter', 'ROOT/tpsReports/DoesNotExist', 'create'));
- }
-
-/**
- * testDbRevoke method
- *
- * @expectedException PHPUnit_Framework_Error_Warning
- * @return void
- */
- public function testRevoke() {
- $this->assertTrue($this->Acl->check('Bobs', 'tpsReports', 'read'));
- $this->Acl->deny('Bobs', 'tpsReports', 'read');
- $this->assertFalse($this->Acl->check('Bobs', 'tpsReports', 'read'));
-
- $this->assertTrue($this->Acl->check('users', 'printers', 'read'));
- $this->Acl->deny('users', 'printers', 'read');
- $this->assertFalse($this->Acl->check('users', 'printers', 'read'));
- $this->assertFalse($this->Acl->check('Samir', 'printers', 'read'));
- $this->assertFalse($this->Acl->check('Peter', 'printers', 'read'));
-
- $this->Acl->deny('Bobs', 'ROOT/printers/DoesNotExist', 'create');
- }
-
-/**
- * debug function - to help editing/creating test cases for the ACL component
- *
- * To check the overal ACL status at any time call $this->__debug();
- * Generates a list of the current aro and aco structures and a grid dump of the permissions that are defined
- * Only designed to work with the db based ACL
- *
- * @param bool $treesToo
- * @return void
- */
- protected function __debug($printTreesToo = false) {
- $this->Acl->Aro->displayField = 'alias';
- $this->Acl->Aco->displayField = 'alias';
- $aros = $this->Acl->Aro->find('list', array('order' => 'lft'));
- $acos = $this->Acl->Aco->find('list', array('order' => 'lft'));
- $rights = array('*', 'create', 'read', 'update', 'delete');
- $permissions['Aros v Acos >'] = $acos;
- foreach ($aros as $aro) {
- $row = array();
- foreach ($acos as $aco) {
- $perms = '';
- foreach ($rights as $right) {
- if ($this->Acl->check($aro, $aco, $right)) {
- if ($right == '*') {
- $perms .= '****';
- break;
- }
- $perms .= $right[0];
- } elseif ($right != '*') {
- $perms .= ' ';
- }
- }
- $row[] = $perms;
- }
- $permissions[$aro] = $row;
- }
- foreach ($permissions as $key => $values) {
- array_unshift($values, $key);
- $values = array_map(array(&$this, '__pad'), $values);
- $permissions[$key] = implode (' ', $values);
- }
- $permisssions = array_map(array(&$this, '__pad'), $permissions);
- array_unshift($permissions, 'Current Permissions :');
- if ($printTreesToo) {
- debug(array('aros' => $this->Acl->Aro->generateTreeList(), 'acos' => $this->Acl->Aco->generateTreeList()));
- }
- debug(implode("\r\n", $permissions));
- }
-
-/**
- * pad function
- * Used by debug to format strings used in the data dump
- *
- * @param string $string
- * @param int $len
- * @return void
- */
- protected function __pad($string = '', $len = 14) {
- return str_pad($string, $len);
- }
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/Acl/IniAclTest.php b/lib/Cake/Test/Case/Controller/Component/Acl/IniAclTest.php
deleted file mode 100644
index de552b1f872..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/Acl/IniAclTest.php
+++ /dev/null
@@ -1,69 +0,0 @@
-config = $Ini->readConfigFile($iniFile);
-
- $this->assertFalse($Ini->check('admin', 'ads'));
- $this->assertTrue($Ini->check('admin', 'posts'));
-
- $this->assertTrue($Ini->check('jenny', 'posts'));
- $this->assertTrue($Ini->check('jenny', 'ads'));
-
- $this->assertTrue($Ini->check('paul', 'posts'));
- $this->assertFalse($Ini->check('paul', 'ads'));
-
- $this->assertFalse($Ini->check('nobody', 'comments'));
- }
-
-/**
- * check should accept a user array.
- *
- * @return void
- */
- public function testCheckArray() {
- $iniFile = CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS . 'acl.ini.php';
-
- $Ini = new IniAcl();
- $Ini->config = $Ini->readConfigFile($iniFile);
- $Ini->userPath = 'User.username';
-
- $user = array(
- 'User' => array('username' => 'admin')
- );
- $this->assertTrue($Ini->check($user, 'posts'));
- }
-}
-
diff --git a/lib/Cake/Test/Case/Controller/Component/Acl/PhpAclTest.php b/lib/Cake/Test/Case/Controller/Component/Acl/PhpAclTest.php
deleted file mode 100644
index 3cf18997206..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/Acl/PhpAclTest.php
+++ /dev/null
@@ -1,336 +0,0 @@
-PhpAcl = new PhpAcl();
- $this->Acl = new AclComponent($Collection, array(
- 'adapter' => array(
- 'config' => CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS . 'acl.php',
- ),
- ));
- }
-
- public function testRoleInheritance() {
- $roles = $this->Acl->Aro->roles('User/peter');
- $this->assertEquals(array('Role/accounting'), $roles[0]);
- $this->assertEquals(array('User/peter'), $roles[1]);
-
- $roles = $this->Acl->Aro->roles('hardy');
- $this->assertEquals(array('Role/database_manager', 'Role/data_acquirer'), $roles[0]);
- $this->assertEquals(array('Role/accounting', 'Role/data_analyst'), $roles[1]);
- $this->assertEquals(array('Role/accounting_manager', 'Role/reports'), $roles[2]);
- $this->assertEquals(array('User/hardy'), $roles[3]);
- }
-
- public function testAddRole() {
- $this->assertEquals(array(array(PhpAro::DEFAULT_ROLE)), $this->Acl->Aro->roles('foobar'));
- $this->Acl->Aro->addRole(array('User/foobar' => 'Role/accounting'));
- $this->assertEquals(array(array('Role/accounting'), array('User/foobar')), $this->Acl->Aro->roles('foobar'));
- }
-
- public function testAroResolve() {
- $map = $this->Acl->Aro->map;
- $this->Acl->Aro->map = array(
- 'User' => 'FooModel/nickname',
- 'Role' => 'FooModel/role',
- );
-
- $this->assertEquals('Role/default', $this->Acl->Aro->resolve('Foo.bar'));
- $this->assertEquals('User/hardy', $this->Acl->Aro->resolve('FooModel/hardy'));
- $this->assertEquals('User/hardy', $this->Acl->Aro->resolve('hardy'));
- $this->assertEquals('User/hardy', $this->Acl->Aro->resolve(array('FooModel' => array('nickname' => 'hardy'))));
- $this->assertEquals('Role/admin', $this->Acl->Aro->resolve(array('FooModel' => array('role' => 'admin'))));
- $this->assertEquals('Role/admin', $this->Acl->Aro->resolve('Role/admin'));
-
- $this->assertEquals('Role/admin', $this->Acl->Aro->resolve('admin'));
- $this->assertEquals('Role/admin', $this->Acl->Aro->resolve('FooModel/admin'));
- $this->assertEquals('Role/accounting', $this->Acl->Aro->resolve('accounting'));
-
- $this->assertEquals(PhpAro::DEFAULT_ROLE, $this->Acl->Aro->resolve('bla'));
- $this->assertEquals(PhpAro::DEFAULT_ROLE, $this->Acl->Aro->resolve(array('FooModel' => array('role' => 'hardy'))));
- }
-
-/**
- * test correct resolution of defined aliases
- */
- public function testAroAliases() {
- $this->Acl->Aro->map = array(
- 'User' => 'User/username',
- 'Role' => 'User/group_id',
- );
-
- $this->Acl->Aro->aliases = array(
- 'Role/1' => 'Role/admin',
- 'Role/24' => 'Role/accounting',
- );
-
- $user = array(
- 'User' => array(
- 'username' => 'unknown_user',
- 'group_id' => '1',
- ),
- );
- // group/1
- $this->assertEquals('Role/admin', $this->Acl->Aro->resolve($user));
- // group/24
- $this->assertEquals('Role/accounting', $this->Acl->Aro->resolve('Role/24'));
- $this->assertEquals('Role/accounting', $this->Acl->Aro->resolve('24'));
-
- // check department
- $user = array(
- 'User' => array(
- 'username' => 'foo',
- 'group_id' => '25',
- ),
- );
-
- $this->Acl->Aro->addRole(array('Role/IT' => null));
- $this->Acl->Aro->addAlias(array('Role/25' => 'Role/IT'));
- $this->Acl->allow('Role/IT', '/rules/debugging/*');
-
- $this->assertEquals(array(array('Role/IT', )), $this->Acl->Aro->roles($user));
- $this->assertTrue($this->Acl->check($user, '/rules/debugging/stats/pageload'));
- $this->assertTrue($this->Acl->check($user, '/rules/debugging/sql/queries'));
- // Role/default is allowed users dashboard, but not Role/IT
- $this->assertFalse($this->Acl->check($user, '/controllers/users/dashboard'));
-
- $this->assertFalse($this->Acl->check($user, '/controllers/invoices/send'));
- // wee add an more specific entry for user foo to also inherit from Role/accounting
- $this->Acl->Aro->addRole(array('User/foo' => 'Role/IT, Role/accounting'));
- $this->assertTrue($this->Acl->check($user, '/controllers/invoices/send'));
- }
-
-/**
- * test check method
- *
- * @return void
- */
- public function testCheck() {
- $this->assertTrue($this->Acl->check('jan', '/controllers/users/Dashboard'));
- $this->assertTrue($this->Acl->check('some_unknown_role', '/controllers/users/Dashboard'));
- $this->assertTrue($this->Acl->check('Role/admin', 'foo/bar'));
- $this->assertTrue($this->Acl->check('role/admin', '/foo/bar'));
- $this->assertTrue($this->Acl->check('jan', 'foo/bar'));
- $this->assertTrue($this->Acl->check('user/jan', 'foo/bar'));
- $this->assertTrue($this->Acl->check('Role/admin', 'controllers/bar'));
- $this->assertTrue($this->Acl->check(array('User' => array('username' => 'jan')), '/controllers/bar/bll'));
- $this->assertTrue($this->Acl->check('Role/database_manager', 'controllers/db/create'));
- $this->assertTrue($this->Acl->check('User/db_manager_2', 'controllers/db/create'));
- $this->assertFalse($this->Acl->check('db_manager_2', '/controllers/users/Dashboard'));
-
- // inheritance: hardy -> reports -> data_analyst -> database_manager
- $this->assertTrue($this->Acl->check('User/hardy', 'controllers/db/create'));
- $this->assertFalse($this->Acl->check('User/jeff', 'controllers/db/create'));
-
- $this->assertTrue($this->Acl->check('Role/database_manager', 'controllers/db/select'));
- $this->assertTrue($this->Acl->check('User/db_manager_2', 'controllers/db/select'));
- $this->assertFalse($this->Acl->check('User/jeff', 'controllers/db/select'));
-
- $this->assertTrue($this->Acl->check('Role/database_manager', 'controllers/db/drop'));
- $this->assertTrue($this->Acl->check('User/db_manager_1', 'controllers/db/drop'));
- $this->assertFalse($this->Acl->check('db_manager_2', 'controllers/db/drop'));
-
- $this->assertTrue($this->Acl->check('db_manager_2', 'controllers/invoices/edit'));
- $this->assertFalse($this->Acl->check('database_manager', 'controllers/invoices/edit'));
- $this->assertFalse($this->Acl->check('db_manager_1', 'controllers/invoices/edit'));
-
- // Role/manager is allowed /controllers/*/*_manager
- $this->assertTrue($this->Acl->check('stan', 'controllers/invoices/manager_edit'));
- $this->assertTrue($this->Acl->check('Role/manager', 'controllers/baz/manager_foo'));
- $this->assertFalse($this->Acl->check('User/stan', 'custom/foo/manager_edit'));
- $this->assertFalse($this->Acl->check('stan', 'bar/baz/manager_foo'));
- $this->assertFalse($this->Acl->check('Role/accounting', 'bar/baz/manager_foo'));
- $this->assertFalse($this->Acl->check('accounting', 'controllers/baz/manager_foo'));
-
- $this->assertTrue($this->Acl->check('User/stan', 'controllers/articles/edit'));
- $this->assertTrue($this->Acl->check('stan', 'controllers/articles/add'));
- $this->assertTrue($this->Acl->check('stan', 'controllers/articles/publish'));
- $this->assertFalse($this->Acl->check('User/stan', 'controllers/articles/delete'));
- $this->assertFalse($this->Acl->check('accounting', 'controllers/articles/edit'));
- $this->assertFalse($this->Acl->check('accounting', 'controllers/articles/add'));
- $this->assertFalse($this->Acl->check('role/accounting', 'controllers/articles/publish'));
- }
-
-/**
- * lhs of defined rules are case insensitive
- */
- public function testCheckIsCaseInsensitive() {
- $this->assertTrue($this->Acl->check('hardy', 'controllers/forms/new'));
- $this->assertTrue($this->Acl->check('Role/data_acquirer', 'controllers/forms/new'));
- $this->assertTrue($this->Acl->check('hardy', 'controllers/FORMS/NEW'));
- $this->assertTrue($this->Acl->check('Role/data_acquirer', 'controllers/FORMS/NEW'));
- }
-
-/**
- * allow should work in-memory
- */
- public function testAllow() {
- $this->assertFalse($this->Acl->check('jeff', 'foo/bar'));
-
- $this->Acl->allow('jeff', 'foo/bar');
-
- $this->assertTrue($this->Acl->check('jeff', 'foo/bar'));
- $this->assertFalse($this->Acl->check('peter', 'foo/bar'));
- $this->assertFalse($this->Acl->check('hardy', 'foo/bar'));
-
- $this->Acl->allow('Role/accounting', 'foo/bar');
-
- $this->assertTrue($this->Acl->check('peter', 'foo/bar'));
- $this->assertTrue($this->Acl->check('hardy', 'foo/bar'));
-
- $this->assertFalse($this->Acl->check('Role/reports', 'foo/bar'));
- }
-
-/**
- * deny should work in-memory
- */
- public function testDeny() {
- $this->assertTrue($this->Acl->check('stan', 'controllers/baz/manager_foo'));
-
- $this->Acl->deny('stan', 'controllers/baz/manager_foo');
-
- $this->assertFalse($this->Acl->check('stan', 'controllers/baz/manager_foo'));
- $this->assertTrue($this->Acl->check('Role/manager', 'controllers/baz/manager_foo'));
- $this->assertTrue($this->Acl->check('stan', 'controllers/baz/manager_bar'));
- $this->assertTrue($this->Acl->check('stan', 'controllers/baz/manager_foooooo'));
- }
-
-/**
- * test that a deny rule wins over an equally specific allow rule
- */
- public function testDenyRuleIsStrongerThanAllowRule() {
- $this->assertFalse($this->Acl->check('peter', 'baz/bam'));
- $this->Acl->allow('peter', 'baz/bam');
- $this->assertTrue($this->Acl->check('peter', 'baz/bam'));
- $this->Acl->deny('peter', 'baz/bam');
- $this->assertFalse($this->Acl->check('peter', 'baz/bam'));
-
- $this->assertTrue($this->Acl->check('stan', 'controllers/reports/foo'));
- // stan is denied as he's sales and sales is denied /controllers/*/delete
- $this->assertFalse($this->Acl->check('stan', 'controllers/reports/delete'));
- $this->Acl->allow('stan', 'controllers/reports/delete');
- $this->assertFalse($this->Acl->check('Role/sales', 'controllers/reports/delete'));
- $this->assertTrue($this->Acl->check('stan', 'controllers/reports/delete'));
- $this->Acl->deny('stan', 'controllers/reports/delete');
- $this->assertFalse($this->Acl->check('stan', 'controllers/reports/delete'));
-
- // there is already an equally specific deny rule that will win
- $this->Acl->allow('stan', 'controllers/reports/delete');
- $this->assertFalse($this->Acl->check('stan', 'controllers/reports/delete'));
- }
-
-/**
- * test that an invalid configuration throws exception
- */
- public function testInvalidConfigWithAroMissing() {
- $this->setExpectedException(
- 'AclException',
- '"roles" section not found in configuration'
- );
- $config = array('aco' => array('allow' => array('foo' => '')));
- $this->PhpAcl->build($config);
- }
-
- public function testInvalidConfigWithAcosMissing() {
- $this->setExpectedException(
- 'AclException',
- 'Neither "allow" nor "deny" rules were provided in configuration.'
- );
-
- $config = array(
- 'roles' => array('Role/foo' => null),
- );
-
- $this->PhpAcl->build($config);
- }
-
-/**
- * test resolving of ACOs
- */
- public function testAcoResolve() {
- $this->assertEquals(array('foo', 'bar'), $this->Acl->Aco->resolve('foo/bar'));
- $this->assertEquals(array('foo', 'bar'), $this->Acl->Aco->resolve('foo/bar'));
- $this->assertEquals(array('foo', 'bar', 'baz'), $this->Acl->Aco->resolve('foo/bar/baz'));
- $this->assertEquals(array('foo', '*-bar', '?-baz'), $this->Acl->Aco->resolve('foo/*-bar/?-baz'));
-
- $this->assertEquals(array('foo', 'bar', '[a-f0-9]{24}', '*_bla', 'bla'), $this->Acl->Aco->resolve('foo/bar/[a-f0-9]{24}/*_bla/bla'));
-
- // multiple slashes will be squashed to a single, trimmed and then exploded
- $this->assertEquals(array('foo', 'bar'), $this->Acl->Aco->resolve('foo//bar'));
- $this->assertEquals(array('foo', 'bar'), $this->Acl->Aco->resolve('//foo///bar/'));
- $this->assertEquals(array('foo', 'bar'), $this->Acl->Aco->resolve('/foo//bar//'));
- $this->assertEquals(array('foo', 'bar'), $this->Acl->Aco->resolve('/foo // bar'));
- $this->assertEquals(array(), $this->Acl->Aco->resolve('/////'));
- }
-
-/**
- * test that declaring cyclic dependencies should give an error when building the tree
- */
- public function testAroDeclarationContainsCycles() {
- $config = array(
- 'roles' => array(
- 'Role/a' => null,
- 'Role/b' => 'User/b',
- 'User/a' => 'Role/a, Role/b',
- 'User/b' => 'User/a',
-
- ),
- 'rules' => array(
- 'allow' => array(
- '*' => 'Role/a',
- ),
- ),
- );
-
- $this->expectError('PHPUnit_Framework_Error', 'cycle detected' /* ... */);
- $this->PhpAcl->build($config);
- }
-
-/**
- * test that with policy allow, only denies count
- */
- public function testPolicy() {
- // allow by default
- $this->Acl->settings['adapter']['policy'] = PhpAcl::ALLOW;
- $this->Acl->adapter($this->PhpAcl);
-
- $this->assertTrue($this->Acl->check('Role/sales', 'foo'));
- $this->assertTrue($this->Acl->check('Role/sales', 'controllers/bla/create'));
- $this->assertTrue($this->Acl->check('Role/default', 'foo'));
- // undefined user, undefined aco
- $this->assertTrue($this->Acl->check('foobar', 'foo/bar'));
-
- // deny rule: Role.sales -> controllers.*.delete
- $this->assertFalse($this->Acl->check('Role/sales', 'controllers/bar/delete'));
- $this->assertFalse($this->Acl->check('Role/sales', 'controllers/bar', 'delete'));
- }
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/AclComponentTest.php b/lib/Cake/Test/Case/Controller/Component/AclComponentTest.php
deleted file mode 100644
index 7261a8222de..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/AclComponentTest.php
+++ /dev/null
@@ -1,91 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Controller.Component
- * @since CakePHP(tm) v 1.2.0.5435
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-App::uses('AclComponent', 'Controller/Component');
-class_exists('AclComponent');
-
-/**
- * Test Case for AclComponent
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class AclComponentTest extends CakeTestCase {
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- if (!class_exists('MockAclImplementation', false)) {
- $this->getMock('AclInterface', array(), array(), 'MockAclImplementation');
- }
- Configure::write('Acl.classname', 'MockAclImplementation');
- $Collection = new ComponentCollection();
- $this->Acl = new AclComponent($Collection);
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- unset($this->Acl);
- }
-
-/**
- * test that constructor throws an exception when Acl.classname is a
- * non-existent class
- *
- * @expectedException CakeException
- * @return void
- */
- public function testConstrutorException() {
- Configure::write('Acl.classname', 'AclClassNameThatDoesNotExist');
- $Collection = new ComponentCollection();
- $acl = new AclComponent($Collection);
- }
-
-/**
- * test that adapter() allows control of the internal implementation AclComponent uses.
- *
- * @return void
- */
- public function testAdapter() {
- $implementation = new MockAclImplementation();
- $implementation->expects($this->once())->method('initialize')->with($this->Acl);
- $this->assertNull($this->Acl->adapter($implementation));
-
- $this->assertEquals($this->Acl->adapter(), $implementation, 'Returned object is different %s');
- }
-
-/**
- * test that adapter() whines when the class is not an AclBase
- *
- * @expectedException CakeException
- * @return void
- */
- public function testAdapterException() {
- $thing = new StdClass();
- $this->Acl->adapter($thing);
- }
-
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/ActionsAuthorizeTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/ActionsAuthorizeTest.php
deleted file mode 100644
index 6b06b37b006..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/Auth/ActionsAuthorizeTest.php
+++ /dev/null
@@ -1,192 +0,0 @@
-controller = $this->getMock('Controller', array(), array(), '', false);
- $this->Acl = $this->getMock('AclComponent', array(), array(), '', false);
- $this->Collection = $this->getMock('ComponentCollection');
-
- $this->auth = new ActionsAuthorize($this->Collection);
- $this->auth->settings['actionPath'] = '/controllers';
- }
-
-/**
- * setup the mock acl.
- *
- * @return void
- */
- protected function _mockAcl() {
- $this->Collection->expects($this->any())
- ->method('load')
- ->with('Acl')
- ->will($this->returnValue($this->Acl));
- }
-
-/**
- * test failure
- *
- * @return void
- */
- public function testAuthorizeFailure() {
- $user = array(
- 'User' => array(
- 'id' => 1,
- 'user' => 'mariano'
- )
- );
- $request = new CakeRequest('/posts/index', false);
- $request->addParams(array(
- 'plugin' => null,
- 'controller' => 'posts',
- 'action' => 'index'
- ));
-
- $this->_mockAcl();
-
- $this->Acl->expects($this->once())
- ->method('check')
- ->with($user, 'controllers/Posts/index')
- ->will($this->returnValue(false));
-
- $this->assertFalse($this->auth->authorize($user['User'], $request));
- }
-
-/**
- * test isAuthorized working.
- *
- * @return void
- */
- public function testAuthorizeSuccess() {
- $user = array(
- 'User' => array(
- 'id' => 1,
- 'user' => 'mariano'
- )
- );
- $request = new CakeRequest('/posts/index', false);
- $request->addParams(array(
- 'plugin' => null,
- 'controller' => 'posts',
- 'action' => 'index'
- ));
-
- $this->_mockAcl();
-
- $this->Acl->expects($this->once())
- ->method('check')
- ->with($user, 'controllers/Posts/index')
- ->will($this->returnValue(true));
-
- $this->assertTrue($this->auth->authorize($user['User'], $request));
- }
-
-/**
- * testAuthorizeSettings
- *
- * @return void
- */
- public function testAuthorizeSettings() {
- $request = new CakeRequest('/posts/index', false);
- $request->addParams(array(
- 'plugin' => null,
- 'controller' => 'posts',
- 'action' => 'index'
- ));
-
- $this->_mockAcl();
-
- $this->auth->settings['userModel'] = 'TestPlugin.TestPluginAuthUser';
- $user = array(
- 'id' => 1,
- 'user' => 'mariano'
- );
-
- $expected = array('TestPlugin.TestPluginAuthUser' => array('id' => 1, 'user' => 'mariano'));
- $this->Acl->expects($this->once())
- ->method('check')
- ->with($expected, 'controllers/Posts/index')
- ->will($this->returnValue(true));
-
- $this->assertTrue($this->auth->authorize($user, $request));
- }
-
-/**
- * test action()
- *
- * @return void
- */
- public function testActionMethod() {
- $request = new CakeRequest('/posts/index', false);
- $request->addParams(array(
- 'plugin' => null,
- 'controller' => 'posts',
- 'action' => 'index'
- ));
-
- $result = $this->auth->action($request);
- $this->assertEquals('controllers/Posts/index', $result);
- }
-
-/**
- * Make sure that action() doesn't create double slashes anywhere.
- *
- * @return void
- */
- public function testActionNoDoubleSlash() {
- $this->auth->settings['actionPath'] = '/controllers/';
- $request = array(
- 'plugin' => null,
- 'controller' => 'posts',
- 'action' => 'index'
- );
- $result = $this->auth->action($request);
- $this->assertEquals('controllers/Posts/index', $result);
- }
-
-/**
- * test action() and plugins
- *
- * @return void
- */
- public function testActionWithPlugin() {
- $request = new CakeRequest('/debug_kit/posts/index', false);
- $request->addParams(array(
- 'plugin' => 'debug_kit',
- 'controller' => 'posts',
- 'action' => 'index'
- ));
-
- $result = $this->auth->action($request);
- $this->assertEquals('controllers/DebugKit/Posts/index', $result);
- }
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/BasicAuthenticateTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/BasicAuthenticateTest.php
deleted file mode 100644
index 44bf9ba6cb5..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/Auth/BasicAuthenticateTest.php
+++ /dev/null
@@ -1,217 +0,0 @@
-Collection = $this->getMock('ComponentCollection');
- $this->auth = new BasicAuthenticate($this->Collection, array(
- 'fields' => array('username' => 'user', 'password' => 'password'),
- 'userModel' => 'User',
- 'realm' => 'localhost',
- 'recursive' => 0
- ));
-
- $password = Security::hash('password', null, true);
- $User = ClassRegistry::init('User');
- $User->updateAll(array('password' => $User->getDataSource()->value($password)));
- $this->server = $_SERVER;
- $this->response = $this->getMock('CakeResponse');
- }
-
-/**
- * tearDown
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- $_SERVER = $this->server;
- }
-
-/**
- * test applying settings in the constructor
- *
- * @return void
- */
- public function testConstructor() {
- $object = new BasicAuthenticate($this->Collection, array(
- 'userModel' => 'AuthUser',
- 'fields' => array('username' => 'user', 'password' => 'password')
- ));
- $this->assertEquals('AuthUser', $object->settings['userModel']);
- $this->assertEquals(array('username' => 'user', 'password' => 'password'), $object->settings['fields']);
- $this->assertEquals(env('SERVER_NAME'), $object->settings['realm']);
- }
-
-/**
- * test the authenticate method
- *
- * @return void
- */
- public function testAuthenticateNoData() {
- $request = new CakeRequest('posts/index', false);
-
- $this->response->expects($this->once())
- ->method('header')
- ->with('WWW-Authenticate: Basic realm="localhost"');
-
- $this->assertFalse($this->auth->authenticate($request, $this->response));
- }
-
-/**
- * test the authenticate method
- *
- * @return void
- */
- public function testAuthenticateNoUsername() {
- $request = new CakeRequest('posts/index', false);
- $_SERVER['PHP_AUTH_PW'] = 'foobar';
-
- $this->response->expects($this->once())
- ->method('header')
- ->with('WWW-Authenticate: Basic realm="localhost"');
-
- $this->assertFalse($this->auth->authenticate($request, $this->response));
- }
-
-/**
- * test the authenticate method
- *
- * @return void
- */
- public function testAuthenticateNoPassword() {
- $request = new CakeRequest('posts/index', false);
- $_SERVER['PHP_AUTH_USER'] = 'mariano';
- $_SERVER['PHP_AUTH_PW'] = null;
-
- $this->response->expects($this->once())
- ->method('header')
- ->with('WWW-Authenticate: Basic realm="localhost"');
-
- $this->assertFalse($this->auth->authenticate($request, $this->response));
- }
-
-/**
- * test the authenticate method
- *
- * @return void
- */
- public function testAuthenticateInjection() {
- $request = new CakeRequest('posts/index', false);
- $request->addParams(array('pass' => array(), 'named' => array()));
-
- $_SERVER['PHP_AUTH_USER'] = '> 1';
- $_SERVER['PHP_AUTH_PW'] = "' OR 1 = 1";
-
- $this->assertFalse($this->auth->authenticate($request, $this->response));
- }
-
-/**
- * test that challenge headers are sent when no credentials are found.
- *
- * @return void
- */
- public function testAuthenticateChallenge() {
- $request = new CakeRequest('posts/index', false);
- $request->addParams(array('pass' => array(), 'named' => array()));
-
- $this->response->expects($this->at(0))
- ->method('header')
- ->with('WWW-Authenticate: Basic realm="localhost"');
-
- $this->response->expects($this->at(1))
- ->method('send');
-
- $result = $this->auth->authenticate($request, $this->response);
- $this->assertFalse($result);
- }
-
-/**
- * test authenticate sucesss
- *
- * @return void
- */
- public function testAuthenticateSuccess() {
- $request = new CakeRequest('posts/index', false);
- $request->addParams(array('pass' => array(), 'named' => array()));
-
- $_SERVER['PHP_AUTH_USER'] = 'mariano';
- $_SERVER['PHP_AUTH_PW'] = 'password';
-
- $result = $this->auth->authenticate($request, $this->response);
- $expected = array(
- 'id' => 1,
- 'user' => 'mariano',
- 'created' => '2007-03-17 01:16:23',
- 'updated' => '2007-03-17 01:18:31'
- );
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test scope failure.
- *
- * @return void
- */
- public function testAuthenticateFailReChallenge() {
- $this->auth->settings['scope'] = array('user' => 'nate');
- $request = new CakeRequest('posts/index', false);
- $request->addParams(array('pass' => array(), 'named' => array()));
-
- $_SERVER['PHP_AUTH_USER'] = 'mariano';
- $_SERVER['PHP_AUTH_PW'] = 'password';
-
- $this->response->expects($this->at(0))
- ->method('header')
- ->with('WWW-Authenticate: Basic realm="localhost"');
-
- $this->response->expects($this->at(1))
- ->method('statusCode')
- ->with(401);
-
- $this->response->expects($this->at(2))
- ->method('send');
-
- $this->assertFalse($this->auth->authenticate($request, $this->response));
- }
-
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php
deleted file mode 100644
index a1dae910854..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/Auth/ControllerAuthorizeTest.php
+++ /dev/null
@@ -1,84 +0,0 @@
-controller = $this->getMock('Controller', array('isAuthorized'), array(), '', false);
- $this->components = $this->getMock('ComponentCollection');
- $this->components->expects($this->any())
- ->method('getController')
- ->will($this->returnValue($this->controller));
-
- $this->auth = new ControllerAuthorize($this->components);
- }
-
-/**
- * @expectedException PHPUnit_Framework_Error
- */
- public function testControllerTypeError() {
- $this->auth->controller(new StdClass());
- }
-
-/**
- * @expectedException CakeException
- */
- public function testControllerErrorOnMissingMethod() {
- $this->auth->controller(new Controller());
- }
-
-/**
- * test failure
- *
- * @return void
- */
- public function testAuthorizeFailure() {
- $user = array();
- $request = new CakeRequest('/posts/index', false);
- $this->assertFalse($this->auth->authorize($user, $request));
- }
-
-/**
- * test isAuthorized working.
- *
- * @return void
- */
- public function testAuthorizeSuccess() {
- $user = array('User' => array('username' => 'mark'));
- $request = new CakeRequest('/posts/index', false);
-
- $this->controller->expects($this->once())
- ->method('isAuthorized')
- ->with($user)
- ->will($this->returnValue(true));
-
- $this->assertTrue($this->auth->authorize($user, $request));
- }
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/CrudAuthorizeTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/CrudAuthorizeTest.php
deleted file mode 100644
index 1f4464571a7..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/Auth/CrudAuthorizeTest.php
+++ /dev/null
@@ -1,186 +0,0 @@
-Acl = $this->getMock('AclComponent', array(), array(), '', false);
- $this->Components = $this->getMock('ComponentCollection');
-
- $this->auth = new CrudAuthorize($this->Components);
- }
-
-/**
- * setup the mock acl.
- *
- * @return void
- */
- protected function _mockAcl() {
- $this->Components->expects($this->any())
- ->method('load')
- ->with('Acl')
- ->will($this->returnValue($this->Acl));
- }
-
-/**
- * test authorize() without a mapped action, ensure an error is generated.
- *
- * @expectedException PHPUnit_Framework_Error_Warning
- * @return void
- */
- public function testAuthorizeNoMappedAction() {
- $request = new CakeRequest('/posts/foobar', false);
- $request->addParams(array(
- 'controller' => 'posts',
- 'action' => 'foobar'
- ));
- $user = array('User' => array('user' => 'mark'));
-
- $this->auth->authorize($user, $request);
- }
-
-/**
- * test check() passing
- *
- * @return void
- */
- public function testAuthorizeCheckSuccess() {
- $request = new CakeRequest('posts/index', false);
- $request->addParams(array(
- 'controller' => 'posts',
- 'action' => 'index'
- ));
- $user = array('User' => array('user' => 'mark'));
-
- $this->_mockAcl();
- $this->Acl->expects($this->once())
- ->method('check')
- ->with($user, 'Posts', 'read')
- ->will($this->returnValue(true));
-
- $this->assertTrue($this->auth->authorize($user['User'], $request));
- }
-
-/**
- * test check() failing
- *
- * @return void
- */
- public function testAuthorizeCheckFailure() {
- $request = new CakeRequest('posts/index', false);
- $request->addParams(array(
- 'controller' => 'posts',
- 'action' => 'index'
- ));
- $user = array('User' => array('user' => 'mark'));
-
- $this->_mockAcl();
- $this->Acl->expects($this->once())
- ->method('check')
- ->with($user, 'Posts', 'read')
- ->will($this->returnValue(false));
-
- $this->assertFalse($this->auth->authorize($user['User'], $request));
- }
-
-/**
- * test getting actionMap
- *
- * @return void
- */
- public function testMapActionsGet() {
- $result = $this->auth->mapActions();
- $expected = array(
- 'create' => 'create',
- 'read' => 'read',
- 'update' => 'update',
- 'delete' => 'delete',
- 'index' => 'read',
- 'add' => 'create',
- 'edit' => 'update',
- 'view' => 'read',
- 'remove' => 'delete'
- );
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test adding into mapActions
- *
- * @return void
- */
- public function testMapActionsSet() {
- $map = array(
- 'create' => array('generate'),
- 'read' => array('listing', 'show'),
- 'update' => array('update'),
- 'random' => 'custom'
- );
- $result = $this->auth->mapActions($map);
- $this->assertNull($result);
-
- $result = $this->auth->mapActions();
- $expected = array(
- 'add' => 'create',
- 'create' => 'create',
- 'read' => 'read',
- 'index' => 'read',
- 'add' => 'create',
- 'edit' => 'update',
- 'view' => 'read',
- 'delete' => 'delete',
- 'remove' => 'delete',
- 'generate' => 'create',
- 'listing' => 'read',
- 'show' => 'read',
- 'update' => 'update',
- 'random' => 'custom',
- );
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test prefix routes getting auto mapped.
- *
- * @return void
- */
- public function testAutoPrefixMapActions() {
- Configure::write('Routing.prefixes', array('admin', 'manager'));
- Router::reload();
-
- $auth = new CrudAuthorize($this->Components);
- $this->assertTrue(isset($auth->settings['actionMap']['admin_index']));
- }
-
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/DigestAuthenticateTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/DigestAuthenticateTest.php
deleted file mode 100644
index f9ca8316b2c..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/Auth/DigestAuthenticateTest.php
+++ /dev/null
@@ -1,306 +0,0 @@
-Collection = $this->getMock('ComponentCollection');
- $this->server = $_SERVER;
- $this->auth = new DigestAuthenticate($this->Collection, array(
- 'fields' => array('username' => 'user', 'password' => 'password'),
- 'userModel' => 'User',
- 'realm' => 'localhost',
- 'nonce' => 123,
- 'opaque' => '123abc'
- ));
-
- $password = DigestAuthenticate::password('mariano', 'cake', 'localhost');
- $User = ClassRegistry::init('User');
- $User->updateAll(array('password' => $User->getDataSource()->value($password)));
-
- $_SERVER['REQUEST_METHOD'] = 'GET';
- $this->response = $this->getMock('CakeResponse');
- }
-
-/**
- * tearDown
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- $_SERVER = $this->server;
- }
-
-/**
- * test applying settings in the constructor
- *
- * @return void
- */
- public function testConstructor() {
- $object = new DigestAuthenticate($this->Collection, array(
- 'userModel' => 'AuthUser',
- 'fields' => array('username' => 'user', 'password' => 'password'),
- 'nonce' => 123456
- ));
- $this->assertEquals('AuthUser', $object->settings['userModel']);
- $this->assertEquals(array('username' => 'user', 'password' => 'password'), $object->settings['fields']);
- $this->assertEquals(123456, $object->settings['nonce']);
- $this->assertEquals(env('SERVER_NAME'), $object->settings['realm']);
- }
-
-/**
- * test the authenticate method
- *
- * @return void
- */
- public function testAuthenticateNoData() {
- $request = new CakeRequest('posts/index', false);
-
- $this->response->expects($this->once())
- ->method('header')
- ->with('WWW-Authenticate: Digest realm="localhost",qop="auth",nonce="123",opaque="123abc"');
-
- $this->assertFalse($this->auth->authenticate($request, $this->response));
- }
-
-/**
- * test the authenticate method
- *
- * @return void
- */
- public function testAuthenticateWrongUsername() {
- $request = new CakeRequest('posts/index', false);
- $request->addParams(array('pass' => array(), 'named' => array()));
-
- $_SERVER['PHP_AUTH_DIGEST'] = <<response->expects($this->at(0))
- ->method('header')
- ->with('WWW-Authenticate: Digest realm="localhost",qop="auth",nonce="123",opaque="123abc"');
-
- $this->response->expects($this->at(1))
- ->method('statusCode')
- ->with(401);
-
- $this->response->expects($this->at(2))
- ->method('send');
-
- $this->assertFalse($this->auth->authenticate($request, $this->response));
- }
-
-/**
- * test that challenge headers are sent when no credentials are found.
- *
- * @return void
- */
- public function testAuthenticateChallenge() {
- $request = new CakeRequest('posts/index', false);
- $request->addParams(array('pass' => array(), 'named' => array()));
-
- $this->response->expects($this->at(0))
- ->method('header')
- ->with('WWW-Authenticate: Digest realm="localhost",qop="auth",nonce="123",opaque="123abc"');
-
- $this->response->expects($this->at(1))
- ->method('statusCode')
- ->with(401);
-
- $this->response->expects($this->at(2))
- ->method('send');
-
- $result = $this->auth->authenticate($request, $this->response);
- $this->assertFalse($result);
- }
-
-/**
- * test authenticate success
- *
- * @return void
- */
- public function testAuthenticateSuccess() {
- $request = new CakeRequest('posts/index', false);
- $request->addParams(array('pass' => array(), 'named' => array()));
-
- $_SERVER['PHP_AUTH_DIGEST'] = <<auth->authenticate($request, $this->response);
- $expected = array(
- 'id' => 1,
- 'user' => 'mariano',
- 'created' => '2007-03-17 01:16:23',
- 'updated' => '2007-03-17 01:18:31'
- );
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test scope failure.
- *
- * @return void
- */
- public function testAuthenticateFailReChallenge() {
- $this->auth->settings['scope'] = array('user' => 'nate');
- $request = new CakeRequest('posts/index', false);
- $request->addParams(array('pass' => array(), 'named' => array()));
-
- $_SERVER['PHP_AUTH_DIGEST'] = <<response->expects($this->at(0))
- ->method('header')
- ->with('WWW-Authenticate: Digest realm="localhost",qop="auth",nonce="123",opaque="123abc"');
-
- $this->response->expects($this->at(1))
- ->method('statusCode')
- ->with(401);
-
- $this->response->expects($this->at(2))
- ->method('send');
-
- $this->assertFalse($this->auth->authenticate($request, $this->response));
- }
-
-/**
- * testParseDigestAuthData method
- *
- * @return void
- */
- public function testParseAuthData() {
- $digest = << 'Mufasa',
- 'realm' => 'testrealm@host.com',
- 'nonce' => 'dcd98b7102dd2f0e8b11d0f600bfb0c093',
- 'uri' => '/dir/index.html',
- 'qop' => 'auth',
- 'nc' => '00000001',
- 'cnonce' => '0a4f113b',
- 'response' => '6629fae49393a05397450978507c4ef1',
- 'opaque' => '5ccc069c403ebaf9f0171e9517f40e41'
- );
- $result = $this->auth->parseAuthData($digest);
- $this->assertSame($expected, $result);
-
- $result = $this->auth->parseAuthData('');
- $this->assertNull($result);
- }
-
-/**
- * test parsing digest information with email addresses
- *
- * @return void
- */
- public function testParseAuthEmailAddress() {
- $digest = << 'mark@example.com',
- 'realm' => 'testrealm@host.com',
- 'nonce' => 'dcd98b7102dd2f0e8b11d0f600bfb0c093',
- 'uri' => '/dir/index.html',
- 'qop' => 'auth',
- 'nc' => '00000001',
- 'cnonce' => '0a4f113b',
- 'response' => '6629fae49393a05397450978507c4ef1',
- 'opaque' => '5ccc069c403ebaf9f0171e9517f40e41'
- );
- $result = $this->auth->parseAuthData($digest);
- $this->assertSame($expected, $result);
- }
-
-/**
- * test password hashing
- *
- * @return void
- */
- public function testPassword() {
- $result = DigestAuthenticate::password('mark', 'password', 'localhost');
- $expected = md5('mark:localhost:password');
- $this->assertEquals($expected, $result);
- }
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php
deleted file mode 100644
index 09097d4b7de..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php
+++ /dev/null
@@ -1,194 +0,0 @@
-Collection = $this->getMock('ComponentCollection');
- $this->auth = new FormAuthenticate($this->Collection, array(
- 'fields' => array('username' => 'user', 'password' => 'password'),
- 'userModel' => 'User'
- ));
- $password = Security::hash('password', null, true);
- $User = ClassRegistry::init('User');
- $User->updateAll(array('password' => $User->getDataSource()->value($password)));
- $this->response = $this->getMock('CakeResponse');
- }
-
-/**
- * test applying settings in the constructor
- *
- * @return void
- */
- public function testConstructor() {
- $object = new FormAuthenticate($this->Collection, array(
- 'userModel' => 'AuthUser',
- 'fields' => array('username' => 'user', 'password' => 'password')
- ));
- $this->assertEquals('AuthUser', $object->settings['userModel']);
- $this->assertEquals(array('username' => 'user', 'password' => 'password'), $object->settings['fields']);
- }
-
-/**
- * test the authenticate method
- *
- * @return void
- */
- public function testAuthenticateNoData() {
- $request = new CakeRequest('posts/index', false);
- $request->data = array();
- $this->assertFalse($this->auth->authenticate($request, $this->response));
- }
-
-/**
- * test the authenticate method
- *
- * @return void
- */
- public function testAuthenticateNoUsername() {
- $request = new CakeRequest('posts/index', false);
- $request->data = array('User' => array('password' => 'foobar'));
- $this->assertFalse($this->auth->authenticate($request, $this->response));
- }
-
-/**
- * test the authenticate method
- *
- * @return void
- */
- public function testAuthenticateNoPassword() {
- $request = new CakeRequest('posts/index', false);
- $request->data = array('User' => array('user' => 'mariano'));
- $this->assertFalse($this->auth->authenticate($request, $this->response));
- }
-
-/**
- * test the authenticate method
- *
- * @return void
- */
- public function testAuthenticateInjection() {
- $request = new CakeRequest('posts/index', false);
- $request->data = array(
- 'User' => array(
- 'user' => '> 1',
- 'password' => "' OR 1 = 1"
- ));
- $this->assertFalse($this->auth->authenticate($request, $this->response));
- }
-
-/**
- * test authenticate success
- *
- * @return void
- */
- public function testAuthenticateSuccess() {
- $request = new CakeRequest('posts/index', false);
- $request->data = array('User' => array(
- 'user' => 'mariano',
- 'password' => 'password'
- ));
- $result = $this->auth->authenticate($request, $this->response);
- $expected = array(
- 'id' => 1,
- 'user' => 'mariano',
- 'created' => '2007-03-17 01:16:23',
- 'updated' => '2007-03-17 01:18:31'
- );
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test scope failure.
- *
- * @return void
- */
- public function testAuthenticateScopeFail() {
- $this->auth->settings['scope'] = array('user' => 'nate');
- $request = new CakeRequest('posts/index', false);
- $request->data = array('User' => array(
- 'user' => 'mariano',
- 'password' => 'password'
- ));
-
- $this->assertFalse($this->auth->authenticate($request, $this->response));
- }
-
-/**
- * test a model in a plugin.
- *
- * @return void
- */
- public function testPluginModel() {
- Cache::delete('object_map', '_cake_core_');
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS),
- ), App::RESET);
- CakePlugin::load('TestPlugin');
-
- $ts = date('Y-m-d H:i:s');
- $PluginModel = ClassRegistry::init('TestPlugin.TestPluginAuthUser');
- $user['id'] = 1;
- $user['username'] = 'gwoo';
- $user['password'] = Security::hash(Configure::read('Security.salt') . 'cake');
- $PluginModel->save($user, false);
-
- $this->auth->settings['userModel'] = 'TestPlugin.TestPluginAuthUser';
- $this->auth->settings['fields']['username'] = 'username';
-
- $request = new CakeRequest('posts/index', false);
- $request->data = array('TestPluginAuthUser' => array(
- 'username' => 'gwoo',
- 'password' => 'cake'
- ));
-
- $result = $this->auth->authenticate($request, $this->response);
- $expected = array(
- 'id' => 1,
- 'username' => 'gwoo',
- 'created' => '2007-03-17 01:16:23'
- );
- $this->assertTrue($result['updated'] >= $ts);
- unset($result['updated']);
- $this->assertEquals($expected, $result);
- CakePlugin::unload();
- }
-
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php b/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php
deleted file mode 100644
index 1fb5e3e325d..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php
+++ /dev/null
@@ -1,1229 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Controller.Component
- * @since CakePHP(tm) v 1.2.0.5347
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('Controller', 'Controller');
-App::uses('AuthComponent', 'Controller/Component');
-App::uses('AclComponent', 'Controller/Component');
-App::uses('FormAuthenticate', 'Controller/Component/Auth');
-
-/**
- * TestAuthComponent class
- *
- * @package Cake.Test.Case.Controller.Component
- * @package Cake.Test.Case.Controller.Component
- */
-class TestAuthComponent extends AuthComponent {
-
-/**
- * testStop property
- *
- * @var bool false
- */
- public $testStop = false;
-
-/**
- * stop method
- *
- * @return void
- */
- protected function _stop($status = 0) {
- $this->testStop = true;
- }
-
- public static function clearUser() {
- self::$_user = array();
- }
-
-}
-
-/**
- * AuthUser class
- *
- * @package Cake.Test.Case.Controller.Component
- * @package Cake.Test.Case.Controller.Component
- */
-class AuthUser extends CakeTestModel {
-
-/**
- * name property
- *
- * @var string 'AuthUser'
- */
- public $name = 'AuthUser';
-
-/**
- * useDbConfig property
- *
- * @var string 'test'
- */
- public $useDbConfig = 'test';
-
-}
-
-/**
- * AuthTestController class
- *
- * @package Cake.Test.Case.Controller.Component
- * @package Cake.Test.Case.Controller.Component
- */
-class AuthTestController extends Controller {
-
-/**
- * name property
- *
- * @var string 'AuthTest'
- */
- public $name = 'AuthTest';
-
-/**
- * uses property
- *
- * @var array
- */
- public $uses = array('AuthUser');
-
-/**
- * components property
- *
- * @var array
- */
- public $components = array('Session', 'Auth');
-
-/**
- * testUrl property
- *
- * @var mixed null
- */
- public $testUrl = null;
-
-/**
- * construct method
- *
- * @return void
- */
- public function __construct($request, $response) {
- $request->addParams(Router::parse('/auth_test'));
- $request->here = '/auth_test';
- $request->webroot = '/';
- Router::setRequestInfo($request);
- parent::__construct($request, $response);
- }
-
-/**
- * login method
- *
- * @return void
- */
- public function login() {
- }
-
-/**
- * admin_login method
- *
- * @return void
- */
- public function admin_login() {
- }
-
-/**
- * admin_add method
- *
- * @return void
- */
- public function admin_add() {
- }
-
-/**
- * logout method
- *
- * @return void
- */
- public function logout() {
- }
-
-/**
- * add method
- *
- * @return void
- */
- public function add() {
- echo "add";
- }
-
-/**
- * add method
- *
- * @return void
- */
- public function camelCase() {
- echo "camelCase";
- }
-
-/**
- * redirect method
- *
- * @param mixed $url
- * @param mixed $status
- * @param mixed $exit
- * @return void
- */
- public function redirect($url, $status = null, $exit = true) {
- $this->testUrl = Router::url($url);
- return false;
- }
-
-/**
- * isAuthorized method
- *
- * @return void
- */
- public function isAuthorized() {
- }
-
-}
-
-/**
- * AjaxAuthController class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class AjaxAuthController extends Controller {
-
-/**
- * name property
- *
- * @var string 'AjaxAuth'
- */
- public $name = 'AjaxAuth';
-
-/**
- * components property
- *
- * @var array
- */
- public $components = array('Session', 'TestAuth');
-
-/**
- * uses property
- *
- * @var array
- */
- public $uses = array();
-
-/**
- * testUrl property
- *
- * @var mixed null
- */
- public $testUrl = null;
-
-/**
- * beforeFilter method
- *
- * @return void
- */
- public function beforeFilter() {
- $this->TestAuth->ajaxLogin = 'test_element';
- $this->TestAuth->userModel = 'AuthUser';
- $this->TestAuth->RequestHandler->ajaxLayout = 'ajax2';
- }
-
-/**
- * add method
- *
- * @return void
- */
- public function add() {
- if ($this->TestAuth->testStop !== true) {
- echo 'Added Record';
- }
- }
-
-/**
- * redirect method
- *
- * @param mixed $url
- * @param mixed $status
- * @param mixed $exit
- * @return void
- */
- public function redirect($url, $status = null, $exit = true) {
- $this->testUrl = Router::url($url);
- return false;
- }
-
-}
-
-/**
- * AuthComponentTest class
- *
- * @package Cake.Test.Case.Controller.Component
- * @package Cake.Test.Case.Controller.Component
- */
-class AuthComponentTest extends CakeTestCase {
-
-/**
- * name property
- *
- * @var string 'Auth'
- */
- public $name = 'Auth';
-
-/**
- * fixtures property
- *
- * @var array
- */
- public $fixtures = array('core.auth_user');
-
-/**
- * initialized property
- *
- * @var bool false
- */
- public $initialized = false;
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- $this->_server = $_SERVER;
- $this->_env = $_ENV;
-
- Configure::write('Security.salt', 'YJfIxfs2guVoUubWDYhG93b0qyJfIxfs2guwvniR2G0FgaC9mi');
- Configure::write('Security.cipherSeed', 770011223369876);
-
- $request = new CakeRequest(null, false);
-
- $this->Controller = new AuthTestController($request, $this->getMock('CakeResponse'));
-
- $collection = new ComponentCollection();
- $collection->init($this->Controller);
- $this->Auth = new TestAuthComponent($collection);
- $this->Auth->request = $request;
- $this->Auth->response = $this->getMock('CakeResponse');
-
- $this->Controller->Components->init($this->Controller);
-
- $this->initialized = true;
- Router::reload();
- Router::connect('/:controller/:action/*');
-
- $User = ClassRegistry::init('AuthUser');
- $User->updateAll(array('password' => $User->getDataSource()->value(Security::hash('cake', null, true))));
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- $_SERVER = $this->_server;
- $_ENV = $this->_env;
-
- TestAuthComponent::clearUser();
- $this->Auth->Session->delete('Auth');
- $this->Auth->Session->delete('Message.auth');
- unset($this->Controller, $this->Auth);
- }
-
-/**
- * testNoAuth method
- *
- * @return void
- */
- public function testNoAuth() {
- $this->assertFalse($this->Auth->isAuthorized());
- }
-
-/**
- * testIsErrorOrTests
- *
- * @return void
- */
- public function testIsErrorOrTests() {
- $this->Controller->Auth->initialize($this->Controller);
-
- $this->Controller->name = 'CakeError';
- $this->assertTrue($this->Controller->Auth->startup($this->Controller));
-
- $this->Controller->name = 'Post';
- $this->Controller->request['action'] = 'thisdoesnotexist';
- $this->assertTrue($this->Controller->Auth->startup($this->Controller));
-
- $this->Controller->scaffold = null;
- $this->Controller->request['action'] = 'index';
- $this->assertFalse($this->Controller->Auth->startup($this->Controller));
- }
-
-/**
- * testLogin method
- *
- * @return void
- */
- public function testLogin() {
- $this->getMock('FormAuthenticate', array(), array(), 'AuthLoginFormAuthenticate', false);
- $this->Auth->authenticate = array(
- 'AuthLoginForm' => array(
- 'userModel' => 'AuthUser'
- )
- );
- $this->Auth->Session = $this->getMock('SessionComponent', array('renew'), array(), '', false);
-
- $mocks = $this->Auth->constructAuthenticate();
- $this->mockObjects[] = $mocks[0];
-
- $this->Auth->request->data = array(
- 'AuthUser' => array(
- 'username' => 'mark',
- 'password' => Security::hash('cake', null, true)
- )
- );
-
- $user = array(
- 'id' => 1,
- 'username' => 'mark'
- );
-
- $mocks[0]->expects($this->once())
- ->method('authenticate')
- ->with($this->Auth->request)
- ->will($this->returnValue($user));
-
- $this->Auth->Session->expects($this->once())
- ->method('renew');
-
- $result = $this->Auth->login();
- $this->assertTrue($result);
-
- $this->assertTrue($this->Auth->loggedIn());
- $this->assertEquals($user, $this->Auth->user());
- }
-
-/**
- * test that being redirected to the login page, with no post data does
- * not set the session value. Saving the session value in this circumstance
- * can cause the user to be redirected to an already public page.
- *
- * @return void
- */
- public function testLoginActionNotSettingAuthRedirect() {
- $_SERVER['HTTP_REFERER'] = '/pages/display/about';
-
- $this->Controller->data = array();
- $this->Controller->request->addParams(Router::parse('auth_test/login'));
- $this->Controller->request->url = 'auth_test/login';
- $this->Auth->Session->delete('Auth');
-
- $this->Auth->loginRedirect = '/users/dashboard';
- $this->Auth->loginAction = 'auth_test/login';
- $this->Auth->userModel = 'AuthUser';
-
- $this->Auth->startup($this->Controller);
- $redirect = $this->Auth->Session->read('Auth.redirect');
- $this->assertNull($redirect);
- }
-
-/**
- * testAuthorizeFalse method
- *
- * @return void
- */
- public function testAuthorizeFalse() {
- $this->AuthUser = new AuthUser();
- $user = $this->AuthUser->find();
- $this->Auth->Session->write('Auth.User', $user['AuthUser']);
- $this->Controller->Auth->userModel = 'AuthUser';
- $this->Controller->Auth->authorize = false;
- $this->Controller->request->addParams(Router::parse('auth_test/add'));
- $result = $this->Controller->Auth->startup($this->Controller);
- $this->assertTrue($result);
-
- $this->Auth->Session->delete('Auth');
- $result = $this->Controller->Auth->startup($this->Controller);
- $this->assertFalse($result);
- $this->assertTrue($this->Auth->Session->check('Message.auth'));
-
- $this->Controller->request->addParams(Router::parse('auth_test/camelCase'));
- $result = $this->Controller->Auth->startup($this->Controller);
- $this->assertFalse($result);
- }
-
-/**
- * @expectedException CakeException
- * @return void
- */
- public function testIsAuthorizedMissingFile() {
- $this->Controller->Auth->authorize = 'Missing';
- $this->Controller->Auth->isAuthorized(array('User' => array('id' => 1)));
- }
-
-/**
- * test that isAuthorized calls methods correctly
- *
- * @return void
- */
- public function testIsAuthorizedDelegation() {
- $this->getMock('BaseAuthorize', array('authorize'), array(), 'AuthMockOneAuthorize', false);
- $this->getMock('BaseAuthorize', array('authorize'), array(), 'AuthMockTwoAuthorize', false);
- $this->getMock('BaseAuthorize', array('authorize'), array(), 'AuthMockThreeAuthorize', false);
-
- $this->Auth->authorize = array(
- 'AuthMockOne',
- 'AuthMockTwo',
- 'AuthMockThree'
- );
- $mocks = $this->Auth->constructAuthorize();
- $request = $this->Auth->request;
-
- $this->assertEquals(3, count($mocks));
- $mocks[0]->expects($this->once())
- ->method('authorize')
- ->with(array('User'), $request)
- ->will($this->returnValue(false));
-
- $mocks[1]->expects($this->once())
- ->method('authorize')
- ->with(array('User'), $request)
- ->will($this->returnValue(true));
-
- $mocks[2]->expects($this->never())
- ->method('authorize');
-
- $this->assertTrue($this->Auth->isAuthorized(array('User'), $request));
- }
-
-/**
- * test that isAuthorized will use the session user if none is given.
- *
- * @return void
- */
- public function testIsAuthorizedUsingUserInSession() {
- $this->getMock('BaseAuthorize', array('authorize'), array(), 'AuthMockFourAuthorize', false);
- $this->Auth->authorize = array('AuthMockFour');
-
- $user = array('user' => 'mark');
- $this->Auth->Session->write('Auth.User', $user);
- $mocks = $this->Auth->constructAuthorize();
- $request = $this->Controller->request;
-
- $mocks[0]->expects($this->once())
- ->method('authorize')
- ->with($user, $request)
- ->will($this->returnValue(true));
-
- $this->assertTrue($this->Auth->isAuthorized(null, $request));
- }
-
-/**
- * test that loadAuthorize resets the loaded objects each time.
- *
- * @return void
- */
- public function testLoadAuthorizeResets() {
- $this->Controller->Auth->authorize = array(
- 'Controller'
- );
- $result = $this->Controller->Auth->constructAuthorize();
- $this->assertEquals(1, count($result));
-
- $result = $this->Controller->Auth->constructAuthorize();
- $this->assertEquals(1, count($result));
- }
-
-/**
- * @expectedException CakeException
- * @return void
- */
- public function testLoadAuthenticateNoFile() {
- $this->Controller->Auth->authenticate = 'Missing';
- $this->Controller->Auth->identify($this->Controller->request, $this->Controller->response);
- }
-
-/**
- * test the * key with authenticate
- *
- * @return void
- */
- public function testAllConfigWithAuthorize() {
- $this->Controller->Auth->authorize = array(
- AuthComponent::ALL => array('actionPath' => 'controllers/'),
- 'Actions'
- );
- $objects = $this->Controller->Auth->constructAuthorize();
- $result = $objects[0];
- $this->assertEquals('controllers/', $result->settings['actionPath']);
- }
-
-/**
- * test that loadAuthorize resets the loaded objects each time.
- *
- * @return void
- */
- public function testLoadAuthenticateResets() {
- $this->Controller->Auth->authenticate = array(
- 'Form'
- );
- $result = $this->Controller->Auth->constructAuthenticate();
- $this->assertEquals(1, count($result));
-
- $result = $this->Controller->Auth->constructAuthenticate();
- $this->assertEquals(1, count($result));
- }
-
-/**
- * test the * key with authenticate
- *
- * @return void
- */
- public function testAllConfigWithAuthenticate() {
- $this->Controller->Auth->authenticate = array(
- AuthComponent::ALL => array('userModel' => 'AuthUser'),
- 'Form'
- );
- $objects = $this->Controller->Auth->constructAuthenticate();
- $result = $objects[0];
- $this->assertEquals('AuthUser', $result->settings['userModel']);
- }
-
-/**
- * Tests that deny always takes precedence over allow
- *
- * @return void
- */
- public function testAllowDenyAll() {
- $this->Controller->Auth->initialize($this->Controller);
-
- $this->Controller->Auth->allow();
- $this->Controller->Auth->deny('add', 'camelCase');
-
- $this->Controller->request['action'] = 'delete';
- $this->assertTrue($this->Controller->Auth->startup($this->Controller));
-
- $this->Controller->request['action'] = 'add';
- $this->assertFalse($this->Controller->Auth->startup($this->Controller));
-
- $this->Controller->request['action'] = 'camelCase';
- $this->assertFalse($this->Controller->Auth->startup($this->Controller));
-
- $this->Controller->Auth->allow();
- $this->Controller->Auth->deny(array('add', 'camelCase'));
-
- $this->Controller->request['action'] = 'delete';
- $this->assertTrue($this->Controller->Auth->startup($this->Controller));
-
- $this->Controller->request['action'] = 'camelCase';
- $this->assertFalse($this->Controller->Auth->startup($this->Controller));
-
- $this->Controller->Auth->allow('*');
- $this->Controller->Auth->deny();
-
- $this->Controller->request['action'] = 'camelCase';
- $this->assertFalse($this->Controller->Auth->startup($this->Controller));
-
- $this->Controller->request['action'] = 'add';
- $this->assertFalse($this->Controller->Auth->startup($this->Controller));
-
- $this->Controller->Auth->allow('camelCase');
- $this->Controller->Auth->deny();
-
- $this->Controller->request['action'] = 'camelCase';
- $this->assertFalse($this->Controller->Auth->startup($this->Controller));
-
- $this->Controller->request['action'] = 'login';
- $this->assertFalse($this->Controller->Auth->startup($this->Controller));
-
- $this->Controller->Auth->deny();
- $this->Controller->Auth->allow(null);
-
- $this->Controller->request['action'] = 'camelCase';
- $this->assertTrue($this->Controller->Auth->startup($this->Controller));
-
- $this->Controller->Auth->allow();
- $this->Controller->Auth->deny(null);
-
- $this->Controller->request['action'] = 'camelCase';
- $this->assertFalse($this->Controller->Auth->startup($this->Controller));
- }
-
-/**
- * test that deny() converts camel case inputs to lowercase.
- *
- * @return void
- */
- public function testDenyWithCamelCaseMethods() {
- $this->Controller->Auth->initialize($this->Controller);
- $this->Controller->Auth->allow();
- $this->Controller->Auth->deny('add', 'camelCase');
-
- $url = '/auth_test/camelCase';
- $this->Controller->request->addParams(Router::parse($url));
- $this->Controller->request->query['url'] = Router::normalize($url);
-
- $this->assertFalse($this->Controller->Auth->startup($this->Controller));
-
- $url = '/auth_test/CamelCase';
- $this->Controller->request->addParams(Router::parse($url));
- $this->Controller->request->query['url'] = Router::normalize($url);
- $this->assertFalse($this->Controller->Auth->startup($this->Controller));
- }
-
-/**
- * test that allow() and allowedActions work with camelCase method names.
- *
- * @return void
- */
- public function testAllowedActionsWithCamelCaseMethods() {
- $url = '/auth_test/camelCase';
- $this->Controller->request->addParams(Router::parse($url));
- $this->Controller->request->query['url'] = Router::normalize($url);
- $this->Controller->Auth->initialize($this->Controller);
- $this->Controller->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login');
- $this->Controller->Auth->userModel = 'AuthUser';
- $this->Controller->Auth->allow();
- $result = $this->Controller->Auth->startup($this->Controller);
- $this->assertTrue($result, 'startup() should return true, as action is allowed. %s');
-
- $url = '/auth_test/camelCase';
- $this->Controller->request->addParams(Router::parse($url));
- $this->Controller->request->query['url'] = Router::normalize($url);
- $this->Controller->Auth->initialize($this->Controller);
- $this->Controller->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login');
- $this->Controller->Auth->userModel = 'AuthUser';
- $this->Controller->Auth->allowedActions = array('delete', 'camelCase', 'add');
- $result = $this->Controller->Auth->startup($this->Controller);
- $this->assertTrue($result, 'startup() should return true, as action is allowed. %s');
-
- $this->Controller->Auth->allowedActions = array('delete', 'add');
- $result = $this->Controller->Auth->startup($this->Controller);
- $this->assertFalse($result, 'startup() should return false, as action is not allowed. %s');
-
- $url = '/auth_test/delete';
- $this->Controller->request->addParams(Router::parse($url));
- $this->Controller->request->query['url'] = Router::normalize($url);
- $this->Controller->Auth->initialize($this->Controller);
- $this->Controller->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login');
- $this->Controller->Auth->userModel = 'AuthUser';
-
- $this->Controller->Auth->allow(array('delete', 'add'));
- $result = $this->Controller->Auth->startup($this->Controller);
- $this->assertTrue($result, 'startup() should return true, as action is allowed. %s');
- }
-
- public function testAllowedActionsSetWithAllowMethod() {
- $url = '/auth_test/action_name';
- $this->Controller->request->addParams(Router::parse($url));
- $this->Controller->request->query['url'] = Router::normalize($url);
- $this->Controller->Auth->initialize($this->Controller);
- $this->Controller->Auth->allow('action_name', 'anotherAction');
- $this->assertEquals(array('action_name', 'anotherAction'), $this->Controller->Auth->allowedActions);
- }
-
-/**
- * testLoginRedirect method
- *
- * @return void
- */
- public function testLoginRedirect() {
- $_SERVER['HTTP_REFERER'] = false;
- $_ENV['HTTP_REFERER'] = false;
- putenv('HTTP_REFERER=');
-
- $this->Auth->Session->write('Auth', array(
- 'AuthUser' => array('id' => '1', 'username' => 'nate')
- ));
-
- $this->Auth->request->addParams(Router::parse('users/login'));
- $this->Auth->request->url = 'users/login';
- $this->Auth->initialize($this->Controller);
-
- $this->Auth->loginRedirect = array(
- 'controller' => 'pages', 'action' => 'display', 'welcome'
- );
- $this->Auth->startup($this->Controller);
- $expected = Router::normalize($this->Auth->loginRedirect);
- $this->assertEquals($expected, $this->Auth->redirect());
-
- $this->Auth->Session->delete('Auth');
-
- //empty referer no session
- $_SERVER['HTTP_REFERER'] = false;
- $_ENV['HTTP_REFERER'] = false;
- putenv('HTTP_REFERER=');
- $url = '/posts/view/1';
-
- $this->Auth->Session->write('Auth', array(
- 'AuthUser' => array('id' => '1', 'username' => 'nate'))
- );
- $this->Controller->testUrl = null;
- $this->Auth->request->addParams(Router::parse($url));
- array_push($this->Controller->methods, 'view', 'edit', 'index');
-
- $this->Auth->initialize($this->Controller);
- $this->Auth->authorize = 'controller';
-
- $this->Auth->loginAction = array(
- 'controller' => 'AuthTest', 'action' => 'login'
- );
- $this->Auth->startup($this->Controller);
- $expected = Router::normalize('/AuthTest/login');
- $this->assertEquals($expected, $this->Controller->testUrl);
-
- $this->Auth->Session->delete('Auth');
- $_SERVER['HTTP_REFERER'] = $_ENV['HTTP_REFERER'] = Router::url('/admin', true);
- $this->Auth->Session->write('Auth', array(
- 'AuthUser' => array('id' => '1', 'username' => 'nate')
- ));
- $this->Auth->request->params['action'] = 'login';
- $this->Auth->request->url = 'auth_test/login';
- $this->Auth->initialize($this->Controller);
- $this->Auth->loginAction = 'auth_test/login';
- $this->Auth->loginRedirect = false;
- $this->Auth->startup($this->Controller);
- $expected = Router::normalize('/admin');
- $this->assertEquals($expected, $this->Auth->redirect());
-
- //Ticket #4750
- //named params
- $this->Controller->request = $this->Auth->request;
- $this->Auth->Session->delete('Auth');
- $url = '/posts/index/year:2008/month:feb';
- $this->Auth->request->addParams(Router::parse($url));
- $this->Auth->request->url = $this->Auth->request->here = Router::normalize($url);
- $this->Auth->initialize($this->Controller);
- $this->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login');
- $this->Auth->startup($this->Controller);
- $expected = Router::normalize('posts/index/year:2008/month:feb');
- $this->assertEquals($expected, $this->Auth->Session->read('Auth.redirect'));
-
- //passed args
- $this->Auth->Session->delete('Auth');
- $url = '/posts/view/1';
- $this->Auth->request->addParams(Router::parse($url));
- $this->Auth->request->url = $this->Auth->request->here = Router::normalize($url);
- $this->Auth->initialize($this->Controller);
- $this->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login');
- $this->Auth->startup($this->Controller);
- $expected = Router::normalize('posts/view/1');
- $this->assertEquals($expected, $this->Auth->Session->read('Auth.redirect'));
-
- // QueryString parameters
- $_back = $_GET;
- $_GET = array(
- 'print' => 'true',
- 'refer' => 'menu'
- );
- $this->Auth->Session->delete('Auth');
- $url = '/posts/index/29';
- $this->Auth->request->addParams(Router::parse($url));
- $this->Auth->request->url = $this->Auth->request->here = Router::normalize($url);
- $this->Auth->request->query = $_GET;
-
- $this->Auth->initialize($this->Controller);
- $this->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login');
- $this->Auth->startup($this->Controller);
- $expected = Router::normalize('posts/index/29?print=true&refer=menu');
- $this->assertEquals($expected, $this->Auth->Session->read('Auth.redirect'));
-
- $_GET = $_back;
-
- //external authed action
- $_SERVER['HTTP_REFERER'] = 'http://webmail.example.com/view/message';
- $this->Auth->Session->delete('Auth');
- $url = '/posts/edit/1';
- $request = new CakeRequest($url);
- $request->query = array();
- $this->Auth->request = $this->Controller->request = $request;
- $this->Auth->request->addParams(Router::parse($url));
- $this->Auth->request->url = $this->Auth->request->here = Router::normalize($url);
- $this->Auth->initialize($this->Controller);
- $this->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login');
- $this->Auth->startup($this->Controller);
- $expected = Router::normalize('/posts/edit/1');
- $this->assertEquals($expected, $this->Auth->Session->read('Auth.redirect'));
-
- //external direct login link
- $_SERVER['HTTP_REFERER'] = 'http://webmail.example.com/view/message';
- $this->Auth->Session->delete('Auth');
- $url = '/AuthTest/login';
- $this->Auth->request = $this->Controller->request = new CakeRequest($url);
- $this->Auth->request->addParams(Router::parse($url));
- $this->Auth->request->url = Router::normalize($url);
- $this->Auth->initialize($this->Controller);
- $this->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login');
- $this->Auth->startup($this->Controller);
- $expected = Router::normalize('/');
- $this->assertEquals($expected, $this->Auth->Session->read('Auth.redirect'));
-
- $this->Auth->Session->delete('Auth');
- }
-
-/**
- * test that no redirects or authorization tests occur on the loginAction
- *
- * @return void
- */
- public function testNoRedirectOnLoginAction() {
- $controller = $this->getMock('Controller');
- $controller->methods = array('login');
-
- $url = '/AuthTest/login';
- $this->Auth->request = $controller->request = new CakeRequest($url);
- $this->Auth->request->addParams(Router::parse($url));
- $this->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login');
- $this->Auth->authorize = array('Controller');
-
- $controller->expects($this->never())
- ->method('redirect');
-
- $this->Auth->startup($controller);
- }
-
-/**
- * Ensure that no redirect is performed when a 404 is reached
- * And the user doesn't have a session.
- *
- * @return void
- */
- public function testNoRedirectOn404() {
- $this->Auth->Session->delete('Auth');
- $this->Auth->initialize($this->Controller);
- $this->Auth->request->addParams(Router::parse('auth_test/something_totally_wrong'));
- $result = $this->Auth->startup($this->Controller);
- $this->assertTrue($result, 'Auth redirected a missing action %s');
- }
-
-/**
- * testAdminRoute method
- *
- * @return void
- */
- public function testAdminRoute() {
- $pref = Configure::read('Routing.prefixes');
- Configure::write('Routing.prefixes', array('admin'));
- Router::reload();
- require CAKE . 'Config' . DS . 'routes.php';
-
- $url = '/admin/auth_test/add';
- $this->Auth->request->addParams(Router::parse($url));
- $this->Auth->request->query['url'] = ltrim($url, '/');
- $this->Auth->request->base = '';
-
- Router::setRequestInfo($this->Auth->request);
- $this->Auth->initialize($this->Controller);
-
- $this->Auth->loginAction = array(
- 'admin' => true, 'controller' => 'auth_test', 'action' => 'login'
- );
-
- $this->Auth->startup($this->Controller);
- $this->assertEquals('/admin/auth_test/login', $this->Controller->testUrl);
-
- Configure::write('Routing.prefixes', $pref);
- }
-
-/**
- * testAjaxLogin method
- *
- * @return void
- */
- public function testAjaxLogin() {
- App::build(array(
- 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
- ));
- $_SERVER['HTTP_X_REQUESTED_WITH'] = "XMLHttpRequest";
-
- App::uses('Dispatcher', 'Routing');
-
- ob_start();
- $Dispatcher = new Dispatcher();
- $Dispatcher->dispatch(new CakeRequest('/ajax_auth/add'), new CakeResponse(), array('return' => 1));
- $result = ob_get_clean();
-
- $this->assertEquals("Ajax!\nthis is the test element", str_replace("\r\n", "\n", $result));
- unset($_SERVER['HTTP_X_REQUESTED_WITH']);
- }
-
-/**
- * testLoginActionRedirect method
- *
- * @return void
- */
- public function testLoginActionRedirect() {
- $admin = Configure::read('Routing.prefixes');
- Configure::write('Routing.prefixes', array('admin'));
- Router::reload();
- require CAKE . 'Config' . DS . 'routes.php';
-
- $url = '/admin/auth_test/login';
- $this->Auth->request->addParams(Router::parse($url));
- $this->Auth->request->url = ltrim($url, '/');
- Router::setRequestInfo(array(
- array(
- 'pass' => array(), 'action' => 'admin_login', 'plugin' => null, 'controller' => 'auth_test',
- 'admin' => true,
- ),
- array(
- 'base' => null, 'here' => $url,
- 'webroot' => '/', 'passedArgs' => array(),
- )
- ));
-
- $this->Auth->initialize($this->Controller);
- $this->Auth->loginAction = array('admin' => true, 'controller' => 'auth_test', 'action' => 'login');
- $this->Auth->startup($this->Controller);
-
- $this->assertNull($this->Controller->testUrl);
-
- Configure::write('Routing.prefixes', $admin);
- }
-
-/**
- * Stateless auth methods like Basic should populate data that can be
- * accessed by $this->user().
- *
- * @return void
- */
- public function testStatelessAuthWorksWithUser() {
- $_SERVER['PHP_AUTH_USER'] = 'mariano';
- $_SERVER['PHP_AUTH_PW'] = 'cake';
- $url = '/auth_test/add';
- $this->Auth->request->addParams(Router::parse($url));
-
- $this->Auth->authenticate = array(
- 'Basic' => array('userModel' => 'AuthUser')
- );
- $this->Auth->startup($this->Controller);
-
- $result = $this->Auth->user();
- $this->assertEquals('mariano', $result['username']);
-
- $result = $this->Auth->user('username');
- $this->assertEquals('mariano', $result);
- }
-
-/**
- * Tests that shutdown destroys the redirect session var
- *
- * @return void
- */
- public function testShutDown() {
- $this->Auth->Session->write('Auth.User', 'not empty');
- $this->Auth->Session->write('Auth.redirect', 'foo');
- $this->Controller->Auth->loggedIn(true);
-
- $this->Controller->Auth->shutdown($this->Controller);
- $this->assertNull($this->Auth->Session->read('Auth.redirect'));
- }
-
-/**
- * test $settings in Controller::$components
- *
- * @return void
- */
- public function testComponentSettings() {
- $request = new CakeRequest(null, false);
- $this->Controller = new AuthTestController($request, $this->getMock('CakeResponse'));
-
- $this->Controller->components = array(
- 'Auth' => array(
- 'loginAction' => array('controller' => 'people', 'action' => 'login'),
- 'logoutRedirect' => array('controller' => 'people', 'action' => 'login'),
- ),
- 'Session'
- );
- $this->Controller->Components->init($this->Controller);
- $this->Controller->Components->trigger('initialize', array(&$this->Controller));
- Router::reload();
-
- $expected = array(
- 'loginAction' => array('controller' => 'people', 'action' => 'login'),
- 'logoutRedirect' => array('controller' => 'people', 'action' => 'login'),
- );
- $this->assertEquals($expected['loginAction'], $this->Controller->Auth->loginAction);
- $this->assertEquals($expected['logoutRedirect'], $this->Controller->Auth->logoutRedirect);
- }
-
-/**
- * test that logout deletes the session variables. and returns the correct url
- *
- * @return void
- */
- public function testLogout() {
- $this->Auth->Session->write('Auth.User.id', '1');
- $this->Auth->Session->write('Auth.redirect', '/users/login');
- $this->Auth->logoutRedirect = '/';
- $result = $this->Auth->logout();
-
- $this->assertEquals('/', $result);
- $this->assertNull($this->Auth->Session->read('Auth.AuthUser'));
- $this->assertNull($this->Auth->Session->read('Auth.redirect'));
- }
-
-/**
- * Logout should trigger a logout method on authentication objects.
- *
- * @return void
- */
- public function testLogoutTrigger() {
- $this->getMock('BaseAuthenticate', array('authenticate', 'logout'), array(), 'LogoutTriggerMockAuthenticate', false);
-
- $this->Auth->authenticate = array('LogoutTriggerMock');
- $mock = $this->Auth->constructAuthenticate();
- $mock[0]->expects($this->once())
- ->method('logout');
-
- $this->Auth->logout();
- }
-
-/**
- * test mapActions loading and delegating to authorize objects.
- *
- * @return void
- */
- public function testMapActionsDelegation() {
- $this->getMock('BaseAuthorize', array('authorize'), array(), 'MapActionMockAuthorize', false);
- $this->Auth->authorize = array('MapActionMock');
- $mock = $this->Auth->constructAuthorize();
- $mock[0]->expects($this->once())
- ->method('mapActions')
- ->with(array('create' => array('my_action')));
-
- $this->Auth->mapActions(array('create' => array('my_action')));
- }
-
-/**
- * test logging in with a request.
- *
- * @return void
- */
- public function testLoginWithRequestData() {
- $this->getMock('FormAuthenticate', array(), array(), 'RequestLoginMockAuthenticate', false);
- $request = new CakeRequest('users/login', false);
- $user = array('username' => 'mark', 'role' => 'admin');
-
- $this->Auth->request = $request;
- $this->Auth->authenticate = array('RequestLoginMock');
- $mock = $this->Auth->constructAuthenticate();
- $mock[0]->expects($this->once())
- ->method('authenticate')
- ->with($request)
- ->will($this->returnValue($user));
-
- $this->assertTrue($this->Auth->login());
- $this->assertEquals($user['username'], $this->Auth->user('username'));
- }
-
-/**
- * test login() with user data
- *
- * @return void
- */
- public function testLoginWithUserData() {
- $this->assertFalse($this->Auth->loggedIn());
-
- $user = array(
- 'username' => 'mariano',
- 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
- 'created' => '2007-03-17 01:16:23',
- 'updated' => '2007-03-17 01:18:31'
- );
- $this->assertTrue($this->Auth->login($user));
- $this->assertTrue($this->Auth->loggedIn());
- $this->assertEquals($user['username'], $this->Auth->user('username'));
- }
-
-/**
- * test flash settings.
- *
- * @return void
- */
- public function testFlashSettings() {
- $this->Auth->Session = $this->getMock('SessionComponent', array(), array(), '', false);
- $this->Auth->Session->expects($this->once())
- ->method('setFlash')
- ->with('Auth failure', 'custom', array(1), 'auth-key');
-
- $this->Auth->flash = array(
- 'element' => 'custom',
- 'params' => array(1),
- 'key' => 'auth-key'
- );
- $this->Auth->flash('Auth failure');
- }
-
-/**
- * test the various states of Auth::redirect()
- *
- * @return void
- */
- public function testRedirectSet() {
- $value = array('controller' => 'users', 'action' => 'home');
- $result = $this->Auth->redirect($value);
- $this->assertEquals('/users/home', $result);
- $this->assertEquals($value, $this->Auth->Session->read('Auth.redirect'));
- }
-
-/**
- * test redirect using Auth.redirect from the session.
- *
- * @return void
- */
- public function testRedirectSessionRead() {
- $this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
- $this->Auth->Session->write('Auth.redirect', '/users/home');
-
- $result = $this->Auth->redirect();
- $this->assertEquals('/users/home', $result);
- $this->assertFalse($this->Auth->Session->check('Auth.redirect'));
- }
-
-/**
- * test that redirect does not return loginAction if that is what's stored in Auth.redirect.
- * instead loginRedirect should be used.
- *
- * @return void
- */
- public function testRedirectSessionReadEqualToLoginAction() {
- $this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
- $this->Auth->loginRedirect = array('controller' => 'users', 'action' => 'home');
- $this->Auth->Session->write('Auth.redirect', array('controller' => 'users', 'action' => 'login'));
-
- $result = $this->Auth->redirect();
- $this->assertEquals('/users/home', $result);
- $this->assertFalse($this->Auth->Session->check('Auth.redirect'));
- }
-
-/**
- * test password hashing
- *
- * @return void
- */
- public function testPassword() {
- $result = $this->Auth->password('password');
- $expected = Security::hash('password', null, true);
- $this->assertEquals($expected, $result);
- }
-
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php
deleted file mode 100644
index 7924876441b..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php
+++ /dev/null
@@ -1,602 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Controller.Component
- * @since CakePHP(tm) v 1.2.0.5435
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('Component', 'Controller');
-App::uses('Controller', 'Controller');
-App::uses('CookieComponent', 'Controller/Component');
-
-
-/**
- * CookieComponentTestController class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class CookieComponentTestController extends Controller {
-
-/**
- * components property
- *
- * @var array
- */
- public $components = array('Cookie');
-
-/**
- * beforeFilter method
- *
- * @return void
- */
- public function beforeFilter() {
- $this->Cookie->name = 'CakeTestCookie';
- $this->Cookie->time = 10;
- $this->Cookie->path = '/';
- $this->Cookie->domain = '';
- $this->Cookie->secure = false;
- $this->Cookie->key = 'somerandomhaskey';
- }
-
-}
-
-/**
- * CookieComponentTest class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class CookieComponentTest extends CakeTestCase {
-
-/**
- * Controller property
- *
- * @var CookieComponentTestController
- */
- public $Controller;
-
-/**
- * start
- *
- * @return void
- */
- public function setUp() {
- $_COOKIE = array();
- $this->Controller = new CookieComponentTestController(new CakeRequest(), new CakeResponse());
- $this->Controller->constructClasses();
- $this->Cookie = $this->Controller->Cookie;
-
- $this->Cookie->name = 'CakeTestCookie';
- $this->Cookie->time = 10;
- $this->Cookie->path = '/';
- $this->Cookie->domain = '';
- $this->Cookie->secure = false;
- $this->Cookie->key = 'somerandomhaskey';
-
- $this->Cookie->startup($this->Controller);
- }
-
-/**
- * end
- *
- * @return void
- */
- public function tearDown() {
- $this->Cookie->destroy();
- }
-
-/**
- * sets up some default cookie data.
- *
- * @return void
- */
- protected function _setCookieData() {
- $this->Cookie->write(array('Encrytped_array' => array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!')));
- $this->Cookie->write(array('Encrytped_multi_cookies.name' => 'CakePHP'));
- $this->Cookie->write(array('Encrytped_multi_cookies.version' => '1.2.0.x'));
- $this->Cookie->write(array('Encrytped_multi_cookies.tag' => 'CakePHP Rocks!'));
-
- $this->Cookie->write(array('Plain_array' => array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!')), null, false);
- $this->Cookie->write(array('Plain_multi_cookies.name' => 'CakePHP'), null, false);
- $this->Cookie->write(array('Plain_multi_cookies.version' => '1.2.0.x'), null, false);
- $this->Cookie->write(array('Plain_multi_cookies.tag' => 'CakePHP Rocks!'), null, false);
- }
-
-/**
- * test that initialize sets settings from components array
- *
- * @return void
- */
- public function testSettings() {
- $settings = array(
- 'time' => '5 days',
- 'path' => '/'
- );
- $Cookie = new CookieComponent(new ComponentCollection(), $settings);
- $this->assertEquals($Cookie->time, $settings['time']);
- $this->assertEquals($Cookie->path, $settings['path']);
- }
-
-/**
- * testCookieName
- *
- * @return void
- */
- public function testCookieName() {
- $this->assertEquals('CakeTestCookie', $this->Cookie->name);
- }
-
-/**
- * testReadEncryptedCookieData
- *
- * @return void
- */
- public function testReadEncryptedCookieData() {
- $this->_setCookieData();
- $data = $this->Cookie->read('Encrytped_array');
- $expected = array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!');
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Encrytped_multi_cookies');
- $expected = array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!');
- $this->assertEquals($expected, $data);
- }
-
-/**
- * testReadPlainCookieData
- *
- * @return void
- */
- public function testReadPlainCookieData() {
- $this->_setCookieData();
- $data = $this->Cookie->read('Plain_array');
- $expected = array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!');
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Plain_multi_cookies');
- $expected = array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!');
- $this->assertEquals($expected, $data);
- }
-
-/**
- * test read() after switching the cookie name.
- *
- * @return void
- */
- public function testReadWithNameSwitch() {
- $_COOKIE = array(
- 'CakeTestCookie' => array(
- 'key' => 'value'
- ),
- 'OtherTestCookie' => array(
- 'key' => 'other value'
- )
- );
- $this->assertEquals('value', $this->Cookie->read('key'));
-
- $this->Cookie->name = 'OtherTestCookie';
- $this->assertEquals('other value', $this->Cookie->read('key'));
- }
-
-/**
- * test a simple write()
- *
- * @return void
- */
- public function testWriteSimple() {
- $this->Cookie->write('Testing', 'value');
- $result = $this->Cookie->read('Testing');
-
- $this->assertEquals('value', $result);
- }
-
-/**
- * test write with httpOnly cookies
- *
- * @return void
- */
- public function testWriteHttpOnly() {
- $this->Cookie->httpOnly = true;
- $this->Cookie->secure = false;
- $this->Cookie->write('Testing', 'value', false);
- $expected = array(
- 'name' => $this->Cookie->name . '[Testing]',
- 'value' => 'value',
- 'expire' => time() + 10,
- 'path' => '/',
- 'domain' => '',
- 'secure' => false,
- 'httpOnly' => true);
- $result = $this->Controller->response->cookie($this->Cookie->name . '[Testing]');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test delete with httpOnly
- *
- * @return void
- */
- public function testDeleteHttpOnly() {
- $this->Cookie->httpOnly = true;
- $this->Cookie->secure = false;
- $this->Cookie->delete('Testing', false);
- $expected = array(
- 'name' => $this->Cookie->name . '[Testing]',
- 'value' => '',
- 'expire' => time() - 42000,
- 'path' => '/',
- 'domain' => '',
- 'secure' => false,
- 'httpOnly' => true);
- $result = $this->Controller->response->cookie($this->Cookie->name . '[Testing]');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * testWritePlainCookieArray
- *
- * @return void
- */
- public function testWritePlainCookieArray() {
- $this->Cookie->write(array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!'), null, false);
-
- $this->assertEquals('CakePHP', $this->Cookie->read('name'));
- $this->assertEquals('1.2.0.x', $this->Cookie->read('version'));
- $this->assertEquals('CakePHP Rocks!', $this->Cookie->read('tag'));
-
- $this->Cookie->delete('name');
- $this->Cookie->delete('version');
- $this->Cookie->delete('tag');
- }
-
-/**
- * test writing values that are not scalars
- *
- * @return void
- */
- public function testWriteArrayValues() {
- $this->Cookie->secure = false;
- $this->Cookie->write('Testing', array(1, 2, 3), false);
- $expected = array(
- 'name' => $this->Cookie->name . '[Testing]',
- 'value' => '[1,2,3]',
- 'expire' => time() + 10,
- 'path' => '/',
- 'domain' => '',
- 'secure' => false,
- 'httpOnly' => false);
- $result = $this->Controller->response->cookie($this->Cookie->name . '[Testing]');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * testReadingCookieValue
- *
- * @return void
- */
- public function testReadingCookieValue() {
- $this->_setCookieData();
- $data = $this->Cookie->read();
- $expected = array(
- 'Encrytped_array' => array(
- 'name' => 'CakePHP',
- 'version' => '1.2.0.x',
- 'tag' => 'CakePHP Rocks!'),
- 'Encrytped_multi_cookies' => array(
- 'name' => 'CakePHP',
- 'version' => '1.2.0.x',
- 'tag' => 'CakePHP Rocks!'),
- 'Plain_array' => array(
- 'name' => 'CakePHP',
- 'version' => '1.2.0.x',
- 'tag' => 'CakePHP Rocks!'),
- 'Plain_multi_cookies' => array(
- 'name' => 'CakePHP',
- 'version' => '1.2.0.x',
- 'tag' => 'CakePHP Rocks!'));
- $this->assertEquals($expected, $data);
- }
-
-/**
- * testDeleteCookieValue
- *
- * @return void
- */
- public function testDeleteCookieValue() {
- $this->_setCookieData();
- $this->Cookie->delete('Encrytped_multi_cookies.name');
- $data = $this->Cookie->read('Encrytped_multi_cookies');
- $expected = array('version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!');
- $this->assertEquals($expected, $data);
-
- $this->Cookie->delete('Encrytped_array');
- $data = $this->Cookie->read('Encrytped_array');
- $this->assertNull($data);
-
- $this->Cookie->delete('Plain_multi_cookies.name');
- $data = $this->Cookie->read('Plain_multi_cookies');
- $expected = array('version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!');
- $this->assertEquals($expected, $data);
-
- $this->Cookie->delete('Plain_array');
- $data = $this->Cookie->read('Plain_array');
- $this->assertNull($data);
- }
-
-/**
- * testReadingCookieArray
- *
- * @return void
- */
- public function testReadingCookieArray() {
- $this->_setCookieData();
-
- $data = $this->Cookie->read('Encrytped_array.name');
- $expected = 'CakePHP';
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Encrytped_array.version');
- $expected = '1.2.0.x';
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Encrytped_array.tag');
- $expected = 'CakePHP Rocks!';
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Encrytped_multi_cookies.name');
- $expected = 'CakePHP';
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Encrytped_multi_cookies.version');
- $expected = '1.2.0.x';
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Encrytped_multi_cookies.tag');
- $expected = 'CakePHP Rocks!';
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Plain_array.name');
- $expected = 'CakePHP';
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Plain_array.version');
- $expected = '1.2.0.x';
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Plain_array.tag');
- $expected = 'CakePHP Rocks!';
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Plain_multi_cookies.name');
- $expected = 'CakePHP';
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Plain_multi_cookies.version');
- $expected = '1.2.0.x';
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Plain_multi_cookies.tag');
- $expected = 'CakePHP Rocks!';
- $this->assertEquals($expected, $data);
- }
-
-/**
- * testReadingCookieDataOnStartup
- *
- * @return void
- */
- public function testReadingCookieDataOnStartup() {
- $data = $this->Cookie->read('Encrytped_array');
- $this->assertNull($data);
-
- $data = $this->Cookie->read('Encrytped_multi_cookies');
- $this->assertNull($data);
-
- $data = $this->Cookie->read('Plain_array');
- $this->assertNull($data);
-
- $data = $this->Cookie->read('Plain_multi_cookies');
- $this->assertNull($data);
-
- $_COOKIE['CakeTestCookie'] = array(
- 'Encrytped_array' => $this->__encrypt(array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!')),
- 'Encrytped_multi_cookies' => array(
- 'name' => $this->__encrypt('CakePHP'),
- 'version' => $this->__encrypt('1.2.0.x'),
- 'tag' => $this->__encrypt('CakePHP Rocks!')),
- 'Plain_array' => '{"name":"CakePHP","version":"1.2.0.x","tag":"CakePHP Rocks!"}',
- 'Plain_multi_cookies' => array(
- 'name' => 'CakePHP',
- 'version' => '1.2.0.x',
- 'tag' => 'CakePHP Rocks!'));
-
- $this->Cookie->startup(new CookieComponentTestController());
-
- $data = $this->Cookie->read('Encrytped_array');
- $expected = array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!');
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Encrytped_multi_cookies');
- $expected = array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!');
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Plain_array');
- $expected = array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!');
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Plain_multi_cookies');
- $expected = array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!');
- $this->assertEquals($expected, $data);
- $this->Cookie->destroy();
- unset($_COOKIE['CakeTestCookie']);
- }
-
-/**
- * testReadingCookieDataWithoutStartup
- *
- * @return void
- */
- public function testReadingCookieDataWithoutStartup() {
- $data = $this->Cookie->read('Encrytped_array');
- $expected = null;
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Encrytped_multi_cookies');
- $expected = null;
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Plain_array');
- $expected = null;
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Plain_multi_cookies');
- $expected = null;
- $this->assertEquals($expected, $data);
-
- $_COOKIE['CakeTestCookie'] = array(
- 'Encrytped_array' => $this->__encrypt(array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!')),
- 'Encrytped_multi_cookies' => array(
- 'name' => $this->__encrypt('CakePHP'),
- 'version' => $this->__encrypt('1.2.0.x'),
- 'tag' => $this->__encrypt('CakePHP Rocks!')),
- 'Plain_array' => '{"name":"CakePHP","version":"1.2.0.x","tag":"CakePHP Rocks!"}',
- 'Plain_multi_cookies' => array(
- 'name' => 'CakePHP',
- 'version' => '1.2.0.x',
- 'tag' => 'CakePHP Rocks!'));
-
- $data = $this->Cookie->read('Encrytped_array');
- $expected = array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!');
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Encrytped_multi_cookies');
- $expected = array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!');
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Plain_array');
- $expected = array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!');
- $this->assertEquals($expected, $data);
-
- $data = $this->Cookie->read('Plain_multi_cookies');
- $expected = array('name' => 'CakePHP', 'version' => '1.2.0.x', 'tag' => 'CakePHP Rocks!');
- $this->assertEquals($expected, $data);
- $this->Cookie->destroy();
- unset($_COOKIE['CakeTestCookie']);
- }
-
-/**
- * Test Reading legacy cookie values.
- *
- * @return void
- */
- public function testReadLegacyCookieValue() {
- $_COOKIE['CakeTestCookie'] = array(
- 'Legacy' => array('value' => $this->_oldImplode(array(1, 2, 3)))
- );
- $result = $this->Cookie->read('Legacy.value');
- $expected = array(1, 2, 3);
- $this->assertEquals($expected, $result);
- }
-
-/**
- * Test reading empty values.
- */
- public function testReadEmpty() {
- $_COOKIE['CakeTestCookie'] = array(
- 'JSON' => '{"name":"value"}',
- 'Empty' => '',
- 'String' => '{"somewhat:"broken"}'
- );
- $this->assertEqual(array('name' => 'value'), $this->Cookie->read('JSON'));
- $this->assertEqual('value', $this->Cookie->read('JSON.name'));
- $this->assertEqual('', $this->Cookie->read('Empty'));
- $this->assertEqual('{"somewhat:"broken"}', $this->Cookie->read('String'));
- }
-
-/**
- * test that no error is issued for non array data.
- *
- * @return void
- */
- public function testNoErrorOnNonArrayData() {
- $this->Cookie->destroy();
- $_COOKIE['CakeTestCookie'] = 'kaboom';
-
- $this->assertNull($this->Cookie->read('value'));
- }
-
-/**
- * test that deleting a top level keys kills the child elements too.
- *
- * @return void
- */
- public function testDeleteRemovesChildren() {
- $_COOKIE['CakeTestCookie'] = array(
- 'User' => array('email' => 'example@example.com', 'name' => 'mark'),
- 'other' => 'value'
- );
- $this->assertEquals('mark', $this->Cookie->read('User.name'));
-
- $this->Cookie->delete('User');
- $this->assertNull($this->Cookie->read('User.email'));
- $this->Cookie->destroy();
- }
-
-/**
- * Test deleting recursively with keys that don't exist.
- *
- * @return void
- */
- public function testDeleteChildrenNotExist() {
- $this->assertNull($this->Cookie->delete('NotFound'));
- $this->assertNull($this->Cookie->delete('Not.Found'));
- }
-
-/**
- * Helper method for generating old style encoded cookie values.
- *
- * @return string.
- */
- protected function _oldImplode(array $array) {
- $string = '';
- foreach ($array as $key => $value) {
- $string .= ',' . $key . '|' . $value;
- }
- return substr($string, 1);
- }
-
-/**
- * Implode method to keep keys are multidimensional arrays
- *
- * @param array $array Map of key and values
- * @return string String in the form key1|value1,key2|value2
- */
- protected function _implode(array $array) {
- return json_encode($array);
- }
-
-/**
- * encrypt method
- *
- * @param mixed $value
- * @return string
- */
- protected function __encrypt($value) {
- if (is_array($value)) {
- $value = $this->_implode($value);
- }
- return "Q2FrZQ==." . base64_encode(Security::cipher($value, $this->Cookie->key));
- }
-
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/EmailComponentTest.php b/lib/Cake/Test/Case/Controller/Component/EmailComponentTest.php
deleted file mode 100644
index b1a272b8215..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/EmailComponentTest.php
+++ /dev/null
@@ -1,882 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Controller.Component
- * @since CakePHP(tm) v 1.2.0.5347
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-App::uses('Controller', 'Controller');
-App::uses('EmailComponent', 'Controller/Component');
-App::uses('AbstractTransport', 'Network/Email');
-
-/**
- * EmailTestComponent class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class EmailTestComponent extends EmailComponent {
-
-/**
- * Convenience method for testing.
- *
- * @return string
- */
- public function strip($content, $message = false) {
- return parent::_strip($content, $message);
- }
-
-}
-
-/**
- * DebugCompTransport class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class DebugCompTransport extends AbstractTransport {
-
-/**
- * Last email
- *
- * @var string
- */
- public static $lastEmail = null;
-
-/**
- * Send mail
- *
- * @params object $email CakeEmail
- * @return boolean
- */
- public function send(CakeEmail $email) {
- $email->addHeaders(array('Date' => EmailComponentTest::$sentDate));
- $headers = $email->getHeaders(array_fill_keys(array('from', 'replyTo', 'readReceipt', 'returnPath', 'to', 'cc', 'bcc', 'subject'), true));
- $to = $headers['To'];
- $subject = $headers['Subject'];
- unset($headers['To'], $headers['Subject']);
-
- $message = implode("\n", $email->message());
-
- $last = '';
- $last .= sprintf("%s %s\n", 'To:', $to);
- $last .= sprintf("%s %s\n", 'From:', $headers['From']);
- $last .= sprintf("%s %s\n", 'Subject:', $subject);
- $last .= sprintf("%s\n\n%s", 'Header:', $this->_headersToString($headers, "\n"));
- $last .= sprintf("%s\n\n%s", 'Message:', $message);
- $last .= ' ';
-
- self::$lastEmail = $last;
-
- return true;
- }
-
-}
-
-/**
- * EmailTestController class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class EmailTestController extends Controller {
-
-/**
- * name property
- *
- * @var string 'EmailTest'
- */
- public $name = 'EmailTest';
-
-/**
- * uses property
- *
- * @var mixed null
- */
- public $uses = null;
-
-/**
- * components property
- *
- * @var array
- */
- public $components = array('Session', 'EmailTest');
-
-}
-
-/**
- * EmailTest class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class EmailComponentTest extends CakeTestCase {
-
-/**
- * Controller property
- *
- * @var EmailTestController
- */
- public $Controller;
-
-/**
- * name property
- *
- * @var string 'Email'
- */
- public $name = 'Email';
-
-/**
- * sentDate
- *
- * @var string
- */
- public static $sentDate = null;
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- $this->_appEncoding = Configure::read('App.encoding');
- Configure::write('App.encoding', 'UTF-8');
-
- $this->Controller = new EmailTestController();
-
- $this->Controller->Components->init($this->Controller);
-
- $this->Controller->EmailTest->initialize($this->Controller, array());
-
- self::$sentDate = date(DATE_RFC2822);
-
- App::build(array(
- 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
- ));
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- Configure::write('App.encoding', $this->_appEncoding);
- App::build();
- ClassRegistry::flush();
- }
-
-/**
- * testSendFormats method
- *
- * @return void
- */
- public function testSendFormats() {
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'Cake SMTP test';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
- $this->Controller->EmailTest->template = null;
- $this->Controller->EmailTest->delivery = 'DebugComp';
- $this->Controller->EmailTest->messageId = false;
-
- $date = self::$sentDate;
- $message = <<To: postmaster@example.com
-From: noreply@example.com
-Subject: Cake SMTP test
-Header:
-
-From: noreply@example.com
-Reply-To: noreply@example.com
-X-Mailer: CakePHP Email Component
-Date: $date
-MIME-Version: 1.0
-Content-Type: {CONTENTTYPE}
-Content-Transfer-Encoding: 8bitMessage:
-
-This is the body of the message
-
-
-MSGBLOC;
-
- $this->Controller->EmailTest->sendAs = 'text';
- $expect = str_replace('{CONTENTTYPE}', 'text/plain; charset=UTF-8', $message);
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- $this->assertTextEquals(DebugCompTransport::$lastEmail, $expect);
-
- $this->Controller->EmailTest->sendAs = 'html';
- $expect = str_replace('{CONTENTTYPE}', 'text/html; charset=UTF-8', $message);
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- $this->assertTextEquals(DebugCompTransport::$lastEmail, $expect);
- }
-
-/**
- * testTemplates method
- *
- * @return void
- */
- public function testTemplates() {
- ClassRegistry::flush();
-
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'Cake SMTP test';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
-
- $this->Controller->EmailTest->delivery = 'DebugComp';
- $this->Controller->EmailTest->messageId = false;
-
- $date = self::$sentDate;
- $header = <<Controller->EmailTest->layout = 'default';
- $this->Controller->EmailTest->template = 'default';
- $this->Controller->set('title_for_layout', 'Email Test');
-
- $text = <<
-
-
-
- Email Test
-
-
-
- This is the body of the message
- This email was sent using the CakePHP Framework
-
-
-HTMLBLOC;
-
- $this->Controller->EmailTest->sendAs = 'text';
- $expect = '' . str_replace('{CONTENTTYPE}', 'text/plain; charset=UTF-8', $header) . $text . "\n" . ' ';
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- $this->assertTextEquals(DebugCompTransport::$lastEmail, $expect);
-
- $this->Controller->EmailTest->sendAs = 'html';
- $expect = '' . str_replace('{CONTENTTYPE}', 'text/html; charset=UTF-8', $header) . $html . "\n" . ' ';
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- $this->assertTextEquals(DebugCompTransport::$lastEmail, $expect);
-
- $this->Controller->EmailTest->sendAs = 'both';
- $expect = str_replace('{CONTENTTYPE}', 'multipart/mixed; boundary="{boundary}"', $header);
- $expect .= "--{boundary}\n" .
- 'Content-Type: multipart/alternative; boundary="alt-{boundary}"' . "\n\n" .
- '--alt-{boundary}' . "\n" .
- 'Content-Type: text/plain; charset=UTF-8' . "\n" .
- 'Content-Transfer-Encoding: 8bit' . "\n\n" .
- $text .
- "\n\n" .
- '--alt-{boundary}' . "\n" .
- 'Content-Type: text/html; charset=UTF-8' . "\n" .
- 'Content-Transfer-Encoding: 8bit' . "\n\n" .
- $html .
- "\n\n" .
- '--alt-{boundary}--' . "\n\n\n" .
- '--{boundary}--' . "\n";
-
- $expect = '' . $expect . ' ';
-
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- $this->assertTextEquals(
- $expect,
- preg_replace('/[a-z0-9]{32}/i', '{boundary}', DebugCompTransport::$lastEmail)
- );
-
- $html = <<
-
-
-
- Email Test
-
-
-
- This is the body of the message
- This email was sent using the CakePHP Framework
-
-
-
-HTMLBLOC;
-
- $this->Controller->EmailTest->sendAs = 'html';
- $expect = '' . str_replace('{CONTENTTYPE}', 'text/html; charset=UTF-8', $header) . $html . ' ';
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message', 'default', 'thin'));
- $this->assertTextEquals(DebugCompTransport::$lastEmail, $expect);
- }
-
-/**
- * test that elements used in email templates get helpers.
- *
- * @return void
- */
- public function testTemplateNestedElements() {
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'Cake SMTP test';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
-
- $this->Controller->EmailTest->delivery = 'DebugComp';
- $this->Controller->EmailTest->messageId = false;
- $this->Controller->EmailTest->layout = 'default';
- $this->Controller->EmailTest->template = 'nested_element';
- $this->Controller->EmailTest->sendAs = 'html';
- $this->Controller->helpers = array('Html');
-
- $this->Controller->EmailTest->send();
- $result = DebugCompTransport::$lastEmail;
- $this->assertRegExp('/Test/', $result);
- $this->assertRegExp('/http\:\/\/example\.com/', $result);
- }
-
-/**
- * testSendDebug method
- *
- * @return void
- */
- public function testSendDebug() {
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->cc = 'cc@example.com';
- $this->Controller->EmailTest->bcc = 'bcc@example.com';
- $this->Controller->EmailTest->subject = 'Cake Debug Test';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
- $this->Controller->EmailTest->template = null;
-
- $this->Controller->EmailTest->delivery = 'DebugComp';
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- $result = DebugCompTransport::$lastEmail;
-
- $this->assertRegExp('/To: postmaster@example.com\n/', $result);
- $this->assertRegExp('/Subject: Cake Debug Test\n/', $result);
- $this->assertRegExp('/Reply-To: noreply@example.com\n/', $result);
- $this->assertRegExp('/From: noreply@example.com\n/', $result);
- $this->assertRegExp('/Cc: cc@example.com\n/', $result);
- $this->assertRegExp('/Bcc: bcc@example.com\n/', $result);
- $this->assertRegExp('/Date: ' . preg_quote(self::$sentDate) . '\n/', $result);
- $this->assertRegExp('/X-Mailer: CakePHP Email Component\n/', $result);
- $this->assertRegExp('/Content-Type: text\/plain; charset=UTF-8\n/', $result);
- $this->assertRegExp('/Content-Transfer-Encoding: 8bitMessage:\n/', $result);
- $this->assertRegExp('/This is the body of the message/', $result);
- }
-
-/**
- * test send with delivery = debug and not using sessions.
- *
- * @return void
- */
- public function testSendDebugWithNoSessions() {
- $session = $this->Controller->Session;
- unset($this->Controller->Session);
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'Cake Debug Test';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
- $this->Controller->EmailTest->template = null;
-
- $this->Controller->EmailTest->delivery = 'DebugComp';
- $this->Controller->EmailTest->send('This is the body of the message');
- $result = DebugCompTransport::$lastEmail;
-
- $this->assertRegExp('/To: postmaster@example.com\n/', $result);
- $this->assertRegExp('/Subject: Cake Debug Test\n/', $result);
- $this->assertRegExp('/Reply-To: noreply@example.com\n/', $result);
- $this->assertRegExp('/From: noreply@example.com\n/', $result);
- $this->assertRegExp('/Date: ' . preg_quote(self::$sentDate) . '\n/', $result);
- $this->assertRegExp('/X-Mailer: CakePHP Email Component\n/', $result);
- $this->assertRegExp('/Content-Type: text\/plain; charset=UTF-8\n/', $result);
- $this->assertRegExp('/Content-Transfer-Encoding: 8bitMessage:\n/', $result);
- $this->assertRegExp('/This is the body of the message/', $result);
- $this->Controller->Session = $session;
- }
-
-/**
- * testMessageRetrievalWithoutTemplate method
- *
- * @return void
- */
- public function testMessageRetrievalWithoutTemplate() {
- App::build(array(
- 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
- ));
-
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'Cake Debug Test';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
- $this->Controller->EmailTest->layout = 'default';
- $this->Controller->EmailTest->template = null;
-
- $this->Controller->EmailTest->delivery = 'DebugComp';
-
- $text = $html = "This is the body of the message\n";
-
- $this->Controller->EmailTest->sendAs = 'both';
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- $this->assertTextEquals($this->Controller->EmailTest->textMessage, $text);
- $this->assertTextEquals($this->Controller->EmailTest->htmlMessage, $html);
-
- $this->Controller->EmailTest->sendAs = 'text';
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- $this->assertTextEquals($this->Controller->EmailTest->textMessage, $text);
- $this->assertNull($this->Controller->EmailTest->htmlMessage);
-
- $this->Controller->EmailTest->sendAs = 'html';
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- $this->assertNull($this->Controller->EmailTest->textMessage);
- $this->assertTextEquals($this->Controller->EmailTest->htmlMessage, $html);
- }
-
-/**
- * testMessageRetrievalWithTemplate method
- *
- * @return void
- */
- public function testMessageRetrievalWithTemplate() {
- App::build(array(
- 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
- ));
-
- $this->Controller->set('value', 22091985);
- $this->Controller->set('title_for_layout', 'EmailTest');
-
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'Cake Debug Test';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
- $this->Controller->EmailTest->layout = 'default';
- $this->Controller->EmailTest->template = 'custom';
-
- $this->Controller->EmailTest->delivery = 'DebugComp';
-
- $text = <<
-
-
-
- EmailTest
-
-
-
- Here is your value: 22091985
-
- This email was sent using the CakePHP Framework
-
-
-HTMLBLOC;
-
- $this->Controller->EmailTest->sendAs = 'both';
- $this->assertTrue($this->Controller->EmailTest->send());
- $this->assertTextEquals($this->Controller->EmailTest->textMessage, $text);
- $this->assertTextEquals($this->Controller->EmailTest->htmlMessage, $html);
-
- $this->Controller->EmailTest->sendAs = 'text';
- $this->assertTrue($this->Controller->EmailTest->send());
- $this->assertTextEquals($this->Controller->EmailTest->textMessage, $text);
- $this->assertNull($this->Controller->EmailTest->htmlMessage);
-
- $this->Controller->EmailTest->sendAs = 'html';
- $this->assertTrue($this->Controller->EmailTest->send());
- $this->assertNull($this->Controller->EmailTest->textMessage);
- $this->assertTextEquals($this->Controller->EmailTest->htmlMessage, $html);
- }
-
-/**
- * testMessageRetrievalWithHelper method
- *
- * @return void
- */
- public function testMessageRetrievalWithHelper() {
- App::build(array(
- 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
- ));
-
- $timestamp = time();
- $this->Controller->set('time', $timestamp);
- $this->Controller->set('title_for_layout', 'EmailTest');
- $this->Controller->helpers = array('Time');
-
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'Cake Debug Test';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
- $this->Controller->EmailTest->layout = 'default';
- $this->Controller->EmailTest->template = 'custom_helper';
- $this->Controller->EmailTest->sendAs = 'text';
- $this->Controller->EmailTest->delivery = 'DebugComp';
-
- $this->assertTrue($this->Controller->EmailTest->send());
- $this->assertTrue((bool)strpos($this->Controller->EmailTest->textMessage, 'Right now: ' . date('Y-m-d\TH:i:s\Z', $timestamp)));
- }
-
-/**
- * testContentArray method
- *
- * @return void
- */
- public function testSendContentArray() {
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'Cake Debug Test';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
- $this->Controller->EmailTest->template = null;
- $this->Controller->EmailTest->delivery = 'DebugComp';
-
- $content = array('First line', 'Second line', 'Third line');
- $this->assertTrue($this->Controller->EmailTest->send($content));
- $result = DebugCompTransport::$lastEmail;
-
- $this->assertRegExp('/To: postmaster@example.com\n/', $result);
- $this->assertRegExp('/Subject: Cake Debug Test\n/', $result);
- $this->assertRegExp('/Reply-To: noreply@example.com\n/', $result);
- $this->assertRegExp('/From: noreply@example.com\n/', $result);
- $this->assertRegExp('/X-Mailer: CakePHP Email Component\n/', $result);
- $this->assertRegExp('/Content-Type: text\/plain; charset=UTF-8\n/', $result);
- $this->assertRegExp('/Content-Transfer-Encoding: 8bitMessage:\n/', $result);
- $this->assertRegExp('/First line\n/', $result);
- $this->assertRegExp('/Second line\n/', $result);
- $this->assertRegExp('/Third line\n/', $result);
- }
-
-/**
- * test setting a custom date.
- *
- * @return void
- */
- public function testDateProperty() {
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'Cake Debug Test';
- $this->Controller->EmailTest->date = self::$sentDate = 'Today!';
- $this->Controller->EmailTest->template = null;
- $this->Controller->EmailTest->delivery = 'DebugComp';
-
- $this->assertTrue($this->Controller->EmailTest->send('test message'));
- $result = DebugCompTransport::$lastEmail;
- $this->assertRegExp('/Date: Today!\n/', $result);
- }
-
-/**
- * testContentStripping method
- *
- * @return void
- */
- public function testContentStripping() {
- $content = "Previous content\n--alt-\nContent-TypeContent-Type:: text/html; charsetcharset==utf-8\nContent-Transfer-Encoding: 8bit";
- $content .= "\n\nMy own html content
";
-
- $result = $this->Controller->EmailTest->strip($content, true);
- $expected = "Previous content\n--alt-\n text/html; utf-8\n 8bit\n\nMy own html content
";
- $this->assertEquals($expected, $result);
-
- $content = 'Some HTML content with an email link ';
- $result = $this->Controller->EmailTest->strip($content, true);
- $expected = $content;
- $this->assertEquals($expected, $result);
-
- $content = '
Some HTML content with an ';
- $content .= 'email link ';
- $result = $this->Controller->EmailTest->strip($content, true);
- $expected = $content;
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test that the _encode() will set mb_internal_encoding.
- *
- * @return void
- */
- public function testEncodeSettingInternalCharset() {
- $this->skipIf(!function_exists('mb_internal_encoding'), 'Missing mb_* functions, cannot run test.');
-
- $restore = mb_internal_encoding();
- mb_internal_encoding('ISO-8859-1');
-
- $this->Controller->charset = 'UTF-8';
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'هذه رسالة بعنوان طويل مرسل للمستلم';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
- $this->Controller->EmailTest->template = null;
- $this->Controller->EmailTest->delivery = 'DebugComp';
-
- $this->Controller->EmailTest->sendAs = 'text';
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
-
- $subject = '=?UTF-8?B?2YfYsNmHINix2LPYp9mE2Kkg2KjYudmG2YjYp9mGINi32YjZitmEINmF2LE=?=' . "\r\n" . ' =?UTF-8?B?2LPZhCDZhNmE2YXYs9iq2YTZhQ==?=';
-
- preg_match('/Subject: (.*)Header:/s', DebugCompTransport::$lastEmail, $matches);
- $this->assertEquals(trim($matches[1]), $subject);
-
- $result = mb_internal_encoding();
- $this->assertEquals('ISO-8859-1', $result);
-
- mb_internal_encoding($restore);
- }
-
-/**
- * testMultibyte method
- *
- * @return void
- */
- public function testMultibyte() {
- $this->Controller->charset = 'UTF-8';
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'هذه رسالة بعنوان طويل مرسل للمستلم';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
- $this->Controller->EmailTest->template = null;
- $this->Controller->EmailTest->delivery = 'DebugComp';
-
- $subject = '=?UTF-8?B?2YfYsNmHINix2LPYp9mE2Kkg2KjYudmG2YjYp9mGINi32YjZitmEINmF2LE=?=' . "\r\n" . ' =?UTF-8?B?2LPZhCDZhNmE2YXYs9iq2YTZhQ==?=';
-
- $this->Controller->EmailTest->sendAs = 'text';
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- preg_match('/Subject: (.*)Header:/s', DebugCompTransport::$lastEmail, $matches);
- $this->assertEquals(trim($matches[1]), $subject);
-
- $this->Controller->EmailTest->sendAs = 'html';
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- preg_match('/Subject: (.*)Header:/s', DebugCompTransport::$lastEmail, $matches);
- $this->assertEquals(trim($matches[1]), $subject);
-
- $this->Controller->EmailTest->sendAs = 'both';
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- preg_match('/Subject: (.*)Header:/s', DebugCompTransport::$lastEmail, $matches);
- $this->assertEquals(trim($matches[1]), $subject);
- }
-
-/**
- * undocumented function
- *
- * @return void
- */
- public function testSendWithAttachments() {
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'Attachment Test';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
- $this->Controller->EmailTest->template = null;
- $this->Controller->EmailTest->delivery = 'DebugComp';
- $this->Controller->EmailTest->attachments = array(
- __FILE__,
- 'some-name.php' => __FILE__
- );
- $body = '
This is the body of the message
';
-
- $this->Controller->EmailTest->sendAs = 'text';
- $this->assertTrue($this->Controller->EmailTest->send($body));
- $msg = DebugCompTransport::$lastEmail;
- $this->assertRegExp('/' . preg_quote('Content-Disposition: attachment; filename="EmailComponentTest.php"') . '/', $msg);
- $this->assertRegExp('/' . preg_quote('Content-Disposition: attachment; filename="some-name.php"') . '/', $msg);
- }
-
-/**
- * testSendAsIsNotIgnoredIfAttachmentsPresent method
- *
- * @return void
- */
- public function testSendAsIsNotIgnoredIfAttachmentsPresent() {
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'Attachment Test';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
- $this->Controller->EmailTest->template = null;
- $this->Controller->EmailTest->delivery = 'DebugComp';
- $this->Controller->EmailTest->attachments = array(__FILE__);
- $body = 'This is the body of the message
';
-
- $this->Controller->EmailTest->sendAs = 'html';
- $this->assertTrue($this->Controller->EmailTest->send($body));
- $msg = DebugCompTransport::$lastEmail;
- $this->assertNotRegExp('/text\/plain/', $msg);
- $this->assertRegExp('/text\/html/', $msg);
-
- $this->Controller->EmailTest->sendAs = 'text';
- $this->assertTrue($this->Controller->EmailTest->send($body));
- $msg = DebugCompTransport::$lastEmail;
- $this->assertRegExp('/text\/plain/', $msg);
- $this->assertNotRegExp('/text\/html/', $msg);
-
- $this->Controller->EmailTest->sendAs = 'both';
- $this->assertTrue($this->Controller->EmailTest->send($body));
- $msg = DebugCompTransport::$lastEmail;
-
- $this->assertRegExp('/text\/plain/', $msg);
- $this->assertRegExp('/text\/html/', $msg);
- $this->assertRegExp('/multipart\/alternative/', $msg);
- }
-
-/**
- * testNoDoubleNewlinesInHeaders function
- *
- * @return void
- */
- public function testNoDoubleNewlinesInHeaders() {
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'Attachment Test';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
- $this->Controller->EmailTest->template = null;
- $this->Controller->EmailTest->delivery = 'DebugComp';
- $body = 'This is the body of the message
';
-
- $this->Controller->EmailTest->sendAs = 'both';
- $this->assertTrue($this->Controller->EmailTest->send($body));
- $msg = DebugCompTransport::$lastEmail;
-
- $this->assertNotRegExp('/\n\nContent-Transfer-Encoding/', $msg);
- $this->assertRegExp('/\nContent-Transfer-Encoding/', $msg);
- }
-
-/**
- * testReset method
- *
- * @return void
- */
- public function testReset() {
- $this->Controller->EmailTest->template = 'default';
- $this->Controller->EmailTest->to = 'test.recipient@example.com';
- $this->Controller->EmailTest->from = 'test.sender@example.com';
- $this->Controller->EmailTest->replyTo = 'test.replyto@example.com';
- $this->Controller->EmailTest->return = 'test.return@example.com';
- $this->Controller->EmailTest->cc = array('cc1@example.com', 'cc2@example.com');
- $this->Controller->EmailTest->bcc = array('bcc1@example.com', 'bcc2@example.com');
- $this->Controller->EmailTest->date = 'Today!';
- $this->Controller->EmailTest->subject = 'Test subject';
- $this->Controller->EmailTest->additionalParams = 'X-additional-header';
- $this->Controller->EmailTest->delivery = 'smtp';
- $this->Controller->EmailTest->smtpOptions['host'] = 'blah';
- $this->Controller->EmailTest->smtpOptions['timeout'] = 0.2;
- $this->Controller->EmailTest->attachments = array('attachment1', 'attachment2');
- $this->Controller->EmailTest->textMessage = 'This is the body of the message';
- $this->Controller->EmailTest->htmlMessage = 'This is the body of the message';
- $this->Controller->EmailTest->messageId = false;
-
- try {
- $this->Controller->EmailTest->send('Should not work');
- $this->fail('No exception');
- } catch (SocketException $e) {
- $this->assertTrue(true, 'SocketException raised');
- }
-
- $this->Controller->EmailTest->reset();
-
- $this->assertNull($this->Controller->EmailTest->template);
- $this->assertSame($this->Controller->EmailTest->to, array());
- $this->assertNull($this->Controller->EmailTest->from);
- $this->assertNull($this->Controller->EmailTest->replyTo);
- $this->assertNull($this->Controller->EmailTest->return);
- $this->assertSame($this->Controller->EmailTest->cc, array());
- $this->assertSame($this->Controller->EmailTest->bcc, array());
- $this->assertNull($this->Controller->EmailTest->date);
- $this->assertNull($this->Controller->EmailTest->subject);
- $this->assertNull($this->Controller->EmailTest->additionalParams);
- $this->assertNull($this->Controller->EmailTest->smtpError);
- $this->assertSame($this->Controller->EmailTest->attachments, array());
- $this->assertNull($this->Controller->EmailTest->textMessage);
- $this->assertTrue($this->Controller->EmailTest->messageId);
- $this->assertEquals('mail', $this->Controller->EmailTest->delivery);
- }
-
- public function testPluginCustomViewClass() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS),
- 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
- ));
-
- $this->Controller->view = 'TestPlugin.Email';
-
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'CustomViewClass test';
- $this->Controller->EmailTest->delivery = 'DebugComp';
- $body = 'Body of message';
-
- $this->assertTrue($this->Controller->EmailTest->send($body));
- $result = DebugCompTransport::$lastEmail;
-
- $this->assertRegExp('/Body of message/', $result);
- }
-
-/**
- * testStartup method
- *
- * @return void
- */
- public function testStartup() {
- $this->assertNull($this->Controller->EmailTest->startup($this->Controller));
- }
-
-/**
- * testMessageId method
- *
- * @return void
- */
- public function testMessageId() {
- $this->Controller->EmailTest->to = 'postmaster@example.com';
- $this->Controller->EmailTest->from = 'noreply@example.com';
- $this->Controller->EmailTest->subject = 'Cake Debug Test';
- $this->Controller->EmailTest->replyTo = 'noreply@example.com';
- $this->Controller->EmailTest->template = null;
-
- $this->Controller->EmailTest->delivery = 'DebugComp';
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- $result = DebugCompTransport::$lastEmail;
-
- $this->assertRegExp('/Message-ID: \<[a-f0-9]{8}[a-f0-9]{4}[a-f0-9]{4}[a-f0-9]{4}[a-f0-9]{12}@' . env('HTTP_HOST') . '\>\n/', $result);
-
- $this->Controller->EmailTest->messageId = '<22091985.998877@example.com>';
-
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- $result = DebugCompTransport::$lastEmail;
-
- $this->assertRegExp('/Message-ID: <22091985.998877@example.com>\n/', $result);
-
- $this->Controller->EmailTest->messageId = false;
-
- $this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
- $result = DebugCompTransport::$lastEmail;
-
- $this->assertNotRegExp('/Message-ID:/', $result);
- }
-
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php b/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php
deleted file mode 100644
index e5ba32c2a72..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php
+++ /dev/null
@@ -1,884 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Controller.Component
- * @since CakePHP(tm) v 2.0
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('Controller', 'Controller');
-App::uses('PaginatorComponent', 'Controller/Component');
-App::uses('CakeRequest', 'Network');
-App::uses('CakeResponse', 'Network');
-
-/**
- * PaginatorTestController class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class PaginatorTestController extends Controller {
-
-/**
- * name property
- *
- * @var string 'PaginatorTest'
- */
- public $name = 'PaginatorTest';
-
-/**
- * components property
- *
- * @var array
- */
- public $components = array('Paginator');
-}
-
-/**
- * PaginatorControllerPost class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class PaginatorControllerPost extends CakeTestModel {
-
-/**
- * name property
- *
- * @var string 'PaginatorControllerPost'
- */
- public $name = 'PaginatorControllerPost';
-
-/**
- * useTable property
- *
- * @var string 'posts'
- */
- public $useTable = 'posts';
-
-/**
- * invalidFields property
- *
- * @var array
- */
- public $invalidFields = array('name' => 'error_msg');
-
-/**
- * lastQueries property
- *
- * @var array
- */
- public $lastQueries = array();
-
-/**
- * belongsTo property
- *
- * @var array
- */
- public $belongsTo = array('PaginatorAuthor' => array('foreignKey' => 'author_id'));
-
-/**
- * beforeFind method
- *
- * @param mixed $query
- * @return void
- */
- public function beforeFind($query) {
- array_unshift($this->lastQueries, $query);
- }
-
-/**
- * find method
- *
- * @param mixed $type
- * @param array $options
- * @return void
- */
- public function find($conditions = null, $fields = array(), $order = null, $recursive = null) {
- if ($conditions == 'popular') {
- $conditions = array($this->name . '.' . $this->primaryKey . ' > ' => '1');
- $options = Set::merge($fields, compact('conditions'));
- return parent::find('all', $options);
- }
- return parent::find($conditions, $fields);
- }
-
-}
-
-/**
- * ControllerPaginateModel class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class ControllerPaginateModel extends CakeTestModel {
-
-/**
- * name property
- *
- * @var string 'ControllerPaginateModel'
- */
- public $name = 'ControllerPaginateModel';
-
-/**
- * useTable property
- *
- * @var string 'comments'
- */
- public $useTable = 'comments';
-
-/**
- * paginate method
- *
- * @return void
- */
- public function paginate($conditions, $fields, $order, $limit, $page, $recursive, $extra) {
- $this->extra = $extra;
- }
-
-/**
- * paginateCount
- *
- * @return void
- */
- public function paginateCount($conditions, $recursive, $extra) {
- $this->extraCount = $extra;
- }
-
-}
-
-/**
- * PaginatorControllerComment class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class PaginatorControllerComment extends CakeTestModel {
-
-/**
- * name property
- *
- * @var string 'Comment'
- */
- public $name = 'Comment';
-
-/**
- * useTable property
- *
- * @var string 'comments'
- */
- public $useTable = 'comments';
-
-/**
- * alias property
- *
- * @var string 'PaginatorControllerComment'
- */
- public $alias = 'PaginatorControllerComment';
-}
-
-/**
- * PaginatorAuthor class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class PaginatorAuthor extends CakeTestModel {
-
-/**
- * name property
- *
- * @var string 'PaginatorAuthor'
- */
- public $name = 'PaginatorAuthor';
-
-/**
- * useTable property
- *
- * @var string 'authors'
- */
- public $useTable = 'authors';
-
-/**
- * alias property
- *
- * @var string 'PaginatorAuthor'
- */
- public $alias = 'PaginatorAuthor';
-
-/**
- * alias property
- *
- * @var string 'PaginatorAuthor'
- */
- public $virtualFields = array(
- 'joined_offset' => 'PaginatorAuthor.id + 1'
- );
-
-}
-
-class PaginatorComponentTest extends CakeTestCase {
-
-/**
- * fixtures property
- *
- * @var array
- */
- public $fixtures = array('core.post', 'core.comment', 'core.author');
-
-/**
- * setup
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- $this->request = new CakeRequest('controller_posts/index');
- $this->request->params['pass'] = $this->request->params['named'] = array();
- $this->Controller = new Controller($this->request);
- $this->Paginator = new PaginatorComponent($this->getMock('ComponentCollection'), array());
- $this->Paginator->Controller = $this->Controller;
- $this->Controller->Post = $this->getMock('Model');
- $this->Controller->Post->alias = 'Post';
- }
-
-/**
- * testPaginate method
- *
- * @return void
- */
- public function testPaginate() {
- $Controller = new PaginatorTestController($this->request);
- $Controller->uses = array('PaginatorControllerPost', 'PaginatorControllerComment');
- $Controller->request->params['pass'] = array('1');
- $Controller->request->query = array();
- $Controller->constructClasses();
-
- $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id');
- $this->assertEquals(array(1, 2, 3), $results);
-
- $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerComment'), '{n}.PaginatorControllerComment.id');
- $this->assertEquals(array(1, 2, 3, 4, 5, 6), $results);
-
- $Controller->modelClass = null;
-
- $Controller->uses[0] = 'Plugin.PaginatorControllerPost';
- $results = Set::extract($Controller->Paginator->paginate(), '{n}.PaginatorControllerPost.id');
- $this->assertEquals(array(1, 2, 3), $results);
-
- $Controller->request->params['named'] = array('page' => '-1');
- $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id');
- $this->assertEquals(1, $Controller->params['paging']['PaginatorControllerPost']['page']);
- $this->assertEquals(array(1, 2, 3), $results);
-
- $Controller->request->params['named'] = array('sort' => 'PaginatorControllerPost.id', 'direction' => 'asc');
- $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id');
- $this->assertEquals(1, $Controller->params['paging']['PaginatorControllerPost']['page']);
- $this->assertEquals(array(1, 2, 3), $results);
-
- $Controller->request->params['named'] = array('sort' => 'PaginatorControllerPost.id', 'direction' => 'desc');
- $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id');
- $this->assertEquals(1, $Controller->params['paging']['PaginatorControllerPost']['page']);
- $this->assertEquals(array(3, 2, 1), $results);
-
- $Controller->request->params['named'] = array('sort' => 'id', 'direction' => 'desc');
- $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id');
- $this->assertEquals(1, $Controller->params['paging']['PaginatorControllerPost']['page']);
- $this->assertEquals(array(3, 2, 1), $results);
-
- $Controller->request->params['named'] = array('sort' => 'NotExisting.field', 'direction' => 'desc');
- $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id');
- $this->assertEquals(1, $Controller->params['paging']['PaginatorControllerPost']['page'], 'Invalid field in query %s');
- $this->assertEquals(array(1, 2, 3), $results);
-
- $Controller->request->params['named'] = array(
- 'sort' => 'PaginatorControllerPost.author_id', 'direction' => 'allYourBase'
- );
- $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id');
- $this->assertEquals(array('PaginatorControllerPost.author_id' => 'asc'), $Controller->PaginatorControllerPost->lastQueries[1]['order'][0]);
- $this->assertEquals(array(1, 3, 2), $results);
-
- $Controller->request->params['named'] = array();
- $Controller->Paginator->settings = array('limit' => 0, 'maxLimit' => 10, 'paramType' => 'named');
- $Controller->Paginator->paginate('PaginatorControllerPost');
- $this->assertSame(1, $Controller->params['paging']['PaginatorControllerPost']['page']);
- $this->assertSame($Controller->params['paging']['PaginatorControllerPost']['pageCount'], 3);
- $this->assertSame($Controller->params['paging']['PaginatorControllerPost']['prevPage'], false);
- $this->assertSame($Controller->params['paging']['PaginatorControllerPost']['nextPage'], true);
-
- $Controller->request->params['named'] = array();
- $Controller->Paginator->settings = array('limit' => 'garbage!', 'maxLimit' => 10, 'paramType' => 'named');
- $Controller->Paginator->paginate('PaginatorControllerPost');
- $this->assertSame(1, $Controller->params['paging']['PaginatorControllerPost']['page']);
- $this->assertSame($Controller->params['paging']['PaginatorControllerPost']['pageCount'], 3);
- $this->assertSame($Controller->params['paging']['PaginatorControllerPost']['prevPage'], false);
- $this->assertSame($Controller->params['paging']['PaginatorControllerPost']['nextPage'], true);
-
- $Controller->request->params['named'] = array();
- $Controller->Paginator->settings = array('limit' => '-1', 'maxLimit' => 10, 'paramType' => 'named');
- $Controller->Paginator->paginate('PaginatorControllerPost');
-
- $this->assertSame($Controller->params['paging']['PaginatorControllerPost']['limit'], 1);
- $this->assertSame(1, $Controller->params['paging']['PaginatorControllerPost']['page']);
- $this->assertSame($Controller->params['paging']['PaginatorControllerPost']['pageCount'], 3);
- $this->assertSame($Controller->params['paging']['PaginatorControllerPost']['prevPage'], false);
- $this->assertSame($Controller->params['paging']['PaginatorControllerPost']['nextPage'], true);
- }
-
-/**
- * Test that non-numeric values are rejected for page, and limit
- *
- * @return void
- */
- public function testPageParamCasting() {
- $this->Controller->Post->expects($this->at(0))
- ->method('hasMethod')
- ->with('paginate')
- ->will($this->returnValue(false));
-
- $this->Controller->Post->expects($this->at(1))
- ->method('find')
- ->will($this->returnValue(array('stuff')));
-
- $this->Controller->Post->expects($this->at(2))
- ->method('hasMethod')
- ->with('paginateCount')
- ->will($this->returnValue(false));
-
- $this->Controller->Post->expects($this->at(3))
- ->method('find')
- ->will($this->returnValue(2));
-
- $this->request->params['named'] = array('page' => '1 " onclick="alert(\'xss\');">');
- $this->Paginator->settings = array('limit' => 1, 'maxLimit' => 10, 'paramType' => 'named');
- $this->Paginator->paginate('Post');
- $this->assertSame(1, $this->request->params['paging']['Post']['page'], 'XSS exploit opened');
- }
-
-/**
- * testPaginateExtraParams method
- *
- * @return void
- */
- public function testPaginateExtraParams() {
- $Controller = new PaginatorTestController($this->request);
-
- $Controller->uses = array('PaginatorControllerPost', 'PaginatorControllerComment');
- $Controller->request->params['pass'] = array('1');
- $Controller->params['url'] = array();
- $Controller->constructClasses();
-
- $Controller->request->params['named'] = array('page' => '-1', 'contain' => array('PaginatorControllerComment'));
- $result = $Controller->Paginator->paginate('PaginatorControllerPost');
- $this->assertEquals(1, $Controller->params['paging']['PaginatorControllerPost']['page']);
- $this->assertEquals(array(1, 2, 3), Set::extract($result, '{n}.PaginatorControllerPost.id'));
- $this->assertTrue(!isset($Controller->PaginatorControllerPost->lastQueries[1]['contain']));
-
- $Controller->request->params['named'] = array('page' => '-1');
- $Controller->Paginator->settings = array(
- 'PaginatorControllerPost' => array(
- 'contain' => array('PaginatorControllerComment'),
- 'maxLimit' => 10,
- 'paramType' => 'named'
- ),
- );
- $result = $Controller->Paginator->paginate('PaginatorControllerPost');
- $this->assertEquals(1, $Controller->params['paging']['PaginatorControllerPost']['page']);
- $this->assertEquals(array(1, 2, 3), Set::extract($result, '{n}.PaginatorControllerPost.id'));
- $this->assertTrue(isset($Controller->PaginatorControllerPost->lastQueries[1]['contain']));
-
- $Controller->Paginator->settings = array(
- 'PaginatorControllerPost' => array(
- 'popular', 'fields' => array('id', 'title'), 'maxLimit' => 10, 'paramType' => 'named'
- ),
- );
- $result = $Controller->Paginator->paginate('PaginatorControllerPost');
- $this->assertEquals(array(2, 3), Set::extract($result, '{n}.PaginatorControllerPost.id'));
- $this->assertEquals(array('PaginatorControllerPost.id > ' => '1'), $Controller->PaginatorControllerPost->lastQueries[1]['conditions']);
-
- $Controller->request->params['named'] = array('limit' => 12);
- $Controller->Paginator->settings = array('limit' => 30, 'maxLimit' => 100, 'paramType' => 'named');
- $result = $Controller->Paginator->paginate('PaginatorControllerPost');
- $paging = $Controller->params['paging']['PaginatorControllerPost'];
-
- $this->assertEquals(12, $Controller->PaginatorControllerPost->lastQueries[1]['limit']);
- $this->assertEquals(12, $paging['options']['limit']);
-
- $Controller = new PaginatorTestController($this->request);
- $Controller->uses = array('ControllerPaginateModel');
- $Controller->request->query = array();
- $Controller->constructClasses();
- $Controller->Paginator->settings = array(
- 'ControllerPaginateModel' => array(
- 'contain' => array('ControllerPaginateModel'),
- 'group' => 'Comment.author_id',
- 'maxLimit' => 10,
- 'paramType' => 'named'
- )
- );
- $result = $Controller->Paginator->paginate('ControllerPaginateModel');
- $expected = array(
- 'contain' => array('ControllerPaginateModel'),
- 'group' => 'Comment.author_id',
- 'maxLimit' => 10,
- 'paramType' => 'named'
- );
- $this->assertEquals($expected, $Controller->ControllerPaginateModel->extra);
- $this->assertEquals($expected, $Controller->ControllerPaginateModel->extraCount);
-
- $Controller->Paginator->settings = array(
- 'ControllerPaginateModel' => array(
- 'foo', 'contain' => array('ControllerPaginateModel'),
- 'group' => 'Comment.author_id',
- 'maxLimit' => 10,
- 'paramType' => 'named'
- )
- );
- $Controller->Paginator->paginate('ControllerPaginateModel');
- $expected = array(
- 'contain' => array('ControllerPaginateModel'),
- 'group' => 'Comment.author_id',
- 'type' => 'foo',
- 'maxLimit' => 10,
- 'paramType' => 'named'
- );
- $this->assertEquals($expected, $Controller->ControllerPaginateModel->extra);
- $this->assertEquals($expected, $Controller->ControllerPaginateModel->extraCount);
- }
-
-/**
- * Test that special paginate types are called and that the type param doesn't leak out into defaults or options.
- *
- * @return void
- */
- public function testPaginateSpecialType() {
- $Controller = new PaginatorTestController($this->request);
- $Controller->uses = array('PaginatorControllerPost', 'PaginatorControllerComment');
- $Controller->passedArgs[] = '1';
- $Controller->params['url'] = array();
- $Controller->constructClasses();
-
- $Controller->Paginator->settings = array(
- 'PaginatorControllerPost' => array(
- 'popular',
- 'fields' => array('id', 'title'),
- 'maxLimit' => 10,
- 'paramType' => 'named'
- )
- );
- $result = $Controller->Paginator->paginate('PaginatorControllerPost');
-
- $this->assertEquals(array(2, 3), Set::extract($result, '{n}.PaginatorControllerPost.id'));
- $this->assertEquals(
- $Controller->PaginatorControllerPost->lastQueries[1]['conditions'],
- array('PaginatorControllerPost.id > ' => '1')
- );
- $this->assertFalse(isset($Controller->params['paging']['PaginatorControllerPost']['options'][0]));
- }
-
-/**
- * testDefaultPaginateParams method
- *
- * @return void
- */
- public function testDefaultPaginateParams() {
- $Controller = new PaginatorTestController($this->request);
- $Controller->modelClass = 'PaginatorControllerPost';
- $Controller->params['url'] = array();
- $Controller->constructClasses();
- $Controller->Paginator->settings = array(
- 'order' => 'PaginatorControllerPost.id DESC',
- 'maxLimit' => 10,
- 'paramType' => 'named'
- );
- $results = Set::extract($Controller->Paginator->paginate('PaginatorControllerPost'), '{n}.PaginatorControllerPost.id');
- $this->assertEquals('PaginatorControllerPost.id DESC', $Controller->params['paging']['PaginatorControllerPost']['order']);
- $this->assertEquals(array(3, 2, 1), $results);
- }
-
-/**
- * test paginate() and virtualField interactions
- *
- * @return void
- */
- public function testPaginateOrderVirtualField() {
- $Controller = new PaginatorTestController($this->request);
- $Controller->uses = array('PaginatorControllerPost', 'PaginatorControllerComment');
- $Controller->params['url'] = array();
- $Controller->constructClasses();
- $Controller->PaginatorControllerPost->virtualFields = array(
- 'offset_test' => 'PaginatorControllerPost.id + 1'
- );
-
- $Controller->Paginator->settings = array(
- 'fields' => array('id', 'title', 'offset_test'),
- 'order' => array('offset_test' => 'DESC'),
- 'maxLimit' => 10,
- 'paramType' => 'named'
- );
- $result = $Controller->Paginator->paginate('PaginatorControllerPost');
- $this->assertEquals(array(4, 3, 2), Set::extract($result, '{n}.PaginatorControllerPost.offset_test'));
-
- $Controller->request->params['named'] = array('sort' => 'offset_test', 'direction' => 'asc');
- $result = $Controller->Paginator->paginate('PaginatorControllerPost');
- $this->assertEquals(array(2, 3, 4), Set::extract($result, '{n}.PaginatorControllerPost.offset_test'));
- }
-
-/**
- * test paginate() and virtualField on joined model
- *
- * @return void
- */
- public function testPaginateOrderVirtualFieldJoinedModel() {
- $Controller = new PaginatorTestController($this->request);
- $Controller->uses = array('PaginatorControllerPost');
- $Controller->params['url'] = array();
- $Controller->constructClasses();
- $Controller->PaginatorControllerPost->recursive = 0;
- $Controller->Paginator->settings = array(
- 'order' => array('PaginatorAuthor.joined_offset' => 'DESC'),
- 'maxLimit' => 10,
- 'paramType' => 'named'
- );
- $result = $Controller->Paginator->paginate('PaginatorControllerPost');
- $this->assertEquals(array(4, 2, 2), Set::extract($result, '{n}.PaginatorAuthor.joined_offset'));
-
- $Controller->request->params['named'] = array('sort' => 'PaginatorAuthor.joined_offset', 'direction' => 'asc');
- $result = $Controller->Paginator->paginate('PaginatorControllerPost');
- $this->assertEquals(array(2, 2, 4), Set::extract($result, '{n}.PaginatorAuthor.joined_offset'));
- }
-
-/**
- * Tests for missing models
- *
- * @expectedException MissingModelException
- */
- public function testPaginateMissingModel() {
- $Controller = new PaginatorTestController($this->request);
- $Controller->constructClasses();
- $Controller->Paginator->paginate('MissingModel');
- }
-
-/**
- * test that option merging prefers specific models
- *
- * @return void
- */
- public function testMergeOptionsModelSpecific() {
- $this->Paginator->settings = array(
- 'page' => 1,
- 'limit' => 20,
- 'maxLimit' => 100,
- 'paramType' => 'named',
- 'Post' => array(
- 'page' => 1,
- 'limit' => 10,
- 'maxLimit' => 50,
- 'paramType' => 'named',
- )
- );
- $result = $this->Paginator->mergeOptions('Silly');
- $this->assertEquals($this->Paginator->settings, $result);
-
- $result = $this->Paginator->mergeOptions('Post');
- $expected = array('page' => 1, 'limit' => 10, 'paramType' => 'named', 'maxLimit' => 50);
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test mergeOptions with named params.
- *
- * @return void
- */
- public function testMergeOptionsNamedParams() {
- $this->request->params['named'] = array(
- 'page' => 10,
- 'limit' => 10
- );
- $this->Paginator->settings = array(
- 'page' => 1,
- 'limit' => 20,
- 'maxLimit' => 100,
- 'paramType' => 'named',
- );
- $result = $this->Paginator->mergeOptions('Post');
- $expected = array('page' => 10, 'limit' => 10, 'maxLimit' => 100, 'paramType' => 'named');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test merging options from the querystring.
- *
- * @return void
- */
- public function testMergeOptionsQueryString() {
- $this->request->params['named'] = array(
- 'page' => 10,
- 'limit' => 10
- );
- $this->request->query = array(
- 'page' => 99,
- 'limit' => 75
- );
- $this->Paginator->settings = array(
- 'page' => 1,
- 'limit' => 20,
- 'maxLimit' => 100,
- 'paramType' => 'querystring',
- );
- $result = $this->Paginator->mergeOptions('Post');
- $expected = array('page' => 99, 'limit' => 75, 'maxLimit' => 100, 'paramType' => 'querystring');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test that the default whitelist doesn't let people screw with things they should not be allowed to.
- *
- * @return void
- */
- public function testMergeOptionsDefaultWhiteList() {
- $this->request->params['named'] = array(
- 'page' => 10,
- 'limit' => 10,
- 'fields' => array('bad.stuff'),
- 'recursive' => 1000,
- 'conditions' => array('bad.stuff'),
- 'contain' => array('bad')
- );
- $this->Paginator->settings = array(
- 'page' => 1,
- 'limit' => 20,
- 'maxLimit' => 100,
- 'paramType' => 'named',
- );
- $result = $this->Paginator->mergeOptions('Post');
- $expected = array('page' => 10, 'limit' => 10, 'maxLimit' => 100, 'paramType' => 'named');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test that modifying the whitelist works.
- *
- * @return void
- */
- public function testMergeOptionsExtraWhitelist() {
- $this->request->params['named'] = array(
- 'page' => 10,
- 'limit' => 10,
- 'fields' => array('bad.stuff'),
- 'recursive' => 1000,
- 'conditions' => array('bad.stuff'),
- 'contain' => array('bad')
- );
- $this->Paginator->settings = array(
- 'page' => 1,
- 'limit' => 20,
- 'maxLimit' => 100,
- 'paramType' => 'named',
- );
- $this->Paginator->whitelist[] = 'fields';
- $result = $this->Paginator->mergeOptions('Post');
- $expected = array(
- 'page' => 10, 'limit' => 10, 'maxLimit' => 100, 'paramType' => 'named', 'fields' => array('bad.stuff')
- );
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test that invalid directions are ignored.
- *
- * @return void
- */
- public function testValidateSortInvalidDirection() {
- $model = $this->getMock('Model');
- $model->alias = 'model';
- $model->expects($this->any())->method('hasField')->will($this->returnValue(true));
-
- $options = array('sort' => 'something', 'direction' => 'boogers');
- $result = $this->Paginator->validateSort($model, $options);
-
- $this->assertEquals('asc', $result['order']['model.something']);
- }
-
-/**
- * test that fields not in whitelist won't be part of order conditions.
- *
- * @return void
- */
- public function testValidateSortWhitelistFailure() {
- $model = $this->getMock('Model');
- $model->alias = 'model';
- $model->expects($this->any())->method('hasField')->will($this->returnValue(true));
-
- $options = array('sort' => 'body', 'direction' => 'asc');
- $result = $this->Paginator->validateSort($model, $options, array('title', 'id'));
-
- $this->assertNull($result['order']);
- }
-
-/**
- * test that virtual fields work.
- *
- * @return void
- */
- public function testValidateSortVirtualField() {
- $model = $this->getMock('Model');
- $model->alias = 'model';
-
- $model->expects($this->at(0))
- ->method('hasField')
- ->with('something')
- ->will($this->returnValue(false));
-
- $model->expects($this->at(1))
- ->method('hasField')
- ->with('something', true)
- ->will($this->returnValue(true));
-
- $options = array('sort' => 'something', 'direction' => 'desc');
- $result = $this->Paginator->validateSort($model, $options);
-
- $this->assertEquals('desc', $result['order']['something']);
- }
-
-/**
- * test that multiple sort works.
- *
- * @return void
- */
- public function testValidateSortMultiple() {
- $model = $this->getMock('Model');
- $model->alias = 'model';
- $model->expects($this->any())->method('hasField')->will($this->returnValue(true));
-
- $options = array('order' => array(
- 'author_id' => 'asc',
- 'title' => 'asc'
- ));
- $result = $this->Paginator->validateSort($model, $options);
- $expected = array(
- 'model.author_id' => 'asc',
- 'model.title' => 'asc'
- );
-
- $this->assertEquals($expected, $result['order']);
- }
-
-/**
- * Test that no sort doesn't trigger an error.
- *
- * @return void
- */
- public function testValidateSortNoSort() {
- $model = $this->getMock('Model');
- $model->alias = 'model';
- $model->expects($this->any())->method('hasField')->will($this->returnValue(true));
-
- $options = array('direction' => 'asc');
- $result = $this->Paginator->validateSort($model, $options, array('title', 'id'));
- $this->assertFalse(isset($result['order']));
-
- $options = array('order' => 'invalid desc');
- $result = $this->Paginator->validateSort($model, $options, array('title', 'id'));
-
- $this->assertEquals($options['order'], $result['order']);
- }
-
-/**
- * test that maxLimit is respected
- *
- * @return void
- */
- public function testCheckLimit() {
- $result = $this->Paginator->checkLimit(array('limit' => 1000000, 'maxLimit' => 100));
- $this->assertEquals(100, $result['limit']);
-
- $result = $this->Paginator->checkLimit(array('limit' => 'sheep!', 'maxLimit' => 100));
- $this->assertEquals(1, $result['limit']);
-
- $result = $this->Paginator->checkLimit(array('limit' => '-1', 'maxLimit' => 100));
- $this->assertEquals(1, $result['limit']);
-
- $result = $this->Paginator->checkLimit(array('limit' => null, 'maxLimit' => 100));
- $this->assertEquals(1, $result['limit']);
-
- $result = $this->Paginator->checkLimit(array('limit' => 0, 'maxLimit' => 100));
- $this->assertEquals(1, $result['limit']);
- }
-
-/**
- * testPaginateMaxLimit
- *
- * @return void
- */
- public function testPaginateMaxLimit() {
- $Controller = new Controller($this->request);
-
- $Controller->uses = array('PaginatorControllerPost', 'ControllerComment');
- $Controller->passedArgs[] = '1';
- $Controller->constructClasses();
-
- $Controller->request->params['named'] = array(
- 'contain' => array('ControllerComment'), 'limit' => '1000'
- );
- $result = $Controller->paginate('PaginatorControllerPost');
- $this->assertEquals(100, $Controller->params['paging']['PaginatorControllerPost']['options']['limit']);
-
- $Controller->request->params['named'] = array(
- 'contain' => array('ControllerComment'), 'limit' => '1000', 'maxLimit' => 1000
- );
- $result = $Controller->paginate('PaginatorControllerPost');
- $this->assertEquals(100, $Controller->params['paging']['PaginatorControllerPost']['options']['limit']);
-
- $Controller->request->params['named'] = array('contain' => array('ControllerComment'), 'limit' => '10');
- $result = $Controller->paginate('PaginatorControllerPost');
- $this->assertEquals(10, $Controller->params['paging']['PaginatorControllerPost']['options']['limit']);
-
- $Controller->request->params['named'] = array('contain' => array('ControllerComment'), 'limit' => '1000');
- $Controller->paginate = array('maxLimit' => 2000, 'paramType' => 'named');
- $result = $Controller->paginate('PaginatorControllerPost');
- $this->assertEquals(1000, $Controller->params['paging']['PaginatorControllerPost']['options']['limit']);
-
- $Controller->request->params['named'] = array('contain' => array('ControllerComment'), 'limit' => '5000');
- $result = $Controller->paginate('PaginatorControllerPost');
- $this->assertEquals(2000, $Controller->params['paging']['PaginatorControllerPost']['options']['limit']);
- }
-
-/**
- * test paginate() and virtualField overlapping with real fields.
- *
- * @return void
- */
- public function testPaginateOrderVirtualFieldSharedWithRealField() {
- $Controller = new Controller($this->request);
- $Controller->uses = array('PaginatorControllerPost', 'PaginatorControllerComment');
- $Controller->constructClasses();
- $Controller->PaginatorControllerComment->virtualFields = array(
- 'title' => 'PaginatorControllerComment.comment'
- );
- $Controller->PaginatorControllerComment->bindModel(array(
- 'belongsTo' => array(
- 'PaginatorControllerPost' => array(
- 'className' => 'PaginatorControllerPost',
- 'foreignKey' => 'article_id'
- )
- )
- ), false);
-
- $Controller->paginate = array(
- 'fields' => array('PaginatorControllerComment.id', 'title', 'PaginatorControllerPost.title'),
- );
- $Controller->passedArgs = array('sort' => 'PaginatorControllerPost.title', 'dir' => 'asc');
- $result = $Controller->paginate('PaginatorControllerComment');
- $this->assertEquals(array(1, 2, 3, 4, 5, 6), Set::extract($result, '{n}.PaginatorControllerComment.id'));
- }
-
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php
deleted file mode 100644
index 2dc35d44f9c..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php
+++ /dev/null
@@ -1,881 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Controller.Component
- * @since CakePHP(tm) v 1.2.0.5435
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-App::uses('Controller', 'Controller');
-App::uses('RequestHandlerComponent', 'Controller/Component');
-App::uses('CakeRequest', 'Network');
-App::uses('CakeResponse', 'Network');
-App::uses('Router', 'Routing');
-
-/**
- * RequestHandlerTestController class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class RequestHandlerTestController extends Controller {
-
-/**
- * uses property
- *
- * @var mixed null
- */
- public $uses = null;
-
-/**
- * test method for ajax redirection
- *
- * @return void
- */
- public function destination() {
- $this->viewPath = 'Posts';
- $this->render('index');
- }
-
-/**
- * test method for ajax redirection + parameter parsing
- *
- * @return void
- */
- public function param_method($one = null, $two = null) {
- echo "one: $one two: $two";
- $this->autoRender = false;
- }
-
-/**
- * test method for testing layout rendering when isAjax()
- *
- * @return void
- */
- public function ajax2_layout() {
- if ($this->autoLayout) {
- $this->layout = 'ajax2';
- }
- $this->destination();
- }
-
-}
-
-
-/**
- * RequestHandlerComponentTest class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class RequestHandlerComponentTest extends CakeTestCase {
-
-/**
- * Controller property
- *
- * @var RequestHandlerTestController
- */
- public $Controller;
-
-/**
- * RequestHandler property
- *
- * @var RequestHandlerComponent
- */
- public $RequestHandler;
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- $this->_server = $_SERVER;
- $this->_init();
- }
-
-/**
- * init method
- *
- * @return void
- */
- protected function _init() {
- $request = new CakeRequest('controller_posts/index');
- $response = new CakeResponse();
- $this->Controller = new RequestHandlerTestController($request, $response);
- $this->Controller->constructClasses();
- $this->RequestHandler = new RequestHandlerComponent($this->Controller->Components);
- $this->_extensions = Router::extensions();
- }
-
-/**
- * endTest method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- unset($this->RequestHandler, $this->Controller);
- if (!headers_sent()) {
- header('Content-type: text/html'); //reset content type.
- }
- $_SERVER = $this->_server;
- call_user_func_array('Router::parseExtensions', $this->_extensions);
- }
-
-/**
- * Test that the constructor sets the settings.
- *
- * @return void
- */
- public function testConstructorSettings() {
- $settings = array(
- 'ajaxLayout' => 'test_ajax'
- );
- $Collection = new ComponentCollection();
- $Collection->init($this->Controller);
- $RequestHandler = new RequestHandlerComponent($Collection, $settings);
- $this->assertEquals('test_ajax', $RequestHandler->ajaxLayout);
- }
-
-/**
- * testInitializeCallback method
- *
- * @return void
- */
- public function testInitializeCallback() {
- $this->assertNull($this->RequestHandler->ext);
- $this->Controller->request->params['ext'] = 'rss';
- $this->RequestHandler->initialize($this->Controller);
- $this->assertEquals('rss', $this->RequestHandler->ext);
- }
-
-/**
- * test that a mapped Accept-type header will set $this->ext correctly.
- *
- * @return void
- */
- public function testInitializeContentTypeSettingExt() {
- $this->assertNull($this->RequestHandler->ext);
-
- $_SERVER['HTTP_ACCEPT'] = 'application/json';
- Router::parseExtensions('json');
-
- $this->RequestHandler->initialize($this->Controller);
- $this->assertEquals('json', $this->RequestHandler->ext);
- }
-
-/**
- * Test that RequestHandler sets $this->ext when jQuery sends its wonky-ish headers.
- *
- * @return void
- */
- public function testInitializeContentTypeWithjQueryAccept() {
- $_SERVER['HTTP_ACCEPT'] = 'application/json, text/javascript, */*; q=0.01';
- $this->assertNull($this->RequestHandler->ext);
- Router::parseExtensions('json');
-
- $this->RequestHandler->initialize($this->Controller);
- $this->assertEquals('json', $this->RequestHandler->ext);
- }
-
-/**
- * Test that RequestHandler sets $this->ext when jQuery sends its wonky-ish headers
- * and the application is configured to handle multiple extensions
- *
- * @return void
- */
- public function testInitializeContentTypeWithjQueryAcceptAndMultiplesExtensions() {
- $_SERVER['HTTP_ACCEPT'] = 'application/json, text/javascript, */*; q=0.01';
- $this->assertNull($this->RequestHandler->ext);
- Router::parseExtensions('rss', 'json');
-
- $this->RequestHandler->initialize($this->Controller);
- $this->assertEquals('json', $this->RequestHandler->ext);
- }
-
-/**
- * Test that RequestHandler does not set $this->ext when multiple accepts are sent.
- *
- * @return void
- */
- public function testInitializeNoContentTypeWithSingleAccept() {
- $_SERVER['HTTP_ACCEPT'] = 'application/json, text/html, */*; q=0.01';
- $this->assertNull($this->RequestHandler->ext);
- Router::parseExtensions('json');
-
- $this->RequestHandler->initialize($this->Controller);
- $this->assertNull($this->RequestHandler->ext);
- }
-
-/**
- * Test that ext is not set with multiple accepted content types.
- *
- * @return void
- */
- public function testInitializeNoContentTypeWithMultipleAcceptedTypes() {
- $_SERVER['HTTP_ACCEPT'] = 'application/json, text/javascript, application/xml, */*; q=0.01';
- $this->assertNull($this->RequestHandler->ext);
- Router::parseExtensions('xml', 'json');
-
- $this->RequestHandler->initialize($this->Controller);
- $this->assertNull($this->RequestHandler->ext);
- }
-
-/**
- * Test that ext is not set with confusing android accepts headers.
- *
- * @return void
- */
- public function testInitializeAmbiguousAndroidAccepts() {
- $_SERVER['HTTP_ACCEPT'] = 'application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5';
- $this->assertNull($this->RequestHandler->ext);
- Router::parseExtensions('html', 'xml');
-
- $this->RequestHandler->initialize($this->Controller);
- $this->assertNull($this->RequestHandler->ext);
- }
-
-/**
- * Test that a type mismatch doesn't incorrectly set the ext
- *
- * @return void
- */
- public function testInitializeContentTypeAndExtensionMismatch() {
- $this->assertNull($this->RequestHandler->ext);
- $extensions = Router::extensions();
- Router::parseExtensions('xml');
-
- $this->Controller->request = $this->getMock('CakeRequest');
- $this->Controller->request->expects($this->any())
- ->method('accepts')
- ->will($this->returnValue(array('application/json')));
-
- $this->RequestHandler->initialize($this->Controller);
- $this->assertNull($this->RequestHandler->ext);
-
- call_user_func_array(array('Router', 'parseExtensions'), $extensions);
- }
-
-/**
- * testDisabling method
- *
- * @return void
- */
- public function testDisabling() {
- $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
- $this->_init();
- $this->RequestHandler->initialize($this->Controller);
- $this->Controller->beforeFilter();
- $this->RequestHandler->startup($this->Controller);
- $this->assertEquals(true, $this->Controller->params['isAjax']);
- }
-
-/**
- * testAutoResponseType method
- *
- * @return void
- */
- public function testAutoResponseType() {
- $this->Controller->ext = '.thtml';
- $this->Controller->request->params['ext'] = 'rss';
- $this->RequestHandler->initialize($this->Controller);
- $this->RequestHandler->startup($this->Controller);
- $this->assertEquals('.ctp', $this->Controller->ext);
- }
-
-/**
- * testAutoAjaxLayout method
- *
- * @return void
- */
- public function testAutoAjaxLayout() {
- $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
- $this->RequestHandler->startup($this->Controller);
- $this->assertEquals($this->Controller->layout, $this->RequestHandler->ajaxLayout);
-
- $this->_init();
- $this->Controller->request->params['ext'] = 'js';
- $this->RequestHandler->initialize($this->Controller);
- $this->RequestHandler->startup($this->Controller);
- $this->assertNotEquals('ajax', $this->Controller->layout);
-
- unset($_SERVER['HTTP_X_REQUESTED_WITH']);
- }
-
-/**
- * testStartupCallback method
- *
- * @return void
- */
- public function testStartupCallback() {
- $_SERVER['REQUEST_METHOD'] = 'PUT';
- $_SERVER['CONTENT_TYPE'] = 'application/xml';
- $this->Controller->request = $this->getMock('CakeRequest', array('_readInput'));
- $this->RequestHandler->startup($this->Controller);
- $this->assertTrue(is_array($this->Controller->data));
- $this->assertFalse(is_object($this->Controller->data));
- }
-
-/**
- * testStartupCallback with charset.
- *
- * @return void
- */
- public function testStartupCallbackCharset() {
- $_SERVER['REQUEST_METHOD'] = 'PUT';
- $_SERVER['CONTENT_TYPE'] = 'application/xml; charset=UTF-8';
- $this->Controller->request = $this->getMock('CakeRequest', array('_readInput'));
- $this->RequestHandler->startup($this->Controller);
- $this->assertTrue(is_array($this->Controller->data));
- $this->assertFalse(is_object($this->Controller->data));
- }
-
-/**
- * Test mapping a new type and having startup process it.
- *
- * @return void
- */
- public function testStartupCustomTypeProcess() {
- if (!function_exists('str_getcsv')) {
- $this->markTestSkipped('Need "str_getcsv" for this test.');
- }
- $_SERVER['REQUEST_METHOD'] = 'POST';
- $_SERVER['CONTENT_TYPE'] = 'text/csv';
- $this->Controller->request = $this->getMock('CakeRequest', array('_readInput'));
- $this->Controller->request->expects($this->once())
- ->method('_readInput')
- ->will($this->returnValue('"A","csv","string"'));
- $this->RequestHandler->addInputType('csv', array('str_getcsv'));
- $this->RequestHandler->startup($this->Controller);
- $expected = array(
- 'A', 'csv', 'string'
- );
- $this->assertEquals($expected, $this->Controller->request->data);
- }
-
-/**
- * testNonAjaxRedirect method
- *
- * @return void
- */
- public function testNonAjaxRedirect() {
- $this->RequestHandler->initialize($this->Controller);
- $this->RequestHandler->startup($this->Controller);
- $this->assertNull($this->RequestHandler->beforeRedirect($this->Controller, '/'));
- }
-
-/**
- * testRenderAs method
- *
- * @return void
- */
- public function testRenderAs() {
- $this->assertFalse(in_array('Rss', $this->Controller->helpers));
- $this->RequestHandler->renderAs($this->Controller, 'rss');
- $this->assertTrue(in_array('Rss', $this->Controller->helpers));
-
- $this->Controller->viewPath = 'request_handler_test\\rss';
- $this->RequestHandler->renderAs($this->Controller, 'js');
- $this->assertEquals('request_handler_test' . DS . 'js', $this->Controller->viewPath);
- }
-
-/**
- * test that attachment headers work with renderAs
- *
- * @return void
- */
- public function testRenderAsWithAttachment() {
- $this->RequestHandler->request = $this->getMock('CakeRequest');
- $this->RequestHandler->request->expects($this->any())
- ->method('parseAccept')
- ->will($this->returnValue(array('1.0' => array('application/xml'))));
-
- $this->RequestHandler->response = $this->getMock('CakeResponse', array('type', 'download', 'charset'));
- $this->RequestHandler->response->expects($this->at(0))
- ->method('type')
- ->with('application/xml');
- $this->RequestHandler->response->expects($this->at(1))
- ->method('charset')
- ->with('UTF-8');
- $this->RequestHandler->response->expects($this->at(2))
- ->method('download')
- ->with('myfile.xml');
-
- $this->RequestHandler->renderAs($this->Controller, 'xml', array('attachment' => 'myfile.xml'));
-
- $this->assertEquals('Xml', $this->Controller->viewClass);
- }
-
-/**
- * test that respondAs works as expected.
- *
- * @return void
- */
- public function testRespondAs() {
- $this->RequestHandler->response = $this->getMock('CakeResponse', array('type'));
- $this->RequestHandler->response->expects($this->at(0))->method('type')
- ->with('application/json');
- $this->RequestHandler->response->expects($this->at(1))->method('type')
- ->with('text/xml');
-
- $result = $this->RequestHandler->respondAs('json');
- $this->assertTrue($result);
- $result = $this->RequestHandler->respondAs('text/xml');
- $this->assertTrue($result);
- }
-
-/**
- * test that attachment headers work with respondAs
- *
- * @return void
- */
- public function testRespondAsWithAttachment() {
- $this->RequestHandler = $this->getMock(
- 'RequestHandlerComponent',
- array('_header'),
- array(&$this->Controller->Components)
- );
- $this->RequestHandler->response = $this->getMock('CakeResponse', array('type', 'download'));
- $this->RequestHandler->request = $this->getMock('CakeRequest');
-
- $this->RequestHandler->request->expects($this->once())
- ->method('parseAccept')
- ->will($this->returnValue(array('1.0' => array('application/xml'))));
-
- $this->RequestHandler->response->expects($this->once())->method('download')
- ->with('myfile.xml');
- $this->RequestHandler->response->expects($this->once())->method('type')
- ->with('application/xml');
-
- $result = $this->RequestHandler->respondAs('xml', array('attachment' => 'myfile.xml'));
- $this->assertTrue($result);
- }
-
-/**
- * test that calling renderAs() more than once continues to work.
- *
- * @link #6466
- * @return void
- */
- public function testRenderAsCalledTwice() {
- $this->RequestHandler->renderAs($this->Controller, 'print');
- $this->assertEquals('RequestHandlerTest' . DS . 'print', $this->Controller->viewPath);
- $this->assertEquals('print', $this->Controller->layoutPath);
-
- $this->RequestHandler->renderAs($this->Controller, 'js');
- $this->assertEquals('RequestHandlerTest' . DS . 'js', $this->Controller->viewPath);
- $this->assertEquals('js', $this->Controller->layoutPath);
- $this->assertTrue(in_array('Js', $this->Controller->helpers));
- }
-
-/**
- * testRequestClientTypes method
- *
- * @return void
- */
- public function testRequestClientTypes() {
- $_SERVER['HTTP_X_PROTOTYPE_VERSION'] = '1.5';
- $this->assertEquals('1.5', $this->RequestHandler->getAjaxVersion());
-
- unset($_SERVER['HTTP_X_REQUESTED_WITH'], $_SERVER['HTTP_X_PROTOTYPE_VERSION']);
- $this->assertFalse($this->RequestHandler->getAjaxVersion());
- }
-
-/**
- * Tests the detection of various Flash versions
- *
- * @return void
- */
- public function testFlashDetection() {
- $request = $this->getMock('CakeRequest');
- $request->expects($this->once())->method('is')
- ->with('flash')
- ->will($this->returnValue(true));
-
- $this->RequestHandler->request = $request;
- $this->assertTrue($this->RequestHandler->isFlash());
- }
-
-/**
- * testRequestContentTypes method
- *
- * @return void
- */
- public function testRequestContentTypes() {
- $_SERVER['REQUEST_METHOD'] = 'GET';
- $this->assertNull($this->RequestHandler->requestedWith());
-
- $_SERVER['REQUEST_METHOD'] = 'POST';
- $_SERVER['CONTENT_TYPE'] = 'application/json';
- $this->assertEquals('json', $this->RequestHandler->requestedWith());
-
- $result = $this->RequestHandler->requestedWith(array('json', 'xml'));
- $this->assertEquals('json', $result);
-
- $result = $this->RequestHandler->requestedWith(array('rss', 'atom'));
- $this->assertFalse($result);
-
- $_SERVER['HTTP_ACCEPT'] = 'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*';
- $this->assertTrue($this->RequestHandler->isXml());
- $this->assertFalse($this->RequestHandler->isAtom());
- $this->assertFalse($this->RequestHandler->isRSS());
-
- $_SERVER['HTTP_ACCEPT'] = 'application/atom+xml,text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*';
- $this->assertTrue($this->RequestHandler->isAtom());
- $this->assertFalse($this->RequestHandler->isRSS());
-
- $_SERVER['HTTP_ACCEPT'] = 'application/rss+xml,text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*';
- $this->assertFalse($this->RequestHandler->isAtom());
- $this->assertTrue($this->RequestHandler->isRSS());
-
- $this->assertFalse($this->RequestHandler->isWap());
- $_SERVER['HTTP_ACCEPT'] = 'text/vnd.wap.wml,text/html,text/plain,image/png,*/*';
- $this->assertTrue($this->RequestHandler->isWap());
-
- $_SERVER['HTTP_ACCEPT'] = 'application/rss+xml,text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*';
- }
-
-/**
- * testResponseContentType method
- *
- * @return void
- */
- public function testResponseContentType() {
- $this->assertEquals('html', $this->RequestHandler->responseType());
- $this->assertTrue($this->RequestHandler->respondAs('atom'));
- $this->assertEquals('atom', $this->RequestHandler->responseType());
- }
-
-/**
- * testMobileDeviceDetection method
- *
- * @return void
- */
- public function testMobileDeviceDetection() {
- $request = $this->getMock('CakeRequest');
- $request->expects($this->once())->method('is')
- ->with('mobile')
- ->will($this->returnValue(true));
-
- $this->RequestHandler->request = $request;
- $this->assertTrue($this->RequestHandler->isMobile());
- }
-
-/**
- * testRequestProperties method
- *
- * @return void
- */
- public function testRequestProperties() {
- $request = $this->getMock('CakeRequest');
- $request->expects($this->once())->method('is')
- ->with('ssl')
- ->will($this->returnValue(true));
-
- $this->RequestHandler->request = $request;
- $this->assertTrue($this->RequestHandler->isSsl());
- }
-
-/**
- * testRequestMethod method
- *
- * @return void
- */
- public function testRequestMethod() {
- $request = $this->getMock('CakeRequest');
- $request->expects($this->at(0))->method('is')
- ->with('get')
- ->will($this->returnValue(true));
-
- $request->expects($this->at(1))->method('is')
- ->with('post')
- ->will($this->returnValue(false));
-
- $request->expects($this->at(2))->method('is')
- ->with('delete')
- ->will($this->returnValue(true));
-
- $request->expects($this->at(3))->method('is')
- ->with('put')
- ->will($this->returnValue(false));
-
- $this->RequestHandler->request = $request;
- $this->assertTrue($this->RequestHandler->isGet());
- $this->assertFalse($this->RequestHandler->isPost());
- $this->assertTrue($this->RequestHandler->isDelete());
- $this->assertFalse($this->RequestHandler->isPut());
- }
-
-/**
- * test that map alias converts aliases to content types.
- *
- * @return void
- */
- public function testMapAlias() {
- $result = $this->RequestHandler->mapAlias('xml');
- $this->assertEquals('application/xml', $result);
-
- $result = $this->RequestHandler->mapAlias('text/html');
- $this->assertNull($result);
-
- $result = $this->RequestHandler->mapAlias('wap');
- $this->assertEquals('text/vnd.wap.wml', $result);
-
- $result = $this->RequestHandler->mapAlias(array('xml', 'js', 'json'));
- $expected = array('application/xml', 'text/javascript', 'application/json');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test accepts() on the component
- *
- * @return void
- */
- public function testAccepts() {
- $_SERVER['HTTP_ACCEPT'] = 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5';
- $this->assertTrue($this->RequestHandler->accepts(array('js', 'xml', 'html')));
- $this->assertFalse($this->RequestHandler->accepts(array('gif', 'jpeg', 'foo')));
-
- $_SERVER['HTTP_ACCEPT'] = '*/*;q=0.5';
- $this->assertFalse($this->RequestHandler->accepts('rss'));
- }
-
-/**
- * test accepts and prefers methods.
- *
- * @return void
- */
- public function testPrefers() {
- $_SERVER['HTTP_ACCEPT'] = 'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*';
- $this->assertNotEquals('rss', $this->RequestHandler->prefers());
- $this->RequestHandler->ext = 'rss';
- $this->assertEquals('rss', $this->RequestHandler->prefers());
- $this->assertFalse($this->RequestHandler->prefers('xml'));
- $this->assertEquals('xml', $this->RequestHandler->prefers(array('js', 'xml', 'xhtml')));
- $this->assertFalse($this->RequestHandler->prefers(array('red', 'blue')));
- $this->assertEquals('xhtml', $this->RequestHandler->prefers(array('js', 'json', 'xhtml')));
- $this->assertTrue($this->RequestHandler->prefers(array('rss')), 'Should return true if input matches ext.');
- $this->assertFalse($this->RequestHandler->prefers(array('html')), 'No match with ext, return false.');
-
- $_SERVER['HTTP_ACCEPT'] = 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5';
- $this->_init();
- $this->assertEquals('xml', $this->RequestHandler->prefers());
-
- $_SERVER['HTTP_ACCEPT'] = '*/*;q=0.5';
- $this->assertEquals('html', $this->RequestHandler->prefers());
- $this->assertFalse($this->RequestHandler->prefers('rss'));
- }
-
-/**
- * testCustomContent method
- *
- * @return void
- */
- public function testCustomContent() {
- $_SERVER['HTTP_ACCEPT'] = 'text/x-mobile,text/html;q=0.9,text/plain;q=0.8,*/*;q=0.5';
- $this->RequestHandler->setContent('mobile', 'text/x-mobile');
- $this->RequestHandler->startup($this->Controller);
- $this->assertEquals('mobile', $this->RequestHandler->prefers());
- }
-
-/**
- * testClientProperties method
- *
- * @return void
- */
- public function testClientProperties() {
- $request = $this->getMock('CakeRequest');
- $request->expects($this->once())->method('referer');
- $request->expects($this->once())->method('clientIp')->will($this->returnValue(false));
-
- $this->RequestHandler->request = $request;
-
- $this->RequestHandler->getReferer();
- $this->RequestHandler->getClientIP(false);
- }
-
-/**
- * test that ajax requests involving redirects trigger requestAction instead.
- *
- * @return void
- */
- public function testAjaxRedirectAsRequestAction() {
- App::build(array(
- 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
- ), App::RESET);
-
- $this->Controller->RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
- $this->Controller->request = $this->getMock('CakeRequest');
- $this->Controller->response = $this->getMock('CakeResponse', array('_sendHeader'));
- $this->Controller->RequestHandler->request = $this->Controller->request;
- $this->Controller->RequestHandler->response = $this->Controller->response;
- $this->Controller->request->expects($this->any())->method('is')->will($this->returnValue(true));
- $this->Controller->RequestHandler->expects($this->once())->method('_stop');
-
- ob_start();
- $this->Controller->RequestHandler->beforeRedirect(
- $this->Controller, array('controller' => 'request_handler_test', 'action' => 'destination')
- );
- $result = ob_get_clean();
- $this->assertRegExp('/posts index/', $result, 'RequestAction redirect failed.');
-
- App::build();
- }
-
-/**
- * test that ajax requests involving redirects don't force no layout
- * this would cause the ajax layout to not be rendered.
- *
- * @return void
- */
- public function testAjaxRedirectAsRequestActionStillRenderingLayout() {
- App::build(array(
- 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
- ), App::RESET);
-
- $this->Controller->RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
- $this->Controller->request = $this->getMock('CakeRequest');
- $this->Controller->response = $this->getMock('CakeResponse', array('_sendHeader'));
- $this->Controller->RequestHandler->request = $this->Controller->request;
- $this->Controller->RequestHandler->response = $this->Controller->response;
- $this->Controller->request->expects($this->any())->method('is')->will($this->returnValue(true));
- $this->Controller->RequestHandler->expects($this->once())->method('_stop');
-
- ob_start();
- $this->Controller->RequestHandler->beforeRedirect(
- $this->Controller, array('controller' => 'request_handler_test', 'action' => 'ajax2_layout')
- );
- $result = ob_get_clean();
- $this->assertRegExp('/posts index/', $result, 'RequestAction redirect failed.');
- $this->assertRegExp('/Ajax!/', $result, 'Layout was not rendered.');
-
- App::build();
- }
-
-/**
- * test that the beforeRedirect callback properly converts
- * array urls into their correct string ones, and adds base => false so
- * the correct urls are generated.
- *
- * @link http://cakephp.lighthouseapp.com/projects/42648-cakephp-1x/tickets/276
- * @return void
- */
- public function testBeforeRedirectCallbackWithArrayUrl() {
- $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
-
- Router::setRequestInfo(array(
- array('plugin' => null, 'controller' => 'accounts', 'action' => 'index', 'pass' => array(), 'named' => array(), 'form' => array(), 'url' => array('url' => 'accounts/')),
- array('base' => '/officespace', 'here' => '/officespace/accounts/', 'webroot' => '/officespace/')
- ));
-
- $RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
- $RequestHandler->response = $this->getMock('CakeResponse', array('_sendHeader'));
- $RequestHandler->request = new CakeRequest('posts/index');
- $RequestHandler->response = $this->getMock('CakeResponse', array('_sendHeader'));
-
- ob_start();
- $RequestHandler->beforeRedirect(
- $this->Controller,
- array('controller' => 'request_handler_test', 'action' => 'param_method', 'first', 'second')
- );
- $result = ob_get_clean();
- $this->assertEquals('one: first two: second', $result);
- }
-
-/**
- * assure that beforeRedirect with a status code will correctly set the status header
- *
- * @return void
- */
- public function testBeforeRedirectCallingHeader() {
- $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
-
- $controller = $this->getMock('Controller', array('header'));
- $RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
- $RequestHandler->response = $this->getMock('CakeResponse', array('_sendHeader','statusCode'));
- $RequestHandler->request = $this->getMock('CakeRequest');
- $RequestHandler->request->expects($this->once())->method('is')
- ->with('ajax')
- ->will($this->returnValue(true));
-
- $RequestHandler->response->expects($this->once())->method('statusCode')->with(403);
-
- ob_start();
- $RequestHandler->beforeRedirect($controller, 'request_handler_test/param_method/first/second', 403);
- $result = ob_get_clean();
- }
-
-/**
- * @expectedException CakeException
- * @return void
- */
- public function testAddInputTypeException() {
- $this->RequestHandler->addInputType('csv', array('I am not callable'));
- }
-
-/**
- * Test checkNotModified method
- *
- * @return void
- **/
- public function testCheckNotModifiedByEtagStar() {
- $_SERVER['HTTP_IF_NONE_MATCH'] = '*';
- $RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
- $RequestHandler->response = $this->getMock('CakeResponse', array('notModified'));
- $RequestHandler->response->etag('something');
- $RequestHandler->response->expects($this->once())->method('notModified');
- $this->assertFalse($RequestHandler->beforeRender($this->Controller));
- }
-
-/**
- * Test checkNotModified method
- *
- * @return void
- **/
- public function testCheckNotModifiedByEtagExact() {
- $_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something", "other"';
- $RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
- $RequestHandler->response = $this->getMock('CakeResponse', array('notModified'));
- $RequestHandler->response->etag('something', true);
- $RequestHandler->response->expects($this->once())->method('notModified');
- $this->assertFalse($RequestHandler->beforeRender($this->Controller));
- }
-
-/**
- * Test checkNotModified method
- *
- * @return void
- **/
- public function testCheckNotModifiedByEtagAndTime() {
- $_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something", "other"';
- $_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
- $RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
- $RequestHandler->response = $this->getMock('CakeResponse', array('notModified'));
- $RequestHandler->response->etag('something', true);
- $RequestHandler->response->modified('2012-01-01 00:00:00');
- $RequestHandler->response->expects($this->once())->method('notModified');
- $this->assertFalse($RequestHandler->beforeRender($this->Controller));
- }
-
-/**
- * Test checkNotModified method
- *
- * @return void
- **/
- public function testCheckNotModifiedNoInfo() {
- $RequestHandler = $this->getMock('RequestHandlerComponent', array('_stop'), array(&$this->Controller->Components));
- $RequestHandler->response = $this->getMock('CakeResponse', array('notModified'));
- $RequestHandler->response->expects($this->never())->method('notModified');
- $this->assertNull($RequestHandler->beforeRender($this->Controller));
- }
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php b/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php
deleted file mode 100644
index c97626df5fb..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php
+++ /dev/null
@@ -1,1342 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Controller.Component
- * @since CakePHP(tm) v 1.2.0.5435
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('SecurityComponent', 'Controller/Component');
-App::uses('Controller', 'Controller');
-
-/**
- * TestSecurityComponent
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class TestSecurityComponent extends SecurityComponent {
-
-/**
- * validatePost method
- *
- * @param Controller $controller
- * @return boolean
- */
- public function validatePost(Controller $controller) {
- return $this->_validatePost($controller);
- }
-
-}
-
-/**
- * SecurityTestController
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class SecurityTestController extends Controller {
-
-/**
- * name property
- *
- * @var string 'SecurityTest'
- */
- public $name = 'SecurityTest';
-
-/**
- * components property
- *
- * @var array
- */
- public $components = array('Session', 'TestSecurity');
-
-/**
- * failed property
- *
- * @var boolean false
- */
- public $failed = false;
-
-/**
- * Used for keeping track of headers in test
- *
- * @var array
- */
- public $testHeaders = array();
-
-/**
- * fail method
- *
- * @return void
- */
- public function fail() {
- $this->failed = true;
- }
-
-/**
- * redirect method
- *
- * @param mixed $option
- * @param mixed $code
- * @param mixed $exit
- * @return void
- */
- public function redirect($url, $status = null, $exit = true) {
- return $status;
- }
-
-/**
- * Convenience method for header()
- *
- * @param string $status
- * @return void
- */
- public function header($status) {
- $this->testHeaders[] = $status;
- }
-
-}
-
-/**
- * SecurityComponentTest class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class SecurityComponentTest extends CakeTestCase {
-
-/**
- * Controller property
- *
- * @var SecurityTestController
- */
- public $Controller;
-
-/**
- * oldSalt property
- *
- * @var string
- */
- public $oldSalt;
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
-
- $request = new CakeRequest('posts/index', false);
- $request->addParams(array('controller' => 'posts', 'action' => 'index'));
- $this->Controller = new SecurityTestController($request);
- $this->Controller->Components->init($this->Controller);
- $this->Controller->Security = $this->Controller->TestSecurity;
- $this->Controller->Security->blackHoleCallback = 'fail';
- $this->Security = $this->Controller->Security;
- $this->Security->csrfCheck = false;
-
- Configure::write('Security.salt', 'foo!');
- }
-
-/**
- * Tear-down method. Resets environment state.
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- $this->Controller->Session->delete('_Token');
- unset($this->Controller->Security);
- unset($this->Controller->Component);
- unset($this->Controller);
- }
-
-/**
- * test that initialize can set properties.
- *
- * @return void
- */
- public function testConstructorSettingProperties() {
- $settings = array(
- 'requirePost' => array('edit', 'update'),
- 'requireSecure' => array('update_account'),
- 'requireGet' => array('index'),
- 'validatePost' => false,
- );
- $Security = new SecurityComponent($this->Controller->Components, $settings);
- $this->Controller->Security->initialize($this->Controller, $settings);
- $this->assertEquals($Security->requirePost, $settings['requirePost']);
- $this->assertEquals($Security->requireSecure, $settings['requireSecure']);
- $this->assertEquals($Security->requireGet, $settings['requireGet']);
- $this->assertEquals($Security->validatePost, $settings['validatePost']);
- }
-
-/**
- * testStartup method
- *
- * @return void
- */
- public function testStartup() {
- $this->Controller->Security->startup($this->Controller);
- $result = $this->Controller->params['_Token']['key'];
- $this->assertNotNull($result);
- $this->assertTrue($this->Controller->Session->check('_Token'));
- }
-
-/**
- * testRequirePostFail method
- *
- * @return void
- */
- public function testRequirePostFail() {
- $_SERVER['REQUEST_METHOD'] = 'GET';
- $this->Controller->request['action'] = 'posted';
- $this->Controller->Security->requirePost(array('posted'));
- $this->Controller->Security->startup($this->Controller);
- $this->assertTrue($this->Controller->failed);
- }
-
-/**
- * testRequirePostSucceed method
- *
- * @return void
- */
- public function testRequirePostSucceed() {
- $_SERVER['REQUEST_METHOD'] = 'POST';
- $this->Controller->request['action'] = 'posted';
- $this->Controller->Security->requirePost('posted');
- $this->Security->startup($this->Controller);
- $this->assertFalse($this->Controller->failed);
- }
-
-/**
- * testRequireSecureFail method
- *
- * @return void
- */
- public function testRequireSecureFail() {
- $_SERVER['HTTPS'] = 'off';
- $_SERVER['REQUEST_METHOD'] = 'POST';
- $this->Controller->request['action'] = 'posted';
- $this->Controller->Security->requireSecure(array('posted'));
- $this->Controller->Security->startup($this->Controller);
- $this->assertTrue($this->Controller->failed);
- }
-
-/**
- * testRequireSecureSucceed method
- *
- * @return void
- */
- public function testRequireSecureSucceed() {
- $_SERVER['REQUEST_METHOD'] = 'Secure';
- $this->Controller->request['action'] = 'posted';
- $_SERVER['HTTPS'] = 'on';
- $this->Controller->Security->requireSecure('posted');
- $this->Controller->Security->startup($this->Controller);
- $this->assertFalse($this->Controller->failed);
- }
-
-/**
- * testRequireAuthFail method
- *
- * @return void
- */
- public function testRequireAuthFail() {
- $_SERVER['REQUEST_METHOD'] = 'AUTH';
- $this->Controller->request['action'] = 'posted';
- $this->Controller->request->data = array('username' => 'willy', 'password' => 'somePass');
- $this->Controller->Security->requireAuth(array('posted'));
- $this->Controller->Security->startup($this->Controller);
- $this->assertTrue($this->Controller->failed);
-
- $this->Controller->Session->write('_Token', array('allowedControllers' => array()));
- $this->Controller->request->data = array('username' => 'willy', 'password' => 'somePass');
- $this->Controller->request['action'] = 'posted';
- $this->Controller->Security->requireAuth('posted');
- $this->Controller->Security->startup($this->Controller);
- $this->assertTrue($this->Controller->failed);
-
- $this->Controller->Session->write('_Token', array(
- 'allowedControllers' => array('SecurityTest'), 'allowedActions' => array('posted2')
- ));
- $this->Controller->request->data = array('username' => 'willy', 'password' => 'somePass');
- $this->Controller->request['action'] = 'posted';
- $this->Controller->Security->requireAuth('posted');
- $this->Controller->Security->startup($this->Controller);
- $this->assertTrue($this->Controller->failed);
- }
-
-/**
- * testRequireAuthSucceed method
- *
- * @return void
- */
- public function testRequireAuthSucceed() {
- $_SERVER['REQUEST_METHOD'] = 'AUTH';
- $this->Controller->request['action'] = 'posted';
- $this->Controller->Security->requireAuth('posted');
- $this->Controller->Security->startup($this->Controller);
- $this->assertFalse($this->Controller->failed);
-
- $this->Controller->Security->Session->write('_Token', array(
- 'allowedControllers' => array('SecurityTest'), 'allowedActions' => array('posted')
- ));
- $this->Controller->request['controller'] = 'SecurityTest';
- $this->Controller->request['action'] = 'posted';
-
- $this->Controller->request->data = array(
- 'username' => 'willy', 'password' => 'somePass', '_Token' => ''
- );
- $this->Controller->action = 'posted';
- $this->Controller->Security->requireAuth('posted');
- $this->Controller->Security->startup($this->Controller);
- $this->assertFalse($this->Controller->failed);
- }
-
-/**
- * testRequirePostSucceedWrongMethod method
- *
- * @return void
- */
- public function testRequirePostSucceedWrongMethod() {
- $_SERVER['REQUEST_METHOD'] = 'GET';
- $this->Controller->request['action'] = 'getted';
- $this->Controller->Security->requirePost('posted');
- $this->Controller->Security->startup($this->Controller);
- $this->assertFalse($this->Controller->failed);
- }
-
-/**
- * testRequireGetFail method
- *
- * @return void
- */
- public function testRequireGetFail() {
- $_SERVER['REQUEST_METHOD'] = 'POST';
- $this->Controller->request['action'] = 'getted';
- $this->Controller->Security->requireGet(array('getted'));
- $this->Controller->Security->startup($this->Controller);
- $this->assertTrue($this->Controller->failed);
- }
-
-/**
- * testRequireGetSucceed method
- *
- * @return void
- */
- public function testRequireGetSucceed() {
- $_SERVER['REQUEST_METHOD'] = 'GET';
- $this->Controller->request['action'] = 'getted';
- $this->Controller->Security->requireGet('getted');
- $this->Controller->Security->startup($this->Controller);
- $this->assertFalse($this->Controller->failed);
- }
-
-/**
- * testRequireGetSucceedWrongMethod method
- *
- * @return void
- */
- public function testRequireGetSucceedWrongMethod() {
- $_SERVER['REQUEST_METHOD'] = 'POST';
- $this->Controller->request['action'] = 'posted';
- $this->Security->requireGet('getted');
- $this->Security->startup($this->Controller);
- $this->assertFalse($this->Controller->failed);
- }
-
-/**
- * testRequirePutFail method
- *
- * @return void
- */
- public function testRequirePutFail() {
- $_SERVER['REQUEST_METHOD'] = 'POST';
- $this->Controller->request['action'] = 'putted';
- $this->Controller->Security->requirePut(array('putted'));
- $this->Controller->Security->startup($this->Controller);
- $this->assertTrue($this->Controller->failed);
- }
-
-/**
- * testRequirePutSucceed method
- *
- * @return void
- */
- public function testRequirePutSucceed() {
- $_SERVER['REQUEST_METHOD'] = 'PUT';
- $this->Controller->request['action'] = 'putted';
- $this->Controller->Security->requirePut('putted');
- $this->Controller->Security->startup($this->Controller);
- $this->assertFalse($this->Controller->failed);
- }
-
-/**
- * testRequirePutSucceedWrongMethod method
- *
- * @return void
- */
- public function testRequirePutSucceedWrongMethod() {
- $_SERVER['REQUEST_METHOD'] = 'POST';
- $this->Controller->request['action'] = 'posted';
- $this->Controller->Security->requirePut('putted');
- $this->Controller->Security->startup($this->Controller);
- $this->assertFalse($this->Controller->failed);
- }
-
-/**
- * testRequireDeleteFail method
- *
- * @return void
- */
- public function testRequireDeleteFail() {
- $_SERVER['REQUEST_METHOD'] = 'POST';
- $this->Controller->request['action'] = 'deleted';
- $this->Controller->Security->requireDelete(array('deleted', 'other_method'));
- $this->Controller->Security->startup($this->Controller);
- $this->assertTrue($this->Controller->failed);
- }
-
-/**
- * testRequireDeleteSucceed method
- *
- * @return void
- */
- public function testRequireDeleteSucceed() {
- $_SERVER['REQUEST_METHOD'] = 'DELETE';
- $this->Controller->request['action'] = 'deleted';
- $this->Controller->Security->requireDelete('deleted');
- $this->Controller->Security->startup($this->Controller);
- $this->assertFalse($this->Controller->failed);
- }
-
-/**
- * testRequireDeleteSucceedWrongMethod method
- *
- * @return void
- */
- public function testRequireDeleteSucceedWrongMethod() {
- $_SERVER['REQUEST_METHOD'] = 'POST';
- $this->Controller->request['action'] = 'posted';
- $this->Controller->Security->requireDelete('deleted');
- $this->Controller->Security->startup($this->Controller);
- $this->assertFalse($this->Controller->failed);
- }
-
-/**
- * Simple hash validation test
- *
- * @return void
- */
- public function testValidatePost() {
- $this->Controller->Security->startup($this->Controller);
-
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';
- $unlocked = '';
-
- $this->Controller->request->data = array(
- 'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
- $this->assertTrue($this->Controller->Security->validatePost($this->Controller));
- }
-
-/**
- * Test that validatePost fails if you are missing the session information.
- *
- * @return void
- */
- public function testValidatePostNoSession() {
- $this->Controller->Security->startup($this->Controller);
- $this->Controller->Session->delete('_Token');
-
- $key = $this->Controller->params['_Token']['key'];
- $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';
-
- $this->Controller->data = array(
- 'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),
- '_Token' => compact('key', 'fields')
- );
- $this->assertFalse($this->Controller->Security->validatePost($this->Controller));
- }
-
-/**
- * test that validatePost fails if any of its required fields are missing.
- *
- * @return void
- */
- public function testValidatePostFormHacking() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->params['_Token']['key'];
- $unlocked = '';
-
- $this->Controller->request->data = array(
- 'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),
- '_Token' => compact('key', 'unlocked')
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertFalse($result, 'validatePost passed when fields were missing. %s');
- }
-
-/**
- * Test that objects can't be passed into the serialized string. This was a vector for RFI and LFI
- * attacks. Thanks to Felix Wilhelm
- *
- * @return void
- */
- public function testValidatePostObjectDeserialize() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877';
- $unlocked = '';
-
- // a corrupted serialized object, so we can see if it ever gets to deserialize
- $attack = 'O:3:"App":1:{s:5:"__map";a:1:{s:3:"foo";s:7:"Hacked!";s:1:"fail"}}';
- $fields .= urlencode(':' . str_rot13($attack));
-
- $this->Controller->request->data = array(
- 'Model' => array('username' => 'mark', 'password' => 'foo', 'valid' => '0'),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertFalse($result, 'validatePost passed when key was missing. %s');
- }
-
-/**
- * Tests validation of checkbox arrays
- *
- * @return void
- */
- public function testValidatePostArray() {
- $this->Controller->Security->startup($this->Controller);
-
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = 'f7d573650a295b94e0938d32b323fde775e5f32b%3A';
- $unlocked = '';
-
- $this->Controller->request->data = array(
- 'Model' => array('multi_field' => array('1', '3')),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
- $this->assertTrue($this->Controller->Security->validatePost($this->Controller));
- }
-
-/**
- * testValidatePostNoModel method
- *
- * @return void
- */
- public function testValidatePostNoModel() {
- $this->Controller->Security->startup($this->Controller);
-
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = '540ac9c60d323c22bafe997b72c0790f39a8bdef%3A';
- $unlocked = '';
-
- $this->Controller->request->data = array(
- 'anything' => 'some_data',
- '_Token' => compact('key', 'fields', 'unlocked')
- );
-
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
- }
-
-/**
- * testValidatePostSimple method
- *
- * @return void
- */
- public function testValidatePostSimple() {
- $this->Controller->Security->startup($this->Controller);
-
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = '69f493434187b867ea14b901fdf58b55d27c935d%3A';
- $unlocked = '';
-
- $this->Controller->request->data = $data = array(
- 'Model' => array('username' => '', 'password' => ''),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
-
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
- }
-
-/**
- * Tests hash validation for multiple records, including locked fields
- *
- * @return void
- */
- public function testValidatePostComplex() {
- $this->Controller->Security->startup($this->Controller);
-
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = 'c9118120e680a7201b543f562e5301006ccfcbe2%3AAddresses.0.id%7CAddresses.1.id';
- $unlocked = '';
-
- $this->Controller->request->data = array(
- 'Addresses' => array(
- '0' => array(
- 'id' => '123456', 'title' => '', 'first_name' => '', 'last_name' => '',
- 'address' => '', 'city' => '', 'phone' => '', 'primary' => ''
- ),
- '1' => array(
- 'id' => '654321', 'title' => '', 'first_name' => '', 'last_name' => '',
- 'address' => '', 'city' => '', 'phone' => '', 'primary' => ''
- )
- ),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
- }
-
-/**
- * test ValidatePost with multiple select elements.
- *
- * @return void
- */
- public function testValidatePostMultipleSelect() {
- $this->Controller->Security->startup($this->Controller);
-
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = '422cde416475abc171568be690a98cad20e66079%3A';
- $unlocked = '';
-
- $this->Controller->request->data = array(
- 'Tag' => array('Tag' => array(1, 2)),
- '_Token' => compact('key', 'fields', 'unlocked'),
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
-
- $this->Controller->request->data = array(
- 'Tag' => array('Tag' => array(1, 2, 3)),
- '_Token' => compact('key', 'fields', 'unlocked'),
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
-
- $this->Controller->request->data = array(
- 'Tag' => array('Tag' => array(1, 2, 3, 4)),
- '_Token' => compact('key', 'fields', 'unlocked'),
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
-
- $fields = '19464422eafe977ee729c59222af07f983010c5f%3A';
- $this->Controller->request->data = array(
- 'User.password' => 'bar', 'User.name' => 'foo', 'User.is_valid' => '1',
- 'Tag' => array('Tag' => array(1)),
- '_Token' => compact('key', 'fields', 'unlocked'),
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
- }
-
-/**
- * testValidatePostCheckbox method
- *
- * First block tests un-checked checkbox
- * Second block tests checked checkbox
- *
- * @return void
- */
- public function testValidatePostCheckbox() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';
- $unlocked = '';
-
- $this->Controller->request->data = array(
- 'Model' => array('username' => '', 'password' => '', 'valid' => '0'),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
-
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
-
- $fields = '874439ca69f89b4c4a5f50fb9c36ff56a28f5d42%3A';
-
- $this->Controller->request->data = array(
- 'Model' => array('username' => '', 'password' => '', 'valid' => '0'),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
-
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
-
- $this->Controller->request->data = array();
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
-
- $this->Controller->request->data = $data = array(
- 'Model' => array('username' => '', 'password' => '', 'valid' => '0'),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
-
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
- }
-
-/**
- * testValidatePostHidden method
- *
- * @return void
- */
- public function testValidatePostHidden() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = '51ccd8cb0997c7b3d4523ecde5a109318405ef8c%3AModel.hidden%7CModel.other_hidden';
- $unlocked = '';
-
- $this->Controller->request->data = array(
- 'Model' => array(
- 'username' => '', 'password' => '', 'hidden' => '0',
- 'other_hidden' => 'some hidden value'
- ),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
- }
-
-/**
- * testValidatePostWithDisabledFields method
- *
- * @return void
- */
- public function testValidatePostWithDisabledFields() {
- $this->Controller->Security->disabledFields = array('Model.username', 'Model.password');
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = 'ef1082968c449397bcd849f963636864383278b1%3AModel.hidden';
- $unlocked = '';
-
- $this->Controller->request->data = array(
- 'Model' => array(
- 'username' => '', 'password' => '', 'hidden' => '0'
- ),
- '_Token' => compact('fields', 'key', 'unlocked')
- );
-
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
- }
-
-/**
- * test validating post data with posted unlocked fields.
- *
- * @return void
- */
- public function testValidatePostDisabledFieldsInData() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
- $unlocked = 'Model.username';
- $fields = array('Model.hidden', 'Model.password');
- $fields = urlencode(Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt')));
-
- $this->Controller->request->data = array(
- 'Model' => array(
- 'username' => 'mark',
- 'password' => 'sekret',
- 'hidden' => '0'
- ),
- '_Token' => compact('fields', 'key', 'unlocked')
- );
-
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
- }
-
-/**
- * test that missing 'unlocked' input causes failure
- *
- * @return void
- */
- public function testValidatePostFailNoDisabled() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = array('Model.hidden', 'Model.password', 'Model.username');
- $fields = urlencode(Security::hash(serialize($fields) . Configure::read('Security.salt')));
-
- $this->Controller->request->data = array(
- 'Model' => array(
- 'username' => 'mark',
- 'password' => 'sekret',
- 'hidden' => '0'
- ),
- '_Token' => compact('fields', 'key')
- );
-
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertFalse($result);
- }
-
-/**
- * Test that validatePost fails when unlocked fields are changed.
- *
- * @return
- */
- public function testValidatePostFailDisabledFieldTampering() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
- $unlocked = 'Model.username';
- $fields = array('Model.hidden', 'Model.password');
- $fields = urlencode(Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt')));
-
- // Tamper the values.
- $unlocked = 'Model.username|Model.password';
-
- $this->Controller->request->data = array(
- 'Model' => array(
- 'username' => 'mark',
- 'password' => 'sekret',
- 'hidden' => '0'
- ),
- '_Token' => compact('fields', 'key', 'unlocked')
- );
-
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertFalse($result);
- }
-
-/**
- * testValidateHiddenMultipleModel method
- *
- * @return void
- */
- public function testValidateHiddenMultipleModel() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = 'a2d01072dc4660eea9d15007025f35a7a5b58e18%3AModel.valid%7CModel2.valid%7CModel3.valid';
- $unlocked = '';
-
- $this->Controller->request->data = array(
- 'Model' => array('username' => '', 'password' => '', 'valid' => '0'),
- 'Model2' => array('valid' => '0'),
- 'Model3' => array('valid' => '0'),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
- }
-
-/**
- * testValidateHasManyModel method
- *
- * @return void
- */
- public function testValidateHasManyModel() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = '51e3b55a6edd82020b3f29c9ae200e14bbeb7ee5%3AModel.0.hidden%7CModel.0.valid';
- $fields .= '%7CModel.1.hidden%7CModel.1.valid';
- $unlocked = '';
-
- $this->Controller->request->data = array(
- 'Model' => array(
- array(
- 'username' => 'username', 'password' => 'password',
- 'hidden' => 'value', 'valid' => '0'
- ),
- array(
- 'username' => 'username', 'password' => 'password',
- 'hidden' => 'value', 'valid' => '0'
- )
- ),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
-
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
- }
-
-/**
- * testValidateHasManyRecordsPass method
- *
- * @return void
- */
- public function testValidateHasManyRecordsPass() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3AAddress.0.id%7CAddress.0.primary%7C';
- $fields .= 'Address.1.id%7CAddress.1.primary';
- $unlocked = '';
-
- $this->Controller->request->data = array(
- 'Address' => array(
- 0 => array(
- 'id' => '123',
- 'title' => 'home',
- 'first_name' => 'Bilbo',
- 'last_name' => 'Baggins',
- 'address' => '23 Bag end way',
- 'city' => 'the shire',
- 'phone' => 'N/A',
- 'primary' => '1',
- ),
- 1 => array(
- 'id' => '124',
- 'title' => 'home',
- 'first_name' => 'Frodo',
- 'last_name' => 'Baggins',
- 'address' => '50 Bag end way',
- 'city' => 'the shire',
- 'phone' => 'N/A',
- 'primary' => '1'
- )
- ),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
-
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
- }
-
-/**
- * Test that values like Foo.0.1
- *
- * @return void
- */
- public function testValidateNestedNumericSets() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
- $unlocked = '';
- $hashFields = array('TaxonomyData');
- $fields = urlencode(Security::hash(serialize($hashFields) . $unlocked . Configure::read('Security.salt')));
-
- $this->Controller->request->data = array(
- 'TaxonomyData' => array(
- 1 => array(array(2)),
- 2 => array(array(3))
- ),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
- }
-
-/**
- * testValidateHasManyRecords method
- *
- * validatePost should fail, hidden fields have been changed.
- *
- * @return void
- */
- public function testValidateHasManyRecordsFail() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3AAddress.0.id%7CAddress.0.primary%7C';
- $fields .= 'Address.1.id%7CAddress.1.primary';
- $unlocked = '';
-
- $this->Controller->request->data = array(
- 'Address' => array(
- 0 => array(
- 'id' => '123',
- 'title' => 'home',
- 'first_name' => 'Bilbo',
- 'last_name' => 'Baggins',
- 'address' => '23 Bag end way',
- 'city' => 'the shire',
- 'phone' => 'N/A',
- 'primary' => '5',
- ),
- 1 => array(
- 'id' => '124',
- 'title' => 'home',
- 'first_name' => 'Frodo',
- 'last_name' => 'Baggins',
- 'address' => '50 Bag end way',
- 'city' => 'the shire',
- 'phone' => 'N/A',
- 'primary' => '1'
- )
- ),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
-
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertFalse($result);
- }
-
-/**
- * testFormDisabledFields method
- *
- * @return void
- */
- public function testFormDisabledFields() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = '11842060341b9d0fc3808b90ba29fdea7054d6ad%3An%3A0%3A%7B%7D';
- $unlocked = '';
-
- $this->Controller->request->data = array(
- 'MyModel' => array('name' => 'some data'),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertFalse($result);
-
- $this->Controller->Security->startup($this->Controller);
- $this->Controller->Security->disabledFields = array('MyModel.name');
- $key = $this->Controller->request->params['_Token']['key'];
-
- $this->Controller->request->data = array(
- 'MyModel' => array('name' => 'some data'),
- '_Token' => compact('key', 'fields', 'unlocked')
- );
-
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
- }
-
-/**
- * testRadio method
- *
- * @return void
- */
- public function testRadio() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
- $fields = '575ef54ca4fc8cab468d6d898e9acd3a9671c17e%3An%3A0%3A%7B%7D';
- $unlocked = '';
-
- $this->Controller->request->data = array(
- '_Token' => compact('key', 'fields', 'unlocked')
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertFalse($result);
-
- $this->Controller->request->data = array(
- '_Token' => compact('key', 'fields', 'unlocked'),
- 'Test' => array('test' => '')
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
-
- $this->Controller->request->data = array(
- '_Token' => compact('key', 'fields', 'unlocked'),
- 'Test' => array('test' => '1')
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
-
- $this->Controller->request->data = array(
- '_Token' => compact('key', 'fields', 'unlocked'),
- 'Test' => array('test' => '2')
- );
- $result = $this->Controller->Security->validatePost($this->Controller);
- $this->assertTrue($result);
- }
-
-/**
- * test that a requestAction's controller will have the _Token appended to
- * the params.
- *
- * @return void
- * @see http://cakephp.lighthouseapp.com/projects/42648/tickets/68
- */
- public function testSettingTokenForRequestAction() {
- $this->Controller->Security->startup($this->Controller);
- $key = $this->Controller->request->params['_Token']['key'];
-
- $this->Controller->params['requested'] = 1;
- unset($this->Controller->request->params['_Token']);
-
- $this->Controller->Security->startup($this->Controller);
- $this->assertEquals($this->Controller->request->params['_Token']['key'], $key);
- }
-
-/**
- * test that blackhole doesn't delete the _Token session key so repeat data submissions
- * stay blackholed.
- *
- * @link http://cakephp.lighthouseapp.com/projects/42648/tickets/214
- * @return void
- */
- public function testBlackHoleNotDeletingSessionInformation() {
- $this->Controller->Security->startup($this->Controller);
-
- $this->Controller->Security->blackHole($this->Controller, 'auth');
- $this->assertTrue($this->Controller->Security->Session->check('_Token'), '_Token was deleted by blackHole %s');
- }
-
-/**
- * test that csrf checks are skipped for request action.
- *
- * @return void
- */
- public function testCsrfSkipRequestAction() {
- $_SERVER['REQUEST_METHOD'] = 'POST';
-
- $this->Security->validatePost = false;
- $this->Security->csrfCheck = true;
- $this->Security->csrfExpires = '+10 minutes';
- $this->Controller->request->params['requested'] = 1;
- $this->Security->startup($this->Controller);
-
- $this->assertFalse($this->Controller->failed, 'fail() was called.');
- }
-
-/**
- * test setting
- *
- * @return void
- */
- public function testCsrfSettings() {
- $this->Security->validatePost = false;
- $this->Security->csrfCheck = true;
- $this->Security->csrfExpires = '+10 minutes';
- $this->Security->startup($this->Controller);
-
- $token = $this->Security->Session->read('_Token');
- $this->assertEquals(1, count($token['csrfTokens']), 'Missing the csrf token.');
- $this->assertEquals(strtotime('+10 minutes'), current($token['csrfTokens']), 'Token expiry does not match');
- $this->assertEquals(array('key', 'unlockedFields'), array_keys($this->Controller->request->params['_Token']), 'Keys don not match');
- }
-
-/**
- * Test setting multiple nonces, when startup() is called more than once, (ie more than one request.)
- *
- * @return void
- */
- public function testCsrfSettingMultipleNonces() {
- $this->Security->validatePost = false;
- $this->Security->csrfCheck = true;
- $this->Security->csrfExpires = '+10 minutes';
- $csrfExpires = strtotime('+10 minutes');
- $this->Security->startup($this->Controller);
- $this->Security->startup($this->Controller);
-
- $token = $this->Security->Session->read('_Token');
- $this->assertEquals(2, count($token['csrfTokens']), 'Missing the csrf token.');
- foreach ($token['csrfTokens'] as $key => $expires) {
- $diff = $csrfExpires - $expires;
- $this->assertTrue($diff === 0 || $diff === 1, 'Token expiry does not match');
- }
- }
-
-/**
- * test that nonces are consumed by form submits.
- *
- * @return void
- */
- public function testCsrfNonceConsumption() {
- $this->Security->validatePost = false;
- $this->Security->csrfCheck = true;
- $this->Security->csrfExpires = '+10 minutes';
-
- $this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('+10 minutes')));
-
- $this->Controller->request = $this->getMock('CakeRequest', array('is'));
- $this->Controller->request->expects($this->once())->method('is')
- ->with('post')
- ->will($this->returnValue(true));
-
- $this->Controller->request->params['action'] = 'index';
- $this->Controller->request->data = array(
- '_Token' => array(
- 'key' => 'nonce1'
- ),
- 'Post' => array(
- 'title' => 'Woot'
- )
- );
- $this->Security->startup($this->Controller);
- $token = $this->Security->Session->read('_Token');
- $this->assertFalse(isset($token['csrfTokens']['nonce1']), 'Token was not consumed');
- }
-
-/**
- * test that expired values in the csrfTokens are cleaned up.
- *
- * @return void
- */
- public function testCsrfNonceVacuum() {
- $this->Security->validatePost = false;
- $this->Security->csrfCheck = true;
- $this->Security->csrfExpires = '+10 minutes';
-
- $this->Security->Session->write('_Token.csrfTokens', array(
- 'valid' => strtotime('+30 minutes'),
- 'poof' => strtotime('-11 minutes'),
- 'dust' => strtotime('-20 minutes')
- ));
- $this->Security->startup($this->Controller);
- $tokens = $this->Security->Session->read('_Token.csrfTokens');
- $this->assertEquals(2, count($tokens), 'Too many tokens left behind');
- $this->assertNotEmpty('valid', $tokens, 'Valid token was removed.');
- }
-
-/**
- * test that when the key is missing the request is blackHoled
- *
- * @return void
- */
- public function testCsrfBlackHoleOnKeyMismatch() {
- $this->Security->validatePost = false;
- $this->Security->csrfCheck = true;
- $this->Security->csrfExpires = '+10 minutes';
-
- $this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('+10 minutes')));
-
- $this->Controller->request = $this->getMock('CakeRequest', array('is'));
- $this->Controller->request->expects($this->once())->method('is')
- ->with('post')
- ->will($this->returnValue(true));
-
- $this->Controller->request->params['action'] = 'index';
- $this->Controller->request->data = array(
- '_Token' => array(
- 'key' => 'not the right value'
- ),
- 'Post' => array(
- 'title' => 'Woot'
- )
- );
- $this->Security->startup($this->Controller);
- $this->assertTrue($this->Controller->failed, 'fail() was not called.');
- }
-
-/**
- * test that when the key is missing the request is blackHoled
- *
- * @return void
- */
- public function testCsrfBlackHoleOnExpiredKey() {
- $this->Security->validatePost = false;
- $this->Security->csrfCheck = true;
- $this->Security->csrfExpires = '+10 minutes';
-
- $this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('-5 minutes')));
-
- $this->Controller->request = $this->getMock('CakeRequest', array('is'));
- $this->Controller->request->expects($this->once())->method('is')
- ->with('post')
- ->will($this->returnValue(true));
-
- $this->Controller->request->params['action'] = 'index';
- $this->Controller->request->data = array(
- '_Token' => array(
- 'key' => 'nonce1'
- ),
- 'Post' => array(
- 'title' => 'Woot'
- )
- );
- $this->Security->startup($this->Controller);
- $this->assertTrue($this->Controller->failed, 'fail() was not called.');
- }
-
-/**
- * test that csrfUseOnce = false works.
- *
- * @return void
- */
- public function testCsrfNotUseOnce() {
- $this->Security->validatePost = false;
- $this->Security->csrfCheck = true;
- $this->Security->csrfUseOnce = false;
- $this->Security->csrfExpires = '+10 minutes';
-
- // Generate one token
- $this->Security->startup($this->Controller);
- $token = $this->Security->Session->read('_Token.csrfTokens');
- $this->assertEquals(1, count($token), 'Should only be one token.');
-
- $this->Security->startup($this->Controller);
- $tokenTwo = $this->Security->Session->read('_Token.csrfTokens');
- $this->assertEquals(1, count($tokenTwo), 'Should only be one token.');
- $this->assertEquals($token, $tokenTwo, 'Tokens should not be different.');
-
- $key = $this->Controller->request->params['_Token']['key'];
- $this->assertEquals(array($key), array_keys($token), '_Token.key and csrfToken do not match request will blackhole.');
- }
-
-/**
- * ensure that longer session tokens are not consumed
- *
- * @return void
- */
- public function testCsrfNotUseOnceValidationLeavingToken() {
- $this->Security->validatePost = false;
- $this->Security->csrfCheck = true;
- $this->Security->csrfUseOnce = false;
- $this->Security->csrfExpires = '+10 minutes';
-
- $this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('+10 minutes')));
-
- $this->Controller->request = $this->getMock('CakeRequest', array('is'));
- $this->Controller->request->expects($this->once())->method('is')
- ->with('post')
- ->will($this->returnValue(true));
-
- $this->Controller->request->params['action'] = 'index';
- $this->Controller->request->data = array(
- '_Token' => array(
- 'key' => 'nonce1'
- ),
- 'Post' => array(
- 'title' => 'Woot'
- )
- );
- $this->Security->startup($this->Controller);
- $token = $this->Security->Session->read('_Token');
- $this->assertTrue(isset($token['csrfTokens']['nonce1']), 'Token was consumed');
- }
-
-/**
- * Test generateToken()
- *
- * @return void
- */
- public function testGenerateToken() {
- $request = $this->Controller->request;
- $this->Security->generateToken($request);
-
- $this->assertNotEmpty($request->params['_Token']);
- $this->assertTrue(isset($request->params['_Token']['unlockedFields']));
- $this->assertTrue(isset($request->params['_Token']['key']));
- }
-
-/**
- * Test the limiting of CSRF tokens.
- *
- * @return void
- */
- public function testCsrfLimit() {
- $this->Security->csrfLimit = 3;
- $time = strtotime('+10 minutes');
- $tokens = array(
- '1' => $time,
- '2' => $time,
- '3' => $time,
- '4' => $time,
- '5' => $time,
- );
- $this->Security->Session->write('_Token', array('csrfTokens' => $tokens));
- $this->Security->generateToken($this->Controller->request);
- $result = $this->Security->Session->read('_Token.csrfTokens');
-
- $this->assertFalse(isset($result['1']));
- $this->assertFalse(isset($result['2']));
- $this->assertFalse(isset($result['3']));
- $this->assertTrue(isset($result['4']));
- $this->assertTrue(isset($result['5']));
- }
-}
diff --git a/lib/Cake/Test/Case/Controller/Component/SessionComponentTest.php b/lib/Cake/Test/Case/Controller/Component/SessionComponentTest.php
deleted file mode 100644
index 8e5af39aea8..00000000000
--- a/lib/Cake/Test/Case/Controller/Component/SessionComponentTest.php
+++ /dev/null
@@ -1,295 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Controller.Component
- * @since CakePHP(tm) v 1.2.0.5436
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-App::uses('Controller', 'Controller');
-App::uses('SessionComponent', 'Controller/Component');
-
-/**
- * SessionTestController class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class SessionTestController extends Controller {
-
-/**
- * uses property
- *
- * @var array
- */
- public $uses = array();
-
-/**
- * sessionId method
- *
- * @return string
- */
- public function sessionId() {
- return $this->Session->id();
- }
-
-}
-
-/**
- * OrangeSessionTestController class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class OrangeSessionTestController extends Controller {
-
-/**
- * uses property
- *
- * @var array
- */
- public $uses = array();
-
-/**
- * sessionId method
- *
- * @return string
- */
- public function sessionId() {
- return $this->Session->id();
- }
-
-}
-
-/**
- * SessionComponentTest class
- *
- * @package Cake.Test.Case.Controller.Component
- */
-class SessionComponentTest extends CakeTestCase {
-
- protected static $_sessionBackup;
-
-/**
- * fixtures
- *
- * @var string
- */
- public $fixtures = array('core.session');
-
-/**
- * test case startup
- *
- * @return void
- */
- public static function setupBeforeClass() {
- self::$_sessionBackup = Configure::read('Session');
- Configure::write('Session', array(
- 'defaults' => 'php',
- 'timeout' => 100,
- 'cookie' => 'test'
- ));
- }
-
-/**
- * cleanup after test case.
- *
- * @return void
- */
- public static function teardownAfterClass() {
- Configure::write('Session', self::$_sessionBackup);
- }
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- $_SESSION = null;
- $this->ComponentCollection = new ComponentCollection();
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- CakeSession::destroy();
- }
-
-/**
- * ensure that session ids don't change when request action is called.
- *
- * @return void
- */
- public function testSessionIdConsistentAcrossRequestAction() {
- $Session = new SessionComponent($this->ComponentCollection);
- $Session->check('Test');
- $this->assertTrue(isset($_SESSION));
-
- $Object = new Object();
- $Session = new SessionComponent($this->ComponentCollection);
- $expected = $Session->id();
-
- $result = $Object->requestAction('/session_test/sessionId');
- $this->assertEquals($expected, $result);
-
- $result = $Object->requestAction('/orange_session_test/sessionId');
- $this->assertEquals($expected, $result);
- }
-
-/**
- * testSessionValid method
- *
- * @return void
- */
- public function testSessionValid() {
- $Session = new SessionComponent($this->ComponentCollection);
-
- $this->assertTrue($Session->valid());
-
- Configure::write('Session.checkAgent', true);
- $Session->userAgent('rweerw');
- $this->assertFalse($Session->valid());
-
- $Session = new SessionComponent($this->ComponentCollection);
- $Session->time = $Session->read('Config.time') + 1;
- $this->assertFalse($Session->valid());
- }
-
-/**
- * testSessionError method
- *
- * @return void
- */
- public function testSessionError() {
- $Session = new SessionComponent($this->ComponentCollection);
- $this->assertFalse($Session->error());
- }
-
-/**
- * testSessionReadWrite method
- *
- * @return void
- */
- public function testSessionReadWrite() {
- $Session = new SessionComponent($this->ComponentCollection);
-
- $this->assertNull($Session->read('Test'));
-
- $this->assertTrue($Session->write('Test', 'some value'));
- $this->assertEquals('some value', $Session->read('Test'));
- $this->assertFalse($Session->write('Test.key', 'some value'));
- $Session->delete('Test');
-
- $this->assertTrue($Session->write('Test.key.path', 'some value'));
- $this->assertEquals('some value', $Session->read('Test.key.path'));
- $this->assertEquals(array('path' => 'some value'), $Session->read('Test.key'));
- $this->assertTrue($Session->write('Test.key.path2', 'another value'));
- $this->assertEquals(array('path' => 'some value', 'path2' => 'another value'), $Session->read('Test.key'));
- $Session->delete('Test');
-
- $array = array('key1' => 'val1', 'key2' => 'val2', 'key3' => 'val3');
- $this->assertTrue($Session->write('Test', $array));
- $this->assertEquals($Session->read('Test'), $array);
- $Session->delete('Test');
-
- $this->assertFalse($Session->write(array('Test'), 'some value'));
- $this->assertTrue($Session->write(array('Test' => 'some value')));
- $this->assertEquals('some value', $Session->read('Test'));
- $Session->delete('Test');
- }
-
-/**
- * testSessionDelete method
- *
- * @return void
- */
- public function testSessionDelete() {
- $Session = new SessionComponent($this->ComponentCollection);
-
- $this->assertFalse($Session->delete('Test'));
-
- $Session->write('Test', 'some value');
- $this->assertTrue($Session->delete('Test'));
- }
-
-/**
- * testSessionCheck method
- *
- * @return void
- */
- public function testSessionCheck() {
- $Session = new SessionComponent($this->ComponentCollection);
-
- $this->assertFalse($Session->check('Test'));
-
- $Session->write('Test', 'some value');
- $this->assertTrue($Session->check('Test'));
- $Session->delete('Test');
- }
-
-/**
- * testSessionFlash method
- *
- * @return void
- */
- public function testSessionFlash() {
- $Session = new SessionComponent($this->ComponentCollection);
-
- $this->assertNull($Session->read('Message.flash'));
-
- $Session->setFlash('This is a test message');
- $this->assertEquals(array('message' => 'This is a test message', 'element' => 'default', 'params' => array()), $Session->read('Message.flash'));
-
- $Session->setFlash('This is a test message', 'test', array('name' => 'Joel Moss'));
- $this->assertEquals(array('message' => 'This is a test message', 'element' => 'test', 'params' => array('name' => 'Joel Moss')), $Session->read('Message.flash'));
-
- $Session->setFlash('This is a test message', 'default', array(), 'myFlash');
- $this->assertEquals(array('message' => 'This is a test message', 'element' => 'default', 'params' => array()), $Session->read('Message.myFlash'));
-
- $Session->setFlash('This is a test message', 'non_existing_layout');
- $this->assertEquals(array('message' => 'This is a test message', 'element' => 'default', 'params' => array()), $Session->read('Message.myFlash'));
-
- $Session->delete('Message');
- }
-
-/**
- * testSessionId method
- *
- * @return void
- */
- public function testSessionId() {
- unset($_SESSION);
- $Session = new SessionComponent($this->ComponentCollection);
- $Session->check('test');
- $this->assertEquals(session_id(), $Session->id());
- }
-
-/**
- * testSessionDestroy method
- *
- * @return void
- */
- public function testSessionDestroy() {
- $Session = new SessionComponent($this->ComponentCollection);
-
- $Session->write('Test', 'some value');
- $this->assertEquals('some value', $Session->read('Test'));
- $Session->destroy('Test');
- $this->assertNull($Session->read('Test'));
- }
-
-}
diff --git a/lib/Cake/Test/Case/Controller/ComponentCollectionTest.php b/lib/Cake/Test/Case/Controller/ComponentCollectionTest.php
deleted file mode 100644
index e556263cc72..00000000000
--- a/lib/Cake/Test/Case/Controller/ComponentCollectionTest.php
+++ /dev/null
@@ -1,178 +0,0 @@
-Components = new ComponentCollection();
- }
-
-/**
- * tearDown
- *
- * @return void
- */
- public function tearDown() {
- unset($this->Components);
- parent::tearDown();
- }
-
-/**
- * test triggering callbacks on loaded helpers
- *
- * @return void
- */
- public function testLoad() {
- $result = $this->Components->load('Cookie');
- $this->assertInstanceOf('CookieComponent', $result);
- $this->assertInstanceOf('CookieComponent', $this->Components->Cookie);
-
- $result = $this->Components->attached();
- $this->assertEquals(array('Cookie'), $result, 'attached() results are wrong.');
-
- $this->assertTrue($this->Components->enabled('Cookie'));
-
- $result = $this->Components->load('Cookie');
- $this->assertSame($result, $this->Components->Cookie);
- }
-
-/**
- * Tests loading as an alias
- *
- * @return void
- */
- public function testLoadWithAlias() {
- $result = $this->Components->load('Cookie', array('className' => 'CookieAlias', 'somesetting' => true));
- $this->assertInstanceOf('CookieAliasComponent', $result);
- $this->assertInstanceOf('CookieAliasComponent', $this->Components->Cookie);
- $this->assertTrue($this->Components->Cookie->settings['somesetting']);
-
- $result = $this->Components->attached();
- $this->assertEquals(array('Cookie'), $result, 'attached() results are wrong.');
-
- $this->assertTrue($this->Components->enabled('Cookie'));
-
- $result = $this->Components->load('Cookie');
- $this->assertInstanceOf('CookieAliasComponent', $result);
-
- App::build(array('Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)));
- CakePlugin::load('TestPlugin');
- $result = $this->Components->load('SomeOther', array('className' => 'TestPlugin.Other'));
- $this->assertInstanceOf('OtherComponent', $result);
- $this->assertInstanceOf('OtherComponent', $this->Components->SomeOther);
-
- $result = $this->Components->attached();
- $this->assertEquals(array('Cookie', 'SomeOther'), $result, 'attached() results are wrong.');
- App::build();
- CakePlugin::unload();
- }
-
-/**
- * test load and enable = false
- *
- * @return void
- */
- public function testLoadWithEnableFalse() {
- $result = $this->Components->load('Cookie', array('enabled' => false));
- $this->assertInstanceOf('CookieComponent', $result);
- $this->assertInstanceOf('CookieComponent', $this->Components->Cookie);
-
- $this->assertFalse($this->Components->enabled('Cookie'), 'Cookie should be disabled');
- }
-
-/**
- * test missingcomponent exception
- *
- * @expectedException MissingComponentException
- * @return void
- */
- public function testLoadMissingComponent() {
- $this->Components->load('ThisComponentShouldAlwaysBeMissing');
- }
-
-/**
- * test loading a plugin component.
- *
- * @return void
- */
- public function testLoadPluginComponent() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS),
- ));
- CakePlugin::load('TestPlugin');
- $result = $this->Components->load('TestPlugin.Other');
- $this->assertInstanceOf('OtherComponent', $result, 'Component class is wrong.');
- $this->assertInstanceOf('OtherComponent', $this->Components->Other, 'Class is wrong');
- App::build();
- CakePlugin::unload();
- }
-
-/**
- * test unload()
- *
- * @return void
- */
- public function testUnload() {
- $this->Components->load('Cookie');
- $this->Components->load('Security');
-
- $result = $this->Components->attached();
- $this->assertEquals(array('Cookie', 'Security'), $result, 'loaded components is wrong');
-
- $this->Components->unload('Cookie');
- $this->assertFalse(isset($this->Components->Cookie));
- $this->assertTrue(isset($this->Components->Security));
-
- $result = $this->Components->attached();
- $this->assertEquals(array('Security'), $result, 'loaded components is wrong');
-
- $result = $this->Components->enabled();
- $this->assertEquals(array('Security'), $result, 'enabled components is wrong');
- }
-
-/**
- * test getting the controller out of the collection
- *
- * @return void
- */
- public function testGetController() {
- $controller = $this->getMock('Controller');
- $controller->components = array('Security');
- $this->Components->init($controller);
- $result = $this->Components->getController();
-
- $this->assertSame($controller, $result);
- }
-}
diff --git a/lib/Cake/Test/Case/Controller/ComponentTest.php b/lib/Cake/Test/Case/Controller/ComponentTest.php
deleted file mode 100644
index 482e304f7ba..00000000000
--- a/lib/Cake/Test/Case/Controller/ComponentTest.php
+++ /dev/null
@@ -1,314 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Controller
- * @since CakePHP(tm) v 1.2.0.5436
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('Controller', 'Controller');
-App::uses('Component', 'Controller');
-
-/**
- * ParamTestComponent
- *
- * @package Cake.Test.Case.Controller
- */
-class ParamTestComponent extends Component {
-
-/**
- * name property
- *
- * @var string 'ParamTest'
- */
- public $name = 'ParamTest';
-
-/**
- * components property
- *
- * @var array
- */
- public $components = array('Banana' => array('config' => 'value'));
-}
-
-/**
- * ComponentTestController class
- *
- * @package Cake.Test.Case.Controller
- */
-class ComponentTestController extends Controller {
-
-/**
- * name property
- *
- * @var string 'ComponentTest'
- */
- public $name = 'ComponentTest';
-
-/**
- * uses property
- *
- * @var array
- */
- public $uses = array();
-
-}
-
-/**
- * AppleComponent class
- *
- * @package Cake.Test.Case.Controller
- */
-class AppleComponent extends Component {
-
-/**
- * components property
- *
- * @var array
- */
- public $components = array('Orange');
-
-/**
- * testName property
- *
- * @var mixed null
- */
- public $testName = null;
-
-/**
- * startup method
- *
- * @param mixed $controller
- * @return void
- */
- public function startup(Controller $controller) {
- $this->testName = $controller->name;
- }
-
-}
-
-/**
- * OrangeComponent class
- *
- * @package Cake.Test.Case.Controller
- */
-class OrangeComponent extends Component {
-
-/**
- * components property
- *
- * @var array
- */
- public $components = array('Banana');
-
-/**
- * initialize method
- *
- * @param mixed $controller
- * @return void
- */
- public function initialize(Controller $controller) {
- $this->Controller = $controller;
- $this->Banana->testField = 'OrangeField';
- }
-
-/**
- * startup method
- *
- * @param Controller $controller
- * @return string
- */
- public function startup(Controller $controller) {
- $controller->foo = 'pass';
- }
-
-}
-
-/**
- * BananaComponent class
- *
- * @package Cake.Test.Case.Controller
- */
-class BananaComponent extends Component {
-
-/**
- * testField property
- *
- * @var string 'BananaField'
- */
- public $testField = 'BananaField';
-
-/**
- * startup method
- *
- * @param Controller $controller
- * @return string
- */
- public function startup(Controller $controller) {
- $controller->bar = 'fail';
- }
-
-}
-
-/**
- * MutuallyReferencingOneComponent class
- *
- * @package Cake.Test.Case.Controller
- */
-class MutuallyReferencingOneComponent extends Component {
-
-/**
- * components property
- *
- * @var array
- */
- public $components = array('MutuallyReferencingTwo');
-}
-
-/**
- * MutuallyReferencingTwoComponent class
- *
- * @package Cake.Test.Case.Controller
- */
-class MutuallyReferencingTwoComponent extends Component {
-
-/**
- * components property
- *
- * @var array
- */
- public $components = array('MutuallyReferencingOne');
-}
-
-/**
- * SomethingWithEmailComponent class
- *
- * @package Cake.Test.Case.Controller
- */
-class SomethingWithEmailComponent extends Component {
-
-/**
- * components property
- *
- * @var array
- */
- public $components = array('Email');
-}
-
-
-/**
- * ComponentTest class
- *
- * @package Cake.Test.Case.Controller
- */
-class ComponentTest extends CakeTestCase {
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- $this->_pluginPaths = App::path('plugins');
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ));
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- App::build();
- ClassRegistry::flush();
- }
-
-/**
- * test accessing inner components.
- *
- * @return void
- */
- public function testInnerComponentConstruction() {
- $Collection = new ComponentCollection();
- $Component = new AppleComponent($Collection);
-
- $this->assertInstanceOf('OrangeComponent', $Component->Orange, 'class is wrong');
- }
-
-/**
- * test component loading
- *
- * @return void
- */
- public function testNestedComponentLoading() {
- $Collection = new ComponentCollection();
- $Apple = new AppleComponent($Collection);
-
- $this->assertInstanceOf('OrangeComponent', $Apple->Orange, 'class is wrong');
- $this->assertInstanceOf('BananaComponent', $Apple->Orange->Banana, 'class is wrong');
- $this->assertTrue(empty($Apple->Session));
- $this->assertTrue(empty($Apple->Orange->Session));
- }
-
-/**
- * test that component components are not enabled in the collection.
- *
- * @return void
- */
- public function testInnerComponentsAreNotEnabled() {
- $Collection = new ComponentCollection();
- $Apple = $Collection->load('Apple');
-
- $this->assertInstanceOf('OrangeComponent', $Apple->Orange, 'class is wrong');
- $result = $Collection->enabled();
- $this->assertEquals(array('Apple'), $result, 'Too many components enabled.');
- }
-
-/**
- * test a component being used more than once.
- *
- * @return void
- */
- public function testMultipleComponentInitialize() {
- $Collection = new ComponentCollection();
- $Banana = $Collection->load('Banana');
- $Orange = $Collection->load('Orange');
-
- $this->assertSame($Banana, $Orange->Banana, 'Should be references');
- $Banana->testField = 'OrangeField';
-
- $this->assertSame($Banana->testField, $Orange->Banana->testField, 'References are broken');
- }
-
-/**
- * Test mutually referencing components.
- *
- * @return void
- */
- public function testSomethingReferencingEmailComponent() {
- $Controller = new ComponentTestController();
- $Controller->components = array('SomethingWithEmail');
- $Controller->uses = false;
- $Controller->constructClasses();
- $Controller->Components->trigger('initialize', array(&$Controller));
- $Controller->beforeFilter();
- $Controller->Components->trigger('startup', array(&$Controller));
-
- $this->assertInstanceOf('SomethingWithEmailComponent', $Controller->SomethingWithEmail);
- $this->assertInstanceOf('EmailComponent', $Controller->SomethingWithEmail->Email);
- }
-
-}
diff --git a/lib/Cake/Test/Case/Controller/ControllerMergeVarsTest.php b/lib/Cake/Test/Case/Controller/ControllerMergeVarsTest.php
deleted file mode 100644
index df96b2bee39..00000000000
--- a/lib/Cake/Test/Case/Controller/ControllerMergeVarsTest.php
+++ /dev/null
@@ -1,252 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Controller
- * @since CakePHP(tm) v 1.2.3
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-App::uses('Controller', 'Controller');
-
-/**
- * Test case AppController
- *
- * @package Cake.Test.Case.Controller
- * @package Cake.Test.Case.Controller
- */
-class MergeVarsAppController extends Controller {
-
-/**
- * components
- *
- * @var array
- */
- public $components = array('MergeVar' => array('flag', 'otherFlag', 'redirect' => false));
-
-/**
- * helpers
- *
- * @var array
- */
- public $helpers = array('MergeVar' => array('format' => 'html', 'terse'));
-}
-
-/**
- * MergeVar Component
- *
- * @package Cake.Test.Case.Controller
- */
-class MergeVarComponent extends Object {
-
-}
-
-/**
- * Additional controller for testing
- *
- * @package Cake.Test.Case.Controller
- */
-class MergeVariablesController extends MergeVarsAppController {
-
-/**
- * name
- *
- * @var string
- */
- public $name = 'MergeVariables';
-
-/**
- * uses
- *
- * @var arrays
- */
- public $uses = array();
-
-/**
- * parent for mergeVars
- *
- * @var string
- */
- protected $_mergeParent = 'MergeVarsAppController';
-}
-
-/**
- * MergeVarPlugin App Controller
- *
- * @package Cake.Test.Case.Controller
- */
-class MergeVarPluginAppController extends MergeVarsAppController {
-
-/**
- * components
- *
- * @var array
- */
- public $components = array('Auth' => array('setting' => 'val', 'otherVal'));
-
-/**
- * helpers
- *
- * @var array
- */
- public $helpers = array('Javascript');
-
-/**
- * parent for mergeVars
- *
- * @var string
- */
- protected $_mergeParent = 'MergeVarsAppController';
-}
-
-/**
- * MergePostsController
- *
- * @package Cake.Test.Case.Controller
- */
-class MergePostsController extends MergeVarPluginAppController {
-
-/**
- * name
- *
- * @var string
- */
- public $name = 'MergePosts';
-
-/**
- * uses
- *
- * @var array
- */
- public $uses = array();
-}
-
-
-/**
- * Test Case for Controller Merging of Vars.
- *
- * @package Cake.Test.Case.Controller
- */
-class ControllerMergeVarsTest extends CakeTestCase {
-
-/**
- * test that component settings are not duplicated when merging component settings
- *
- * @return void
- */
- public function testComponentParamMergingNoDuplication() {
- $Controller = new MergeVariablesController();
- $Controller->constructClasses();
-
- $expected = array('MergeVar' => array('flag', 'otherFlag', 'redirect' => false));
- $this->assertEquals($expected, $Controller->components, 'Duplication of settings occurred. %s');
- }
-
-/**
- * test component merges with redeclared components
- *
- * @return void
- */
- public function testComponentMergingWithRedeclarations() {
- $Controller = new MergeVariablesController();
- $Controller->components['MergeVar'] = array('remote', 'redirect' => true);
- $Controller->constructClasses();
-
- $expected = array('MergeVar' => array('flag', 'otherFlag', 'redirect' => true, 'remote'));
- $this->assertEquals($expected, $Controller->components, 'Merging of settings is wrong. %s');
- }
-
-/**
- * test merging of helpers array, ensure no duplication occurs
- *
- * @return void
- */
- public function testHelperSettingMergingNoDuplication() {
- $Controller = new MergeVariablesController();
- $Controller->constructClasses();
-
- $expected = array('MergeVar' => array('format' => 'html', 'terse'));
- $this->assertEquals($expected, $Controller->helpers, 'Duplication of settings occurred. %s');
- }
-
-/**
- * Test that helpers declared in appcontroller come before those in the subclass
- * orderwise
- *
- * @return void
- */
- public function testHelperOrderPrecedence() {
- $Controller = new MergeVariablesController();
- $Controller->helpers = array('Custom', 'Foo' => array('something'));
- $Controller->constructClasses();
-
- $expected = array(
- 'MergeVar' => array('format' => 'html', 'terse'),
- 'Custom' => null,
- 'Foo' => array('something')
- );
- $this->assertSame($expected, $Controller->helpers, 'Order is incorrect.');
- }
-
-/**
- * test merging of vars with plugin
- *
- * @return void
- */
- public function testMergeVarsWithPlugin() {
- $Controller = new MergePostsController();
- $Controller->components = array('Email' => array('ports' => 'open'));
- $Controller->plugin = 'MergeVarPlugin';
- $Controller->constructClasses();
-
- $expected = array(
- 'MergeVar' => array('flag', 'otherFlag', 'redirect' => false),
- 'Auth' => array('setting' => 'val', 'otherVal'),
- 'Email' => array('ports' => 'open')
- );
- $this->assertEquals($expected, $Controller->components, 'Components are unexpected.');
-
- $expected = array(
- 'MergeVar' => array('format' => 'html', 'terse'),
- 'Javascript' => null
- );
- $this->assertEquals($expected, $Controller->helpers, 'Helpers are unexpected.');
-
- $Controller = new MergePostsController();
- $Controller->components = array();
- $Controller->plugin = 'MergeVarPlugin';
- $Controller->constructClasses();
-
- $expected = array(
- 'MergeVar' => array('flag', 'otherFlag', 'redirect' => false),
- 'Auth' => array('setting' => 'val', 'otherVal'),
- );
- $this->assertEquals($expected, $Controller->components, 'Components are unexpected.');
- }
-
-/**
- * Ensure that _mergeControllerVars is not being greedy and merging with
- * AppController when you make an instance of Controller
- *
- * @return void
- */
- public function testMergeVarsNotGreedy() {
- $Controller = new Controller();
- $Controller->components = array();
- $Controller->uses = array();
- $Controller->constructClasses();
-
- $this->assertFalse(isset($Controller->Session));
- }
-}
diff --git a/lib/Cake/Test/Case/Controller/ControllerTest.php b/lib/Cake/Test/Case/Controller/ControllerTest.php
deleted file mode 100644
index b2b0a1ba398..00000000000
--- a/lib/Cake/Test/Case/Controller/ControllerTest.php
+++ /dev/null
@@ -1,1409 +0,0 @@
- 'error_msg');
-
-/**
- * lastQuery property
- *
- * @var mixed null
- */
- public $lastQuery = null;
-
-/**
- * beforeFind method
- *
- * @param mixed $query
- * @return void
- */
- public function beforeFind($query) {
- $this->lastQuery = $query;
- }
-
-/**
- * find method
- *
- * @param mixed $type
- * @param array $options
- * @return void
- */
- public function find($type = 'first', $options = array()) {
- if ($type == 'popular') {
- $conditions = array($this->name . '.' . $this->primaryKey . ' > ' => '1');
- $options = Set::merge($options, compact('conditions'));
- return parent::find('all', $options);
- }
- return parent::find($type, $options);
- }
-
-}
-
-/**
- * ControllerPostsController class
- *
- * @package Cake.Test.Case.Controller
- */
-class ControllerCommentsController extends ControllerTestAppController {
-
-/**
- * name property
- *
- * @var string 'ControllerPost'
- */
- public $name = 'ControllerComments';
-
- protected $_mergeParent = 'ControllerTestAppController';
-}
-
-/**
- * ControllerComment class
- *
- * @package Cake.Test.Case.Controller
- */
-class ControllerComment extends CakeTestModel {
-
-/**
- * name property
- *
- * @var string 'ControllerComment'
- */
- public $name = 'Comment';
-
-/**
- * useTable property
- *
- * @var string 'comments'
- */
- public $useTable = 'comments';
-
-/**
- * data property
- *
- * @var array
- */
- public $data = array('name' => 'Some Name');
-
-/**
- * alias property
- *
- * @var string 'ControllerComment'
- */
- public $alias = 'ControllerComment';
-}
-
-/**
- * ControllerAlias class
- *
- * @package Cake.Test.Case.Controller
- */
-class ControllerAlias extends CakeTestModel {
-
-/**
- * name property
- *
- * @var string 'ControllerAlias'
- */
- public $name = 'ControllerAlias';
-
-/**
- * alias property
- *
- * @var string 'ControllerSomeAlias'
- */
- public $alias = 'ControllerSomeAlias';
-
-/**
- * useTable property
- *
- * @var string 'posts'
- */
- public $useTable = 'posts';
-}
-
-/**
- * NameTest class
- *
- * @package Cake.Test.Case.Controller
- */
-class NameTest extends CakeTestModel {
-
-/**
- * name property
- * @var string 'Name'
- */
- public $name = 'Name';
-
-/**
- * useTable property
- * @var string 'names'
- */
- public $useTable = 'comments';
-
-/**
- * alias property
- *
- * @var string 'ControllerComment'
- */
- public $alias = 'Name';
-}
-
-/**
- * TestController class
- *
- * @package Cake.Test.Case.Controller
- */
-class TestController extends ControllerTestAppController {
-
-/**
- * name property
- * @var string 'Name'
- */
- public $name = 'Test';
-
-/**
- * helpers property
- *
- * @var array
- */
- public $helpers = array('Session');
-
-/**
- * components property
- *
- * @var array
- */
- public $components = array('Security');
-
-/**
- * uses property
- *
- * @var array
- */
- public $uses = array('ControllerComment', 'ControllerAlias');
-
- protected $_mergeParent = 'ControllerTestAppController';
-
-/**
- * index method
- *
- * @param mixed $testId
- * @param mixed $test2Id
- * @return void
- */
- public function index($testId, $testTwoId) {
- $this->data = array(
- 'testId' => $testId,
- 'test2Id' => $testTwoId
- );
- }
-
-/**
- * view method
- *
- * @param mixed $testId
- * @param mixed $test2Id
- * @return void
- */
- public function view($testId, $testTwoId) {
- $this->data = array(
- 'testId' => $testId,
- 'test2Id' => $testTwoId
- );
- }
-
- public function returner() {
- return 'I am from the controller.';
- }
-
- protected function protected_m() {
- }
-
- private function private_m() {
- }
-
- public function _hidden() {
- }
-
- public function admin_add() {
- }
-
-}
-
-/**
- * TestComponent class
- *
- * @package Cake.Test.Case.Controller
- */
-class TestComponent extends Object {
-
-/**
- * beforeRedirect method
- *
- * @return void
- */
- public function beforeRedirect() {
- }
-
-/**
- * initialize method
- *
- * @return void
- */
- public function initialize(Controller $controller) {
- }
-
-/**
- * startup method
- *
- * @return void
- */
- public function startup(Controller $controller) {
- }
-
-/**
- * shutdown method
- *
- * @return void
- */
- public function shutdown(Controller $controller) {
- }
-
-/**
- * beforeRender callback
- *
- * @return void
- */
- public function beforeRender(Controller $controller) {
- if ($this->viewclass) {
- $controller->viewClass = $this->viewclass;
- }
- }
-
-}
-
-class Test2Component extends TestComponent {
-
- public function beforeRender(Controller $controller) {
- return false;
- }
-
-}
-
-/**
- * AnotherTestController class
- *
- * @package Cake.Test.Case.Controller
- */
-class AnotherTestController extends ControllerTestAppController {
-
-/**
- * name property
- * @var string 'Name'
- */
- public $name = 'AnotherTest';
-
-/**
- * uses property
- *
- * @var array
- */
- public $uses = false;
-
-/**
- * merge parent
- *
- * @var string
- */
- protected $_mergeParent = 'ControllerTestAppController';
-}
-
-/**
- * ControllerTest class
- *
- * @package Cake.Test.Case.Controller
- */
-class ControllerTest extends CakeTestCase {
-
-/**
- * fixtures property
- *
- * @var array
- */
- public $fixtures = array('core.post', 'core.comment', 'core.name');
-
-/**
- * reset environment.
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- App::objects('plugin', null, false);
- App::build();
- Router::reload();
- }
-
-/**
- * tearDown
- *
- * @return void
- */
- public function tearDown() {
- CakePlugin::unload();
- App::build();
- parent::tearDown();
- }
-
-/**
- * testLoadModel method
- *
- * @return void
- */
- public function testLoadModel() {
- $request = new CakeRequest('controller_posts/index');
- $response = $this->getMock('CakeResponse');
- $Controller = new Controller($request, $response);
-
- $this->assertFalse(isset($Controller->ControllerPost));
-
- $result = $Controller->loadModel('ControllerPost');
- $this->assertTrue($result);
- $this->assertTrue(is_a($Controller->ControllerPost, 'ControllerPost'));
- $this->assertTrue(in_array('ControllerPost', $Controller->uses));
-
- ClassRegistry::flush();
- unset($Controller);
- }
-
-/**
- * testLoadModel method from a plugin controller
- *
- * @return void
- */
- public function testLoadModelInPlugins() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS),
- 'Controller' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Controller' . DS),
- 'Model' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Model' . DS)
- ));
- CakePlugin::load('TestPlugin');
- App::uses('TestPluginAppController', 'TestPlugin.Controller');
- App::uses('TestPluginController', 'TestPlugin.Controller');
-
- $Controller = new TestPluginController();
- $Controller->plugin = 'TestPlugin';
- $Controller->uses = false;
-
- $this->assertFalse(isset($Controller->Comment));
-
- $result = $Controller->loadModel('Comment');
- $this->assertTrue($result);
- $this->assertInstanceOf('Comment', $Controller->Comment);
- $this->assertTrue(in_array('Comment', $Controller->uses));
-
- ClassRegistry::flush();
- unset($Controller);
- }
-
-/**
- * testConstructClasses method
- *
- * @return void
- */
- public function testConstructClasses() {
- $request = new CakeRequest('controller_posts/index');
-
- $Controller = new Controller($request);
- $Controller->uses = array('ControllerPost', 'ControllerComment');
- $Controller->constructClasses();
- $this->assertTrue(is_a($Controller->ControllerPost, 'ControllerPost'));
- $this->assertTrue(is_a($Controller->ControllerComment, 'ControllerComment'));
-
- $this->assertEquals('Comment', $Controller->ControllerComment->name);
-
- unset($Controller);
-
- App::build(array('Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)));
- CakePlugin::load('TestPlugin');
-
- $Controller = new Controller($request);
- $Controller->uses = array('TestPlugin.TestPluginPost');
- $Controller->constructClasses();
-
- $this->assertTrue(isset($Controller->TestPluginPost));
- $this->assertTrue(is_a($Controller->TestPluginPost, 'TestPluginPost'));
- }
-
-/**
- * testAliasName method
- *
- * @return void
- */
- public function testAliasName() {
- $request = new CakeRequest('controller_posts/index');
- $Controller = new Controller($request);
- $Controller->uses = array('NameTest');
- $Controller->constructClasses();
-
- $this->assertEquals('Name', $Controller->NameTest->name);
- $this->assertEquals('Name', $Controller->NameTest->alias);
-
- unset($Controller);
- }
-
-/**
- * testFlash method
- *
- * @return void
- */
- public function testFlash() {
- $request = new CakeRequest('controller_posts/index');
- $request->webroot = '/';
- $request->base = '/';
-
- $Controller = new Controller($request, $this->getMock('CakeResponse', array('_sendHeader')));
- $Controller->flash('this should work', '/flash');
- $result = $Controller->response->body();
-
- $expected = '
-
-
-
- this should work
-
-
-
- this should work
-
- ';
- $result = str_replace(array("\t", "\r\n", "\n"), "", $result);
- $expected = str_replace(array("\t", "\r\n", "\n"), "", $expected);
- $this->assertEquals($expected, $result);
-
- App::build(array(
- 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
- ));
- $Controller = new Controller($request);
- $Controller->response = $this->getMock('CakeResponse', array('_sendHeader'));
- $Controller->flash('this should work', '/flash', 1, 'ajax2');
- $result = $Controller->response->body();
- $this->assertRegExp('/Ajax!/', $result);
- App::build();
- }
-
-/**
- * testControllerSet method
- *
- * @return void
- */
- public function testControllerSet() {
- $request = new CakeRequest('controller_posts/index');
- $Controller = new Controller($request);
-
- $Controller->set('variable_with_underscores', null);
- $this->assertTrue(array_key_exists('variable_with_underscores', $Controller->viewVars));
-
- $Controller->viewVars = array();
- $viewVars = array('ModelName' => array('id' => 1, 'name' => 'value'));
- $Controller->set($viewVars);
- $this->assertTrue(array_key_exists('ModelName', $Controller->viewVars));
-
- $Controller->viewVars = array();
- $Controller->set('variable_with_underscores', 'value');
- $this->assertTrue(array_key_exists('variable_with_underscores', $Controller->viewVars));
-
- $Controller->viewVars = array();
- $viewVars = array('ModelName' => 'name');
- $Controller->set($viewVars);
- $this->assertTrue(array_key_exists('ModelName', $Controller->viewVars));
-
- $Controller->set('title', 'someTitle');
- $this->assertSame($Controller->viewVars['title'], 'someTitle');
- $this->assertTrue(empty($Controller->pageTitle));
-
- $Controller->viewVars = array();
- $expected = array('ModelName' => 'name', 'ModelName2' => 'name2');
- $Controller->set(array('ModelName', 'ModelName2'), array('name', 'name2'));
- $this->assertSame($expected, $Controller->viewVars);
-
- $Controller->viewVars = array();
- $Controller->set(array(3 => 'three', 4 => 'four'));
- $Controller->set(array(1 => 'one', 2 => 'two'));
- $expected = array(3 => 'three', 4 => 'four', 1 => 'one', 2 => 'two');
- $this->assertEquals($expected, $Controller->viewVars);
- }
-
-/**
- * testRender method
- *
- * @return void
- */
- public function testRender() {
- App::build(array(
- 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
- ), App::RESET);
- ClassRegistry::flush();
- $request = new CakeRequest('controller_posts/index');
- $request->params['action'] = 'index';
-
- $Controller = new Controller($request, new CakeResponse());
- $Controller->viewPath = 'Posts';
-
- $result = $Controller->render('index');
- $this->assertRegExp('/posts index/', (string)$result);
-
- $Controller->view = 'index';
- $result = $Controller->render();
- $this->assertRegExp('/posts index/', (string)$result);
-
- $result = $Controller->render('/Elements/test_element');
- $this->assertRegExp('/this is the test element/', (string)$result);
- $Controller->view = null;
-
- $Controller = new TestController($request, new CakeResponse());
- $Controller->uses = array('ControllerAlias', 'TestPlugin.ControllerComment', 'ControllerPost');
- $Controller->helpers = array('Html');
- $Controller->constructClasses();
- $Controller->ControllerComment->validationErrors = array('title' => 'tooShort');
- $expected = $Controller->ControllerComment->validationErrors;
-
- $Controller->viewPath = 'Posts';
- $result = $Controller->render('index');
- $View = $Controller->View;
- $this->assertTrue(isset($View->validationErrors['ControllerComment']));
- $this->assertEquals($expected, $View->validationErrors['ControllerComment']);
-
- $expectedModels = array(
- 'ControllerAlias' => array('plugin' => null, 'className' => 'ControllerAlias'),
- 'ControllerComment' => array('plugin' => 'TestPlugin', 'className' => 'ControllerComment'),
- 'ControllerPost' => array('plugin' => null, 'className' => 'ControllerPost')
- );
- $this->assertEquals($expectedModels, $Controller->request->params['models']);
-
- ClassRegistry::flush();
- App::build();
- }
-
-/**
- * test that a component beforeRender can change the controller view class.
- *
- * @return void
- */
- public function testComponentBeforeRenderChangingViewClass() {
- App::build(array(
- 'View' => array(
- CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS
- )
- ), true);
- $Controller = new Controller($this->getMock('CakeRequest'), new CakeResponse());
- $Controller->uses = array();
- $Controller->components = array('Test');
- $Controller->constructClasses();
- $Controller->Test->viewclass = 'Theme';
- $Controller->viewPath = 'Posts';
- $Controller->theme = 'TestTheme';
- $result = $Controller->render('index');
- $this->assertRegExp('/default test_theme layout/', (string)$result);
- App::build();
- }
-
-/**
- * test that a component beforeRender can change the controller view class.
- *
- * @return void
- */
- public function testComponentCancelRender() {
- $Controller = new Controller($this->getMock('CakeRequest'), new CakeResponse());
- $Controller->uses = array();
- $Controller->components = array('Test2');
- $Controller->constructClasses();
- $result = $Controller->render('index');
- $this->assertInstanceOf('CakeResponse', $result);
- }
-
-/**
- * testToBeInheritedGuardmethods method
- *
- * @return void
- */
- public function testToBeInheritedGuardmethods() {
- $request = new CakeRequest('controller_posts/index');
-
- $Controller = new Controller($request, $this->getMock('CakeResponse'));
- $this->assertTrue($Controller->beforeScaffold(''));
- $this->assertTrue($Controller->afterScaffoldSave(''));
- $this->assertTrue($Controller->afterScaffoldSaveError(''));
- $this->assertFalse($Controller->scaffoldError(''));
- }
-
-/**
- * Generates status codes for redirect test.
- *
- * @return void
- */
- public static function statusCodeProvider() {
- return array(
- array(300, "Multiple Choices"),
- array(301, "Moved Permanently"),
- array(302, "Found"),
- array(303, "See Other"),
- array(304, "Not Modified"),
- array(305, "Use Proxy"),
- array(307, "Temporary Redirect")
- );
- }
-
-/**
- * testRedirect method
- *
- * @dataProvider statusCodeProvider
- * @return void
- */
- public function testRedirectByCode($code, $msg) {
- $Controller = new Controller(null);
- $Controller->response = $this->getMock('CakeResponse', array('header', 'statusCode'));
-
- $Controller->Components = $this->getMock('ComponentCollection', array('trigger'));
-
- $Controller->response->expects($this->once())->method('statusCode')
- ->with($code);
- $Controller->response->expects($this->once())->method('header')
- ->with('Location', 'http://cakephp.org');
-
- $Controller->redirect('http://cakephp.org', (int)$code, false);
- $this->assertFalse($Controller->autoRender);
- }
-
-/**
- * test redirecting by message
- *
- * @dataProvider statusCodeProvider
- * @return void
- */
- public function testRedirectByMessage($code, $msg) {
- $Controller = new Controller(null);
- $Controller->response = $this->getMock('CakeResponse', array('header', 'statusCode'));
-
- $Controller->Components = $this->getMock('ComponentCollection', array('trigger'));
-
- $Controller->response->expects($this->once())->method('statusCode')
- ->with($code);
-
- $Controller->response->expects($this->once())->method('header')
- ->with('Location', 'http://cakephp.org');
-
- $Controller->redirect('http://cakephp.org', $msg, false);
- $this->assertFalse($Controller->autoRender);
- }
-
-/**
- * test that redirect triggers methods on the components.
- *
- * @return void
- */
- public function testRedirectTriggeringComponentsReturnNull() {
- $Controller = new Controller(null);
- $Controller->response = $this->getMock('CakeResponse', array('header', 'statusCode'));
- $Controller->Components = $this->getMock('ComponentCollection', array('trigger'));
-
- $Controller->Components->expects($this->once())->method('trigger')
- ->will($this->returnValue(null));
-
- $Controller->response->expects($this->once())->method('statusCode')
- ->with(301);
-
- $Controller->response->expects($this->once())->method('header')
- ->with('Location', 'http://cakephp.org');
-
- $Controller->redirect('http://cakephp.org', 301, false);
- }
-
-/**
- * test that beforeRedirect callback returning null doesn't affect things.
- *
- * @return void
- */
- public function testRedirectBeforeRedirectModifyingParams() {
- $Controller = new Controller(null);
- $Controller->response = $this->getMock('CakeResponse', array('header', 'statusCode'));
- $Controller->Components = $this->getMock('ComponentCollection', array('trigger'));
-
- $Controller->Components->expects($this->once())->method('trigger')
- ->will($this->returnValue(array('http://book.cakephp.org')));
-
- $Controller->response->expects($this->once())->method('statusCode')
- ->with(301);
-
- $Controller->response->expects($this->once())->method('header')
- ->with('Location', 'http://book.cakephp.org');
-
- $Controller->redirect('http://cakephp.org', 301, false);
- }
-
-/**
- * test that beforeRedirect callback returning null doesn't affect things.
- *
- * @return void
- */
- public function testRedirectBeforeRedirectModifyingParamsArrayReturn() {
- $Controller = $this->getMock('Controller', array('header', '_stop'));
- $Controller->response = $this->getMock('CakeResponse');
- $Controller->Components = $this->getMock('ComponentCollection', array('trigger'));
-
- $return = array(
- array(
- 'url' => 'http://example.com/test/1',
- 'exit' => false,
- 'status' => 302
- ),
- array(
- 'url' => 'http://example.com/test/2',
- ),
- );
- $Controller->Components->expects($this->once())->method('trigger')
- ->will($this->returnValue($return));
-
- $Controller->response->expects($this->once())->method('header')
- ->with('Location', 'http://example.com/test/2');
-
- $Controller->response->expects($this->at(1))->method('statusCode')
- ->with(302);
-
- $Controller->expects($this->never())->method('_stop');
- $Controller->redirect('http://cakephp.org', 301);
- }
-
-/**
- * test that beforeRedirect callback returning false in controller
- *
- * @return void
- */
- public function testRedirectBeforeRedirectInController() {
- $Controller = $this->getMock('Controller', array('_stop', 'beforeRedirect'));
- $Controller->response = $this->getMock('CakeResponse', array('header'));
- $Controller->Components = $this->getMock('ComponentCollection', array('trigger'));
-
- $Controller->expects($this->once())->method('beforeRedirect')
- ->with('http://cakephp.org')
- ->will($this->returnValue(false));
- $Controller->response->expects($this->never())->method('header');
- $Controller->expects($this->never())->method('_stop');
- $Controller->redirect('http://cakephp.org');
- }
-
-/**
- * testMergeVars method
- *
- * @return void
- */
- public function testMergeVars() {
- $request = new CakeRequest('controller_posts/index');
-
- $TestController = new TestController($request);
- $TestController->constructClasses();
-
- $testVars = get_class_vars('TestController');
- $appVars = get_class_vars('ControllerTestAppController');
-
- $components = is_array($appVars['components'])
- ? array_merge($appVars['components'], $testVars['components'])
- : $testVars['components'];
- if (!in_array('Session', $components)) {
- $components[] = 'Session';
- }
- $helpers = is_array($appVars['helpers'])
- ? array_merge($appVars['helpers'], $testVars['helpers'])
- : $testVars['helpers'];
- $uses = is_array($appVars['uses'])
- ? array_merge($appVars['uses'], $testVars['uses'])
- : $testVars['uses'];
-
- $this->assertEquals(0, count(array_diff_key($TestController->helpers, array_flip($helpers))));
- $this->assertEquals(0, count(array_diff($TestController->uses, $uses)));
- $this->assertEquals(count(array_diff_assoc(Set::normalize($TestController->components), Set::normalize($components))), 0);
-
- $expected = array('ControllerComment', 'ControllerAlias', 'ControllerPost');
- $this->assertEquals($expected, $TestController->uses, '$uses was merged incorrectly, ControllerTestAppController models should be last.');
-
- $TestController = new AnotherTestController($request);
- $TestController->constructClasses();
-
- $appVars = get_class_vars('ControllerTestAppController');
- $testVars = get_class_vars('AnotherTestController');
-
- $this->assertTrue(in_array('ControllerPost', $appVars['uses']));
- $this->assertFalse($testVars['uses']);
-
- $this->assertFalse(property_exists($TestController, 'ControllerPost'));
-
- $TestController = new ControllerCommentsController($request);
- $TestController->constructClasses();
-
- $appVars = get_class_vars('ControllerTestAppController');
- $testVars = get_class_vars('ControllerCommentsController');
-
- $this->assertTrue(in_array('ControllerPost', $appVars['uses']));
- $this->assertEquals(array('ControllerPost'), $testVars['uses']);
-
- $this->assertTrue(isset($TestController->ControllerPost));
- $this->assertTrue(isset($TestController->ControllerComment));
- }
-
-/**
- * test that options from child classes replace those in the parent classes.
- *
- * @return void
- */
- public function testChildComponentOptionsSupercedeParents() {
- $request = new CakeRequest('controller_posts/index');
-
- $TestController = new TestController($request);
-
- $expected = array('foo');
- $TestController->components = array('Cookie' => $expected);
- $TestController->constructClasses();
- $this->assertEquals($expected, $TestController->components['Cookie']);
- }
-
-/**
- * Ensure that _mergeControllerVars is not being greedy and merging with
- * ControllerTestAppController when you make an instance of Controller
- *
- * @return void
- */
- public function testMergeVarsNotGreedy() {
- $request = new CakeRequest('controller_posts/index');
-
- $Controller = new Controller($request);
- $Controller->components = array();
- $Controller->uses = array();
- $Controller->constructClasses();
-
- $this->assertFalse(isset($Controller->Session));
- }
-
-/**
- * testReferer method
- *
- * @return void
- */
- public function testReferer() {
- $request = $this->getMock('CakeRequest');
-
- $request->expects($this->any())->method('referer')
- ->with(true)
- ->will($this->returnValue('/posts/index'));
-
- $Controller = new Controller($request);
- $result = $Controller->referer(null, true);
- $this->assertEquals('/posts/index', $result);
-
- $Controller = new Controller($request);
- $request->setReturnValue('referer', '/', array(true));
- $result = $Controller->referer(array('controller' => 'posts', 'action' => 'index'), true);
- $this->assertEquals('/posts/index', $result);
-
- $request = $this->getMock('CakeRequest');
-
- $request->expects($this->any())->method('referer')
- ->with(false)
- ->will($this->returnValue('http://localhost/posts/index'));
-
- $Controller = new Controller($request);
- $result = $Controller->referer();
- $this->assertEquals('http://localhost/posts/index', $result);
-
- $Controller = new Controller(null);
- $result = $Controller->referer();
- $this->assertEquals('/', $result);
- }
-
-/**
- * testSetAction method
- *
- * @return void
- */
- public function testSetAction() {
- $request = new CakeRequest('controller_posts/index');
-
- $TestController = new TestController($request);
- $TestController->setAction('view', 1, 2);
- $expected = array('testId' => 1, 'test2Id' => 2);
- $this->assertSame($expected, $TestController->request->data);
- $this->assertSame('view', $TestController->request->params['action']);
- $this->assertSame('view', $TestController->view);
- }
-
-/**
- * testValidateErrors method
- *
- * @return void
- */
- public function testValidateErrors() {
- ClassRegistry::flush();
- $request = new CakeRequest('controller_posts/index');
-
- $TestController = new TestController($request);
- $TestController->constructClasses();
- $this->assertFalse($TestController->validateErrors());
- $this->assertEquals(0, $TestController->validate());
-
- $TestController->ControllerComment->invalidate('some_field', 'error_message');
- $TestController->ControllerComment->invalidate('some_field2', 'error_message2');
-
- $comment = new ControllerComment($request);
- $comment->set('someVar', 'data');
- $result = $TestController->validateErrors($comment);
- $expected = array('some_field' => array('error_message'), 'some_field2' => array('error_message2'));
- $this->assertSame($expected, $result);
- $this->assertEquals(2, $TestController->validate($comment));
- }
-
-/**
- * test that validateErrors works with any old model.
- *
- * @return void
- */
- public function testValidateErrorsOnArbitraryModels() {
- $TestController = new TestController();
-
- $Post = new ControllerPost();
- $Post->validate = array('title' => 'notEmpty');
- $Post->set('title', '');
- $result = $TestController->validateErrors($Post);
-
- $expected = array('title' => array('This field cannot be left blank'));
- $this->assertEquals($expected, $result);
- }
-
-/**
- * testPostConditions method
- *
- * @return void
- */
- public function testPostConditions() {
- $request = new CakeRequest('controller_posts/index');
-
- $Controller = new Controller($request);
-
- $data = array(
- 'Model1' => array('field1' => '23'),
- 'Model2' => array('field2' => 'string'),
- 'Model3' => array('field3' => '23'),
- );
- $expected = array(
- 'Model1.field1' => '23',
- 'Model2.field2' => 'string',
- 'Model3.field3' => '23',
- );
- $result = $Controller->postConditions($data);
- $this->assertSame($expected, $result);
-
- $data = array();
- $Controller->data = array(
- 'Model1' => array('field1' => '23'),
- 'Model2' => array('field2' => 'string'),
- 'Model3' => array('field3' => '23'),
- );
- $expected = array(
- 'Model1.field1' => '23',
- 'Model2.field2' => 'string',
- 'Model3.field3' => '23',
- );
- $result = $Controller->postConditions($data);
- $this->assertSame($expected, $result);
-
- $data = array();
- $Controller->data = array();
- $result = $Controller->postConditions($data);
- $this->assertNull($result);
-
- $data = array();
- $Controller->data = array(
- 'Model1' => array('field1' => '23'),
- 'Model2' => array('field2' => 'string'),
- 'Model3' => array('field3' => '23'),
- );
- $ops = array(
- 'Model1.field1' => '>',
- 'Model2.field2' => 'LIKE',
- 'Model3.field3' => '<=',
- );
- $expected = array(
- 'Model1.field1 >' => '23',
- 'Model2.field2 LIKE' => "%string%",
- 'Model3.field3 <=' => '23',
- );
- $result = $Controller->postConditions($data, $ops);
- $this->assertSame($expected, $result);
- }
-
-/**
- * testControllerHttpCodes method
- *
- * @return void
- */
- public function testControllerHttpCodes() {
- $response = $this->getMock('CakeResponse', array('httpCodes'));
- $Controller = new Controller(null, $response);
- $Controller->response->expects($this->at(0))->method('httpCodes')->with(null);
- $Controller->response->expects($this->at(1))->method('httpCodes')->with(100);
- $Controller->httpCodes();
- $Controller->httpCodes(100);
- }
-
-/**
- * Tests that the startup process calls the correct functions
- *
- * @return void
- */
- public function testStartupProcess() {
- $Controller = $this->getMock('Controller', array('getEventManager'));
-
- $eventManager = $this->getMock('CakeEventManager');
- $eventManager->expects($this->at(0))->method('dispatch')
- ->with(
- $this->logicalAnd(
- $this->isInstanceOf('CakeEvent'),
- $this->attributeEqualTo('_name', 'Controller.initialize'),
- $this->attributeEqualTo('_subject', $Controller)
- )
- );
- $eventManager->expects($this->at(1))->method('dispatch')
- ->with(
- $this->logicalAnd(
- $this->isInstanceOf('CakeEvent'),
- $this->attributeEqualTo('_name', 'Controller.startup'),
- $this->attributeEqualTo('_subject', $Controller)
- )
- );
- $Controller->expects($this->exactly(2))->method('getEventManager')
- ->will($this->returnValue($eventManager));
- $Controller->startupProcess();
- }
-
-/**
- * Tests that the shutdown process calls the correct functions
- *
- * @return void
- */
- public function testStartupProcessIndirect() {
- $Controller = $this->getMock('Controller', array('beforeFilter'));
-
- $Controller->components = array('MockShutdown');
- $Controller->Components = $this->getMock('ComponentCollection', array('trigger'));
-
- $Controller->expects($this->once())->method('beforeFilter');
- $Controller->Components->expects($this->exactly(2))->method('trigger')->with($this->isInstanceOf('CakeEvent'));
-
- $Controller->startupProcess();
- }
-
-/**
- * Tests that the shutdown process calls the correct functions
- *
- * @return void
- */
- public function testShutdownProcess() {
- $Controller = $this->getMock('Controller', array('getEventManager'));
-
- $eventManager = $this->getMock('CakeEventManager');
- $eventManager->expects($this->once())->method('dispatch')
- ->with(
- $this->logicalAnd(
- $this->isInstanceOf('CakeEvent'),
- $this->attributeEqualTo('_name', 'Controller.shutdown'),
- $this->attributeEqualTo('_subject', $Controller)
- )
- );
- $Controller->expects($this->once())->method('getEventManager')
- ->will($this->returnValue($eventManager));
- $Controller->shutdownProcess();
- }
-
-/**
- * Tests that the shutdown process calls the correct functions
- *
- * @return void
- */
- public function testShutdownProcessIndirect() {
- $Controller = $this->getMock('Controller', array('afterFilter'));
-
- $Controller->components = array('MockShutdown');
- $Controller->Components = $this->getMock('ComponentCollection', array('trigger'));
-
- $Controller->expects($this->once())->method('afterFilter');
- $Controller->Components->expects($this->exactly(1))->method('trigger')->with($this->isInstanceOf('CakeEvent'));
-
- $Controller->shutdownProcess();
- }
-
-/**
- * test that BC works for attributes on the request object.
- *
- * @return void
- */
- public function testPropertyBackwardsCompatibility() {
- $request = new CakeRequest('posts/index', null);
- $request->addParams(array('controller' => 'posts', 'action' => 'index'));
- $request->data = array('Post' => array('id' => 1));
- $request->here = '/posts/index';
- $request->webroot = '/';
-
- $Controller = new TestController($request);
- $this->assertEquals($request->data, $Controller->data);
- $this->assertEquals($request->webroot, $Controller->webroot);
- $this->assertEquals($request->here, $Controller->here);
- $this->assertEquals($request->action, $Controller->action);
-
- $this->assertFalse(empty($Controller->data));
- $this->assertTrue(isset($Controller->data));
- $this->assertTrue(empty($Controller->something));
- $this->assertFalse(isset($Controller->something));
-
- $this->assertEquals($request, $Controller->params);
- $this->assertEquals($request->params['controller'], $Controller->params['controller']);
- }
-
-/**
- * test that the BC wrapper doesn't interfere with models and components.
- *
- * @return void
- */
- public function testPropertyCompatibilityAndModelsComponents() {
- $request = new CakeRequest('controller_posts/index');
-
- $Controller = new TestController($request);
- $Controller->constructClasses();
- $this->assertInstanceOf('SecurityComponent', $Controller->Security);
- $this->assertInstanceOf('ControllerComment', $Controller->ControllerComment);
- }
-
-/**
- * test that using Controller::paginate() falls back to PaginatorComponent
- *
- * @return void
- */
- public function testPaginateBackwardsCompatibility() {
- $request = new CakeRequest('controller_posts/index');
- $request->params['pass'] = $request->params['named'] = array();
- $response = $this->getMock('CakeResponse', array('httpCodes'));
-
- $Controller = new Controller($request, $response);
- $Controller->uses = array('ControllerPost', 'ControllerComment');
- $Controller->passedArgs[] = '1';
- $Controller->params['url'] = array();
- $Controller->constructClasses();
- $expected = array('page' => 1, 'limit' => 20, 'maxLimit' => 100, 'paramType' => 'named');
- $this->assertEquals($expected, $Controller->paginate);
-
- $results = Set::extract($Controller->paginate('ControllerPost'), '{n}.ControllerPost.id');
- $this->assertEquals(array(1, 2, 3), $results);
-
- $Controller->passedArgs = array();
- $Controller->paginate = array('limit' => '-1');
- $this->assertEquals(array('limit' => '-1'), $Controller->paginate);
- $Controller->paginate('ControllerPost');
- $this->assertSame($Controller->params['paging']['ControllerPost']['page'], 1);
- $this->assertSame($Controller->params['paging']['ControllerPost']['pageCount'], 3);
- $this->assertSame($Controller->params['paging']['ControllerPost']['prevPage'], false);
- $this->assertSame($Controller->params['paging']['ControllerPost']['nextPage'], true);
- }
-
-/**
- * testMissingAction method
- *
- * @expectedException MissingActionException
- * @expectedExceptionMessage Action TestController::missing() could not be found.
- * @return void
- */
- public function testInvokeActionMissingAction() {
- $url = new CakeRequest('test/missing');
- $url->addParams(array('controller' => 'test_controller', 'action' => 'missing'));
- $response = $this->getMock('CakeResponse');
-
- $Controller = new TestController($url, $response);
- $Controller->invokeAction($url);
- }
-
-/**
- * test invoking private methods.
- *
- * @expectedException PrivateActionException
- * @expectedExceptionMessage Private Action TestController::private_m() is not directly accessible.
- * @return void
- */
- public function testInvokeActionPrivate() {
- $url = new CakeRequest('test/private_m/');
- $url->addParams(array('controller' => 'test_controller', 'action' => 'private_m'));
- $response = $this->getMock('CakeResponse');
-
- $Controller = new TestController($url, $response);
- $Controller->invokeAction($url);
- }
-
-/**
- * test invoking protected methods.
- *
- * @expectedException PrivateActionException
- * @expectedExceptionMessage Private Action TestController::protected_m() is not directly accessible.
- * @return void
- */
- public function testInvokeActionProtected() {
- $url = new CakeRequest('test/protected_m/');
- $url->addParams(array('controller' => 'test_controller', 'action' => 'protected_m'));
- $response = $this->getMock('CakeResponse');
-
- $Controller = new TestController($url, $response);
- $Controller->invokeAction($url);
- }
-
-/**
- * test invoking hidden methods.
- *
- * @expectedException PrivateActionException
- * @expectedExceptionMessage Private Action TestController::_hidden() is not directly accessible.
- * @return void
- */
- public function testInvokeActionHidden() {
- $url = new CakeRequest('test/_hidden/');
- $url->addParams(array('controller' => 'test_controller', 'action' => '_hidden'));
- $response = $this->getMock('CakeResponse');
-
- $Controller = new TestController($url, $response);
- $Controller->invokeAction($url);
- }
-
-/**
- * test invoking controller methods.
- *
- * @expectedException PrivateActionException
- * @expectedExceptionMessage Private Action TestController::redirect() is not directly accessible.
- * @return void
- */
- public function testInvokeActionBaseMethods() {
- $url = new CakeRequest('test/redirect/');
- $url->addParams(array('controller' => 'test_controller', 'action' => 'redirect'));
- $response = $this->getMock('CakeResponse');
-
- $Controller = new TestController($url, $response);
- $Controller->invokeAction($url);
- }
-
-/**
- * test invoking controller methods.
- *
- * @expectedException PrivateActionException
- * @expectedExceptionMessage Private Action TestController::admin_add() is not directly accessible.
- * @return void
- */
- public function testInvokeActionPrefixProtection() {
- Router::reload();
- Router::connect('/admin/:controller/:action/*', array('prefix' => 'admin'));
-
- $url = new CakeRequest('test/admin_add/');
- $url->addParams(array('controller' => 'test_controller', 'action' => 'admin_add'));
- $response = $this->getMock('CakeResponse');
-
- $Controller = new TestController($url, $response);
- $Controller->invokeAction($url);
- }
-
-/**
- * test invoking controller methods.
- *
- * @return void
- */
- public function testInvokeActionReturnValue() {
- $url = new CakeRequest('test/returner/');
- $url->addParams(array(
- 'controller' => 'test_controller',
- 'action' => 'returner',
- 'pass' => array()
- ));
- $response = $this->getMock('CakeResponse');
-
- $Controller = new TestController($url, $response);
- $result = $Controller->invokeAction($url);
- $this->assertEquals('I am from the controller.', $result);
- }
-
-}
diff --git a/lib/Cake/Test/Case/Controller/PagesControllerTest.php b/lib/Cake/Test/Case/Controller/PagesControllerTest.php
deleted file mode 100644
index 829a940d963..00000000000
--- a/lib/Cake/Test/Case/Controller/PagesControllerTest.php
+++ /dev/null
@@ -1,53 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Controller
- * @since CakePHP(tm) v 1.2.0.5436
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('PagesController', 'Controller');
-
-/**
- * PagesControllerTest class
- *
- * @package Cake.Test.Case.Controller
- */
-class PagesControllerTest extends CakeTestCase {
-
-/**
- * testDisplay method
- *
- * @return void
- */
- public function testDisplay() {
- App::build(array(
- 'View' => array(
- CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS
- )
- ));
- $Pages = new PagesController(new CakeRequest(null, false), new CakeResponse());
-
- $Pages->viewPath = 'Posts';
- $Pages->display('index');
- $this->assertRegExp('/posts index/', $Pages->response->body());
- $this->assertEquals('index', $Pages->viewVars['page']);
-
- $Pages->viewPath = 'Themed';
- $Pages->display('TestTheme', 'Posts', 'index');
- $this->assertRegExp('/posts index themed view/', $Pages->response->body());
- $this->assertEquals('TestTheme', $Pages->viewVars['page']);
- $this->assertEquals('Posts', $Pages->viewVars['subpage']);
- }
-}
diff --git a/lib/Cake/Test/Case/Controller/ScaffoldTest.php b/lib/Cake/Test/Case/Controller/ScaffoldTest.php
deleted file mode 100644
index cd5ac89cb46..00000000000
--- a/lib/Cake/Test/Case/Controller/ScaffoldTest.php
+++ /dev/null
@@ -1,350 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Controller
- * @since CakePHP(tm) v 1.2.0.5436
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-App::uses('Router', 'Routing');
-App::uses('Controller', 'Controller');
-App::uses('Scaffold', 'Controller');
-App::uses('ScaffoldView', 'View');
-App::uses('AppModel', 'Model');
-
-require_once dirname(dirname(__FILE__)) . DS . 'Model' . DS . 'models.php';
-
-/**
- * ScaffoldMockController class
- *
- * @package Cake.Test.Case.Controller
- */
-class ScaffoldMockController extends Controller {
-
-/**
- * name property
- *
- * @var string 'ScaffoldMock'
- */
- public $name = 'ScaffoldMock';
-
-/**
- * scaffold property
- *
- * @var mixed
- */
- public $scaffold;
-}
-
-/**
- * ScaffoldMockControllerWithFields class
- *
- * @package Cake.Test.Case.Controller
- */
-class ScaffoldMockControllerWithFields extends Controller {
-
-/**
- * name property
- *
- * @var string 'ScaffoldMock'
- */
- public $name = 'ScaffoldMock';
-
-/**
- * scaffold property
- *
- * @var mixed
- */
- public $scaffold;
-
-/**
- * function beforeScaffold
- *
- * @param string method
- */
- public function beforeScaffold($method) {
- $this->set('scaffoldFields', array('title'));
- return true;
- }
-
-}
-
-/**
- * TestScaffoldMock class
- *
- * @package Cake.Test.Case.Controller
- */
-class TestScaffoldMock extends Scaffold {
-
-/**
- * Overload _scaffold
- *
- * @param unknown_type $params
- */
- protected function _scaffold(CakeRequest $request) {
- $this->_params = $request;
- }
-
-/**
- * Get Params from the Controller.
- *
- * @return unknown
- */
- public function getParams() {
- return $this->_params;
- }
-
-}
-
-/**
- * Scaffold Test class
- *
- * @package Cake.Test.Case.Controller
- */
-class ScaffoldTest extends CakeTestCase {
-
-/**
- * Controller property
- *
- * @var SecurityTestController
- */
- public $Controller;
-
-/**
- * fixtures property
- *
- * @var array
- */
- public $fixtures = array('core.article', 'core.user', 'core.comment', 'core.join_thing', 'core.tag');
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- $request = new CakeRequest(null, false);
- $this->Controller = new ScaffoldMockController($request);
- $this->Controller->response = $this->getMock('CakeResponse', array('_sendHeader'));
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- parent::tearDown();
- unset($this->Controller);
- }
-
-/**
- * Test the correct Generation of Scaffold Params.
- * This ensures that the correct action and view will be generated
- *
- * @return void
- */
- public function testScaffoldParams() {
- $params = array(
- 'plugin' => null,
- 'pass' => array(),
- 'form' => array(),
- 'named' => array(),
- 'url' => array('url' => 'admin/scaffold_mock/edit'),
- 'controller' => 'scaffold_mock',
- 'action' => 'admin_edit',
- 'admin' => true,
- );
- $this->Controller->request->base = '';
- $this->Controller->request->webroot = '/';
- $this->Controller->request->here = '/admin/scaffold_mock/edit';
- $this->Controller->request->addParams($params);
-
- //set router.
- Router::setRequestInfo($this->Controller->request);
-
- $this->Controller->constructClasses();
- $Scaffold = new TestScaffoldMock($this->Controller, $this->Controller->request);
- $result = $Scaffold->getParams();
- $this->assertEquals('admin_edit', $result['action']);
- }
-
-/**
- * test that the proper names and variable values are set by Scaffold
- *
- * @return void
- */
- public function testScaffoldVariableSetting() {
- $params = array(
- 'plugin' => null,
- 'pass' => array(),
- 'form' => array(),
- 'named' => array(),
- 'url' => array('url' => 'admin/scaffold_mock/edit'),
- 'controller' => 'scaffold_mock',
- 'action' => 'admin_edit',
- 'admin' => true,
- );
- $this->Controller->request->base = '';
- $this->Controller->request->webroot = '/';
- $this->Controller->request->here = '/admin/scaffold_mock/edit';
- $this->Controller->request->addParams($params);
-
- //set router.
- Router::setRequestInfo($this->Controller->request);
-
- $this->Controller->constructClasses();
- $Scaffold = new TestScaffoldMock($this->Controller, $this->Controller->request);
- $result = $Scaffold->controller->viewVars;
-
- $this->assertEquals('Scaffold :: Admin Edit :: Scaffold Mock', $result['title_for_layout']);
- $this->assertEquals('Scaffold Mock', $result['singularHumanName']);
- $this->assertEquals('Scaffold Mock', $result['pluralHumanName']);
- $this->assertEquals('ScaffoldMock', $result['modelClass']);
- $this->assertEquals('id', $result['primaryKey']);
- $this->assertEquals('title', $result['displayField']);
- $this->assertEquals('scaffoldMock', $result['singularVar']);
- $this->assertEquals('scaffoldMock', $result['pluralVar']);
- $this->assertEquals(array('id', 'user_id', 'title', 'body', 'published', 'created', 'updated'), $result['scaffoldFields']);
- }
-
-/**
- * test that Scaffold overrides the view property even if its set to 'Theme'
- *
- * @return void
- */
- public function testScaffoldChangingViewProperty() {
- $this->Controller->action = 'edit';
- $this->Controller->theme = 'TestTheme';
- $this->Controller->viewClass = 'Theme';
- $this->Controller->constructClasses();
- $Scaffold = new TestScaffoldMock($this->Controller, $this->Controller->request);
-
- $this->assertEquals('Scaffold', $this->Controller->viewClass);
- }
-
-/**
- * test that scaffold outputs flash messages when sessions are unset.
- *
- * @return void
- */
- public function testScaffoldFlashMessages() {
- $params = array(
- 'plugin' => null,
- 'pass' => array(1),
- 'form' => array(),
- 'named' => array(),
- 'url' => array('url' => 'scaffold_mock'),
- 'controller' => 'scaffold_mock',
- 'action' => 'edit',
- );
- $this->Controller->request->base = '';
- $this->Controller->request->webroot = '/';
- $this->Controller->request->here = '/scaffold_mock/edit';
- $this->Controller->request->addParams($params);
-
- //set router.
- Router::reload();
- Router::setRequestInfo($this->Controller->request);
- $this->Controller->request->data = array(
- 'ScaffoldMock' => array(
- 'id' => 1,
- 'title' => 'New title',
- 'body' => 'new body'
- )
- );
- $this->Controller->constructClasses();
- unset($this->Controller->Session);
-
- ob_start();
- new Scaffold($this->Controller, $this->Controller->request);
- $this->Controller->response->send();
- $result = ob_get_clean();
- $this->assertRegExp('/Scaffold Mock has been updated/', $result);
- }
-
-/**
- * test that habtm relationship keys get added to scaffoldFields.
- *
- * @return void
- */
- public function testHabtmFieldAdditionWithScaffoldForm() {
- CakePlugin::unload();
- $params = array(
- 'plugin' => null,
- 'pass' => array(1),
- 'form' => array(),
- 'named' => array(),
- 'url' => array('url' => 'scaffold_mock'),
- 'controller' => 'scaffold_mock',
- 'action' => 'edit',
- );
- $this->Controller->request->base = '';
- $this->Controller->request->webroot = '/';
- $this->Controller->request->here = '/scaffold_mock/edit';
- $this->Controller->request->addParams($params);
-
- //set router.
- Router::reload();
- Router::setRequestInfo($this->Controller->request);
-
- $this->Controller->constructClasses();
- ob_start();
- $Scaffold = new Scaffold($this->Controller, $this->Controller->request);
- $this->Controller->response->send();
- $result = ob_get_clean();
- $this->assertRegExp('/name="data\[ScaffoldTag\]\[ScaffoldTag\]"/', $result);
-
- $result = $Scaffold->controller->viewVars;
- $this->assertEquals(array('id', 'user_id', 'title', 'body', 'published', 'created', 'updated', 'ScaffoldTag'), $result['scaffoldFields']);
- }
-
-/**
- * test that the proper names and variable values are set by Scaffold
- *
- * @return void
- */
- public function testEditScaffoldWithScaffoldFields() {
- $request = new CakeRequest(null, false);
- $this->Controller = new ScaffoldMockControllerWithFields($request);
- $this->Controller->response = $this->getMock('CakeResponse', array('_sendHeader'));
-
- $params = array(
- 'plugin' => null,
- 'pass' => array(1),
- 'form' => array(),
- 'named' => array(),
- 'url' => array('url' => 'scaffold_mock/edit'),
- 'controller' => 'scaffold_mock',
- 'action' => 'edit',
- );
- $this->Controller->request->base = '';
- $this->Controller->request->webroot = '/';
- $this->Controller->request->here = '/scaffold_mock/edit';
- $this->Controller->request->addParams($params);
-
- //set router.
- Router::reload();
- Router::setRequestInfo($this->Controller->request);
-
- $this->Controller->constructClasses();
- ob_start();
- new Scaffold($this->Controller, $this->Controller->request);
- $this->Controller->response->send();
- $result = ob_get_clean();
-
- $this->assertNotRegExp('/textarea name="data\[ScaffoldMock\]\[body\]" cols="30" rows="6" id="ScaffoldMockBody"/', $result);
- }
-
-}
diff --git a/lib/Cake/Test/Case/Core/AppTest.php b/lib/Cake/Test/Case/Core/AppTest.php
deleted file mode 100644
index 029537ef27a..00000000000
--- a/lib/Cake/Test/Case/Core/AppTest.php
+++ /dev/null
@@ -1,850 +0,0 @@
-assertEquals($expected, $old);
-
- App::build(array('Model' => array('/path/to/models/')));
- $new = App::path('Model');
- $expected = array(
- '/path/to/models/',
- APP . 'Model' . DS
- );
- $this->assertEquals($expected, $new);
-
- App::build();
- App::build(array('Model' => array('/path/to/models/')), App::PREPEND);
- $new = App::path('Model');
- $expected = array(
- '/path/to/models/',
- APP . 'Model' . DS
- );
- $this->assertEquals($expected, $new);
-
- App::build();
- App::build(array('Model' => array('/path/to/models/')), App::APPEND);
- $new = App::path('Model');
- $expected = array(
- APP . 'Model' . DS,
- '/path/to/models/'
- );
- $this->assertEquals($expected, $new);
-
- App::build();
- App::build(array(
- 'Model' => array('/path/to/models/'),
- 'Controller' => array('/path/to/controllers/'),
- ), App::APPEND);
- $new = App::path('Model');
- $expected = array(
- APP . 'Model' . DS,
- '/path/to/models/'
- );
- $this->assertEquals($expected, $new);
- $new = App::path('Controller');
- $expected = array(
- APP . 'Controller' . DS,
- '/path/to/controllers/'
- );
- $this->assertEquals($expected, $new);
-
- App::build(); //reset defaults
- $defaults = App::path('Model');
- $this->assertEquals($old, $defaults);
- }
-
-/**
- * tests that it is possible to set up paths using the cake 1.3 notation for them (models, behaviors, controllers...)
- *
- * @return void
- */
- public function testCompatibleBuild() {
- $old = App::path('models');
- $expected = array(
- APP . 'Model' . DS
- );
- $this->assertEquals($expected, $old);
-
- App::build(array('models' => array('/path/to/models/')));
-
- $new = App::path('models');
-
- $expected = array(
- '/path/to/models/',
- APP . 'Model' . DS
- );
- $this->assertEquals($expected, $new);
- $this->assertEquals($expected, App::path('Model'));
-
- App::build(array('datasources' => array('/path/to/datasources/')));
- $expected = array(
- '/path/to/datasources/',
- APP . 'Model' . DS . 'Datasource' . DS
- );
- $result = App::path('datasources');
- $this->assertEquals($expected, $result);
- $this->assertEquals($expected, App::path('Model/Datasource'));
-
- App::build(array('behaviors' => array('/path/to/behaviors/')));
- $expected = array(
- '/path/to/behaviors/',
- APP . 'Model' . DS . 'Behavior' . DS
- );
- $result = App::path('behaviors');
- $this->assertEquals($expected, $result);
- $this->assertEquals($expected, App::path('Model/Behavior'));
-
- App::build(array('controllers' => array('/path/to/controllers/')));
- $expected = array(
- '/path/to/controllers/',
- APP . 'Controller' . DS
- );
- $result = App::path('controllers');
- $this->assertEquals($expected, $result);
- $this->assertEquals($expected, App::path('Controller'));
-
- App::build(array('components' => array('/path/to/components/')));
- $expected = array(
- '/path/to/components/',
- APP . 'Controller' . DS . 'Component' . DS
- );
- $result = App::path('components');
- $this->assertEquals($expected, $result);
- $this->assertEquals($expected, App::path('Controller/Component'));
-
- App::build(array('views' => array('/path/to/views/')));
- $expected = array(
- '/path/to/views/',
- APP . 'View' . DS
- );
- $result = App::path('views');
- $this->assertEquals($expected, $result);
- $this->assertEquals($expected, App::path('View'));
-
- App::build(array('helpers' => array('/path/to/helpers/')));
- $expected = array(
- '/path/to/helpers/',
- APP . 'View' . DS . 'Helper' . DS
- );
- $result = App::path('helpers');
- $this->assertEquals($expected, $result);
- $this->assertEquals($expected, App::path('View/Helper'));
-
- App::build(array('shells' => array('/path/to/shells/')));
- $expected = array(
- '/path/to/shells/',
- APP . 'Console' . DS . 'Command' . DS
- );
- $result = App::path('shells');
- $this->assertEquals($expected, $result);
- $this->assertEquals($expected, App::path('Console/Command'));
-
- App::build(); //reset defaults
- $defaults = App::path('Model');
- $this->assertEquals($old, $defaults);
- }
-
-/**
- * test package build() with App::REGISTER.
- *
- * @return void
- */
- public function testBuildPackage() {
- $pluginPaths = array(
- '/foo/bar',
- APP . 'Plugin' . DS,
- dirname(dirname(CAKE)) . DS . 'plugins' . DS
- );
- App::build(array(
- 'Plugin' => array(
- '/foo/bar'
- )
- ));
- $result = App::path('Plugin');
- $this->assertEquals($pluginPaths, $result);
-
- $paths = App::path('Service');
- $this->assertEquals(array(), $paths);
-
- App::build(array(
- 'Service' => array(
- '%s' . 'Service' . DS,
- ),
- ), App::REGISTER);
-
- $expected = array(
- APP . 'Service' . DS,
- );
- $result = App::path('Service');
- $this->assertEquals($expected, $result);
-
- //Ensure new paths registered for other packages are not affected
- $result = App::path('Plugin');
- $this->assertEquals($pluginPaths, $result);
-
- App::build();
- $paths = App::path('Service');
- $this->assertEquals(array(), $paths);
- }
-
-/**
- * test path() with a plugin.
- *
- * @return void
- */
- public function testPathWithPlugins() {
- $basepath = CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS;
- App::build(array(
- 'Plugin' => array($basepath),
- ));
- CakePlugin::load('TestPlugin');
-
- $result = App::path('Vendor', 'TestPlugin');
- $this->assertEquals($basepath . 'TestPlugin' . DS . 'Vendor' . DS, $result[0]);
- }
-
-/**
- * testBuildWithReset method
- *
- * @return void
- */
- public function testBuildWithReset() {
- $old = App::path('Model');
- $expected = array(
- APP . 'Model' . DS
- );
- $this->assertEquals($expected, $old);
-
- App::build(array('Model' => array('/path/to/models/')), App::RESET);
-
- $new = App::path('Model');
-
- $expected = array(
- '/path/to/models/'
- );
- $this->assertEquals($expected, $new);
-
- App::build(); //reset defaults
- $defaults = App::path('Model');
- $this->assertEquals($old, $defaults);
- }
-
-/**
- * testCore method
- *
- * @return void
- */
- public function testCore() {
- $model = App::core('Model');
- $this->assertEquals(array(CAKE . 'Model' . DS), $model);
-
- $view = App::core('View');
- $this->assertEquals(array(CAKE . 'View' . DS), $view);
-
- $controller = App::core('Controller');
- $this->assertEquals(array(CAKE . 'Controller' . DS), $controller);
-
- $component = App::core('Controller/Component');
- $this->assertEquals(array(CAKE . 'Controller' . DS . 'Component' . DS), str_replace('/', DS, $component));
-
- $auth = App::core('Controller/Component/Auth');
- $this->assertEquals(array(CAKE . 'Controller' . DS . 'Component' . DS . 'Auth' . DS), str_replace('/', DS, $auth));
-
- $datasource = App::core('Model/Datasource');
- $this->assertEquals(array(CAKE . 'Model' . DS . 'Datasource' . DS), str_replace('/', DS, $datasource));
- }
-
-/**
- * testListObjects method
- *
- * @return void
- */
- public function testListObjects() {
- $result = App::objects('class', CAKE . 'Routing', false);
- $this->assertTrue(in_array('Dispatcher', $result));
- $this->assertTrue(in_array('Router', $result));
-
- App::build(array(
- 'Model/Behavior' => App::core('Model/Behavior'),
- 'Controller' => App::core('Controller'),
- 'Controller/Component' => App::core('Controller/Component'),
- 'View' => App::core('View'),
- 'Model' => App::core('Model'),
- 'View/Helper' => App::core('View/Helper'),
- ), App::RESET);
- $result = App::objects('behavior', null, false);
- $this->assertTrue(in_array('TreeBehavior', $result));
- $result = App::objects('Model/Behavior', null, false);
- $this->assertTrue(in_array('TreeBehavior', $result));
-
- $result = App::objects('component', null, false);
- $this->assertTrue(in_array('AuthComponent', $result));
- $result = App::objects('Controller/Component', null, false);
- $this->assertTrue(in_array('AuthComponent', $result));
-
- $result = App::objects('view', null, false);
- $this->assertTrue(in_array('MediaView', $result));
- $result = App::objects('View', null, false);
- $this->assertTrue(in_array('MediaView', $result));
-
- $result = App::objects('helper', null, false);
- $this->assertTrue(in_array('HtmlHelper', $result));
- $result = App::objects('View/Helper', null, false);
- $this->assertTrue(in_array('HtmlHelper', $result));
-
- $result = App::objects('model', null, false);
- $this->assertTrue(in_array('AcoAction', $result));
- $result = App::objects('Model', null, false);
- $this->assertTrue(in_array('AcoAction', $result));
-
- $result = App::objects('file');
- $this->assertFalse($result);
-
- $result = App::objects('file', 'non_existing_configure');
- $expected = array();
- $this->assertEquals($expected, $result);
-
- $result = App::objects('NonExistingType');
- $this->assertEquals(array(), $result);
-
- App::build(array(
- 'plugins' => array(
- CAKE . 'Test' . DS . 'test_app' . DS . 'Lib' . DS
- )
- ));
- $result = App::objects('plugin', null, false);
- $this->assertTrue(in_array('Cache', $result));
- $this->assertTrue(in_array('Log', $result));
-
- App::build();
- }
-
-/**
- * Make sure that .svn and friends are excluded from App::objects('plugin')
- */
- public function testListObjectsIgnoreDotDirectories() {
- $path = CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS;
-
- $this->skipIf(!is_writable($path), $path . ' is not writable.');
-
- App::build(array(
- 'plugins' => array($path)
- ), App::RESET);
- mkdir($path . '.svn');
- $result = App::objects('plugin', null, false);
- rmdir($path . '.svn');
-
- $this->assertNotContains('.svn', $result);
- }
-
-/**
- * Tests listing objects within a plugin
- *
- * @return void
- */
- public function testListObjectsInPlugin() {
- App::build(array(
- 'Model' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Model' . DS),
- 'plugins' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ), App::RESET);
- CakePlugin::load(array('TestPlugin', 'TestPluginTwo'));
-
- $result = App::objects('TestPlugin.model');
- $this->assertTrue(in_array('TestPluginPost', $result));
- $result = App::objects('TestPlugin.Model');
- $this->assertTrue(in_array('TestPluginPost', $result));
-
- $result = App::objects('TestPlugin.behavior');
- $this->assertTrue(in_array('TestPluginPersisterOneBehavior', $result));
- $result = App::objects('TestPlugin.Model/Behavior');
- $this->assertTrue(in_array('TestPluginPersisterOneBehavior', $result));
-
- $result = App::objects('TestPlugin.helper');
- $expected = array('OtherHelperHelper', 'PluggedHelperHelper', 'TestPluginAppHelper');
- $this->assertEquals($expected, $result);
- $result = App::objects('TestPlugin.View/Helper');
- $expected = array('OtherHelperHelper', 'PluggedHelperHelper', 'TestPluginAppHelper');
- $this->assertEquals($expected, $result);
-
- $result = App::objects('TestPlugin.component');
- $this->assertTrue(in_array('OtherComponent', $result));
- $result = App::objects('TestPlugin.Controller/Component');
- $this->assertTrue(in_array('OtherComponent', $result));
-
- $result = App::objects('TestPluginTwo.behavior');
- $this->assertEquals(array(), $result);
- $result = App::objects('TestPluginTwo.Model/Behavior');
- $this->assertEquals(array(), $result);
-
- $result = App::objects('model', null, false);
- $this->assertTrue(in_array('Comment', $result));
- $this->assertTrue(in_array('Post', $result));
-
- $result = App::objects('Model', null, false);
- $this->assertTrue(in_array('Comment', $result));
- $this->assertTrue(in_array('Post', $result));
-
- App::build();
- }
-
-/**
- * test that pluginPath can find paths for plugins.
- *
- * @return void
- */
- public function testPluginPath() {
- App::build(array(
- 'plugins' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ));
- CakePlugin::load(array('TestPlugin', 'TestPluginTwo'));
-
- $path = App::pluginPath('TestPlugin');
- $expected = CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS . 'TestPlugin' . DS;
- $this->assertEquals($expected, $path);
-
- $path = App::pluginPath('TestPluginTwo');
- $expected = CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS . 'TestPluginTwo' . DS;
- $this->assertEquals($expected, $path);
- App::build();
- }
-
-/**
- * test that themePath can find paths for themes.
- *
- * @return void
- */
- public function testThemePath() {
- App::build(array(
- 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
- ));
- $path = App::themePath('test_theme');
- $expected = CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS . 'Themed' . DS . 'TestTheme' . DS;
- $this->assertEquals($expected, $path);
-
- $path = App::themePath('TestTheme');
- $expected = CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS . 'Themed' . DS . 'TestTheme' . DS;
- $this->assertEquals($expected, $path);
-
- App::build();
- }
-
-/**
- * testClassLoading method
- *
- * @return void
- */
- public function testClassLoading() {
- $file = App::import('Model', 'Model', false);
- $this->assertTrue($file);
- $this->assertTrue(class_exists('Model'));
-
- $file = App::import('Controller', 'Controller', false);
- $this->assertTrue($file);
- $this->assertTrue(class_exists('Controller'));
-
- $file = App::import('Component', 'Auth', false);
- $this->assertTrue($file);
- $this->assertTrue(class_exists('AuthComponent'));
-
- $file = App::import('Shell', 'Shell', false);
- $this->assertTrue($file);
- $this->assertTrue(class_exists('Shell'));
-
- $file = App::import('Configure', 'PhpReader');
- $this->assertTrue($file);
- $this->assertTrue(class_exists('PhpReader'));
-
- $file = App::import('Model', 'SomeRandomModelThatDoesNotExist', false);
- $this->assertFalse($file);
-
- $file = App::import('Model', 'AppModel', false);
- $this->assertTrue($file);
- $this->assertTrue(class_exists('AppModel'));
-
- $file = App::import('WrongType', null, true, array(), '');
- $this->assertFalse($file);
-
- $file = App::import('Model', 'NonExistingPlugin.NonExistingModel', false);
- $this->assertFalse($file);
-
- $file = App::import('Model', array('NonExistingPlugin.NonExistingModel'), false);
- $this->assertFalse($file);
-
- if (!class_exists('AppController', false)) {
- $classes = array_flip(get_declared_classes());
-
- $this->assertFalse(isset($classes['PagesController']));
- $this->assertFalse(isset($classes['AppController']));
-
- $file = App::import('Controller', 'Pages');
- $this->assertTrue($file);
- $this->assertTrue(class_exists('PagesController'));
-
- $classes = array_flip(get_declared_classes());
-
- $this->assertTrue(isset($classes['PagesController']));
- $this->assertTrue(isset($classes['AppController']));
-
- $file = App::import('Behavior', 'Containable');
- $this->assertTrue($file);
- $this->assertTrue(class_exists('ContainableBehavior'));
-
- $file = App::import('Component', 'RequestHandler');
- $this->assertTrue($file);
- $this->assertTrue(class_exists('RequestHandlerComponent'));
-
- $file = App::import('Helper', 'Form');
- $this->assertTrue($file);
- $this->assertTrue(class_exists('FormHelper'));
-
- $file = App::import('Model', 'NonExistingModel');
- $this->assertFalse($file);
-
- $file = App::import('Datasource', 'DboSource');
- $this->assertTrue($file);
- $this->assertTrue(class_exists('DboSource'));
- }
- App::build();
- }
-
-/**
- * test import() with plugins
- *
- * @return void
- */
- public function testPluginImporting() {
- App::build(array(
- 'Lib' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Lib' . DS),
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ));
- CakePlugin::load(array('TestPlugin', 'TestPluginTwo'));
-
- $result = App::import('Controller', 'TestPlugin.Tests');
- $this->assertTrue($result);
- $this->assertTrue(class_exists('TestPluginAppController'));
- $this->assertTrue(class_exists('TestsController'));
-
- $result = App::import('Lib', 'TestPlugin.TestPluginLibrary');
- $this->assertTrue($result);
- $this->assertTrue(class_exists('TestPluginLibrary'));
-
- $result = App::import('Lib', 'Library');
- $this->assertTrue($result);
- $this->assertTrue(class_exists('Library'));
-
- $result = App::import('Helper', 'TestPlugin.OtherHelper');
- $this->assertTrue($result);
- $this->assertTrue(class_exists('OtherHelperHelper'));
-
- $result = App::import('Helper', 'TestPlugin.TestPluginApp');
- $this->assertTrue($result);
- $this->assertTrue(class_exists('TestPluginAppHelper'));
-
- $result = App::import('Datasource', 'TestPlugin.TestSource');
- $this->assertTrue($result);
- $this->assertTrue(class_exists('TestSource'));
-
- App::uses('ExampleExample', 'TestPlugin.Vendor/Example');
- $this->assertTrue(class_exists('ExampleExample'));
-
- App::build();
- }
-
-/**
- * test that building helper paths actually works.
- *
- * @return void
- * @link http://cakephp.lighthouseapp.com/projects/42648/tickets/410
- */
- public function testImportingHelpersFromAlternatePaths() {
- $this->assertFalse(class_exists('BananaHelper', false), 'BananaHelper exists, cannot test importing it.');
- App::build(array(
- 'View/Helper' => array(
- CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS . 'Helper' . DS
- )
- ));
- $this->assertFalse(class_exists('BananaHelper', false), 'BananaHelper exists, cannot test importing it.');
- App::import('Helper', 'Banana');
- $this->assertTrue(class_exists('BananaHelper', false), 'BananaHelper was not loaded.');
-
- App::build();
- }
-
-/**
- * testFileLoading method
- *
- * @return void
- */
- public function testFileLoading() {
- $file = App::import('File', 'RealFile', false, array(), CAKE . 'Config' . DS . 'config.php');
- $this->assertTrue($file);
-
- $file = App::import('File', 'NoFile', false, array(), CAKE . 'Config' . DS . 'cake' . DS . 'config.php');
- $this->assertFalse($file);
- }
-
-/**
- * testFileLoadingWithArray method
- *
- * @return void
- */
- public function testFileLoadingWithArray() {
- $type = array(
- 'type' => 'File',
- 'name' => 'SomeName',
- 'parent' => false,
- 'file' => CAKE . DS . 'Config' . DS . 'config.php'
- );
- $file = App::import($type);
- $this->assertTrue($file);
-
- $type = array(
- 'type' => 'File',
- 'name' => 'NoFile',
- 'parent' => false,
- 'file' => CAKE . 'Config' . DS . 'cake' . DS . 'config.php'
- );
- $file = App::import($type);
- $this->assertFalse($file);
- }
-
-/**
- * testFileLoadingReturnValue method
- *
- * @return void
- */
- public function testFileLoadingReturnValue() {
- $file = App::import('File', 'Name', false, array(), CAKE . 'Config' . DS . 'config.php', true);
- $this->assertTrue(!empty($file));
-
- $this->assertTrue(isset($file['Cake.version']));
-
- $type = array(
- 'type' => 'File',
- 'name' => 'OtherName',
- 'parent' => false,
- 'file' => CAKE . 'Config' . DS . 'config.php', 'return' => true
- );
- $file = App::import($type);
- $this->assertTrue(!empty($file));
-
- $this->assertTrue(isset($file['Cake.version']));
- }
-
-/**
- * testLoadingWithSearch method
- *
- * @return void
- */
- public function testLoadingWithSearch() {
- $file = App::import('File', 'NewName', false, array(CAKE . 'Config' . DS), 'config.php');
- $this->assertTrue($file);
-
- $file = App::import('File', 'AnotherNewName', false, array(CAKE), 'config.php');
- $this->assertFalse($file);
- }
-
-/**
- * testLoadingWithSearchArray method
- *
- * @return void
- */
- public function testLoadingWithSearchArray() {
- $type = array(
- 'type' => 'File',
- 'name' => 'RandomName',
- 'parent' => false,
- 'file' => 'config.php',
- 'search' => array(CAKE . 'Config' . DS)
- );
- $file = App::import($type);
- $this->assertTrue($file);
-
- $type = array(
- 'type' => 'File',
- 'name' => 'AnotherRandomName',
- 'parent' => false,
- 'file' => 'config.php',
- 'search' => array(CAKE)
- );
- $file = App::import($type);
- $this->assertFalse($file);
- }
-
-/**
- * testMultipleLoading method
- *
- * @return void
- */
- public function testMultipleLoading() {
- if (class_exists('PersisterOne', false) || class_exists('PersisterTwo', false)) {
- $this->markTestSkipped('Cannot test loading of classes that exist.');
- }
- App::build(array(
- 'Model' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Model' . DS)
- ));
- $toLoad = array('PersisterOne', 'PersisterTwo');
- $load = App::import('Model', $toLoad);
- $this->assertTrue($load);
-
- $classes = array_flip(get_declared_classes());
-
- $this->assertTrue(isset($classes['PersisterOne']));
- $this->assertTrue(isset($classes['PersisterTwo']));
-
- $load = App::import('Model', array('PersisterOne', 'SomeNotFoundClass', 'PersisterTwo'));
- $this->assertFalse($load);
- }
-
- public function testLoadingVendor() {
- App::build(array(
- 'plugins' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS),
- 'vendors' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS),
- ), App::RESET);
- CakePlugin::load(array('TestPlugin', 'TestPluginTwo'));
-
- ob_start();
- $result = App::import('Vendor', 'css/TestAsset', array('ext' => 'css'));
- $text = ob_get_clean();
- $this->assertTrue($result);
- $this->assertEquals('this is the test asset css file', $text);
-
- $result = App::import('Vendor', 'TestPlugin.sample/SamplePlugin');
- $this->assertTrue($result);
- $this->assertTrue(class_exists('SamplePluginClassTestName'));
-
- $result = App::import('Vendor', 'sample/ConfigureTestVendorSample');
- $this->assertTrue($result);
- $this->assertTrue(class_exists('ConfigureTestVendorSample'));
-
- ob_start();
- $result = App::import('Vendor', 'SomeNameInSubfolder', array('file' => 'somename/some.name.php'));
- $text = ob_get_clean();
- $this->assertTrue($result);
- $this->assertEquals('This is a file with dot in file name', $text);
-
- ob_start();
- $result = App::import('Vendor', 'TestHello', array('file' => 'Test' . DS . 'hello.php'));
- $text = ob_get_clean();
- $this->assertTrue($result);
- $this->assertEquals('This is the hello.php file in Test directory', $text);
-
- ob_start();
- $result = App::import('Vendor', 'MyTest', array('file' => 'Test' . DS . 'MyTest.php'));
- $text = ob_get_clean();
- $this->assertTrue($result);
- $this->assertEquals('This is the MyTest.php file', $text);
-
- ob_start();
- $result = App::import('Vendor', 'Welcome');
- $text = ob_get_clean();
- $this->assertTrue($result);
- $this->assertEquals('This is the welcome.php file in vendors directory', $text);
-
- ob_start();
- $result = App::import('Vendor', 'TestPlugin.Welcome');
- $text = ob_get_clean();
- $this->assertTrue($result);
- $this->assertEquals('This is the welcome.php file in test_plugin/vendors directory', $text);
- }
-
-/**
- * Tests that the automatic class loader will also find in "libs" folder for both
- * app and plugins if it does not find the class in other configured paths
- *
- */
- public function testLoadClassInLibs() {
- App::build(array(
- 'libs' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Lib' . DS),
- 'plugins' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ), App::RESET);
- CakePlugin::load(array('TestPlugin', 'TestPluginTwo'));
-
- $this->assertFalse(class_exists('CustomLibClass', false));
- App::uses('CustomLibClass', 'TestPlugin.Custom/Package');
- $this->assertTrue(class_exists('CustomLibClass'));
-
- $this->assertFalse(class_exists('TestUtilityClass', false));
- App::uses('TestUtilityClass', 'Utility');
- $this->assertTrue(class_exists('CustomLibClass'));
- }
-
-/**
- * Tests that App::location() returns the defined path for a class
- *
- * @return void
- */
- public function testClassLocation() {
- App::uses('MyCustomClass', 'MyPackage/Name');
- $this->assertEquals('MyPackage/Name', App::location('MyCustomClass'));
- }
-
-/**
- * Test that paths() works.
- *
- * @return void
- */
- public function testPaths() {
- $result = App::paths();
- $this->assertArrayHasKey('Plugin', $result);
- $this->assertArrayHasKey('Controller', $result);
- $this->assertArrayHasKey('Controller/Component', $result);
- }
-
-/**
- * Proves that it is possible to load plugin libraries in top
- * level Lib dir for plugins
- *
- * @return void
- */
- public function testPluginLibClasses() {
- App::build(array(
- 'plugins' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ), App::RESET);
- CakePlugin::load(array('TestPlugin', 'TestPluginTwo'));
- $this->assertFalse(class_exists('TestPluginOtherLibrary', false));
- App::uses('TestPluginOtherLibrary', 'TestPlugin.Lib');
- $this->assertTrue(class_exists('TestPluginOtherLibrary'));
- }
-}
diff --git a/lib/Cake/Test/Case/Core/CakePluginTest.php b/lib/Cake/Test/Case/Core/CakePluginTest.php
deleted file mode 100644
index 87926a20983..00000000000
--- a/lib/Cake/Test/Case/Core/CakePluginTest.php
+++ /dev/null
@@ -1,268 +0,0 @@
- array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ), App::RESET);
- App::objects('plugins', null, false);
- }
-
-/**
- * Reverts the changes done to the environment while testing
- *
- * @return void
- */
- public function tearDown() {
- App::build();
- CakePlugin::unload();
- Configure::delete('CakePluginTest');
- }
-
-/**
- * Tests loading a single plugin
- *
- * @return void
- */
- public function testLoadSingle() {
- CakePlugin::unload();
- CakePlugin::load('TestPlugin');
- $expected = array('TestPlugin');
- $this->assertEquals($expected, CakePlugin::loaded());
- }
-
-/**
- * Tests unloading plugins
- *
- * @return void
- */
- public function testUnload() {
- CakePlugin::load('TestPlugin');
- $expected = array('TestPlugin');
- $this->assertEquals($expected, CakePlugin::loaded());
-
- CakePlugin::unload('TestPlugin');
- $this->assertEquals(array(), CakePlugin::loaded());
-
- CakePlugin::load('TestPlugin');
- $expected = array('TestPlugin');
- $this->assertEquals($expected, CakePlugin::loaded());
-
- CakePlugin::unload('TestFakePlugin');
- $this->assertEquals($expected, CakePlugin::loaded());
- }
-
-/**
- * Tests loading a plugin and its bootstrap file
- *
- * @return void
- */
- public function testLoadSingleWithBootstrap() {
- CakePlugin::load('TestPlugin', array('bootstrap' => true));
- $this->assertTrue(CakePlugin::loaded('TestPlugin'));
- $this->assertEquals('loaded plugin bootstrap', Configure::read('CakePluginTest.test_plugin.bootstrap'));
- }
-
-/**
- * Tests loading a plugin with bootstrap file and routes file
- *
- * @return void
- */
- public function testLoadSingleWithBootstrapAndRoutes() {
- CakePlugin::load('TestPlugin', array('bootstrap' => true, 'routes' => true));
- $this->assertTrue(CakePlugin::loaded('TestPlugin'));
- $this->assertEquals('loaded plugin bootstrap', Configure::read('CakePluginTest.test_plugin.bootstrap'));
-
- CakePlugin::routes();
- $this->assertEquals('loaded plugin routes', Configure::read('CakePluginTest.test_plugin.routes'));
- }
-
-/**
- * Tests loading multiple plugins at once
- *
- * @return void
- */
- public function testLoadMultiple() {
- CakePlugin::load(array('TestPlugin', 'TestPluginTwo'));
- $expected = array('TestPlugin', 'TestPluginTwo');
- $this->assertEquals($expected, CakePlugin::loaded());
- }
-
-/**
- * Tests loading multiple plugins and their bootstrap files
- *
- * @return void
- */
- public function testLoadMultipleWithDefaults() {
- CakePlugin::load(array('TestPlugin', 'TestPluginTwo'), array('bootstrap' => true, 'routes' => false));
- $expected = array('TestPlugin', 'TestPluginTwo');
- $this->assertEquals($expected, CakePlugin::loaded());
- $this->assertEquals('loaded plugin bootstrap', Configure::read('CakePluginTest.test_plugin.bootstrap'));
- $this->assertEquals('loaded plugin two bootstrap', Configure::read('CakePluginTest.test_plugin_two.bootstrap'));
- }
-
-/**
- * Tests loading multiple plugins with default loading params and some overrides
- *
- * @return void
- */
- public function testLoadMultipleWithDefaultsAndOverride() {
- CakePlugin::load(
- array('TestPlugin', 'TestPluginTwo' => array('routes' => false)),
- array('bootstrap' => true, 'routes' => true)
- );
- $expected = array('TestPlugin', 'TestPluginTwo');
- $this->assertEquals($expected, CakePlugin::loaded());
- $this->assertEquals('loaded plugin bootstrap', Configure::read('CakePluginTest.test_plugin.bootstrap'));
- $this->assertEquals(null, Configure::read('CakePluginTest.test_plugin_two.bootstrap'));
- }
-
-/**
- * Tests that it is possible to load multiple bootstrap files at once
- *
- * @return void
- */
- public function testMultipleBootstrapFiles() {
- CakePlugin::load('TestPlugin', array('bootstrap' => array('bootstrap', 'custom_config')));
- $this->assertTrue(CakePlugin::loaded('TestPlugin'));
- $this->assertEquals('loaded plugin bootstrap', Configure::read('CakePluginTest.test_plugin.bootstrap'));
- }
-
-/**
- * Tests that it is possible to load plugin bootstrap by calling a callback function
- *
- * @return void
- */
- public function testCallbackBootstrap() {
- CakePlugin::load('TestPlugin', array('bootstrap' => array($this, 'pluginBootstrap')));
- $this->assertTrue(CakePlugin::loaded('TestPlugin'));
- $this->assertEquals('called plugin bootstrap callback', Configure::read('CakePluginTest.test_plugin.bootstrap'));
- }
-
-/**
- * Tests that loading a missing routes file throws a warning
- *
- * @return void
- * @expectedException PHPUNIT_FRAMEWORK_ERROR_WARNING
- */
- public function testLoadMultipleWithDefaultsMissingFile() {
- CakePlugin::load(array('TestPlugin', 'TestPluginTwo'), array('bootstrap' => true, 'routes' => true));
- CakePlugin::routes();
- }
-
-/**
- * Tests that CakePlugin::load() throws an exception on unknown plugin
- *
- * @return void
- * @expectedException MissingPluginException
- */
- public function testLoadNotFound() {
- CakePlugin::load('MissingPlugin');
- }
-
-/**
- * Tests that CakePlugin::path() returns the correct path for the loaded plugins
- *
- * @return void
- */
- public function testPath() {
- CakePlugin::load(array('TestPlugin', 'TestPluginTwo'));
- $expected = CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS . 'TestPlugin' . DS;
- $this->assertEquals(CakePlugin::path('TestPlugin'), $expected);
-
- $expected = CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS . 'TestPluginTwo' . DS;
- $this->assertEquals(CakePlugin::path('TestPluginTwo'), $expected);
- }
-
-/**
- * Tests that CakePlugin::path() throws an exception on unknown plugin
- *
- * @return void
- * @expectedException MissingPluginException
- */
- public function testPathNotFound() {
- CakePlugin::path('TestPlugin');
- }
-
-/**
- * Tests that CakePlugin::loadAll() will load all plugins in the configured folder
- *
- * @return void
- */
- public function testLoadAll() {
- CakePlugin::loadAll();
- $expected = array('PluginJs', 'TestPlugin', 'TestPluginTwo');
- $this->assertEquals($expected, CakePlugin::loaded());
- }
-
-/**
- * Tests that CakePlugin::loadAll() will load all plugins in the configured folder with bootstrap loading
- *
- * @return void
- */
- public function testLoadAllWithDefaults() {
- $defaults = array('bootstrap' => true);
- CakePlugin::loadAll(array($defaults));
- $expected = array('PluginJs', 'TestPlugin', 'TestPluginTwo');
- $this->assertEquals($expected, CakePlugin::loaded());
- $this->assertEquals('loaded js plugin bootstrap', Configure::read('CakePluginTest.js_plugin.bootstrap'));
- $this->assertEquals('loaded plugin bootstrap', Configure::read('CakePluginTest.test_plugin.bootstrap'));
- $this->assertEquals('loaded plugin two bootstrap', Configure::read('CakePluginTest.test_plugin_two.bootstrap'));
- }
-
-/**
- * Tests that CakePlugin::loadAll() will load all plugins in the configured folder wit defaults
- * and overrides for a plugin
- *
- * @return void
- */
- public function testLoadAllWithDefaultsAndOverride() {
- CakePlugin::loadAll(array(array('bootstrap' => true), 'TestPlugin' => array('routes' => true)));
- CakePlugin::routes();
-
- $expected = array('PluginJs', 'TestPlugin', 'TestPluginTwo');
- $this->assertEquals($expected, CakePlugin::loaded());
- $this->assertEquals('loaded js plugin bootstrap', Configure::read('CakePluginTest.js_plugin.bootstrap'));
- $this->assertEquals('loaded plugin routes', Configure::read('CakePluginTest.test_plugin.routes'));
- $this->assertEquals(null, Configure::read('CakePluginTest.test_plugin.bootstrap'));
- $this->assertEquals('loaded plugin two bootstrap', Configure::read('CakePluginTest.test_plugin_two.bootstrap'));
- }
-
-/**
- * Auxiliary function to test plugin bootstrap callbacks
- *
- * @return void
- */
- public function pluginBootstrap() {
- Configure::write('CakePluginTest.test_plugin.bootstrap', 'called plugin bootstrap callback');
- }
-}
diff --git a/lib/Cake/Test/Case/Core/ConfigureTest.php b/lib/Cake/Test/Case/Core/ConfigureTest.php
deleted file mode 100644
index 9a73a1e7c5a..00000000000
--- a/lib/Cake/Test/Case/Core/ConfigureTest.php
+++ /dev/null
@@ -1,357 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Core
- * @since CakePHP(tm) v 1.2.0.5432
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-App::uses('PhpReader', 'Configure');
-
-/**
- * ConfigureTest
- *
- * @package Cake.Test.Case.Core
- */
-class ConfigureTest extends CakeTestCase {
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- $this->_cacheDisable = Configure::read('Cache.disable');
- $this->_debug = Configure::read('debug');
-
- Configure::write('Cache.disable', true);
- App::build();
- App::objects('plugin', null, true);
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- if (file_exists(TMP . 'cache' . DS . 'persistent' . DS . 'cake_core_core_paths')) {
- unlink(TMP . 'cache' . DS . 'persistent' . DS . 'cake_core_core_paths');
- }
- if (file_exists(TMP . 'cache' . DS . 'persistent' . DS . 'cake_core_dir_map')) {
- unlink(TMP . 'cache' . DS . 'persistent' . DS . 'cake_core_dir_map');
- }
- if (file_exists(TMP . 'cache' . DS . 'persistent' . DS . 'cake_core_file_map')) {
- unlink(TMP . 'cache' . DS . 'persistent' . DS . 'cake_core_file_map');
- }
- if (file_exists(TMP . 'cache' . DS . 'persistent' . DS . 'cake_core_object_map')) {
- unlink(TMP . 'cache' . DS . 'persistent' . DS . 'cake_core_object_map');
- }
- if (file_exists(TMP . 'cache' . DS . 'persistent' . DS . 'test.config.php')) {
- unlink(TMP . 'cache' . DS . 'persistent' . DS . 'test.config.php');
- }
- if (file_exists(TMP . 'cache' . DS . 'persistent' . DS . 'test.php')) {
- unlink(TMP . 'cache' . DS . 'persistent' . DS . 'test.php');
- }
- Configure::write('debug', $this->_debug);
- Configure::write('Cache.disable', $this->_cacheDisable);
- Configure::drop('test');
- }
-
-/**
- * testRead method
- *
- * @return void
- */
- public function testRead() {
- $expected = 'ok';
- Configure::write('level1.level2.level3_1', $expected);
- Configure::write('level1.level2.level3_2', 'something_else');
- $result = Configure::read('level1.level2.level3_1');
- $this->assertEquals($expected, $result);
-
- $result = Configure::read('level1.level2.level3_2');
- $this->assertEquals('something_else', $result);
-
- $result = Configure::read('debug');
- $this->assertTrue($result >= 0);
-
- $result = Configure::read();
- $this->assertTrue(is_array($result));
- $this->assertTrue(isset($result['debug']));
- $this->assertTrue(isset($result['level1']));
-
- $result = Configure::read('something_I_just_made_up_now');
- $this->assertEquals(null, $result, 'Missing key should return null.');
- }
-
-/**
- * testWrite method
- *
- * @return void
- */
- public function testWrite() {
- $writeResult = Configure::write('SomeName.someKey', 'myvalue');
- $this->assertTrue($writeResult);
- $result = Configure::read('SomeName.someKey');
- $this->assertEquals('myvalue', $result);
-
- $writeResult = Configure::write('SomeName.someKey', null);
- $this->assertTrue($writeResult);
- $result = Configure::read('SomeName.someKey');
- $this->assertEquals(null, $result);
-
- $expected = array('One' => array('Two' => array('Three' => array('Four' => array('Five' => 'cool')))));
- $writeResult = Configure::write('Key', $expected);
- $this->assertTrue($writeResult);
-
- $result = Configure::read('Key');
- $this->assertEquals($expected, $result);
-
- $result = Configure::read('Key.One');
- $this->assertEquals($expected['One'], $result);
-
- $result = Configure::read('Key.One.Two');
- $this->assertEquals($expected['One']['Two'], $result);
-
- $result = Configure::read('Key.One.Two.Three.Four.Five');
- $this->assertEquals('cool', $result);
-
- Configure::write('one.two.three.four', '4');
- $result = Configure::read('one.two.three.four');
- $this->assertEquals('4', $result);
- }
-
-/**
- * test setting display_errors with debug.
- *
- * @return void
- */
- public function testDebugSettingDisplayErrors() {
- Configure::write('debug', 0);
- $result = ini_get('display_errors');
- $this->assertEquals(0, $result);
-
- Configure::write('debug', 2);
- $result = ini_get('display_errors');
- $this->assertEquals(1, $result);
- }
-
-/**
- * testDelete method
- *
- * @return void
- */
- public function testDelete() {
- Configure::write('SomeName.someKey', 'myvalue');
- $result = Configure::read('SomeName.someKey');
- $this->assertEquals('myvalue', $result);
-
- Configure::delete('SomeName.someKey');
- $result = Configure::read('SomeName.someKey');
- $this->assertTrue($result === null);
-
- Configure::write('SomeName', array('someKey' => 'myvalue', 'otherKey' => 'otherValue'));
-
- $result = Configure::read('SomeName.someKey');
- $this->assertEquals('myvalue', $result);
-
- $result = Configure::read('SomeName.otherKey');
- $this->assertEquals('otherValue', $result);
-
- Configure::delete('SomeName');
-
- $result = Configure::read('SomeName.someKey');
- $this->assertTrue($result === null);
-
- $result = Configure::read('SomeName.otherKey');
- $this->assertTrue($result === null);
- }
-
-/**
- * testLoad method
- *
- * @expectedException RuntimeException
- * @return void
- */
- public function testLoadExceptionOnNonExistantFile() {
- Configure::config('test', new PhpReader());
- $result = Configure::load('non_existing_configuration_file', 'test');
- }
-
-/**
- * test load method for default config creation
- *
- * @return void
- */
- public function testLoadDefaultConfig() {
- try {
- Configure::load('non_existing_configuration_file');
- } catch (Exception $e) {
- $result = Configure::configured('default');
- $this->assertTrue($result);
- }
- }
-
-/**
- * test load with merging
- *
- * @return void
- */
- public function testLoadWithMerge() {
- Configure::config('test', new PhpReader(CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS));
-
- $result = Configure::load('var_test', 'test');
- $this->assertTrue($result);
-
- $this->assertEquals('value', Configure::read('Read'));
-
- $result = Configure::load('var_test2', 'test', true);
- $this->assertTrue($result);
-
- $this->assertEquals('value2', Configure::read('Read'));
- $this->assertEquals('buried2', Configure::read('Deep.Second.SecondDeepest'));
- $this->assertEquals('buried', Configure::read('Deep.Deeper.Deepest'));
- $this->assertEquals('Overwrite', Configure::read('TestAcl.classname'));
- $this->assertEquals('one', Configure::read('TestAcl.custom'));
- }
-
-/**
- * test loading with overwrite
- *
- * @return void
- */
- public function testLoadNoMerge() {
- Configure::config('test', new PhpReader(CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS));
-
- $result = Configure::load('var_test', 'test');
- $this->assertTrue($result);
-
- $this->assertEquals('value', Configure::read('Read'));
-
- $result = Configure::load('var_test2', 'test', false);
- $this->assertTrue($result);
-
- $this->assertEquals('value2', Configure::read('Read'));
- $this->assertEquals('buried2', Configure::read('Deep.Second.SecondDeepest'));
- $this->assertNull(Configure::read('Deep.Deeper.Deepest'));
- }
-
-/**
- * testLoad method
- *
- * @return void
- */
- public function testLoadPlugin() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ), App::RESET);
- Configure::config('test', new PhpReader());
- CakePlugin::load('TestPlugin');
- $result = Configure::load('TestPlugin.load', 'test');
- $this->assertTrue($result);
- $expected = '/test_app/plugins/test_plugin/config/load.php';
- $config = Configure::read('plugin_load');
- $this->assertEquals($expected, $config);
-
- $result = Configure::load('TestPlugin.more.load', 'test');
- $this->assertTrue($result);
- $expected = '/test_app/plugins/test_plugin/config/more.load.php';
- $config = Configure::read('plugin_more_load');
- $this->assertEquals($expected, $config);
- CakePlugin::unload();
- }
-
-/**
- * testStore method
- *
- * @return void
- */
- public function testStoreAndRestore() {
- Configure::write('Cache.disable', false);
-
- Configure::write('Testing', 'yummy');
- $this->assertTrue(Configure::store('store_test', 'default'));
-
- Configure::delete('Testing');
- $this->assertNull(Configure::read('Testing'));
-
- Configure::restore('store_test', 'default');
- $this->assertEquals('yummy', Configure::read('Testing'));
-
- Cache::delete('store_test', 'default');
- }
-
-/**
- * test that store and restore only store/restore the provided data.
- *
- * @return void
- */
- public function testStoreAndRestoreWithData() {
- Configure::write('Cache.disable', false);
-
- Configure::write('testing', 'value');
- Configure::store('store_test', 'default', array('store_test' => 'one'));
- Configure::delete('testing');
- $this->assertNull(Configure::read('store_test'), 'Calling store with data shouldn\'t modify runtime.');
-
- Configure::restore('store_test', 'default');
- $this->assertEquals('one', Configure::read('store_test'));
- $this->assertNull(Configure::read('testing'), 'Values that were not stored are not restored.');
-
- Cache::delete('store_test', 'default');
- }
-
-/**
- * testVersion method
- *
- * @return void
- */
- public function testVersion() {
- $result = Configure::version();
- $this->assertTrue(version_compare($result, '1.2', '>='));
- }
-
-/**
- * test adding new readers.
- *
- * @return void
- */
- public function testReaderSetup() {
- $reader = new PhpReader();
- Configure::config('test', $reader);
- $configured = Configure::configured();
-
- $this->assertTrue(in_array('test', $configured));
-
- $this->assertTrue(Configure::configured('test'));
- $this->assertFalse(Configure::configured('fake_garbage'));
-
- $this->assertTrue(Configure::drop('test'));
- $this->assertFalse(Configure::drop('test'), 'dropping things that do not exist should return false.');
- }
-
-/**
- * test reader() throwing exceptions on missing interface.
- *
- * @expectedException PHPUnit_Framework_Error
- * @return void
- */
- public function testReaderExceptionOnIncorrectClass() {
- $reader = new StdClass();
- Configure::config('test', $reader);
- }
-
-}
diff --git a/lib/Cake/Test/Case/Core/ObjectTest.php b/lib/Cake/Test/Case/Core/ObjectTest.php
deleted file mode 100644
index 0258d040265..00000000000
--- a/lib/Cake/Test/Case/Core/ObjectTest.php
+++ /dev/null
@@ -1,672 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Core
- * @since CakePHP(tm) v 1.2.0.5432
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('Object', 'Core');
-App::uses('Router', 'Routing');
-App::uses('Controller', 'Controller');
-App::uses('Model', 'Model');
-
-/**
- * RequestActionPost class
- *
- * @package Cake.Test.Case.Core
- */
-class RequestActionPost extends CakeTestModel {
-
-/**
- * name property
- *
- * @var string 'ControllerPost'
- */
- public $name = 'RequestActionPost';
-
-/**
- * useTable property
- *
- * @var string 'posts'
- */
- public $useTable = 'posts';
-}
-
-/**
- * RequestActionController class
- *
- * @package Cake.Test.Case.Core
- */
-class RequestActionController extends Controller {
-
-/**
- * uses property
- *
- * @var array
- * @access public
- */
- public $uses = array('RequestActionPost');
-
-/**
- * test_request_action method
- *
- * @access public
- * @return void
- */
- public function test_request_action() {
- return 'This is a test';
- }
-
-/**
- * another_ra_test method
- *
- * @param mixed $id
- * @param mixed $other
- * @access public
- * @return void
- */
- public function another_ra_test($id, $other) {
- return $id + $other;
- }
-
-/**
- * normal_request_action method
- *
- * @return void
- */
- public function normal_request_action() {
- return 'Hello World';
- }
-
-/**
- * returns $this->here
- *
- * @return void
- */
- public function return_here() {
- return $this->here;
- }
-
-/**
- * paginate_request_action method
- *
- * @return void
- */
- public function paginate_request_action() {
- $data = $this->paginate();
- return true;
- }
-
-/**
- * post pass, testing post passing
- *
- * @return array
- */
- public function post_pass() {
- return $this->request->data;
- }
-
-/**
- * test param passing and parsing.
- *
- * @return array
- */
- public function params_pass() {
- return $this->request;
- }
-
- public function param_check() {
- $this->autoRender = false;
- $content = '';
- if (isset($this->request->params[0])) {
- $content = 'return found';
- }
- $this->response->body($content);
- }
-
-}
-
-/**
- * TestObject class
- *
- * @package Cake.Test.Case.Core
- */
-class TestObject extends Object {
-
-/**
- * firstName property
- *
- * @var string 'Joel'
- */
- public $firstName = 'Joel';
-
-/**
- * lastName property
- *
- * @var string 'Moss'
- */
- public $lastName = 'Moss';
-
-/**
- * methodCalls property
- *
- * @var array
- */
- public $methodCalls = array();
-
-/**
- * emptyMethod method
- *
- * @return void
- */
- public function emptyMethod() {
- $this->methodCalls[] = 'emptyMethod';
- }
-
-/**
- * oneParamMethod method
- *
- * @param mixed $param
- * @return void
- */
- public function oneParamMethod($param) {
- $this->methodCalls[] = array('oneParamMethod' => array($param));
- }
-
-/**
- * twoParamMethod method
- *
- * @param mixed $param
- * @param mixed $paramTwo
- * @return void
- */
- public function twoParamMethod($param, $paramTwo) {
- $this->methodCalls[] = array('twoParamMethod' => array($param, $paramTwo));
- }
-
-/**
- * threeParamMethod method
- *
- * @param mixed $param
- * @param mixed $paramTwo
- * @param mixed $paramThree
- * @return void
- */
- public function threeParamMethod($param, $paramTwo, $paramThree) {
- $this->methodCalls[] = array('threeParamMethod' => array($param, $paramTwo, $paramThree));
- }
-
-/**
- * fourParamMethod method
- *
- * @param mixed $param
- * @param mixed $paramTwo
- * @param mixed $paramThree
- * @param mixed $paramFour
- * @return void
- */
- public function fourParamMethod($param, $paramTwo, $paramThree, $paramFour) {
- $this->methodCalls[] = array('fourParamMethod' => array($param, $paramTwo, $paramThree, $paramFour));
- }
-
-/**
- * fiveParamMethod method
- *
- * @param mixed $param
- * @param mixed $paramTwo
- * @param mixed $paramThree
- * @param mixed $paramFour
- * @param mixed $paramFive
- * @return void
- */
- public function fiveParamMethod($param, $paramTwo, $paramThree, $paramFour, $paramFive) {
- $this->methodCalls[] = array('fiveParamMethod' => array($param, $paramTwo, $paramThree, $paramFour, $paramFive));
- }
-
-/**
- * crazyMethod method
- *
- * @param mixed $param
- * @param mixed $paramTwo
- * @param mixed $paramThree
- * @param mixed $paramFour
- * @param mixed $paramFive
- * @param mixed $paramSix
- * @param mixed $paramSeven
- * @return void
- */
- public function crazyMethod($param, $paramTwo, $paramThree, $paramFour, $paramFive, $paramSix, $paramSeven = null) {
- $this->methodCalls[] = array('crazyMethod' => array($param, $paramTwo, $paramThree, $paramFour, $paramFive, $paramSix, $paramSeven));
- }
-
-/**
- * methodWithOptionalParam method
- *
- * @param mixed $param
- * @return void
- */
- public function methodWithOptionalParam($param = null) {
- $this->methodCalls[] = array('methodWithOptionalParam' => array($param));
- }
-
-/**
- * undocumented function
- *
- * @return void
- */
- public function set($properties = array()) {
- return parent::_set($properties);
- }
-
-}
-
-/**
- * ObjectTestModel class
- *
- * @package Cake.Test.Case.Core
- */
-class ObjectTestModel extends CakeTestModel {
-
- public $useTable = false;
-
- public $name = 'ObjectTestModel';
-
-}
-
-/**
- * Object Test class
- *
- * @package Cake.Test.Case.Core
- */
-class ObjectTest extends CakeTestCase {
-
-/**
- * fixtures
- *
- * @var string
- */
- public $fixtures = array('core.post', 'core.test_plugin_comment', 'core.comment');
-
-/**
- * setUp method
- *
- * @return void
- */
- public function setUp() {
- $this->object = new TestObject();
- }
-
-/**
- * tearDown method
- *
- * @return void
- */
- public function tearDown() {
- App::build();
- CakePlugin::unload();
- unset($this->object);
- }
-
-/**
- * testLog method
- *
- * @return void
- */
- public function testLog() {
- if (file_exists(LOGS . 'error.log')) {
- unlink(LOGS . 'error.log');
- }
- $this->assertTrue($this->object->log('Test warning 1'));
- $this->assertTrue($this->object->log(array('Test' => 'warning 2')));
- $result = file(LOGS . 'error.log');
- $this->assertRegExp('/^2[0-9]{3}-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+ Error: Test warning 1$/', $result[0]);
- $this->assertRegExp('/^2[0-9]{3}-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+ Error: Array$/', $result[1]);
- $this->assertRegExp('/^\($/', $result[2]);
- $this->assertRegExp('/\[Test\] => warning 2$/', $result[3]);
- $this->assertRegExp('/^\)$/', $result[4]);
- unlink(LOGS . 'error.log');
-
- $this->assertTrue($this->object->log('Test warning 1', LOG_WARNING));
- $this->assertTrue($this->object->log(array('Test' => 'warning 2'), LOG_WARNING));
- $result = file(LOGS . 'error.log');
- $this->assertRegExp('/^2[0-9]{3}-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+ Warning: Test warning 1$/', $result[0]);
- $this->assertRegExp('/^2[0-9]{3}-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+ Warning: Array$/', $result[1]);
- $this->assertRegExp('/^\($/', $result[2]);
- $this->assertRegExp('/\[Test\] => warning 2$/', $result[3]);
- $this->assertRegExp('/^\)$/', $result[4]);
- unlink(LOGS . 'error.log');
- }
-
-/**
- * testSet method
- *
- * @return void
- */
- public function testSet() {
- $this->object->set('a string');
- $this->assertEquals('Joel', $this->object->firstName);
-
- $this->object->set(array('firstName'));
- $this->assertEquals('Joel', $this->object->firstName);
-
- $this->object->set(array('firstName' => 'Ashley'));
- $this->assertEquals('Ashley', $this->object->firstName);
-
- $this->object->set(array('firstName' => 'Joel', 'lastName' => 'Moose'));
- $this->assertEquals('Joel', $this->object->firstName);
- $this->assertEquals('Moose', $this->object->lastName);
- }
-
-/**
- * testToString method
- *
- * @return void
- */
- public function testToString() {
- $result = strtolower($this->object->toString());
- $this->assertEquals('testobject', $result);
- }
-
-/**
- * testMethodDispatching method
- *
- * @return void
- */
- public function testMethodDispatching() {
- $this->object->emptyMethod();
- $expected = array('emptyMethod');
- $this->assertSame($this->object->methodCalls, $expected);
-
- $this->object->oneParamMethod('Hello');
- $expected[] = array('oneParamMethod' => array('Hello'));
- $this->assertSame($this->object->methodCalls, $expected);
-
- $this->object->twoParamMethod(true, false);
- $expected[] = array('twoParamMethod' => array(true, false));
- $this->assertSame($this->object->methodCalls, $expected);
-
- $this->object->threeParamMethod(true, false, null);
- $expected[] = array('threeParamMethod' => array(true, false, null));
- $this->assertSame($this->object->methodCalls, $expected);
-
- $this->object->crazyMethod(1, 2, 3, 4, 5, 6, 7);
- $expected[] = array('crazyMethod' => array(1, 2, 3, 4, 5, 6, 7));
- $this->assertSame($this->object->methodCalls, $expected);
-
- $this->object = new TestObject();
- $this->assertSame($this->object->methodCalls, array());
-
- $this->object->dispatchMethod('emptyMethod');
- $expected = array('emptyMethod');
- $this->assertSame($this->object->methodCalls, $expected);
-
- $this->object->dispatchMethod('oneParamMethod', array('Hello'));
- $expected[] = array('oneParamMethod' => array('Hello'));
- $this->assertSame($this->object->methodCalls, $expected);
-
- $this->object->dispatchMethod('twoParamMethod', array(true, false));
- $expected[] = array('twoParamMethod' => array(true, false));
- $this->assertSame($this->object->methodCalls, $expected);
-
- $this->object->dispatchMethod('threeParamMethod', array(true, false, null));
- $expected[] = array('threeParamMethod' => array(true, false, null));
- $this->assertSame($this->object->methodCalls, $expected);
-
- $this->object->dispatchMethod('fourParamMethod', array(1, 2, 3, 4));
- $expected[] = array('fourParamMethod' => array(1, 2, 3, 4));
- $this->assertSame($this->object->methodCalls, $expected);
-
- $this->object->dispatchMethod('fiveParamMethod', array(1, 2, 3, 4, 5));
- $expected[] = array('fiveParamMethod' => array(1, 2, 3, 4, 5));
- $this->assertSame($this->object->methodCalls, $expected);
-
- $this->object->dispatchMethod('crazyMethod', array(1, 2, 3, 4, 5, 6, 7));
- $expected[] = array('crazyMethod' => array(1, 2, 3, 4, 5, 6, 7));
- $this->assertSame($this->object->methodCalls, $expected);
-
- $this->object->dispatchMethod('methodWithOptionalParam', array('Hello'));
- $expected[] = array('methodWithOptionalParam' => array("Hello"));
- $this->assertSame($this->object->methodCalls, $expected);
-
- $this->object->dispatchMethod('methodWithOptionalParam');
- $expected[] = array('methodWithOptionalParam' => array(null));
- $this->assertSame($this->object->methodCalls, $expected);
- }
-
-/**
- * testRequestAction method
- *
- * @return void
- */
- public function testRequestAction() {
- App::build(array(
- 'Model' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Model' . DS),
- 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS),
- 'Controller' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Controller' . DS)
- ), App::RESET);
- $this->assertNull(Router::getRequest(), 'request stack should be empty.');
-
- $result = $this->object->requestAction('');
- $this->assertFalse($result);
-
- $result = $this->object->requestAction('/request_action/test_request_action');
- $expected = 'This is a test';
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction(FULL_BASE_URL . '/request_action/test_request_action');
- $expected = 'This is a test';
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction('/request_action/another_ra_test/2/5');
- $expected = 7;
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction('/tests_apps/index', array('return'));
- $expected = 'This is the TestsAppsController index view ';
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction('/tests_apps/some_method');
- $expected = 5;
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction('/request_action/paginate_request_action');
- $this->assertTrue($result);
-
- $result = $this->object->requestAction('/request_action/normal_request_action');
- $expected = 'Hello World';
- $this->assertEquals($expected, $result);
-
- $this->assertNull(Router::getRequest(), 'requests were not popped off the stack, this will break url generation');
- }
-
-/**
- * test requestAction() and plugins.
- *
- * @return void
- */
- public function testRequestActionPlugins() {
- App::build(array(
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS),
- ), App::RESET);
- CakePlugin::load('TestPlugin');
- Router::reload();
-
- $result = $this->object->requestAction('/test_plugin/tests/index', array('return'));
- $expected = 'test plugin index';
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction('/test_plugin/tests/index/some_param', array('return'));
- $expected = 'test plugin index';
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction(
- array('controller' => 'tests', 'action' => 'index', 'plugin' => 'test_plugin'), array('return')
- );
- $expected = 'test plugin index';
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction('/test_plugin/tests/some_method');
- $expected = 25;
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction(
- array('controller' => 'tests', 'action' => 'some_method', 'plugin' => 'test_plugin')
- );
- $expected = 25;
- $this->assertEquals($expected, $result);
- }
-
-/**
- * test requestAction() with arrays.
- *
- * @return void
- */
- public function testRequestActionArray() {
- App::build(array(
- 'Model' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Model' . DS),
- 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS),
- 'Controller' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Controller' . DS),
- 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
- ), App::RESET);
- CakePlugin::load(array('TestPlugin'));
-
- $result = $this->object->requestAction(
- array('controller' => 'request_action', 'action' => 'test_request_action')
- );
- $expected = 'This is a test';
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction(
- array('controller' => 'request_action', 'action' => 'another_ra_test'),
- array('pass' => array('5', '7'))
- );
- $expected = 12;
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction(
- array('controller' => 'tests_apps', 'action' => 'index'), array('return')
- );
- $expected = 'This is the TestsAppsController index view ';
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction(array('controller' => 'tests_apps', 'action' => 'some_method'));
- $expected = 5;
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction(
- array('controller' => 'request_action', 'action' => 'normal_request_action')
- );
- $expected = 'Hello World';
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction(
- array('controller' => 'request_action', 'action' => 'paginate_request_action')
- );
- $this->assertTrue($result);
-
- $result = $this->object->requestAction(
- array('controller' => 'request_action', 'action' => 'paginate_request_action'),
- array('pass' => array(5), 'named' => array('param' => 'value'))
- );
- $this->assertTrue($result);
- }
-
-/**
- * Test that requestAction() does not forward the 0 => return value.
- *
- * @return void
- */
- public function testRequestActionRemoveReturnParam() {
- $result = $this->object->requestAction(
- '/request_action/param_check', array('return')
- );
- $this->assertEquals('', $result, 'Return key was found');
- }
-
-/**
- * Test that requestAction() is populating $this->params properly
- *
- * @return void
- */
- public function testRequestActionParamParseAndPass() {
- $result = $this->object->requestAction('/request_action/params_pass');
- $this->assertEquals('request_action/params_pass', $result->url);
- $this->assertEquals('request_action', $result['controller']);
- $this->assertEquals('params_pass', $result['action']);
- $this->assertEquals(null, $result['plugin']);
-
- $result = $this->object->requestAction('/request_action/params_pass/sort:desc/limit:5');
- $expected = array('sort' => 'desc', 'limit' => 5,);
- $this->assertEquals($expected, $result['named']);
-
- $result = $this->object->requestAction(
- array('controller' => 'request_action', 'action' => 'params_pass'),
- array('named' => array('sort' => 'desc', 'limit' => 5))
- );
- $this->assertEquals($expected, $result['named']);
- }
-
-/**
- * test that requestAction does not fish data out of the POST
- * superglobal.
- *
- * @return void
- */
- public function testRequestActionNoPostPassing() {
- $_tmp = $_POST;
-
- $_POST = array('data' => array(
- 'item' => 'value'
- ));
- $result = $this->object->requestAction(array('controller' => 'request_action', 'action' => 'post_pass'));
- $expected = null;
- $this->assertEmpty($result);
-
- $result = $this->object->requestAction(
- array('controller' => 'request_action', 'action' => 'post_pass'),
- array('data' => $_POST['data'])
- );
- $expected = $_POST['data'];
- $this->assertEquals($expected, $result);
-
- $result = $this->object->requestAction('/request_action/post_pass');
- $expected = $_POST['data'];
- $this->assertEquals($expected, $result);
-
- $_POST = $_tmp;
- }
-
-/**
- * Test requestAction with post data.
- *
- * @return void
- */
- public function testRequestActionPostWithData() {
- $data = array(
- 'Post' => array('id' => 2)
- );
- $result = $this->object->requestAction(
- array('controller' => 'request_action', 'action' => 'post_pass'),
- array('data' => $data)
- );
- $this->assertEquals($data, $result);
-
- $result = $this->object->requestAction(
- '/request_action/post_pass',
- array('data' => $data)
- );
- $this->assertEquals($data, $result);
- }
-}
diff --git a/lib/Cake/Test/Case/Error/ErrorHandlerTest.php b/lib/Cake/Test/Case/Error/ErrorHandlerTest.php
deleted file mode 100644
index 0385361eacb..00000000000
--- a/lib/Cake/Test/Case/Error/ErrorHandlerTest.php
+++ /dev/null
@@ -1,246 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Error
- * @since CakePHP(tm) v 1.2.0.5432
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('ErrorHandler', 'Error');
-App::uses('Controller', 'Controller');
-App::uses('Router', 'Routing');
-
-/**
- * ErrorHandlerTest class
- *
- * @package Cake.Test.Case.Error
- */
-class ErrorHandlerTest extends CakeTestCase {
-
- protected $_restoreError = false;
-
-/**
- * setup create a request object to get out of router later.
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- App::build(array(
- 'View' => array(
- CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS
- )
- ), App::RESET);
- Router::reload();
-
- $request = new CakeRequest(null, false);
- $request->base = '';
- Router::setRequestInfo($request);
- $this->_debug = Configure::read('debug');
- $this->_error = Configure::read('Error');
- Configure::write('debug', 2);
- }
-
-/**
- * tearDown
- *
- * @return void
- */
- public function tearDown() {
- Configure::write('debug', $this->_debug);
- Configure::write('Error', $this->_error);
- App::build();
- if ($this->_restoreError) {
- restore_error_handler();
- }
- parent::tearDown();
- }
-
-/**
- * test error handling when debug is on, an error should be printed from Debugger.
- *
- * @return void
- */
- public function testHandleErrorDebugOn() {
- set_error_handler('ErrorHandler::handleError');
- $this->_restoreError = true;
-
- ob_start();
- $wrong .= '';
- $result = ob_get_clean();
-
- $this->assertRegExp('//', $result);
- $this->assertRegExp('/Notice<\/b>/', $result);
- $this->assertRegExp('/variable:\s+wrong/', $result);
- }
-
-/**
- * provides errors for mapping tests.
- *
- * @return void
- */
- public static function errorProvider() {
- return array(
- array(E_USER_NOTICE, 'Notice'),
- array(E_USER_WARNING, 'Warning'),
- array(E_USER_ERROR, 'Fatal Error'),
- );
- }
-
-/**
- * test error mappings
- *
- * @dataProvider errorProvider
- * @return void
- */
- public function testErrorMapping($error, $expected) {
- set_error_handler('ErrorHandler::handleError');
- $this->_restoreError = true;
-
- ob_start();
- trigger_error('Test error', $error);
-
- $result = ob_get_clean();
- $this->assertRegExp('/' . $expected . '<\/b>/', $result);
- }
-
-/**
- * test error prepended by @
- *
- * @return void
- */
- public function testErrorSuppressed() {
- set_error_handler('ErrorHandler::handleError');
- $this->_restoreError = true;
-
- ob_start();
- @include 'invalid.file';
- $result = ob_get_clean();
- $this->assertTrue(empty($result));
- }
-
-/**
- * Test that errors go into CakeLog when debug = 0.
- *
- * @return void
- */
- public function testHandleErrorDebugOff() {
- Configure::write('debug', 0);
- Configure::write('Error.trace', false);
- if (file_exists(LOGS . 'debug.log')) {
- @unlink(LOGS . 'debug.log');
- }
-
- set_error_handler('ErrorHandler::handleError');
- $this->_restoreError = true;
-
- $out .= '';
-
- $result = file(LOGS . 'debug.log');
- $this->assertEquals(1, count($result));
- $this->assertRegExp(
- '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} (Notice|Debug): Notice \(8\): Undefined variable:\s+out in \[.+ line \d+\]$/',
- $result[0]
- );
- @unlink(LOGS . 'debug.log');
- }
-
-/**
- * Test that errors going into CakeLog include traces.
- *
- * @return void
- */
- public function testHandleErrorLoggingTrace() {
- Configure::write('debug', 0);
- Configure::write('Error.trace', true);
- if (file_exists(LOGS . 'debug.log')) {
- @unlink(LOGS . 'debug.log');
- }
-
- set_error_handler('ErrorHandler::handleError');
- $this->_restoreError = true;
-
- $out .= '';
-
- $result = file(LOGS . 'debug.log');
- $this->assertRegExp(
- '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} (Notice|Debug): Notice \(8\): Undefined variable:\s+out in \[.+ line \d+\]$/',
- $result[0]
- );
- $this->assertRegExp('/^Trace:/', $result[1]);
- $this->assertRegExp('/^ErrorHandlerTest\:\:testHandleErrorLoggingTrace\(\)/', $result[2]);
- @unlink(LOGS . 'debug.log');
- }
-
-/**
- * test handleException generating a page.
- *
- * @return void
- */
- public function testHandleException() {
- $this->skipIf(file_exists(APP . 'app_error.php'), 'App error exists cannot run.');
-
- $error = new NotFoundException('Kaboom!');
- ob_start();
- ErrorHandler::handleException($error);
- $result = ob_get_clean();
- $this->assertRegExp('/Kaboom!/', $result, 'message missing.');
- }
-
-/**
- * test handleException generating a page.
- *
- * @return void
- */
- public function testHandleExceptionLog() {
- $this->skipIf(file_exists(APP . 'app_error.php'), 'App error exists cannot run.');
-
- if (file_exists(LOGS . 'error.log')) {
- unlink(LOGS . 'error.log');
- }
- Configure::write('Exception.log', true);
- $error = new NotFoundException('Kaboom!');
-
- ob_start();
- ErrorHandler::handleException($error);
- $result = ob_get_clean();
- $this->assertRegExp('/Kaboom!/', $result, 'message missing.');
-
- $log = file(LOGS . 'error.log');
- $this->assertRegExp('/\[NotFoundException\] Kaboom!/', $log[0], 'message missing.');
- $this->assertRegExp('/\#0.*ErrorHandlerTest->testHandleExceptionLog/', $log[1], 'Stack trace missing.');
- }
-
-/**
- * tests it is possible to load a plugin exception renderer
- *
- * @return void
- */
- public function testLoadPluginHanlder() {
- App::build(array(
- 'Plugin' => array(
- CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS
- )
- ), App::RESET);
- CakePlugin::load('TestPlugin');
- Configure::write('Exception.renderer', 'TestPlugin.TestPluginExceptionRenderer');
- $error = new NotFoundException('Kaboom!');
- ob_start();
- ErrorHandler::handleException($error);
- $result = ob_get_clean();
- $this->assertEquals('Rendered by test plugin', $result);
- CakePlugin::unload();
- }
-
-}
diff --git a/lib/Cake/Test/Case/Error/ExceptionRendererTest.php b/lib/Cake/Test/Case/Error/ExceptionRendererTest.php
deleted file mode 100644
index 42c5dfc6571..00000000000
--- a/lib/Cake/Test/Case/Error/ExceptionRendererTest.php
+++ /dev/null
@@ -1,742 +0,0 @@
-
- * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- *
- * Licensed under The MIT License
- * Redistributions of files must retain the above copyright notice
- *
- * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
- * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
- * @package Cake.Test.Case.Error
- * @since CakePHP(tm) v 2.0
- * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
- */
-
-App::uses('ExceptionRenderer', 'Error');
-App::uses('Controller', 'Controller');
-App::uses('AppController', 'Controller');
-App::uses('Component', 'Controller');
-App::uses('Router', 'Routing');
-
-/**
- * Short description for class.
- *
- * @package Cake.Test.Case.Error
- */
-class AuthBlueberryUser extends CakeTestModel {
-
-/**
- * name property
- *
- * @var string 'AuthBlueberryUser'
- */
- public $name = 'AuthBlueberryUser';
-
-/**
- * useTable property
- *
- * @var string
- */
- public $useTable = false;
-}
-
-/**
- * BlueberryComponent class
- *
- * @package Cake.Test.Case.Error
- */
-class BlueberryComponent extends Component {
-
-/**
- * testName property
- *
- * @return void
- */
- public $testName = null;
-
-/**
- * initialize method
- *
- * @return void
- */
- public function initialize(Controller $controller) {
- $this->testName = 'BlueberryComponent';
- }
-
-}
-
-/**
- * TestErrorController class
- *
- * @package Cake.Test.Case.Error
- */
-class TestErrorController extends Controller {
-
-/**
- * uses property
- *
- * @var array
- */
- public $uses = array();
-
-/**
- * components property
- *
- * @return void
- */
- public $components = array('Blueberry');
-
-/**
- * beforeRender method
- *
- * @return void
- */
- public function beforeRender() {
- echo $this->Blueberry->testName;
- }
-
-/**
- * index method
- *
- * @return void
- */
- public function index() {
- $this->autoRender = false;
- return 'what up';
- }
-
-}
-
-/**
- * MyCustomExceptionRenderer class
- *
- * @package Cake.Test.Case.Error
- */
-class MyCustomExceptionRenderer extends ExceptionRenderer {
-
-/**
- * custom error message type.
- *
- * @return void
- */
- public function missingWidgetThing() {
- echo 'widget thing is missing';
- }
-
-}
-
-/**
- * Exception class for testing app error handlers and custom errors.
- *
- * @package Cake.Test.Case.Error
- */
-class MissingWidgetThingException extends NotFoundException {
-}
-
-
-/**
- * ExceptionRendererTest class
- *
- * @package Cake.Test.Case.Error
- */
-class ExceptionRendererTest extends CakeTestCase {
-
- protected $_restoreError = false;
-
-/**
- * setup create a request object to get out of router later.
- *
- * @return void
- */
- public function setUp() {
- parent::setUp();
- App::build(array(
- 'View' => array(
- CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS
- )
- ), App::RESET);
- Router::reload();
-
- $request = new CakeRequest(null, false);
- $request->base = '';
- Router::setRequestInfo($request);
- $this->_debug = Configure::read('debug');
- $this->_error = Configure::read('Error');
- Configure::write('debug', 2);
- }
-
-/**
- * tearDown
- *
- * @return void
- */
- public function tearDown() {
- Configure::write('debug', $this->_debug);
- Configure::write('Error', $this->_error);
- App::build();
- if ($this->_restoreError) {
- restore_error_handler();
- }
- parent::tearDown();
- }
-
-/**
- * Mocks out the response on the ExceptionRenderer object so headers aren't modified.
- *
- * @return void
- */
- protected function _mockResponse($error) {
- $error->controller->response = $this->getMock('CakeResponse', array('_sendHeader'));
- return $error;
- }
-
-/**
- * test that methods declared in an ExceptionRenderer subclass are not converted
- * into error400 when debug > 0
- *
- * @return void
- */
- public function testSubclassMethodsNotBeingConvertedToError() {
- Configure::write('debug', 2);
-
- $exception = new MissingWidgetThingException('Widget not found');
- $ExceptionRenderer = $this->_mockResponse(new MyCustomExceptionRenderer($exception));
-
- ob_start();
- $ExceptionRenderer->render();
- $result = ob_get_clean();
-
- $this->assertEquals('widget thing is missing', $result);
- }
-
-/**
- * test that subclass methods are not converted when debug = 0
- *
- * @return void
- */
- public function testSubclassMethodsNotBeingConvertedDebug0() {
- Configure::write('debug', 0);
- $exception = new MissingWidgetThingException('Widget not found');
- $ExceptionRenderer = $this->_mockResponse(new MyCustomExceptionRenderer($exception));
-
- $this->assertEquals('missingWidgetThing', $ExceptionRenderer->method);
-
- ob_start();
- $ExceptionRenderer->render();
- $result = ob_get_clean();
-
- $this->assertEquals('widget thing is missing', $result, 'Method declared in subclass converted to error400');
- }
-
-/**
- * test that ExceptionRenderer subclasses properly convert framework errors.
- *
- * @return void
- */
- public function testSubclassConvertingFrameworkErrors() {
- Configure::write('debug', 0);
-
- $exception = new MissingControllerException('PostsController');
- $ExceptionRenderer = $this->_mockResponse(new MyCustomExceptionRenderer($exception));
-
- $this->assertEquals('error400', $ExceptionRenderer->method);
-
- ob_start();
- $ExceptionRenderer->render();
- $result = ob_get_clean();
-
- $this->assertRegExp('/Not Found/', $result, 'Method declared in error handler not converted to error400. %s');
- }
-
-/**
- * test things in the constructor.
- *
- * @return void
- */
- public function testConstruction() {
- $exception = new NotFoundException('Page not found');
- $ExceptionRenderer = new ExceptionRenderer($exception);
-
- $this->assertInstanceOf('CakeErrorController', $ExceptionRenderer->controller);
- $this->assertEquals('error400', $ExceptionRenderer->method);
- $this->assertEquals($exception, $ExceptionRenderer->error);
- }
-
-/**
- * test that method gets coerced when debug = 0
- *
- * @return void
- */
- public function testErrorMethodCoercion() {
- Configure::write('debug', 0);
- $exception = new MissingActionException('Page not found');
- $ExceptionRenderer = new ExceptionRenderer($exception);
-
- $this->assertInstanceOf('CakeErrorController', $ExceptionRenderer->controller);
- $this->assertEquals('error400', $ExceptionRenderer->method);
- $this->assertEquals($exception, $ExceptionRenderer->error);
- }
-
-/**
- * test that unknown exception types with valid status codes are treated correctly.
- *
- * @return void
- */
- public function testUnknownExceptionTypeWithExceptionThatHasA400Code() {
- $exception = new MissingWidgetThingException('coding fail.');
- $ExceptionRenderer = new ExceptionRenderer($exception);
- $ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('statusCode', '_sendHeader'));
- $ExceptionRenderer->controller->response->expects($this->once())->method('statusCode')->with(404);
-
- ob_start();
- $ExceptionRenderer->render();
- $result = ob_get_clean();
-
- $this->assertFalse(method_exists($ExceptionRenderer, 'missingWidgetThing'), 'no method should exist.');
- $this->assertEquals('error400', $ExceptionRenderer->method, 'incorrect method coercion.');
- $this->assertContains('coding fail', $result, 'Text should show up.');
- }
-
-/**
- * test that unknown exception types with valid status codes are treated correctly.
- *
- * @return void
- */
- public function testUnknownExceptionTypeWithNoCodeIsA500() {
- $exception = new OutOfBoundsException('foul ball.');
- $ExceptionRenderer = new ExceptionRenderer($exception);
- $ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('statusCode', '_sendHeader'));
- $ExceptionRenderer->controller->response->expects($this->once())
- ->method('statusCode')
- ->with(500);
-
- ob_start();
- $ExceptionRenderer->render();
- $result = ob_get_clean();
-
- $this->assertEquals('error500', $ExceptionRenderer->method, 'incorrect method coercion.');
- $this->assertContains('foul ball.', $result, 'Text should show up as its debug mode.');
- }
-
-/**
- * test that unknown exceptions have messages ignored.
- *
- * @return void
- */
- public function testUnknownExceptionInProduction() {
- Configure::write('debug', 0);
-
- $exception = new OutOfBoundsException('foul ball.');
- $ExceptionRenderer = new ExceptionRenderer($exception);
- $ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('statusCode', '_sendHeader'));
- $ExceptionRenderer->controller->response->expects($this->once())
- ->method('statusCode')
- ->with(500);
-
- ob_start();
- $ExceptionRenderer->render();
- $result = ob_get_clean();
-
- $this->assertEquals('error500', $ExceptionRenderer->method, 'incorrect method coercion.');
- $this->assertNotContains('foul ball.', $result, 'Text should no show up.');
- $this->assertContains('Internal Error', $result, 'Generic message only.');
- }
-
-/**
- * test that unknown exception types with valid status codes are treated correctly.
- *
- * @return void
- */
- public function testUnknownExceptionTypeWithCodeHigherThan500() {
- $exception = new OutOfBoundsException('foul ball.', 501);
- $ExceptionRenderer = new ExceptionRenderer($exception);
- $ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('statusCode', '_sendHeader'));
- $ExceptionRenderer->controller->response->expects($this->once())->method('statusCode')->with(501);
-
- ob_start();
- $ExceptionRenderer->render();
- $result = ob_get_clean();
-
- $this->assertEquals('error500', $ExceptionRenderer->method, 'incorrect method coercion.');
- $this->assertContains('foul ball.', $result, 'Text should show up as its debug mode.');
- }
-
-/**
- * testerror400 method
- *
- * @return void
- */
- public function testError400() {
- Router::reload();
-
- $request = new CakeRequest('posts/view/1000', false);
- Router::setRequestInfo($request);
-
- $exception = new NotFoundException('Custom message');
- $ExceptionRenderer = new ExceptionRenderer($exception);
- $ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('statusCode', '_sendHeader'));
- $ExceptionRenderer->controller->response->expects($this->once())->method('statusCode')->with(404);
-
- ob_start();
- $ExceptionRenderer->render();
- $result = ob_get_clean();
-
- $this->assertRegExp('/Custom message<\/h2>/', $result);
- $this->assertRegExp("/'.*?\/posts\/view\/1000'<\/strong>/", $result);
- }
-
-/**
- * test that error400 only modifies the messages on CakeExceptions.
- *
- * @return void
- */
- public function testerror400OnlyChangingCakeException() {
- Configure::write('debug', 0);
-
- $exception = new NotFoundException('Custom message');
- $ExceptionRenderer = $this->_mockResponse(new ExceptionRenderer($exception));
-
- ob_start();
- $ExceptionRenderer->render();
- $result = ob_get_clean();
- $this->assertContains('Custom message', $result);
-
- $exception = new MissingActionException(array('controller' => 'PostsController', 'action' => 'index'));
- $ExceptionRenderer = $this->_mockResponse(new ExceptionRenderer($exception));
-
- ob_start();
- $ExceptionRenderer->render();
- $result = ob_get_clean();
- $this->assertContains('Not Found', $result);
- }
-
-/**
- * test that error400 doesn't expose XSS
- *
- * @return void
- */
- public function testError400NoInjection() {
- Router::reload();
-
- $request = new CakeRequest('pages/pink ', false);
- Router::setRequestInfo($request);
-
- $exception = new NotFoundException('Custom message');
- $ExceptionRenderer = $this->_mockResponse(new ExceptionRenderer($exception));
-
- ob_start();
- $ExceptionRenderer->render();
- $result = ob_get_clean();
-
- $this->assertNotRegExp('##', $result);
- }
-
-/**
- * testError500 method
- *
- * @return void
- */
- public function testError500Message() {
- $exception = new InternalErrorException('An Internal Error Has Occurred');
- $ExceptionRenderer = new ExceptionRenderer($exception);
- $ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('statusCode', '_sendHeader'));
- $ExceptionRenderer->controller->response->expects($this->once())->method('statusCode')->with(500);
-
- ob_start();
- $ExceptionRenderer->render();
- $result = ob_get_clean();
-
- $this->assertRegExp('/